From e1314b0d8873a90087a98ad2cb5a2d5be1bd852e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 24 Nov 2020 18:11:34 +0000 Subject: [PATCH] Starting work on builder, very broken. --- .../builder/src/builderStore/generate_css.js | 43 --------- packages/builder/src/builderStore/index.js | 34 ++++--- .../src/builderStore/store/frontend.js | 96 ++++++------------- .../modals/CreateTableModal.svelte | 2 +- .../components/start/CreateAppModal.svelte | 3 +- .../AppPreview/CurrentItemPreview.svelte | 2 +- .../ScreenDropdownMenu.svelte | 2 +- .../ComponentSelectionList.svelte | 4 +- .../userInterface/FrontendNavigatePane.svelte | 4 +- .../{PagesList.svelte => LayoutsList.svelte} | 14 +-- .../userInterface/SettingsView.svelte | 12 +-- .../userInterface/temporaryPanelStructure.js | 3 +- .../automate/[automation]/_layout.svelte | 2 +- .../design/[page]/[screen]/_layout.svelte | 6 +- .../design/[page]/_layout.svelte | 2 +- packages/builder/tests/generate_css.spec.js | 51 ---------- 16 files changed, 76 insertions(+), 204 deletions(-) delete mode 100644 packages/builder/src/builderStore/generate_css.js rename packages/builder/src/components/userInterface/{PagesList.svelte => LayoutsList.svelte} (76%) delete mode 100644 packages/builder/tests/generate_css.spec.js diff --git a/packages/builder/src/builderStore/generate_css.js b/packages/builder/src/builderStore/generate_css.js deleted file mode 100644 index 2bb5a3bd2e..0000000000 --- a/packages/builder/src/builderStore/generate_css.js +++ /dev/null @@ -1,43 +0,0 @@ -export const generate_screen_css = component_arr => { - let styles = "" - for (const { _styles, _id, _children, _component } of component_arr) { - let [componentName] = _component.match(/[a-z]*$/) - Object.keys(_styles).forEach(selector => { - const cssString = generate_css(_styles[selector]) - if (cssString) { - styles += apply_class(_id, componentName, cssString, selector) - } - }) - if (_children && _children.length) { - styles += generate_screen_css(_children) + "\n" - } - } - return styles.trim() -} - -export const generate_css = style => { - let cssString = Object.entries(style).reduce((str, [key, value]) => { - if (typeof value === "string") { - if (value) { - return (str += `${key}: ${value};\n`) - } - } else if (Array.isArray(value)) { - if (value.length > 0 && !value.every(v => v === "")) { - return (str += `${key}: ${value.join(" ")};\n`) - } - } - - return str - }, "") - - return (cssString || "").trim() -} - -export const apply_class = (id, name = "element", styles, selector) => { - if (selector === "normal") { - return `.${name}-${id} {\n${styles}\n}` - } else { - let sel = selector === "selected" ? "::selection" : `:${selector}` - return `.${name}-${id}${sel} {\n${styles}\n}` - } -} diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index ae77889404..aac2437560 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -10,19 +10,29 @@ export const backendUiStore = getBackendUiStore() export const automationStore = getAutomationStore() export const themeStore = getThemeStore() +export const currentAsset = derived(store, $store => { + const layout = $store.layouts ? $store.layouts.find(layout => layout._id === $store.currentAssetId) : null + if (layout) { + return layout + } + const screen = $store.screens ? $store.screens.find(screen => screen._id === $store.currentAssetId) : null + if (screen) { + return screen + } + return null +}) + +export const currentAssetName = derived(store, () => { + return currentAsset.name +}) + +// leave this as before for consistency export const allScreens = derived(store, $store => { - let screens = [] - if ($store.pages == null) { - return screens - } - for (let page of Object.values($store.pages)) { - screens = screens.concat(page._screens) - } - return screens + return $store.screens }) export const currentScreens = derived(store, $store => { - const currentScreens = $store.pages[$store.currentPageName]?._screens + const currentScreens = $store.layouts[currentAssetName]?._screens if (currentScreens == null) { return [] } @@ -31,12 +41,6 @@ export const currentScreens = derived(store, $store => { : Object.values(currentScreens) }) -export const selectedPage = derived(store, $store => { - if (!$store.pages) return null - - return $store.pages[$store.currentPageName || "main"] -}) - export const initialise = async () => { try { await analytics.activate() diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 778c7f7be5..0523b6693f 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -5,8 +5,7 @@ import { getBuiltin, makePropsSafe, } from "components/userInterface/pagesParsing/createProps" -import { allScreens, backendUiStore, selectedPage } from "builderStore" -import { generate_screen_css } from "../generate_css" +import { allScreens, backendUiStore, currentAsset } from "builderStore" import { fetchComponentLibDefinitions } from "../loadComponentLibraries" import api from "../api" import { DEFAULT_PAGES_OBJECT } from "../../constants" @@ -23,14 +22,15 @@ const INITIAL_FRONTEND_STATE = { apps: [], name: "", description: "", - pages: DEFAULT_PAGES_OBJECT, + layouts: DEFAULT_PAGES_OBJECT, + screens: [], mainUi: {}, unauthenticatedUi: {}, components: [], currentPreviewItem: null, currentComponentInfo: null, currentFrontEndType: "none", - currentPageName: "", + currentAssetId: "", currentComponentProps: null, errors: [], hasAppPackage: false, @@ -43,52 +43,12 @@ export const getFrontendStore = () => { const store = writable({ ...INITIAL_FRONTEND_STATE }) store.actions = { - // TODO: REFACTOR initialise: async pkg => { + const layouts = pkg.layouts, screens = pkg.screens, application = pkg.application store.update(state => { - state.appId = pkg.application._id + state.appId = application._id return state }) - const screens = await api.get("/api/screens").then(r => r.json()) - - const mainScreens = screens.filter(screen => - screen._id.includes(pkg.pages.main._id) - ), - unauthScreens = screens.filter(screen => - screen._id.includes(pkg.pages.unauthenticated._id) - ) - pkg.pages = { - main: { - ...pkg.pages.main, - _screens: mainScreens, - }, - unauthenticated: { - ...pkg.pages.unauthenticated, - _screens: unauthScreens, - }, - } - - // if the app has just been created - // we need to build the CSS and save - if (pkg.justCreated) { - for (let pageName of ["main", "unauthenticated"]) { - const page = pkg.pages[pageName] - store.actions.screens.regenerateCss(page) - for (let screen of page._screens) { - store.actions.screens.regenerateCss(screen) - } - - await api.post(`/api/pages/${page._id}`, { - page: { - componentLibraries: pkg.application.componentLibraries, - ...page, - }, - screens: page._screens, - }) - } - } - - pkg.justCreated = false const components = await fetchComponentLibDefinitions(pkg.application._id) @@ -99,7 +59,8 @@ export const getFrontendStore = () => { name: pkg.application.name, description: pkg.application.description, appId: pkg.application._id, - pages: pkg.pages, + layouts, + screens, hasAppPackage: true, builtins: [getBuiltin("##builtin/screenslot")], appInstance: pkg.application.instance, @@ -111,7 +72,7 @@ export const getFrontendStore = () => { store.update(state => { state.currentFrontEndType = type - const page = get(selectedPage) + const page = get(currentAsset) const pageOrScreen = type === "page" ? page : page._screens[0] @@ -168,7 +129,7 @@ export const getFrontendStore = () => { await savePromise }, save: async screen => { - const page = get(selectedPage) + const page = get(currentAsset) const currentPageScreens = page._screens const creatingNewScreen = screen._id === undefined @@ -197,14 +158,15 @@ export const getFrontendStore = () => { state.currentComponentInfo = safeProps screen.props = safeProps } - savePromise = store.actions.pages.save() + savePromise = store.actions.layouts.save() return state }) if (savePromise) await savePromise }, - regenerateCss: screen => { - screen._css = generate_screen_css([screen.props]) + regenerateCss: async asset => { + const response = await api.post("/api/css/generate", asset) + asset._css = await response.json() }, regenerateCssForCurrentScreen: () => { const { currentPreviewItem } = get(store) @@ -218,7 +180,7 @@ export const getFrontendStore = () => { const screensToDelete = Array.isArray(screens) ? screens : [screens] store.update(state => { - const currentPage = get(selectedPage) + const currentPage = get(currentAsset) for (let screenToDelete of screensToDelete) { // Remove screen from current page as well @@ -242,17 +204,17 @@ export const getFrontendStore = () => { if (state.currentFrontEndType !== "page") { await store.actions.screens.save(state.currentPreviewItem) } - await store.actions.pages.save() + await store.actions.layouts.save() }, }, - pages: { + layouts: { select: pageName => { store.update(state => { - const currentPage = state.pages[pageName] + const currentPage = state.layouts[pageName] state.currentFrontEndType = "page" state.currentView = "detail" - state.currentPageName = pageName + state.currentAssetId = pageName // This is the root of many problems. // Uncaught (in promise) TypeError: Cannot read property '_component' of undefined @@ -264,11 +226,11 @@ export const getFrontendStore = () => { ) state.currentComponentInfo = safeProps currentPage.props = safeProps - state.currentPreviewItem = state.pages[pageName] + state.currentPreviewItem = state.layouts[pageName] store.actions.screens.regenerateCssForCurrentScreen() for (let screen of get(allScreens)) { - screen._css = generate_screen_css([screen.props]) + screen._css = store.actions.screens.regenerateCss(screen) } return state @@ -276,7 +238,7 @@ export const getFrontendStore = () => { }, save: async page => { const storeContents = get(store) - const pageName = storeContents.currentPageName || "main" + const pageName = storeContents.currentAssetId || "main" const pageToSave = page || storeContents.pages[pageName] // TODO: revisit. This sends down a very weird payload @@ -293,7 +255,7 @@ export const getFrontendStore = () => { if (!json.ok) throw new Error("Error updating page") store.update(state => { - state.pages[pageName]._rev = json.rev + state.layouts[pageName]._rev = json.rev return state }) }, @@ -324,7 +286,7 @@ export const getFrontendStore = () => { if ( componentToAdd.startsWith("##") && - findSlot(state.pages[state.currentPageName].props._children) + findSlot(state.layouts[state.currentAssetId].props._children) ) { return state } @@ -480,7 +442,7 @@ export const getFrontendStore = () => { store.update(state => { // Try to extract a nav component from the master screen const nav = findChildComponentType( - state.pages.main, + state.layouts.main, "@budibase/standard-components/Navigation" ) if (nav) { @@ -515,12 +477,12 @@ export const getFrontendStore = () => { // Save page and regenerate all CSS because otherwise weird things happen nav._children = [...nav._children, newLink] - state.currentPageName = "main" - store.actions.screens.regenerateCss(state.pages.main) - for (let screen of state.pages.main._screens) { + state.currentAssetId = "main" + store.actions.screens.regenerateCss(state.layouts.main) + for (let screen of state.layouts.main._screens) { store.actions.screens.regenerateCss(screen) } - savePromise = store.actions.pages.save() + savePromise = store.actions.layouts.save() } return state }) diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index f064ff923c..d111821fb3 100644 --- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -51,7 +51,7 @@ const screens = screenTemplates($store, [table]) .filter(template => defaultScreens.includes(template.id)) .map(template => template.create()) - store.actions.pages.select("main") + store.actions.layouts.select("main") for (let screen of screens) { // Record the table that created this screen so we can link it later screen.autoTableId = table._id diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 049b21c995..99539e965f 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -155,9 +155,8 @@ const pkg = await applicationPkg.json() if (applicationPkg.ok) { backendUiStore.actions.reset() - pkg.justCreated = true await store.actions.initialise(pkg) - automationStore.actions.fetch() + await automationStore.actions.fetch() } else { throw new Error(pkg) } diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte index c9fe02e786..2e7d719084 100644 --- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte @@ -56,7 +56,7 @@ screenPlaceholder.props._id = "screenslot-placeholder" // Extract data to pass to the iframe - $: page = $store.pages[$store.currentPageName] + $: page = $store.layouts[$store.currentPageName] $: screen = $store.currentFrontEndType === "page" ? screenPlaceholder diff --git a/packages/builder/src/components/userInterface/ComponentNavigationTree/ScreenDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentNavigationTree/ScreenDropdownMenu.svelte index 3ecd8ce0dc..07f0f042a1 100644 --- a/packages/builder/src/components/userInterface/ComponentNavigationTree/ScreenDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ComponentNavigationTree/ScreenDropdownMenu.svelte @@ -19,7 +19,7 @@ // update the page if required store.update(state => { if (state.currentPreviewItem._id === screen) { - store.actions.pages.select($store.currentPageName) + store.actions.layouts.select($store.currentPageName) notifier.success(`Screen ${screenToDelete.name} deleted successfully.`) $goto(`./:page/page-layout`) } diff --git a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte index f099984e5a..edce828f41 100644 --- a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte +++ b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte @@ -1,6 +1,6 @@
- {#each pages as { title, id }} - {/each} diff --git a/packages/builder/src/components/userInterface/SettingsView.svelte b/packages/builder/src/components/userInterface/SettingsView.svelte index 8afdfce7ec..1ceb0f6c06 100644 --- a/packages/builder/src/components/userInterface/SettingsView.svelte +++ b/packages/builder/src/components/userInterface/SettingsView.svelte @@ -4,7 +4,7 @@ import Input from "./PropertyPanelControls/Input.svelte" import { goto } from "@sveltech/routify" import { excludeProps } from "./propertyCategories.js" - import { store, allScreens } from "builderStore" + import { store, allScreens, currentAsset } from "builderStore" import { walkProps } from "builderStore/storeUtils" export let panelDefinition = [] @@ -58,15 +58,15 @@ } }) } - // check page first - lookForDuplicate($store.pages[$store.currentPageName].props) - if (duplicate) return true - + // check against layouts + for (let layout of $store.layouts) { + lookForDuplicate(layout.props) + } // if viewing screen, check current screen for duplicate if ($store.currentFrontEndType === "screen") { lookForDuplicate($store.currentPreviewItem.props) } else { - // viewing master page - need to dedupe against all screens + // need to dedupe against all screens for (let screen of $allScreens) { lookForDuplicate(screen.props) } diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index e18ca6014f..5c18e012b0 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -1185,6 +1185,7 @@ export default { settings: [{ label: "Logo URL", key: "logoUrl", control: Input }], }, }, + // TODO: need to deal with this { name: "Login", _component: "@budibase/standard-components/login", @@ -1192,7 +1193,7 @@ export default { "A component that automatically generates a login screen for your app.", icon: "ri-login-box-line", children: [], - showOnPages: ["unauthenticated"], + showOnAsset: ["login-screen"], properties: { design: { ...all }, settings: [ diff --git a/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte b/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte index a61df114db..87d314e5bd 100644 --- a/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte +++ b/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte @@ -1,4 +1,4 @@ diff --git a/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte b/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte index 99434b7cd5..56884a4879 100644 --- a/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte +++ b/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte @@ -14,7 +14,7 @@ if (!validScreen) { // Go to main layout if URL set to invalid screen - store.actions.pages.select("main") + store.actions.layouts.select("main") $goto("../../main") } else { // Otherwise proceed to set screen @@ -23,7 +23,7 @@ // There are leftover stuff, like IDs, so navigate the components and find the ID and select it. if ($leftover) { // Get the correct screen children. - const screenChildren = $store.pages[$params.page]._screens.find( + const screenChildren = $store.layouts[$params.page]._screens.find( screen => screen._id === $params.screen || screen._id === decodeURIComponent($params.screen) @@ -37,7 +37,7 @@ // There are leftover stuff, like IDs, so navigate the components and find the ID and select it. if ($leftover) { - findComponent(componentIds, $store.pages[$params.page].props._children) + findComponent(componentIds, $store.layouts[$params.page].props._children) } } diff --git a/packages/builder/src/pages/[application]/design/[page]/_layout.svelte b/packages/builder/src/pages/[application]/design/[page]/_layout.svelte index d07a4c5695..45f577a0a8 100644 --- a/packages/builder/src/pages/[application]/design/[page]/_layout.svelte +++ b/packages/builder/src/pages/[application]/design/[page]/_layout.svelte @@ -2,7 +2,7 @@ import { params } from "@sveltech/routify" import { store } from "builderStore" - store.actions.pages.select($params.page) + store.actions.layouts.select($params.page) diff --git a/packages/builder/tests/generate_css.spec.js b/packages/builder/tests/generate_css.spec.js deleted file mode 100644 index 5fcdef25c1..0000000000 --- a/packages/builder/tests/generate_css.spec.js +++ /dev/null @@ -1,51 +0,0 @@ -import { - generate_css, - generate_screen_css, -} from "../src/builderStore/generate_css.js" - -describe("generate_css", () => { - - - test("Check how array styles are output", () => { - expect(generate_css({ margin: ["0", "10", "0", "15"] })).toBe("margin: 0px 10px 0px 15px;") - }) - - test("Check handling of an array with empty string values", () => { - expect(generate_css({ padding: ["", "", "", ""] })).toBe("") - }) - - test("Check handling of an empty array", () => { - expect(generate_css({ margin: [] })).toBe("") - }) - - test("Check handling of valid font property", () => { - expect(generate_css({ "font-size": "10px" })).toBe("font-size: 10px;") - }) -}) - - -describe("generate_screen_css", () => { - const normalComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: { "font-size": "16px" }, hover: {}, active: {}, selected: {} } } - - test("Test generation of normal css styles", () => { - expect(generate_screen_css([normalComponent])).toBe(".header-123-456 {\nfont-size: 16px;\n}") - }) - - const hoverComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {"font-size": "16px"}, active: {}, selected: {} } } - - test("Test generation of hover css styles", () => { - expect(generate_screen_css([hoverComponent])).toBe(".header-123-456:hover {\nfont-size: 16px;\n}") - }) - - const selectedComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {}, active: {}, selected: { "font-size": "16px" } } } - - test("Test generation of selection css styles", () => { - expect(generate_screen_css([selectedComponent])).toBe(".header-123-456::selection {\nfont-size: 16px;\n}") - }) - - const emptyComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {}, active: {}, selected: {} } } - - test.only("Testing handling of empty component styles", () => { - expect(generate_screen_css([emptyComponent])).toBe("") - }) -}) \ No newline at end of file