diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 3f0ecd84c5..b351d6edbf 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -28,8 +28,8 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: yarn - - run: yarn lint - run: yarn bootstrap + - run: yarn lint - run: yarn build - run: yarn test env: diff --git a/package.json b/package.json index 5a0a0d7495..61ff67b076 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "lint": "yarn run lint:eslint && yarn run lint:prettier", "lint:fix:eslint": "eslint --fix packages", "lint:fix:prettier": "prettier --write \"packages/**/*.{js,svelte}\"", - "lint:fix": "yarn run lint:fix:prettier && yarn run lint:fix:eslint", + "lint:fix:ts": "lerna run lint:fix", + "lint:fix": "yarn run lint:fix:ts && yarn run lint:fix:prettier && yarn run lint:fix:eslint", "test:e2e": "lerna run cy:test", "test:e2e:ci": "lerna run cy:ci", "build:docker": "lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -", diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js index 7d9e9ad637..e20255bfd3 100644 --- a/packages/auth/src/redis/index.js +++ b/packages/auth/src/redis/index.js @@ -18,6 +18,8 @@ function connectionError(timeout, err) { if (CLOSED) { return } + CLIENT.end() + CLOSED = true // always clear this on error clearTimeout(timeout) CONNECTED = false @@ -41,7 +43,7 @@ function init() { // start the timer - only allowed 5 seconds to connect timeout = setTimeout(() => { if (!CONNECTED) { - connectionError(timeout) + connectionError(timeout, "Did not successfully connect in timeout") } }, STARTUP_TIMEOUT_MS) diff --git a/packages/bbui/src/ColorPicker/ColorPicker.svelte b/packages/bbui/src/ColorPicker/ColorPicker.svelte new file mode 100644 index 0000000000..2f4b79b91a --- /dev/null +++ b/packages/bbui/src/ColorPicker/ColorPicker.svelte @@ -0,0 +1,239 @@ + + +
+
(open = true)} + /> + {#if open} +
(open = false)} + transition:fly={{ y: -20, duration: 200 }} + class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + > + {#each categories as category} +
+
{category.label}
+
+ {#each category.colors as color} +
{ + onChange(`var(--spectrum-global-color-static-${color})`) + }} + class="color" + style="background: var(--spectrum-global-color-static-{color}); color: {checkColor};" + title={prettyPrint(color)} + > + {#if value === `var(--spectrum-global-color-static-${color})`} + + {/if} +
+ {/each} +
+
+ {/each} +
+
Custom
+
+ + onChange(null)} + /> +
+
+
+ {/if} +
+ + diff --git a/packages/bbui/src/DetailSummary/DetailSummary.svelte b/packages/bbui/src/DetailSummary/DetailSummary.svelte index 7071ab26d5..518c615504 100644 --- a/packages/bbui/src/DetailSummary/DetailSummary.svelte +++ b/packages/bbui/src/DetailSummary/DetailSummary.svelte @@ -2,13 +2,15 @@ import Icon from "../Icon/Icon.svelte" import { createEventDispatcher } from "svelte" + export let name + export let show = false + export let collapsible = true + const dispatch = createEventDispatcher() - - export let thin = false - export let name, - show = false - const onHeaderClick = () => { + if (!collapsible) { + return + } show = !show if (show) { dispatch("open") @@ -16,14 +18,14 @@ } -
+
-
{name}
-
+
{name}
+ {#if collapsible} -
+ {/if}
-
+
@@ -32,10 +34,9 @@ .property-group-container { display: flex; flex-direction: column; - height: auto; - justify-content: center; - border-radius: var(--border-radius-m); - font-family: var(--font-sans); + justify-content: flex-start; + align-items: stretch; + border-bottom: var(--border-light); } .property-group-name { @@ -45,42 +46,38 @@ flex-direction: row; justify-content: space-between; align-items: center; + padding: var(--spacing-m) var(--spacing-xl); + color: var(--spectrum-global-color-gray-600); + transition: color 130ms ease-in-out; + } + .property-group-name:hover { + color: var(--spectrum-global-color-gray-900); } .name { text-align: left; - font-size: 14px; + font-size: var(--font-size-s); font-weight: 600; letter-spacing: 0.14px; - color: var(--ink); flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; - text-transform: capitalize; + text-transform: uppercase; white-space: nowrap; user-select: none; } - .name.thin { - font-size: var(--spectrum-global-dimension-font-size-75); - } - - .icon { - flex: 0 0 20px; - text-align: center; - } .property-panel { - /* height: 0px; - overflow: hidden; */ display: none; + padding: var(--spacing-s) var(--spacing-xl) var(--spacing-xl) + var(--spacing-xl); } .show { - /* overflow: auto; - height: auto; */ display: flex; flex-direction: column; - flex: 1; - margin-top: var(--spacing-m); + justify-content: flex-start; + align-items: stretch; + gap: var(--spacing-l); } diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index fe49b19aa7..5ca413409c 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -20,6 +20,7 @@ export let open = false export let readonly = false export let quiet = false + export let autoWidth = false const dispatch = createEventDispatcher() const onClick = () => { @@ -41,7 +42,11 @@ aria-haspopup="listbox" on:mousedown={onClick} > - + {fieldText} {#if error} @@ -67,11 +72,12 @@ use:clickOutside={() => (open = false)} transition:fly={{ y: -20, duration: 200 }} class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + class:auto-width={autoWidth} >
    {#if placeholderOption}
  • .spectrum-Popover { max-height: 240px; - width: 100%; z-index: 999; top: 100%; } + .spectrum-Popover:not(.auto-width) { + width: 100%; + } + .spectrum-Popover.auto-width :global(.spectrum-Menu-itemLabel) { + white-space: nowrap; + } .spectrum-Picker { width: 100%; } - .spectrum-Picker-label { + .spectrum-Picker-label:not(.auto-width) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 0; } + .placeholder { + font-style: italic; + } + .spectrum-Picker-label.auto-width.is-placeholder { + padding-right: 2px; + } diff --git a/packages/bbui/src/Form/Core/Select.svelte b/packages/bbui/src/Form/Core/Select.svelte index f449b576e5..93e59e2420 100644 --- a/packages/bbui/src/Form/Core/Select.svelte +++ b/packages/bbui/src/Form/Core/Select.svelte @@ -12,6 +12,7 @@ export let getOptionValue = option => option export let readonly = false export let quiet = false + export let autoWidth = false const dispatch = createEventDispatcher() let open = false @@ -51,6 +52,7 @@ {readonly} {fieldText} {options} + {autoWidth} {getOptionLabel} {getOptionValue} isPlaceholder={value == null || value === ""} diff --git a/packages/bbui/src/Form/Core/TextField.svelte b/packages/bbui/src/Form/Core/TextField.svelte index 650aee4f82..926c3eda11 100644 --- a/packages/bbui/src/Form/Core/TextField.svelte +++ b/packages/bbui/src/Form/Core/TextField.svelte @@ -10,6 +10,7 @@ export let id = null export let readonly = false export let updateOnChange = true + export let quiet = false const dispatch = createEventDispatcher() let focus = false @@ -59,6 +60,7 @@
    { @@ -29,6 +30,7 @@ {value} {placeholder} {type} + {quiet} on:change={onChange} on:click on:input diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 4a6955a97c..808c4c2789 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -14,6 +14,7 @@ export let getOptionLabel = option => extractProperty(option, "label") export let getOptionValue = option => extractProperty(option, "value") export let quiet = false + export let autoWidth = false const dispatch = createEventDispatcher() const onChange = e => { @@ -37,6 +38,7 @@ {value} {options} {placeholder} + {autoWidth} {getOptionLabel} {getOptionValue} on:change={onChange} diff --git a/packages/bbui/src/Tabs/Tabs.svelte b/packages/bbui/src/Tabs/Tabs.svelte index 3eddb3dfec..3e1080f2cd 100644 --- a/packages/bbui/src/Tabs/Tabs.svelte +++ b/packages/bbui/src/Tabs/Tabs.svelte @@ -5,6 +5,8 @@ export let selected export let vertical = false + export let noPadding = false + let _id = id() const tab = writable({ title: selected, id: _id }) setContext("tab", tab) @@ -63,14 +65,17 @@ {/if}
    -
    +
    diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js index f6d2c4eb9c..4d045e504b 100644 --- a/packages/bbui/src/index.js +++ b/packages/bbui/src/index.js @@ -55,6 +55,7 @@ export { default as Search } from "./Form/Search.svelte" export { default as Pagination } from "./Pagination/Pagination.svelte" export { default as Badge } from "./Badge/Badge.svelte" export { default as StatusLight } from "./StatusLight/StatusLight.svelte" +export { default as ColorPicker } from "./ColorPicker/ColorPicker.svelte" // Typography export { default as Body } from "./Typography/Body.svelte" diff --git a/packages/bbui/src/utils/helpers.js b/packages/bbui/src/utils/helpers.js index 13531d7f09..83d305d573 100644 --- a/packages/bbui/src/utils/helpers.js +++ b/packages/bbui/src/utils/helpers.js @@ -4,3 +4,5 @@ export const generateID = () => { // Starts with a letter so that its a valid DOM ID return `A${rand}` } + +export const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1) diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 0aa43308af..2c09c4b3c5 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -4,6 +4,8 @@ const path = require("path") const tmpdir = path.join(require("os").tmpdir(), ".budibase") // these run on ports we don't normally use so that they can run alongside the +const fs = require("fs") + // normal development system const WORKER_PORT = "10002" const MAIN_PORT = cypressConfig.env.PORT @@ -27,10 +29,14 @@ process.env.LOG_LEVEL = "error" async function run() { // require("dotenv").config({ path: resolve(dir, ".env") }) + if (!fs.existsSync("../server/dist")) { + console.error("Unable to run cypress, need to build server first") + process.exit(-1) + } // dont make this a variable or top level require // it will cause environment module to be loaded prematurely - const server = require("../../server/src/app") + const server = require("../../server/dist/app") process.env.PORT = WORKER_PORT const worker = require("../../worker/src/index") // reload main port for rest of system diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 9a7e2715da..a462167ce2 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -488,12 +488,12 @@ export const getFrontendStore = () => { }) await Promise.all(promises) }, - updateStyle: async (type, name, value) => { + updateStyle: async (name, value) => { const selected = get(selectedComponent) if (value == null || value === "") { - delete selected._styles[type][name] + delete selected._styles.normal[name] } else { - selected._styles[type][name] = value + selected._styles.normal[name] = value } await store.actions.preview.saveSelected() }, diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js index 7d7283c3d6..83b6e6a502 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -54,6 +54,10 @@ function generateTitleContainer(table) { .type("h2") .instanceName("Title") .text(table.name) + .customProps({ + size: "M", + align: "left", + }) return new Component("@budibase/standard-components/container") .normalStyle({ diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js b/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js index 239a4dfb50..04ff1f4ba2 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js @@ -21,6 +21,7 @@ export class Screen extends BaseStructure { hAlign: "stretch", vAlign: "top", size: "grow", + gap: "M", }, routing: { route: "", diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js index 4d2c13355d..93361e6c11 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js @@ -25,11 +25,8 @@ export function makeLinkComponent(tableName) { .customProps({ url: `/${tableName.toLowerCase()}`, openInNewTab: false, - color: "", - hoverColor: "", - underline: false, - fontSize: "", - fontFamily: "initial", + size: "S", + align: "left", }) } @@ -62,6 +59,10 @@ export function makeBreadcrumbContainer(tableName, text, capitalise = false) { .customStyle(spectrumColor(700)) .text(">") .instanceName("Arrow") + .customProps({ + size: "S", + align: "left", + }) const textStyling = { color: "#000000", @@ -77,6 +78,10 @@ export function makeBreadcrumbContainer(tableName, text, capitalise = false) { .customStyle(spectrumColor(700)) .text(text) .instanceName("Identifier") + .customProps({ + size: "S", + align: "left", + }) return new Component("@budibase/standard-components/container") .normalStyle({ @@ -148,6 +153,10 @@ export function makeTitleContainer(title) { .type("h2") .instanceName("Title") .text(title) + .customProps({ + size: "M", + align: "left", + }) return new Component("@budibase/standard-components/container") .normalStyle({ diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte index 180d03f7ff..d8c29ed250 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte @@ -45,7 +45,7 @@ size="L" confirmText="Create" onConfirm={saveDatasource} - disabled={error || !name} + disabled={error || !name || !integration?.type} > { const { type, data } = event.detail - if (type === "select-component") { + if (type === "select-component" && data.id) { store.actions.components.select({ _id: data.id }) } else if (type === "update-prop") { store.actions.components.updateProp(data.prop, data.value) + } else if (type === "delete-component" && data.id) { + idToDelete = data.id + confirmDeleteDialog.show() } else { console.log(data) } }) }) + + const deleteComponent = () => { + store.actions.components.delete({ _id: idToDelete }) + idToDelete = null + } + const cancelDeleteComponent = () => { + idToDelete = null + }
    @@ -92,6 +106,14 @@ srcdoc={template} />
    + diff --git a/packages/builder/src/components/design/PropertiesPanel/SettingsView.svelte b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte similarity index 62% rename from packages/builder/src/components/design/PropertiesPanel/SettingsView.svelte rename to packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte index 9dcd5f0daa..637ce22233 100644 --- a/packages/builder/src/components/design/PropertiesPanel/SettingsView.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte @@ -1,11 +1,13 @@ -
    - {#if assetInstance} - {#each assetDefinition as def (`${componentInstance._id}-${def.key}`)} - onScreenPropChange(def.key, val)} - /> - {/each} - {/if} - - {#if showDisplayName} + + {#if !componentInstance._component.endsWith("/layout")} updateProp("_instanceName", val)} /> {/if} - {#if settings && settings.length > 0} {#each settings as setting (`${componentInstance._id}-${setting.key}`)} {#if canRenderControl(setting)} @@ -147,52 +114,28 @@ value={componentInstance[setting.key] ?? componentInstance[setting.key]?.defaultValue} {componentInstance} - onChange={val => onChange(setting.key, val)} - props={{ options: setting.options, placeholder: setting.placeholder }} + onChange={val => updateProp(setting.key, val)} + props={{ + options: setting.options, + placeholder: setting.placeholder, + }} /> {/if} {/each} - {:else} -
    This component doesn't have any additional settings.
    + {/if} + {#if componentDefinition?.component?.endsWith("/fieldgroup")} + {/if} {#if componentDefinition?.info}
    {@html componentDefinition?.info}
    {/if} - - {#if componentDefinition?.component?.endsWith("/fieldgroup")} -
    - -
    - {/if} -
    - + diff --git a/packages/builder/src/components/design/PropertiesPanel/CustomStylesSection.svelte b/packages/builder/src/components/design/PropertiesPanel/CustomStylesSection.svelte new file mode 100644 index 0000000000..af8ba61ae6 --- /dev/null +++ b/packages/builder/src/components/design/PropertiesPanel/CustomStylesSection.svelte @@ -0,0 +1,60 @@ + + + +
    + Edit custom CSS +
    +
    + + + +
    + + Custom CSS overrides all other component styles. +