diff --git a/.github/workflows/close-featurebranch.yml b/.github/workflows/close-featurebranch.yml index 0ec3b43598..5f232b2f26 100644 --- a/.github/workflows/close-featurebranch.yml +++ b/.github/workflows/close-featurebranch.yml @@ -14,7 +14,7 @@ jobs: - uses: passeidireto/trigger-external-workflow-action@main env: PAYLOAD_BRANCH: ${{ github.head_ref }} - PAYLOAD_PR_NUMBER: ${{ github.ref }} + PAYLOAD_PR_NUMBER: ${{ github.event.pull_request.number }} with: repository: budibase/budibase-deploys event: featurebranch-qa-close diff --git a/.github/workflows/deploy-featurebranch.yml b/.github/workflows/deploy-featurebranch.yml index f06707ab2b..ddf185a1d9 100644 --- a/.github/workflows/deploy-featurebranch.yml +++ b/.github/workflows/deploy-featurebranch.yml @@ -13,7 +13,7 @@ jobs: - uses: passeidireto/trigger-external-workflow-action@main env: PAYLOAD_BRANCH: ${{ github.head_ref }} - PAYLOAD_PR_NUMBER: ${{ github.ref }} + PAYLOAD_PR_NUMBER: ${{ github.event.pull_request.number }} with: repository: budibase/budibase-deploys event: featurebranch-qa-deploy diff --git a/lerna.json b/lerna.json index c4d2219e21..8c55fa94b7 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.12-alpha.23", + "version": "2.11.5-alpha.2", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index d758888eab..e5b6554fca 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "prettier-plugin-svelte": "^2.3.0", "rimraf": "^3.0.2", "rollup-plugin-replace": "^2.2.0", - "svelte": "^3.38.2", + "svelte": "3.49.0", "typescript": "5.2.2", "@babel/core": "^7.22.5", "@babel/eslint-parser": "^7.22.5", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 1c94163d93..b1dced660c 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -33,17 +33,14 @@ "bull": "4.10.1", "correlation-id": "4.0.0", "dotenv": "16.0.1", - "emitter-listener": "1.1.2", "ioredis": "5.3.2", "joi": "17.6.0", "jsonwebtoken": "9.0.0", "koa-passport": "4.1.4", "koa-pino-logger": "4.0.0", "lodash": "4.17.21", - "lodash.isarguments": "3.1.0", "node-fetch": "2.6.7", "passport-google-oauth": "2.0.0", - "passport-jwt": "4.0.0", "passport-local": "1.0.0", "passport-oauth2-refresh": "^2.1.0", "pino": "8.11.0", @@ -59,14 +56,13 @@ "uuid": "8.3.2" }, "devDependencies": { - "@jest/test-sequencer": "29.6.2", "@shopify/jest-koa-mocks": "5.1.1", "@swc/core": "1.3.71", "@swc/jest": "0.2.27", "@trendyol/jest-testcontainers": "^2.1.1", "@types/chance": "1.1.3", + "@types/cookies": "0.7.8", "@types/jest": "29.5.3", - "@types/koa": "2.13.4", "@types/lodash": "4.14.180", "@types/node": "18.17.0", "@types/node-fetch": "2.6.4", @@ -80,13 +76,9 @@ "jest": "29.6.2", "jest-environment-node": "29.6.2", "jest-serial-runner": "1.2.1", - "koa": "2.13.4", - "nodemon": "2.0.16", "pino-pretty": "10.0.0", "pouchdb-adapter-memory": "7.2.2", "timekeeper": "2.2.0", - "ts-node": "10.8.1", - "tsconfig-paths": "4.0.0", "typescript": "5.2.2" }, "nx": { diff --git a/packages/backend-core/src/constants/db.ts b/packages/backend-core/src/constants/db.ts index 83f8298f54..f918dcc352 100644 --- a/packages/backend-core/src/constants/db.ts +++ b/packages/backend-core/src/constants/db.ts @@ -18,7 +18,7 @@ export enum ViewName { ROUTING = "screen_routes", AUTOMATION_LOGS = "automation_logs", ACCOUNT_BY_EMAIL = "account_by_email", - PLATFORM_USERS_LOWERCASE = "platform_users_lowercase", + PLATFORM_USERS_LOWERCASE = "platform_users_lowercase_2", USER_BY_GROUP = "user_by_group", APP_BACKUP_BY_TRIGGER = "by_trigger", } diff --git a/packages/backend-core/src/db/views.ts b/packages/backend-core/src/db/views.ts index 7f5ef29a0a..f0980ad217 100644 --- a/packages/backend-core/src/db/views.ts +++ b/packages/backend-core/src/db/views.ts @@ -190,6 +190,10 @@ export const createPlatformUserView = async () => { if (doc.tenantId) { emit(doc._id.toLowerCase(), doc._id) } + + if (doc.ssoId) { + emit(doc.ssoId, doc._id) + } }` await createPlatformView(viewJs, ViewName.PLATFORM_USERS_LOWERCASE) } diff --git a/packages/backend-core/src/platform/users.ts b/packages/backend-core/src/platform/users.ts index c65a7e0ec4..6f030afb7c 100644 --- a/packages/backend-core/src/platform/users.ts +++ b/packages/backend-core/src/platform/users.ts @@ -5,6 +5,7 @@ import { PlatformUser, PlatformUserByEmail, PlatformUserById, + PlatformUserBySsoId, User, } from "@budibase/types" @@ -45,6 +46,20 @@ function newUserEmailDoc( } } +function newUserSsoIdDoc( + ssoId: string, + email: string, + userId: string, + tenantId: string +): PlatformUserBySsoId { + return { + _id: ssoId, + userId, + email, + tenantId, + } +} + /** * Add a new user id or email doc if it doesn't exist. */ @@ -64,11 +79,24 @@ async function addUserDoc(emailOrId: string, newDocFn: () => PlatformUser) { } } -export async function addUser(tenantId: string, userId: string, email: string) { - await Promise.all([ +export async function addUser( + tenantId: string, + userId: string, + email: string, + ssoId?: string +) { + const promises = [ addUserDoc(userId, () => newUserIdDoc(userId, tenantId)), addUserDoc(email, () => newUserEmailDoc(userId, email, tenantId)), - ]) + ] + + if (ssoId) { + promises.push( + addUserDoc(ssoId, () => newUserSsoIdDoc(ssoId, email, userId, tenantId)) + ) + } + + await Promise.all(promises) } // DELETE diff --git a/packages/backend-core/src/security/permissions.ts b/packages/backend-core/src/security/permissions.ts index 13083534b1..539bbaef27 100644 --- a/packages/backend-core/src/security/permissions.ts +++ b/packages/backend-core/src/security/permissions.ts @@ -1,8 +1,9 @@ -import { PermissionType, PermissionLevel } from "@budibase/types" -export { PermissionType, PermissionLevel } from "@budibase/types" +import { PermissionLevel, PermissionType } from "@budibase/types" import flatten from "lodash/flatten" import cloneDeep from "lodash/fp/cloneDeep" +export { PermissionType, PermissionLevel } from "@budibase/types" + export type RoleHierarchy = { permissionId: string }[] @@ -78,6 +79,7 @@ export const BUILTIN_PERMISSIONS = { permissions: [ new Permission(PermissionType.QUERY, PermissionLevel.READ), new Permission(PermissionType.TABLE, PermissionLevel.READ), + new Permission(PermissionType.APP, PermissionLevel.READ), ], }, WRITE: { @@ -88,6 +90,7 @@ export const BUILTIN_PERMISSIONS = { new Permission(PermissionType.TABLE, PermissionLevel.WRITE), new Permission(PermissionType.AUTOMATION, PermissionLevel.EXECUTE), new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ), + new Permission(PermissionType.APP, PermissionLevel.READ), ], }, POWER: { @@ -99,6 +102,7 @@ export const BUILTIN_PERMISSIONS = { new Permission(PermissionType.AUTOMATION, PermissionLevel.EXECUTE), new Permission(PermissionType.WEBHOOK, PermissionLevel.READ), new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ), + new Permission(PermissionType.APP, PermissionLevel.READ), ], }, ADMIN: { @@ -111,6 +115,7 @@ export const BUILTIN_PERMISSIONS = { new Permission(PermissionType.WEBHOOK, PermissionLevel.READ), new Permission(PermissionType.QUERY, PermissionLevel.ADMIN), new Permission(PermissionType.LEGACY_VIEW, PermissionLevel.READ), + new Permission(PermissionType.APP, PermissionLevel.READ), ], }, } diff --git a/packages/backend-core/src/security/roles.ts b/packages/backend-core/src/security/roles.ts index e87df2e9c9..24279e6b5c 100644 --- a/packages/backend-core/src/security/roles.ts +++ b/packages/backend-core/src/security/roles.ts @@ -215,21 +215,23 @@ async function getAllUserRoles(userRoleId?: string): Promise { return roles } +export async function getUserRoleIdHierarchy( + userRoleId?: string +): Promise { + const roles = await getUserRoleHierarchy(userRoleId) + return roles.map(role => role._id!) +} + /** * Returns an ordered array of the user's inherited role IDs, this can be used * to determine if a user can access something that requires a specific role. * @param {string} userRoleId The user's role ID, this can be found in their access token. - * @param {object} opts Various options, such as whether to only retrieve the IDs (default true). - * @returns {Promise} returns an ordered array of the roles, with the first being their + * @returns {Promise} returns an ordered array of the roles, with the first being their * highest level of access and the last being the lowest level. */ -export async function getUserRoleHierarchy( - userRoleId?: string, - opts = { idOnly: true } -) { +export async function getUserRoleHierarchy(userRoleId?: string) { // special case, if they don't have a role then they are a public user - const roles = await getAllUserRoles(userRoleId) - return opts.idOnly ? roles.map(role => role._id) : roles + return getAllUserRoles(userRoleId) } // this function checks that the provided permissions are in an array format @@ -249,6 +251,11 @@ export function checkForRoleResourceArray( return rolePerms } +export async function getAllRoleIds(appId?: string) { + const roles = await getAllRoles(appId) + return roles.map(role => role._id) +} + /** * Given an app ID this will retrieve all of the roles that are currently within that app. * @return {Promise} An array of the role objects that were found. @@ -332,9 +339,7 @@ export class AccessController { } let roleIds = userRoleId ? this.userHierarchies[userRoleId] : null if (!roleIds && userRoleId) { - roleIds = (await getUserRoleHierarchy(userRoleId, { - idOnly: true, - })) as string[] + roleIds = await getUserRoleIdHierarchy(userRoleId) this.userHierarchies[userRoleId] = roleIds } diff --git a/packages/backend-core/src/users/db.ts b/packages/backend-core/src/users/db.ts index c288540f35..1d02bebc32 100644 --- a/packages/backend-core/src/users/db.ts +++ b/packages/backend-core/src/users/db.ts @@ -278,7 +278,12 @@ export class UserDB { builtUser._rev = response.rev await eventHelpers.handleSaveEvents(builtUser, dbUser) - await platform.users.addUser(tenantId, builtUser._id!, builtUser.email) + await platform.users.addUser( + tenantId, + builtUser._id!, + builtUser.email, + builtUser.ssoId + ) await cache.user.invalidateUser(response.id) await Promise.all(groupPromises) diff --git a/packages/backend-core/src/utils/utils.ts b/packages/backend-core/src/utils/utils.ts index 82da95983a..ac43fa1fdb 100644 --- a/packages/backend-core/src/utils/utils.ts +++ b/packages/backend-core/src/utils/utils.ts @@ -10,7 +10,7 @@ import { Event, TenantResolutionStrategy, } from "@budibase/types" -import { SetOption } from "cookies" +import type { SetOption } from "cookies" const jwt = require("jsonwebtoken") const APP_PREFIX = DocumentType.APP + SEPARATOR diff --git a/packages/backend-core/tests/core/utilities/structures/accounts.ts b/packages/backend-core/tests/core/utilities/structures/accounts.ts index 67e4411ea3..515f94db1e 100644 --- a/packages/backend-core/tests/core/utilities/structures/accounts.ts +++ b/packages/backend-core/tests/core/utilities/structures/accounts.ts @@ -1,4 +1,4 @@ -import { generator, uuid, quotas } from "." +import { generator, quotas, uuid } from "." import { generateGlobalUserID } from "../../../../src/docIds" import { Account, @@ -6,10 +6,11 @@ import { AccountSSOProviderType, AuthType, CloudAccount, - Hosting, - SSOAccount, CreateAccount, CreatePassswordAccount, + CreateVerifiableSSOAccount, + Hosting, + SSOAccount, } from "@budibase/types" import sample from "lodash/sample" @@ -68,6 +69,23 @@ export function ssoAccount(account: Account = cloudAccount()): SSOAccount { } } +export function verifiableSsoAccount( + account: Account = cloudAccount() +): SSOAccount { + return { + ...account, + authType: AuthType.SSO, + oauth2: { + accessToken: generator.string(), + refreshToken: generator.string(), + }, + pictureUrl: generator.url(), + provider: AccountSSOProvider.MICROSOFT, + providerType: AccountSSOProviderType.MICROSOFT, + thirdPartyProfile: { id: "abc123" }, + } +} + export const cloudCreateAccount: CreatePassswordAccount = { email: "cloud@budibase.com", tenantId: "cloud", @@ -91,6 +109,19 @@ export const cloudSSOCreateAccount: CreateAccount = { profession: "Software Engineer", } +export const cloudVerifiableSSOCreateAccount: CreateVerifiableSSOAccount = { + email: "cloud-sso@budibase.com", + tenantId: "cloud-sso", + hosting: Hosting.CLOUD, + authType: AuthType.SSO, + tenantName: "cloudsso", + name: "Budi Armstrong", + size: "10+", + profession: "Software Engineer", + provider: AccountSSOProvider.MICROSOFT, + thirdPartyProfile: { id: "abc123" }, +} + export const selfCreateAccount: CreatePassswordAccount = { email: "self@budibase.com", tenantId: "self", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index dc6c910be8..4791776c57 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -20,14 +20,12 @@ "@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.2.1", - "cross-env": "^7.0.2", - "nollup": "^0.14.1", "postcss": "^8.2.9", "rollup": "^2.45.2", "rollup-plugin-postcss": "^4.0.0", "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-terser": "^7.0.2", - "svelte": "^3.38.2" + "svelte": "3.49.0" }, "keywords": [ "svelte" diff --git a/packages/builder/package.json b/packages/builder/package.json index a53f3509cf..20530cad20 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -65,7 +65,6 @@ "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", "@sentry/browser": "5.19.1", - "@spectrum-css/accordion": "^3.0.24", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", "codemirror": "^5.59.0", @@ -75,18 +74,17 @@ "lodash": "4.17.21", "posthog-js": "^1.36.0", "remixicon": "2.5.0", + "sanitize-html": "^2.7.0", "shortid": "2.2.15", "svelte-dnd-action": "^0.9.8", "svelte-loading-spinners": "^0.1.1", "svelte-portal": "1.0.0", - "uuid": "8.3.1", "yup": "0.29.2" }, "devDependencies": { "@babel/core": "^7.12.14", "@babel/plugin-transform-runtime": "^7.13.10", "@babel/preset-env": "^7.13.12", - "@babel/runtime": "^7.13.10", "@rollup/plugin-replace": "^2.4.2", "@roxi/routify": "2.18.5", "@sveltejs/vite-plugin-svelte": "1.0.1", @@ -96,19 +94,10 @@ "identity-obj-proxy": "^3.0.0", "jest": "29.6.2", "jsdom": "^21.1.1", - "mochawesome": "^7.1.3", - "mochawesome-merge": "^4.2.1", - "mochawesome-report-generator": "^6.2.0", "ncp": "^2.0.0", - "rimraf": "^3.0.2", "rollup": "^2.44.0", - "rollup-plugin-copy": "^3.4.0", - "start-server-and-test": "^1.12.1", "svelte": "^3.48.0", "svelte-jester": "^1.3.2", - "ts-node": "10.8.1", - "tsconfig-paths": "4.0.0", - "typescript": "5.2.2", "vite": "^3.0.8", "vite-plugin-static-copy": "^0.16.0", "vitest": "^0.29.2" diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index 4ebf0515d6..c22240370b 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -221,18 +221,6 @@ const automationActions = store => ({ newAutomation.definition.steps.splice(blockIdx, 0, block) await store.actions.save(newAutomation) }, - /** - * "rowControl" appears to be the name of the flag used to determine whether - * a certain automation block uses values or bindings as inputs - */ - toggleRowControl: async (block, rowControl) => { - const newBlock = { ...block, rowControl } - const newAutomation = store.actions.getUpdatedDefinition( - get(selectedAutomation), - newBlock - ) - await store.actions.save(newAutomation) - }, deleteAutomationBlock: async block => { const automation = get(selectedAutomation) let newAutomation = cloneDeep(automation) diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js index bbefe65fc8..b17bd99e10 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -33,6 +33,8 @@ const generateTableBlock = datasource => { showTitleButton: true, titleButtonText: "Create row", titleButtonClickBehaviour: "new", + sidePanelSaveLabel: "Save", + sidePanelDeleteLabel: "Delete", }) .instanceName(`${datasource.label} - Table block`) return tableBlock diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte index 85c3776fdb..6c964c84a9 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte @@ -7,7 +7,6 @@ Detail, Modal, Button, - Select, ActionButton, notifications, Label, @@ -39,9 +38,6 @@ step => step.stepId === ActionStepID.COLLECT ) $: automationId = $selectedAutomation?._id - $: showBindingPicker = - block.stepId === ActionStepID.CREATE_ROW || - block.stepId === ActionStepID.UPDATE_ROW $: isTrigger = block.type === "TRIGGER" $: steps = $selectedAutomation?.definition?.steps ?? [] $: blockIdx = steps.findIndex(step => step.id === block.id) @@ -96,15 +92,6 @@ } } - /** - * "rowControl" appears to be the name of the flag used to determine whether - * a certain automation block uses values or bindings as inputs - */ - function toggleRowControl(evt) { - const rowControl = evt.detail !== "Use values" - automationStore.actions.toggleRowControl(block, rowControl) - } - async function addLooping() { const loopDefinition = $automationStore.blockDefinitions.ACTION.LOOP const loopBlock = automationStore.actions.constructBlock( @@ -189,16 +176,6 @@ Add Looping {/if} - {#if showBindingPicker} - onChange(e, key)} @@ -469,7 +420,6 @@ /> {:else if value.customType === "row"} { diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte index 5039c37ece..c3097f3072 100644 --- a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte +++ b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte @@ -1,18 +1,16 @@
@@ -17,15 +18,17 @@ table.name} + getOptionValue={table => table._id} + bind:value={relationshipTableIdPrimary} />
@@ -34,7 +37,7 @@ table._id !== relationshipTableIdPrimary + )} getOptionLabel={table => table.name} getOptionValue={table => table._id} /> diff --git a/packages/builder/src/components/common/bindings/DrawerBindableSlot.svelte b/packages/builder/src/components/common/bindings/DrawerBindableSlot.svelte new file mode 100644 index 0000000000..b38e8c3ae5 --- /dev/null +++ b/packages/builder/src/components/common/bindings/DrawerBindableSlot.svelte @@ -0,0 +1,250 @@ + + +
+ {#if !isValid(value)} + onChange(event.detail)} + on:blur={onBlur} + {placeholder} + {updateOnChange} + /> +
{ + if (!isJS) { + dispatch("change", "") + } + }} + > + +
+ {:else} + + {/if} + {#if !disabled && type !== "formula"} +
{ + bindingDrawer.show() + }} + > + +
+ {/if} +
+ + + Add the objects on the left to enrich your text. + + + (tempValue = event.detail)} + {bindings} + {allowJS} + {allowHelpers} + /> + + + diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte index 6e7ee52268..59a3289731 100644 --- a/packages/builder/src/components/integration/QueryViewer.svelte +++ b/packages/builder/src/components/integration/QueryViewer.svelte @@ -337,11 +337,12 @@ padding: 8px 10px 8px 16px; display: flex; border-bottom: 2px solid transparent; - transition: border-bottom 130ms ease-out; + transition: border-bottom 130ms ease-out, background 130ms ease-out; } .header.scrolling { border-bottom: var(--border-light); + background: var(--background); } .body { diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index 047152eeed..8b76207822 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -120,10 +120,11 @@ export const FIELDS = { presence: false, }, }, - USER: { + BB_REFERENCE_USER: { name: "User", type: "bb_reference", subtype: "user", + compositeType: "bb_reference_user", // Used for working with the subtype on CreateEditColumn as is it was a primary type icon: "User", }, } diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/panels/Relationships.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/panels/Relationships.svelte index 384b87e11d..1a46ecb540 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/panels/Relationships.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/panels/Relationships.svelte @@ -21,15 +21,22 @@ function getRelationships(tables) { const relatedColumns = {} - tables.forEach(({ name: tableName, schema }) => { + tables.forEach(({ name: tableName, schema, _id: tableId }) => { Object.values(schema).forEach(column => { if (column.type !== "link") return - relatedColumns[column._id] ??= {} - relatedColumns[column._id].through = - relatedColumns[column._id].through || column.through + const columnId = + column.through || + column._id || + (column.main + ? `${tableId}_${column.fieldName}__${column.tableId}_${column.foreignKey}` + : `${column.tableId}_${column.foreignKey}__${tableId}_${column.fieldName}`) - relatedColumns[column._id][column.main ? "from" : "to"] = { + relatedColumns[columnId] ??= {} + relatedColumns[columnId].through = + relatedColumns[columnId].through || column.through + + relatedColumns[columnId][column.main ? "from" : "to"] = { ...column, tableName, } diff --git a/packages/builder/src/pages/builder/portal/apps/_layout.svelte b/packages/builder/src/pages/builder/portal/apps/_layout.svelte index c4a0bfd913..4067856bfa 100644 --- a/packages/builder/src/pages/builder/portal/apps/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/apps/_layout.svelte @@ -46,7 +46,9 @@ {#if loaded}
- + {#if $apps.length > 0} + + {/if}
{/if} diff --git a/packages/builder/src/stores/backend/tables.js b/packages/builder/src/stores/backend/tables.js index 201a67824d..457a58fdbb 100644 --- a/packages/builder/src/stores/backend/tables.js +++ b/packages/builder/src/stores/backend/tables.js @@ -1,7 +1,7 @@ import { get, writable, derived } from "svelte/store" import { cloneDeep } from "lodash/fp" import { API } from "api" -import { SWITCHABLE_TYPES } from "constants/backend" +import { SWITCHABLE_TYPES, FIELDS } from "constants/backend" export function createTablesStore() { const store = writable({ @@ -21,6 +21,23 @@ export function createTablesStore() { })) } + const singleFetch = async tableId => { + const table = await API.getTable(tableId) + store.update(state => { + const list = [] + // update the list, keep order accurate + for (let tbl of state.list) { + if (table._id === tbl._id) { + list.push(table) + } else { + list.push(tbl) + } + } + state.list = list + return state + }) + } + const select = tableId => { store.update(state => ({ ...state, @@ -63,6 +80,20 @@ export function createTablesStore() { const savedTable = await API.saveTable(updatedTable) replaceTable(savedTable._id, savedTable) select(savedTable._id) + // make sure tables up to date (related) + let tableIdsToFetch = [] + for (let column of Object.values(updatedTable?.schema || {})) { + if (column.type === FIELDS.LINK.type) { + tableIdsToFetch.push(column.tableId) + } + } + tableIdsToFetch = [...new Set(tableIdsToFetch)] + // too many tables to fetch, just get all + if (tableIdsToFetch.length > 3) { + await fetch() + } else { + await Promise.all(tableIdsToFetch.map(id => singleFetch(id))) + } return savedTable } diff --git a/packages/builder/tsconfig.json b/packages/builder/tsconfig.json index 0913aea33d..b2084dba65 100644 --- a/packages/builder/tsconfig.json +++ b/packages/builder/tsconfig.json @@ -5,8 +5,5 @@ "declaration": true, "sourceMap": true, "baseUrl": "." - }, - "ts-node": { - "require": ["tsconfig-paths/register"] } } diff --git a/packages/cli/package.json b/packages/cli/package.json index 04eeb523cd..49384538ef 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -32,7 +32,6 @@ "@budibase/backend-core": "0.0.0", "@budibase/string-templates": "0.0.0", "@budibase/types": "0.0.0", - "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", "commander": "7.1.0", @@ -41,7 +40,6 @@ "download": "8.0.0", "find-free-port": "^2.0.0", "inquirer": "8.0.0", - "joi": "17.6.0", "lookpath": "1.1.0", "node-fetch": "2.6.7", "pkg": "5.8.0", @@ -53,13 +51,9 @@ "yaml": "^2.1.1" }, "devDependencies": { - "@swc/core": "1.3.71", - "@swc/jest": "0.2.27", "@types/jest": "29.5.3", "@types/node-fetch": "2.6.4", "@types/pouchdb": "^6.4.0", - "copyfiles": "^2.4.1", - "eslint": "^7.20.0", "renamer": "^4.0.0", "ts-node": "^10.9.1", "typescript": "5.2.2" diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index e557874edb..bdab0dd9ab 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -3,16 +3,16 @@ import { writable } from "svelte/store" import { Heading, Icon, clickOutside } from "@budibase/bbui" import { FieldTypes } from "constants" + import { Constants } from "@budibase/frontend-core" import active from "svelte-spa-router/active" - import { RoleUtils } from "@budibase/frontend-core" const sdk = getContext("sdk") const { routeStore, + roleStore, styleable, linkable, builderStore, - currentRole, sidePanelStore, } = sdk const component = getContext("component") @@ -61,7 +61,7 @@ }) setContext("layout", store) - $: validLinks = getValidLinks(links, $currentRole) + $: validLinks = getValidLinks(links, $roleStore) $: typeClass = NavigationClasses[navigation] || NavigationClasses.None $: navWidthClass = WidthClasses[navWidth || width] || WidthClasses.Large $: pageWidthClass = WidthClasses[pageWidth || width] || WidthClasses.Large @@ -99,14 +99,13 @@ } } - const getValidLinks = (allLinks, role) => { + const getValidLinks = (allLinks, userRoleHierarchy) => { // Strip links missing required info let validLinks = (allLinks || []).filter(link => link.text && link.url) - // Filter to only links allowed by the current role - const priority = RoleUtils.getRolePriority(role) return validLinks.filter(link => { - return !link.roleId || RoleUtils.getRolePriority(link.roleId) <= priority + const role = link.roleId || Constants.Roles.BASIC + return userRoleHierarchy?.find(roleId => roleId === role) }) } diff --git a/packages/client/src/components/app/Section.svelte b/packages/client/src/components/app/Section.svelte index 11f0f2978f..b86c5cc352 100644 --- a/packages/client/src/components/app/Section.svelte +++ b/packages/client/src/components/app/Section.svelte @@ -47,28 +47,29 @@