From 5ddc543bd59b12b14fa9fc054e70220c3e6d4444 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 23 Nov 2023 12:57:43 +0000 Subject: [PATCH 01/42] Minor UX updates --- .../_components/BuilderSidePanel.svelte | 33 ++++++++++++------- .../builder/portal/users/users/index.svelte | 1 + 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index a67c2d3c61..c3bb5171a4 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -781,7 +781,7 @@ {/if} {:else} - +
@@ -808,19 +808,21 @@ : Constants.BudibaseRoleOptionsNew.filter( option => option.value !== Constants.BudibaseRoles.Admin )} - label="Role" + label="Access" /> {#if creationRoleType !== Constants.BudibaseRoles.Admin} - + + + {/if} {#if creationRoleType === Constants.BudibaseRoles.Admin} @@ -847,6 +849,13 @@
diff --git a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/GridColumnConfiguration.svelte b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/GridColumnConfiguration.svelte new file mode 100644 index 0000000000..4286328367 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/GridColumnConfiguration.svelte @@ -0,0 +1,107 @@ + + +{#if columns.primary} +
+
+
+ columns.update(e.detail)} + /> +
+
+
+{/if} + columns.updateSortable(e.detail)} + on:itemChange={e => columns.update(e.detail)} + items={columns.sortable} + listItemKey={"_id"} + listType={FieldSetting} +/> + + diff --git a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/PrimaryColumnFieldSetting.svelte b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/PrimaryColumnFieldSetting.svelte new file mode 100644 index 0000000000..1cb29ac6e7 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/PrimaryColumnFieldSetting.svelte @@ -0,0 +1,100 @@ + + +
+
+ +
+ + {item.field} +
+
+
{item.label || item.field}
+
+
+ +
+
+ + diff --git a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.js b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.js new file mode 100644 index 0000000000..72fdbe4108 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.js @@ -0,0 +1,129 @@ +const modernize = columns => { + if (!columns) { + return [] + } + // If the first element has no active key then it's safe to assume all elements are in the old format + if (columns?.[0] && columns[0].active === undefined) { + return columns.map(column => ({ + label: column.displayName, + field: column.name, + active: true, + })) + } + + return columns +} + +const removeInvalidAddMissing = ( + columns = [], + defaultColumns, + primaryDisplayColumnName +) => { + const defaultColumnNames = defaultColumns.map(column => column.field) + const columnNames = columns.map(column => column.field) + + const validColumns = columns.filter(column => + defaultColumnNames.includes(column.field) + ) + let missingColumns = defaultColumns.filter( + defaultColumn => !columnNames.includes(defaultColumn.field) + ) + + // If the user already has fields selected, any appended missing fields should be disabled by default + if (validColumns.length) { + missingColumns = missingColumns.map(field => ({ ...field, active: false })) + } + + const combinedColumns = [...validColumns, ...missingColumns] + + // Ensure the primary display column is always visible + const primaryDisplayIndex = combinedColumns.findIndex( + column => column.field === primaryDisplayColumnName + ) + if (primaryDisplayIndex > -1) { + combinedColumns[primaryDisplayIndex].active = true + } + + return combinedColumns +} + +const getDefault = (schema = {}) => { + const defaultValues = Object.values(schema) + .filter(column => !column.nestedJSON) + .map(column => ({ + label: column.name, + field: column.name, + active: column.visible ?? true, + order: column.visible ? column.order ?? -1 : Number.MAX_SAFE_INTEGER, + })) + + defaultValues.sort((a, b) => a.order - b.order) + + return defaultValues +} + +const toGridFormat = draggableListColumns => { + return draggableListColumns.map(entry => ({ + label: entry.label, + field: entry.field, + active: entry.active, + })) +} + +const toDraggableListFormat = (gridFormatColumns, createComponent, schema) => { + return gridFormatColumns.map(column => { + return createComponent( + "@budibase/standard-components/labelfield", + { + _instanceName: column.field, + active: column.active, + field: column.field, + label: column.label, + columnType: schema[column.field].type, + }, + {} + ) + }) +} + +const getColumns = ({ + columns, + schema, + primaryDisplayColumnName, + onChange, + createComponent, +}) => { + const validatedColumns = removeInvalidAddMissing( + modernize(columns), + getDefault(schema), + primaryDisplayColumnName + ) + const draggableList = toDraggableListFormat( + validatedColumns, + createComponent, + schema + ) + const primary = draggableList.find( + entry => entry.field === primaryDisplayColumnName + ) + const sortable = draggableList.filter( + entry => entry.field !== primaryDisplayColumnName + ) + + return { + primary, + sortable, + updateSortable: newDraggableList => { + onChange(toGridFormat(newDraggableList.concat(primary))) + }, + update: newEntry => { + const newDraggableList = draggableList.map(entry => { + return newEntry.field === entry.field ? newEntry : entry + }) + + onChange(toGridFormat(newDraggableList)) + }, + } +} + +export default getColumns diff --git a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.test.js b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.test.js new file mode 100644 index 0000000000..d7092a2c52 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/getColumns.test.js @@ -0,0 +1,374 @@ +import { it, expect, describe, beforeEach, vi } from "vitest" +import getColumns from "./getColumns" + +describe("getColumns", () => { + beforeEach(ctx => { + ctx.schema = { + one: { name: "one", visible: false, order: 0, type: "foo" }, + two: { name: "two", visible: true, order: 1, type: "foo" }, + three: { name: "three", visible: true, order: 2, type: "foo" }, + four: { name: "four", visible: false, order: 3, type: "foo" }, + five: { + name: "excluded", + visible: true, + order: 4, + type: "foo", + nestedJSON: true, + }, + } + + ctx.primaryDisplayColumnName = "four" + ctx.onChange = vi.fn() + ctx.createComponent = (componentName, props) => { + return { componentName, ...props } + } + }) + + describe("nested json fields", () => { + beforeEach(ctx => { + ctx.columns = getColumns({ + columns: null, + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + }) + + it("does not return nested json fields, as the grid cannot display them", ctx => { + expect(ctx.columns.sortable).not.toContainEqual({ + name: "excluded", + visible: true, + order: 4, + type: "foo", + nestedJSON: true, + }) + }) + }) + + describe("using the old grid column format", () => { + beforeEach(ctx => { + const oldGridFormatColumns = [ + { displayName: "three label", name: "three" }, + { displayName: "two label", name: "two" }, + ] + + ctx.columns = getColumns({ + columns: oldGridFormatColumns, + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + }) + + it("returns the selected and unselected fields in the modern format, respecting the original order", ctx => { + expect(ctx.columns.sortable).toEqual([ + { + _instanceName: "three", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "three", + label: "three label", + }, + { + _instanceName: "two", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "two", + label: "two label", + }, + { + _instanceName: "one", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "one", + label: "one", + }, + ]) + + expect(ctx.columns.primary).toEqual({ + _instanceName: "four", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "four", + label: "four", + }) + }) + }) + + describe("default columns", () => { + beforeEach(ctx => { + ctx.columns = getColumns({ + columns: undefined, + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + }) + + it("returns all columns, with non-hidden columns automatically selected", ctx => { + expect(ctx.columns.sortable).toEqual([ + { + _instanceName: "two", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "two", + label: "two", + }, + { + _instanceName: "three", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "three", + label: "three", + }, + { + _instanceName: "one", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "one", + label: "one", + }, + ]) + + expect(ctx.columns.primary).toEqual({ + _instanceName: "four", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "four", + label: "four", + }) + }) + + it("Unselected columns should be placed at the end", ctx => { + expect(ctx.columns.sortable[2].field).toEqual("one") + }) + }) + + describe("missing columns", () => { + beforeEach(ctx => { + const gridFormatColumns = [ + { label: "three label", field: "three", active: true }, + ] + + ctx.columns = getColumns({ + columns: gridFormatColumns, + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + }) + + it("returns all columns, including those missing from the initial data", ctx => { + expect(ctx.columns.sortable).toEqual([ + { + _instanceName: "three", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "three", + label: "three label", + }, + { + _instanceName: "two", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "two", + label: "two", + }, + { + _instanceName: "one", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "one", + label: "one", + }, + ]) + + expect(ctx.columns.primary).toEqual({ + _instanceName: "four", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "four", + label: "four", + }) + }) + }) + + describe("invalid columns", () => { + beforeEach(ctx => { + const gridFormatColumns = [ + { label: "three label", field: "three", active: true }, + { label: "some nonsense", field: "some nonsense", active: true }, + ] + + ctx.columns = getColumns({ + columns: gridFormatColumns, + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + }) + + it("returns all valid columns, excluding those that aren't valid for the schema", ctx => { + expect(ctx.columns.sortable).toEqual([ + { + _instanceName: "three", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "three", + label: "three label", + }, + { + _instanceName: "two", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "two", + label: "two", + }, + { + _instanceName: "one", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "one", + label: "one", + }, + ]) + + expect(ctx.columns.primary).toEqual({ + _instanceName: "four", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "four", + label: "four", + }) + }) + }) + + describe("methods", () => { + beforeEach(ctx => { + const { update, updateSortable } = getColumns({ + columns: [], + schema: ctx.schema, + primaryDisplayColumnName: ctx.primaryDisplayColumnName, + onChange: ctx.onChange, + createComponent: ctx.createComponent, + }) + + ctx.update = update + ctx.updateSortable = updateSortable + }) + + describe("update", () => { + beforeEach(ctx => { + ctx.update({ + field: "one", + label: "a new label", + active: true, + }) + }) + + it("calls the callback with the updated columns", ctx => { + expect(ctx.onChange).toHaveBeenCalledTimes(1) + expect(ctx.onChange).toHaveBeenCalledWith([ + { + field: "two", + label: "two", + active: true, + }, + { + field: "three", + label: "three", + active: true, + }, + { + field: "one", + label: "a new label", + active: true, + }, + { + field: "four", + label: "four", + active: true, + }, + ]) + }) + }) + + describe("updateSortable", () => { + beforeEach(ctx => { + ctx.updateSortable([ + { + _instanceName: "three", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "three", + label: "three", + }, + { + _instanceName: "one", + active: true, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "one", + label: "one", + }, + { + _instanceName: "two", + active: false, + columnType: "foo", + componentName: "@budibase/standard-components/labelfield", + field: "two", + label: "two", + }, + ]) + }) + + it("calls the callback with the updated columns", ctx => { + expect(ctx.onChange).toHaveBeenCalledTimes(1) + expect(ctx.onChange).toHaveBeenCalledWith([ + { + field: "three", + label: "three", + active: true, + }, + { + field: "one", + label: "one", + active: true, + }, + { + field: "two", + label: "two", + active: false, + }, + { + field: "four", + label: "four", + active: true, + }, + ]) + }) + }) + }) +}) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 07645d874a..c7a207fc28 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2698,6 +2698,22 @@ } ] }, + "labelfield": { + "name": "Text Field", + "icon": "Text", + "editable": true, + "size": { + "width": 400, + "height": 32 + }, + "settings": [ + { + "type": "plainText", + "label": "Label", + "key": "label" + } + ] + }, "stringfield": { "name": "Text Field", "icon": "Text", @@ -6308,19 +6324,6 @@ "key": "table", "required": true }, - { - "type": "columns/grid", - "label": "Columns", - "key": "columns", - "dependsOn": [ - "table", - { - "setting": "table.type", - "value": "custom", - "invert": true - } - ] - }, { "type": "filter", "label": "Filtering", @@ -6417,6 +6420,18 @@ "key": "stripeRows", "defaultValue": false }, + { + "section": true, + "name": "Columns", + "settings": [ + { + "type": "columns/grid", + "key": "columns", + "nested": true, + "resetOn": "table" + } + ] + }, { "section": true, "name": "Buttons", diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 0b1c12524a..30040bfe9c 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -19,6 +19,22 @@ export let onRowClick = null export let buttons = null + // parses columns to fix older formats + const getParsedColumns = columns => { + // If the first element has an active key all elements should be in the new format + if (columns?.length && columns[0]?.active !== undefined) { + return columns + } + + return columns?.map(column => ({ + label: column.displayName || column.name, + field: column.name, + active: true, + })) + } + + $: parsedColumns = getParsedColumns(columns) + const context = getContext("context") const component = getContext("component") const { @@ -33,16 +49,17 @@ let grid - $: columnWhitelist = columns?.map(col => col.name) - $: schemaOverrides = getSchemaOverrides(columns) + $: columnWhitelist = parsedColumns + ?.filter(col => col.active) + ?.map(col => col.field) + $: schemaOverrides = getSchemaOverrides(parsedColumns) $: enrichedButtons = enrichButtons(buttons) const getSchemaOverrides = columns => { let overrides = {} columns?.forEach(column => { - overrides[column.name] = { - displayName: column.displayName || column.name, - visible: true, + overrides[column.field] = { + displayName: column.label, } }) return overrides diff --git a/packages/frontend-core/src/components/grid/stores/datasource.js b/packages/frontend-core/src/components/grid/stores/datasource.js index 7ee3a19b8a..7b95fe7430 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.js +++ b/packages/frontend-core/src/components/grid/stores/datasource.js @@ -55,11 +55,20 @@ export const deriveStores = context => { // Apply whitelist if specified if ($columnWhitelist?.length) { - Object.keys(enrichedSchema).forEach(key => { - if (!$columnWhitelist.includes(key)) { - delete enrichedSchema[key] + const sortedColumns = {} + + $columnWhitelist.forEach((columnKey, idx) => { + const enrichedColumn = enrichedSchema[columnKey] + if (enrichedColumn) { + sortedColumns[columnKey] = { + ...enrichedColumn, + order: idx, + visible: true, + } } }) + + return sortedColumns } return enrichedSchema From 3cdb1da6d8c8d37d8e1e93267ce797b410bf87dd Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Nov 2023 12:57:09 +0100 Subject: [PATCH 17/42] Update tsconfig --- packages/server/tsconfig.build.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/tsconfig.build.json b/packages/server/tsconfig.build.json index 4e509bd14e..7e0aba1adf 100644 --- a/packages/server/tsconfig.build.json +++ b/packages/server/tsconfig.build.json @@ -17,7 +17,8 @@ "@budibase/backend-core": ["../backend-core/src"], "@budibase/backend-core/*": ["../backend-core/*"], "@budibase/shared-core": ["../shared-core/src"], - "@budibase/pro": ["../pro/src"] + "@budibase/pro": ["../pro/src"], + "@budibase/string-templates": ["../string-templates/src"] } }, "include": ["src/**/*"], From 813511da2872e34ce98366d37c84df0ab2e26437 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Nov 2023 12:59:07 +0100 Subject: [PATCH 18/42] Remove v2 from sh script --- .../{updateWorkspaceVersions.V2.sh => updateWorkspaceVersions.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/{updateWorkspaceVersions.V2.sh => updateWorkspaceVersions.sh} (100%) diff --git a/scripts/updateWorkspaceVersions.V2.sh b/scripts/updateWorkspaceVersions.sh similarity index 100% rename from scripts/updateWorkspaceVersions.V2.sh rename to scripts/updateWorkspaceVersions.sh From 9c221afc595b695a8a8df39fdd7c8318715c8799 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Nov 2023 13:02:14 +0100 Subject: [PATCH 19/42] Rename Dockerfile.v2 to Dockerfile --- hosting/single/Dockerfile | 113 ++++++++++++++++------------- hosting/single/Dockerfile.v2 | 131 ---------------------------------- packages/server/Dockerfile | 44 +++++++++--- packages/server/Dockerfile.v2 | 84 ---------------------- packages/worker/Dockerfile | 35 +++++++-- packages/worker/Dockerfile.v2 | 58 --------------- 6 files changed, 126 insertions(+), 339 deletions(-) delete mode 100644 hosting/single/Dockerfile.v2 delete mode 100644 packages/server/Dockerfile.v2 delete mode 100644 packages/worker/Dockerfile.v2 diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile index c7b90dbdc4..ec03a1b5a2 100644 --- a/hosting/single/Dockerfile +++ b/hosting/single/Dockerfile @@ -1,44 +1,59 @@ FROM node:18-slim as build # install node-gyp dependencies -RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends apt-utils cron g++ make python3 +RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq -# add pin script -WORKDIR / -ADD scripts/cleanup.sh ./ -RUN chmod +x /cleanup.sh -# build server +# copy and install dependencies WORKDIR /app -ADD packages/server . +COPY package.json . COPY yarn.lock . -RUN yarn install --production=true --network-timeout 1000000 -RUN /cleanup.sh +COPY lerna.json . +COPY .yarnrc . -# build worker -WORKDIR /worker -ADD packages/worker . -COPY yarn.lock . -RUN yarn install --production=true --network-timeout 1000000 -RUN /cleanup.sh +COPY packages/server/package.json packages/server/package.json +COPY packages/worker/package.json packages/worker/package.json +# string-templates does not get bundled during the esbuild process, so we want to use the local version +COPY packages/string-templates/package.json packages/string-templates/package.json -FROM budibase/couchdb + +COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh +RUN chmod +x ./scripts/removeWorkspaceDependencies.sh +RUN ./scripts/removeWorkspaceDependencies.sh packages/server/package.json +RUN ./scripts/removeWorkspaceDependencies.sh packages/worker/package.json + + +# We will never want to sync pro, but the script is still required +RUN echo '' > scripts/syncProPackage.js +RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json +RUN ./scripts/removeWorkspaceDependencies.sh package.json +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production + +# copy the actual code +COPY packages/server/dist packages/server/dist +COPY packages/server/pm2.config.js packages/server/pm2.config.js +COPY packages/server/client packages/server/client +COPY packages/server/builder packages/server/builder +COPY packages/worker/dist packages/worker/dist +COPY packages/worker/pm2.config.js packages/worker/pm2.config.js +COPY packages/string-templates packages/string-templates + + +FROM budibase/couchdb as runner ARG TARGETARCH ENV TARGETARCH $TARGETARCH +ENV NODE_MAJOR 18 #TARGETBUILD can be set to single (for single docker image) or aas (for azure app service) # e.g. docker build --build-arg TARGETBUILD=aas .... ARG TARGETBUILD=single ENV TARGETBUILD $TARGETBUILD -COPY --from=build /app /app -COPY --from=build /worker /worker - # install base dependencies RUN apt-get update && \ - apt-get install -y --no-install-recommends software-properties-common nginx uuid-runtime redis-server + apt-get install -y --no-install-recommends software-properties-common nginx uuid-runtime redis-server libaio1 # Install postgres client for pg_dump utils -RUN apt install software-properties-common apt-transport-https gpg -y \ +RUN apt install -y software-properties-common apt-transport-https ca-certificates gnupg \ && curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \ && echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \ && apt update -y \ @@ -47,14 +62,12 @@ RUN apt install software-properties-common apt-transport-https gpg -y \ # install other dependencies, nodejs, oracle requirements, jdk8, redis, nginx WORKDIR /nodejs -RUN curl -sL https://deb.nodesource.com/setup_16.x -o /tmp/nodesource_setup.sh && \ - bash /tmp/nodesource_setup.sh && \ - apt-get install -y --no-install-recommends libaio1 nodejs && \ - npm install --global yarn pm2 +COPY scripts/install-node.sh ./install.sh +RUN chmod +x install.sh && ./install.sh # setup nginx -ADD hosting/single/nginx/nginx.conf /etc/nginx -ADD hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default +COPY hosting/single/nginx/nginx.conf /etc/nginx +COPY hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default RUN mkdir -p /var/log/nginx && \ touch /var/log/nginx/error.log && \ touch /var/run/nginx.pid && \ @@ -62,29 +75,41 @@ RUN mkdir -p /var/log/nginx && \ WORKDIR / RUN mkdir -p scripts/integrations/oracle -ADD packages/server/scripts/integrations/oracle scripts/integrations/oracle +COPY packages/server/scripts/integrations/oracle scripts/integrations/oracle RUN /bin/bash -e ./scripts/integrations/oracle/instantclient/linux/install.sh # setup minio WORKDIR /minio -ADD scripts/install-minio.sh ./install.sh +COPY scripts/install-minio.sh ./install.sh RUN chmod +x install.sh && ./install.sh # setup runner file WORKDIR / -ADD hosting/single/runner.sh . +COPY hosting/single/runner.sh . RUN chmod +x ./runner.sh -ADD hosting/single/healthcheck.sh . +COPY hosting/single/healthcheck.sh . RUN chmod +x ./healthcheck.sh # Script below sets the path for storing data based on $DATA_DIR # For Azure App Service install SSH & point data locations to /home -ADD hosting/single/ssh/sshd_config /etc/ -ADD hosting/single/ssh/ssh_setup.sh /tmp +COPY hosting/single/ssh/sshd_config /etc/ +COPY hosting/single/ssh/ssh_setup.sh /tmp RUN /build-target-paths.sh -# cleanup cache -RUN yarn cache clean -f + +# setup letsencrypt certificate +RUN apt-get install -y certbot python3-certbot-nginx +COPY hosting/letsencrypt /app/letsencrypt +RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh + +COPY --from=build /app/node_modules /node_modules +COPY --from=build /app/package.json /package.json +COPY --from=build /app/packages/server /app +COPY --from=build /app/packages/worker /worker +COPY --from=build /app/packages/string-templates /string-templates + +RUN cd /string-templates && yarn link && cd ../app && yarn link @budibase/string-templates && cd ../worker && yarn link @budibase/string-templates + EXPOSE 80 EXPOSE 443 @@ -92,20 +117,10 @@ EXPOSE 443 EXPOSE 2222 VOLUME /data -# setup letsencrypt certificate -RUN apt-get install -y certbot python3-certbot-nginx -ADD hosting/letsencrypt /app/letsencrypt -RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh -# Remove cached files -RUN rm -rf \ - /root/.cache \ - /root/.npm \ - /root/.pip \ - /usr/local/share/doc \ - /usr/share/doc \ - /usr/share/man \ - /var/lib/apt/lists/* \ - /tmp/* +ARG BUDIBASE_VERSION +# Ensuring the version argument is sent +RUN test -n "$BUDIBASE_VERSION" +ENV BUDIBASE_VERSION=$BUDIBASE_VERSION HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh" diff --git a/hosting/single/Dockerfile.v2 b/hosting/single/Dockerfile.v2 deleted file mode 100644 index ec03a1b5a2..0000000000 --- a/hosting/single/Dockerfile.v2 +++ /dev/null @@ -1,131 +0,0 @@ -FROM node:18-slim as build - -# install node-gyp dependencies -RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq - - -# copy and install dependencies -WORKDIR /app -COPY package.json . -COPY yarn.lock . -COPY lerna.json . -COPY .yarnrc . - -COPY packages/server/package.json packages/server/package.json -COPY packages/worker/package.json packages/worker/package.json -# string-templates does not get bundled during the esbuild process, so we want to use the local version -COPY packages/string-templates/package.json packages/string-templates/package.json - - -COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh -RUN chmod +x ./scripts/removeWorkspaceDependencies.sh -RUN ./scripts/removeWorkspaceDependencies.sh packages/server/package.json -RUN ./scripts/removeWorkspaceDependencies.sh packages/worker/package.json - - -# We will never want to sync pro, but the script is still required -RUN echo '' > scripts/syncProPackage.js -RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json -RUN ./scripts/removeWorkspaceDependencies.sh package.json -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production - -# copy the actual code -COPY packages/server/dist packages/server/dist -COPY packages/server/pm2.config.js packages/server/pm2.config.js -COPY packages/server/client packages/server/client -COPY packages/server/builder packages/server/builder -COPY packages/worker/dist packages/worker/dist -COPY packages/worker/pm2.config.js packages/worker/pm2.config.js -COPY packages/string-templates packages/string-templates - - -FROM budibase/couchdb as runner -ARG TARGETARCH -ENV TARGETARCH $TARGETARCH -ENV NODE_MAJOR 18 -#TARGETBUILD can be set to single (for single docker image) or aas (for azure app service) -# e.g. docker build --build-arg TARGETBUILD=aas .... -ARG TARGETBUILD=single -ENV TARGETBUILD $TARGETBUILD - -# install base dependencies -RUN apt-get update && \ - apt-get install -y --no-install-recommends software-properties-common nginx uuid-runtime redis-server libaio1 - -# Install postgres client for pg_dump utils -RUN apt install -y software-properties-common apt-transport-https ca-certificates gnupg \ - && curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \ - && echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \ - && apt update -y \ - && apt install postgresql-client-15 -y \ - && apt remove software-properties-common apt-transport-https gpg -y - -# install other dependencies, nodejs, oracle requirements, jdk8, redis, nginx -WORKDIR /nodejs -COPY scripts/install-node.sh ./install.sh -RUN chmod +x install.sh && ./install.sh - -# setup nginx -COPY hosting/single/nginx/nginx.conf /etc/nginx -COPY hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default -RUN mkdir -p /var/log/nginx && \ - touch /var/log/nginx/error.log && \ - touch /var/run/nginx.pid && \ - usermod -a -G tty www-data - -WORKDIR / -RUN mkdir -p scripts/integrations/oracle -COPY packages/server/scripts/integrations/oracle scripts/integrations/oracle -RUN /bin/bash -e ./scripts/integrations/oracle/instantclient/linux/install.sh - -# setup minio -WORKDIR /minio -COPY scripts/install-minio.sh ./install.sh -RUN chmod +x install.sh && ./install.sh - -# setup runner file -WORKDIR / -COPY hosting/single/runner.sh . -RUN chmod +x ./runner.sh -COPY hosting/single/healthcheck.sh . -RUN chmod +x ./healthcheck.sh - -# Script below sets the path for storing data based on $DATA_DIR -# For Azure App Service install SSH & point data locations to /home -COPY hosting/single/ssh/sshd_config /etc/ -COPY hosting/single/ssh/ssh_setup.sh /tmp -RUN /build-target-paths.sh - - -# setup letsencrypt certificate -RUN apt-get install -y certbot python3-certbot-nginx -COPY hosting/letsencrypt /app/letsencrypt -RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh - -COPY --from=build /app/node_modules /node_modules -COPY --from=build /app/package.json /package.json -COPY --from=build /app/packages/server /app -COPY --from=build /app/packages/worker /worker -COPY --from=build /app/packages/string-templates /string-templates - -RUN cd /string-templates && yarn link && cd ../app && yarn link @budibase/string-templates && cd ../worker && yarn link @budibase/string-templates - - -EXPOSE 80 -EXPOSE 443 -# Expose port 2222 for SSH on Azure App Service build -EXPOSE 2222 -VOLUME /data - -ARG BUDIBASE_VERSION -# Ensuring the version argument is sent -RUN test -n "$BUDIBASE_VERSION" -ENV BUDIBASE_VERSION=$BUDIBASE_VERSION - -HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh" - -# must set this just before running -ENV NODE_ENV=production -WORKDIR / - -CMD ["./runner.sh"] diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index ea4c5b217a..f737570fcd 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -18,12 +18,12 @@ ENV TOP_LEVEL_PATH=/ # handle node-gyp RUN apt-get update \ - && apt-get install -y --no-install-recommends g++ make python3 + && apt-get install -y --no-install-recommends g++ make python3 jq RUN yarn global add pm2 # Install client for oracle datasource RUN apt-get install unzip libaio1 -COPY scripts/integrations/oracle/ scripts/integrations/oracle/ +COPY packages/server/scripts/integrations/oracle/ scripts/integrations/oracle/ RUN /bin/bash -e scripts/integrations/oracle/instantclient/linux/x86-64/install.sh # Install postgres client for pg_dump utils @@ -35,18 +35,42 @@ RUN apt update && apt upgrade -y \ && apt install postgresql-client-15 -y \ && apt remove software-properties-common apt-transport-https curl gpg -y +WORKDIR / -COPY package.json . -COPY dist/yarn.lock . -RUN yarn install --production=true --network-timeout 1000000 \ +COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh +RUN chmod +x ./scripts/removeWorkspaceDependencies.sh + + +WORKDIR /string-templates +COPY packages/string-templates/package.json package.json +RUN ../scripts/removeWorkspaceDependencies.sh package.json +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 +COPY packages/string-templates . + + +WORKDIR /app +COPY packages/server/package.json . +COPY packages/server/dist/yarn.lock . +RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates + +COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh +RUN chmod +x ./scripts/removeWorkspaceDependencies.sh +RUN ./scripts/removeWorkspaceDependencies.sh package.json + +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 \ # Remove unneeded data from file system to reduce image size - && yarn cache clean && apt-get remove -y --purge --auto-remove g++ make python \ + && yarn cache clean && apt-get remove -y --purge --auto-remove g++ make python jq \ && rm -rf /tmp/* /root/.node-gyp /usr/local/lib/node_modules/npm/node_modules/node-gyp -COPY dist/ dist/ -COPY docker_run.sh . -COPY builder/ builder/ -COPY client/ client/ +COPY packages/server/dist/ dist/ +COPY packages/server/docker_run.sh . +COPY packages/server/builder/ builder/ +COPY packages/server/client/ client/ + +ARG BUDIBASE_VERSION +# Ensuring the version argument is sent +RUN test -n "$BUDIBASE_VERSION" +ENV BUDIBASE_VERSION=$BUDIBASE_VERSION EXPOSE 4001 diff --git a/packages/server/Dockerfile.v2 b/packages/server/Dockerfile.v2 deleted file mode 100644 index f737570fcd..0000000000 --- a/packages/server/Dockerfile.v2 +++ /dev/null @@ -1,84 +0,0 @@ -FROM node:18-slim - -LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.post-update="scripts/watchtower-hooks/post-update.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.post-check="scripts/watchtower-hooks/post-check.sh" - -WORKDIR /app - -ENV PORT=4001 -ENV COUCH_DB_URL=https://couchdb.budi.live:5984 -ENV BUDIBASE_ENVIRONMENT=PRODUCTION -ENV SERVICE=app-service -ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU -ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR -ENV ACCOUNT_PORTAL_URL=https://account.budibase.app -ENV TOP_LEVEL_PATH=/ - -# handle node-gyp -RUN apt-get update \ - && apt-get install -y --no-install-recommends g++ make python3 jq -RUN yarn global add pm2 - -# Install client for oracle datasource -RUN apt-get install unzip libaio1 -COPY packages/server/scripts/integrations/oracle/ scripts/integrations/oracle/ -RUN /bin/bash -e scripts/integrations/oracle/instantclient/linux/x86-64/install.sh - -# Install postgres client for pg_dump utils -RUN apt update && apt upgrade -y \ - && apt install software-properties-common apt-transport-https curl gpg -y \ - && curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \ - && echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \ - && apt update -y \ - && apt install postgresql-client-15 -y \ - && apt remove software-properties-common apt-transport-https curl gpg -y - -WORKDIR / - -COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh -RUN chmod +x ./scripts/removeWorkspaceDependencies.sh - - -WORKDIR /string-templates -COPY packages/string-templates/package.json package.json -RUN ../scripts/removeWorkspaceDependencies.sh package.json -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 -COPY packages/string-templates . - - -WORKDIR /app -COPY packages/server/package.json . -COPY packages/server/dist/yarn.lock . -RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates - -COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh -RUN chmod +x ./scripts/removeWorkspaceDependencies.sh -RUN ./scripts/removeWorkspaceDependencies.sh package.json - -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 \ - # Remove unneeded data from file system to reduce image size - && yarn cache clean && apt-get remove -y --purge --auto-remove g++ make python jq \ - && rm -rf /tmp/* /root/.node-gyp /usr/local/lib/node_modules/npm/node_modules/node-gyp - -COPY packages/server/dist/ dist/ -COPY packages/server/docker_run.sh . -COPY packages/server/builder/ builder/ -COPY packages/server/client/ client/ - -ARG BUDIBASE_VERSION -# Ensuring the version argument is sent -RUN test -n "$BUDIBASE_VERSION" -ENV BUDIBASE_VERSION=$BUDIBASE_VERSION - -EXPOSE 4001 - -# have to add node environment production after install -# due to this causing yarn to stop installing dev dependencies -# which are actually needed to get this environment up and running -ENV NODE_ENV=production -ENV CLUSTER_MODE=${CLUSTER_MODE} -ENV TOP_LEVEL_PATH=/app - -CMD ["./docker_run.sh"] diff --git a/packages/worker/Dockerfile b/packages/worker/Dockerfile index 50f1bb78b9..4706ca155a 100644 --- a/packages/worker/Dockerfile +++ b/packages/worker/Dockerfile @@ -5,22 +5,38 @@ LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-ho LABEL com.centurylinklabs.watchtower.lifecycle.post-update="scripts/watchtower-hooks/post-update.sh" LABEL com.centurylinklabs.watchtower.lifecycle.post-check="scripts/watchtower-hooks/post-check.sh" -WORKDIR /app # handle node-gyp -RUN apk add --no-cache --virtual .gyp python3 make g++ +RUN apk add --no-cache --virtual .gyp python3 make g++ jq RUN yarn global add pm2 +WORKDIR / -COPY package.json . -COPY dist/yarn.lock . -RUN yarn install --production=true --network-timeout 1000000 +COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh +RUN chmod +x ./scripts/removeWorkspaceDependencies.sh + + +WORKDIR /string-templates +COPY packages/string-templates/package.json package.json +RUN ../scripts/removeWorkspaceDependencies.sh package.json +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 +COPY packages/string-templates . + + +WORKDIR /app +COPY packages/worker/package.json . +COPY packages/worker/dist/yarn.lock . +RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates + +RUN ../scripts/removeWorkspaceDependencies.sh package.json + +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 # Remove unneeded data from file system to reduce image size RUN apk del .gyp \ && yarn cache clean -COPY dist/ dist/ -COPY docker_run.sh . +COPY packages/worker/dist/ dist/ +COPY packages/worker/docker_run.sh . EXPOSE 4001 @@ -34,4 +50,9 @@ ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR ENV ACCOUNT_PORTAL_URL=https://account.budibase.app +ARG BUDIBASE_VERSION +# Ensuring the version argument is sent +RUN test -n "$BUDIBASE_VERSION" +ENV BUDIBASE_VERSION=$BUDIBASE_VERSION + CMD ["./docker_run.sh"] diff --git a/packages/worker/Dockerfile.v2 b/packages/worker/Dockerfile.v2 deleted file mode 100644 index 4706ca155a..0000000000 --- a/packages/worker/Dockerfile.v2 +++ /dev/null @@ -1,58 +0,0 @@ -FROM node:18-alpine - -LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="scripts/watchtower-hooks/pre-check.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="scripts/watchtower-hooks/pre-update.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.post-update="scripts/watchtower-hooks/post-update.sh" -LABEL com.centurylinklabs.watchtower.lifecycle.post-check="scripts/watchtower-hooks/post-check.sh" - - -# handle node-gyp -RUN apk add --no-cache --virtual .gyp python3 make g++ jq -RUN yarn global add pm2 - -WORKDIR / - -COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh -RUN chmod +x ./scripts/removeWorkspaceDependencies.sh - - -WORKDIR /string-templates -COPY packages/string-templates/package.json package.json -RUN ../scripts/removeWorkspaceDependencies.sh package.json -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 -COPY packages/string-templates . - - -WORKDIR /app -COPY packages/worker/package.json . -COPY packages/worker/dist/yarn.lock . -RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates - -RUN ../scripts/removeWorkspaceDependencies.sh package.json - -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 -# Remove unneeded data from file system to reduce image size -RUN apk del .gyp \ - && yarn cache clean - -COPY packages/worker/dist/ dist/ -COPY packages/worker/docker_run.sh . - -EXPOSE 4001 - -# have to add node environment production after install -# due to this causing yarn to stop installing dev dependencies -# which are actually needed to get this environment up and running -ENV NODE_ENV=production -ENV CLUSTER_MODE=${CLUSTER_MODE} -ENV SERVICE=worker-service -ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU -ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR -ENV ACCOUNT_PORTAL_URL=https://account.budibase.app - -ARG BUDIBASE_VERSION -# Ensuring the version argument is sent -RUN test -n "$BUDIBASE_VERSION" -ENV BUDIBASE_VERSION=$BUDIBASE_VERSION - -CMD ["./docker_run.sh"] From 4a1fd20f08917f8ed6d1e9dd0163b1b311a51060 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Nov 2023 13:04:23 +0100 Subject: [PATCH 20/42] Renames --- hosting/docker-compose.build.yaml | 4 ++-- scripts/build-single-image.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hosting/docker-compose.build.yaml b/hosting/docker-compose.build.yaml index 7ead001a1c..dbc3613599 100644 --- a/hosting/docker-compose.build.yaml +++ b/hosting/docker-compose.build.yaml @@ -6,7 +6,7 @@ services: app-service: build: context: .. - dockerfile: packages/server/Dockerfile.v2 + dockerfile: packages/server/Dockerfile args: - BUDIBASE_VERSION=0.0.0+dev-docker container_name: build-bbapps @@ -36,7 +36,7 @@ services: worker-service: build: context: .. - dockerfile: packages/worker/Dockerfile.v2 + dockerfile: packages/worker/Dockerfile args: - BUDIBASE_VERSION=0.0.0+dev-docker container_name: build-bbworker diff --git a/scripts/build-single-image.sh b/scripts/build-single-image.sh index ed3d9a8ed6..ba64d6121b 100755 --- a/scripts/build-single-image.sh +++ b/scripts/build-single-image.sh @@ -1,4 +1,4 @@ #!/bin/bash yarn build --scope @budibase/server --scope @budibase/worker version=$(./scripts/getCurrentVersion.sh) -docker build -f hosting/single/Dockerfile.v2 -t budibase:latest --build-arg BUDIBASE_VERSION=$version . +docker build -f hosting/single/Dockerfile -t budibase:latest --build-arg BUDIBASE_VERSION=$version . From c4de70c77c3d680715622a262d95cae0532ae7d1 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 12:24:14 +0000 Subject: [PATCH 21/42] Update builder side panel to use new copy for roles --- .../src/components/common/RoleSelect.svelte | 90 +++++++++++-------- .../_components/BuilderSidePanel.svelte | 34 +++---- 2 files changed, 67 insertions(+), 57 deletions(-) diff --git a/packages/builder/src/components/common/RoleSelect.svelte b/packages/builder/src/components/common/RoleSelect.svelte index 2df61926e1..1158107fd6 100644 --- a/packages/builder/src/components/common/RoleSelect.svelte +++ b/packages/builder/src/components/common/RoleSelect.svelte @@ -20,73 +20,91 @@ export let allowedRoles = null export let allowCreator = false export let fancySelect = false + export let labelPrefix = null const dispatch = createEventDispatcher() const RemoveID = "remove" + $: enrichLabel = label => (labelPrefix ? `${labelPrefix} ${label}` : label) $: options = getOptions( $roles, allowPublic, allowRemove, allowedRoles, - allowCreator + allowCreator, + enrichLabel ) + const getOptions = ( roles, allowPublic, allowRemove, allowedRoles, - allowCreator + allowCreator, + enrichLabel ) => { + // Use roles whitelist if specified if (allowedRoles?.length) { - const filteredRoles = roles.filter(role => - allowedRoles.includes(role._id) - ) - return [ - ...filteredRoles, - ...(allowedRoles.includes(Constants.Roles.CREATOR) - ? [{ _id: Constants.Roles.CREATOR, name: "Creator", enabled: false }] - : []), - ] - } - let newRoles = [...roles] - - if (allowCreator) { - newRoles = [ - { + let options = roles + .filter(role => allowedRoles.includes(role._id)) + .map(role => ({ + name: enrichLabel(role.name), + _id: role._id, + })) + if (allowedRoles.includes(Constants.Roles.CREATOR)) { + options.push({ _id: Constants.Roles.CREATOR, - name: "Creator", - tag: - !$licensing.perAppBuildersEnabled && - capitalise(Constants.PlanType.BUSINESS), - }, - ...newRoles, - ] + name: "Can edit", + enabled: false, + }) + } + return options } + + // Allow all core roles + let options = roles.map(role => ({ + name: enrichLabel(role.name), + _id: role._id, + })) + + // Add creator if required + if (allowCreator) { + options.unshift({ + _id: Constants.Roles.CREATOR, + name: "Can edit", + tag: + !$licensing.perAppBuildersEnabled && + capitalise(Constants.PlanType.BUSINESS), + }) + } + + // Add remove option if required if (allowRemove) { - newRoles = [ - ...newRoles, - { - _id: RemoveID, - name: "Remove", - }, - ] + options.push({ + _id: RemoveID, + name: "Remove", + }) } - if (allowPublic) { - return newRoles + + // Remove public if not allowed + if (!allowPublic) { + options = options.filter(role => role._id !== Constants.Roles.PUBLIC) } - return newRoles.filter(role => role._id !== Constants.Roles.PUBLIC) + + return options } const getColor = role => { - if (allowRemove && role._id === RemoveID) { + // Creator and remove options have no colors + if (role._id === Constants.Roles.CREATOR || role._id === RemoveID) { return null } return RoleUtils.getRoleColour(role._id) } const getIcon = role => { - if (allowRemove && role._id === RemoveID) { + // Only remove option has an icon + if (role._id === RemoveID) { return "Close" } return null diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 6f3979e3ad..adb0c985dc 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -471,10 +471,6 @@ await users.removeAppBuilder(userId, prodAppId) } - const addGroupAppBuilder = async groupId => { - await groups.actions.addGroupAppBuilder(groupId, prodAppId) - } - const removeGroupAppBuilder = async groupId => { await groups.actions.removeGroupAppBuilder(groupId, prodAppId) } @@ -495,14 +491,12 @@ } const getInviteRoleValue = invite => { - if (invite.info?.admin?.global && invite.info?.builder?.global) { - return Constants.Roles.ADMIN - } - - if (invite.info?.builder?.apps?.includes(prodAppId)) { + if ( + (invite.info?.admin?.global && invite.info?.builder?.global) || + invite.info?.builder?.apps?.includes(prodAppId) + ) { return Constants.Roles.CREATOR } - return invite.info.apps?.[prodAppId] } @@ -512,7 +506,7 @@ return `This user has been given ${role?.name} access from the ${user.group} group` } if (user.isAdminOrGlobalBuilder) { - return "This user's role grants admin access to all apps" + return "Account admins can edit all apps" } return null } @@ -650,8 +644,9 @@ autoWidth align="right" allowedRoles={user.isAdminOrGlobalBuilder - ? [Constants.Roles.ADMIN] + ? [Constants.Roles.CREATOR] : null} + labelPrefix="Can use as" />
@@ -695,19 +690,16 @@ allowRemove={group.role} allowPublic={false} quiet={true} - allowCreator={true} + allowCreator={group.role === Constants.Roles.CREATOR} on:change={e => { - if (e.detail === Constants.Roles.CREATOR) { - addGroupAppBuilder(group._id) - } else { - onUpdateGroup(group, e.detail) - } + onUpdateGroup(group, e.detail) }} on:remove={() => { onUpdateGroup(group) }} autoWidth align="right" + labelPrefix="Can use as" /> @@ -753,6 +745,7 @@ allowedRoles={user.isAdminOrGlobalBuilder ? [Constants.Roles.CREATOR] : null} + labelPrefix="Can use as" /> @@ -898,7 +891,6 @@ display: flex; flex-direction: column; gap: var(--spacing-s); - width: 400px; } .auth-entity-meta { @@ -927,7 +919,7 @@ .auth-entity, .auth-entity-header { display: grid; - grid-template-columns: 1fr 110px; + grid-template-columns: 1fr 180px; align-items: center; gap: var(--spacing-xl); } @@ -958,7 +950,7 @@ overflow-y: auto; overflow-x: hidden; position: absolute; - width: 400px; + width: 440px; right: 0; height: 100%; box-shadow: 0 0 40px 10px rgba(0, 0, 0, 0.1); From 295965d1d392ad3238aa776c4e0b5eaa979a122e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 15:23:22 +0000 Subject: [PATCH 22/42] Move picker subtitle to below the label --- packages/bbui/src/Form/Core/Picker.svelte | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 6361b345d1..94fbe73cf2 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -224,13 +224,12 @@ {/if} - {#if getOptionSubtitle(option, idx)} - {getOptionSubtitle(option, idx)} - {/if} - {getOptionLabel(option, idx)} + {#if getOptionSubtitle(option, idx)} + + {getOptionSubtitle(option, idx)} + + {/if} {#if option.tag} @@ -275,10 +274,9 @@ font-size: 12px; line-height: 15px; font-weight: 500; - top: 10px; color: var(--spectrum-global-color-gray-600); display: block; - margin-bottom: var(--spacing-s); + margin-top: var(--spacing-s); } .spectrum-Picker-label.auto-width { From 8ee32b4353234742451aa88185d57d61025e2cb2 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Fri, 24 Nov 2023 15:31:43 +0000 Subject: [PATCH 23/42] Changes to the single image and CouchDB image builds to make them work with new Helm chart changes. --- hosting/couchdb/Dockerfile | 3 +- hosting/couchdb/build-target-paths.sh | 24 --------------- hosting/couchdb/runner.sh | 42 +++++++++++++++++++++++++-- hosting/single/Dockerfile | 2 -- hosting/single/runner.sh | 4 +-- 5 files changed, 43 insertions(+), 32 deletions(-) delete mode 100644 hosting/couchdb/build-target-paths.sh diff --git a/hosting/couchdb/Dockerfile b/hosting/couchdb/Dockerfile index 792856cac7..f83df7038b 100644 --- a/hosting/couchdb/Dockerfile +++ b/hosting/couchdb/Dockerfile @@ -29,7 +29,6 @@ WORKDIR /opt/couchdb ADD couch/vm.args couch/local.ini ./etc/ WORKDIR / -ADD build-target-paths.sh . ADD runner.sh ./bbcouch-runner.sh -RUN chmod +x ./bbcouch-runner.sh /opt/clouseau/bin/clouseau ./build-target-paths.sh +RUN chmod +x ./bbcouch-runner.sh /opt/clouseau/bin/clouseau CMD ["./bbcouch-runner.sh"] diff --git a/hosting/couchdb/build-target-paths.sh b/hosting/couchdb/build-target-paths.sh deleted file mode 100644 index 34227011f4..0000000000 --- a/hosting/couchdb/build-target-paths.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -echo ${TARGETBUILD} > /buildtarget.txt -if [[ "${TARGETBUILD}" = "aas" ]]; then - # Azure AppService uses /home for persistent data & SSH on port 2222 - DATA_DIR="${DATA_DIR:-/home}" - WEBSITES_ENABLE_APP_SERVICE_STORAGE=true - mkdir -p $DATA_DIR/{search,minio,couch} - mkdir -p $DATA_DIR/couch/{dbs,views} - chown -R couchdb:couchdb $DATA_DIR/couch/ - apt update - apt-get install -y openssh-server - echo "root:Docker!" | chpasswd - mkdir -p /tmp - chmod +x /tmp/ssh_setup.sh \ - && (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null) - cp /etc/sshd_config /etc/ssh/sshd_config - /etc/init.d/ssh restart - sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini - sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini -else - sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini - sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini -fi \ No newline at end of file diff --git a/hosting/couchdb/runner.sh b/hosting/couchdb/runner.sh index 4102d2a751..2e4d26122f 100644 --- a/hosting/couchdb/runner.sh +++ b/hosting/couchdb/runner.sh @@ -1,14 +1,52 @@ #!/bin/bash DATA_DIR=${DATA_DIR:-/data} + mkdir -p ${DATA_DIR} mkdir -p ${DATA_DIR}/couch/{dbs,views} mkdir -p ${DATA_DIR}/search chown -R couchdb:couchdb ${DATA_DIR}/couch -/build-target-paths.sh + +echo ${TARGETBUILD} > /buildtarget.txt +if [[ "${TARGETBUILD}" = "aas" ]]; then + # Azure AppService uses /home for persistent data & SSH on port 2222 + DATA_DIR="${DATA_DIR:-/home}" + WEBSITES_ENABLE_APP_SERVICE_STORAGE=true + mkdir -p $DATA_DIR/{search,minio,couch} + mkdir -p $DATA_DIR/couch/{dbs,views} + chown -R couchdb:couchdb $DATA_DIR/couch/ + apt update + apt-get install -y openssh-server + echo "root:Docker!" | chpasswd + mkdir -p /tmp + chmod +x /tmp/ssh_setup.sh \ + && (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null) + cp /etc/sshd_config /etc/ssh/sshd_config + /etc/init.d/ssh restart + sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini +elif [[ "${TARGETBUILD}" = "single" ]]; then + sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini +elif [[ -n $KUBERNETES_SERVICE_HOST ]]; then + # In Kubernetes the directory /opt/couchdb/data has a persistent volume + # mount for storing database data. + sed -i "s#DATA_DIR#/opt/couchdb/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/opt/couchdb/data#g" /opt/couchdb/etc/local.ini + sed -i "s/^-name .*$//g" /opt/couchdb/etc/vm.args +else + sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini + sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini +fi + /opt/clouseau/bin/clouseau > /dev/stdout 2>&1 & /docker-entrypoint.sh /opt/couchdb/bin/couchdb & -sleep 10 + +while [[ $(curl -s -w "%{http_code}\n" http://localhost:5984/_up -o /dev/null) -ne 200 ]]; do + echo 'Waiting for CouchDB to start...'; + sleep 5; +done + curl -X PUT http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@localhost:5984/_users curl -X PUT http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@localhost:5984/_replicator sleep infinity \ No newline at end of file diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile index ec03a1b5a2..e9ff6c6596 100644 --- a/hosting/single/Dockerfile +++ b/hosting/single/Dockerfile @@ -94,8 +94,6 @@ RUN chmod +x ./healthcheck.sh # For Azure App Service install SSH & point data locations to /home COPY hosting/single/ssh/sshd_config /etc/ COPY hosting/single/ssh/ssh_setup.sh /tmp -RUN /build-target-paths.sh - # setup letsencrypt certificate RUN apt-get install -y certbot python3-certbot-nginx diff --git a/hosting/single/runner.sh b/hosting/single/runner.sh index 87201c95c0..f4b2b5b127 100644 --- a/hosting/single/runner.sh +++ b/hosting/single/runner.sh @@ -22,11 +22,11 @@ declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONME # Azure App Service customisations if [[ "${TARGETBUILD}" = "aas" ]]; then - DATA_DIR="${DATA_DIR:-/home}" + export DATA_DIR="${DATA_DIR:-/home}" WEBSITES_ENABLE_APP_SERVICE_STORAGE=true /etc/init.d/ssh start else - DATA_DIR=${DATA_DIR:-/data} + export DATA_DIR=${DATA_DIR:-/data} fi mkdir -p ${DATA_DIR} # Mount NFS or GCP Filestore if env vars exist for it From 302f6f61063ee4e370f99a26cb46408c443017f7 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 15:47:40 +0000 Subject: [PATCH 24/42] Fix footer in fancy select and allow inviting creators from side panel --- .../bbui/src/FancyForm/FancySelect.svelte | 3 + .../_components/BuilderSidePanel.svelte | 68 ++++++++++--------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/packages/bbui/src/FancyForm/FancySelect.svelte b/packages/bbui/src/FancyForm/FancySelect.svelte index e015f51570..14911f10ab 100644 --- a/packages/bbui/src/FancyForm/FancySelect.svelte +++ b/packages/bbui/src/FancyForm/FancySelect.svelte @@ -12,11 +12,13 @@ export let error = null export let validate = null export let options = [] + export let footer = null export let isOptionEnabled = () => true export let getOptionLabel = option => extractProperty(option, "label") export let getOptionValue = option => extractProperty(option, "value") export let getOptionSubtitle = option => extractProperty(option, "subtitle") export let getOptionColour = () => null + const dispatch = createEventDispatcher() let open = false @@ -100,6 +102,7 @@ {error} {disabled} {options} + {footer} {getOptionLabel} {getOptionValue} {getOptionSubtitle} diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index adb0c985dc..726b79e23d 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -364,7 +364,10 @@ const payload = [ { email: newUserEmail, - builder: { global: creationRoleType === Constants.BudibaseRoles.Admin }, + builder: { + global: creationRoleType === Constants.BudibaseRoles.Admin, + creator: creationRoleType === Constants.BudibaseRoles.Creator, + }, admin: { global: creationRoleType === Constants.BudibaseRoles.Admin }, }, ] @@ -517,6 +520,18 @@ } return user.role } + + const checkAppAccess = e => { + // Ensure we don't get into an invalid combo of tenant role and app access + if ( + e.detail === Constants.BudibaseRoles.AppUser && + creationAccessType === Constants.Roles.CREATOR + ) { + creationAccessType = Constants.Roles.BASIC + } else if (e.detail === Constants.BudibaseRoles.Admin) { + creationAccessType = Constants.Roles.CREATOR + } + } @@ -802,28 +817,29 @@ option => option.value !== Constants.BudibaseRoles.Admin )} label="Access" + on:change={checkAppAccess} /> - {#if creationRoleType !== Constants.BudibaseRoles.Admin} - - - - {/if} + + + - {#if creationRoleType === Constants.BudibaseRoles.Admin} -
- - Admins will get full access to all apps and settings -
- {/if} - {#if open} -
-
    - {#each options as option, idx} -
  • onPick(getOptionValue(option, idx))} - > - - {getOptionLabel(option, idx)} - - -
  • - {/each} -
-
- {/if} + {#if open} +
+
    + {#each options as option, idx} +
  • onPick(getOptionValue(option, idx))} + > + + {getOptionLabel(option, idx)} + {#if getOptionSubtitle(option, idx)} + + {getOptionSubtitle(option, idx)} + + {/if} + + +
  • + {/each} +
+
+ {/if} diff --git a/packages/bbui/src/Form/InputDropdown.svelte b/packages/bbui/src/Form/InputDropdown.svelte index 93766495b8..54b07cf0d7 100644 --- a/packages/bbui/src/Form/InputDropdown.svelte +++ b/packages/bbui/src/Form/InputDropdown.svelte @@ -43,6 +43,7 @@ {quiet} {autofocus} {options} + isOptionSelected={option => option === dropdownValue} on:change={onChange} on:pick={onPick} on:click diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte index 0730c31674..346b293235 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AddUserModal.svelte @@ -29,7 +29,6 @@ }, ] $: hasError = userData.find(x => x.error != null) - $: userCount = $licensing.userCount + userData.length $: reached = licensing.usersLimitReached(userCount) $: exceeded = licensing.usersLimitExceeded(userCount) diff --git a/packages/builder/src/pages/builder/portal/users/users/index.svelte b/packages/builder/src/pages/builder/portal/users/users/index.svelte index 744908fd14..50afd0004a 100644 --- a/packages/builder/src/pages/builder/portal/users/users/index.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/index.svelte @@ -191,18 +191,18 @@ for (const user of userData?.users ?? []) { const { email } = user - if ( newUsers.find(x => x.email === email) || currentUserEmails.includes(email) - ) + ) { continue - + } newUsers.push(user) } - if (!newUsers.length) + if (!newUsers.length) { notifications.info("Duplicated! There is no new users to add.") + } return { ...userData, users: newUsers } } @@ -267,7 +267,6 @@ try { await groups.actions.init() groupsLoaded = true - pendingInvites = await users.getInvites() invitesLoaded = true } catch (error) { From 7f17d2f94365e0621e04b41d9d6548d5424652d5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 16:34:58 +0000 Subject: [PATCH 29/42] Allow creating creator users via users store --- packages/builder/src/stores/portal/users.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index f653259e13..0e64d7a6cd 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -78,6 +78,9 @@ export function createUsersStore() { case "developer": body.builder = { global: true } break + case "creator": + body.builder = { creator: true, global: false } + break case "admin": body.admin = { global: true } body.builder = { global: true } From bc48661a64638ed59059159dc8cf5ec3f70d1e57 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 16:45:37 +0000 Subject: [PATCH 30/42] Lint and update user app tables to use new copy --- .../pages/builder/portal/users/users/[userId].svelte | 1 + .../users/_components/AppRoleTableRenderer.svelte | 10 +++++++--- .../users/users/_components/ImportUsersModal.svelte | 2 +- .../users/users/_components/RoleTableRenderer.svelte | 6 ------ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 8bb1ba5452..95e297e409 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -55,6 +55,7 @@ }, role: { width: "1fr", + displayName: "Access", }, } const customGroupTableRenderers = [ diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte index a9f2ca6e08..e0b743cfa2 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte @@ -14,6 +14,10 @@ } - - {getRoleLabel(value)} - +{#if value === Constants.Roles.CREATOR} + Can edit +{:else} + + Can use as {getRoleLabel(value)} + +{/if} diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte index 24f0222d14..bb03f166b3 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/ImportUsersModal.svelte @@ -11,11 +11,11 @@ import { emailValidator } from "helpers/validation" import { Constants } from "@budibase/frontend-core" import { capitalise } from "helpers" - import { BudibaseRoleOptions } from "@budibase/frontend-core/src/constants" const BYTES_IN_MB = 1000000 const FILE_SIZE_LIMIT = BYTES_IN_MB * 5 const MAX_USERS_UPLOAD_LIMIT = 1000 + export let createUsersFromCsv let files = [] diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte index d8abacf00b..936cd12517 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/RoleTableRenderer.svelte @@ -4,12 +4,6 @@ export let row - const TooltipMap = { - appUser: "Only has access to assigned apps", - developer: "Access to the app builder", - admin: "Full access", - } - $: role = Constants.BudibaseRoleOptions.find( x => x.value === users.getUserRole(row) ) From 018d42b440bcc6ebfe43bcedf050922cebdf4d97 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:05:31 +0000 Subject: [PATCH 31/42] Be explicit when checking if a user is a creator or not when displaying their global role in the user table list and user details page --- packages/builder/src/stores/portal/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index 0e64d7a6cd..5da5d4038d 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -129,7 +129,7 @@ export function createUsersStore() { return Constants.BudibaseRoles.Admin } else if (sdk.users.isBuilder(user)) { return Constants.BudibaseRoles.Developer - } else if (sdk.users.isCreator(user)) { + } else if (sdk.users.hasCreatorPermissions(user)) { return Constants.BudibaseRoles.Creator } else { return Constants.BudibaseRoles.AppUser From 168e87566294dab7ccbdd65aa403f5b8e8e443cf Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:27:22 +0000 Subject: [PATCH 32/42] Persist legacy creator access when promoting to creator --- .../src/pages/builder/portal/users/users/[userId].svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 95e297e409..368e45d83c 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -187,7 +187,11 @@ } else if (detail === Constants.BudibaseRoles.Creator) { toggleFlags({ admin: { global: false }, - builder: { global: false, creator: true }, + builder: { + global: false, + creator: true, + apps: user?.builder?.apps || [], + }, }) } } From a8c5f626667434cc9c0ff78324584942510ac34d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 24 Nov 2023 17:28:06 +0000 Subject: [PATCH 33/42] Fix label for tenant role when inviting users via builder side panel --- .../app/[application]/_components/BuilderSidePanel.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 726b79e23d..b937d69fd7 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -816,7 +816,7 @@ : Constants.BudibaseRoleOptions.filter( option => option.value !== Constants.BudibaseRoles.Admin )} - label="Access" + label="Role" on:change={checkAppAccess} /> From 1ae61eb4d668d06bd31b7437c874164a16bb29bb Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Sun, 26 Nov 2023 18:29:51 +0000 Subject: [PATCH 34/42] update pro reference --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 13b15ecb28..5e3d59fc40 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 13b15ecb28a147fe89e55314f7f8dfe837c7bdd1 +Subproject commit 5e3d59fc4060fd44b14b2599269c207753d4e5be From 3180ab76bfa223beddb1403cb3833a364daa9b95 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 27 Nov 2023 00:54:12 +0000 Subject: [PATCH 35/42] Bump version to 2.13.16 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index faba64ce90..0345af6bcf 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.15", + "version": "2.13.16", "npmClient": "yarn", "packages": [ "packages/*" From 1eb5dc73455760d43eca8f641afda2618c2697d3 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 27 Nov 2023 09:18:02 +0000 Subject: [PATCH 36/42] updating master ref --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 5e3d59fc40..618613f357 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 5e3d59fc4060fd44b14b2599269c207753d4e5be +Subproject commit 618613f3575b01f74940d9f58fdb53a9a5b2dc1a From bcaad6c2195423c2e67b1dcb637f67b8f4221f94 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 27 Nov 2023 09:30:02 +0000 Subject: [PATCH 37/42] Bump version to 2.13.17 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 0345af6bcf..40e167f36c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.16", + "version": "2.13.17", "npmClient": "yarn", "packages": [ "packages/*" From a65b29eb880f264fbc4fc78d3468f6109bc7044b Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 27 Nov 2023 18:50:44 +0000 Subject: [PATCH 38/42] banner changes for new pricing, fix for onboarding to prevent flash of UI before onboarding tutorial --- packages/backend-core/src/objectStore/objectStore.ts | 4 ++-- .../src/pages/builder/portal/apps/_layout.svelte | 2 +- .../src/pages/builder/portal/apps/index.svelte | 12 ++++++++++++ packages/pro | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index cdaf19fa55..cfd988f5e0 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -260,12 +260,12 @@ export async function listAllObjects(bucketName: string, path: string) { } /** - * Generate a presigned url with a default TTL of 1 hour + * Generate a presigned url with a default TTL of 1 day */ export function getPresignedUrl( bucketName: string, key: string, - durationSeconds: number = 3600 + durationSeconds: number = 86400 ) { const objectStore = ObjectStore(bucketName, { presigning: true }) const params = { diff --git a/packages/builder/src/pages/builder/portal/apps/_layout.svelte b/packages/builder/src/pages/builder/portal/apps/_layout.svelte index 38c0274eca..8810edca9c 100644 --- a/packages/builder/src/pages/builder/portal/apps/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/apps/_layout.svelte @@ -14,7 +14,7 @@ import PortalSideBar from "./_components/PortalSideBar.svelte" // Don't block loading if we've already hydrated state - let loaded = $apps.length != null + let loaded = !!$apps?.length onMount(async () => { try { diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index ad0d3658ea..fb0ba8bc2e 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -1,5 +1,6 @@