diff --git a/lerna.json b/lerna.json index 24172a05b0..e26819bf33 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.1.32-alpha.3", + "version": "2.1.32-alpha.11", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 6a54c16c89..fdc41293eb 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.1.32-alpha.3", + "version": "2.1.32-alpha.11", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -20,7 +20,7 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@budibase/types": "2.1.32-alpha.3", + "@budibase/types": "2.1.32-alpha.11", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-sdk": "2.1030.0", @@ -37,7 +37,6 @@ "lodash.isarguments": "3.1.0", "nano": "^10.1.0", "node-fetch": "2.6.7", - "passport-google-auth": "1.0.2", "passport-google-oauth": "2.0.0", "passport-jwt": "4.0.0", "passport-local": "1.0.0", diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index 9920be7e55..04feafa008 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -171,7 +171,7 @@ export function getGlobalUserParams(globalId: any, otherProps: any = {}) { /** * Gets parameters for retrieving users, this is a utility function for the getDocParams function. */ -export function getUserMetadataParams(userId?: string, otherProps = {}) { +export function getUserMetadataParams(userId?: string | null, otherProps = {}) { return getRowParams(InternalTable.USER_METADATA, userId, otherProps) } @@ -244,7 +244,7 @@ export function getTemplateParams( * Generates a new role ID. * @returns {string} The new role ID which the role doc can be stored under. */ -export function generateRoleID(id: any) { +export function generateRoleID(id?: any) { return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}` } diff --git a/packages/backend-core/src/migrations/migrations.ts b/packages/backend-core/src/migrations/migrations.ts index 60c17f4020..7bc2dec290 100644 --- a/packages/backend-core/src/migrations/migrations.ts +++ b/packages/backend-core/src/migrations/migrations.ts @@ -1,10 +1,13 @@ import { DEFAULT_TENANT_ID } from "../constants" -import { doWithDB } from "../db" -import { DocumentType, StaticDatabases } from "../db/constants" -import { getAllApps } from "../db/utils" +import { + DocumentType, + StaticDatabases, + getAllApps, + getGlobalDBName, + doWithDB, +} from "../db" import environment from "../environment" import { doInTenant, getTenantIds, getTenantId } from "../tenancy" -import { getGlobalDBName } from "../db/tenancy" import * as context from "../context" import { DEFINITIONS } from "." import { diff --git a/packages/backend-core/src/objectStore/index.ts b/packages/backend-core/src/objectStore/index.ts index 84eebeff81..a1193c0303 100644 --- a/packages/backend-core/src/objectStore/index.ts +++ b/packages/backend-core/src/objectStore/index.ts @@ -390,7 +390,7 @@ export const uploadDirectory = async ( return files } -exports.downloadTarballDirect = async ( +export const downloadTarballDirect = async ( url: string, path: string, headers = {} diff --git a/packages/backend-core/src/security/roles.ts b/packages/backend-core/src/security/roles.ts index da475322a7..bdf7a38726 100644 --- a/packages/backend-core/src/security/roles.ts +++ b/packages/backend-core/src/security/roles.ts @@ -1,10 +1,5 @@ import { BuiltinPermissionID, PermissionLevel } from "./permissions" -import { - generateRoleID, - getRoleParams, - DocumentType, - SEPARATOR, -} from "../db/utils" +import { generateRoleID, getRoleParams, DocumentType, SEPARATOR } from "../db" import { getAppDB } from "../context" import { doWithDB } from "../db" import { Screen, Role as RoleDoc } from "@budibase/types" @@ -30,20 +25,18 @@ const EXTERNAL_BUILTIN_ROLE_IDS = [ BUILTIN_IDS.PUBLIC, ] -export class Role { +export class Role implements RoleDoc { _id: string + _rev?: string name: string - permissionId?: string + permissionId: string inherits?: string + permissions = {} - constructor(id: string, name: string) { + constructor(id: string, name: string, permissionId: string) { this._id = id this.name = name - } - - addPermission(permissionId: string) { this.permissionId = permissionId - return this } addInheritance(inherits: string) { @@ -53,24 +46,26 @@ export class Role { } const BUILTIN_ROLES = { - ADMIN: new Role(BUILTIN_IDS.ADMIN, "Admin") - .addPermission(BuiltinPermissionID.ADMIN) - .addInheritance(BUILTIN_IDS.POWER), - POWER: new Role(BUILTIN_IDS.POWER, "Power") - .addPermission(BuiltinPermissionID.POWER) - .addInheritance(BUILTIN_IDS.BASIC), - BASIC: new Role(BUILTIN_IDS.BASIC, "Basic") - .addPermission(BuiltinPermissionID.WRITE) - .addInheritance(BUILTIN_IDS.PUBLIC), - PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public").addPermission( - BuiltinPermissionID.PUBLIC - ), - BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder").addPermission( + ADMIN: new Role( + BUILTIN_IDS.ADMIN, + "Admin", BuiltinPermissionID.ADMIN - ), + ).addInheritance(BUILTIN_IDS.POWER), + POWER: new Role( + BUILTIN_IDS.POWER, + "Power", + BuiltinPermissionID.POWER + ).addInheritance(BUILTIN_IDS.BASIC), + BASIC: new Role( + BUILTIN_IDS.BASIC, + "Basic", + BuiltinPermissionID.WRITE + ).addInheritance(BUILTIN_IDS.PUBLIC), + PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public", BuiltinPermissionID.PUBLIC), + BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder", BuiltinPermissionID.ADMIN), } -export function getBuiltinRoles() { +export function getBuiltinRoles(): { [key: string]: RoleDoc } { return cloneDeep(BUILTIN_ROLES) } @@ -104,7 +99,7 @@ export function builtinRoleToNumber(id?: string) { if (!role) { break } - role = builtins[role.inherits] + role = builtins[role.inherits!] count++ } while (role !== null) return count @@ -129,12 +124,12 @@ export async function roleToNumber(id?: string) { /** * Returns whichever builtin roleID is lower. */ -export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string) { +export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string): string { if (!roleId1) { - return roleId2 + return roleId2 as string } if (!roleId2) { - return roleId1 + return roleId1 as string } return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2) ? roleId2 diff --git a/packages/backend-core/src/security/sessions.ts b/packages/backend-core/src/security/sessions.ts index 33230afc60..48e75b0d60 100644 --- a/packages/backend-core/src/security/sessions.ts +++ b/packages/backend-core/src/security/sessions.ts @@ -89,6 +89,7 @@ export async function createASession( userId, } await client.store(key, session, EXPIRY_SECONDS) + return session } export async function updateSessionTTL(session: Session) { diff --git a/packages/bbui/package.json b/packages/bbui/package.json index b619e85651..2e2a9f7f36 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.1.32-alpha.3", + "version": "2.1.32-alpha.11", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "2.1.32-alpha.3", + "@budibase/string-templates": "2.1.32-alpha.11", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Skeleton/Skeleton.svelte b/packages/bbui/src/Skeleton/Skeleton.svelte new file mode 100644 index 0000000000..e12d37b057 --- /dev/null +++ b/packages/bbui/src/Skeleton/Skeleton.svelte @@ -0,0 +1,56 @@ +
+
+ +
+
+ + diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte index 7745c3c407..d6be0e8c9b 100644 --- a/packages/bbui/src/Table/Table.svelte +++ b/packages/bbui/src/Table/Table.svelte @@ -71,7 +71,8 @@ visibleRowCount, rowCount, totalRowCount, - rowHeight + rowHeight, + loading ) $: sortedRows = sortRows(rows, sortColumn, sortOrder) $: gridStyle = getGridStyle(fields, schema, showEditColumn) @@ -120,8 +121,12 @@ visibleRowCount, rowCount, totalRowCount, - rowHeight + rowHeight, + loading ) => { + if (loading) { + return `height: ${headerHeight + visibleRowCount * rowHeight}px;` + } if (!rowCount || !visibleRowCount || totalRowCount <= rowCount) { return "" } @@ -277,9 +282,11 @@ bind:offsetHeight={height} style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`} > - {#if !loaded} + {#if loading}
- + + +
{:else}
@@ -438,9 +445,10 @@ /* Loading */ .loading { - display: grid; - place-items: center; + display: flex; + align-items: center; min-height: 100px; + justify-content: center; } /* Table */ diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js index 538a62188f..601c4dcbca 100644 --- a/packages/bbui/src/index.js +++ b/packages/bbui/src/index.js @@ -4,6 +4,7 @@ import "./bbui.css" import "@spectrum-css/icon/dist/index-vars.css" // Components +export { default as Skeleton } from "./Skeleton/Skeleton.svelte" export { default as Input } from "./Form/Input.svelte" export { default as Stepper } from "./Form/Stepper.svelte" export { default as TextArea } from "./Form/TextArea.svelte" diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index f148ca201e..3b748a7daf 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -53,10 +53,10 @@ to-gfm-code-block "^0.1.1" year "^0.2.1" -"@budibase/string-templates@2.1.22-alpha.5": - version "2.1.22-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.1.22-alpha.5.tgz#3493be2ec8a3799ad1f7e470c308d9cdcd36abf6" - integrity sha512-iFN4nccB8eIjsaU0ki7DyC+zznJaGC+cUQiAiwgO+aDm3SD6vkF443IjwL/fcmpK81/4WpEWmJPDjVuQ+vjlKQ== +"@budibase/string-templates@2.1.32-alpha.0": + version "2.1.32-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.1.32-alpha.0.tgz#97452a80b3c3238e0d11b48ec36d2d7b8cb8e1d5" + integrity sha512-F+AkIWb8CitLt+YCJV/GQB8ECfj7GfO4I/vptIyNay9EWo0MRIU+4Xn715nBfEW5e23BQPKF3QR8S6y0IgxFbg== dependencies: "@budibase/handlebars-helpers" "^0.11.8" dayjs "^1.10.4" @@ -824,7 +824,7 @@ component-emitter@^1.2.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-with-sourcemaps@*, concat-with-sourcemaps@^1.1.0: version "1.1.0" @@ -2080,10 +2080,10 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -loader-utils@^1.1.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3" - integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg== +loader-utils@1.4.1, loader-utils@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.1.tgz#278ad7006660bccc4d2c0c1578e17c5c78d5c0e0" + integrity sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" @@ -2220,9 +2220,9 @@ mime@1.6.0: integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" diff --git a/packages/builder/cypress/integration/appPublishWorkflow.spec.js b/packages/builder/cypress/integration/appPublishWorkflow.spec.js index 0e3fbb191b..ab799f40fe 100644 --- a/packages/builder/cypress/integration/appPublishWorkflow.spec.js +++ b/packages/builder/cypress/integration/appPublishWorkflow.spec.js @@ -30,7 +30,6 @@ filterTests(['all'], () => { it("Should publish an application and correctly reflect that", () => { //Assuming the previous test was run and the unpublished app is open in edit mode. - cy.closeModal() cy.get(interact.TOPRIGHTNAV_BUTTON_SPECTRUM).contains("Publish").click({ force : true }) cy.get(interact.DEPLOY_APP_MODAL).should("be.visible") @@ -86,8 +85,7 @@ filterTests(['all'], () => { .within(() => { cy.get(interact.APP_TABLE_APP_NAME).click({ force: true }) }) - - cy.closeModal() + cy.get(interact.DEPLOYMENT_TOP_GLOBE).should("exist").click({ force: true }) cy.get("[data-cy='publish-popover-menu']") diff --git a/packages/builder/cypress/integration/createBinding.spec.js b/packages/builder/cypress/integration/createBinding.spec.js index 0c1ddf1e7d..0722d29f1d 100644 --- a/packages/builder/cypress/integration/createBinding.spec.js +++ b/packages/builder/cypress/integration/createBinding.spec.js @@ -9,9 +9,10 @@ filterTests(['smoke', 'all'], () => { }) it("should add a current user binding", () => { - cy.searchAndAddComponent("Paragraph").then(() => { + cy.searchAndAddComponent("Paragraph").then(componentId => { addSettingBinding("text", ["Current User", "_id"], "Current User._id") }) + cy.deleteComponentByName("New Paragraph") }) it("should handle an invalid binding", () => { @@ -21,6 +22,7 @@ filterTests(['smoke', 'all'], () => { .type("{{}{{}{{} Current User._id {}}{}}") .blur() cy.getComponent(componentId).should("have.text", "{{{ [user].[_id] }}") + cy.deleteComponentByName("New Paragraph") }) }) diff --git a/packages/builder/cypress/integration/datasources/rest.spec.js b/packages/builder/cypress/integration/datasources/rest.spec.js index 7cfe1ce9bb..7f715ae50c 100644 --- a/packages/builder/cypress/integration/datasources/rest.spec.js +++ b/packages/builder/cypress/integration/datasources/rest.spec.js @@ -1,7 +1,7 @@ import filterTests from "../../support/filterTests" filterTests(["smoke", "all"], () => { - context("REST Datasource Testing", () => { + xcontext("REST Datasource Testing", () => { before(() => { cy.login() cy.createTestApp() diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index c8d977258c..278c6504f8 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -440,8 +440,8 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => { // Creates an internal Budibase DB table if (!initialTable) { cy.navigateToDataSection() - cy.get(`[data-cy="new-datasource"]`, { timeout: 2000 }).click() } + cy.get(`[data-cy="new-datasource"]`, { timeout: 2000 }).click() cy.wait(2000) cy.get(".item", { timeout: 2000 }) .contains("Budibase DB") @@ -458,6 +458,9 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => { }) // Ensure modal has closed and table is created cy.get(".spectrum-Modal", { timeout: 2000 }).should("not.exist") + cy.get(".nav-item", { timeout: 2000 }) + .contains("Budibase DB") + .click({ force: true }) cy.get(".spectrum-Tabs-content", { timeout: 2000 }).should( "contain", tableName @@ -525,7 +528,7 @@ Cypress.Commands.add("addRowMultiValue", values => { }) Cypress.Commands.add("selectTable", tableName => { - cy.expandBudibaseConnection() + cy.get(".nav-item").contains("Budibase DB").click() cy.contains(".nav-item", tableName).click() }) @@ -576,6 +579,18 @@ Cypress.Commands.add("searchAndAddComponent", component => { }) }) +Cypress.Commands.add("deleteComponentByName", componentName => { + cy.get(".body") + .eq(0) + .contains(componentName) + .siblings(".actions") + .within(() => { + cy.get(".spectrum-Icon").click({ force: true }) + }) + cy.get(".spectrum-Menu").contains("Delete").click() + cy.get(".spectrum-Dialog").contains("Delete Component").click() +}) + Cypress.Commands.add("addComponent", (category, component) => { if (category) { cy.get(`[data-cy="category-${category}"]`, { timeout: 3000 }).click({ diff --git a/packages/builder/package.json b/packages/builder/package.json index 2e8367db1f..ec531fe7ec 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.1.32-alpha.3", + "version": "2.1.32-alpha.11", "license": "GPL-3.0", "private": true, "scripts": { @@ -71,10 +71,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.1.32-alpha.3", - "@budibase/client": "2.1.32-alpha.3", - "@budibase/frontend-core": "2.1.32-alpha.3", - "@budibase/string-templates": "2.1.32-alpha.3", + "@budibase/bbui": "2.1.32-alpha.11", + "@budibase/client": "2.1.32-alpha.11", + "@budibase/frontend-core": "2.1.32-alpha.11", + "@budibase/string-templates": "2.1.32-alpha.11", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 1291f81294..fb486c6d27 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -20,6 +20,11 @@ import { } from "../componentUtils" import { Helpers } from "@budibase/bbui" import { Utils } from "@budibase/frontend-core" +import { + BUDIBASE_INTERNAL_DB_ID, + DB_TYPE_INTERNAL, + DB_TYPE_EXTERNAL, +} from "constants/backend" const INITIAL_FRONTEND_STATE = { apps: [], @@ -481,8 +486,41 @@ export const getFrontendStore = () => { return null } - // Generate default props + // Flattened settings const settings = getComponentSettings(componentName) + + let dataSourceField = settings.find( + setting => setting.type == "dataSource" || setting.type == "table" + ) + + let defaultDatasource + if (dataSourceField) { + const _tables = get(tables) + const filteredTables = _tables.list.filter( + table => table._id != "ta_users" + ) + + const internalTable = filteredTables.find( + table => + table.sourceId === BUDIBASE_INTERNAL_DB_ID && + table.type == DB_TYPE_INTERNAL + ) + + const defaultSourceTable = filteredTables.find( + table => + table.sourceId !== BUDIBASE_INTERNAL_DB_ID && + table.type == DB_TYPE_INTERNAL + ) + + const defaultExternalTable = filteredTables.find( + table => table.type == DB_TYPE_EXTERNAL + ) + + defaultDatasource = + defaultSourceTable || internalTable || defaultExternalTable + } + + // Generate default props let props = { ...presetProps } settings.forEach(setting => { if (setting.defaultValue !== undefined) { @@ -490,6 +528,15 @@ export const getFrontendStore = () => { } }) + // Set a default datasource + if (dataSourceField && defaultDatasource) { + props[dataSourceField.key] = { + label: defaultDatasource.name, + tableId: defaultDatasource._id, + type: "table", + } + } + // Add any extra properties the component needs let extras = {} if (definition.hasChildren) { diff --git a/packages/builder/src/components/integration/QueryBindingBuilder.svelte b/packages/builder/src/components/integration/QueryBindingBuilder.svelte index 255bee21dd..3a89c4b968 100644 --- a/packages/builder/src/components/integration/QueryBindingBuilder.svelte +++ b/packages/builder/src/components/integration/QueryBindingBuilder.svelte @@ -1,5 +1,5 @@
Bindings - {#if !bindable} - - {/if}
{#if !bindable} diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index 5ecc7bc324..f3898e1d9e 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -175,6 +175,8 @@ export const SWITCHABLE_TYPES = [ export const BUDIBASE_INTERNAL_DB_ID = "bb_internal" export const BUDIBASE_DATASOURCE_TYPE = "budibase" +export const DB_TYPE_INTERNAL = "internal" +export const DB_TYPE_EXTERNAL = "external" export const IntegrationTypes = { POSTGRES: "POSTGRES", diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index a854d09304..5296604dc7 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -1,7 +1,6 @@ -{#if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden} +{#if showSkeleton} + +{:else if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden}
+ import { writable } from "svelte/store" import { setContext, getContext, onMount } from "svelte" import Router, { querystring } from "svelte-spa-router" import { routeStore, stateStore } from "stores" @@ -9,6 +10,9 @@ const component = getContext("component") setContext("screenslot", true) + const loading = writable(false) + setContext("loading", loading) + // Only wrap this as an array to take advantage of svelte keying, // to ensure the svelte-spa-router is fully remounted when route config // changes diff --git a/packages/client/src/components/app/DataProvider.svelte b/packages/client/src/components/app/DataProvider.svelte index 8cd2f00eec..c28cdef24c 100644 --- a/packages/client/src/components/app/DataProvider.svelte +++ b/packages/client/src/components/app/DataProvider.svelte @@ -1,6 +1,7 @@ {#if $component.empty} - {:else if rows.length > 0} + {:else if !$loading && rows.length === 0} +
{noRowsMessage}
+ {:else} {#each rows as row, index} {/each} - {:else if loaded && noRowsMessage} -
{noRowsMessage}
{/if}
diff --git a/packages/client/src/components/app/Skeleton.svelte b/packages/client/src/components/app/Skeleton.svelte new file mode 100644 index 0000000000..5c247bf3e4 --- /dev/null +++ b/packages/client/src/components/app/Skeleton.svelte @@ -0,0 +1,31 @@ + + +
+ + + +
diff --git a/packages/client/src/components/app/forms/AttachmentField.svelte b/packages/client/src/components/app/forms/AttachmentField.svelte index 9887901d4c..da04c57e82 100644 --- a/packages/client/src/components/app/forms/AttachmentField.svelte +++ b/packages/client/src/components/app/forms/AttachmentField.svelte @@ -76,18 +76,26 @@ bind:fieldApi defaultValue={[]} > - {#if fieldState} - - {/if} +
+ {#if fieldState} + + {/if} +
+ + diff --git a/packages/client/src/components/app/forms/Field.svelte b/packages/client/src/components/app/forms/Field.svelte index d6dddbbe39..a14c6ac9c8 100644 --- a/packages/client/src/components/app/forms/Field.svelte +++ b/packages/client/src/components/app/forms/Field.svelte @@ -1,6 +1,7 @@