diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index f4d47064be..f94cea2399 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -1,4 +1,4 @@ -import { cloneDeep, values } from "lodash/fp" +import { values } from "lodash/fp" import { backendUiStore } from "builderStore" import * as backendStoreActions from "./backend" import { writable, get } from "svelte/store" @@ -16,6 +16,14 @@ import { buildCodeForScreens } from "../buildCodeForScreens" import { generate_screen_css } from "../generate_css" import { insertCodeMetadata } from "../insertCodeMetadata" import { uuid } from "../uuid" +import { + selectComponent as _selectComponent, + getParent, + walkProps, + savePage as _savePage, + saveCurrentPreviewItem as _saveCurrentPreviewItem, + saveScreenApi as _saveScreenApi, +} from "../storeUtils" export const getStore = () => { const initial = { @@ -57,10 +65,6 @@ export const getStore = () => { store.setComponentStyle = setComponentStyle(store) store.setComponentCode = setComponentCode(store) store.setScreenType = setScreenType(store) - store.deleteComponent = deleteComponent(store) - store.moveUpComponent = moveUpComponent(store) - store.moveDownComponent = moveDownComponent(store) - store.copyComponent = copyComponent(store) store.getPathToComponent = getPathToComponent(store) store.addTemplatedComponent = addTemplatedComponent(store) store.setMetadataProp = setMetadataProp(store) @@ -69,6 +73,9 @@ export const getStore = () => { export default getStore +export const getComponentDefinition = (state, name) => + name.startsWith("##") ? getBuiltin(name) : state.components[name] + const setPackage = (store, initial) => async pkg => { const [main_screens, unauth_screens] = await Promise.all([ api @@ -140,12 +147,6 @@ const _saveScreen = async (store, s, screen) => { return s } -const _saveScreenApi = (screen, s) => { - api - .post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen) - .then(() => _savePage(s)) -} - const createScreen = store => (screenName, route, layoutComponentName) => { store.update(state => { const rootComponent = state.components[layoutComponentName] @@ -277,15 +278,6 @@ const removeStylesheet = store => stylesheet => { }) } -const _savePage = async s => { - const page = s.pages[s.currentPageName] - await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, { - page: { componentLibraries: s.pages.componentLibraries, ...page }, - uiFunctions: s.currentPageFunctions, - screens: page._screens, - }) -} - const setCurrentPage = store => pageName => { store.update(state => { const current_screens = state.pages[pageName]._screens @@ -317,8 +309,6 @@ const setCurrentPage = store => pageName => { }) } -// const getComponentDefinition = (components, name) => components.find(c => c.name === name) - /** * @param {string} componentToAdd - name of the component to add to the application * @param {string} presetName - name of the component preset if defined @@ -344,9 +334,7 @@ const addChildComponent = store => (componentToAdd, presetName) => { return state } - const component = componentToAdd.startsWith("##") - ? getBuiltin(componentToAdd) - : state.components[componentToAdd] + const component = getComponentDefinition(state, componentToAdd) const presetProps = presetName ? component.presets[presetName] : {} @@ -400,12 +388,7 @@ const addTemplatedComponent = store => props => { const selectComponent = store => component => { store.update(state => { - const componentDef = component._component.startsWith("##") - ? component - : state.components[component._component] - state.currentComponentInfo = makePropsSafe(componentDef, component) - state.currentView = "component" - return state + return _selectComponent(state, component) }) } @@ -472,75 +455,6 @@ const setScreenType = store => type => { }) } -const deleteComponent = store => componentName => { - store.update(state => { - const parent = getParent(state.currentPreviewItem.props, componentName) - - if (parent) { - parent._children = parent._children.filter( - component => component !== componentName - ) - } - - _saveCurrentPreviewItem(state) - - return state - }) -} - -const moveUpComponent = store => component => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) - - if (parent) { - const currentIndex = parent._children.indexOf(component) - if (currentIndex === 0) return s - - const newChildren = parent._children.filter(c => c !== component) - newChildren.splice(currentIndex - 1, 0, component) - parent._children = newChildren - } - s.currentComponentInfo = component - _saveCurrentPreviewItem(s) - - return s - }) -} - -const moveDownComponent = store => component => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) - - if (parent) { - const currentIndex = parent._children.indexOf(component) - if (currentIndex === parent._children.length - 1) return s - - const newChildren = parent._children.filter(c => c !== component) - newChildren.splice(currentIndex + 1, 0, component) - parent._children = newChildren - } - s.currentComponentInfo = component - _saveCurrentPreviewItem(s) - - return s - }) -} - -const copyComponent = store => component => { - 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] - s.curren - _saveCurrentPreviewItem(s) - s.currentComponentInfo = copiedComponent - return s - }) -} - const getPathToComponent = store => component => { // Gets all the components to needed to construct a path. const tempStore = get(store) @@ -572,39 +486,9 @@ const getPathToComponent = store => component => { return path } -const getParent = (rootProps, child) => { - let parent - walkProps(rootProps, (p, breakWalk) => { - if (p._children && p._children.includes(child)) { - parent = p - breakWalk() - } - }) - return parent -} - -const walkProps = (props, action, cancelToken = null) => { - cancelToken = cancelToken || { cancelled: false } - action(props, () => { - cancelToken.cancelled = true - }) - - if (props._children) { - for (let child of props._children) { - if (cancelToken.cancelled) return - walkProps(child, action, cancelToken) - } - } -} - const setMetadataProp = store => (name, prop) => { store.update(s => { s.currentPreviewItem[name] = prop return s }) } - -const _saveCurrentPreviewItem = s => - s.currentFrontEndType === "page" - ? _savePage(s) - : _saveScreenApi(s.currentPreviewItem, s) diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js new file mode 100644 index 0000000000..68e20e56b3 --- /dev/null +++ b/packages/builder/src/builderStore/storeUtils.js @@ -0,0 +1,59 @@ +import { makePropsSafe } from "components/userInterface/pagesParsing/createProps" +import api from "./api" + +export const selectComponent = (state, component) => { + const componentDef = component._component.startsWith("##") + ? component + : state.components[component._component] + state.currentComponentInfo = makePropsSafe(componentDef, component) + state.currentView = "component" + return state +} + +export const getParent = (rootProps, child) => { + let parent + walkProps(rootProps, (p, breakWalk) => { + if ( + p._children && + (p._children.includes(child) || p._children.some(c => c._id === child)) + ) { + parent = p + breakWalk() + } + }) + return parent +} + +export const saveCurrentPreviewItem = s => + s.currentFrontEndType === "page" + ? savePage(s) + : saveScreenApi(s.currentPreviewItem, s) + +export const savePage = async s => { + const page = s.pages[s.currentPageName] + await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, { + page: { componentLibraries: s.pages.componentLibraries, ...page }, + uiFunctions: s.currentPageFunctions, + screens: page._screens, + }) +} + +export const saveScreenApi = (screen, s) => { + api + .post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen) + .then(() => savePage(s)) +} + +export const walkProps = (props, action, cancelToken = null) => { + cancelToken = cancelToken || { cancelled: false } + action(props, () => { + cancelToken.cancelled = true + }) + + if (props._children) { + for (let child of props._children) { + if (cancelToken.cancelled) return + walkProps(child, action, cancelToken) + } + } +} diff --git a/packages/builder/src/components/common/Icons/More.svelte b/packages/builder/src/components/common/Icons/More.svelte new file mode 100644 index 0000000000..1ec4139eae --- /dev/null +++ b/packages/builder/src/components/common/Icons/More.svelte @@ -0,0 +1,12 @@ + + + + diff --git a/packages/builder/src/components/common/Icons/index.js b/packages/builder/src/components/common/Icons/index.js index 69b78421da..4e4b41082d 100644 --- a/packages/builder/src/components/common/Icons/index.js +++ b/packages/builder/src/components/common/Icons/index.js @@ -31,3 +31,4 @@ export { default as EmailIcon } from "./Email.svelte" export { default as TwitterIcon } from "./Twitter.svelte" export { default as InfoIcon } from "./Info.svelte" export { default as CloseIcon } from "./Close.svelte" +export { default as MoreIcon } from "./More.svelte" diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/FieldView.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/FieldView.svelte index ae78405ccb..46f8bd9189 100644 --- a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/FieldView.svelte +++ b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditModel/FieldView.svelte @@ -13,16 +13,20 @@ const FIELD_TYPES = ["string", "number", "boolean"] - export let field = { type: "string", constraints: { type: "string", presence: false } } + export let field = { + type: "string", + constraints: { type: "string", presence: false }, + } export let schema export let goBack let errors = [] let draftField = cloneDeep(field) - + let type = field.type let constraints = field.constraints - let required = field.constraints.presence && !field.constraints.presence.allowEmpty + let required = + field.constraints.presence && !field.constraints.presence.allowEmpty const save = () => { constraints.presence = required ? { allowEmpty: false } : false @@ -31,15 +35,19 @@ schema[field.name] = draftField goBack() } - - $: constraints = - type === "string" ? { type: "string", length: {}, presence: false } - : type === "number" ? { type: "number", presence: false, numericality: {} } - : type === "boolean" ? { type: "boolean", presence: false } - : type === "datetime" ? { type: "date", datetime: {}, presence: false } - : type.startsWith('array') ? { type: "array", presence: false } + + $: constraints = + type === "string" + ? { type: "string", length: {}, presence: false } + : type === "number" + ? { type: "number", presence: false, numericality: {} } + : type === "boolean" + ? { type: "boolean", presence: false } + : type === "datetime" + ? { type: "date", datetime: {}, presence: false } + : type.startsWith("array") + ? { type: "array", presence: false } : { type: "string", presence: false } -
@@ -48,24 +56,26 @@
- - + + - {#if type === 'string'} {:else if type === 'datetime'} - + {:else if type === 'number'} - - + + {/if}
diff --git a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte index d5320eca0d..62688d58e3 100644 --- a/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte +++ b/packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte @@ -23,22 +23,22 @@ function closed() { onClosed() } - + const isSelect = meta => - meta.type === "string" - && meta.constraints - && meta.constraints.inclusion - && meta.constraints.inclusion.length > 0 - + meta.type === "string" && + meta.constraints && + meta.constraints.inclusion && + meta.constraints.inclusion.length > 0 + function determineInputType(meta) { if (meta.type === "datetime") return "date" if (meta.type === "number") return "number" if (meta.type === "boolean") return "checkbox" if (isSelect(meta)) return "select" - + return "text" } - + function determineOptions(meta) { return isSelect(meta) ? meta.constraints.inclusion : [] } @@ -54,8 +54,8 @@ ) if (recordResponse.errors) { errors = Object.keys(recordResponse.errors) - .map(k => ({dataPath: k, message: recordResponse.errors[k]})) - .flat() + .map(k => ({ dataPath: k, message: recordResponse.errors[k] })) + .flat() return } diff --git a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte b/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte index b0571a2353..5c308a7abb 100644 --- a/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte +++ b/packages/builder/src/components/database/ModelDataTable/modals/RecordFieldControl.svelte @@ -4,15 +4,15 @@ export let label export let errors = [] export let options = [] - + let checked = type === "checkbox" ? value : false - + const determineClassName = type => { if (type === "checkbox") return "uk-checkbox" if (type === "select") return "uk-select" return "uk-input" } - + const handleInput = event => { if (event.target.type === "checkbox") { value = event.target.checked @@ -30,22 +30,22 @@ -{#if type === "select"} - +{#if type === 'select'} + {:else} - 0} - {checked} - {type} - {value} - on:input={handleInput} - on:change={handleInput} /> + 0} + {checked} + {type} + {value} + on:input={handleInput} + on:change={handleInput} /> {/if} diff --git a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte new file mode 100644 index 0000000000..712031aa3d --- /dev/null +++ b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte @@ -0,0 +1,232 @@ + + +
{}}> + + +
+ + + + diff --git a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte index 714e1c2cc9..7a2e38d3d2 100644 --- a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte +++ b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte @@ -35,11 +35,6 @@ sortBy("title"), ]) - const confirmDeleteComponent = component => { - componentToDelete = component - confirmDeleteDialog.show() - } - const changeScreen = screen => { store.setCurrentScreen(screen.title) $goto(`./:page/${screen.title}`) @@ -69,23 +64,12 @@ {#if $store.currentPreviewItem.name === screen.title && screen.component.props._children} + currentComponent={$store.currentComponentInfo} /> {/if} {/each} - store.deleteComponent(componentToDelete)} /> - diff --git a/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte b/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte index cee63c4cbb..86804885ff 100644 --- a/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte +++ b/packages/builder/src/components/userInterface/FrontendNavigatePane.svelte @@ -45,5 +45,4 @@ .newscreen:hover { background: var(--grey-light); } - diff --git a/packages/builder/src/components/userInterface/PageLayout.svelte b/packages/builder/src/components/userInterface/PageLayout.svelte index ec32e1cb44..093dd12e4e 100644 --- a/packages/builder/src/components/userInterface/PageLayout.svelte +++ b/packages/builder/src/components/userInterface/PageLayout.svelte @@ -34,11 +34,6 @@ title: lastPartOfName(layout), } - const confirmDeleteComponent = async component => { - componentToDelete = component - confirmDeleteDialog.show() - } - const setCurrentScreenToLayout = () => { store.setScreenType("page") $goto("./:page/page-layout") @@ -63,21 +58,10 @@ + currentComponent={$store.currentComponentInfo} /> {/if} - store.deleteComponent(componentToDelete)} /> -