diff --git a/.github/AUTHORS.md b/.github/AUTHORS.md index df346f3325..d31bb64987 100644 --- a/.github/AUTHORS.md +++ b/.github/AUTHORS.md @@ -8,4 +8,5 @@ Contributors * Andrew Kingston - [@aptkingston](https://github.com/aptkingston) * Michael Drury - [@mike12345567](https://github.com/mike12345567) * Peter Clement - [@PClmnt](https://github.com/PClmnt) -* Rory Powell - [@Rory-Powell](https://github.com/Rory-Powell) \ No newline at end of file +* Rory Powell - [@Rory-Powell](https://github.com/Rory-Powell) +* Michaƫl St-Georges [@CSLTech](https://github.com/CSLTech) \ No newline at end of file diff --git a/lerna.json b/lerna.json index b29f82c71a..cba15492eb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.26.1", + "version": "2.26.4", "npmClient": "yarn", "packages": [ "packages/*", diff --git a/packages/backend-core/src/objectStore/utils.ts b/packages/backend-core/src/objectStore/utils.ts index 5b9c2e3646..30c2fefbf1 100644 --- a/packages/backend-core/src/objectStore/utils.ts +++ b/packages/backend-core/src/objectStore/utils.ts @@ -9,6 +9,9 @@ import { AutomationAttachmentContent, BucketedContent, } from "@budibase/types" +import stream from "stream" +import streamWeb from "node:stream/web" + /**************************************************** * NOTE: When adding a new bucket - name * * sure that S3 usages (like budibase-infra) * @@ -53,12 +56,10 @@ export const bucketTTLConfig = ( Rules: [lifecycleRule], } - const params = { + return { Bucket: bucketName, LifecycleConfiguration: lifecycleConfiguration, } - - return params } async function processUrlAttachment( @@ -69,9 +70,12 @@ async function processUrlAttachment( throw new Error(`Unexpected response ${response.statusText}`) } const fallbackFilename = path.basename(new URL(attachment.url).pathname) + if (!response.body) { + throw new Error("No response received for attachment") + } return { filename: attachment.filename || fallbackFilename, - content: response.body, + content: stream.Readable.fromWeb(response.body as streamWeb.ReadableStream), } } diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 6c4fcab757..21635592d2 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -155,6 +155,8 @@ export default function positionDropdown(element, opts) { applyXStrategy(Strategies.StartToEnd) } else if (align === "left-outside") { applyXStrategy(Strategies.EndToStart) + } else if (align === "center") { + applyXStrategy(Strategies.MidPoint) } else { applyXStrategy(Strategies.StartToStart) } diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 85af5bbafd..879927343f 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -374,6 +374,16 @@ return `${value.title || (key === "row" ? "Table" : key)} ${requiredSuffix}` } + function handleAttachmentParams(keyValueObj) { + let params = {} + if (keyValueObj?.length) { + for (let param of keyValueObj) { + params[param.url] = param.filename + } + } + return params + } + onMount(async () => { try { await environment.loadVariables() @@ -381,15 +391,6 @@ console.error(error) } }) - const handleAttachmentParams = keyValuObj => { - let params = {} - if (keyValuObj?.length) { - for (let param of keyValuObj) { - params[param.url] = param.filename - } - } - return params - }
diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte index 9b4e5e36f6..1b52e35314 100644 --- a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte +++ b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte @@ -25,21 +25,21 @@ return !!schema.constraints?.inclusion?.length } - const handleAttachmentParams = keyValuObj => { + function handleAttachmentParams(keyValueObj) { let params = {} if ( schema.type === FieldType.ATTACHMENT_SINGLE && - Object.keys(keyValuObj).length === 0 + Object.keys(keyValueObj).length === 0 ) { return [] } - if (!Array.isArray(keyValuObj)) { - keyValuObj = [keyValuObj] + if (!Array.isArray(keyValueObj) && keyValueObj) { + keyValueObj = [keyValueObj] } - if (keyValuObj.length) { - for (let param of keyValuObj) { + if (keyValueObj.length) { + for (let param of keyValueObj) { params[param.url] = param.filename } } diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte index 1ec32cb3fd..4ff8ae994b 100644 --- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte +++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte @@ -14,9 +14,8 @@ import LinkedRowSelector from "components/common/LinkedRowSelector.svelte" import Editor from "../../integration/QueryEditor.svelte" - export let defaultValue export let meta - export let value = defaultValue || (meta.type === "boolean" ? false : "") + export let value export let readonly export let error diff --git a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte index 77229f3a17..26972ede16 100644 --- a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte @@ -1,5 +1,6 @@ @@ -14,12 +15,16 @@
-
- -
-
+ {#if !disabled} +
+ +
+
+ +
+ {:else} -
+ {/if}
diff --git a/packages/builder/src/components/common/UpdateAppForm.svelte b/packages/builder/src/components/common/UpdateAppForm.svelte new file mode 100644 index 0000000000..0e07c5c918 --- /dev/null +++ b/packages/builder/src/components/common/UpdateAppForm.svelte @@ -0,0 +1,214 @@ + + +
+
+
+ + ($validation.touched.name = true)} + on:change={nameToUrl($values.name)} + disabled={appDeployed} + /> +
+
+ + ($validation.touched.url = true)} + on:change={tidyUrl($values.url)} + placeholder={$values.url + ? $values.url + : `/${resolveAppUrl(null, $values.name)}`} + disabled={appDeployed} + /> +
+
+ + +
+
+ {#if !appDeployed} + + {:else} +
+ Unpublish your app to edit name and URL +
+ {/if} +
+
+
+ + diff --git a/packages/builder/src/components/common/UpdateAppTopNav.svelte b/packages/builder/src/components/common/UpdateAppTopNav.svelte new file mode 100644 index 0000000000..f4a76c4576 --- /dev/null +++ b/packages/builder/src/components/common/UpdateAppTopNav.svelte @@ -0,0 +1,68 @@ + + +
+ + +
{ + formPopover.show() + }} + > + + + + +
+
+ + { + formPopoverOpen = false + }} + on:open={() => { + formPopoverOpen = true + }} +> + +
+ { + formPopover.hide() + }} + /> +
+
+
+ + diff --git a/packages/builder/src/components/deploy/AppActions.svelte b/packages/builder/src/components/deploy/AppActions.svelte index 105d1ed958..bb950983a6 100644 --- a/packages/builder/src/components/deploy/AppActions.svelte +++ b/packages/builder/src/components/deploy/AppActions.svelte @@ -8,13 +8,11 @@ ActionButton, Icon, Link, - Modal, StatusLight, AbsTooltip, } from "@budibase/bbui" import RevertModal from "components/deploy/RevertModal.svelte" import VersionModal from "components/deploy/VersionModal.svelte" - import UpdateAppModal from "components/start/UpdateAppModal.svelte" import { processStringSync } from "@budibase/string-templates" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import analytics, { Events, EventSource } from "analytics" @@ -26,7 +24,6 @@ isOnlyUser, appStore, deploymentStore, - initialise, sortedScreens, } from "stores/builder" import TourWrap from "components/portal/onboarding/TourWrap.svelte" @@ -37,7 +34,6 @@ export let loaded let unpublishModal - let updateAppModal let revertModal let versionModal let appActionPopover @@ -61,11 +57,6 @@ $: canPublish = !publishing && loaded && $sortedScreens.length > 0 $: lastDeployed = getLastDeployedString($deploymentStore, lastOpened) - const initialiseApp = async () => { - const applicationPkg = await API.fetchAppPackage($appStore.devId) - await initialise(applicationPkg) - } - const getLastDeployedString = deployments => { return deployments?.length ? processStringSync("Published {{ duration time 'millisecond' }} ago", { @@ -247,16 +238,12 @@ appActionPopover.hide() if (isPublished) { viewApp() - } else { - updateAppModal.show() } }} > {$appStore.url} {#if isPublished} - {:else} - {/if} @@ -330,20 +317,6 @@ Are you sure you want to unpublish the app {selectedApp?.name}? - - { - await initialiseApp() - }} - /> - - diff --git a/packages/builder/src/components/design/settings/controls/S3DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/S3DataSourceSelect.svelte index d5d42f1514..c52532508c 100644 --- a/packages/builder/src/components/design/settings/controls/S3DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/S3DataSourceSelect.svelte @@ -5,7 +5,7 @@ export let value = null $: dataSources = $datasources.list - .filter(ds => ds.source === "S3" && !ds.config?.endpoint) + .filter(ds => ds.source === "S3") .map(ds => ({ label: ds.name, value: ds._id, diff --git a/packages/builder/src/components/portal/onboarding/EnterpriseBasicTrialModal.svelte b/packages/builder/src/components/portal/onboarding/EnterpriseBasicTrialModal.svelte index 6652bd4104..e195b52106 100644 --- a/packages/builder/src/components/portal/onboarding/EnterpriseBasicTrialModal.svelte +++ b/packages/builder/src/components/portal/onboarding/EnterpriseBasicTrialModal.svelte @@ -2,21 +2,21 @@ import { Modal, ModalContent } from "@budibase/bbui" import FreeTrial from "../../../../assets/FreeTrial.svelte" import { get } from "svelte/store" - import { auth, licensing } from "stores/portal" + import { auth, licensing, admin } from "stores/portal" import { API } from "api" import { PlanType } from "@budibase/types" - import { sdk } from "@budibase/shared-core" let freeTrialModal $: planType = $licensing?.license?.plan?.type $: showFreeTrialModal(planType, freeTrialModal) + $: isOwner = $auth.accountPortalAccess && $admin.cloud const showFreeTrialModal = (planType, freeTrialModal) => { if ( planType === PlanType.ENTERPRISE_BASIC_TRIAL && !$auth.user?.freeTrialConfirmedAt && - sdk.users.isAdmin($auth.user) + isOwner ) { freeTrialModal?.show() } diff --git a/packages/builder/src/components/start/UpdateAppModal.svelte b/packages/builder/src/components/start/UpdateAppModal.svelte deleted file mode 100644 index 94f6b20694..0000000000 --- a/packages/builder/src/components/start/UpdateAppModal.svelte +++ /dev/null @@ -1,151 +0,0 @@ - - - - ($validation.touched.name = true)} - on:change={nameToUrl($values.name)} - label="Name" - /> - - - - - ($validation.touched.url = true)} - on:change={tidyUrl($values.url)} - label="URL" - placeholder={$values.url - ? $values.url - : `/${resolveAppUrl(null, $values.name)}`} - /> - diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index 75f6a053b5..6ac37e60be 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -33,7 +33,7 @@ export const FIELDS = { }, }, BARCODEQR: { - name: "Barcode/QR", + name: "Barcode / QR", type: FieldType.BARCODEQR, icon: TypeIconMap[FieldType.BARCODEQR], constraints: { @@ -43,7 +43,7 @@ export const FIELDS = { }, }, LONGFORM: { - name: "Long Form Text", + name: "Long form text", type: FieldType.LONGFORM, icon: TypeIconMap[FieldType.LONGFORM], constraints: { @@ -53,7 +53,7 @@ export const FIELDS = { }, }, OPTIONS: { - name: "Options", + name: "Single select", type: FieldType.OPTIONS, icon: TypeIconMap[FieldType.OPTIONS], constraints: { @@ -63,7 +63,7 @@ export const FIELDS = { }, }, ARRAY: { - name: "Multi-select", + name: "Multi select", type: FieldType.ARRAY, icon: TypeIconMap[FieldType.ARRAY], constraints: { @@ -83,7 +83,7 @@ export const FIELDS = { }, }, BIGINT: { - name: "BigInt", + name: "Big integer", type: FieldType.BIGINT, icon: TypeIconMap[FieldType.BIGINT], }, @@ -97,7 +97,7 @@ export const FIELDS = { }, }, DATETIME: { - name: "Date/Time", + name: "Date / time", type: FieldType.DATETIME, icon: TypeIconMap[FieldType.DATETIME], constraints: { @@ -111,7 +111,7 @@ export const FIELDS = { }, }, ATTACHMENT_SINGLE: { - name: "Attachment", + name: "Single attachment", type: FieldType.ATTACHMENT_SINGLE, icon: TypeIconMap[FieldType.ATTACHMENT_SINGLE], constraints: { @@ -119,7 +119,7 @@ export const FIELDS = { }, }, ATTACHMENTS: { - name: "Attachment List", + name: "Multi attachment", type: FieldType.ATTACHMENTS, icon: TypeIconMap[FieldType.ATTACHMENTS], constraints: { @@ -137,7 +137,7 @@ export const FIELDS = { }, }, AUTO: { - name: "Auto Column", + name: "Auto column", type: FieldType.AUTO, icon: TypeIconMap[FieldType.AUTO], constraints: {}, @@ -158,7 +158,7 @@ export const FIELDS = { }, }, USER: { - name: "User", + name: "Single user", type: FieldType.BB_REFERENCE_SINGLE, subtype: BBReferenceFieldSubType.USER, icon: TypeIconMap[FieldType.BB_REFERENCE_SINGLE][ @@ -166,7 +166,7 @@ export const FIELDS = { ], }, USERS: { - name: "User List", + name: "Multi user", type: FieldType.BB_REFERENCE, subtype: BBReferenceFieldSubType.USER, icon: TypeIconMap[FieldType.BB_REFERENCE][BBReferenceFieldSubType.USER], diff --git a/packages/builder/src/dataBinding.js b/packages/builder/src/dataBinding.js index af229ce7e4..4e48c237ca 100644 --- a/packages/builder/src/dataBinding.js +++ b/packages/builder/src/dataBinding.js @@ -830,7 +830,7 @@ export const getActionBindings = (actions, actionId) => { * @return {{schema: Object, table: Object}} */ export const getSchemaForDatasourcePlus = (resourceId, options) => { - const isViewV2 = resourceId?.includes("view_") + const isViewV2 = resourceId?.startsWith("view_") const datasource = isViewV2 ? { type: "viewV2", diff --git a/packages/builder/src/helpers/validation/yup/app.js b/packages/builder/src/helpers/validation/yup/app.js index 1947844f63..3a00b7a49f 100644 --- a/packages/builder/src/helpers/validation/yup/app.js +++ b/packages/builder/src/helpers/validation/yup/app.js @@ -19,11 +19,10 @@ export const name = (validation, { apps, currentApp } = { apps: [] }) => { // exit early, above validator will fail return true } - if (currentApp) { - // filter out the current app if present - apps = apps.filter(app => app.appId !== currentApp.appId) - } return !apps + .filter(app => { + return app.appId !== currentApp?.appId + }) .map(app => app.name) .some(appName => appName.toLowerCase() === value.toLowerCase()) } diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index f100260343..7d4958db04 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -33,6 +33,7 @@ import { TOUR_KEYS } from "components/portal/onboarding/tours.js" import PreviewOverlay from "./_components/PreviewOverlay.svelte" import EnterpriseBasicTrialModal from "components/portal/onboarding/EnterpriseBasicTrialModal.svelte" + import UpdateAppTopNav from "components/common/UpdateAppTopNav.svelte" export let application @@ -164,7 +165,11 @@
- {$appStore.name} +
+ + {$appStore.name} + +
@@ -253,7 +258,6 @@ font-weight: 600; overflow: hidden; text-overflow: ellipsis; - padding: 0px var(--spacing-m); } .topleftnav { diff --git a/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte b/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte index be580552c7..e91b8ac3a8 100644 --- a/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte @@ -1,30 +1,6 @@ @@ -33,61 +9,5 @@ Edit your app's name and URL - - - - {$appStore?.name} - - - - -
- -
-
- - - - {$appStore.url} - - -
- -
+ - - - { - await initialiseApp() - }} - /> - - - diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte index a62233fad5..73152a1cd5 100644 --- a/packages/builder/src/pages/builder/portal/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/_layout.svelte @@ -1,7 +1,14 @@
- - onRowClick?.({ row: e.detail })} - on:columnresize={onColumnResize} - /> - + onRowClick?.({ row: e.detail })} + on:columnresize={onColumnResize} + />
@@ -198,14 +200,9 @@ border: 1px solid var(--spectrum-global-color-gray-300); border-radius: 4px; overflow: hidden; + height: 410px; } div.in-builder :global(*) { pointer-events: none; } - span { - display: contents; - } - span :global(.grid) { - height: var(--height); - } diff --git a/packages/client/src/components/app/forms/AttachmentField.svelte b/packages/client/src/components/app/forms/AttachmentField.svelte index 3489fd809c..27286a8666 100644 --- a/packages/client/src/components/app/forms/AttachmentField.svelte +++ b/packages/client/src/components/app/forms/AttachmentField.svelte @@ -25,7 +25,7 @@ let fieldState let fieldApi - const { API, notificationStore } = getContext("sdk") + const { API, notificationStore, environmentStore } = getContext("sdk") const formContext = getContext("form") const BYTES_IN_MB = 1000000 @@ -87,7 +87,7 @@ error={fieldState.error} on:change={handleChange} {processFiles} - {handleFileTooLarge} + handleFileTooLarge={$environmentStore.cloud ? handleFileTooLarge : null} {handleTooManyFiles} {maximum} {extensions} diff --git a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte index 1a2494987a..ea452c86a8 100644 --- a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte @@ -12,7 +12,7 @@ export let schema export let maximum - const { API, notifications } = getContext("grid") + const { API, notifications, props } = getContext("grid") const imageExtensions = ["png", "tiff", "gif", "raw", "jpg", "jpeg"] let isOpen = false @@ -106,7 +106,7 @@ on:change={e => onChange(e.detail)} maximum={maximum || schema.constraints?.length?.maximum} {processFiles} - {handleFileTooLarge} + handleFileTooLarge={$props.isCloud ? handleFileTooLarge : null} />
diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte index bb38c5094f..530595fe40 100644 --- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte @@ -386,7 +386,7 @@ > Hide column - {#if $config.canEditColumns && column.schema.type === "link" && column.schema.tableId === TableNames.USERS} + {#if $config.canEditColumns && column.schema.type === "link" && column.schema.tableId === TableNames.USERS && !column.schema.autocolumn} Migrate to user column diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index 23f61b424f..7dbb86ab23 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -1,6 +1,6 @@