diff --git a/packages/builder/package.json b/packages/builder/package.json index e4b9040088..8645f285af 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -112,7 +112,7 @@ "rollup-plugin-terser": "^7.0.2", "rollup-plugin-url": "^2.2.2", "start-server-and-test": "^1.11.0", - "svelte": "^3.24.1", + "svelte": "^3.29.0", "svelte-jester": "^1.0.6" }, "gitHead": "115189f72a850bfb52b65ec61d932531bf327072" diff --git a/packages/builder/src/builderStore/getNewComponentName.js b/packages/builder/src/builderStore/getNewComponentName.js index b3ddc4e953..9ab8ef16dc 100644 --- a/packages/builder/src/builderStore/getNewComponentName.js +++ b/packages/builder/src/builderStore/getNewComponentName.js @@ -8,8 +8,9 @@ export default function(component, state) { const findMatches = props => { walkProps(props, c => { - if ((c._instanceName || "").startsWith(capitalised)) { - matchingComponents.push(c._instanceName) + const thisInstanceName = get_capitalised_name(c._instanceName) + if ((thisInstanceName || "").startsWith(capitalised)) { + matchingComponents.push(thisInstanceName) } }) } diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 70b88eb778..6941c74b22 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -124,17 +124,18 @@ const saveScreen = store => screen => { } const _saveScreen = async (store, s, screen) => { - const currentPageScreens = s.pages[s.currentPageName]._screens + const pageName = s.currentPageName || "main" + const currentPageScreens = s.pages[pageName]._screens await api - .post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen) + .post(`/_builder/api/${s.appId}/pages/${pageName}/screen`, screen) .then(() => { if (currentPageScreens.includes(screen)) return const screens = [...currentPageScreens, screen] store.update(innerState => { - innerState.pages[s.currentPageName]._screens = screens + innerState.pages[pageName]._screens = screens innerState.screens = screens innerState.currentPreviewItem = screen innerState.allScreens = [...innerState.allScreens, screen] @@ -153,27 +154,17 @@ const _saveScreen = async (store, s, screen) => { return s } -const createScreen = store => (screenName, route, layoutComponentName) => { +const createScreen = store => async screen => { + let savePromise store.update(state => { - const rootComponent = state.components[layoutComponentName] - - const newScreen = { - description: "", - url: "", - _css: "", - props: createProps(rootComponent).props, - } - newScreen.route = route - newScreen.name = newScreen.props._id - newScreen.props._instanceName = screenName || "" - state.currentPreviewItem = newScreen - state.currentComponentInfo = newScreen.props + state.currentPreviewItem = screen + state.currentComponentInfo = screen.props state.currentFrontEndType = "screen" - - _saveScreen(store, state, newScreen) - + savePromise = _saveScreen(store, state, screen) + regenerateCssForCurrentScreen(state) return state }) + await savePromise } const setCurrentScreen = store => screenName => { diff --git a/packages/builder/src/builderStore/store/screenTemplates/createFromScratchScreen.js b/packages/builder/src/builderStore/store/screenTemplates/createFromScratchScreen.js new file mode 100644 index 0000000000..a8ab27df3d --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/createFromScratchScreen.js @@ -0,0 +1,22 @@ +export default { + name: `Create from scratch`, + create: () => createScreen(), +} + +const createScreen = () => ({ + props: { + _id: "", + _component: "@budibase/standard-components/container", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + type: "div", + _children: [], + _instanceName: "", + }, + route: "", + name: "screen-id", +}) diff --git a/packages/builder/src/builderStore/store/screenTemplates/emptyNewRowScreen.js b/packages/builder/src/builderStore/store/screenTemplates/emptyNewRowScreen.js new file mode 100644 index 0000000000..e58319688b --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/emptyNewRowScreen.js @@ -0,0 +1,22 @@ +export default { + name: `New Row (Empty)`, + create: () => createScreen(), +} + +const createScreen = () => ({ + props: { + _id: "", + _component: "@budibase/standard-components/newrow", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _children: [], + _instanceName: "", + table: "", + }, + route: "", + name: "screen-id", +}) diff --git a/packages/builder/src/builderStore/store/screenTemplates/emptyRowDetailScreen.js b/packages/builder/src/builderStore/store/screenTemplates/emptyRowDetailScreen.js new file mode 100644 index 0000000000..a75de583cb --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/emptyRowDetailScreen.js @@ -0,0 +1,22 @@ +export default { + name: `Row Detail (Empty)`, + create: () => createScreen(), +} + +const createScreen = () => ({ + props: { + _id: "", + _component: "@budibase/standard-components/rowdetail", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _children: [], + _instanceName: "", + table: "", + }, + route: "", + name: "screen-id", +}) diff --git a/packages/builder/src/builderStore/store/screenTemplates/index.js b/packages/builder/src/builderStore/store/screenTemplates/index.js new file mode 100644 index 0000000000..5abe428966 --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/index.js @@ -0,0 +1,35 @@ +import newRowScreen from "./newRowScreen" +import rowDetailScreen from "./rowDetailScreen" +import rowListScreen from "./rowListScreen" +import emptyNewRowScreen from "./emptyNewRowScreen" +import createFromScratchScreen from "./createFromScratchScreen" +import emptyRowDetailScreen from "./emptyRowDetailScreen" +import { generateNewIdsForComponent } from "../../storeUtils" +import { uuid } from "builderStore/uuid" + +const allTemplates = tables => [ + createFromScratchScreen, + ...newRowScreen(tables), + ...rowDetailScreen(tables), + ...rowListScreen(tables), + emptyNewRowScreen, + emptyRowDetailScreen, +] + +// allows us to apply common behaviour to all create() functions +const createTemplateOverride = (frontendState, create) => () => { + const screen = create() + for (let component of screen.props._children) { + generateNewIdsForComponent(component, frontendState, false) + } + screen.props._id = uuid() + screen.name = screen.props._id + screen.route = screen.route.toLowerCase() + return screen +} + +export default (frontendState, tables) => + allTemplates(tables).map(template => ({ + ...template, + create: createTemplateOverride(frontendState, template.create), + })) diff --git a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js new file mode 100644 index 0000000000..571007c092 --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js @@ -0,0 +1,135 @@ +export default function(tables) { + return tables.map(table => { + const fields = Object.keys(table.schema) + const heading = fields.length > 0 ? `{{ data.${fields[0]} }}` : "Add Row" + return { + name: `${table.name} - New`, + create: () => createScreen(table, heading), + id: NEW_ROW_TEMPLATE, + } + }) +} + +export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE" + +const createScreen = (table, heading) => ({ + props: { + _id: "", + _component: "@budibase/standard-components/newrow", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + table: table._id, + _children: [ + { + _id: "", + _component: "@budibase/standard-components/heading", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + text: heading, + type: "h1", + _instanceName: "Heading 1", + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/dataform", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + _instanceName: `${table.name} Form`, + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/container", + _styles: { + normal: { + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "flex-end", + }, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + onLoad: [], + type: "div", + _instanceName: "Buttons Container", + _children: [ + { + _id: "", + _component: "@budibase/standard-components/button", + _styles: { + normal: { + "margin-right": "20px", + }, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + text: "Back", + className: "", + disabled: false, + onClick: [ + { + parameters: { + url: `/${table.name.toLowerCase()}`, + }, + "##eventHandlerType": "Navigate To", + }, + ], + _instanceName: "Back Button", + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/button", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + text: "Save", + className: "", + disabled: false, + onClick: [ + { + parameters: { + contextPath: "data", + tableId: table._id, + }, + "##eventHandlerType": "Save Row", + }, + ], + _instanceName: "Save Button", + _children: [], + }, + ], + }, + ], + _instanceName: `${table.name} - New`, + _code: "", + }, + route: `/${table.name.toLowerCase()}/new`, + name: "", +}) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js new file mode 100644 index 0000000000..58ca2f6d05 --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/rowDetailScreen.js @@ -0,0 +1,135 @@ +export default function(tables) { + return tables.map(table => { + const fields = Object.keys(table.schema) + const heading = fields.length > 0 ? `{{ data.${fields[0]} }}` : "Detail" + return { + name: `${table.name} - Detail`, + create: () => createScreen(table, heading), + id: ROW_DETAIL_TEMPLATE, + } + }) +} + +export const ROW_DETAIL_TEMPLATE = "ROW_DETAIL_TEMPLATE" + +const createScreen = (table, heading) => ({ + props: { + _id: "", + _component: "@budibase/standard-components/rowdetail", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + table: table._id, + _children: [ + { + _id: "", + _component: "@budibase/standard-components/heading", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + text: heading, + type: "h1", + _instanceName: "Heading 1", + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/dataform", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + _instanceName: `${table.name} Form`, + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/container", + _styles: { + normal: { + display: "flex", + "flex-direction": "row", + "align-items": "center", + "justify-content": "flex-end", + }, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + onLoad: [], + type: "div", + _instanceName: "Buttons Container", + _children: [ + { + _id: "", + _component: "@budibase/standard-components/button", + _styles: { + normal: { + "margin-right": "20px", + }, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + text: "Back", + className: "", + disabled: false, + onClick: [ + { + parameters: { + url: `/${table.name.toLowerCase()}`, + }, + "##eventHandlerType": "Navigate To", + }, + ], + _instanceName: "Back Button", + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/button", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + text: "Save", + className: "", + disabled: false, + onClick: [ + { + parameters: { + contextPath: "data", + tableId: table._id, + }, + "##eventHandlerType": "Save Row", + }, + ], + _instanceName: "Save Button", + _children: [], + }, + ], + }, + ], + _instanceName: `${table.name} - Detail`, + _code: "", + }, + route: `/${table.name.toLowerCase()}/:id`, + name: "", +}) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js new file mode 100644 index 0000000000..20f8f9c13f --- /dev/null +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -0,0 +1,118 @@ +export default function(tables) { + return tables.map(table => { + return { + name: `${table.name} - List`, + create: () => createScreen(table), + id: ROW_LIST_TEMPLATE, + } + }) +} + +export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE" + +const createScreen = table => ({ + props: { + _id: "", + _component: "@budibase/standard-components/container", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + type: "div", + _children: [ + { + _id: "", + _component: "@budibase/standard-components/container", + _styles: { + normal: { + display: "flex", + "flex-direction": "row", + "justify-content": "space-between", + "align-items": "center", + }, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + onLoad: [], + type: "div", + _instanceName: "Header", + _children: [ + { + _id: "", + _component: "@budibase/standard-components/heading", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + className: "", + text: `${table.name} List`, + type: "h1", + _instanceName: "Heading 1", + _children: [], + }, + { + _id: "", + _component: "@budibase/standard-components/button", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + text: "Create New", + className: "", + disabled: false, + onClick: [ + { + parameters: { + url: `/${table.name}/new`, + }, + "##eventHandlerType": "Navigate To", + }, + ], + _instanceName: "Create New Button", + _children: [], + }, + ], + }, + { + _id: "", + _component: "@budibase/standard-components/datatable", + _styles: { + normal: {}, + hover: {}, + active: {}, + selected: {}, + }, + _code: "", + datasource: { + label: "Deals", + name: `all_${table._id}`, + tableId: table._id, + isTable: true, + }, + stripeColor: "", + borderColor: "", + backgroundColor: "", + color: "", + _instanceName: `${table.name} Table`, + _children: [], + }, + ], + _instanceName: `${table.name} - List`, + _code: "", + className: "", + onLoad: [], + }, + route: `/${table.name.toLowerCase()}`, + name: "", +}) diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 2efffc9d4c..aeff3f2528 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -85,10 +85,10 @@ export const regenerateCssForCurrentScreen = state => { return state } -export const generateNewIdsForComponent = (c, state) => +export const generateNewIdsForComponent = (c, state, changeName = true) => walkProps(c, p => { p._id = uuid() - p._instanceName = getNewComponentName(p._component, state) + if (changeName) p._instanceName = getNewComponentName(p._component, state) }) export const getComponentDefinition = (state, name) => diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index 7a1720289a..c936f39c0b 100644 --- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -1,11 +1,21 @@ diff --git a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte index ec2122d6bf..828c99a2a0 100644 --- a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte @@ -68,18 +68,8 @@ } const copyComponent = () => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) - const copiedComponent = cloneDeep(component) - walkProps(copiedComponent, p => { - p._id = uuid() - }) - parent._children = [...parent._children, copiedComponent] - saveCurrentPreviewItem(s) - s.currentComponentInfo = copiedComponent - regenerateCssForCurrentScreen(s) - return s - }) + storeComponentForCopy(false) + pasteComponent("below") } const deleteComponent = () => { diff --git a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte index a6608307c3..b9bcf2fa95 100644 --- a/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte +++ b/packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte @@ -41,14 +41,6 @@ const onStyleChanged = store.setComponentStyle - function onPropChanged(key, value) { - if ($store.currentView !== "component") { - store.setPageOrScreenProp(key, value) - return - } - store.setComponentProp(key, value) - } - $: isComponentOrScreen = $store.currentView === "component" || $store.currentFrontEndType === "screen" @@ -103,7 +95,8 @@ {componentDefinition} {panelDefinition} displayNameField={displayName} - onChange={onPropChanged} + onChange={store.setComponentProp} + onScreenPropChange={store.setPageOrScreenProp} screenOrPageInstance={$store.currentView !== 'component' && $store.currentPreviewItem} /> {/if} diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte index eaab93a8ea..1c5043f333 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte @@ -73,7 +73,7 @@ {#if fields} {#each fields as field} - + + + {/each} + + {/if} + + {#if parameters.contextPath} + + {/if} + + + + diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/index.js b/packages/builder/src/components/userInterface/EventsEditor/actions/index.js index aff12d84ff..109a3104f8 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/index.js +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/index.js @@ -1,6 +1,5 @@ import NavigateTo from "./NavigateTo.svelte" -import UpdateRow from "./UpdateRow.svelte" -import CreateRow from "./CreateRow.svelte" +import SaveRow from "./SaveRow.svelte" // defines what actions are available, when adding a new one // the component is the setup panel for the action @@ -9,15 +8,11 @@ import CreateRow from "./CreateRow.svelte" export default [ { - name: "Create Row", - component: CreateRow, + name: "Save Row", + component: SaveRow, }, { name: "Navigate To", component: NavigateTo, }, - { - name: "Update Row", - component: UpdateRow, - }, ] diff --git a/packages/builder/src/components/userInterface/NewScreenModal.svelte b/packages/builder/src/components/userInterface/NewScreenModal.svelte index d38d4bbb7b..403a982d6d 100644 --- a/packages/builder/src/components/userInterface/NewScreenModal.svelte +++ b/packages/builder/src/components/userInterface/NewScreenModal.svelte @@ -1,27 +1,49 @@ + + + + - + diff --git a/packages/builder/src/components/userInterface/SettingsView.svelte b/packages/builder/src/components/userInterface/SettingsView.svelte index 159093fe8e..0460e15ad6 100644 --- a/packages/builder/src/components/userInterface/SettingsView.svelte +++ b/packages/builder/src/components/userInterface/SettingsView.svelte @@ -11,6 +11,7 @@ export let componentDefinition = {} export let componentInstance = {} export let onChange = () => {} + export let onScreenPropChange = () => {} export let displayNameField = false export let screenOrPageInstance @@ -91,7 +92,7 @@ label={def.label} key={def.key} value={screenOrPageInstance[def.key]} - {onChange} + onChange={onScreenPropChange} props={{ ...excludeProps(def, ['control', 'label']) }} /> {/each}
diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index 80ed9bd927..e38ac63727 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -583,23 +583,7 @@ export default { icon: "ri-file-edit-line", properties: { design: { ...all }, - settings: [ - { - label: "Table", - key: "table", - control: TableSelect, - }, - { - label: "Title", - key: "title", - control: Input, - }, - { - label: "Button Text", - key: "buttonText", - control: Input, - }, - ], + settings: [], }, }, { @@ -608,23 +592,7 @@ export default { icon: "ri-file-edit-line", properties: { design: { ...all }, - settings: [ - { - label: "Table", - key: "table", - control: TableSelect, - }, - { - label: "Title", - key: "title", - control: Input, - }, - { - label: "Button Text", - key: "buttonText", - control: Input, - }, - ], + settings: [], }, }, ], @@ -1136,6 +1104,18 @@ export default { }, children: [], }, + { + name: "New Row", + _component: "@budibase/standard-components/newrow", + description: + "Sets up a new row for creation, which can be used with {{ context }}, in children", + icon: "ri-profile-line", + properties: { + design: { ...all }, + settings: [{ label: "Table", key: "table", control: TableSelect }], + }, + children: [], + }, // { // name: "Map", // _component: "@budibase/standard-components/datamap", diff --git a/packages/builder/yarn.lock b/packages/builder/yarn.lock index 94a7501bce..dfeebc7214 100644 --- a/packages/builder/yarn.lock +++ b/packages/builder/yarn.lock @@ -5850,10 +5850,10 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== -svelte@^3.24.1: - version "3.25.1" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.25.1.tgz#218def1243fea5a97af6eb60f5e232315bb57ac4" - integrity sha512-IbrVKTmuR0BvDw4ii8/gBNy8REu7nWTRy9uhUz+Yuae5lIjWgSGwKlWtJGC2Vg95s+UnXPqDu0Kk/sUwe0t2GQ== +svelte@^3.29.0: + version "3.29.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.0.tgz#80acac4254341ad8f3301e5ef03f4127ea967d96" + integrity sha512-f+A65eyOQ5ujETLy+igNXtlr6AEjAQLYd1yJE1VwNiXMQO5Z/Vmiy3rL+zblV/9jd7rtTTWqO1IcuXsP2Qv0OA== symbol-observable@^1.1.0: version "1.2.0" diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index 905b901f13..6082accb51 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -52,14 +52,14 @@ const apiOpts = { delete: del, } -const createRow = async params => +const saveRow = async (params, state) => await post({ url: `/api/${params.tableId}/rows`, - body: makeRowRequestBody(params), + body: makeRowRequestBody(params, state), }) -const updateRow = async params => { - const row = makeRowRequestBody(params) +const updateRow = async (params, state) => { + const row = makeRowRequestBody(params, state) row._id = params._id await patch({ url: `/api/${params.tableId}/rows/${params._id}`, @@ -67,8 +67,14 @@ const updateRow = async params => { }) } -const makeRowRequestBody = parameters => { - const body = {} +const makeRowRequestBody = (parameters, state) => { + // start with the row thats currently in context + const body = { ...(state.data || {}) } + + // dont send the table + if (body._table) delete body._table + + // then override with supplied parameters for (let fieldName in parameters.fields) { const field = parameters.fields[fieldName] @@ -95,6 +101,6 @@ const makeRowRequestBody = parameters => { export default { authenticate: authenticate(apiOpts), - createRow, + saveRow, updateRow, } diff --git a/packages/client/src/state/eventHandlers.js b/packages/client/src/state/eventHandlers.js index 01a135308d..64c4b22e25 100644 --- a/packages/client/src/state/eventHandlers.js +++ b/packages/client/src/state/eventHandlers.js @@ -6,8 +6,8 @@ export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType" export const eventHandlers = routeTo => { const handlers = { "Navigate To": param => routeTo(param && param.url), - "Create Row": api.createRow, - "Update Row": api.updateRow, + "Update Record": api.updateRow, + "Save Record": api.saveRow, "Trigger Workflow": api.triggerWorkflow, } @@ -19,7 +19,7 @@ export const eventHandlers = routeTo => { const handler = handlers[action[EVENT_TYPE_MEMBER_NAME]] const parameters = createParameters(action.parameters, state) if (handler) { - await handler(parameters) + await handler(parameters, state) } } } diff --git a/packages/client/src/state/store.js b/packages/client/src/state/store.js index 6464589b03..cf284ec08e 100644 --- a/packages/client/src/state/store.js +++ b/packages/client/src/state/store.js @@ -95,7 +95,7 @@ const getState = contextStoreKey => contextStoreKey ? contextStores[contextStoreKey].state : rootState const getStore = contextStoreKey => - contextStoreKey ? contextStores[contextStoreKey] : rootStore + contextStoreKey ? contextStores[contextStoreKey].store : rootStore export default { subscribe, diff --git a/packages/server/src/db/linkedRows/index.js b/packages/server/src/db/linkedRows/index.js index d68a1e3d06..ebbba3ec1d 100644 --- a/packages/server/src/db/linkedRows/index.js +++ b/packages/server/src/db/linkedRows/index.js @@ -1,5 +1,6 @@ const LinkController = require("./LinkController") const { IncludeDocs, getLinkDocuments, createLinkView } = require("./linkUtils") +const _ = require("lodash") /** * This functionality makes sure that when rows with links are created, updated or deleted they are processed @@ -90,8 +91,7 @@ exports.attachLinkInfo = async (instanceId, rows) => { } let tableIds = [...new Set(rows.map(el => el.tableId))] // start by getting all the link values for performance reasons - let responses = [].concat.apply( - [], + let responses = _.flatten( await Promise.all( tableIds.map(tableId => getLinkDocuments({ diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index 6ffff2752e..337b5e43d1 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -218,20 +218,12 @@ "dataform": { "description": "an HTML table that fetches data from a table or view and displays it.", "data": true, - "props": { - "table": "tables", - "title": "string", - "buttonText": "string" - } + "props": {} }, "dataformwide": { "description": "an HTML table that fetches data from a table or view and displays it.", "data": true, - "props": { - "table": "tables", - "title": "string", - "buttonText": "string" - } + "props": {} }, "datalist": { "description": "A configurable data list that attaches to your backend tables.", @@ -270,10 +262,26 @@ } }, "rowdetail": { +<<<<<<< HEAD "description": "Loads a row, using an ID in the url", "context": "table", +======= + "description": "Loads a record, using an ID in the url", + "context": "model", +>>>>>>> 3af1d8dc7f13091cc4673d53046919bad9ea28f7 "children": true, "data": true, + "baseComponent": true, + "props": { + "model": "models" + } + }, + "newrow": { + "description": "Prepares a new record for creation", + "context": "model", + "children": true, + "data": true, + "baseComponent": true, "props": { "table": "tables" } @@ -715,7 +723,7 @@ "default": "div" } }, - "container": true, + "baseComponent": true, "tags": [ "div", "container", diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json index af12bfbf19..8ed9aeab0f 100644 --- a/packages/standard-components/package.json +++ b/packages/standard-components/package.json @@ -16,17 +16,17 @@ "@budibase/client": "^0.2.0", "@rollup/plugin-commonjs": "^11.1.0", "lodash": "^4.17.15", - "rollup": "^1.11.0", + "rollup": "^2.11.2", "rollup-plugin-commonjs": "^10.0.2", "rollup-plugin-json": "^4.0.0", "rollup-plugin-livereload": "^1.0.1", "rollup-plugin-node-resolve": "^5.0.0", "rollup-plugin-postcss": "^3.1.5", - "rollup-plugin-svelte": "^5.0.0", - "rollup-plugin-terser": "^5.1.1", + "rollup-plugin-svelte": "^5.0.3", + "rollup-plugin-terser": "^7.0.2", "shortid": "^2.2.15", "sirv-cli": "^0.4.4", - "svelte": "^3.12.1" + "svelte": "^3.29.0" }, "keywords": [ "svelte" diff --git a/packages/standard-components/src/Form.svelte b/packages/standard-components/src/Form.svelte index a7876fdded..ed9a393440 100644 --- a/packages/standard-components/src/Form.svelte +++ b/packages/standard-components/src/Form.svelte @@ -1,168 +1,61 @@ -
- {#if title} -

{title}

- {/if} -
- - {#each fields as field} -
- {#if !(schema[field].type === 'boolean' && !wide)} - - {/if} - {#if schema[field].type === 'options'} - - {:else if schema[field].type === 'datetime'} - - {:else if schema[field].type === 'boolean'} - - {:else if schema[field].type === 'number'} - - {:else if schema[field].type === 'string'} - - {:else if schema[field].type === 'attachment'} - - {:else if schema[field].type === 'link'} - - {/if} -
- {/each} -
- +
+ + {#each fields as field} +
+ {#if !(schema[field].type === 'boolean' && !wide)} + + {/if} + {#if schema[field].type === 'options'} + + {:else if schema[field].type === 'datetime'} + + {:else if schema[field].type === 'boolean'} + + {:else if schema[field].type === 'number'} + + {:else if schema[field].type === 'string'} + + {:else if schema[field].type === 'attachment'} + + {:else if schema[field].type === 'link'} + + {/if}
-
- + {/each} +
diff --git a/packages/standard-components/src/NewRow.svelte b/packages/standard-components/src/NewRow.svelte new file mode 100644 index 0000000000..817e07e0d0 --- /dev/null +++ b/packages/standard-components/src/NewRow.svelte @@ -0,0 +1,37 @@ + + +
diff --git a/packages/standard-components/src/RowDetail.svelte b/packages/standard-components/src/RowDetail.svelte index d20a6e706a..51df6d4b9f 100644 --- a/packages/standard-components/src/RowDetail.svelte +++ b/packages/standard-components/src/RowDetail.svelte @@ -20,6 +20,7 @@ if (response.status === 200) { const allRows = await response.json() if (allRows.length > 0) return allRows[0] + return { tableId: table } } } @@ -29,31 +30,35 @@ let row // if srcdoc, then we assume this is the builder preview if (pathParts.length === 0 || pathParts[0] === "srcdoc") { - row = await fetchFirstRow() - } else { - const id = pathParts[pathParts.length - 1] - const GET_ROW_URL = `/api/${table}/rows/${id}` + if (table) row = await fetchFirstRow() + } else if (_bb.routeParams().id) { + const GET_ROW_URL = `/api/${table}/rows/${_bb.routeParams().id}` const response = await _bb.api.get(GET_ROW_URL) if (response.status === 200) { row = await response.json() + } else { + throw new Error("Failed to fetch row.", response) } + } else { + throw new Exception("Row ID was not supplied to RowDetail") } if (row) { // Fetch table schema so we can check for linked rows - const table = await fetchTable(row.tableId) - for (let key of Object.keys(table.schema)) { - if (table.schema[key].type === "link") { + const tableObj = await fetchTable(row.tableId) + for (let key of Object.keys(tableObj.schema)) { + if (tableObj.schema[key].type === "link") { row[key] = Array.isArray(row[key]) ? row[key].length : 0 } } + row._table = tableObj + _bb.attachChildren(target, { - hydrate: false, context: row, }) } else { - throw new Error("Failed to fetch row.", response) + _bb.attachChildren(target) } } diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js index 369a01bfcd..f4bfd0e280 100644 --- a/packages/standard-components/src/index.js +++ b/packages/standard-components/src/index.js @@ -27,6 +27,7 @@ export { default as stackedlist } from "./StackedList.svelte" export { default as card } from "./Card.svelte" export { default as cardhorizontal } from "./CardHorizontal.svelte" export { default as rowdetail } from "./RowDetail.svelte" +export { default as newrow } from "./NewRow.svelte" export { default as datepicker } from "./DatePicker.svelte" export * from "./Chart" export { default as icon } from "./Icon.svelte"