From fdaa69ee7f8dd3d11496d79f6590b516bde74f94 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 9 Oct 2020 18:49:23 +0100 Subject: [PATCH] Renaming Model -> Table across the entire system, this is an unstable update and has not been tested fully yet. --- CONTRIBUTING.md | 2 +- .../cypress/integration/createView.spec.js | 6 +- packages/builder/cypress/support/commands.js | 2 +- .../builderStore/fetchBindableProperties.js | 36 ++-- .../store/automation/tests/testAutomation.js | 8 +- .../builder/src/builderStore/store/backend.js | 90 +++++----- .../flowchart/AutomationBlockTagline.svelte | 8 +- .../SetupPanel/AutomationBlockSetup.svelte | 6 +- .../ParamInputs/RecordSelector.svelte | 14 +- ...elSelector.svelte => TableSelector.svelte} | 4 +- ...ModelDataTable.svelte => DataTable.svelte} | 10 +- .../DataTable/RelationshipDataTable.svelte | 20 +-- .../components/backend/DataTable/Table.svelte | 4 +- .../src/components/backend/DataTable/api.js | 6 +- .../modals/CreateEditRecordModal.svelte | 14 +- .../popovers/CalculatePopover.svelte | 10 +- .../DataTable/popovers/ColumnPopover.svelte | 4 +- .../popovers/CreateEditColumnPopover.svelte | 12 +- .../popovers/CreateViewPopover.svelte | 10 +- .../DataTable/popovers/FilterPopover.svelte | 26 +-- .../DataTable/popovers/GroupByPopover.svelte | 6 +- .../ListItem.svelte | 2 +- .../TableDataImport.svelte | 12 +- .../TableNavigator.svelte} | 22 +-- .../modals/CreateTableModal.svelte | 4 +- .../popovers/EditTablePopover.svelte | 4 +- .../popovers/EditViewPopover.svelte | 4 +- .../common/LinkedRecordSelector.svelte | 18 +- .../EventsEditor/actions/CreateRecord.svelte | 20 +-- .../EventsEditor/actions/SaveFields.svelte | 2 +- .../EventsEditor/actions/UpdateRecord.svelte | 16 +- .../userInterface/PropertyControl.svelte | 2 +- ...{ModelSelect.svelte => TableSelect.svelte} | 4 +- ...ect.svelte => TableViewFieldSelect.svelte} | 14 +- ...ewSelect.svelte => TableViewSelect.svelte} | 18 +- .../userInterface/pagesParsing/types.js | 2 +- .../userInterface/temporaryPanelStructure.js | 52 +++--- .../[application]/backend/_layout.svelte | 4 +- .../pages/[application]/backend/index.svelte | 2 +- .../model/[selectedModel]/_layout.svelte | 15 -- .../backend/model/_layout.svelte | 32 ---- .../[application]/backend/model/index.svelte | 35 ---- .../table/[selectedTable]/_layout.svelte | 15 ++ .../[selectedTable]}/index.svelte | 8 +- .../[selectedField]/index.svelte | 2 +- .../[selectedRecord]/index.svelte | 0 .../relationship/index.svelte | 0 .../backend/table/_layout.svelte | 32 ++++ .../[application]/backend/table/index.svelte | 35 ++++ .../view/[selectedView]/_layout.svelte | 6 +- .../tests/fetchBindableProperties.spec.js | 22 +-- packages/client/src/api/index.js | 4 +- packages/server/.vscode/launch.json | 4 +- packages/server/src/api/controllers/record.js | 92 +++++----- .../api/controllers/{model.js => table.js} | 76 ++++---- .../server/src/api/controllers/view/index.js | 22 +-- .../__snapshots__/viewBuilder.spec.js.snap | 12 +- .../view/tests/viewBuilder.spec.js | 6 +- .../src/api/controllers/view/viewBuilder.js | 8 +- packages/server/src/api/index.js | 6 +- packages/server/src/api/routes/index.js | 4 +- packages/server/src/api/routes/model.js | 27 --- packages/server/src/api/routes/record.js | 32 ++-- packages/server/src/api/routes/table.js | 27 +++ .../src/api/routes/tests/accesslevel.spec.js | 32 ++-- .../src/api/routes/tests/automation.spec.js | 12 +- .../src/api/routes/tests/couchTestUtils.js | 24 +-- .../src/api/routes/tests/record.spec.js | 50 +++--- .../tests/{model.spec.js => table.spec.js} | 92 +++++----- .../server/src/api/routes/tests/view.spec.js | 36 ++-- .../server/src/automations/automationUtils.js | 20 +-- .../src/automations/steps/createRecord.js | 16 +- .../src/automations/steps/deleteRecord.js | 10 +- .../src/automations/steps/updateRecord.js | 4 +- packages/server/src/automations/triggers.js | 34 ++-- .../src/db/linkedRecords/LinkController.js | 166 +++++++++--------- packages/server/src/db/linkedRecords/index.js | 48 ++--- .../server/src/db/linkedRecords/linkUtils.js | 16 +- packages/server/src/db/utils.js | 50 +++--- packages/server/src/events/index.js | 26 +-- packages/server/src/utilities/accessLevels.js | 4 +- packages/server/src/utilities/permissions.js | 20 +-- packages/server/yarn.lock | 8 +- packages/standard-components/components.json | 44 ++--- packages/standard-components/public/bundle.js | 10 +- .../standard-components/public/bundle.js.map | 6 +- .../public/clientAppDefinition.js | 6 +- .../src/Chart/Brush.svelte | 10 +- .../src/Chart/Bullet.svelte | 10 +- .../src/Chart/Heatmap.svelte | 10 +- .../src/Chart/ScatterPlot.svelte | 10 +- .../src/Chart/Sparkline.svelte | 10 +- .../src/Chart/StackedArea.svelte | 10 +- .../src/Chart/StackedBar.svelte | 10 +- .../standard-components/src/Chart/Step.svelte | 10 +- .../src/Chart/tests/line.html | 18 +- .../standard-components/src/DataChart.svelte | 8 +- .../standard-components/src/DataForm.svelte | 4 +- .../src/DataFormWide.svelte | 4 +- .../standard-components/src/DataList.svelte | 12 +- .../standard-components/src/DataSearch.svelte | 2 +- .../standard-components/src/DataTable.svelte | 16 +- packages/standard-components/src/Form.svelte | 32 ++-- .../src/LinkedRecordSelector.svelte | 32 ++-- .../src/RecordDetail.svelte | 20 +-- packages/standard-components/src/fetchData.js | 26 +-- 106 files changed, 1005 insertions(+), 1005 deletions(-) rename packages/builder/src/components/automation/SetupPanel/ParamInputs/{ModelSelector.svelte => TableSelector.svelte} (73%) rename packages/builder/src/components/backend/DataTable/{ModelDataTable.svelte => DataTable.svelte} (82%) rename packages/builder/src/components/backend/{ModelNavigator => TableNavigator}/ListItem.svelte (97%) rename packages/builder/src/components/backend/{ModelNavigator => TableNavigator}/TableDataImport.svelte (95%) rename packages/builder/src/components/backend/{ModelNavigator/ModelNavigator.svelte => TableNavigator/TableNavigator.svelte} (78%) rename packages/builder/src/components/backend/{ModelNavigator => TableNavigator}/modals/CreateTableModal.svelte (93%) rename packages/builder/src/components/backend/{ModelNavigator => TableNavigator}/popovers/EditTablePopover.svelte (96%) rename packages/builder/src/components/backend/{ModelNavigator => TableNavigator}/popovers/EditViewPopover.svelte (98%) rename packages/builder/src/components/userInterface/{ModelSelect.svelte => TableSelect.svelte} (69%) rename packages/builder/src/components/userInterface/{ModelViewFieldSelect.svelte => TableViewFieldSelect.svelte} (50%) rename packages/builder/src/components/userInterface/{ModelViewSelect.svelte => TableViewSelect.svelte} (80%) delete mode 100644 packages/builder/src/pages/[application]/backend/model/[selectedModel]/_layout.svelte delete mode 100644 packages/builder/src/pages/[application]/backend/model/_layout.svelte delete mode 100644 packages/builder/src/pages/[application]/backend/model/index.svelte create mode 100644 packages/builder/src/pages/[application]/backend/table/[selectedTable]/_layout.svelte rename packages/builder/src/pages/[application]/backend/{model/[selectedModel] => table/[selectedTable]}/index.svelte (50%) rename packages/builder/src/pages/[application]/backend/{model/[selectedModel] => table/[selectedTable]}/relationship/[selectedRecord]/[selectedField]/index.svelte (88%) rename packages/builder/src/pages/[application]/backend/{model/[selectedModel] => table/[selectedTable]}/relationship/[selectedRecord]/index.svelte (100%) rename packages/builder/src/pages/[application]/backend/{model/[selectedModel] => table/[selectedTable]}/relationship/index.svelte (100%) create mode 100644 packages/builder/src/pages/[application]/backend/table/_layout.svelte create mode 100644 packages/builder/src/pages/[application]/backend/table/index.svelte rename packages/server/src/api/controllers/{model.js => table.js} (59%) delete mode 100644 packages/server/src/api/routes/model.js create mode 100644 packages/server/src/api/routes/table.js rename packages/server/src/api/routes/tests/{model.spec.js => table.spec.js} (63%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5cf27a8f2..544c24c003 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,7 +145,7 @@ The HTML and CSS for your apps runtime pages, as well as the budibase client lib #### Backend -The backend schema, models and records are stored using PouchDB when developing locally, and in [CouchDB](https://pouchdb.com/) when running in production. +The backend schema, tables and records are stored using PouchDB when developing locally, and in [CouchDB](https://pouchdb.com/) when running in production. ### Publishing Budibase to NPM diff --git a/packages/builder/cypress/integration/createView.spec.js b/packages/builder/cypress/integration/createView.spec.js index 8f0c9565c8..c224b8af42 100644 --- a/packages/builder/cypress/integration/createView.spec.js +++ b/packages/builder/cypress/integration/createView.spec.js @@ -109,7 +109,7 @@ context("Create a View", () => { }) it("renames a view", () => { - cy.contains("[data-cy=model-nav-item]", "Test View") + cy.contains("[data-cy=table-nav-item]", "Test View") .find(".ri-more-line") .click() cy.contains("Edit").click() @@ -121,8 +121,8 @@ context("Create a View", () => { }) it("deletes a view", () => { - cy.contains("[data-cy=model-nav-item]", "Test View Updated").click() - cy.contains("[data-cy=model-nav-item]", "Test View Updated") + cy.contains("[data-cy=table-nav-item]", "Test View Updated").click() + cy.contains("[data-cy=table-nav-item]", "Test View Updated") .find(".ri-more-line") .click() cy.contains("Delete").click() diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 79fd83875d..bcc82a0396 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -64,7 +64,7 @@ Cypress.Commands.add("createTestTableWithData", () => { }) Cypress.Commands.add("createTable", tableName => { - // Enter model name + // Enter table name cy.contains("Create New Table").click() cy.get(".modal").within(() => { cy.get("input") diff --git a/packages/builder/src/builderStore/fetchBindableProperties.js b/packages/builder/src/builderStore/fetchBindableProperties.js index 92359ae630..081d643637 100644 --- a/packages/builder/src/builderStore/fetchBindableProperties.js +++ b/packages/builder/src/builderStore/fetchBindableProperties.js @@ -6,7 +6,7 @@ import { cloneDeep, difference } from "lodash/fp" * @property {string} componentInstanceId - an _id of a component that has been added to a screen, which you want to fetch bindable props for * @propperty {Object} screen - current screen - where componentInstanceId lives * @property {Object} components - dictionary of component definitions - * @property {Array} models - array of all models + * @property {Array} tables - array of all tables */ /** @@ -23,13 +23,13 @@ import { cloneDeep, difference } from "lodash/fp" * @param {fetchBindablePropertiesParameter} param * @returns {Array.} */ -export default function({ componentInstanceId, screen, components, models }) { +export default function({ componentInstanceId, screen, components, tables }) { const walkResult = walk({ // cloning so we are free to mutate props (e.g. by adding _contexts) instance: cloneDeep(screen.props), targetId: componentInstanceId, components, - models, + tables, }) return [ @@ -38,7 +38,7 @@ export default function({ componentInstanceId, screen, components, models }) { .map(componentInstanceToBindable(walkResult)), ...(walkResult.target?._contexts - .map(contextToBindables(models, walkResult)) + .map(contextToBindables(tables, walkResult)) .flat() ?? []), ] } @@ -71,15 +71,15 @@ const componentInstanceToBindable = walkResult => i => { } } -const contextToBindables = (models, walkResult) => context => { +const contextToBindables = (tables, walkResult) => context => { const contextParentPath = getParentPath(walkResult, context) - const isModel = context.model?.isModel || typeof context.model === "string" - const modelId = - typeof context.model === "string" ? context.model : context.model.modelId - const model = models.find(model => model._id === modelId) + const isTable = context.table?.isTable || typeof context.table === "string" + const tableId = + typeof context.table === "string" ? context.table : context.table.tableId + const table = tables.find(table => table._id === tableId) // Avoid crashing whenever no data source has been selected - if (model == null) { + if (table == null) { return [] } @@ -89,12 +89,12 @@ const contextToBindables = (models, walkResult) => context => { // how the binding expression persists, and is used in the app at runtime runtimeBinding: `${contextParentPath}data.${key}`, // how the binding exressions looks to the user of the builder - readableBinding: `${context.instance._instanceName}.${model.name}.${key}`, + readableBinding: `${context.instance._instanceName}.${table.name}.${key}`, }) - // see ModelViewSelect.svelte for the format of context.model - // ... this allows us to bind to Model schemas, or View schemas - const schema = isModel ? model.schema : model.views[context.model.name].schema + // see TableViewSelect.svelte for the format of context.table + // ... this allows us to bind to Table schemas, or View schemas + const schema = isTable ? table.schema : table.views[context.table.name].schema return ( Object.keys(schema) @@ -118,7 +118,7 @@ const getParentPath = (walkResult, context) => { ) } -const walk = ({ instance, targetId, components, models, result }) => { +const walk = ({ instance, targetId, components, tables, result }) => { if (!result) { result = { target: null, @@ -157,8 +157,8 @@ const walk = ({ instance, targetId, components, models, result }) => { if (contextualInstance) { // add to currentContexts (ancestory of context) // before walking children - const model = instance[component.context] - result.currentContexts.push({ instance, model }) + const table = instance[component.context] + result.currentContexts.push({ instance, table }) } const currentContexts = [...result.currentContexts] @@ -167,7 +167,7 @@ const walk = ({ instance, targetId, components, models, result }) => { // these have been deep cloned above, so shouln't modify the // original component instances child._contexts = currentContexts - walk({ instance: child, targetId, components, models, result }) + walk({ instance: child, targetId, components, tables, result }) } if (contextualInstance) { diff --git a/packages/builder/src/builderStore/store/automation/tests/testAutomation.js b/packages/builder/src/builderStore/store/automation/tests/testAutomation.js index e75560c1f0..8f714bdead 100644 --- a/packages/builder/src/builderStore/store/automation/tests/testAutomation.js +++ b/packages/builder/src/builderStore/store/automation/tests/testAutomation.js @@ -29,13 +29,13 @@ export default { name: "Record Saved", event: "record:save", icon: "ri-save-line", - tagline: "Record is added to {{model.name}}", + tagline: "Record is added to {{table.name}}", description: "Fired when a record is saved to your database.", - params: { model: "model" }, + params: { table: "table" }, type: "TRIGGER", args: { - model: { - type: "model", + table: { + type: "table", views: {}, name: "users", schema: { diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js index bbfbcd4726..a5d7afcbb5 100644 --- a/packages/builder/src/builderStore/store/backend.js +++ b/packages/builder/src/builderStore/store/backend.js @@ -3,12 +3,12 @@ import { cloneDeep } from "lodash/fp" import api from "../api" const INITIAL_BACKEND_UI_STATE = { - models: [], + tables: [], views: [], users: [], selectedDatabase: {}, - selectedModel: {}, - draftModel: {}, + selectedTable: {}, + draftTable: {}, } export const getBackendUiStore = () => { @@ -18,11 +18,11 @@ export const getBackendUiStore = () => { reset: () => store.set({ ...INITIAL_BACKEND_UI_STATE }), database: { select: async db => { - const modelsResponse = await api.get(`/api/models`) - const models = await modelsResponse.json() + const tablesResponse = await api.get(`/api/tables`) + const tables = await tablesResponse.json() store.update(state => { state.selectedDatabase = db - state.models = models + state.tables = tables return state }) }, @@ -44,50 +44,50 @@ export const getBackendUiStore = () => { return state }), }, - models: { + tables: { fetch: async () => { - const modelsResponse = await api.get(`/api/models`) - const models = await modelsResponse.json() + const tablesResponse = await api.get(`/api/tables`) + const tables = await tablesResponse.json() store.update(state => { - state.models = models + state.tables = tables return state }) }, - select: model => + select: table => store.update(state => { - state.selectedModel = model - state.draftModel = cloneDeep(model) - state.selectedView = { name: `all_${model._id}` } + state.selectedTable = table + state.draftTable = cloneDeep(table) + state.selectedView = { name: `all_${table._id}` } return state }), - save: async model => { - const updatedModel = cloneDeep(model) + save: async table => { + const updatedTable = cloneDeep(table) // update any renamed schema keys to reflect their names - for (let key in updatedModel.schema) { - const field = updatedModel.schema[key] + for (let key in updatedTable.schema) { + const field = updatedTable.schema[key] // field has been renamed if (field.name && field.name !== key) { - updatedModel.schema[field.name] = field - updatedModel._rename = { old: key, updated: field.name } - delete updatedModel.schema[key] + updatedTable.schema[field.name] = field + updatedTable._rename = { old: key, updated: field.name } + delete updatedTable.schema[key] } } - const SAVE_MODEL_URL = `/api/models` - const response = await api.post(SAVE_MODEL_URL, updatedModel) - const savedModel = await response.json() - await store.actions.models.fetch() - store.actions.models.select(savedModel) - return savedModel + const SAVE_TABLE_URL = `/api/tables` + const response = await api.post(SAVE_TABLE_URL, updatedTable) + const savedTable = await response.json() + await store.actions.tables.fetch() + store.actions.tables.select(savedTable) + return savedTable }, - delete: async model => { - await api.delete(`/api/models/${model._id}/${model._rev}`) + delete: async table => { + await api.delete(`/api/tables/${table._id}/${table._rev}`) store.update(state => { - state.models = state.models.filter( - existing => existing._id !== model._id + state.tables = state.tables.filter( + existing => existing._id !== table._id ) - state.selectedModel = {} + state.selectedTable = {} return state }) }, @@ -95,23 +95,23 @@ export const getBackendUiStore = () => { store.update(state => { // delete the original if renaming if (originalName) { - delete state.draftModel.schema[originalName] - state.draftModel._rename = { + delete state.draftTable.schema[originalName] + state.draftTable._rename = { old: originalName, updated: field.name, } } - state.draftModel.schema[field.name] = cloneDeep(field) + state.draftTable.schema[field.name] = cloneDeep(field) - store.actions.models.save(state.draftModel) + store.actions.tables.save(state.draftTable) return state }) }, deleteField: field => { store.update(state => { - delete state.draftModel.schema[field.name] - store.actions.models.save(state.draftModel) + delete state.draftTable.schema[field.name] + store.actions.tables.save(state.draftTable) return state }) }, @@ -120,12 +120,12 @@ export const getBackendUiStore = () => { select: view => store.update(state => { state.selectedView = view - state.selectedModel = {} + state.selectedTable = {} return state }), delete: async view => { await api.delete(`/api/views/${view}`) - await store.actions.models.fetch() + await store.actions.tables.fetch() }, save: async view => { const response = await api.post(`/api/views`, view) @@ -137,14 +137,14 @@ export const getBackendUiStore = () => { } store.update(state => { - const viewModel = state.models.find( - model => model._id === view.modelId + const viewTable = state.tables.find( + table => table._id === view.tableId ) - if (view.originalName) delete viewModel.views[view.originalName] - viewModel.views[view.name] = viewMeta + if (view.originalName) delete viewTable.views[view.originalName] + viewTable.views[view.name] = viewMeta - state.models = state.models + state.tables = state.tables state.selectedView = viewMeta return state }) diff --git a/packages/builder/src/components/automation/AutomationBuilder/flowchart/AutomationBlockTagline.svelte b/packages/builder/src/components/automation/AutomationBuilder/flowchart/AutomationBlockTagline.svelte index 1b612390ea..b0a588314f 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/flowchart/AutomationBlockTagline.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/flowchart/AutomationBlockTagline.svelte @@ -13,10 +13,10 @@ function enrichInputs(inputs) { let enrichedInputs = { ...inputs, enriched: {} } - const modelId = inputs.modelId || inputs.record?.modelId - if (modelId) { - enrichedInputs.enriched.model = $backendUiStore.models.find( - model => model._id === modelId + const tableId = inputs.tableId || inputs.record?.tableId + if (tableId) { + enrichedInputs.enriched.table = $backendUiStore.tables.find( + table => table._id === tableId ) } return enrichedInputs diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 808001bb91..a43126afbb 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -1,5 +1,5 @@
- - {#each $backendUiStore.models as model} - + {#each $backendUiStore.tables as table} + {/each}
diff --git a/packages/builder/src/components/automation/SetupPanel/ParamInputs/ModelSelector.svelte b/packages/builder/src/components/automation/SetupPanel/ParamInputs/TableSelector.svelte similarity index 73% rename from packages/builder/src/components/automation/SetupPanel/ParamInputs/ModelSelector.svelte rename to packages/builder/src/components/automation/SetupPanel/ParamInputs/TableSelector.svelte index 8251e605c3..ba0b55cc85 100644 --- a/packages/builder/src/components/automation/SetupPanel/ParamInputs/ModelSelector.svelte +++ b/packages/builder/src/components/automation/SetupPanel/ParamInputs/TableSelector.svelte @@ -8,8 +8,8 @@
diff --git a/packages/builder/src/components/backend/DataTable/ModelDataTable.svelte b/packages/builder/src/components/backend/DataTable/DataTable.svelte similarity index 82% rename from packages/builder/src/components/backend/DataTable/ModelDataTable.svelte rename to packages/builder/src/components/backend/DataTable/DataTable.svelte index 63d94aeab4..b714d97304 100644 --- a/packages/builder/src/components/backend/DataTable/ModelDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/DataTable.svelte @@ -10,14 +10,14 @@ let data = [] let loading = false - $: title = $backendUiStore.selectedModel.name - $: schema = $backendUiStore.selectedModel.schema - $: modelView = { + $: title = $backendUiStore.selectedTable.name + $: schema = $backendUiStore.selectedTable.schema + $: tableView = { schema, name: $backendUiStore.selectedView.name, } - // Fetch records for specified model + // Fetch records for specified table $: { if ($backendUiStore.selectedView?.name?.startsWith("all_")) { loading = true @@ -34,6 +34,6 @@ {#if Object.keys(schema).length > 0} - + {/if} diff --git a/packages/builder/src/components/backend/DataTable/RelationshipDataTable.svelte b/packages/builder/src/components/backend/DataTable/RelationshipDataTable.svelte index 6712b8cf68..f50cc004ff 100644 --- a/packages/builder/src/components/backend/DataTable/RelationshipDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/RelationshipDataTable.svelte @@ -4,7 +4,7 @@ import { onMount } from "svelte" import { backendUiStore } from "builderStore" - export let modelId + export let tableId export let recordId export let fieldName @@ -12,15 +12,15 @@ let title $: data = record?.[fieldName] ?? [] - $: linkedModelId = data?.length ? data[0].modelId : null - $: linkedModel = $backendUiStore.models.find( - model => model._id === linkedModelId + $: linkedTableId = data?.length ? data[0].tableId : null + $: linkedTable = $backendUiStore.tables.find( + table => table._id === linkedTableId ) - $: schema = linkedModel?.schema - $: model = $backendUiStore.models.find(model => model._id === modelId) - $: fetchData(modelId, recordId) + $: schema = linkedTable?.schema + $: table = $backendUiStore.tables.find(table => table._id === tableId) + $: fetchData(tableId, recordId) $: { - let recordLabel = record?.[model?.primaryDisplay] + let recordLabel = record?.[table?.primaryDisplay] if (recordLabel) { title = `${recordLabel} - ${fieldName}` } else { @@ -28,8 +28,8 @@ } } - async function fetchData(modelId, recordId) { - const QUERY_VIEW_URL = `/api/${modelId}/${recordId}/enrich` + async function fetchData(tableId, recordId) { + const QUERY_VIEW_URL = `/api/${tableId}/${recordId}/enrich` const response = await api.get(QUERY_VIEW_URL) record = await response.json() } diff --git a/packages/builder/src/components/backend/DataTable/Table.svelte b/packages/builder/src/components/backend/DataTable/Table.svelte index c1e34074e6..9c387ca6b2 100644 --- a/packages/builder/src/components/backend/DataTable/Table.svelte +++ b/packages/builder/src/components/backend/DataTable/Table.svelte @@ -39,14 +39,14 @@ currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE ) : [] - $: modelId = data?.length ? data[0].modelId : null + $: tableId = data?.length ? data[0].tableId : null function selectRelationship(record, fieldName) { if (!record?.[fieldName]?.length) { return } $goto( - `/${$params.application}/backend/model/${modelId}/relationship/${record._id}/${fieldName}` + `/${$params.application}/backend/table/${tableId}/relationship/${record._id}/${fieldName}` ) } diff --git a/packages/builder/src/components/backend/DataTable/api.js b/packages/builder/src/components/backend/DataTable/api.js index f4c9a44380..b14a7fc613 100644 --- a/packages/builder/src/components/backend/DataTable/api.js +++ b/packages/builder/src/components/backend/DataTable/api.js @@ -6,15 +6,15 @@ export async function createUser(user) { return await response.json() } -export async function saveRecord(record, modelId) { - const SAVE_RECORDS_URL = `/api/${modelId}/records` +export async function saveRecord(record, tableId) { + const SAVE_RECORDS_URL = `/api/${tableId}/records` const response = await api.post(SAVE_RECORDS_URL, record) return await response.json() } export async function deleteRecord(record) { - const DELETE_RECORDS_URL = `/api/${record.modelId}/records/${record._id}/${record._rev}` + const DELETE_RECORDS_URL = `/api/${record.tableId}/records/${record._id}/${record._rev}` const response = await api.delete(DELETE_RECORDS_URL) return response } diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditRecordModal.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditRecordModal.svelte index 2e8771ac6e..08aaae1880 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditRecordModal.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditRecordModal.svelte @@ -11,15 +11,15 @@ let errors = [] $: creating = record?._id == null - $: model = record.modelId - ? $backendUiStore.models.find(model => model._id === record?.modelId) - : $backendUiStore.selectedModel - $: modelSchema = Object.entries(model?.schema ?? {}) + $: table = record.tableId + ? $backendUiStore.tables.find(table => table._id === record?.tableId) + : $backendUiStore.selectedTable + $: tableSchema = Object.entries(table?.schema ?? {}) async function saveRecord() { const recordResponse = await api.saveRecord( - { ...record, modelId: model._id }, - model._id + { ...record, tableId: table._id }, + table._id ) if (recordResponse.errors) { errors = Object.keys(recordResponse.errors) @@ -38,7 +38,7 @@ confirmText={creating ? 'Create Row' : 'Save Row'} onConfirm={saveRecord}> - {#each modelSchema as [key, meta]} + {#each tableSchema as [key, meta]}
diff --git a/packages/builder/src/components/backend/DataTable/popovers/CalculatePopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/CalculatePopover.svelte index 0275b68414..1b079dbb4a 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/CalculatePopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/CalculatePopover.svelte @@ -14,13 +14,13 @@ export let view = {} export let onClosed - $: viewModel = $backendUiStore.models.find( - ({ _id }) => _id === $backendUiStore.selectedView.modelId + $: viewTable = $backendUiStore.tables.find( + ({ _id }) => _id === $backendUiStore.selectedView.tableId ) $: fields = - viewModel && - Object.keys(viewModel.schema).filter( - field => viewModel.schema[field].type === "number" + viewTable && + Object.keys(viewTable.schema).filter( + field => viewTable.schema[field].type === "number" ) function saveView() { diff --git a/packages/builder/src/components/backend/DataTable/popovers/ColumnPopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/ColumnPopover.svelte index de431035da..e4db32d900 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/ColumnPopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/ColumnPopover.svelte @@ -32,10 +32,10 @@ } function deleteColumn() { - if (field.name === $backendUiStore.selectedModel.primaryDisplay) { + if (field.name === $backendUiStore.selectedTable.primaryDisplay) { notifier.danger("You cannot delete the primary display column") } else { - backendUiStore.actions.models.deleteField(field) + backendUiStore.actions.tables.deleteField(field) notifier.success("Column deleted") } hideEditor() diff --git a/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte index 2e2ad6f158..4caa3e3d40 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/CreateEditColumnPopover.svelte @@ -31,14 +31,14 @@ } let originalName = field.name - $: modelOptions = $backendUiStore.models.filter( - model => model._id !== $backendUiStore.draftModel._id + $: tableOptions = $backendUiStore.tables.filter( + table => table._id !== $backendUiStore.draftTable._id ) $: required = !!field?.constraints?.presence async function saveColumn() { backendUiStore.update(state => { - backendUiStore.actions.models.saveField({ + backendUiStore.actions.tables.saveField({ originalName, field, }) @@ -111,10 +111,10 @@ label="Max Value" bind:value={field.constraints.numericality.lessThanOrEqualTo} /> {:else if field.type === 'link'} - - {#each modelOptions as model} - + {#each tableOptions as table} + {/each} { - return $backendUiStore.selectedModel.schema[key].type === "number" + $: fields = Object.keys($backendUiStore.selectedTable.schema).filter(key => { + return $backendUiStore.selectedTable.schema[key].type === "number" }) - $: views = $backendUiStore.models.flatMap(model => - Object.keys(model.views || {}) + $: views = $backendUiStore.tables.flatMap(table => + Object.keys(table.views || {}) ) function saveView() { @@ -24,7 +24,7 @@ } backendUiStore.actions.views.save({ name, - modelId: $backendUiStore.selectedModel._id, + tableId: $backendUiStore.selectedTable._id, field, }) notifier.success(`View ${name} created`) diff --git a/packages/builder/src/components/backend/DataTable/popovers/FilterPopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/FilterPopover.svelte index 3d6241f0ab..c6d00f2875 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/FilterPopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/FilterPopover.svelte @@ -45,10 +45,10 @@ export let view = {} export let onClosed - $: viewModel = $backendUiStore.models.find( - ({ _id }) => _id === $backendUiStore.selectedView.modelId + $: viewTable = $backendUiStore.tables.find( + ({ _id }) => _id === $backendUiStore.selectedView.tableId ) - $: fields = viewModel && Object.keys(viewModel.schema) + $: fields = viewTable && Object.keys(viewTable.schema) function saveView() { backendUiStore.actions.views.save(view) @@ -71,25 +71,25 @@ function isMultipleChoice(field) { return ( - (viewModel.schema[field].constraints && - viewModel.schema[field].constraints.inclusion && - viewModel.schema[field].constraints.inclusion.length) || - viewModel.schema[field].type === "boolean" + (viewTable.schema[field].constraints && + viewTable.schema[field].constraints.inclusion && + viewTable.schema[field].constraints.inclusion.length) || + viewTable.schema[field].type === "boolean" ) } function fieldOptions(field) { - return viewModel.schema[field].type === "string" - ? viewModel.schema[field].constraints.inclusion + return viewTable.schema[field].type === "string" + ? viewTable.schema[field].constraints.inclusion : [true, false] } function isDate(field) { - return viewModel.schema[field].type === "datetime" + return viewTable.schema[field].type === "datetime" } function isNumber(field) { - return viewModel.schema[field].type === "number" + return viewTable.schema[field].type === "number" } const fieldChanged = filter => ev => { @@ -97,8 +97,8 @@ if ( filter.key && ev.target.value && - viewModel.schema[filter.key].type !== - viewModel.schema[ev.target.value].type + viewTable.schema[filter.key].type !== + viewTable.schema[ev.target.value].type ) { filter.value = "" } diff --git a/packages/builder/src/components/backend/DataTable/popovers/GroupByPopover.svelte b/packages/builder/src/components/backend/DataTable/popovers/GroupByPopover.svelte index da5cf7b8ec..36fde06d77 100644 --- a/packages/builder/src/components/backend/DataTable/popovers/GroupByPopover.svelte +++ b/packages/builder/src/components/backend/DataTable/popovers/GroupByPopover.svelte @@ -6,10 +6,10 @@ export let view = {} export let onClosed - $: viewModel = $backendUiStore.models.find( - ({ _id }) => _id === $backendUiStore.selectedView.modelId + $: viewTable = $backendUiStore.tables.find( + ({ _id }) => _id === $backendUiStore.selectedView.tableId ) - $: fields = viewModel && Object.keys(viewModel.schema) + $: fields = viewTable && Object.keys(viewTable.schema) function saveView() { backendUiStore.actions.views.save(view) diff --git a/packages/builder/src/components/backend/ModelNavigator/ListItem.svelte b/packages/builder/src/components/backend/TableNavigator/ListItem.svelte similarity index 97% rename from packages/builder/src/components/backend/ModelNavigator/ListItem.svelte rename to packages/builder/src/components/backend/TableNavigator/ListItem.svelte index 31dd5b5ac4..f148eaf8b2 100644 --- a/packages/builder/src/components/backend/ModelNavigator/ListItem.svelte +++ b/packages/builder/src/components/backend/TableNavigator/ListItem.svelte @@ -7,7 +7,7 @@
schema[column].success) $: dataImport = { valid, - schema: buildModelSchema(schema), + schema: buildTableSchema(schema), path: files[0] && files[0].path, } - function buildModelSchema(schema) { - const modelSchema = {} + function buildTableSchema(schema) { + const tableSchema = {} for (let key in schema) { const type = schema[key].type if (type === "omit") continue - modelSchema[key] = { + tableSchema[key] = { name: key, type, constraints: FIELDS[type.toUpperCase()].constraints, } } - return modelSchema + return tableSchema } async function validateCSV() { - const response = await api.post("/api/models/csv/validate", { + const response = await api.post("/api/tables/csv/validate", { file: files[0], schema: schema || {}, }) diff --git a/packages/builder/src/components/backend/ModelNavigator/ModelNavigator.svelte b/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte similarity index 78% rename from packages/builder/src/components/backend/ModelNavigator/ModelNavigator.svelte rename to packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte index 627acab415..03b59a8681 100644 --- a/packages/builder/src/components/backend/ModelNavigator/ModelNavigator.svelte +++ b/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte @@ -11,9 +11,9 @@ $: selectedView = $backendUiStore.selectedView && $backendUiStore.selectedView.name - function selectModel(model) { - backendUiStore.actions.models.select(model) - $goto(`./model/${model._id}`) + function selectTable(table) { + backendUiStore.actions.tables.select(table) + $goto(`./table/${table._id}`) } function selectView(view) { @@ -30,15 +30,15 @@
- {#each $backendUiStore.models as model} + {#each $backendUiStore.tables as table} selectModel(model)}> - + on:click={() => selectTable(table)}> + - {#each Object.keys(model.views || {}) as viewName} + {#each Object.keys(table.views || {}) as viewName} (selectedView === viewName ? {} : selectView({ name: viewName, - ...model.views[viewName], + ...table.views[viewName], }))}> + view={{ name: viewName, ...table.views[viewName] }} /> {/each} {/each} diff --git a/packages/builder/src/components/backend/ModelNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte similarity index 93% rename from packages/builder/src/components/backend/ModelNavigator/modals/CreateTableModal.svelte rename to packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index 1cc0e8894c..7a1720289a 100644 --- a/packages/builder/src/components/backend/ModelNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -17,13 +17,13 @@ } async function saveTable() { - const model = await backendUiStore.actions.models.save({ + const table = await backendUiStore.actions.tables.save({ name, schema: dataImport.schema || {}, dataImport, }) notifier.success(`Table ${name} created successfully.`) - $goto(`./model/${model._id}`) + $goto(`./table/${table._id}`) analytics.captureEvent("Table Created", { name }) } diff --git a/packages/builder/src/components/backend/ModelNavigator/popovers/EditTablePopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte similarity index 96% rename from packages/builder/src/components/backend/ModelNavigator/popovers/EditTablePopover.svelte rename to packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte index 028b78a1e8..9df5f36993 100644 --- a/packages/builder/src/components/backend/ModelNavigator/popovers/EditTablePopover.svelte +++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte @@ -29,13 +29,13 @@ } async function deleteTable() { - await backendUiStore.actions.models.delete(table) + await backendUiStore.actions.tables.delete(table) notifier.success("Table deleted") hideEditor() } async function save() { - await backendUiStore.actions.models.save(table) + await backendUiStore.actions.tables.save(table) notifier.success("Table renamed successfully") hideEditor() } diff --git a/packages/builder/src/components/backend/ModelNavigator/popovers/EditViewPopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte similarity index 98% rename from packages/builder/src/components/backend/ModelNavigator/popovers/EditViewPopover.svelte rename to packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte index bd1e184e06..9c165355d2 100644 --- a/packages/builder/src/components/backend/ModelNavigator/popovers/EditViewPopover.svelte +++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte @@ -39,10 +39,10 @@ async function deleteView() { const name = view.name - const id = view.modelId + const id = view.tableId await backendUiStore.actions.views.delete(name) notifier.success("View deleted") - $goto(`./model/${id}`) + $goto(`./table/${id}`) } diff --git a/packages/builder/src/components/common/LinkedRecordSelector.svelte b/packages/builder/src/components/common/LinkedRecordSelector.svelte index e7cf245eb8..174cf4e1ac 100644 --- a/packages/builder/src/components/common/LinkedRecordSelector.svelte +++ b/packages/builder/src/components/common/LinkedRecordSelector.svelte @@ -11,14 +11,14 @@ let records = [] $: label = capitalise(schema.name) - $: linkedModelId = schema.modelId - $: linkedModel = $backendUiStore.models.find( - model => model._id === linkedModelId + $: linkedTableId = schema.tableId + $: linkedTable = $backendUiStore.tables.find( + table => table._id === linkedTableId ) - $: fetchRecords(linkedModelId) + $: fetchRecords(linkedTableId) - async function fetchRecords(linkedModelId) { - const FETCH_RECORDS_URL = `/api/${linkedModelId}/records` + async function fetchRecords(linkedTableId) { + const FETCH_RECORDS_URL = `/api/${linkedTableId}/records` try { const response = await api.get(FETCH_RECORDS_URL) records = await response.json() @@ -29,15 +29,15 @@ } function getPrettyName(record) { - return record[linkedModel.primaryDisplay || "_id"] + return record[linkedTable.primaryDisplay || "_id"] } -{#if linkedModel.primaryDisplay == null} +{#if linkedTable.primaryDisplay == null} {:else} diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte index b3a6079284..6c71025d67 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte @@ -10,23 +10,23 @@ componentInstanceId: $store.currentComponentInfo._id, components: $store.components, screen: $store.currentPreviewItem, - models: $backendUiStore.models, + tables: $backendUiStore.tables, }) // just wraps binding in {{ ... }} const toBindingExpression = bindingPath => `{{ ${bindingPath} }}` - const modelFields = modelId => { - const model = $backendUiStore.models.find(m => m._id === modelId) + const tableFields = tableId => { + const table = $backendUiStore.tables.find(m => m._id === tableId) - return Object.keys(model.schema).map(k => ({ + return Object.keys(table.schema).map(k => ({ name: k, - type: model.schema[k].type, + type: table.schema[k].type, })) } $: schemaFields = - parameters && parameters.modelId ? modelFields(parameters.modelId) : [] + parameters && parameters.tableId ? tableFields(parameters.tableId) : [] const onFieldsChanged = e => { parameters.fields = e.detail @@ -35,14 +35,14 @@
- + {#each $backendUiStore.tables as table} + {/each} - {#if parameters.modelId} + {#if parameters.tableId} { diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte index 229fec90c5..a72ffdac1f 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte @@ -14,7 +14,7 @@ componentInstanceId: $store.currentComponentInfo._id, components: $store.components, screen: $store.currentPreviewItem, - models: $backendUiStore.models, + tables: $backendUiStore.tables, }) let idFields @@ -56,16 +56,16 @@ const component = $store.components[instance._component] - // component.context is the name of the prop that holds the modelId - const modelInfo = instance[component.context] + // component.context is the name of the prop that holds the tableId + const tableInfo = instance[component.context] - if (!modelInfo) return [] + if (!tableInfo) return [] - const model = $backendUiStore.models.find(m => m._id === modelInfo.modelId) - parameters.modelId = modelInfo.modelId - return Object.keys(model.schema).map(k => ({ + const table = $backendUiStore.tables.find(m => m._id === tableInfo.tableId) + parameters.tableId = tableInfo.tableId + return Object.keys(table.schema).map(k => ({ name: k, - type: model.schema[k].type, + type: table.schema[k].type, })) } diff --git a/packages/builder/src/components/userInterface/PropertyControl.svelte b/packages/builder/src/components/userInterface/PropertyControl.svelte index 59cdbd868b..2bd9959e28 100644 --- a/packages/builder/src/components/userInterface/PropertyControl.svelte +++ b/packages/builder/src/components/userInterface/PropertyControl.svelte @@ -37,7 +37,7 @@ componentInstanceId: $store.currentComponentInfo._id, components: $store.components, screen: $store.currentPreviewItem, - models: $backendUiStore.models, + tables: $backendUiStore.tables, }) } diff --git a/packages/builder/src/components/userInterface/ModelSelect.svelte b/packages/builder/src/components/userInterface/TableSelect.svelte similarity index 69% rename from packages/builder/src/components/userInterface/ModelSelect.svelte rename to packages/builder/src/components/userInterface/TableSelect.svelte index c2010ce4af..db0490b212 100644 --- a/packages/builder/src/components/userInterface/ModelSelect.svelte +++ b/packages/builder/src/components/userInterface/TableSelect.svelte @@ -7,7 +7,7 @@ diff --git a/packages/builder/src/components/userInterface/ModelViewFieldSelect.svelte b/packages/builder/src/components/userInterface/TableViewFieldSelect.svelte similarity index 50% rename from packages/builder/src/components/userInterface/ModelViewFieldSelect.svelte rename to packages/builder/src/components/userInterface/TableViewFieldSelect.svelte index a6b3ef2224..3b829ba576 100644 --- a/packages/builder/src/components/userInterface/ModelViewFieldSelect.svelte +++ b/packages/builder/src/components/userInterface/TableViewFieldSelect.svelte @@ -7,18 +7,18 @@ export let value = "" export let onChange = (val = {}) - const models = $backendUiStore.models + const tables = $backendUiStore.tables let options = [] - $: model = componentInstance.datasource - ? models.find(m => m._id === componentInstance.datasource.modelId) + $: table = componentInstance.datasource + ? tables.find(m => m._id === componentInstance.datasource.tableId) : null - $: if (model) { - options = componentInstance.datasource.isModel - ? Object.keys(model.schema) - : Object.keys(model.views[componentInstance.datasource.name].schema) + $: if (table) { + options = componentInstance.datasource.isTable + ? Object.keys(table.schema) + : Object.keys(table.views[componentInstance.datasource.name].schema) } diff --git a/packages/builder/src/components/userInterface/ModelViewSelect.svelte b/packages/builder/src/components/userInterface/TableViewSelect.svelte similarity index 80% rename from packages/builder/src/components/userInterface/ModelViewSelect.svelte rename to packages/builder/src/components/userInterface/TableViewSelect.svelte index 282c6c93f0..f7a1a10cea 100644 --- a/packages/builder/src/components/userInterface/ModelViewSelect.svelte +++ b/packages/builder/src/components/userInterface/TableViewSelect.svelte @@ -13,14 +13,14 @@ dropdownRight.hide() } - const models = $backendUiStore.models.map(m => ({ + const tables = $backendUiStore.tables.map(m => ({ label: m.name, name: `all_${m._id}`, - modelId: m._id, - isModel: true, + tableId: m._id, + isTable: true, })) - const views = $backendUiStore.models.reduce((acc, cur) => { + const views = $backendUiStore.tables.reduce((acc, cur) => { let viewsArr = Object.entries(cur.views).map(([key, value]) => ({ label: key, name: key, @@ -32,7 +32,7 @@ @@ -42,11 +42,11 @@ Tables
    - {#each models as model} + {#each tables as table}
  • handleSelected(model)}> - {model.label} + class:selected={value === table} + on:click={() => handleSelected(table)}> + {table.label}
  • {/each}
diff --git a/packages/builder/src/components/userInterface/pagesParsing/types.js b/packages/builder/src/components/userInterface/pagesParsing/types.js index b5f073e689..f85c83a733 100644 --- a/packages/builder/src/components/userInterface/pagesParsing/types.js +++ b/packages/builder/src/components/userInterface/pagesParsing/types.js @@ -20,7 +20,7 @@ export const TYPE_MAP = { "##bbstate": "", }, }, - models: { + tables: { default: {}, }, } diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index 296ae26606..fb1259b53b 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -1,9 +1,9 @@ import Input from "./PropertyPanelControls/Input.svelte" import OptionSelect from "./OptionSelect.svelte" import Checkbox from "../common/Checkbox.svelte" -import ModelSelect from "components/userInterface/ModelSelect.svelte" -import ModelViewSelect from "components/userInterface/ModelViewSelect.svelte" -import ModelViewFieldSelect from "components/userInterface/ModelViewFieldSelect.svelte" +import TableSelect from "components/userInterface/TableSelect.svelte" +import TableViewSelect from "components/userInterface/TableViewSelect.svelte" +import TableViewFieldSelect from "components/userInterface/TableViewFieldSelect.svelte" import Event from "components/userInterface/EventsEditor/EventPropertyControl.svelte" import ScreenSelect from "components/userInterface/ScreenSelect.svelte" import { IconSelect } from "components/userInterface/IconSelect" @@ -307,7 +307,7 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, ], }, @@ -540,7 +540,7 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, { label: "Stripe Color", @@ -566,7 +566,7 @@ export default { control: Colorpicker, defaultValue: "#FFFFFF", }, - { label: "Table", key: "model", control: ModelSelect }, + { label: "Table", key: "table", control: TableSelect }, ], }, children: [], @@ -586,8 +586,8 @@ export default { settings: [ { label: "Table", - key: "model", - control: ModelSelect, + key: "table", + control: TableSelect, }, { label: "Title", @@ -611,8 +611,8 @@ export default { settings: [ { label: "Table", - key: "model", - control: ModelSelect, + key: "table", + control: TableSelect, }, { label: "Title", @@ -644,19 +644,19 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, { label: "Name Field", key: "nameKey", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Value Field", key: "valueKey", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Animate Chart", @@ -738,19 +738,19 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, { label: "Name Label", key: "nameLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Value Label", key: "valueLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Y Axis Label", @@ -852,25 +852,25 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, { label: "Name Label", key: "nameLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Group Label", key: "groupLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Value Label", key: "valueLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Color", @@ -955,25 +955,25 @@ export default { { label: "Table", key: "datasource", - control: ModelViewSelect, + control: TableViewSelect, }, { label: "Value Label", key: "valueLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Topic Label", key: "topicLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Date Label", key: "dateLabel", dependsOn: "datasource", - control: ModelViewFieldSelect, + control: TableViewFieldSelect, }, { label: "Colors", @@ -1120,7 +1120,7 @@ export default { // icon: "ri-file-list-line", // properties: { // design: { ...all }, - // settings: [{ label: "Table", key: "model", control: ModelSelect }], + // settings: [{ label: "Table", key: "table", control: TableSelect }], // }, // children: [], // }, @@ -1132,7 +1132,7 @@ export default { icon: "ri-profile-line", properties: { design: { ...all }, - settings: [{ label: "Table", key: "model", control: ModelSelect }], + settings: [{ label: "Table", key: "table", control: TableSelect }], }, children: [], }, diff --git a/packages/builder/src/pages/[application]/backend/_layout.svelte b/packages/builder/src/pages/[application]/backend/_layout.svelte index f5a5c4e89c..1ac92b84c9 100644 --- a/packages/builder/src/pages/[application]/backend/_layout.svelte +++ b/packages/builder/src/pages/[application]/backend/_layout.svelte @@ -1,13 +1,13 @@
diff --git a/packages/builder/src/pages/[application]/backend/index.svelte b/packages/builder/src/pages/[application]/backend/index.svelte index 488c67ff0e..b893d8680f 100644 --- a/packages/builder/src/pages/[application]/backend/index.svelte +++ b/packages/builder/src/pages/[application]/backend/index.svelte @@ -1,6 +1,6 @@ diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/_layout.svelte b/packages/builder/src/pages/[application]/backend/model/[selectedModel]/_layout.svelte deleted file mode 100644 index 4ed98f3a38..0000000000 --- a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/_layout.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/packages/builder/src/pages/[application]/backend/model/_layout.svelte b/packages/builder/src/pages/[application]/backend/model/_layout.svelte deleted file mode 100644 index 74e14a5ad4..0000000000 --- a/packages/builder/src/pages/[application]/backend/model/_layout.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - -
- -
- - diff --git a/packages/builder/src/pages/[application]/backend/model/index.svelte b/packages/builder/src/pages/[application]/backend/model/index.svelte deleted file mode 100644 index 2e800648e8..0000000000 --- a/packages/builder/src/pages/[application]/backend/model/index.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -{#if $backendUiStore.models.length === 0} - Create your first table to start building -{:else} - Select a table to edit -{/if} - - diff --git a/packages/builder/src/pages/[application]/backend/table/[selectedTable]/_layout.svelte b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/_layout.svelte new file mode 100644 index 0000000000..9892da00db --- /dev/null +++ b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/_layout.svelte @@ -0,0 +1,15 @@ + + + diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/index.svelte similarity index 50% rename from packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte rename to packages/builder/src/pages/[application]/backend/table/[selectedTable]/index.svelte index c2cf7f6ff9..555d304586 100644 --- a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte +++ b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/index.svelte @@ -1,12 +1,12 @@ -{#if $backendUiStore.selectedDatabase._id && selectedModel.name} - +{#if $backendUiStore.selectedDatabase._id && selectedTable.name} + {:else} Create your first table to start building {/if} diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/[selectedRecord]/[selectedField]/index.svelte b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/[selectedRecord]/[selectedField]/index.svelte similarity index 88% rename from packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/[selectedRecord]/[selectedField]/index.svelte rename to packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/[selectedRecord]/[selectedField]/index.svelte index c9a1475716..1ee08621fb 100644 --- a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/[selectedRecord]/[selectedField]/index.svelte +++ b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/[selectedRecord]/[selectedField]/index.svelte @@ -4,6 +4,6 @@ diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/[selectedRecord]/index.svelte b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/[selectedRecord]/index.svelte similarity index 100% rename from packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/[selectedRecord]/index.svelte rename to packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/[selectedRecord]/index.svelte diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/index.svelte b/packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/index.svelte similarity index 100% rename from packages/builder/src/pages/[application]/backend/model/[selectedModel]/relationship/index.svelte rename to packages/builder/src/pages/[application]/backend/table/[selectedTable]/relationship/index.svelte diff --git a/packages/builder/src/pages/[application]/backend/table/_layout.svelte b/packages/builder/src/pages/[application]/backend/table/_layout.svelte new file mode 100644 index 0000000000..3f8b33a095 --- /dev/null +++ b/packages/builder/src/pages/[application]/backend/table/_layout.svelte @@ -0,0 +1,32 @@ + + +
+ +
+ + diff --git a/packages/builder/src/pages/[application]/backend/table/index.svelte b/packages/builder/src/pages/[application]/backend/table/index.svelte new file mode 100644 index 0000000000..137a25aa48 --- /dev/null +++ b/packages/builder/src/pages/[application]/backend/table/index.svelte @@ -0,0 +1,35 @@ + + +{#if $backendUiStore.tables.length === 0} + Create your first table to start building +{:else} + Select a table to edit +{/if} + + diff --git a/packages/builder/src/pages/[application]/backend/view/[selectedView]/_layout.svelte b/packages/builder/src/pages/[application]/backend/view/[selectedView]/_layout.svelte index e718c5de00..e890c7e276 100644 --- a/packages/builder/src/pages/[application]/backend/view/[selectedView]/_layout.svelte +++ b/packages/builder/src/pages/[application]/backend/view/[selectedView]/_layout.svelte @@ -5,9 +5,9 @@ if ($params.selectedView) { let view const viewName = decodeURI($params.selectedView) - for (let model of $backendUiStore.models) { - if (model.views && model.views[viewName]) { - view = model.views[viewName] + for (let table of $backendUiStore.tables) { + if (table.views && table.views[viewName]) { + view = table.views[viewName] } } if (view) { diff --git a/packages/builder/tests/fetchBindableProperties.spec.js b/packages/builder/tests/fetchBindableProperties.spec.js index 76e8e33f05..8963e5aa66 100644 --- a/packages/builder/tests/fetchBindableProperties.spec.js +++ b/packages/builder/tests/fetchBindableProperties.spec.js @@ -22,7 +22,7 @@ describe("fetch bindable properties", () => { expect(componentBinding).not.toBeDefined() }) - it("should return model schema, when inside a context", () => { + it("should return table schema, when inside a context", () => { const result = fetchBindableProperties({ componentInstanceId: "list-item-input-id", ...testData() @@ -44,13 +44,13 @@ describe("fetch bindable properties", () => { expect(idbinding.readableBinding).toBe("list-name.Test Model._id") }) - it("should return model schema, for grantparent context", () => { + it("should return table schema, for grantparent context", () => { const result = fetchBindableProperties({ componentInstanceId: "child-list-item-input-id", ...testData() }) const contextBindings = result.filter(r => r.type==="context") - // 2 fields + _id + _rev ... x 2 models + // 2 fields + _id + _rev ... x 2 tables expect(contextBindings.length).toBe(8) const namebinding_parent = contextBindings.find(b => b.runtimeBinding === "parent.data.name") @@ -126,7 +126,7 @@ const testData = () => { _id: "list-id", _component: "@budibase/standard-components/list", _instanceName: "list-name", - model: { isModel: true, modelId: "test-model-id", label: "Test Model", name: "all_test-model-id" }, + table: { isTable: true, tableId: "test-table-id", label: "Test Model", name: "all_test-table-id" }, _children: [ { _id: "list-item-heading-id", @@ -144,7 +144,7 @@ const testData = () => { _id: "child-list-id", _component: "@budibase/standard-components/list", _instanceName: "child-list-name", - model: { isModel: true, modelId: "test-model-id", label: "Test Model", name: "all_test-model-id"}, + table: { isTable: true, tableId: "test-table-id", label: "Test Model", name: "all_test-table-id"}, _children: [ { _id: "child-list-item-heading-id", @@ -166,8 +166,8 @@ const testData = () => { } } - const models = [{ - _id: "test-model-id", + const tables = [{ + _id: "test-table-id", name: "Test Model", schema: { name: { @@ -184,9 +184,9 @@ const testData = () => { props: {}, }, "@budibase/standard-components/list" : { - context: "model", + context: "table", props: { - model: "string" + table: "string" }, }, "@budibase/standard-components/input" : { @@ -202,6 +202,6 @@ const testData = () => { }, } - return { screen, models, components } + return { screen, tables, components } -} \ No newline at end of file +} diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index 34441d563b..eb18ed506a 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -54,7 +54,7 @@ const apiOpts = { const createRecord = async params => await post({ - url: `/api/${params.modelId}/records`, + url: `/api/${params.tableId}/records`, body: makeRecordRequestBody(params), }) @@ -62,7 +62,7 @@ const updateRecord = async params => { const record = makeRecordRequestBody(params) record._id = params._id await patch({ - url: `/api/${params.modelId}/records/${params._id}`, + url: `/api/${params.tableId}/records/${params._id}`, body: record, }) } diff --git a/packages/server/.vscode/launch.json b/packages/server/.vscode/launch.json index 452a377b3d..7279e560d8 100644 --- a/packages/server/.vscode/launch.json +++ b/packages/server/.vscode/launch.json @@ -80,7 +80,7 @@ "request": "launch", "name": "Jest - Models", "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": ["model.spec", "--runInBand"], + "args": ["table.spec", "--runInBand"], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "disableOptimisticBPs": true, @@ -136,4 +136,4 @@ "console": "externalTerminal" } ] -} \ No newline at end of file +} diff --git a/packages/server/src/api/controllers/record.js b/packages/server/src/api/controllers/record.js index bd62d38bff..f4729ba71e 100644 --- a/packages/server/src/api/controllers/record.js +++ b/packages/server/src/api/controllers/record.js @@ -9,7 +9,7 @@ const { } = require("../../db/utils") const { cloneDeep } = require("lodash") -const MODEL_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.MODEL}${SEPARATOR}` +const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}` validateJs.extend(validateJs.validators.datetime, { parse: function(value) { @@ -25,18 +25,18 @@ exports.patch = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) let record = await db.get(ctx.params.id) - const model = await db.get(record.modelId) + const table = await db.get(record.tableId) const patchfields = ctx.request.body - record = coerceRecordValues(record, model) + record = coerceRecordValues(record, table) for (let key of Object.keys(patchfields)) { - if (!model.schema[key]) continue + if (!table.schema[key]) continue record[key] = patchfields[key] } const validateResult = await validate({ record, - model, + table, }) if (!validateResult.valid) { @@ -53,40 +53,40 @@ exports.patch = async function(ctx) { instanceId, eventType: linkRecords.EventType.RECORD_UPDATE, record, - modelId: record.modelId, - model, + tableId: record.tableId, + table, }) const response = await db.put(record) record._rev = response.rev record.type = "record" ctx.eventEmitter && - ctx.eventEmitter.emitRecord(`record:update`, instanceId, record, model) + ctx.eventEmitter.emitRecord(`record:update`, instanceId, record, table) ctx.body = record ctx.status = 200 - ctx.message = `${model.name} updated successfully.` + ctx.message = `${table.name} updated successfully.` } exports.save = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) let record = ctx.request.body - record.modelId = ctx.params.modelId + record.tableId = ctx.params.tableId if (!record._rev && !record._id) { - record._id = generateRecordID(record.modelId) + record._id = generateRecordID(record.tableId) } // if the record obj had an _id then it will have been retrieved const existingRecord = ctx.preExisting - const model = await db.get(record.modelId) + const table = await db.get(record.tableId) - record = coerceRecordValues(record, model) + record = coerceRecordValues(record, table) const validateResult = await validate({ record, - model, + table, }) if (!validateResult.valid) { @@ -103,8 +103,8 @@ exports.save = async function(ctx) { instanceId, eventType: linkRecords.EventType.RECORD_SAVE, record, - modelId: record.modelId, - model, + tableId: record.tableId, + table, }) if (existingRecord) { @@ -113,7 +113,7 @@ exports.save = async function(ctx) { record.type = "record" ctx.body = record ctx.status = 200 - ctx.message = `${model.name} updated successfully.` + ctx.message = `${table.name} updated successfully.` return } @@ -122,10 +122,10 @@ exports.save = async function(ctx) { record._rev = response.rev ctx.eventEmitter && - ctx.eventEmitter.emitRecord(`record:save`, instanceId, record, model) + ctx.eventEmitter.emitRecord(`record:save`, instanceId, record, table) ctx.body = record ctx.status = 200 - ctx.message = `${model.name} created successfully` + ctx.message = `${table.name} created successfully` } exports.fetchView = async function(ctx) { @@ -134,10 +134,10 @@ exports.fetchView = async function(ctx) { const { stats, group, field } = ctx.query const viewName = ctx.params.viewName - // if this is a model view being looked for just transfer to that - if (viewName.indexOf(MODEL_VIEW_BEGINS_WITH) === 0) { - ctx.params.modelId = viewName.substring(4) - await exports.fetchModelRecords(ctx) + // if this is a table view being looked for just transfer to that + if (viewName.indexOf(TABLE_VIEW_BEGINS_WITH) === 0) { + ctx.params.tableId = viewName.substring(4) + await exports.fetchTableRecords(ctx) return } @@ -160,11 +160,11 @@ exports.fetchView = async function(ctx) { ctx.body = await linkRecords.attachLinkInfo(instanceId, response.rows) } -exports.fetchModelRecords = async function(ctx) { +exports.fetchTableRecords = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) const response = await db.allDocs( - getRecordParams(ctx.params.modelId, null, { + getRecordParams(ctx.params.tableId, null, { include_docs: true, }) ) @@ -192,8 +192,8 @@ exports.find = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) const record = await db.get(ctx.params.recordId) - if (record.modelId !== ctx.params.modelId) { - ctx.throw(400, "Supplied modelId does not match the records modelId") + if (record.tableId !== ctx.params.tableId) { + ctx.throw(400, "Supplied tableId does not match the records tableId") return } ctx.body = await linkRecords.attachLinkInfo(instanceId, record) @@ -203,15 +203,15 @@ exports.destroy = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) const record = await db.get(ctx.params.recordId) - if (record.modelId !== ctx.params.modelId) { - ctx.throw(400, "Supplied modelId doesn't match the record's modelId") + if (record.tableId !== ctx.params.tableId) { + ctx.throw(400, "Supplied tableId doesn't match the record's tableId") return } await linkRecords.updateLinks({ instanceId, eventType: linkRecords.EventType.RECORD_DELETE, record, - modelId: record.modelId, + tableId: record.tableId, }) ctx.body = await db.remove(ctx.params.recordId, ctx.params.revId) ctx.status = 200 @@ -225,23 +225,23 @@ exports.destroy = async function(ctx) { exports.validate = async function(ctx) { const errors = await validate({ instanceId: ctx.user.instanceId, - modelId: ctx.params.modelId, + tableId: ctx.params.tableId, record: ctx.request.body, }) ctx.status = 200 ctx.body = errors } -async function validate({ instanceId, modelId, record, model }) { - if (!model) { +async function validate({ instanceId, tableId, record, table }) { + if (!table) { const db = new CouchDB(instanceId) - model = await db.get(modelId) + table = await db.get(tableId) } const errors = {} - for (let fieldName of Object.keys(model.schema)) { + for (let fieldName of Object.keys(table.schema)) { const res = validateJs.single( record[fieldName], - model.schema[fieldName].constraints + table.schema[fieldName].constraints ) if (res) errors[fieldName] = res } @@ -251,9 +251,9 @@ async function validate({ instanceId, modelId, record, model }) { exports.fetchEnrichedRecord = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) - const modelId = ctx.params.modelId + const tableId = ctx.params.tableId const recordId = ctx.params.recordId - if (instanceId == null || modelId == null || recordId == null) { + if (instanceId == null || tableId == null || recordId == null) { ctx.status = 400 ctx.body = { status: 400, @@ -262,12 +262,12 @@ exports.fetchEnrichedRecord = async function(ctx) { } return } - // need model to work out where links go in record - const [model, record] = await Promise.all([db.get(modelId), db.get(recordId)]) + // need table to work out where links go in record + const [table, record] = await Promise.all([db.get(tableId), db.get(recordId)]) // get the link docs const linkVals = await linkRecords.getLinkDocuments({ instanceId, - modelId, + tableId, recordId, }) // look up the actual records based on the ids @@ -281,11 +281,11 @@ exports.fetchEnrichedRecord = async function(ctx) { response.rows.map(row => row.doc) ) // insert the link records in the correct place throughout the main record - for (let fieldName of Object.keys(model.schema)) { - let field = model.schema[fieldName] + for (let fieldName of Object.keys(table.schema)) { + let field = table.schema[fieldName] if (field.type === "link") { record[fieldName] = linkedRecords.filter( - linkRecord => linkRecord.modelId === field.modelId + linkRecord => linkRecord.tableId === field.tableId ) } } @@ -293,10 +293,10 @@ exports.fetchEnrichedRecord = async function(ctx) { ctx.status = 200 } -function coerceRecordValues(rec, model) { +function coerceRecordValues(rec, table) { const record = cloneDeep(rec) for (let [key, value] of Object.entries(record)) { - const field = model.schema[key] + const field = table.schema[key] if (!field) continue // eslint-disable-next-line no-prototype-builtins diff --git a/packages/server/src/api/controllers/model.js b/packages/server/src/api/controllers/table.js similarity index 59% rename from packages/server/src/api/controllers/model.js rename to packages/server/src/api/controllers/table.js index 87a2449f76..e19b752501 100644 --- a/packages/server/src/api/controllers/model.js +++ b/packages/server/src/api/controllers/table.js @@ -3,15 +3,15 @@ const linkRecords = require("../../db/linkedRecords") const csvParser = require("../../utilities/csvParser") const { getRecordParams, - getModelParams, - generateModelID, + getTableParams, + generateTableID, generateRecordID, } = require("../../db/utils") exports.fetch = async function(ctx) { const db = new CouchDB(ctx.user.instanceId) const body = await db.allDocs( - getModelParams(null, { + getTableParams(null, { include_docs: true, }) ) @@ -27,25 +27,25 @@ exports.save = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) const { dataImport, ...rest } = ctx.request.body - const modelToSave = { - type: "model", - _id: generateModelID(), + const tableToSave = { + type: "table", + _id: generateTableID(), views: {}, ...rest, } - // if the model obj had an _id then it will have been retrieved - const oldModel = ctx.preExisting + // if the table obj had an _id then it will have been retrieved + const oldTable = ctx.preExisting // rename record fields when table column is renamed - const { _rename } = modelToSave - if (_rename && modelToSave.schema[_rename.updated].type === "link") { + const { _rename } = tableToSave + if (_rename && tableToSave.schema[_rename.updated].type === "link") { throw "Cannot rename a linked field." - } else if (_rename && modelToSave.primaryDisplay === _rename.old) { + } else if (_rename && tableToSave.primaryDisplay === _rename.old) { throw "Cannot rename the primary display field." } else if (_rename) { const records = await db.allDocs( - getRecordParams(modelToSave._id, null, { + getRecordParams(tableToSave._id, null, { include_docs: true, }) ) @@ -57,62 +57,62 @@ exports.save = async function(ctx) { }) await db.bulkDocs(docs) - delete modelToSave._rename + delete tableToSave._rename } // update schema of non-statistics views when new columns are added - for (let view in modelToSave.views) { - const modelView = modelToSave.views[view] - if (!modelView) continue + for (let view in tableToSave.views) { + const tableView = tableToSave.views[view] + if (!tableView) continue - if (modelView.schema.group || modelView.schema.field) continue - modelView.schema = modelToSave.schema + if (tableView.schema.group || tableView.schema.field) continue + tableView.schema = tableToSave.schema } - const result = await db.post(modelToSave) - modelToSave._rev = result.rev + const result = await db.post(tableToSave) + tableToSave._rev = result.rev // update linked records await linkRecords.updateLinks({ instanceId, - eventType: oldModel - ? linkRecords.EventType.MODEL_UPDATED - : linkRecords.EventType.MODEL_SAVE, - model: modelToSave, - oldModel: oldModel, + eventType: oldTable + ? linkRecords.EventType.TABLE_UPDATED + : linkRecords.EventType.TABLE_SAVE, + table: tableToSave, + oldTable: oldTable, }) ctx.eventEmitter && - ctx.eventEmitter.emitModel(`model:save`, instanceId, modelToSave) + ctx.eventEmitter.emitTable(`table:save`, instanceId, tableToSave) if (dataImport && dataImport.path) { // Populate the table with records imported from CSV in a bulk update const data = await csvParser.transform(dataImport) for (let row of data) { - row._id = generateRecordID(modelToSave._id) - row.modelId = modelToSave._id + row._id = generateRecordID(tableToSave._id) + row.tableId = tableToSave._id } await db.bulkDocs(data) } ctx.status = 200 - ctx.message = `Model ${ctx.request.body.name} saved successfully.` - ctx.body = modelToSave + ctx.message = `Table ${ctx.request.body.name} saved successfully.` + ctx.body = tableToSave } exports.destroy = async function(ctx) { const instanceId = ctx.user.instanceId const db = new CouchDB(instanceId) - const modelToDelete = await db.get(ctx.params.modelId) + const tableToDelete = await db.get(ctx.params.tableId) - await db.remove(modelToDelete) + await db.remove(tableToDelete) - // Delete all records for that model + // Delete all records for that table const records = await db.allDocs( - getRecordParams(ctx.params.modelId, null, { + getRecordParams(ctx.params.tableId, null, { include_docs: true, }) ) @@ -123,14 +123,14 @@ exports.destroy = async function(ctx) { // update linked records await linkRecords.updateLinks({ instanceId, - eventType: linkRecords.EventType.MODEL_DELETE, - model: modelToDelete, + eventType: linkRecords.EventType.TABLE_DELETE, + table: tableToDelete, }) ctx.eventEmitter && - ctx.eventEmitter.emitModel(`model:delete`, instanceId, modelToDelete) + ctx.eventEmitter.emitTable(`table:delete`, instanceId, tableToDelete) ctx.status = 200 - ctx.message = `Model ${ctx.params.modelId} deleted.` + ctx.message = `Table ${ctx.params.tableId} deleted.` } exports.validateCSVSchema = async function(ctx) { diff --git a/packages/server/src/api/controllers/view/index.js b/packages/server/src/api/controllers/view/index.js index 1c98466b7a..791046674b 100644 --- a/packages/server/src/api/controllers/view/index.js +++ b/packages/server/src/api/controllers/view/index.js @@ -45,21 +45,21 @@ const controller = { await db.put(designDoc) - // add views to model document - const model = await db.get(ctx.request.body.modelId) - if (!model.views) model.views = {} + // add views to table document + const table = await db.get(ctx.request.body.tableId) + if (!table.views) table.views = {} if (!view.meta.schema) { - view.meta.schema = model.schema + view.meta.schema = table.schema } - model.views[viewToSave.name] = view.meta + table.views[viewToSave.name] = view.meta if (originalName) { - delete model.views[originalName] + delete table.views[originalName] } - await db.put(model) + await db.put(table) - ctx.body = model.views[viewToSave.name] + ctx.body = table.views[viewToSave.name] ctx.message = `View ${viewToSave.name} saved successfully.` }, destroy: async ctx => { @@ -74,9 +74,9 @@ const controller = { await db.put(designDoc) - const model = await db.get(view.meta.modelId) - delete model.views[viewName] - await db.put(model) + const table = await db.get(view.meta.tableId) + delete table.views[viewName] + await db.put(table) ctx.body = view ctx.message = `View ${ctx.params.viewName} saved successfully.` diff --git a/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap b/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap index a2fb80f583..a5a0aba028 100644 --- a/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap +++ b/packages/server/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap @@ -3,7 +3,7 @@ exports[`viewBuilder Calculate creates a view with the calculation statistics schema 1`] = ` Object { "map": "function (doc) { - if (doc.modelId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" ) { + if (doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" ) { emit(doc[\\"_id\\"], doc[\\"myField\\"]); } }", @@ -12,7 +12,7 @@ Object { "field": "myField", "filters": Array [], "groupBy": undefined, - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "schema": Object { "avg": Object { "type": "number", @@ -44,7 +44,7 @@ Object { exports[`viewBuilder Filter creates a view with multiple filters and conjunctions 1`] = ` Object { "map": "function (doc) { - if (doc.modelId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" && doc[\\"Name\\"] === \\"Test\\" || doc[\\"Yes\\"] > \\"Value\\") { + if (doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" && doc[\\"Name\\"] === \\"Test\\" || doc[\\"Yes\\"] > \\"Value\\") { emit(doc._id); } }", @@ -65,7 +65,7 @@ Object { }, ], "groupBy": undefined, - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "schema": null, }, } @@ -74,7 +74,7 @@ Object { exports[`viewBuilder Group By creates a view emitting the group by field 1`] = ` Object { "map": "function (doc) { - if (doc.modelId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" ) { + if (doc.tableId === \\"14f1c4e94d6a47b682ce89d35d4c78b0\\" ) { emit(doc[\\"age\\"], doc[\\"score\\"]); } }", @@ -83,7 +83,7 @@ Object { "field": "score", "filters": Array [], "groupBy": "age", - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "schema": null, }, "reduce": "_stats", diff --git a/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js b/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js index 555c5e71fb..d1674bca08 100644 --- a/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js +++ b/packages/server/src/api/controllers/view/tests/viewBuilder.spec.js @@ -6,7 +6,7 @@ describe("viewBuilder", () => { it("creates a view with multiple filters and conjunctions", () => { expect(viewTemplate({ "name": "Test View", - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "filters": [{ "value": "Test", "condition": "EQUALS", @@ -27,7 +27,7 @@ describe("viewBuilder", () => { "name": "Calculate View", "field": "myField", "calculation": "stats", - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "filters": [] })).toMatchSnapshot() }) @@ -37,7 +37,7 @@ describe("viewBuilder", () => { it("creates a view emitting the group by field", () => { expect(viewTemplate({ "name": "Test Scores Grouped By Age", - "modelId": "14f1c4e94d6a47b682ce89d35d4c78b0", + "tableId": "14f1c4e94d6a47b682ce89d35d4c78b0", "groupBy": "age", "field": "score", "filters": [], diff --git a/packages/server/src/api/controllers/view/viewBuilder.js b/packages/server/src/api/controllers/view/viewBuilder.js index 036f68ecc6..df1c3daef9 100644 --- a/packages/server/src/api/controllers/view/viewBuilder.js +++ b/packages/server/src/api/controllers/view/viewBuilder.js @@ -90,12 +90,12 @@ function parseEmitExpression(field, groupBy) { * * @param {Object} viewDefinition - the JSON definition for a custom view. * field: field that calculations will be performed on - * modelId: modelId of the model this view was created from + * tableId: tableId of the table this view was created from * groupBy: field that calculations will be grouped by. Field must be present for this to be useful * filters: Array of filter objects containing predicates that are parsed into a JS expression * calculation: an optional calculation to be performed over the view data. */ -function viewTemplate({ field, modelId, groupBy, filters = [], calculation }) { +function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) { const parsedFilters = parseFilterExpression(filters) const filterExpression = parsedFilters ? `&& ${parsedFilters}` : "" @@ -115,14 +115,14 @@ function viewTemplate({ field, modelId, groupBy, filters = [], calculation }) { return { meta: { field, - modelId, + tableId, groupBy, filters, schema, calculation, }, map: `function (doc) { - if (doc.modelId === "${modelId}" ${filterExpression}) { + if (doc.tableId === "${tableId}" ${filterExpression}) { ${emitExpression} } }`, diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 2688baf832..de93ae2a78 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -12,7 +12,7 @@ const { clientRoutes, applicationRoutes, recordRoutes, - modelRoutes, + tableRoutes, viewRoutes, staticRoutes, componentRoutes, @@ -74,8 +74,8 @@ router.use(authRoutes.allowedMethods()) router.use(viewRoutes.routes()) router.use(viewRoutes.allowedMethods()) -router.use(modelRoutes.routes()) -router.use(modelRoutes.allowedMethods()) +router.use(tableRoutes.routes()) +router.use(tableRoutes.allowedMethods()) router.use(recordRoutes.routes()) router.use(recordRoutes.allowedMethods()) diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js index d24ef50935..7884ca0a7b 100644 --- a/packages/server/src/api/routes/index.js +++ b/packages/server/src/api/routes/index.js @@ -4,7 +4,7 @@ const userRoutes = require("./user") const instanceRoutes = require("./instance") const clientRoutes = require("./client") const applicationRoutes = require("./application") -const modelRoutes = require("./model") +const tableRoutes = require("./table") const recordRoutes = require("./record") const viewRoutes = require("./view") const staticRoutes = require("./static") @@ -25,7 +25,7 @@ module.exports = { clientRoutes, applicationRoutes, recordRoutes, - modelRoutes, + tableRoutes, viewRoutes, staticRoutes, componentRoutes, diff --git a/packages/server/src/api/routes/model.js b/packages/server/src/api/routes/model.js deleted file mode 100644 index fe782d4cf5..0000000000 --- a/packages/server/src/api/routes/model.js +++ /dev/null @@ -1,27 +0,0 @@ -const Router = require("@koa/router") -const modelController = require("../controllers/model") -const authorized = require("../../middleware/authorized") -const { BUILDER, READ_MODEL } = require("../../utilities/accessLevels") - -const router = Router() - -router - .get("/api/models", authorized(BUILDER), modelController.fetch) - .get( - "/api/models/:id", - authorized(READ_MODEL, ctx => ctx.params.id), - modelController.find - ) - .post("/api/models", authorized(BUILDER), modelController.save) - .post( - "/api/models/csv/validate", - authorized(BUILDER), - modelController.validateCSVSchema - ) - .delete( - "/api/models/:modelId/:revId", - authorized(BUILDER), - modelController.destroy - ) - -module.exports = router diff --git a/packages/server/src/api/routes/record.js b/packages/server/src/api/routes/record.js index b3b5e9ed56..a6c5271f14 100644 --- a/packages/server/src/api/routes/record.js +++ b/packages/server/src/api/routes/record.js @@ -2,46 +2,46 @@ const Router = require("@koa/router") const recordController = require("../controllers/record") const authorized = require("../../middleware/authorized") const usage = require("../../middleware/usageQuota") -const { READ_MODEL, WRITE_MODEL } = require("../../utilities/accessLevels") +const { READ_TABLE, WRITE_TABLE } = require("../../utilities/accessLevels") const router = Router() router .get( - "/api/:modelId/:recordId/enrich", - authorized(READ_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/:recordId/enrich", + authorized(READ_TABLE, ctx => ctx.params.tableId), recordController.fetchEnrichedRecord ) .get( - "/api/:modelId/records", - authorized(READ_MODEL, ctx => ctx.params.modelId), - recordController.fetchModelRecords + "/api/:tableId/records", + authorized(READ_TABLE, ctx => ctx.params.tableId), + recordController.fetchTableRecords ) .get( - "/api/:modelId/records/:recordId", - authorized(READ_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/records/:recordId", + authorized(READ_TABLE, ctx => ctx.params.tableId), recordController.find ) .post("/api/records/search", recordController.search) .post( - "/api/:modelId/records", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/records", + authorized(WRITE_TABLE, ctx => ctx.params.tableId), usage, recordController.save ) .patch( - "/api/:modelId/records/:id", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/records/:id", + authorized(WRITE_TABLE, ctx => ctx.params.tableId), recordController.patch ) .post( - "/api/:modelId/records/validate", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/records/validate", + authorized(WRITE_TABLE, ctx => ctx.params.tableId), recordController.validate ) .delete( - "/api/:modelId/records/:recordId/:revId", - authorized(WRITE_MODEL, ctx => ctx.params.modelId), + "/api/:tableId/records/:recordId/:revId", + authorized(WRITE_TABLE, ctx => ctx.params.tableId), usage, recordController.destroy ) diff --git a/packages/server/src/api/routes/table.js b/packages/server/src/api/routes/table.js new file mode 100644 index 0000000000..40bfa9326f --- /dev/null +++ b/packages/server/src/api/routes/table.js @@ -0,0 +1,27 @@ +const Router = require("@koa/router") +const tableController = require("../controllers/table") +const authorized = require("../../middleware/authorized") +const { BUILDER, READ_TABLE } = require("../../utilities/accessLevels") + +const router = Router() + +router + .get("/api/tables", authorized(BUILDER), tableController.fetch) + .get( + "/api/tables/:id", + authorized(READ_TABLE, ctx => ctx.params.id), + tableController.find + ) + .post("/api/tables", authorized(BUILDER), tableController.save) + .post( + "/api/tables/csv/validate", + authorized(BUILDER), + tableController.validateCSVSchema + ) + .delete( + "/api/tables/:tableId/:revId", + authorized(BUILDER), + tableController.destroy + ) + +module.exports = router diff --git a/packages/server/src/api/routes/tests/accesslevel.spec.js b/packages/server/src/api/routes/tests/accesslevel.spec.js index b2878e92ed..79f92e8a69 100644 --- a/packages/server/src/api/routes/tests/accesslevel.spec.js +++ b/packages/server/src/api/routes/tests/accesslevel.spec.js @@ -2,7 +2,7 @@ const { createInstance, createClientDatabase, createApplication, - createModel, + createTable, createView, supertest, defaultHeaders @@ -12,8 +12,8 @@ const { generatePowerUserPermissions, POWERUSER_LEVEL_ID, ADMIN_LEVEL_ID, - READ_MODEL, - WRITE_MODEL, + READ_TABLE, + WRITE_TABLE, } = require("../../../utilities/accessLevels") describe("/accesslevels", () => { @@ -21,7 +21,7 @@ describe("/accesslevels", () => { let server let request let instanceId - let model + let table let view beforeAll(async () => { @@ -36,8 +36,8 @@ describe("/accesslevels", () => { beforeEach(async () => { instanceId = (await createInstance(request, appId))._id - model = await createModel(request, appId, instanceId) - view = await createView(request, appId, instanceId, model._id) + table = await createTable(request, appId, instanceId) + view = await createView(request, appId, instanceId, table._id) }) describe("create", () => { @@ -63,7 +63,7 @@ describe("/accesslevels", () => { it("should list custom levels, plus 2 default levels", async () => { const createRes = await request .post(`/api/accesslevels`) - .send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL }] }) + .send({ name: "user", permissions: [ { itemId: table._id, name: READ_TABLE }] }) .set(defaultHeaders(appId, instanceId)) .expect('Content-Type', /json/) .expect(200) @@ -96,7 +96,7 @@ describe("/accesslevels", () => { it("should delete custom access level", async () => { const createRes = await request .post(`/api/accesslevels`) - .send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL } ] }) + .send({ name: "user", permissions: [ { itemId: table._id, name: READ_TABLE } ] }) .set(defaultHeaders(appId, instanceId)) .expect('Content-Type', /json/) .expect(200) @@ -119,7 +119,7 @@ describe("/accesslevels", () => { it("should add given permissions", async () => { const createRes = await request .post(`/api/accesslevels`) - .send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL }] }) + .send({ name: "user", permissions: [ { itemId: table._id, name: READ_TABLE }] }) .set(defaultHeaders(appId, instanceId)) .expect('Content-Type', /json/) .expect(200) @@ -130,7 +130,7 @@ describe("/accesslevels", () => { .patch(`/api/accesslevels/${customLevel._id}`) .send({ _rev: customLevel._rev, - addedPermissions: [ { itemId: model._id, name: WRITE_MODEL } ] + addedPermissions: [ { itemId: table._id, name: WRITE_TABLE } ] }) .set(defaultHeaders(appId, instanceId)) .expect('Content-Type', /json/) @@ -142,8 +142,8 @@ describe("/accesslevels", () => { .expect(200) expect(finalRes.body.permissions.length).toBe(2) - expect(finalRes.body.permissions.some(p => p.name === WRITE_MODEL)).toBe(true) - expect(finalRes.body.permissions.some(p => p.name === READ_MODEL)).toBe(true) + expect(finalRes.body.permissions.some(p => p.name === WRITE_TABLE)).toBe(true) + expect(finalRes.body.permissions.some(p => p.name === READ_TABLE)).toBe(true) }) it("should remove given permissions", async () => { @@ -152,8 +152,8 @@ describe("/accesslevels", () => { .send({ name: "user", permissions: [ - { itemId: model._id, name: READ_MODEL }, - { itemId: model._id, name: WRITE_MODEL }, + { itemId: table._id, name: READ_TABLE }, + { itemId: table._id, name: WRITE_TABLE }, ] }) .set(defaultHeaders(appId, instanceId)) @@ -166,7 +166,7 @@ describe("/accesslevels", () => { .patch(`/api/accesslevels/${customLevel._id}`) .send({ _rev: customLevel._rev, - removedPermissions: [ { itemId: model._id, name: WRITE_MODEL }] + removedPermissions: [ { itemId: table._id, name: WRITE_TABLE }] }) .set(defaultHeaders(appId, instanceId)) .expect('Content-Type', /json/) @@ -178,7 +178,7 @@ describe("/accesslevels", () => { .expect(200) expect(finalRes.body.permissions.length).toBe(1) - expect(finalRes.body.permissions.some(p => p.name === READ_MODEL)).toBe(true) + expect(finalRes.body.permissions.some(p => p.name === READ_TABLE)).toBe(true) }) }) }); diff --git a/packages/server/src/api/routes/tests/automation.spec.js b/packages/server/src/api/routes/tests/automation.spec.js index 52fe59ad29..bd90620a2b 100644 --- a/packages/server/src/api/routes/tests/automation.spec.js +++ b/packages/server/src/api/routes/tests/automation.spec.js @@ -2,8 +2,8 @@ const { createClientDatabase, createApplication, createInstance, - createModel, - getAllFromModel, + createTable, + getAllFromTable, defaultHeaders, supertest, insertDocument, @@ -167,9 +167,9 @@ describe("/automations", () => { describe("trigger", () => { it("trigger the automation successfully", async () => { - let model = await createModel(request, app._id, instance._id) - TEST_AUTOMATION.definition.trigger.inputs.modelId = model._id - TEST_AUTOMATION.definition.steps[0].inputs.record.modelId = model._id + let table = await createTable(request, app._id, instance._id) + TEST_AUTOMATION.definition.trigger.inputs.tableId = table._id + TEST_AUTOMATION.definition.steps[0].inputs.record.tableId = table._id await createAutomation() // this looks a bit mad but we don't actually have a way to wait for a response from the automation to // know that it has finished all of its actions - this is currently the best way @@ -180,7 +180,7 @@ describe("/automations", () => { expect(res.body.message).toEqual(`Automation ${automation._id} has been triggered.`) expect(res.body.automation.name).toEqual(TEST_AUTOMATION.name) await delay(500) - let elements = await getAllFromModel(request, app._id, instance._id, model._id) + let elements = await getAllFromTable(request, app._id, instance._id, table._id) // don't test it unless there are values to test if (elements.length === 1) { expect(elements.length).toEqual(1) diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js index 0e2fe88ede..b4abf52ea4 100644 --- a/packages/server/src/api/routes/tests/couchTestUtils.js +++ b/packages/server/src/api/routes/tests/couchTestUtils.js @@ -39,13 +39,13 @@ exports.defaultHeaders = (appId, instanceId) => { } } -exports.createModel = async (request, appId, instanceId, model) => { - if (model != null && model._id) { - delete model._id +exports.createTable = async (request, appId, instanceId, table) => { + if (table != null && table._id) { + delete table._id } - model = model || { - name: "TestModel", - type: "model", + table = table || { + name: "TestTable", + type: "table", key: "name", schema: { name: { @@ -64,23 +64,23 @@ exports.createModel = async (request, appId, instanceId, model) => { } const res = await request - .post(`/api/models`) + .post(`/api/tables`) .set(exports.defaultHeaders(appId, instanceId)) - .send(model) + .send(table) return res.body } -exports.getAllFromModel = async (request, appId, instanceId, modelId) => { +exports.getAllFromTable = async (request, appId, instanceId, tableId) => { const res = await request - .get(`/api/${modelId}/records`) + .get(`/api/${tableId}/records`) .set(exports.defaultHeaders(appId, instanceId)) return res.body } -exports.createView = async (request, appId, instanceId, modelId, view) => { +exports.createView = async (request, appId, instanceId, tableId, view) => { view = view || { map: "function(doc) { emit(doc[doc.key], doc._id); } ", - modelId: modelId, + tableId: tableId, } const res = await request diff --git a/packages/server/src/api/routes/tests/record.spec.js b/packages/server/src/api/routes/tests/record.spec.js index 1b0381a924..912b46c5c8 100644 --- a/packages/server/src/api/routes/tests/record.spec.js +++ b/packages/server/src/api/routes/tests/record.spec.js @@ -2,7 +2,7 @@ const { createApplication, createClientDatabase, createInstance, - createModel, + createTable, supertest, defaultHeaders, } = require("./couchTestUtils"); @@ -11,7 +11,7 @@ describe("/records", () => { let request let server let instance - let model + let table let record let app @@ -27,18 +27,18 @@ describe("/records", () => { beforeEach(async () => { instance = await createInstance(request, app._id) - model = await createModel(request, app._id, instance._id) + table = await createTable(request, app._id, instance._id) record = { name: "Test Contact", description: "original description", status: "new", - modelId: model._id + tableId: table._id } }) const createRecord = async r => await request - .post(`/api/${r ? r.modelId : record.modelId}/records`) + .post(`/api/${r ? r.tableId : record.tableId}/records`) .send(r || record) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) @@ -46,7 +46,7 @@ describe("/records", () => { const loadRecord = async id => await request - .get(`/api/${model._id}/records/${id}`) + .get(`/api/${table._id}/records/${id}`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) @@ -57,7 +57,7 @@ describe("/records", () => { it("returns a success message when the record is created", async () => { const res = await createRecord() - expect(res.res.statusMessage).toEqual(`${model.name} created successfully`) + expect(res.res.statusMessage).toEqual(`${table.name} created successfully`) expect(res.body.name).toEqual("Test Contact") expect(res.body._rev).toBeDefined() }) @@ -67,18 +67,18 @@ describe("/records", () => { const existing = rec.body const res = await request - .post(`/api/${model._id}/records`) + .post(`/api/${table._id}/records`) .send({ _id: existing._id, _rev: existing._rev, - modelId: model._id, + tableId: table._id, name: "Updated Name", }) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) - expect(res.res.statusMessage).toEqual(`${model.name} updated successfully.`) + expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`) expect(res.body.name).toEqual("Updated Name") }) @@ -87,7 +87,7 @@ describe("/records", () => { const existing = rec.body const res = await request - .get(`/api/${model._id}/records/${existing._id}`) + .get(`/api/${table._id}/records/${existing._id}`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) @@ -100,9 +100,9 @@ describe("/records", () => { }) }) - it("should list all records for given modelId", async () => { + it("should list all records for given tableId", async () => { const newRecord = { - modelId: model._id, + tableId: table._id, name: "Second Contact", status: "new" } @@ -110,7 +110,7 @@ describe("/records", () => { await createRecord(newRecord) const res = await request - .get(`/api/${model._id}/records`) + .get(`/api/${table._id}/records`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) @@ -122,7 +122,7 @@ describe("/records", () => { it("lists records when queried by their ID", async () => { const newRecord = { - modelId: model._id, + tableId: table._id, name: "Second Contact", status: "new" } @@ -147,7 +147,7 @@ describe("/records", () => { it("load should return 404 when record does not exist", async () => { await createRecord() await request - .get(`/api/${model._id}/records/not-a-valid-id`) + .get(`/api/${table._id}/records/not-a-valid-id`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(404) @@ -160,9 +160,9 @@ describe("/records", () => { const number = {type:"number", constraints: { type: "number", presence: false }} const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }} - model = await createModel(request, app._id, instance._id, { - name: "TestModel2", - type: "model", + table = await createTable(request, app._id, instance._id, { + name: "TestTable2", + type: "table", key: "name", schema: { name: str, @@ -209,7 +209,7 @@ describe("/records", () => { boolUndefined: undefined, boolString: "true", boolBool: true, - modelId: model._id, + tableId: table._id, attachmentNull : null, attachmentUndefined : undefined, attachmentEmpty : "", @@ -249,18 +249,18 @@ describe("/records", () => { const existing = rec.body const res = await request - .patch(`/api/${model._id}/records/${existing._id}`) + .patch(`/api/${table._id}/records/${existing._id}`) .send({ _id: existing._id, _rev: existing._rev, - modelId: model._id, + tableId: table._id, name: "Updated Name", }) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) - expect(res.res.statusMessage).toEqual(`${model.name} updated successfully.`) + expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`) expect(res.body.name).toEqual("Updated Name") expect(res.body.description).toEqual(existing.description) @@ -275,7 +275,7 @@ describe("/records", () => { describe("validate", () => { it("should return no errors on valid record", async () => { const result = await request - .post(`/api/${model._id}/records/validate`) + .post(`/api/${table._id}/records/validate`) .send({ name: "ivan" }) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) @@ -287,7 +287,7 @@ describe("/records", () => { it("should errors on invalid record", async () => { const result = await request - .post(`/api/${model._id}/records/validate`) + .post(`/api/${table._id}/records/validate`) .send({ name: 1 }) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) diff --git a/packages/server/src/api/routes/tests/model.spec.js b/packages/server/src/api/routes/tests/table.spec.js similarity index 63% rename from packages/server/src/api/routes/tests/model.spec.js rename to packages/server/src/api/routes/tests/table.spec.js index 4cc533e1da..03c92b318c 100644 --- a/packages/server/src/api/routes/tests/model.spec.js +++ b/packages/server/src/api/routes/tests/table.spec.js @@ -1,6 +1,6 @@ const { createInstance, - createModel, + createTable, supertest, createClientDatabase, createApplication, @@ -9,7 +9,7 @@ const { getDocument } = require("./couchTestUtils") -describe("/models", () => { +describe("/tables", () => { let request let server let app @@ -30,11 +30,11 @@ describe("/models", () => { instance = await createInstance(request, app._id); }); - it("returns a success message when the model is successfully created", done => { + it("returns a success message when the table is successfully created", done => { request - .post(`/api/models`) + .post(`/api/tables`) .send({ - name: "TestModel", + name: "TestTable", key: "name", schema: { name: { type: "string" } @@ -44,17 +44,17 @@ describe("/models", () => { .expect('Content-Type', /json/) .expect(200) .end(async (err, res) => { - expect(res.res.statusMessage).toEqual("Model TestModel saved successfully."); - expect(res.body.name).toEqual("TestModel"); + expect(res.res.statusMessage).toEqual("Table TestTable saved successfully."); + expect(res.body.name).toEqual("TestTable"); done(); }); }) - it("renames all the record fields for a model when a schema key is renamed", async () => { - const testModel = await createModel(request, app._id, instance._id); + it("renames all the record fields for a table when a schema key is renamed", async () => { + const testTable = await createTable(request, app._id, instance._id); const testRecord = await request - .post(`/api/${testModel._id}/records`) + .post(`/api/${testTable._id}/records`) .send({ name: "test" }) @@ -62,12 +62,12 @@ describe("/models", () => { .expect('Content-Type', /json/) .expect(200) - const updatedModel = await request - .post(`/api/models`) + const updatedTable = await request + .post(`/api/tables`) .send({ - _id: testModel._id, - _rev: testModel._rev, - name: "TestModel", + _id: testTable._id, + _rev: testTable._rev, + name: "TestTable", key: "name", _rename: { old: "name", @@ -81,11 +81,11 @@ describe("/models", () => { .expect('Content-Type', /json/) .expect(200) - expect(updatedModel.res.statusMessage).toEqual("Model TestModel saved successfully."); - expect(updatedModel.body.name).toEqual("TestModel"); + expect(updatedTable.res.statusMessage).toEqual("Table TestTable saved successfully."); + expect(updatedTable.body.name).toEqual("TestTable"); const res = await request - .get(`/api/${testModel._id}/records/${testRecord.body._id}`) + .get(`/api/${testTable._id}/records/${testRecord.body._id}`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) @@ -98,11 +98,11 @@ describe("/models", () => { await builderEndpointShouldBlockNormalUsers({ request, method: "POST", - url: `/api/models`, + url: `/api/tables`, instanceId: instance._id, appId: app._id, body: { - name: "TestModel", + name: "TestTable", key: "name", schema: { name: { type: "string" } @@ -113,27 +113,27 @@ describe("/models", () => { }); describe("fetch", () => { - let testModel + let testTable beforeEach(async () => { instance = await createInstance(request, app._id) - testModel = await createModel(request, app._id, instance._id, testModel) + testTable = await createTable(request, app._id, instance._id, testTable) }); afterEach(() => { - delete testModel._rev + delete testTable._rev }); - it("returns all the models for that instance in the response body", done => { + it("returns all the tables for that instance in the response body", done => { request - .get(`/api/models`) + .get(`/api/tables`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) .end(async (_, res) => { - const fetchedModel = res.body[0]; - expect(fetchedModel.name).toEqual(testModel.name); - expect(fetchedModel.type).toEqual("model"); + const fetchedTable = res.body[0]; + expect(fetchedTable.name).toEqual(testTable.name); + expect(fetchedTable.type).toEqual("table"); done(); }); }) @@ -142,7 +142,7 @@ describe("/models", () => { await builderEndpointShouldBlockNormalUsers({ request, method: "GET", - url: `/api/models`, + url: `/api/tables`, instanceId: instance._id, appId: app._id, }) @@ -150,33 +150,33 @@ describe("/models", () => { }); describe("destroy", () => { - let testModel; + let testTable; beforeEach(async () => { instance = await createInstance(request, app._id) - testModel = await createModel(request, app._id, instance._id, testModel) + testTable = await createTable(request, app._id, instance._id, testTable) }); afterEach(() => { - delete testModel._rev + delete testTable._rev }); - it("returns a success response when a model is deleted.", async done => { + it("returns a success response when a table is deleted.", async done => { request - .delete(`/api/models/${testModel._id}/${testModel._rev}`) + .delete(`/api/tables/${testTable._id}/${testTable._rev}`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) .end(async (_, res) => { - expect(res.res.statusMessage).toEqual(`Model ${testModel._id} deleted.`); + expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`); done(); }); }) - it("deletes linked references to the model after deletion", async done => { - const linkedModel = await createModel(request, app._id, instance._id, { - name: "LinkedModel", - type: "model", + it("deletes linked references to the table after deletion", async done => { + const linkedTable = await createTable(request, app._id, instance._id, { + name: "LinkedTable", + type: "table", key: "name", schema: { name: { @@ -185,9 +185,9 @@ describe("/models", () => { type: "string", }, }, - TestModel: { + TestTable: { type: "link", - modelId: testModel._id, + tableId: testTable._id, constraints: { type: "array" } @@ -196,14 +196,14 @@ describe("/models", () => { }) request - .delete(`/api/models/${testModel._id}/${testModel._rev}`) + .delete(`/api/tables/${testTable._id}/${testTable._rev}`) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) .expect(200) .end(async (_, res) => { - expect(res.res.statusMessage).toEqual(`Model ${testModel._id} deleted.`); - const dependentModel = await getDocument(instance._id, linkedModel._id) - expect(dependentModel.schema.TestModel).not.toBeDefined(); + expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`); + const dependentTable = await getDocument(instance._id, linkedTable._id) + expect(dependentTable.schema.TestTable).not.toBeDefined(); done(); }); }) @@ -212,7 +212,7 @@ describe("/models", () => { await builderEndpointShouldBlockNormalUsers({ request, method: "DELETE", - url: `/api/models/${testModel._id}/${testModel._rev}`, + url: `/api/tables/${testTable._id}/${testTable._rev}`, instanceId: instance._id, appId: app._id, }) diff --git a/packages/server/src/api/routes/tests/view.spec.js b/packages/server/src/api/routes/tests/view.spec.js index d4bdee1283..113e753f3d 100644 --- a/packages/server/src/api/routes/tests/view.spec.js +++ b/packages/server/src/api/routes/tests/view.spec.js @@ -2,7 +2,7 @@ const { createClientDatabase, createApplication, createInstance, - createModel, + createTable, supertest, defaultHeaders, getDocument @@ -13,12 +13,12 @@ describe("/views", () => { let server let app let instance - let model + let table const createView = async (config = { name: "TestView", field: "Price", - modelId: model._id + tableId: table._id }) => await request .post(`/api/views`) @@ -28,7 +28,7 @@ describe("/views", () => { .expect(200) const createRecord = async record => request - .post(`/api/${model._id}/records`) + .post(`/api/${table._id}/records`) .send(record) .set(defaultHeaders(app._id, instance._id)) .expect('Content-Type', /json/) @@ -50,7 +50,7 @@ describe("/views", () => { describe("create", () => { beforeEach(async () => { - model = await createModel(request, app._id, instance._id); + table = await createTable(request, app._id, instance._id); }) it("returns a success message when the view is successfully created", async () => { @@ -58,14 +58,14 @@ describe("/views", () => { expect(res.res.statusMessage).toEqual("View TestView saved successfully."); }) - it("updates the model record with the new view metadata", async () => { + it("updates the table record with the new view metadata", async () => { const res = await createView() expect(res.res.statusMessage).toEqual("View TestView saved successfully."); - const updatedModel = await getDocument(instance._id, model._id) - expect(updatedModel.views).toEqual({ + const updatedTable = await getDocument(instance._id, table._id) + expect(updatedTable.views).toEqual({ TestView: { field: "Price", - modelId: model._id, + tableId: table._id, filters: [], schema: { name: { @@ -88,7 +88,7 @@ describe("/views", () => { describe("fetch", () => { beforeEach(async () => { - model = await createModel(request, app._id, instance._id); + table = await createTable(request, app._id, instance._id); }); it("returns only custom views", async () => { @@ -105,21 +105,21 @@ describe("/views", () => { describe("query", () => { beforeEach(async () => { - model = await createModel(request, app._id, instance._id); + table = await createTable(request, app._id, instance._id); }); it("returns data for the created view", async () => { await createView() await createRecord({ - modelId: model._id, + tableId: table._id, Price: 1000 }) await createRecord({ - modelId: model._id, + tableId: table._id, Price: 2000 }) await createRecord({ - modelId: model._id, + tableId: table._id, Price: 4000 }) const res = await request @@ -136,20 +136,20 @@ describe("/views", () => { name: "TestView", field: "Price", groupBy: "Category", - modelId: model._id + tableId: table._id }) await createRecord({ - modelId: model._id, + tableId: table._id, Price: 1000, Category: "One" }) await createRecord({ - modelId: model._id, + tableId: table._id, Price: 2000, Category: "One" }) await createRecord({ - modelId: model._id, + tableId: table._id, Price: 4000, Category: "Two" }) diff --git a/packages/server/src/automations/automationUtils.js b/packages/server/src/automations/automationUtils.js index 507cbf8542..07095c685a 100644 --- a/packages/server/src/automations/automationUtils.js +++ b/packages/server/src/automations/automationUtils.js @@ -85,32 +85,32 @@ module.exports.cleanInputValues = (inputs, schema) => { /** * Given a record input like a save or update record we need to clean the inputs against a schema that is not part of - * the automation but is instead part of the Table/Model. This function will get the model schema and use it to instead + * the automation but is instead part of the Table/Table. This function will get the table schema and use it to instead * perform the cleanInputValues function on the input record. * - * @param {string} instanceId The instance which the Table/Model is contained under. - * @param {string} modelId The ID of the Table/Model which the schema is to be retrieved for. + * @param {string} instanceId The instance which the Table/Table is contained under. + * @param {string} tableId The ID of the Table/Table which the schema is to be retrieved for. * @param {object} record The input record structure which requires clean-up after having been through mustache statements. * @returns {Promise} The cleaned up records object, will should now have all the required primitive types. */ -module.exports.cleanUpRecord = async (instanceId, modelId, record) => { +module.exports.cleanUpRecord = async (instanceId, tableId, record) => { const db = new CouchDB(instanceId) - const model = await db.get(modelId) + const table = await db.get(tableId) - return module.exports.cleanInputValues(record, { properties: model.schema }) + return module.exports.cleanInputValues(record, { properties: table.schema }) } /** - * A utility function for the cleanUpRecord, which can be used if only the record ID is known (not the model ID) to clean + * A utility function for the cleanUpRecord, which can be used if only the record ID is known (not the table ID) to clean * up a record after mustache statements have been replaced. This is specifically useful for the update record action. * - * @param {string} instanceId The instance which the Table/Model is contained under. - * @param {string} recordId The ID of the record from which the modelId will be extracted, to get the Table/Model schema. + * @param {string} instanceId The instance which the Table/Table is contained under. + * @param {string} recordId The ID of the record from which the tableId will be extracted, to get the Table/Table schema. * @param {object} record The input record structure which requires clean-up after having been through mustache statements. * @returns {Promise} The cleaned up records object, which will now have all the required primitive types. */ module.exports.cleanUpRecordById = async (instanceId, recordId, record) => { const db = new CouchDB(instanceId) const foundRecord = await db.get(recordId) - return module.exports.cleanUpRecord(instanceId, foundRecord.modelId, record) + return module.exports.cleanUpRecord(instanceId, foundRecord.tableId, record) } diff --git a/packages/server/src/automations/steps/createRecord.js b/packages/server/src/automations/steps/createRecord.js index e268f218e2..c5f639cfc4 100644 --- a/packages/server/src/automations/steps/createRecord.js +++ b/packages/server/src/automations/steps/createRecord.js @@ -5,7 +5,7 @@ const usage = require("../../utilities/usageQuota") module.exports.definition = { name: "Create Row", - tagline: "Create a {{inputs.enriched.model.name}} row", + tagline: "Create a {{inputs.enriched.table.name}} row", icon: "ri-save-3-fill", description: "Add a row to your database", type: "ACTION", @@ -17,14 +17,14 @@ module.exports.definition = { record: { type: "object", properties: { - modelId: { + tableId: { type: "string", - customType: "model", + customType: "table", }, }, customType: "record", title: "Table", - required: ["modelId"], + required: ["tableId"], }, }, required: ["record"], @@ -60,18 +60,18 @@ module.exports.definition = { module.exports.run = async function({ inputs, instanceId, apiKey }) { // TODO: better logging of when actions are missed due to missing parameters - if (inputs.record == null || inputs.record.modelId == null) { + if (inputs.record == null || inputs.record.tableId == null) { return } inputs.record = await automationUtils.cleanUpRecord( instanceId, - inputs.record.modelId, + inputs.record.tableId, inputs.record ) - // have to clean up the record, remove the model from it + // have to clean up the record, remove the table from it const ctx = { params: { - modelId: inputs.record.modelId, + tableId: inputs.record.tableId, }, request: { body: inputs.record, diff --git a/packages/server/src/automations/steps/deleteRecord.js b/packages/server/src/automations/steps/deleteRecord.js index 6126895da6..7bb4983224 100644 --- a/packages/server/src/automations/steps/deleteRecord.js +++ b/packages/server/src/automations/steps/deleteRecord.js @@ -6,16 +6,16 @@ module.exports.definition = { description: "Delete a row from your database", icon: "ri-delete-bin-line", name: "Delete Row", - tagline: "Delete a {{inputs.enriched.model.name}} row", + tagline: "Delete a {{inputs.enriched.table.name}} row", type: "ACTION", stepId: "DELETE_RECORD", inputs: {}, schema: { inputs: { properties: { - modelId: { + tableId: { type: "string", - customType: "model", + customType: "table", title: "Table", }, id: { @@ -27,7 +27,7 @@ module.exports.definition = { title: "Row Revision", }, }, - required: ["modelId", "id", "revision"], + required: ["tableId", "id", "revision"], }, outputs: { properties: { @@ -57,7 +57,7 @@ module.exports.run = async function({ inputs, instanceId, apiKey }) { } let ctx = { params: { - modelId: inputs.modelId, + tableId: inputs.tableId, recordId: inputs.id, revId: inputs.revision, }, diff --git a/packages/server/src/automations/steps/updateRecord.js b/packages/server/src/automations/steps/updateRecord.js index 403af5e5cd..dfdf354df3 100644 --- a/packages/server/src/automations/steps/updateRecord.js +++ b/packages/server/src/automations/steps/updateRecord.js @@ -3,7 +3,7 @@ const automationUtils = require("../automationUtils") module.exports.definition = { name: "Update Row", - tagline: "Update a {{inputs.enriched.model.name}} record", + tagline: "Update a {{inputs.enriched.table.name}} record", icon: "ri-refresh-fill", description: "Update a row in your database", type: "ACTION", @@ -70,7 +70,7 @@ module.exports.run = async function({ inputs, instanceId }) { } } - // have to clean up the record, remove the model from it + // have to clean up the record, remove the table from it const ctx = { params: { id: inputs.recordId, diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index 44bf8b14f6..8e4969325a 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -15,20 +15,20 @@ const BUILTIN_DEFINITIONS = { name: "Row Saved", event: "record:save", icon: "ri-save-line", - tagline: "Row is added to {{inputs.enriched.model.name}}", + tagline: "Row is added to {{inputs.enriched.table.name}}", description: "Fired when a row is saved to your database", stepId: "RECORD_SAVED", inputs: {}, schema: { inputs: { properties: { - modelId: { + tableId: { type: "string", - customType: "model", + customType: "table", title: "Table", }, }, - required: ["modelId"], + required: ["tableId"], }, outputs: { properties: { @@ -55,20 +55,20 @@ const BUILTIN_DEFINITIONS = { name: "Row Deleted", event: "record:delete", icon: "ri-delete-bin-line", - tagline: "Row is deleted from {{inputs.enriched.model.name}}", + tagline: "Row is deleted from {{inputs.enriched.table.name}}", description: "Fired when a row is deleted from your database", stepId: "RECORD_DELETED", inputs: {}, schema: { inputs: { properties: { - modelId: { + tableId: { type: "string", - customType: "model", + customType: "table", title: "Table", }, }, - required: ["modelId"], + required: ["tableId"], }, outputs: { properties: { @@ -108,7 +108,7 @@ async function queueRelevantRecordAutomations(event, eventType) { if ( !automation.live || !automationTrigger.inputs || - automationTrigger.inputs.modelId !== event.record.modelId + automationTrigger.inputs.tableId !== event.record.tableId ) { continue } @@ -117,14 +117,14 @@ async function queueRelevantRecordAutomations(event, eventType) { } emitter.on("record:save", async function(event) { - if (!event || !event.record || !event.record.modelId) { + if (!event || !event.record || !event.record.tableId) { return } await queueRelevantRecordAutomations(event, "record:save") }) emitter.on("record:delete", async function(event) { - if (!event || !event.record || !event.record.modelId) { + if (!event || !event.record || !event.record.tableId) { return } await queueRelevantRecordAutomations(event, "record:delete") @@ -132,16 +132,16 @@ emitter.on("record:delete", async function(event) { async function fillRecordOutput(automation, params) { let triggerSchema = automation.definition.trigger - let modelId = triggerSchema.inputs.modelId + let tableId = triggerSchema.inputs.tableId const db = new CouchDB(params.instanceId) try { - let model = await db.get(modelId) + let table = await db.get(tableId) let record = {} - for (let schemaKey of Object.keys(model.schema)) { + for (let schemaKey of Object.keys(table.schema)) { if (params[schemaKey] != null) { continue } - let propSchema = model.schema[schemaKey] + let propSchema = table.schema[schemaKey] switch (propSchema.constraints.type) { case "string": record[schemaKey] = FAKE_STRING @@ -159,7 +159,7 @@ async function fillRecordOutput(automation, params) { } params.record = record } catch (err) { - throw "Failed to find model for trigger" + throw "Failed to find table for trigger" } return params } @@ -169,7 +169,7 @@ module.exports.externalTrigger = async function(automation, params) { if ( automation.definition != null && automation.definition.trigger != null && - automation.definition.trigger.inputs.modelId != null + automation.definition.trigger.inputs.tableId != null ) { params = await fillRecordOutput(automation, params) } diff --git a/packages/server/src/db/linkedRecords/LinkController.js b/packages/server/src/db/linkedRecords/LinkController.js index b006e798c2..649837e658 100644 --- a/packages/server/src/db/linkedRecords/LinkController.js +++ b/packages/server/src/db/linkedRecords/LinkController.js @@ -6,8 +6,8 @@ const { generateLinkID } = require("../utils") * Creates a new link document structure which can be put to the database. It is important to * note that while this talks about linker/linked the link is bi-directional and for all intent * and purposes it does not matter from which direction the link was initiated. - * @param {string} modelId1 The ID of the first model (the linker). - * @param {string} modelId2 The ID of the second model (the linked). + * @param {string} tableId1 The ID of the first table (the linker). + * @param {string} tableId2 The ID of the second table (the linked). * @param {string} fieldName1 The name of the field in the linker table. * @param {string} fieldName2 The name of the field in the linked table. * @param {string} recordId1 The ID of the record which is acting as the linker. @@ -15,65 +15,65 @@ const { generateLinkID } = require("../utils") * @constructor */ function LinkDocument( - modelId1, + tableId1, fieldName1, recordId1, - modelId2, + tableId2, fieldName2, recordId2 ) { // build the ID out of unique references to this link document - this._id = generateLinkID(modelId1, modelId2, recordId1, recordId2) + this._id = generateLinkID(tableId1, tableId2, recordId1, recordId2) // required for referencing in view this.type = "link" this.doc1 = { - modelId: modelId1, + tableId: tableId1, fieldName: fieldName1, recordId: recordId1, } this.doc2 = { - modelId: modelId2, + tableId: tableId2, fieldName: fieldName2, recordId: recordId2, } } class LinkController { - constructor({ instanceId, modelId, record, model, oldModel }) { + constructor({ instanceId, tableId, record, table, oldTable }) { this._instanceId = instanceId this._db = new CouchDB(instanceId) - this._modelId = modelId + this._tableId = tableId this._record = record - this._model = model - this._oldModel = oldModel + this._table = table + this._oldTable = oldTable } /** - * Retrieves the model, if it was not already found in the eventData. - * @returns {Promise} This will return a model based on the event data, either - * if it was in the event already, or it uses the specified modelId to get it. + * Retrieves the table, if it was not already found in the eventData. + * @returns {Promise} This will return a table based on the event data, either + * if it was in the event already, or it uses the specified tableId to get it. */ - async model() { - if (this._model == null) { - this._model = - this._model == null ? await this._db.get(this._modelId) : this._model + async table() { + if (this._table == null) { + this._table = + this._table == null ? await this._db.get(this._tableId) : this._table } - return this._model + return this._table } /** - * Checks if the model this was constructed with has any linking columns currently. - * If the model has not been retrieved this will retrieve it based on the eventData. - * @params {object|null} model If a model that is not known to the link controller is to be tested. + * Checks if the table this was constructed with has any linking columns currently. + * If the table has not been retrieved this will retrieve it based on the eventData. + * @params {object|null} table If a table that is not known to the link controller is to be tested. * @returns {Promise} True if there are any linked fields, otherwise it will return * false. */ - async doesModelHaveLinkedFields(model = null) { - if (model == null) { - model = await this.model() + async doesTableHaveLinkedFields(table = null) { + if (table == null) { + table = await this.table() } - for (let fieldName of Object.keys(model.schema)) { - const { type } = model.schema[fieldName] + for (let fieldName of Object.keys(table.schema)) { + const { type } = table.schema[fieldName] if (type === "link") { return true } @@ -87,7 +87,7 @@ class LinkController { getRecordLinkDocs(recordId) { return getLinkDocuments({ instanceId: this._instanceId, - modelId: this._modelId, + tableId: this._tableId, recordId, includeDocs: IncludeDocs.INCLUDE, }) @@ -96,15 +96,15 @@ class LinkController { /** * Utility function for main getLinkDocuments function - refer to it for functionality. */ - getModelLinkDocs() { + getTableLinkDocs() { return getLinkDocuments({ instanceId: this._instanceId, - modelId: this._modelId, + tableId: this._tableId, includeDocs: IncludeDocs.INCLUDE, }) } - // all operations here will assume that the model + // all operations here will assume that the table // this operation is related to has linked records /** * When a record is saved this will carry out the necessary operations to make sure @@ -113,15 +113,15 @@ class LinkController { * have also been created. */ async recordSaved() { - const model = await this.model() + const table = await this.table() const record = this._record const operations = [] // get link docs to compare against const linkDocs = await this.getRecordLinkDocs(record._id) - for (let fieldName of Object.keys(model.schema)) { + for (let fieldName of Object.keys(table.schema)) { // get the links this record wants to make const recordField = record[fieldName] - const field = model.schema[fieldName] + const field = table.schema[fieldName] if (field.type === "link" && recordField != null) { // check which links actual pertain to the update in this record const thisFieldLinkDocs = linkDocs.filter( @@ -139,10 +139,10 @@ class LinkController { if (linkId && linkId !== "" && linkDocIds.indexOf(linkId) === -1) { operations.push( new LinkDocument( - model._id, + table._id, fieldName, record._id, - field.modelId, + field.tableId, field.fieldName, linkId ) @@ -193,17 +193,17 @@ class LinkController { } /** - * Remove a field from a model as well as any linked records that pertained to it. - * @param {string} fieldName The field to be removed from the model. - * @returns {Promise} The model has now been updated. + * Remove a field from a table as well as any linked records that pertained to it. + * @param {string} fieldName The field to be removed from the table. + * @returns {Promise} The table has now been updated. */ - async removeFieldFromModel(fieldName) { - let oldModel = this._oldModel - let field = oldModel.schema[fieldName] - const linkDocs = await this.getModelLinkDocs() + async removeFieldFromTable(fieldName) { + let oldTable = this._oldTable + let field = oldTable.schema[fieldName] + const linkDocs = await this.getTableLinkDocs() let toDelete = linkDocs.filter(linkDoc => { let correctFieldName = - linkDoc.doc1.modelId === oldModel._id + linkDoc.doc1.tableId === oldTable._id ? linkDoc.doc1.fieldName : linkDoc.doc2.fieldName return correctFieldName === fieldName @@ -216,83 +216,83 @@ class LinkController { } }) ) - // remove schema from other model - let linkedModel = await this._db.get(field.modelId) - delete linkedModel.schema[field.fieldName] - this._db.put(linkedModel) + // remove schema from other table + let linkedTable = await this._db.get(field.tableId) + delete linkedTable.schema[field.fieldName] + this._db.put(linkedTable) } /** - * When a model is saved this will carry out the necessary operations to make sure - * any linked models are notified and updated correctly. + * When a table is saved this will carry out the necessary operations to make sure + * any linked tables are notified and updated correctly. * @returns {Promise} The operation has been completed and the link documents should now - * be accurate. Also returns the model that was operated on. + * be accurate. Also returns the table that was operated on. */ - async modelSaved() { - const model = await this.model() - const schema = model.schema + async tableSaved() { + const table = await this.table() + const schema = table.schema for (let fieldName of Object.keys(schema)) { const field = schema[fieldName] if (field.type === "link") { - // create the link field in the other model - const linkedModel = await this._db.get(field.modelId) - linkedModel.schema[field.fieldName] = { + // create the link field in the other table + const linkedTable = await this._db.get(field.tableId) + linkedTable.schema[field.fieldName] = { name: field.fieldName, type: "link", // these are the props of the table that initiated the link - modelId: model._id, + tableId: table._id, fieldName: fieldName, } - await this._db.put(linkedModel) + await this._db.put(linkedTable) } } - return model + return table } /** - * Update a model, this means if a field is removed need to handle removing from other table and removing + * Update a table, this means if a field is removed need to handle removing from other table and removing * any link docs that pertained to it. - * @returns {Promise} The model which has been saved, same response as with the modelSaved function. + * @returns {Promise} The table which has been saved, same response as with the tableSaved function. */ - async modelUpdated() { - const oldModel = this._oldModel + async tableUpdated() { + const oldTable = this._oldTable // first start by checking if any link columns have been deleted - const newModel = await this.model() - for (let fieldName of Object.keys(oldModel.schema)) { - const field = oldModel.schema[fieldName] - // this field has been removed from the model schema - if (field.type === "link" && newModel.schema[fieldName] == null) { - await this.removeFieldFromModel(fieldName) + const newTable = await this.table() + for (let fieldName of Object.keys(oldTable.schema)) { + const field = oldTable.schema[fieldName] + // this field has been removed from the table schema + if (field.type === "link" && newTable.schema[fieldName] == null) { + await this.removeFieldFromTable(fieldName) } } // now handle as if its a new save - return this.modelSaved() + return this.tableSaved() } /** - * When a model is deleted this will carry out the necessary operations to make sure - * any linked models have the joining column correctly removed as well as removing any + * When a table is deleted this will carry out the necessary operations to make sure + * any linked tables have the joining column correctly removed as well as removing any * now stale linking documents. * @returns {Promise} The operation has been completed and the link documents should now - * be accurate. Also returns the model that was operated on. + * be accurate. Also returns the table that was operated on. */ - async modelDeleted() { - const model = await this.model() - const schema = model.schema + async tableDeleted() { + const table = await this.table() + const schema = table.schema for (let fieldName of Object.keys(schema)) { const field = schema[fieldName] if (field.type === "link") { - const linkedModel = await this._db.get(field.modelId) - delete linkedModel.schema[model.name] - await this._db.put(linkedModel) + const linkedTable = await this._db.get(field.tableId) + delete linkedTable.schema[table.name] + await this._db.put(linkedTable) } } // need to get the full link docs to delete them - const linkDocs = await this.getModelLinkDocs() + const linkDocs = await this.getTableLinkDocs() if (linkDocs.length === 0) { return null } - // get link docs for this model and configure for deletion + // get link docs for this table and configure for deletion const toDelete = linkDocs.map(doc => { return { ...doc, @@ -300,7 +300,7 @@ class LinkController { } }) await this._db.bulkDocs(toDelete) - return model + return table } } diff --git a/packages/server/src/db/linkedRecords/index.js b/packages/server/src/db/linkedRecords/index.js index 115553696c..49473d0380 100644 --- a/packages/server/src/db/linkedRecords/index.js +++ b/packages/server/src/db/linkedRecords/index.js @@ -10,9 +10,9 @@ const EventType = { RECORD_SAVE: "record:save", RECORD_UPDATE: "record:update", RECORD_DELETE: "record:delete", - MODEL_SAVE: "model:save", - MODEL_UPDATED: "model:updated", - MODEL_DELETE: "model:delete", + TABLE_SAVE: "table:save", + TABLE_UPDATED: "table:updated", + TABLE_DELETE: "table:delete", } exports.EventType = EventType @@ -22,37 +22,37 @@ exports.getLinkDocuments = getLinkDocuments exports.createLinkView = createLinkView /** - * Update link documents for a record or model - this is to be called by the API controller when a change is occurring. + * Update link documents for a record or table - this is to be called by the API controller when a change is occurring. * @param {string} eventType states what type of change which is occurring, means this can be expanded upon in the * future quite easily (all updates go through one function). * @param {string} instanceId The ID of the instance in which the change is occurring. - * @param {string} modelId The ID of the of the model which is being changed. + * @param {string} tableId The ID of the of the table which is being changed. * @param {object|null} record The record which is changing, e.g. created, updated or deleted. - * @param {object|null} model If the model has already been retrieved this can be used to reduce database gets. - * @param {object|null} oldModel If the model is being updated then the old model can be provided for differencing. + * @param {object|null} table If the table has already been retrieved this can be used to reduce database gets. + * @param {object|null} oldTable If the table is being updated then the old table can be provided for differencing. * @returns {Promise} When the update is complete this will respond successfully. Returns the record for - * record operations and the model for model operations. + * record operations and the table for table operations. */ exports.updateLinks = async function({ eventType, instanceId, record, - modelId, - model, - oldModel, + tableId, + table, + oldTable, }) { if (instanceId == null) { throw "Cannot operate without an instance ID." } - // make sure model ID is set - if (modelId == null && model != null) { - arguments[0].modelId = model._id + // make sure table ID is set + if (tableId == null && table != null) { + arguments[0].tableId = table._id } let linkController = new LinkController(arguments[0]) if ( - !(await linkController.doesModelHaveLinkedFields()) && - (oldModel == null || - !(await linkController.doesModelHaveLinkedFields(oldModel))) + !(await linkController.doesTableHaveLinkedFields()) && + (oldTable == null || + !(await linkController.doesTableHaveLinkedFields(oldTable))) ) { return record } @@ -62,12 +62,12 @@ exports.updateLinks = async function({ return await linkController.recordSaved() case EventType.RECORD_DELETE: return await linkController.recordDeleted() - case EventType.MODEL_SAVE: - return await linkController.modelSaved() - case EventType.MODEL_UPDATED: - return await linkController.modelUpdated() - case EventType.MODEL_DELETE: - return await linkController.modelDeleted() + case EventType.TABLE_SAVE: + return await linkController.tableSaved() + case EventType.TABLE_UPDATED: + return await linkController.tableUpdated() + case EventType.TABLE_DELETE: + return await linkController.tableDeleted() default: throw "Type of event is not known, linked record handler requires update." } @@ -93,7 +93,7 @@ exports.attachLinkInfo = async (instanceId, records) => { records.map(record => getLinkDocuments({ instanceId, - modelId: record.modelId, + tableId: record.tableId, recordId: record._id, includeDocs: IncludeDocs.EXCLUDE, }) diff --git a/packages/server/src/db/linkedRecords/linkUtils.js b/packages/server/src/db/linkedRecords/linkUtils.js index 7680a2603f..821346b5fe 100644 --- a/packages/server/src/db/linkedRecords/linkUtils.js +++ b/packages/server/src/db/linkedRecords/linkUtils.js @@ -25,11 +25,11 @@ exports.createLinkView = async instanceId => { if (doc.type === "link") { let doc1 = doc.doc1 let doc2 = doc.doc2 - emit([doc1.modelId, doc1.recordId], { + emit([doc1.tableId, doc1.recordId], { id: doc2.recordId, fieldName: doc1.fieldName, }) - emit([doc2.modelId, doc2.recordId], { + emit([doc2.tableId, doc2.recordId], { id: doc1.recordId, fieldName: doc2.fieldName, }) @@ -46,11 +46,11 @@ exports.createLinkView = async instanceId => { /** * Gets the linking documents, not the linked documents themselves. * @param {string} instanceId The instance in which we are searching for linked records. - * @param {string} modelId The model which we are searching for linked records against. + * @param {string} tableId The table which we are searching for linked records against. * @param {string|null} fieldName The name of column/field which is being altered, only looking for * linking documents that are related to it. If this is not specified then the table level will be assumed. * @param {string|null} recordId The ID of the record which we want to find linking documents for - - * if this is not specified then it will assume model or field level depending on whether the + * if this is not specified then it will assume table or field level depending on whether the * field name has been specified. * @param {boolean|null} includeDocs whether to include docs in the response call, this is considerably slower so only * use this if actually interested in the docs themselves. @@ -59,18 +59,18 @@ exports.createLinkView = async instanceId => { */ exports.getLinkDocuments = async function({ instanceId, - modelId, + tableId, recordId, includeDocs, }) { const db = new CouchDB(instanceId) let params if (recordId != null) { - params = { key: [modelId, recordId] } + params = { key: [tableId, recordId] } } - // only model is known + // only table is known else { - params = { startKey: [modelId], endKey: [modelId, {}] } + params = { startKey: [tableId], endKey: [tableId, {}] } } params.include_docs = !!includeDocs try { diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 7c55da43ff..1a632aaf76 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -4,7 +4,7 @@ const UNICODE_MAX = "\ufff0" const SEPARATOR = "_" const DocumentTypes = { - MODEL: "mo", + TABLE: "ta", RECORD: "re", USER: "us", AUTOMATION: "au", @@ -18,11 +18,11 @@ exports.SEPARATOR = SEPARATOR /** * If creating DB allDocs/query params with only a single top level ID this can be used, this - * is usually the case as most of our docs are top level e.g. models, automations, users and so on. + * is usually the case as most of our docs are top level e.g. tables, automations, users and so on. * More complex cases such as link docs and records which have multiple levels of IDs that their * ID consists of need their own functions to build the allDocs parameters. * @param {string} docType The type of document which input params are being built for, e.g. user, - * link, app, model and so on. + * link, app, table and so on. * @param {string|null} docId The ID of the document minus its type - this is only needed if looking * for a singular document. * @param {object} otherProps Add any other properties onto the request, e.g. include_docs. @@ -40,46 +40,46 @@ function getDocParams(docType, docId = null, otherProps = {}) { } /** - * Gets parameters for retrieving models, this is a utility function for the getDocParams function. + * Gets parameters for retrieving tables, this is a utility function for the getDocParams function. */ -exports.getModelParams = (modelId = null, otherProps = {}) => { - return getDocParams(DocumentTypes.MODEL, modelId, otherProps) +exports.getTableParams = (tableId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.TABLE, tableId, otherProps) } /** - * Generates a new model ID. - * @returns {string} The new model ID which the model doc can be stored under. + * Generates a new table ID. + * @returns {string} The new table ID which the table doc can be stored under. */ -exports.generateModelID = () => { - return `${DocumentTypes.MODEL}${SEPARATOR}${newid()}` +exports.generateTableID = () => { + return `${DocumentTypes.TABLE}${SEPARATOR}${newid()}` } /** * Gets the DB allDocs/query params for retrieving a record. - * @param {string} modelId The model in which the records have been stored. + * @param {string} tableId The table in which the records have been stored. * @param {string|null} recordId The ID of the record which is being specifically queried for. This can be - * left null to get all the records in the model. + * left null to get all the records in the table. * @param {object} otherProps Any other properties to add to the request. * @returns {object} Parameters which can then be used with an allDocs request. */ -exports.getRecordParams = (modelId, recordId = null, otherProps = {}) => { - if (modelId == null) { - throw "Cannot build params for records without a model ID" +exports.getRecordParams = (tableId, recordId = null, otherProps = {}) => { + if (tableId == null) { + throw "Cannot build params for records without a table ID" } const endOfKey = recordId == null - ? `${modelId}${SEPARATOR}` - : `${modelId}${SEPARATOR}${recordId}` + ? `${tableId}${SEPARATOR}` + : `${tableId}${SEPARATOR}${recordId}` return getDocParams(DocumentTypes.RECORD, endOfKey, otherProps) } /** - * Gets a new record ID for the specified model. - * @param {string} modelId The model which the record is being created for. + * Gets a new record ID for the specified table. + * @param {string} tableId The table which the record is being created for. * @returns {string} The new ID which a record doc can be stored under. */ -exports.generateRecordID = modelId => { - return `${DocumentTypes.RECORD}${SEPARATOR}${modelId}${SEPARATOR}${newid()}` +exports.generateRecordID = tableId => { + return `${DocumentTypes.RECORD}${SEPARATOR}${tableId}${SEPARATOR}${newid()}` } /** @@ -116,14 +116,14 @@ exports.generateAutomationID = () => { /** * Generates a new link doc ID. This is currently not usable with the alldocs call, * instead a view is built to make walking to tree easier. - * @param {string} modelId1 The ID of the linker model. - * @param {string} modelId2 The ID of the linked model. + * @param {string} tableId1 The ID of the linker table. + * @param {string} tableId2 The ID of the linked table. * @param {string} recordId1 The ID of the linker record. * @param {string} recordId2 The ID of the linked record. * @returns {string} The new link doc ID which the automation doc can be stored under. */ -exports.generateLinkID = (modelId1, modelId2, recordId1, recordId2) => { - return `${DocumentTypes.AUTOMATION}${SEPARATOR}${modelId1}${SEPARATOR}${modelId2}${SEPARATOR}${recordId1}${SEPARATOR}${recordId2}` +exports.generateLinkID = (tableId1, tableId2, recordId1, recordId2) => { + return `${DocumentTypes.AUTOMATION}${SEPARATOR}${tableId1}${SEPARATOR}${tableId2}${SEPARATOR}${recordId1}${SEPARATOR}${recordId2}` } /** diff --git a/packages/server/src/events/index.js b/packages/server/src/events/index.js index d02cac447d..69b29176ce 100644 --- a/packages/server/src/events/index.js +++ b/packages/server/src/events/index.js @@ -11,14 +11,14 @@ const EventEmitter = require("events").EventEmitter * This is specifically quite important for mustache used in automations. */ class BudibaseEmitter extends EventEmitter { - emitRecord(eventName, instanceId, record, model = null) { + emitRecord(eventName, instanceId, record, table = null) { let event = { record, instanceId, - modelId: record.modelId, + tableId: record.tableId, } - if (model) { - event.model = model + if (table) { + event.table = table } event.id = record._id if (record._rev) { @@ -27,19 +27,19 @@ class BudibaseEmitter extends EventEmitter { this.emit(eventName, event) } - emitModel(eventName, instanceId, model = null) { - const modelId = model._id + emitTable(eventName, instanceId, table = null) { + const tableId = table._id let event = { - model: { - ...model, - modelId: modelId, + table: { + ...table, + tableId: tableId, }, instanceId, - modelId: modelId, + tableId: tableId, } - event.id = modelId - if (model._rev) { - event.revision = model._rev + event.id = tableId + if (table._rev) { + event.revision = table._rev } this.emit(eventName, event) } diff --git a/packages/server/src/utilities/accessLevels.js b/packages/server/src/utilities/accessLevels.js index 0de8e85ffb..201007527c 100644 --- a/packages/server/src/utilities/accessLevels.js +++ b/packages/server/src/utilities/accessLevels.js @@ -1,6 +1,6 @@ // Permissions -module.exports.READ_MODEL = "read-model" -module.exports.WRITE_MODEL = "write-model" +module.exports.READ_TABLE = "read-table" +module.exports.WRITE_TABLE = "write-table" module.exports.READ_VIEW = "read-view" module.exports.EXECUTE_AUTOMATION = "execute-automation" module.exports.USER_MANAGEMENT = "user-management" diff --git a/packages/server/src/utilities/permissions.js b/packages/server/src/utilities/permissions.js index aa7ce12bcb..8cd30c9ff8 100644 --- a/packages/server/src/utilities/permissions.js +++ b/packages/server/src/utilities/permissions.js @@ -1,5 +1,5 @@ const viewController = require("../api/controllers/view") -const modelController = require("../api/controllers/model") +const tableController = require("../api/controllers/table") const automationController = require("../api/controllers/automation") const accessLevels = require("./accessLevels") @@ -10,13 +10,13 @@ const generateAdminPermissions = async instanceId => [ ] const generatePowerUserPermissions = async instanceId => { - const fetchModelsCtx = { + const fetchTablesCtx = { user: { instanceId, }, } - await modelController.fetch(fetchModelsCtx) - const models = fetchModelsCtx.body + await tableController.fetch(fetchTablesCtx) + const tables = fetchTablesCtx.body const fetchViewsCtx = { user: { @@ -34,14 +34,14 @@ const generatePowerUserPermissions = async instanceId => { await automationController.fetch(fetchAutomationsCtx) const automations = fetchAutomationsCtx.body - const readModelPermissions = models.map(m => ({ + const readTablePermissions = tables.map(m => ({ itemId: m._id, - name: accessLevels.READ_MODEL, + name: accessLevels.READ_TABLE, })) - const writeModelPermissions = models.map(m => ({ + const writeTablePermissions = tables.map(m => ({ itemId: m._id, - name: accessLevels.WRITE_MODEL, + name: accessLevels.WRITE_TABLE, })) const viewPermissions = views.map(v => ({ @@ -55,8 +55,8 @@ const generatePowerUserPermissions = async instanceId => { })) return [ - ...readModelPermissions, - ...writeModelPermissions, + ...readTablePermissions, + ...writeTablePermissions, ...viewPermissions, ...executeAutomationPermissions, { name: accessLevels.LIST_USERS }, diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 67b4dbdcf2..3f60a67cc0 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -172,10 +172,10 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@budibase/client@^0.1.25": - version "0.1.25" - resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.1.25.tgz#f08c4a614f9018eb0f0faa6d20bb05f7a3215c70" - integrity sha512-vZ0cqJwLYcs7MHihFnJO3qOe7qxibnB4Va1+IYNfnPc9kcxy4KvfQxCx/G/DDxP9CXfEvsguy9ymzR3RUAvBHw== +"@budibase/client@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.2.0.tgz#247218de40538b31aeac7367f0e323c28fc8ca40" + integrity sha512-FJibQ7OqYCQOpIw4GDBPZEfJI+MiVn9irevZ2UjQBGJjbZMxoQTRAD/FoAq2Yu3s9L4tA5mTMutuMNkjpTs85Q== dependencies: deep-equal "^2.0.1" mustache "^4.0.1" diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index e600b264be..56e4b19823 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -208,7 +208,7 @@ "description": "an HTML table that fetches data from a table or view and displays it.", "data": true, "props": { - "datasource": "models", + "datasource": "tables", "stripeColor": "string", "borderColor": "string", "backgroundColor": "string", @@ -219,7 +219,7 @@ "description": "an HTML table that fetches data from a table or view and displays it.", "data": true, "props": { - "model": "models", + "table": "tables", "title": "string", "buttonText": "string" } @@ -228,16 +228,16 @@ "description": "an HTML table that fetches data from a table or view and displays it.", "data": true, "props": { - "model": "models", + "table": "tables", "title": "string", "buttonText": "string" } }, "datalist": { - "description": "A configurable data list that attaches to your backend models.", + "description": "A configurable data list that attaches to your backend tables.", "data": true, "props": { - "model": "models", + "table": "tables", "layout": { "type": "options", "default": "list", @@ -249,12 +249,12 @@ } }, "list": { - "description": "A configurable data list that attaches to your backend models.", + "description": "A configurable data list that attaches to your backend tables.", "context": "datasource", "children": true, "data": true, "props": { - "datasource": "models" + "datasource": "tables" } }, "stackedlist": { @@ -271,11 +271,11 @@ }, "recorddetail": { "description": "Loads a record, using an ID in the url", - "context": "model", + "context": "table", "children": true, "data": true, "props": { - "model": "models" + "table": "tables" } }, "card": { @@ -357,7 +357,7 @@ "description": "shiny chart", "data": true, "props": { - "model": "models" + "table": "tables" } }, "donut": { @@ -389,7 +389,7 @@ "description": "Sparkline Chart", "data": true, "props": { - "model": "string", + "table": "string", "areaGradient": "string", "height": "number", "width": "number", @@ -405,7 +405,7 @@ "description": "Stacked Bar Chart", "data": true, "props": { - "datasource": "models", + "datasource": "tables", "color": "string", "height": "number", "width": "number", @@ -434,7 +434,7 @@ "description": "Step Chart", "data": true, "props": { - "model": "string", + "table": "string", "color": "string", "height": "number", "width": "number", @@ -468,7 +468,7 @@ "description": "Step Chart", "data": true, "props": { - "model": "string", + "table": "string", "height": "number", "width": "number", "margin": "string", @@ -483,7 +483,7 @@ "description": "Scatterplot Chart", "data": true, "props": { - "model": "string", + "table": "string", "color": "string", "height": "number", "width": "number", @@ -506,7 +506,7 @@ "description": "Bar Chart", "data": true, "props": { - "datasource": "models", + "datasource": "tables", "nameLabel": "string", "valueLabel": "string", "betweenBarsPadding": "number", @@ -530,7 +530,7 @@ "description": "Line Chart", "data": true, "props": { - "datasource": "models", + "datasource": "tables", "width": "number", "height": "number", "axisTimeCombinations": "string", @@ -560,7 +560,7 @@ "description": "brush chart", "data": true, "props": { - "model": "string", + "table": "string", "gradient": "string", "height": "number", "width": "number", @@ -577,7 +577,7 @@ "description": "Heatmap chart", "data": true, "props": { - "model": "string", + "table": "string", "color": "string", "height": "number", "width": "number", @@ -590,7 +590,7 @@ "description": "Groupedbar chart", "data": true, "props": { - "datasource": "models", + "datasource": "tables", "nameLabel": "string", "valueLabel": "string", "color": "string", @@ -610,7 +610,7 @@ "description": "Bullet chart", "data": true, "props": { - "model": "string", + "table": "string", "color": "string", "customSubtitle": "string", "customTitle": "string", @@ -631,7 +631,7 @@ "description": "shiny chart", "data": true, "props": { - "model": "models", + "table": "tables", "type": { "type": "options", "default": "column2d", diff --git a/packages/standard-components/public/bundle.js b/packages/standard-components/public/bundle.js index e88c503dc1..9ea5b06b45 100644 --- a/packages/standard-components/public/bundle.js +++ b/packages/standard-components/public/bundle.js @@ -21242,7 +21242,7 @@ var app = (function (crypto$1) { "indexType", "reference index may only exist on a record node", index => - isModel(index.parent()) || index.indexType !== indexTypes.reference + isTable(index.parent()) || index.indexType !== indexTypes.reference ), makerule( "indexType", @@ -21321,9 +21321,9 @@ var app = (function (crypto$1) { const isNode = (appHierarchy, key) => isSomething(getExactNodeForKey(appHierarchy)(key)); - const isModel = node => isSomething(node) && node.type === "record"; - const isSingleRecord = node => isModel(node) && node.isSingle; - const isCollectionRecord = node => isModel(node) && !node.isSingle; + const isTable = node => isSomething(node) && node.type === "record"; + const isSingleRecord = node => isTable(node) && node.isSingle; + const isCollectionRecord = node => isTable(node) && !node.isSingle; const isRoot = node => isSomething(node) && node.isRoot(); const getSafeFieldParser = (tryParse, defaultValueFunctions) => ( @@ -22056,7 +22056,7 @@ var app = (function (crypto$1) { const nodeKeyMaker = node => () => switchCase( [ - n => isModel(n) && !isSingleRecord(n), + n => isTable(n) && !isSingleRecord(n), n => joinKey( node.parent().nodeKey(), diff --git a/packages/standard-components/public/bundle.js.map b/packages/standard-components/public/bundle.js.map index ac50cdc26b..c054f74ee6 100644 --- a/packages/standard-components/public/bundle.js.map +++ b/packages/standard-components/public/bundle.js.map @@ -110,8 +110,8 @@ "import { filter, map } from \"lodash/fp\"\r\nimport { $, isSomething } from \"./index\"\r\n\r\nexport const stringNotEmpty = s => isSomething(s) && s.trim().length > 0\r\n\r\nexport const makerule = (field, error, isValid) => ({ field, error, isValid })\r\n\r\nexport const validationError = (rule, item) => ({ ...rule, item })\r\n\r\nexport const applyRuleSet = ruleSet => itemToValidate =>\r\n $(ruleSet, [map(applyRule(itemToValidate)), filter(isSomething)])\r\n\r\nexport const applyRule = itemTovalidate => rule =>\r\n rule.isValid(itemTovalidate) ? null : validationError(rule, itemTovalidate)\r\n", "var filters = new Map();\nvar limiters = new Map();\n\nfunction filter(name, handler) {\n if (typeof name !== 'string') {\n throw new TypeError('First argument must be a string.');\n }\n if (typeof handler !== 'function') {\n throw new TypeError('Second argument must be a function.');\n }\n if (filters.has(name)) {\n throw new Error((\"A filter named \" + name + \" is already registered.\"));\n }\n filters.set(name, handler);\n}\n\nfunction limiter(name, handler) {\n if (typeof name !== 'string') {\n throw new TypeError('First argument must be a string.');\n }\n if (typeof handler !== 'function') {\n throw new TypeError('Second argument must be a function.');\n }\n if (limiters.has(name)) {\n throw new Error((\"A limiter named \" + name + \" is already registered.\"));\n }\n limiters.set(name, handler);\n}\n\nfunction compileRawExpression(src) {\n return new Function('context', 'tempVars', // eslint-disable-line\n (\"const sandbox = $nxCompileToSandbox(context, tempVars)\\n try { with (sandbox) { return \" + src + \" } } catch (err) {\\n if (!(err instanceof TypeError)) throw err\\n }\\n $nxClearSandbox()\"));\n}\n\nfunction compileRawCode(src) {\n return new Function('context', 'tempVars', // eslint-disable-line\n (\"const sandbox = $nxCompileToSandbox(context, tempVars)\\n with (sandbox) { \" + src + \" }\\n $nxClearSandbox()\"));\n}\n\nvar filterRegex = /(?:[^\\|]|\\|\\|)+/g;\nvar limiterRegex = /(?:[^&]|&&)+/g;\nvar argsRegex = /\\S+/g;\n\nfunction parseExpression(src) {\n var tokens = src.match(filterRegex);\n if (tokens.length === 1) {\n return compileRawExpression(tokens[0]);\n }\n\n var expression = {\n exec: compileRawExpression(tokens[0]),\n filters: []\n };\n for (var i = 1; i < tokens.length; i++) {\n var filterTokens = tokens[i].match(argsRegex);\n var filterName = filterTokens.shift();\n var effect = filters.get(filterName);\n if (!effect) {\n throw new Error((\"There is no filter named: \" + filterName + \".\"));\n }\n expression.filters.push({ effect: effect, argExpressions: filterTokens.map(compileRawExpression) });\n }\n return expression;\n}\n\nfunction parseCode(src) {\n var tokens = src.match(limiterRegex);\n if (tokens.length === 1) {\n return compileRawCode(tokens[0]);\n }\n\n var code = {\n exec: compileRawCode(tokens[0]),\n limiters: []\n };\n for (var i = 1; i < tokens.length; i++) {\n var limiterTokens = tokens[i].match(argsRegex);\n var limiterName = limiterTokens.shift();\n var effect = limiters.get(limiterName);\n if (!effect) {\n throw new Error((\"There is no limiter named: \" + limiterName + \".\"));\n }\n code.limiters.push({ effect: effect, argExpressions: limiterTokens.map(compileRawExpression) });\n }\n return code;\n}\n\nvar expressionCache = new Map();\nvar codeCache = new Map();\n\nfunction compileExpression(src) {\n if (typeof src !== 'string') {\n throw new TypeError('First argument must be a string.');\n }\n var expression = expressionCache.get(src);\n if (!expression) {\n expression = parseExpression(src);\n expressionCache.set(src, expression);\n }\n\n if (typeof expression === 'function') {\n return expression;\n }\n\n return function evaluateExpression(context, tempVars) {\n var value = expression.exec(context, tempVars);\n for (var i = 0, list = expression.filters; i < list.length; i += 1) {\n var filter = list[i];\n\n var args = filter.argExpressions.map(evaluateArgExpression, context);\n value = filter.effect.apply(filter, [ value ].concat( args ));\n }\n return value;\n };\n}\n\nfunction compileCode(src) {\n if (typeof src !== 'string') {\n throw new TypeError('First argument must be a string.');\n }\n var code = codeCache.get(src);\n if (!code) {\n code = parseCode(src);\n codeCache.set(src, code);\n }\n\n if (typeof code === 'function') {\n return code;\n }\n\n var context = {};\n return function evaluateCode(state, tempVars) {\n var i = 0;\n function next() {\n Object.assign(context, tempVars);\n if (i < code.limiters.length) {\n var limiter = code.limiters[i++];\n var args = limiter.argExpressions.map(evaluateArgExpression, state);\n limiter.effect.apply(limiter, [ next, context ].concat( args ));\n } else {\n code.exec(state, tempVars);\n }\n }\n next();\n };\n}\n\nfunction evaluateArgExpression(argExpression) {\n return argExpression(this);\n}\n\nvar hasHandler = { has: has };\nvar allHandlers = { has: has, get: get };\nvar globals = new Set();\nvar temp;\n\nvar globalObj;\nif (typeof window !== 'undefined') { globalObj = window; } // eslint-disable-line\nelse if (typeof global !== 'undefined') { globalObj = global; } // eslint-disable-line\n else if (typeof self !== 'undefined') { globalObj = self; } // eslint-disable-line\nglobalObj.$nxCompileToSandbox = toSandbox;\nglobalObj.$nxClearSandbox = clearSandbox;\n\nfunction expose() {\n var globalNames = [], len = arguments.length;\n while ( len-- ) globalNames[ len ] = arguments[ len ];\n\n for (var i = 0, list = globalNames; i < list.length; i += 1) {\n var globalName = list[i];\n\n globals.add(globalName);\n }\n}\n\nfunction hide() {\n var globalNames = [], len = arguments.length;\n while ( len-- ) globalNames[ len ] = arguments[ len ];\n\n for (var i = 0, list = globalNames; i < list.length; i += 1) {\n var globalName = list[i];\n\n globals.delete(globalName);\n }\n}\n\nfunction hideAll() {\n globals.clear();\n}\n\nfunction has(target, key) {\n return globals.has(key) ? key in target : true;\n}\n\nfunction get(target, key) {\n return key in temp ? temp[key] : target[key];\n}\n\nfunction toSandbox(obj, tempVars) {\n if (tempVars) {\n temp = tempVars;\n return new Proxy(obj, allHandlers);\n }\n return new Proxy(obj, hasHandler);\n}\n\nfunction clearSandbox() {\n temp = undefined;\n}\n\nexport { compileExpression, compileCode, compileRawExpression, compileRawCode, expose, hide, hideAll, filters, limiters, filter, limiter };\n", "import { compileExpression, compileCode } from \"@nx-js/compiler-util\"\r\nimport { isUndefined, keys, cloneDeep, isFunction } from \"lodash/fp\"\r\nimport { defineError } from \"../common\"\r\n\r\nexport const filterEval = \"FILTER_EVALUATE\"\r\nexport const filterCompile = \"FILTER_COMPILE\"\r\nexport const mapEval = \"MAP_EVALUATE\"\r\nexport const mapCompile = \"MAP_COMPILE\"\r\nexport const removeUndeclaredFields = \"REMOVE_UNDECLARED_FIELDS\"\r\nexport const addUnMappedFields = \"ADD_UNMAPPED_FIELDS\"\r\nexport const addTheKey = \"ADD_KEY\"\r\n\r\nconst getEvaluateResult = () => ({\r\n isError: false,\r\n passedFilter: true,\r\n result: null,\r\n})\r\n\r\nexport const compileFilter = index => compileExpression(index.filter)\r\n\r\nexport const compileMap = index => compileCode(index.map)\r\n\r\nexport const passesFilter = (record, index) => {\r\n const context = { record }\r\n if (!index.filter) return true\r\n\r\n const compiledFilter = defineError(() => compileFilter(index), filterCompile)\r\n\r\n return defineError(() => compiledFilter(context), filterEval)\r\n}\r\n\r\nexport const mapRecord = (record, index) => {\r\n const recordClone = cloneDeep(record)\r\n const context = { record: recordClone }\r\n\r\n const map = index.map ? index.map : \"return {...record};\"\r\n\r\n const compiledMap = defineError(() => compileCode(map), mapCompile)\r\n\r\n const mapped = defineError(() => compiledMap(context), mapEval)\r\n\r\n const mappedKeys = keys(mapped)\r\n for (let i = 0; i < mappedKeys.length; i++) {\r\n const key = mappedKeys[i]\r\n mapped[key] = isUndefined(mapped[key]) ? null : mapped[key]\r\n if (isFunction(mapped[key])) {\r\n delete mapped[key]\r\n }\r\n }\r\n\r\n mapped.key = record.key\r\n mapped.sortKey = index.getSortKey\r\n ? compileCode(index.getSortKey)(context)\r\n : record.id\r\n\r\n return mapped\r\n}\r\n\r\nexport const evaluate = record => index => {\r\n const result = getEvaluateResult()\r\n\r\n try {\r\n result.passedFilter = passesFilter(record, index)\r\n } catch (err) {\r\n result.isError = true\r\n result.passedFilter = false\r\n result.result = err.message\r\n }\r\n\r\n if (!result.passedFilter) return result\r\n\r\n try {\r\n result.result = mapRecord(record, index)\r\n } catch (err) {\r\n result.isError = true\r\n result.result = err.message\r\n }\r\n\r\n return result\r\n}\r\n\r\nexport default evaluate\r\n", - "import { map, isEmpty, countBy, flatten, includes, join, keys } from \"lodash/fp\"\r\nimport {} from \"lodash\"\r\nimport { applyRuleSet, makerule } from \"../common/validationCommon\"\r\nimport { compileFilter, compileMap } from \"../indexing/evaluate\"\r\nimport { isNonEmptyString, executesWithoutException, $ } from \"../common\"\r\nimport { isModel } from \"./hierarchy\"\r\n\r\nexport const indexTypes = { reference: \"reference\", ancestor: \"ancestor\" }\r\n\r\nexport const indexRuleSet = [\r\n makerule(\"map\", \"index has no map function\", index =>\r\n isNonEmptyString(index.map)\r\n ),\r\n makerule(\r\n \"map\",\r\n \"index's map function does not compile\",\r\n index =>\r\n !isNonEmptyString(index.map) ||\r\n executesWithoutException(() => compileMap(index))\r\n ),\r\n makerule(\r\n \"filter\",\r\n \"index's filter function does not compile\",\r\n index =>\r\n !isNonEmptyString(index.filter) ||\r\n executesWithoutException(() => compileFilter(index))\r\n ),\r\n makerule(\"name\", \"must declare a name for index\", index =>\r\n isNonEmptyString(index.name)\r\n ),\r\n makerule(\r\n \"name\",\r\n \"there is a duplicate named index on this node\",\r\n index =>\r\n isEmpty(index.name) ||\r\n countBy(\"name\")(index.parent().indexes)[index.name] === 1\r\n ),\r\n makerule(\r\n \"indexType\",\r\n \"reference index may only exist on a record node\",\r\n index =>\r\n isModel(index.parent()) || index.indexType !== indexTypes.reference\r\n ),\r\n makerule(\r\n \"indexType\",\r\n `index type must be one of: ${join(\", \")(keys(indexTypes))}`,\r\n index => includes(index.indexType)(keys(indexTypes))\r\n ),\r\n]\r\n\r\nexport const validateIndex = (index, allReferenceIndexesOnNode) =>\r\n applyRuleSet(indexRuleSet(allReferenceIndexesOnNode))(index)\r\n\r\nexport const validateAllIndexes = node =>\r\n $(node.indexes, [map(i => validateIndex(i, node.indexes)), flatten])\r\n", - "import {\r\n find,\r\n constant,\r\n map,\r\n last,\r\n first,\r\n split,\r\n intersection,\r\n take,\r\n union,\r\n includes,\r\n filter,\r\n some,\r\n} from \"lodash/fp\"\r\nimport {\r\n $,\r\n switchCase,\r\n isNothing,\r\n isSomething,\r\n defaultCase,\r\n splitKey,\r\n isNonEmptyString,\r\n joinKey,\r\n getHashCode,\r\n} from \"../common\"\r\nimport { indexTypes } from \"./indexes\"\r\n\r\nexport const getFlattenedHierarchy = (appHierarchy, useCached = true) => {\r\n if (isSomething(appHierarchy.getFlattenedHierarchy) && useCached) {\r\n return appHierarchy.getFlattenedHierarchy()\r\n }\r\n\r\n const flattenHierarchy = (currentNode, flattened) => {\r\n flattened.push(currentNode)\r\n if (\r\n (!currentNode.children || currentNode.children.length === 0) &&\r\n (!currentNode.indexes || currentNode.indexes.length === 0) &&\r\n (!currentNode.aggregateGroups || currentNode.aggregateGroups.length === 0)\r\n ) {\r\n return flattened\r\n }\r\n\r\n const unionIfAny = l2 => l1 => union(l1)(!l2 ? [] : l2)\r\n\r\n const children = $(\r\n [],\r\n [\r\n unionIfAny(currentNode.children),\r\n unionIfAny(currentNode.indexes),\r\n unionIfAny(currentNode.aggregateGroups),\r\n ]\r\n )\r\n\r\n for (const child of children) {\r\n flattenHierarchy(child, flattened)\r\n }\r\n return flattened\r\n }\r\n\r\n appHierarchy.getFlattenedHierarchy = () => flattenHierarchy(appHierarchy, [])\r\n return appHierarchy.getFlattenedHierarchy()\r\n}\r\n\r\nexport const getLastPartInKey = key => last(splitKey(key))\r\n\r\nexport const getNodesInPath = appHierarchy => key =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n filter(n => new RegExp(`${n.pathRegx()}`).test(key)),\r\n ])\r\n\r\nexport const getExactNodeForKey = appHierarchy => key =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => new RegExp(`${n.pathRegx()}$`).test(key)),\r\n ])\r\n\r\nexport const getNodeForCollectionPath = appHierarchy => collectionKey =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(\r\n n =>\r\n isCollectionRecord(n) &&\r\n new RegExp(`${n.collectionPathRegx()}$`).test(collectionKey)\r\n ),\r\n ])\r\n\r\nexport const hasMatchingAncestor = ancestorPredicate => decendantNode =>\r\n switchCase(\r\n [node => isNothing(node.parent()), constant(false)],\r\n\r\n [node => ancestorPredicate(node.parent()), constant(true)],\r\n\r\n [defaultCase, node => hasMatchingAncestor(ancestorPredicate)(node.parent())]\r\n )(decendantNode)\r\n\r\nexport const getNode = (appHierarchy, nodeKey) =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(\r\n n =>\r\n n.nodeKey() === nodeKey ||\r\n (isCollectionRecord(n) && n.collectionNodeKey() === nodeKey)\r\n ),\r\n ])\r\n\r\nexport const getCollectionNode = (appHierarchy, nodeKey) =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => isCollectionRecord(n) && n.collectionNodeKey() === nodeKey),\r\n ])\r\n\r\nexport const getNodeByKeyOrNodeKey = (appHierarchy, keyOrNodeKey) => {\r\n const nodeByKey = getExactNodeForKey(appHierarchy)(keyOrNodeKey)\r\n return isNothing(nodeByKey) ? getNode(appHierarchy, keyOrNodeKey) : nodeByKey\r\n}\r\n\r\nexport const getCollectionNodeByKeyOrNodeKey = (appHierarchy, keyOrNodeKey) => {\r\n const nodeByKey = getNodeForCollectionPath(appHierarchy)(keyOrNodeKey)\r\n return isNothing(nodeByKey)\r\n ? getCollectionNode(appHierarchy, keyOrNodeKey)\r\n : nodeByKey\r\n}\r\n\r\nexport const isNode = (appHierarchy, key) =>\r\n isSomething(getExactNodeForKey(appHierarchy)(key))\r\n\r\nexport const getActualKeyOfParent = (parentNodeKey, actualChildKey) =>\r\n $(actualChildKey, [\r\n splitKey,\r\n take(splitKey(parentNodeKey).length),\r\n ks => joinKey(...ks),\r\n ])\r\n\r\nexport const getParentKey = key => {\r\n return $(key, [splitKey, take(splitKey(key).length - 1), joinKey])\r\n}\r\n\r\nexport const isKeyAncestorOf = ancestorKey => decendantNode =>\r\n hasMatchingAncestor(p => p.nodeKey() === ancestorKey)(decendantNode)\r\n\r\nexport const hasNoMatchingAncestors = parentPredicate => node =>\r\n !hasMatchingAncestor(parentPredicate)(node)\r\n\r\nexport const findField = (recordNode, fieldName) =>\r\n find(f => f.name == fieldName)(recordNode.fields)\r\n\r\nexport const isAncestor = decendant => ancestor =>\r\n isKeyAncestorOf(ancestor.nodeKey())(decendant)\r\n\r\nexport const isDecendant = ancestor => decendant =>\r\n isAncestor(decendant)(ancestor)\r\n\r\nexport const getRecordNodeId = recordKey =>\r\n $(recordKey, [splitKey, last, getRecordNodeIdFromId])\r\n\r\nexport const getRecordNodeIdFromId = recordId =>\r\n $(recordId, [split(\"-\"), first, parseInt])\r\n\r\nexport const getRecordNodeById = (hierarchy, recordId) =>\r\n $(hierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => isModel(n) && n.nodeId === getRecordNodeIdFromId(recordId)),\r\n ])\r\n\r\nexport const recordNodeIdIsAllowed = indexNode => nodeId =>\r\n indexNode.allowedModelNodeIds.length === 0 ||\r\n includes(nodeId)(indexNode.allowedModelNodeIds)\r\n\r\nexport const recordNodeIsAllowed = indexNode => recordNode =>\r\n recordNodeIdIsAllowed(indexNode)(recordNode.nodeId)\r\n\r\nexport const getAllowedRecordNodesForIndex = (appHierarchy, indexNode) => {\r\n const recordNodes = $(appHierarchy, [getFlattenedHierarchy, filter(isModel)])\r\n\r\n if (isGlobalIndex(indexNode)) {\r\n return $(recordNodes, [filter(recordNodeIsAllowed(indexNode))])\r\n }\r\n\r\n if (isAncestorIndex(indexNode)) {\r\n return $(recordNodes, [\r\n filter(isDecendant(indexNode.parent())),\r\n filter(recordNodeIsAllowed(indexNode)),\r\n ])\r\n }\r\n\r\n if (isReferenceIndex(indexNode)) {\r\n return $(recordNodes, [\r\n filter(n => some(fieldReversesReferenceToIndex(indexNode))(n.fields)),\r\n ])\r\n }\r\n}\r\n\r\nexport const getNodeFromNodeKeyHash = hierarchy => hash =>\r\n $(hierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => getHashCode(n.nodeKey()) === hash),\r\n ])\r\n\r\nexport const isModel = node => isSomething(node) && node.type === \"record\"\r\nexport const isSingleRecord = node => isModel(node) && node.isSingle\r\nexport const isCollectionRecord = node => isModel(node) && !node.isSingle\r\nexport const isIndex = node => isSomething(node) && node.type === \"index\"\r\nexport const isaggregateGroup = node =>\r\n isSomething(node) && node.type === \"aggregateGroup\"\r\nexport const isShardedIndex = node =>\r\n isIndex(node) && isNonEmptyString(node.getShardName)\r\nexport const isRoot = node => isSomething(node) && node.isRoot()\r\nexport const isDecendantOfARecord = hasMatchingAncestor(isModel)\r\nexport const isGlobalIndex = node => isIndex(node) && isRoot(node.parent())\r\nexport const isReferenceIndex = node =>\r\n isIndex(node) && node.indexType === indexTypes.reference\r\nexport const isAncestorIndex = node =>\r\n isIndex(node) && node.indexType === indexTypes.ancestor\r\n\r\nexport const fieldReversesReferenceToNode = node => field =>\r\n field.type === \"reference\" &&\r\n intersection(field.typeOptions.reverseIndexNodeKeys)(\r\n map(i => i.nodeKey())(node.indexes)\r\n ).length > 0\r\n\r\nexport const fieldReversesReferenceToIndex = indexNode => field =>\r\n field.type === \"reference\" &&\r\n intersection(field.typeOptions.reverseIndexNodeKeys)([indexNode.nodeKey()])\r\n .length > 0\r\n\r\nexport default {\r\n getLastPartInKey,\r\n getNodesInPath,\r\n getExactNodeForKey,\r\n hasMatchingAncestor,\r\n getNode,\r\n getNodeByKeyOrNodeKey,\r\n isNode,\r\n getActualKeyOfParent,\r\n getParentKey,\r\n isKeyAncestorOf,\r\n hasNoMatchingAncestors,\r\n findField,\r\n isAncestor,\r\n isDecendant,\r\n getRecordNodeId,\r\n getRecordNodeIdFromId,\r\n getRecordNodeById,\r\n recordNodeIdIsAllowed,\r\n recordNodeIsAllowed,\r\n getAllowedRecordNodesForIndex,\r\n getNodeFromNodeKeyHash,\r\n isModel,\r\n isCollectionRecord,\r\n isIndex,\r\n isaggregateGroup,\r\n isShardedIndex,\r\n isRoot,\r\n isDecendantOfARecord,\r\n isGlobalIndex,\r\n isReferenceIndex,\r\n isAncestorIndex,\r\n fieldReversesReferenceToNode,\r\n fieldReversesReferenceToIndex,\r\n getFlattenedHierarchy,\r\n}\r\n", + "import { map, isEmpty, countBy, flatten, includes, join, keys } from \"lodash/fp\"\r\nimport {} from \"lodash\"\r\nimport { applyRuleSet, makerule } from \"../common/validationCommon\"\r\nimport { compileFilter, compileMap } from \"../indexing/evaluate\"\r\nimport { isNonEmptyString, executesWithoutException, $ } from \"../common\"\r\nimport { isTable } from \"./hierarchy\"\r\n\r\nexport const indexTypes = { reference: \"reference\", ancestor: \"ancestor\" }\r\n\r\nexport const indexRuleSet = [\r\n makerule(\"map\", \"index has no map function\", index =>\r\n isNonEmptyString(index.map)\r\n ),\r\n makerule(\r\n \"map\",\r\n \"index's map function does not compile\",\r\n index =>\r\n !isNonEmptyString(index.map) ||\r\n executesWithoutException(() => compileMap(index))\r\n ),\r\n makerule(\r\n \"filter\",\r\n \"index's filter function does not compile\",\r\n index =>\r\n !isNonEmptyString(index.filter) ||\r\n executesWithoutException(() => compileFilter(index))\r\n ),\r\n makerule(\"name\", \"must declare a name for index\", index =>\r\n isNonEmptyString(index.name)\r\n ),\r\n makerule(\r\n \"name\",\r\n \"there is a duplicate named index on this node\",\r\n index =>\r\n isEmpty(index.name) ||\r\n countBy(\"name\")(index.parent().indexes)[index.name] === 1\r\n ),\r\n makerule(\r\n \"indexType\",\r\n \"reference index may only exist on a record node\",\r\n index =>\r\n isTable(index.parent()) || index.indexType !== indexTypes.reference\r\n ),\r\n makerule(\r\n \"indexType\",\r\n `index type must be one of: ${join(\", \")(keys(indexTypes))}`,\r\n index => includes(index.indexType)(keys(indexTypes))\r\n ),\r\n]\r\n\r\nexport const validateIndex = (index, allReferenceIndexesOnNode) =>\r\n applyRuleSet(indexRuleSet(allReferenceIndexesOnNode))(index)\r\n\r\nexport const validateAllIndexes = node =>\r\n $(node.indexes, [map(i => validateIndex(i, node.indexes)), flatten])\r\n", + "import {\r\n find,\r\n constant,\r\n map,\r\n last,\r\n first,\r\n split,\r\n intersection,\r\n take,\r\n union,\r\n includes,\r\n filter,\r\n some,\r\n} from \"lodash/fp\"\r\nimport {\r\n $,\r\n switchCase,\r\n isNothing,\r\n isSomething,\r\n defaultCase,\r\n splitKey,\r\n isNonEmptyString,\r\n joinKey,\r\n getHashCode,\r\n} from \"../common\"\r\nimport { indexTypes } from \"./indexes\"\r\n\r\nexport const getFlattenedHierarchy = (appHierarchy, useCached = true) => {\r\n if (isSomething(appHierarchy.getFlattenedHierarchy) && useCached) {\r\n return appHierarchy.getFlattenedHierarchy()\r\n }\r\n\r\n const flattenHierarchy = (currentNode, flattened) => {\r\n flattened.push(currentNode)\r\n if (\r\n (!currentNode.children || currentNode.children.length === 0) &&\r\n (!currentNode.indexes || currentNode.indexes.length === 0) &&\r\n (!currentNode.aggregateGroups || currentNode.aggregateGroups.length === 0)\r\n ) {\r\n return flattened\r\n }\r\n\r\n const unionIfAny = l2 => l1 => union(l1)(!l2 ? [] : l2)\r\n\r\n const children = $(\r\n [],\r\n [\r\n unionIfAny(currentNode.children),\r\n unionIfAny(currentNode.indexes),\r\n unionIfAny(currentNode.aggregateGroups),\r\n ]\r\n )\r\n\r\n for (const child of children) {\r\n flattenHierarchy(child, flattened)\r\n }\r\n return flattened\r\n }\r\n\r\n appHierarchy.getFlattenedHierarchy = () => flattenHierarchy(appHierarchy, [])\r\n return appHierarchy.getFlattenedHierarchy()\r\n}\r\n\r\nexport const getLastPartInKey = key => last(splitKey(key))\r\n\r\nexport const getNodesInPath = appHierarchy => key =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n filter(n => new RegExp(`${n.pathRegx()}`).test(key)),\r\n ])\r\n\r\nexport const getExactNodeForKey = appHierarchy => key =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => new RegExp(`${n.pathRegx()}$`).test(key)),\r\n ])\r\n\r\nexport const getNodeForCollectionPath = appHierarchy => collectionKey =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(\r\n n =>\r\n isCollectionRecord(n) &&\r\n new RegExp(`${n.collectionPathRegx()}$`).test(collectionKey)\r\n ),\r\n ])\r\n\r\nexport const hasMatchingAncestor = ancestorPredicate => decendantNode =>\r\n switchCase(\r\n [node => isNothing(node.parent()), constant(false)],\r\n\r\n [node => ancestorPredicate(node.parent()), constant(true)],\r\n\r\n [defaultCase, node => hasMatchingAncestor(ancestorPredicate)(node.parent())]\r\n )(decendantNode)\r\n\r\nexport const getNode = (appHierarchy, nodeKey) =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(\r\n n =>\r\n n.nodeKey() === nodeKey ||\r\n (isCollectionRecord(n) && n.collectionNodeKey() === nodeKey)\r\n ),\r\n ])\r\n\r\nexport const getCollectionNode = (appHierarchy, nodeKey) =>\r\n $(appHierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => isCollectionRecord(n) && n.collectionNodeKey() === nodeKey),\r\n ])\r\n\r\nexport const getNodeByKeyOrNodeKey = (appHierarchy, keyOrNodeKey) => {\r\n const nodeByKey = getExactNodeForKey(appHierarchy)(keyOrNodeKey)\r\n return isNothing(nodeByKey) ? getNode(appHierarchy, keyOrNodeKey) : nodeByKey\r\n}\r\n\r\nexport const getCollectionNodeByKeyOrNodeKey = (appHierarchy, keyOrNodeKey) => {\r\n const nodeByKey = getNodeForCollectionPath(appHierarchy)(keyOrNodeKey)\r\n return isNothing(nodeByKey)\r\n ? getCollectionNode(appHierarchy, keyOrNodeKey)\r\n : nodeByKey\r\n}\r\n\r\nexport const isNode = (appHierarchy, key) =>\r\n isSomething(getExactNodeForKey(appHierarchy)(key))\r\n\r\nexport const getActualKeyOfParent = (parentNodeKey, actualChildKey) =>\r\n $(actualChildKey, [\r\n splitKey,\r\n take(splitKey(parentNodeKey).length),\r\n ks => joinKey(...ks),\r\n ])\r\n\r\nexport const getParentKey = key => {\r\n return $(key, [splitKey, take(splitKey(key).length - 1), joinKey])\r\n}\r\n\r\nexport const isKeyAncestorOf = ancestorKey => decendantNode =>\r\n hasMatchingAncestor(p => p.nodeKey() === ancestorKey)(decendantNode)\r\n\r\nexport const hasNoMatchingAncestors = parentPredicate => node =>\r\n !hasMatchingAncestor(parentPredicate)(node)\r\n\r\nexport const findField = (recordNode, fieldName) =>\r\n find(f => f.name == fieldName)(recordNode.fields)\r\n\r\nexport const isAncestor = decendant => ancestor =>\r\n isKeyAncestorOf(ancestor.nodeKey())(decendant)\r\n\r\nexport const isDecendant = ancestor => decendant =>\r\n isAncestor(decendant)(ancestor)\r\n\r\nexport const getRecordNodeId = recordKey =>\r\n $(recordKey, [splitKey, last, getRecordNodeIdFromId])\r\n\r\nexport const getRecordNodeIdFromId = recordId =>\r\n $(recordId, [split(\"-\"), first, parseInt])\r\n\r\nexport const getRecordNodeById = (hierarchy, recordId) =>\r\n $(hierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => isTable(n) && n.nodeId === getRecordNodeIdFromId(recordId)),\r\n ])\r\n\r\nexport const recordNodeIdIsAllowed = indexNode => nodeId =>\r\n indexNode.allowedTableNodeIds.length === 0 ||\r\n includes(nodeId)(indexNode.allowedTableNodeIds)\r\n\r\nexport const recordNodeIsAllowed = indexNode => recordNode =>\r\n recordNodeIdIsAllowed(indexNode)(recordNode.nodeId)\r\n\r\nexport const getAllowedRecordNodesForIndex = (appHierarchy, indexNode) => {\r\n const recordNodes = $(appHierarchy, [getFlattenedHierarchy, filter(isTable)])\r\n\r\n if (isGlobalIndex(indexNode)) {\r\n return $(recordNodes, [filter(recordNodeIsAllowed(indexNode))])\r\n }\r\n\r\n if (isAncestorIndex(indexNode)) {\r\n return $(recordNodes, [\r\n filter(isDecendant(indexNode.parent())),\r\n filter(recordNodeIsAllowed(indexNode)),\r\n ])\r\n }\r\n\r\n if (isReferenceIndex(indexNode)) {\r\n return $(recordNodes, [\r\n filter(n => some(fieldReversesReferenceToIndex(indexNode))(n.fields)),\r\n ])\r\n }\r\n}\r\n\r\nexport const getNodeFromNodeKeyHash = hierarchy => hash =>\r\n $(hierarchy, [\r\n getFlattenedHierarchy,\r\n find(n => getHashCode(n.nodeKey()) === hash),\r\n ])\r\n\r\nexport const isTable = node => isSomething(node) && node.type === \"record\"\r\nexport const isSingleRecord = node => isTable(node) && node.isSingle\r\nexport const isCollectionRecord = node => isTable(node) && !node.isSingle\r\nexport const isIndex = node => isSomething(node) && node.type === \"index\"\r\nexport const isaggregateGroup = node =>\r\n isSomething(node) && node.type === \"aggregateGroup\"\r\nexport const isShardedIndex = node =>\r\n isIndex(node) && isNonEmptyString(node.getShardName)\r\nexport const isRoot = node => isSomething(node) && node.isRoot()\r\nexport const isDecendantOfARecord = hasMatchingAncestor(isTable)\r\nexport const isGlobalIndex = node => isIndex(node) && isRoot(node.parent())\r\nexport const isReferenceIndex = node =>\r\n isIndex(node) && node.indexType === indexTypes.reference\r\nexport const isAncestorIndex = node =>\r\n isIndex(node) && node.indexType === indexTypes.ancestor\r\n\r\nexport const fieldReversesReferenceToNode = node => field =>\r\n field.type === \"reference\" &&\r\n intersection(field.typeOptions.reverseIndexNodeKeys)(\r\n map(i => i.nodeKey())(node.indexes)\r\n ).length > 0\r\n\r\nexport const fieldReversesReferenceToIndex = indexNode => field =>\r\n field.type === \"reference\" &&\r\n intersection(field.typeOptions.reverseIndexNodeKeys)([indexNode.nodeKey()])\r\n .length > 0\r\n\r\nexport default {\r\n getLastPartInKey,\r\n getNodesInPath,\r\n getExactNodeForKey,\r\n hasMatchingAncestor,\r\n getNode,\r\n getNodeByKeyOrNodeKey,\r\n isNode,\r\n getActualKeyOfParent,\r\n getParentKey,\r\n isKeyAncestorOf,\r\n hasNoMatchingAncestors,\r\n findField,\r\n isAncestor,\r\n isDecendant,\r\n getRecordNodeId,\r\n getRecordNodeIdFromId,\r\n getRecordNodeById,\r\n recordNodeIdIsAllowed,\r\n recordNodeIsAllowed,\r\n getAllowedRecordNodesForIndex,\r\n getNodeFromNodeKeyHash,\r\n isTable,\r\n isCollectionRecord,\r\n isIndex,\r\n isaggregateGroup,\r\n isShardedIndex,\r\n isRoot,\r\n isDecendantOfARecord,\r\n isGlobalIndex,\r\n isReferenceIndex,\r\n isAncestorIndex,\r\n fieldReversesReferenceToNode,\r\n fieldReversesReferenceToIndex,\r\n getFlattenedHierarchy,\r\n}\r\n", "import { merge } from \"lodash\"\r\nimport { constant, isUndefined, has, mapValues, cloneDeep } from \"lodash/fp\"\r\nimport { isNotEmpty } from \"../common\"\r\n\r\nexport const getSafeFieldParser = (tryParse, defaultValueFunctions) => (\r\n field,\r\n record\r\n) => {\r\n if (has(field.name)(record)) {\r\n return getSafeValueParser(\r\n tryParse,\r\n defaultValueFunctions\r\n )(record[field.name])\r\n }\r\n return defaultValueFunctions[field.getUndefinedValue]()\r\n}\r\n\r\nexport const getSafeValueParser = (\r\n tryParse,\r\n defaultValueFunctions\r\n) => value => {\r\n const parsed = tryParse(value)\r\n if (parsed.success) {\r\n return parsed.value\r\n }\r\n return defaultValueFunctions.default()\r\n}\r\n\r\nexport const getNewValue = (tryParse, defaultValueFunctions) => field => {\r\n const getInitialValue =\r\n isUndefined(field) || isUndefined(field.getInitialValue)\r\n ? \"default\"\r\n : field.getInitialValue\r\n\r\n return has(getInitialValue)(defaultValueFunctions)\r\n ? defaultValueFunctions[getInitialValue]()\r\n : getSafeValueParser(tryParse, defaultValueFunctions)(getInitialValue)\r\n}\r\n\r\nexport const typeFunctions = specificFunctions =>\r\n merge(\r\n {\r\n value: constant,\r\n null: constant(null),\r\n },\r\n specificFunctions\r\n )\r\n\r\nexport const validateTypeConstraints = validationRules => async (\r\n field,\r\n record,\r\n context\r\n) => {\r\n const fieldValue = record[field.name]\r\n const validateRule = async r =>\r\n !(await r.isValid(fieldValue, field.typeOptions, context))\r\n ? r.getMessage(fieldValue, field.typeOptions)\r\n : \"\"\r\n\r\n const errors = []\r\n for (const r of validationRules) {\r\n const err = await validateRule(r)\r\n if (isNotEmpty(err)) errors.push(err)\r\n }\r\n\r\n return errors\r\n}\r\n\r\nconst getDefaultOptions = mapValues(v => v.defaultValue)\r\n\r\nexport const makerule = (isValid, getMessage) => ({ isValid, getMessage })\r\nexport const parsedFailed = val => ({ success: false, value: val })\r\nexport const parsedSuccess = val => ({ success: true, value: val })\r\nexport const getDefaultExport = (\r\n name,\r\n tryParse,\r\n functions,\r\n options,\r\n validationRules,\r\n sampleValue,\r\n stringify\r\n) => ({\r\n getNew: getNewValue(tryParse, functions),\r\n safeParseField: getSafeFieldParser(tryParse, functions),\r\n safeParseValue: getSafeValueParser(tryParse, functions),\r\n tryParse,\r\n name,\r\n getDefaultOptions: () => getDefaultOptions(cloneDeep(options)),\r\n optionDefinitions: options,\r\n validateTypeConstraints: validateTypeConstraints(validationRules),\r\n sampleValue,\r\n stringify: val => (val === null || val === undefined ? \"\" : stringify(val)),\r\n getDefaultValue: functions.default,\r\n})\r\n", "import { constant, isString, isNull, includes, isBoolean } from \"lodash/fp\"\r\nimport {\r\n typeFunctions,\r\n makerule,\r\n parsedSuccess,\r\n getDefaultExport,\r\n} from \"./typeHelpers\"\r\nimport {\r\n switchCase,\r\n defaultCase,\r\n toBoolOrNull,\r\n toNumberOrNull,\r\n isSafeInteger,\r\n isArrayOfString,\r\n} from \"../common\"\r\n\r\nconst stringFunctions = typeFunctions({\r\n default: constant(null),\r\n})\r\n\r\nconst stringTryParse = switchCase(\r\n [isString, parsedSuccess],\r\n [isNull, parsedSuccess],\r\n [defaultCase, v => parsedSuccess(v.toString())]\r\n)\r\n\r\nconst options = {\r\n maxLength: {\r\n defaultValue: null,\r\n isValid: n => n === null || (isSafeInteger(n) && n > 0),\r\n requirementDescription:\r\n \"max length must be null (no limit) or a greater than zero integer\",\r\n parse: toNumberOrNull,\r\n },\r\n values: {\r\n defaultValue: null,\r\n isValid: v =>\r\n v === null || (isArrayOfString(v) && v.length > 0 && v.length < 10000),\r\n requirementDescription:\r\n \"'values' must be null (no values) or an arry of at least one string\",\r\n parse: s => s,\r\n },\r\n allowDeclaredValuesOnly: {\r\n defaultValue: false,\r\n isValid: isBoolean,\r\n requirementDescription: \"allowDeclaredValuesOnly must be true or false\",\r\n parse: toBoolOrNull,\r\n },\r\n}\r\n\r\nconst typeConstraints = [\r\n makerule(\r\n async (val, opts) =>\r\n val === null || opts.maxLength === null || val.length <= opts.maxLength,\r\n (val, opts) => `value exceeds maximum length of ${opts.maxLength}`\r\n ),\r\n makerule(\r\n async (val, opts) =>\r\n val === null ||\r\n opts.allowDeclaredValuesOnly === false ||\r\n includes(val)(opts.values),\r\n val => `\"${val}\" does not exist in the list of allowed values`\r\n ),\r\n]\r\n\r\nexport default getDefaultExport(\r\n \"string\",\r\n stringTryParse,\r\n stringFunctions,\r\n options,\r\n typeConstraints,\r\n \"abcde\",\r\n str => str\r\n)\r\n", "import { constant, isBoolean, isNull } from \"lodash/fp\"\r\nimport {\r\n typeFunctions,\r\n makerule,\r\n parsedFailed,\r\n parsedSuccess,\r\n getDefaultExport,\r\n} from \"./typeHelpers\"\r\nimport { switchCase, defaultCase, isOneOf, toBoolOrNull } from \"../common\"\r\n\r\nconst boolFunctions = typeFunctions({\r\n default: constant(null),\r\n})\r\n\r\nconst boolTryParse = switchCase(\r\n [isBoolean, parsedSuccess],\r\n [isNull, parsedSuccess],\r\n [isOneOf(\"true\", \"1\", \"yes\", \"on\"), () => parsedSuccess(true)],\r\n [isOneOf(\"false\", \"0\", \"no\", \"off\"), () => parsedSuccess(false)],\r\n [defaultCase, parsedFailed]\r\n)\r\n\r\nconst options = {\r\n allowNulls: {\r\n defaultValue: true,\r\n isValid: isBoolean,\r\n requirementDescription: \"must be a true or false\",\r\n parse: toBoolOrNull,\r\n },\r\n}\r\n\r\nconst typeConstraints = [\r\n makerule(\r\n async (val, opts) => opts.allowNulls === true || val !== null,\r\n () => \"field cannot be null\"\r\n ),\r\n]\r\n\r\nexport default getDefaultExport(\r\n \"bool\",\r\n boolTryParse,\r\n boolFunctions,\r\n options,\r\n typeConstraints,\r\n true,\r\n JSON.stringify\r\n)\r\n", @@ -125,7 +125,7 @@ "import { values, includes, some } from \"lodash/fp\"\r\nimport { permissionTypes } from \"./authCommon\"\r\nimport { $, isNothing, apiWrapperSync, events } from \"../common\"\r\nimport { getNodeByKeyOrNodeKey, isNode } from \"../templateApi/hierarchy\"\r\nimport { alwaysAuthorized } from \"./permissions\"\r\n\r\nexport const isAuthorized = app => (permissionType, resourceKey) =>\r\n apiWrapperSync(\r\n app,\r\n events.authApi.isAuthorized,\r\n alwaysAuthorized,\r\n { resourceKey, permissionType },\r\n _isAuthorized,\r\n app,\r\n permissionType,\r\n resourceKey\r\n )\r\n\r\nexport const _isAuthorized = (app, permissionType, resourceKey) => {\r\n if (!app.user) {\r\n return false\r\n }\r\n\r\n const validType = $(permissionTypes, [values, includes(permissionType)])\r\n\r\n if (!validType) {\r\n return false\r\n }\r\n\r\n const permMatchesResource = userperm => {\r\n const nodeKey = isNothing(resourceKey)\r\n ? null\r\n : isNode(app.hierarchy, resourceKey)\r\n ? getNodeByKeyOrNodeKey(app.hierarchy, resourceKey).nodeKey()\r\n : resourceKey\r\n\r\n return (\r\n userperm.type === permissionType &&\r\n (isNothing(resourceKey) || nodeKey === userperm.nodeKey)\r\n )\r\n }\r\n\r\n return $(app.user.permissions, [some(permMatchesResource)])\r\n}\r\n", "import { permissionTypes } from \"./authCommon\"\r\nimport { isAuthorized } from \"./isAuthorized\"\r\n\r\nexport const temporaryAccessPermissions = () => [\r\n { type: permissionTypes.SET_PASSWORD },\r\n]\r\n\r\nconst nodePermission = type => ({\r\n add: (nodeKey, accessLevel) =>\r\n accessLevel.permissions.push({ type, nodeKey }),\r\n isAuthorized: resourceKey => app => isAuthorized(app)(type, resourceKey),\r\n isNode: true,\r\n get: nodeKey => ({ type, nodeKey }),\r\n})\r\n\r\nconst staticPermission = type => ({\r\n add: accessLevel => accessLevel.permissions.push({ type }),\r\n isAuthorized: app => isAuthorized(app)(type),\r\n isNode: false,\r\n get: () => ({ type }),\r\n})\r\n\r\nconst createRecord = nodePermission(permissionTypes.CREATE_RECORD)\r\n\r\nconst updateRecord = nodePermission(permissionTypes.UPDATE_RECORD)\r\n\r\nconst deleteRecord = nodePermission(permissionTypes.DELETE_RECORD)\r\n\r\nconst readRecord = nodePermission(permissionTypes.READ_RECORD)\r\n\r\nconst writeTemplates = staticPermission(permissionTypes.WRITE_TEMPLATES)\r\n\r\nconst createUser = staticPermission(permissionTypes.CREATE_USER)\r\n\r\nconst setPassword = staticPermission(permissionTypes.SET_PASSWORD)\r\n\r\nconst readIndex = nodePermission(permissionTypes.READ_INDEX)\r\n\r\nconst manageIndex = staticPermission(permissionTypes.MANAGE_INDEX)\r\n\r\nconst manageCollection = staticPermission(permissionTypes.MANAGE_COLLECTION)\r\n\r\nconst createTemporaryAccess = staticPermission(\r\n permissionTypes.CREATE_TEMPORARY_ACCESS\r\n)\r\n\r\nconst enableDisableUser = staticPermission(permissionTypes.ENABLE_DISABLE_USER)\r\n\r\nconst writeAccessLevels = staticPermission(permissionTypes.WRITE_ACCESS_LEVELS)\r\n\r\nconst listUsers = staticPermission(permissionTypes.LIST_USERS)\r\n\r\nconst listAccessLevels = staticPermission(permissionTypes.LIST_ACCESS_LEVELS)\r\n\r\nconst setUserAccessLevels = staticPermission(\r\n permissionTypes.SET_USER_ACCESS_LEVELS\r\n)\r\n\r\nconst executeAction = nodePermission(permissionTypes.EXECUTE_ACTION)\r\n\r\nexport const alwaysAuthorized = () => true\r\n\r\nexport const permission = {\r\n createRecord,\r\n updateRecord,\r\n deleteRecord,\r\n readRecord,\r\n writeTemplates,\r\n createUser,\r\n setPassword,\r\n readIndex,\r\n createTemporaryAccess,\r\n enableDisableUser,\r\n writeAccessLevels,\r\n listUsers,\r\n listAccessLevels,\r\n manageIndex,\r\n manageCollection,\r\n executeAction,\r\n setUserAccessLevels,\r\n}\r\n", "import { keyBy, mapValues } from \"lodash/fp\"\r\nimport { generate } from \"shortid\"\r\nimport {\r\n getNodeForCollectionPath,\r\n isSingleRecord,\r\n} from \"../templateApi/hierarchy\"\r\nimport { getNewFieldValue } from \"../types\"\r\nimport { $, joinKey, safeKey, apiWrapperSync, events } from \"../common\"\r\nimport { permission } from \"../authApi/permissions\"\r\n\r\nexport const getNew = app => (collectionKey, recordTypeName) => {\r\n const recordNode = getRecordNode(app, collectionKey, recordTypeName)\r\n collectionKey = safeKey(collectionKey)\r\n return apiWrapperSync(\r\n app,\r\n events.recordApi.getNew,\r\n permission.createRecord.isAuthorized(recordNode.nodeKey()),\r\n { collectionKey, recordTypeName },\r\n _getNew,\r\n recordNode,\r\n collectionKey\r\n )\r\n}\r\n\r\nexport const _getNew = (recordNode, collectionKey) =>\r\n constructRecord(recordNode, getNewFieldValue, collectionKey)\r\n\r\nconst getRecordNode = (app, collectionKey) => {\r\n collectionKey = safeKey(collectionKey)\r\n return getNodeForCollectionPath(app.hierarchy)(collectionKey)\r\n}\r\n\r\nexport const getNewChild = app => (recordKey, collectionName, recordTypeName) =>\r\n getNew(app)(joinKey(recordKey, collectionName), recordTypeName)\r\n\r\nexport const constructRecord = (recordNode, getFieldValue, collectionKey) => {\r\n const record = $(recordNode.fields, [keyBy(\"name\"), mapValues(getFieldValue)])\r\n\r\n record.id = `${recordNode.nodeId}-${generate()}`\r\n record.key = isSingleRecord(recordNode)\r\n ? joinKey(collectionKey, recordNode.name)\r\n : joinKey(collectionKey, record.id)\r\n record.isNew = true\r\n record.type = recordNode.name\r\n return record\r\n}\r\n", - "import { each, find } from \"lodash\"\r\nimport { map, max, constant } from \"lodash/fp\"\r\nimport {\r\n switchCase,\r\n defaultCase,\r\n joinKey,\r\n $,\r\n isNothing,\r\n isSomething,\r\n} from \"../common\"\r\nimport {\r\n isIndex,\r\n isRoot,\r\n isSingleRecord,\r\n isCollectionRecord,\r\n isModel,\r\n isaggregateGroup,\r\n getFlattenedHierarchy,\r\n} from \"./hierarchy\"\r\nimport { all } from \"../types\"\r\nimport { BadRequestError } from \"../common/errors\"\r\n\r\nexport const createNodeErrors = {\r\n indexCannotBeParent: \"Index template cannot be a parent\",\r\n allNonRootNodesMustHaveParent: \"Only the root node may have no parent\",\r\n indexParentMustBeRecordOrRoot:\r\n \"An index may only have a record or root as a parent\",\r\n aggregateParentMustBeAnIndex: \"aggregateGroup parent must be an index\",\r\n}\r\n\r\nconst pathRegxMaker = node => () =>\r\n node.nodeKey().replace(/{id}/g, \"[a-zA-Z0-9_-]+\")\r\n\r\nconst nodeKeyMaker = node => () =>\r\n switchCase(\r\n [\r\n n => isModel(n) && !isSingleRecord(n),\r\n n =>\r\n joinKey(\r\n node.parent().nodeKey(),\r\n node.collectionName,\r\n `${n.nodeId}-{id}`\r\n ),\r\n ],\r\n\r\n [isRoot, constant(\"/\")],\r\n\r\n [defaultCase, n => joinKey(node.parent().nodeKey(), n.name)]\r\n )(node)\r\n\r\nconst validate = parent => node => {\r\n if (\r\n isIndex(node) &&\r\n isSomething(parent) &&\r\n !isRoot(parent) &&\r\n !isModel(parent)\r\n ) {\r\n throw new BadRequestError(createNodeErrors.indexParentMustBeRecordOrRoot)\r\n }\r\n\r\n if (isaggregateGroup(node) && isSomething(parent) && !isIndex(parent)) {\r\n throw new BadRequestError(createNodeErrors.aggregateParentMustBeAnIndex)\r\n }\r\n\r\n if (isNothing(parent) && !isRoot(node)) {\r\n throw new BadRequestError(createNodeErrors.allNonRootNodesMustHaveParent)\r\n }\r\n\r\n return node\r\n}\r\n\r\nconst construct = parent => node => {\r\n node.nodeKey = nodeKeyMaker(node)\r\n node.pathRegx = pathRegxMaker(node)\r\n node.parent = constant(parent)\r\n node.isRoot = () =>\r\n isNothing(parent) && node.name === \"root\" && node.type === \"root\"\r\n if (isCollectionRecord(node)) {\r\n node.collectionNodeKey = () =>\r\n joinKey(parent.nodeKey(), node.collectionName)\r\n node.collectionPathRegx = () =>\r\n joinKey(parent.pathRegx(), node.collectionName)\r\n }\r\n return node\r\n}\r\n\r\nconst addToParent = obj => {\r\n const parent = obj.parent()\r\n if (isSomething(parent)) {\r\n if (isIndex(obj)) {\r\n // Q: why are indexes not children ?\r\n // A: because they cannot have children of their own.\r\n parent.indexes.push(obj)\r\n } else if (isaggregateGroup(obj)) {\r\n parent.aggregateGroups.push(obj)\r\n } else {\r\n parent.children.push(obj)\r\n }\r\n\r\n if (isModel(obj)) {\r\n const defaultIndex = find(\r\n parent.indexes,\r\n i => i.name === `${parent.name}_index`\r\n )\r\n if (defaultIndex) {\r\n defaultIndex.allowedModelNodeIds.push(obj.nodeId)\r\n }\r\n }\r\n }\r\n return obj\r\n}\r\n\r\nexport const constructNode = (parent, obj) =>\r\n $(obj, [construct(parent), validate(parent), addToParent])\r\n\r\nconst getNodeId = parentNode => {\r\n // this case is handled better elsewhere\r\n if (!parentNode) return null\r\n const findRoot = n => (isRoot(n) ? n : findRoot(n.parent()))\r\n const root = findRoot(parentNode)\r\n\r\n return $(root, [getFlattenedHierarchy, map(n => n.nodeId), max]) + 1\r\n}\r\n\r\nexport const constructHierarchy = (node, parent) => {\r\n construct(parent)(node)\r\n if (node.indexes) {\r\n each(node.indexes, child => constructHierarchy(child, node))\r\n }\r\n if (node.aggregateGroups) {\r\n each(node.aggregateGroups, child => constructHierarchy(child, node))\r\n }\r\n if (node.children && node.children.length > 0) {\r\n each(node.children, child => constructHierarchy(child, node))\r\n }\r\n if (node.fields) {\r\n each(node.fields, f =>\r\n each(f.typeOptions, (val, key) => {\r\n const def = all[f.type].optionDefinitions[key]\r\n if (!def) {\r\n // unknown typeOption\r\n delete f.typeOptions[key]\r\n } else {\r\n f.typeOptions[key] = def.parse(val)\r\n }\r\n })\r\n )\r\n }\r\n return node\r\n}\r\n\r\nexport const getNewRootLevel = () =>\r\n construct()({\r\n name: \"root\",\r\n type: \"root\",\r\n children: [],\r\n pathMaps: [],\r\n indexes: [],\r\n nodeId: 0,\r\n })\r\n\r\nconst _getNewModelTemplate = (parent, name, createDefaultIndex, isSingle) => {\r\n const node = constructNode(parent, {\r\n name,\r\n type: \"record\",\r\n fields: [],\r\n children: [],\r\n validationRules: [],\r\n nodeId: getNodeId(parent),\r\n indexes: [],\r\n estimatedRecordCount: isModel(parent) ? 500 : 1000000,\r\n collectionName: \"\",\r\n isSingle,\r\n })\r\n\r\n if (createDefaultIndex) {\r\n const defaultIndex = getNewIndexTemplate(parent)\r\n defaultIndex.name = `${name}_index`\r\n defaultIndex.allowedModelNodeIds.push(node.nodeId)\r\n }\r\n\r\n return node\r\n}\r\n\r\nexport const getNewModelTemplate = (\r\n parent,\r\n name = \"\",\r\n createDefaultIndex = true\r\n) => _getNewModelTemplate(parent, name, createDefaultIndex, false)\r\n\r\nexport const getNewSingleRecordTemplate = parent =>\r\n _getNewModelTemplate(parent, \"\", false, true)\r\n\r\nexport const getNewIndexTemplate = (parent, type = \"ancestor\") =>\r\n constructNode(parent, {\r\n name: \"\",\r\n type: \"index\",\r\n map: \"return {...record};\",\r\n filter: \"\",\r\n indexType: type,\r\n getShardName: \"\",\r\n getSortKey: \"record.id\",\r\n aggregateGroups: [],\r\n allowedModelNodeIds: [],\r\n nodeId: getNodeId(parent),\r\n })\r\n\r\nexport const getNewAggregateGroupTemplate = index =>\r\n constructNode(index, {\r\n name: \"\",\r\n type: \"aggregateGroup\",\r\n groupBy: \"\",\r\n aggregates: [],\r\n condition: \"\",\r\n nodeId: getNodeId(index),\r\n })\r\n\r\nexport const getNewAggregateTemplate = set => {\r\n const aggregatedValue = {\r\n name: \"\",\r\n aggregatedValue: \"\",\r\n }\r\n set.aggregates.push(aggregatedValue)\r\n return aggregatedValue\r\n}\r\n\r\nexport default {\r\n getNewRootLevel,\r\n getNewModelTemplate,\r\n getNewIndexTemplate,\r\n createNodeErrors,\r\n constructHierarchy,\r\n getNewAggregateGroupTemplate,\r\n getNewAggregateTemplate,\r\n}\r\n", + "import { each, find } from \"lodash\"\r\nimport { map, max, constant } from \"lodash/fp\"\r\nimport {\r\n switchCase,\r\n defaultCase,\r\n joinKey,\r\n $,\r\n isNothing,\r\n isSomething,\r\n} from \"../common\"\r\nimport {\r\n isIndex,\r\n isRoot,\r\n isSingleRecord,\r\n isCollectionRecord,\r\n isTable,\r\n isaggregateGroup,\r\n getFlattenedHierarchy,\r\n} from \"./hierarchy\"\r\nimport { all } from \"../types\"\r\nimport { BadRequestError } from \"../common/errors\"\r\n\r\nexport const createNodeErrors = {\r\n indexCannotBeParent: \"Index template cannot be a parent\",\r\n allNonRootNodesMustHaveParent: \"Only the root node may have no parent\",\r\n indexParentMustBeRecordOrRoot:\r\n \"An index may only have a record or root as a parent\",\r\n aggregateParentMustBeAnIndex: \"aggregateGroup parent must be an index\",\r\n}\r\n\r\nconst pathRegxMaker = node => () =>\r\n node.nodeKey().replace(/{id}/g, \"[a-zA-Z0-9_-]+\")\r\n\r\nconst nodeKeyMaker = node => () =>\r\n switchCase(\r\n [\r\n n => isTable(n) && !isSingleRecord(n),\r\n n =>\r\n joinKey(\r\n node.parent().nodeKey(),\r\n node.collectionName,\r\n `${n.nodeId}-{id}`\r\n ),\r\n ],\r\n\r\n [isRoot, constant(\"/\")],\r\n\r\n [defaultCase, n => joinKey(node.parent().nodeKey(), n.name)]\r\n )(node)\r\n\r\nconst validate = parent => node => {\r\n if (\r\n isIndex(node) &&\r\n isSomething(parent) &&\r\n !isRoot(parent) &&\r\n !isTable(parent)\r\n ) {\r\n throw new BadRequestError(createNodeErrors.indexParentMustBeRecordOrRoot)\r\n }\r\n\r\n if (isaggregateGroup(node) && isSomething(parent) && !isIndex(parent)) {\r\n throw new BadRequestError(createNodeErrors.aggregateParentMustBeAnIndex)\r\n }\r\n\r\n if (isNothing(parent) && !isRoot(node)) {\r\n throw new BadRequestError(createNodeErrors.allNonRootNodesMustHaveParent)\r\n }\r\n\r\n return node\r\n}\r\n\r\nconst construct = parent => node => {\r\n node.nodeKey = nodeKeyMaker(node)\r\n node.pathRegx = pathRegxMaker(node)\r\n node.parent = constant(parent)\r\n node.isRoot = () =>\r\n isNothing(parent) && node.name === \"root\" && node.type === \"root\"\r\n if (isCollectionRecord(node)) {\r\n node.collectionNodeKey = () =>\r\n joinKey(parent.nodeKey(), node.collectionName)\r\n node.collectionPathRegx = () =>\r\n joinKey(parent.pathRegx(), node.collectionName)\r\n }\r\n return node\r\n}\r\n\r\nconst addToParent = obj => {\r\n const parent = obj.parent()\r\n if (isSomething(parent)) {\r\n if (isIndex(obj)) {\r\n // Q: why are indexes not children ?\r\n // A: because they cannot have children of their own.\r\n parent.indexes.push(obj)\r\n } else if (isaggregateGroup(obj)) {\r\n parent.aggregateGroups.push(obj)\r\n } else {\r\n parent.children.push(obj)\r\n }\r\n\r\n if (isTable(obj)) {\r\n const defaultIndex = find(\r\n parent.indexes,\r\n i => i.name === `${parent.name}_index`\r\n )\r\n if (defaultIndex) {\r\n defaultIndex.allowedTableNodeIds.push(obj.nodeId)\r\n }\r\n }\r\n }\r\n return obj\r\n}\r\n\r\nexport const constructNode = (parent, obj) =>\r\n $(obj, [construct(parent), validate(parent), addToParent])\r\n\r\nconst getNodeId = parentNode => {\r\n // this case is handled better elsewhere\r\n if (!parentNode) return null\r\n const findRoot = n => (isRoot(n) ? n : findRoot(n.parent()))\r\n const root = findRoot(parentNode)\r\n\r\n return $(root, [getFlattenedHierarchy, map(n => n.nodeId), max]) + 1\r\n}\r\n\r\nexport const constructHierarchy = (node, parent) => {\r\n construct(parent)(node)\r\n if (node.indexes) {\r\n each(node.indexes, child => constructHierarchy(child, node))\r\n }\r\n if (node.aggregateGroups) {\r\n each(node.aggregateGroups, child => constructHierarchy(child, node))\r\n }\r\n if (node.children && node.children.length > 0) {\r\n each(node.children, child => constructHierarchy(child, node))\r\n }\r\n if (node.fields) {\r\n each(node.fields, f =>\r\n each(f.typeOptions, (val, key) => {\r\n const def = all[f.type].optionDefinitions[key]\r\n if (!def) {\r\n // unknown typeOption\r\n delete f.typeOptions[key]\r\n } else {\r\n f.typeOptions[key] = def.parse(val)\r\n }\r\n })\r\n )\r\n }\r\n return node\r\n}\r\n\r\nexport const getNewRootLevel = () =>\r\n construct()({\r\n name: \"root\",\r\n type: \"root\",\r\n children: [],\r\n pathMaps: [],\r\n indexes: [],\r\n nodeId: 0,\r\n })\r\n\r\nconst _getNewTableTemplate = (parent, name, createDefaultIndex, isSingle) => {\r\n const node = constructNode(parent, {\r\n name,\r\n type: \"record\",\r\n fields: [],\r\n children: [],\r\n validationRules: [],\r\n nodeId: getNodeId(parent),\r\n indexes: [],\r\n estimatedRecordCount: isTable(parent) ? 500 : 1000000,\r\n collectionName: \"\",\r\n isSingle,\r\n })\r\n\r\n if (createDefaultIndex) {\r\n const defaultIndex = getNewIndexTemplate(parent)\r\n defaultIndex.name = `${name}_index`\r\n defaultIndex.allowedTableNodeIds.push(node.nodeId)\r\n }\r\n\r\n return node\r\n}\r\n\r\nexport const getNewTableTemplate = (\r\n parent,\r\n name = \"\",\r\n createDefaultIndex = true\r\n) => _getNewTableTemplate(parent, name, createDefaultIndex, false)\r\n\r\nexport const getNewSingleRecordTemplate = parent =>\r\n _getNewTableTemplate(parent, \"\", false, true)\r\n\r\nexport const getNewIndexTemplate = (parent, type = \"ancestor\") =>\r\n constructNode(parent, {\r\n name: \"\",\r\n type: \"index\",\r\n map: \"return {...record};\",\r\n filter: \"\",\r\n indexType: type,\r\n getShardName: \"\",\r\n getSortKey: \"record.id\",\r\n aggregateGroups: [],\r\n allowedTableNodeIds: [],\r\n nodeId: getNodeId(parent),\r\n })\r\n\r\nexport const getNewAggregateGroupTemplate = index =>\r\n constructNode(index, {\r\n name: \"\",\r\n type: \"aggregateGroup\",\r\n groupBy: \"\",\r\n aggregates: [],\r\n condition: \"\",\r\n nodeId: getNodeId(index),\r\n })\r\n\r\nexport const getNewAggregateTemplate = set => {\r\n const aggregatedValue = {\r\n name: \"\",\r\n aggregatedValue: \"\",\r\n }\r\n set.aggregates.push(aggregatedValue)\r\n return aggregatedValue\r\n}\r\n\r\nexport default {\r\n getNewRootLevel,\r\n getNewTableTemplate,\r\n getNewIndexTemplate,\r\n createNodeErrors,\r\n constructHierarchy,\r\n getNewAggregateGroupTemplate,\r\n getNewAggregateTemplate,\r\n}\r\n", "import { createCoreApp } from \"./createCoreApp\"\r\nimport { getNew, getNewChild } from \"../../../core/src/recordApi/getNew\"\r\nimport { constructHierarchy } from \"../../../core/src/templateApi/createNodes\"\r\n\r\nexport const createCoreApi = (backendDefinition, user) => {\r\n const app = createCoreApp(backendDefinition, user)\r\n\r\n return {\r\n recordApi: {\r\n getNew: getNew(app),\r\n getNewChild: getNewChild(app),\r\n },\r\n\r\n templateApi: {\r\n constructHierarchy,\r\n },\r\n }\r\n}\r\n", "export const BB_STATE_BINDINGPATH = \"##bbstate\"\r\nexport const BB_STATE_BINDINGSOURCE = \"##bbsource\"\r\nexport const BB_STATE_FALLBACK = \"##bbstatefallback\"\r\n\r\nexport const isBound = prop =>\r\n prop !== undefined && prop[BB_STATE_BINDINGPATH] !== undefined\r\n\r\nexport const takeStateFromStore = prop =>\r\n prop[BB_STATE_BINDINGSOURCE] === undefined ||\r\n prop[BB_STATE_BINDINGSOURCE] === \"store\"\r\n\r\nexport const takeStateFromContext = prop =>\r\n prop[BB_STATE_BINDINGSOURCE] === \"context\"\r\n\r\nexport const takeStateFromEventParameters = prop =>\r\n prop[BB_STATE_BINDINGSOURCE] === \"event\"\r\n", "import { isUndefined, isObject } from \"lodash/fp\"\r\nimport {\r\n isBound,\r\n BB_STATE_BINDINGPATH,\r\n BB_STATE_FALLBACK,\r\n takeStateFromStore,\r\n} from \"./isState\"\r\n\r\nexport const getState = (s, path, fallback) => {\r\n if (!s) return fallback\r\n if (!path || path.length === 0) return fallback\r\n\r\n if (path === \"$\") return s\r\n\r\n const pathParts = path.split(\".\")\r\n const safeGetPath = (obj, currentPartIndex = 0) => {\r\n const currentKey = pathParts[currentPartIndex]\r\n\r\n if (pathParts.length - 1 == currentPartIndex) {\r\n const value = obj[currentKey]\r\n if (isUndefined(value)) return fallback\r\n else return value\r\n }\r\n\r\n if (\r\n obj[currentKey] === null ||\r\n obj[currentKey] === undefined ||\r\n !isObject(obj[currentKey])\r\n ) {\r\n return fallback\r\n }\r\n\r\n return safeGetPath(obj[currentKey], currentPartIndex + 1)\r\n }\r\n\r\n return safeGetPath(s)\r\n}\r\n\r\nexport const getStateOrValue = (globalState, prop, currentContext) => {\r\n if (!prop) return prop\r\n\r\n if (isBound(prop)) {\r\n const stateToUse = takeStateFromStore(prop) ? globalState : currentContext\r\n\r\n return getState(\r\n stateToUse,\r\n prop[BB_STATE_BINDINGPATH],\r\n prop[BB_STATE_FALLBACK]\r\n )\r\n }\r\n\r\n if (prop.path && prop.source) {\r\n const stateToUse = prop.source === \"store\" ? globalState : currentContext\r\n\r\n return getState(stateToUse, prop.path, prop.fallback)\r\n }\r\n\r\n return prop\r\n}\r\n", diff --git a/packages/standard-components/public/clientAppDefinition.js b/packages/standard-components/public/clientAppDefinition.js index f77f59ec03..c781299a5c 100644 --- a/packages/standard-components/public/clientAppDefinition.js +++ b/packages/standard-components/public/clientAppDefinition.js @@ -59,7 +59,7 @@ window["##BUDIBASE_APPDEFINITION##"] = { getShardName: "", getSortKey: "record.id", aggregateGroups: [], - allowedModelNodeIds: [2], + allowedTableNodeIds: [2], nodeId: 5, }, ], @@ -79,7 +79,7 @@ window["##BUDIBASE_APPDEFINITION##"] = { getShardName: "", getSortKey: "record.id", aggregateGroups: [], - allowedModelNodeIds: [1], + allowedTableNodeIds: [1], nodeId: 4, }, { @@ -91,7 +91,7 @@ window["##BUDIBASE_APPDEFINITION##"] = { getShardName: "", getSortKey: "record.id", aggregateGroups: [], - allowedModelNodeIds: [2], + allowedTableNodeIds: [2], nodeId: 6, }, ], diff --git a/packages/standard-components/src/Chart/Brush.svelte b/packages/standard-components/src/Chart/Brush.svelte index 4294782575..31bd79b92a 100644 --- a/packages/standard-components/src/Chart/Brush.svelte +++ b/packages/standard-components/src/Chart/Brush.svelte @@ -12,7 +12,7 @@ */ export let _bb - export let model + export let table let store = _bb.store @@ -43,7 +43,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -54,12 +54,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -109,7 +109,7 @@ } } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: chartGradient = getChartGradient(gradient) $: console.log(chartGradient) diff --git a/packages/standard-components/src/Chart/Bullet.svelte b/packages/standard-components/src/Chart/Bullet.svelte index c4c140356e..83caea8136 100644 --- a/packages/standard-components/src/Chart/Bullet.svelte +++ b/packages/standard-components/src/Chart/Bullet.svelte @@ -9,7 +9,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -36,7 +36,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -46,12 +46,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -95,7 +95,7 @@ } } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/Heatmap.svelte b/packages/standard-components/src/Chart/Heatmap.svelte index 2d5422d364..daad75ddc0 100644 --- a/packages/standard-components/src/Chart/Heatmap.svelte +++ b/packages/standard-components/src/Chart/Heatmap.svelte @@ -9,7 +9,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -31,7 +31,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -41,12 +41,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -72,7 +72,7 @@ } } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/ScatterPlot.svelte b/packages/standard-components/src/Chart/ScatterPlot.svelte index d685f7421f..1f58d11e73 100644 --- a/packages/standard-components/src/Chart/ScatterPlot.svelte +++ b/packages/standard-components/src/Chart/ScatterPlot.svelte @@ -9,7 +9,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -58,7 +58,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -70,12 +70,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -176,7 +176,7 @@ tooltipContainer.datum([]).call(tooltip) } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/Sparkline.svelte b/packages/standard-components/src/Chart/Sparkline.svelte index e1bc29e278..372628c1e6 100644 --- a/packages/standard-components/src/Chart/Sparkline.svelte +++ b/packages/standard-components/src/Chart/Sparkline.svelte @@ -9,7 +9,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -35,7 +35,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -45,12 +45,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -91,7 +91,7 @@ } } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: aGradient = getChartGradient(areaGradient) $: lGradient = getChartGradient(lineGradient) diff --git a/packages/standard-components/src/Chart/StackedArea.svelte b/packages/standard-components/src/Chart/StackedArea.svelte index 0218ae327f..c493cabba6 100644 --- a/packages/standard-components/src/Chart/StackedArea.svelte +++ b/packages/standard-components/src/Chart/StackedArea.svelte @@ -9,7 +9,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -58,7 +58,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -70,12 +70,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -170,7 +170,7 @@ } } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/StackedBar.svelte b/packages/standard-components/src/Chart/StackedBar.svelte index f616d1a398..324bf42f78 100644 --- a/packages/standard-components/src/Chart/StackedBar.svelte +++ b/packages/standard-components/src/Chart/StackedBar.svelte @@ -13,7 +13,7 @@ const legendClass = `legend-container-${_id}` export let _bb - export let model + export let table let store = _bb.store @@ -53,7 +53,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -65,12 +65,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -165,7 +165,7 @@ tooltipContainer.datum([]).call(tooltip) } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/Step.svelte b/packages/standard-components/src/Chart/Step.svelte index 342f5ca3ec..044b39bb4e 100644 --- a/packages/standard-components/src/Chart/Step.svelte +++ b/packages/standard-components/src/Chart/Step.svelte @@ -13,7 +13,7 @@ const _id = shortid.generate() export let _bb - export let model + export let table let store = _bb.store @@ -48,7 +48,7 @@ onMount(async () => { if (chart) { - if (model) { + if (table) { await fetchData() } chartContainer = select(`.${chartClass}`) @@ -60,12 +60,12 @@ }) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -118,7 +118,7 @@ tooltipContainer.datum([]).call(tooltip) } - $: _data = model ? $store[model] : data + $: _data = table ? $store[table] : data $: colorSchema = getColorSchema(color) diff --git a/packages/standard-components/src/Chart/tests/line.html b/packages/standard-components/src/Chart/tests/line.html index ecf812dc70..2df1369f30 100644 --- a/packages/standard-components/src/Chart/tests/line.html +++ b/packages/standard-components/src/Chart/tests/line.html @@ -31,7 +31,7 @@ amount: 8, audited: new Date("2020-01-01T16:00:00-08:00"), city: "Belfast", name: 1, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "ceb87054790f480e80512368545755bb", _rev: "2-56e401ebaf59e6310b85fb0c6c2fece5", @@ -41,7 +41,7 @@ amount: 12, audited: new Date("2020-01-03T16:00:00-08:00"), city: "Belfast", name: 1, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "0a36103b55124f348a23d10b2f3ed0e3", _rev: "2-50d62530b2edfc63d5fd0b3719dbb286", @@ -51,7 +51,7 @@ amount: 6, audited: new Date("2020-01-04T16:00:00-08:00"), city: "Belfast", name: 1, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "68ade2bb94754caa8fc62c7084e3cef7", _rev: "2-a03fe02f3595920adfbcd9c70564fe9d", @@ -61,7 +61,7 @@ amount: 2, audited: new Date("2020-01-01T16:00:00-08:00"), city: "Dublin", name: 2, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "2ab6dabf833f4d99b3438fa4353ba429", _rev: "2-45b190489e76842981902cc9f04369ec", @@ -71,7 +71,7 @@ amount: 16, audited: new Date("2020-01-02T16:00:00-08:00"), city: "Dublin", name: 2, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "1b2ca36db1724427a98ba95547f946e0", _rev: "2-c43def17ada959948b9af5484ad5b6b7", @@ -81,7 +81,7 @@ amount: 7, audited: new Date("2020-01-03T16:00:00-08:00"), city: "Dublin", name: 2, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "d9235d884a224ca68ac30cefdbb8ae53", _rev: "2-695e426a261a25474cbf6b1f069dccb4", @@ -91,7 +91,7 @@ amount: 3, audited: new Date("2020-01-04T16:00:00-08:00"), city: "Dublin", name: 2, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "9f8bc39a9cfb4f779da8c998d7622927", _rev: "2-8ae1aff82e1ffc6ffa75f6b9d074e003", @@ -101,7 +101,7 @@ amount: 4, audited: new Date("2020-01-02T16:00:00-08:00"), city: "London", name: 3, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "75274e906073493bbf75cda8656e8db0", _rev: "2-6cfc6bb2fccb83c92b50aa5507f2a092" @@ -111,7 +111,7 @@ amount: 22, audited: new Date("2020-01-06T16:00:00-08:00"), city: "London", name: 3, -modelId: "2334751ac0764c1a931bff5b6b6767eb", +tableId: "2334751ac0764c1a931bff5b6b6767eb", type: "record", _id: "da3d4b151bc641f4ace487a2314d2550", _rev: "2-ac18490eaa016be0e71bd4c4ea332981", diff --git a/packages/standard-components/src/DataChart.svelte b/packages/standard-components/src/DataChart.svelte index 8b6dcdcc17..4e659902c8 100644 --- a/packages/standard-components/src/DataChart.svelte +++ b/packages/standard-components/src/DataChart.svelte @@ -8,7 +8,7 @@ fcRoot(FusionCharts, Charts, FusionTheme) export let _bb - export let model + export let table export let type = "column2d" let store = _bb.store @@ -19,19 +19,19 @@ height: "400", dataFormat: "json", dataSource: { - data: $store[model] || [], + data: $store[table] || [], }, } $: console.log("CHART CONFIGS", chartConfigs) async function fetchData() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { diff --git a/packages/standard-components/src/DataForm.svelte b/packages/standard-components/src/DataForm.svelte index 3cb7b7204c..8e7f9cb50d 100644 --- a/packages/standard-components/src/DataForm.svelte +++ b/packages/standard-components/src/DataForm.svelte @@ -2,9 +2,9 @@ import Form from "./Form.svelte" export let _bb - export let model + export let table export let title export let buttonText -
+ diff --git a/packages/standard-components/src/DataFormWide.svelte b/packages/standard-components/src/DataFormWide.svelte index 68dfd7b7cf..412f29a5ce 100644 --- a/packages/standard-components/src/DataFormWide.svelte +++ b/packages/standard-components/src/DataFormWide.svelte @@ -2,9 +2,9 @@ import Form from "./Form.svelte" export let _bb - export let model + export let table export let title export let buttonText - + diff --git a/packages/standard-components/src/DataList.svelte b/packages/standard-components/src/DataList.svelte index 9ef0b92d2c..502c005c1c 100644 --- a/packages/standard-components/src/DataList.svelte +++ b/packages/standard-components/src/DataList.svelte @@ -2,22 +2,22 @@ import { onMount } from "svelte" export let _bb - export let model + export let table export let layout = "list" let headers = [] let store = _bb.store async function fetchData() { - if (!model || !model.length) return + if (!table || !table.length) return - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const json = await response.json() store.update(state => { - state[model] = json + state[table] = json return state }) } else { @@ -25,8 +25,8 @@ } } - $: data = $store[model] || [] - $: if (model) fetchData() + $: data = $store[table] || [] + $: if (table) fetchData() onMount(async () => { await fetchData() diff --git a/packages/standard-components/src/DataSearch.svelte b/packages/standard-components/src/DataSearch.svelte index 7251d82aa7..1521dae418 100644 --- a/packages/standard-components/src/DataSearch.svelte +++ b/packages/standard-components/src/DataSearch.svelte @@ -1,6 +1,6 @@ -{#if linkedModel != null} - {#if linkedModel.primaryDisplay == null} +{#if linkedTable != null} + {#if linkedTable.primaryDisplay == null} {#if showLabel} {/if} {:else} diff --git a/packages/standard-components/src/RecordDetail.svelte b/packages/standard-components/src/RecordDetail.svelte index aa9d39c0cc..2e51bd3937 100644 --- a/packages/standard-components/src/RecordDetail.svelte +++ b/packages/standard-components/src/RecordDetail.svelte @@ -2,20 +2,20 @@ import { onMount } from "svelte" export let _bb - export let model + export let table let headers = [] let store = _bb.store let target - async function fetchModel(id) { - const FETCH_MODEL_URL = `/api/models/${id}` - const response = await _bb.api.get(FETCH_MODEL_URL) + async function fetchTable(id) { + const FETCH_TABLE_URL = `/api/tables/${id}` + const response = await _bb.api.get(FETCH_TABLE_URL) return await response.json() } async function fetchFirstRecord() { - const FETCH_RECORDS_URL = `/api/views/all_${model}` + const FETCH_RECORDS_URL = `/api/views/all_${table}` const response = await _bb.api.get(FETCH_RECORDS_URL) if (response.status === 200) { const allRecords = await response.json() @@ -32,7 +32,7 @@ record = await fetchFirstRecord() } else { const id = pathParts[pathParts.length - 1] - const GET_RECORD_URL = `/api/${model}/records/${id}` + const GET_RECORD_URL = `/api/${table}/records/${id}` const response = await _bb.api.get(GET_RECORD_URL) if (response.status === 200) { record = await response.json() @@ -40,10 +40,10 @@ } if (record) { - // Fetch model schema so we can check for linked records - const model = await fetchModel(record.modelId) - for (let key of Object.keys(model.schema)) { - if (model.schema[key].type === "link") { + // Fetch table schema so we can check for linked records + const table = await fetchTable(record.tableId) + for (let key of Object.keys(table.schema)) { + if (table.schema[key].type === "link") { record[key] = Array.isArray(record[key]) ? record[key].length : 0 } } diff --git a/packages/standard-components/src/fetchData.js b/packages/standard-components/src/fetchData.js index a0c50c233a..3722522b80 100644 --- a/packages/standard-components/src/fetchData.js +++ b/packages/standard-components/src/fetchData.js @@ -1,18 +1,18 @@ import api from "./api" export default async function fetchData(datasource) { - const { isModel, name } = datasource + const { isTable, name } = datasource if (name) { - const records = isModel ? await fetchModelData() : await fetchViewData() + const records = isTable ? await fetchTableData() : await fetchViewData() - // Fetch model schema so we can check for linked records + // Fetch table schema so we can check for linked records if (records && records.length) { - const model = await fetchModel(records[0].modelId) - const keys = Object.keys(model.schema) + const table = await fetchTable(records[0].tableId) + const keys = Object.keys(table.schema) records.forEach(record => { for (let key of keys) { - if (model.schema[key].type === "link") { + if (table.schema[key].type === "link") { record[key] = Array.isArray(record[key]) ? record[key].length : 0 } } @@ -22,18 +22,18 @@ export default async function fetchData(datasource) { return records } - async function fetchModel(id) { - const FETCH_MODEL_URL = `/api/models/${id}` - const response = await api.get(FETCH_MODEL_URL) + async function fetchTable(id) { + const FETCH_TABLE_URL = `/api/tables/${id}` + const response = await api.get(FETCH_TABLE_URL) return await response.json() } - async function fetchModelData() { + async function fetchTableData() { if (!name.startsWith("all_")) { - throw new Error("Incorrect model convention - must begin with all_") + throw new Error("Incorrect table convention - must begin with all_") } - const modelsResponse = await api.get(`/api/views/${name}`) - return await modelsResponse.json() + const tablesResponse = await api.get(`/api/views/${name}`) + return await tablesResponse.json() } async function fetchViewData() {