From 3ffba9faf8bda98bc16e606bf8650f3e88bbc4ed Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 22 Mar 2024 09:49:05 +0100 Subject: [PATCH 01/60] Add download file option --- .../actions/DownloadFile.svelte | 28 +++++++++++++++++++ .../ButtonActionEditor/actions/index.js | 1 + .../controls/ButtonActionEditor/manifest.json | 5 ++++ 3 files changed, 34 insertions(+) create mode 100644 packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte new file mode 100644 index 0000000000..1c1974155b --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte @@ -0,0 +1,28 @@ + + +
+ + (parameters.value = e.detail)} + /> +
+ + diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/index.js b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/index.js index eb354d6557..587993377d 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/index.js +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/index.js @@ -22,3 +22,4 @@ export { default as PromptUser } from "./PromptUser.svelte" export { default as OpenSidePanel } from "./OpenSidePanel.svelte" export { default as CloseSidePanel } from "./CloseSidePanel.svelte" export { default as ClearRowSelection } from "./ClearRowSelection.svelte" +export { default as DownloadFile } from "./DownloadFile.svelte" diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json index 9391baf3dc..6d1794c991 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json @@ -161,6 +161,11 @@ "name": "Clear Row Selection", "type": "data", "component": "ClearRowSelection" + }, + { + "name": "Download file", + "type": "data", + "component": "DownloadFile" } ] } From 496679f3ebcf3b60b03573e47ec0f76900b12e40 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 22 Mar 2024 10:38:09 +0100 Subject: [PATCH 02/60] Download config --- .../ButtonActionEditor/actions/DownloadFile.svelte | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte index 1c1974155b..741b21a768 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte @@ -1,17 +1,23 @@
(parameters.value = e.detail)} />
From 349b22ba252ac93450bc549463ce748352a67910 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 22 Mar 2024 11:34:05 +0100 Subject: [PATCH 03/60] Move downloadfile to frontend-core --- .../components/start/ExportAppModal.svelte | 38 ++----------------- packages/frontend-core/src/utils/download.js | 31 +++++++++++++++ 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/packages/builder/src/components/start/ExportAppModal.svelte b/packages/builder/src/components/start/ExportAppModal.svelte index ec0cf42fe0..8cf2025c39 100644 --- a/packages/builder/src/components/start/ExportAppModal.svelte +++ b/packages/builder/src/components/start/ExportAppModal.svelte @@ -8,6 +8,7 @@ Input, notifications, } from "@budibase/bbui" + import { downloadFile } from "@budibase/frontend-core" import { createValidationStore } from "helpers/validation/yup" export let app @@ -55,42 +56,11 @@ const exportApp = async () => { const id = published ? app.prodId : app.devId const url = `/api/backups/export?appId=${id}` - await downloadFile(url, { - excludeRows: !includeInternalTablesRows, - encryptPassword: password, - }) - } - - async function downloadFile(url, body) { try { - const response = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(body), + await downloadFile(url, { + excludeRows: !includeInternalTablesRows, + encryptPassword: password, }) - - if (response.ok) { - const contentDisposition = response.headers.get("Content-Disposition") - - const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( - contentDisposition - ) - - const filename = matches[1].replace(/['"]/g, "") - - const url = URL.createObjectURL(await response.blob()) - - const link = document.createElement("a") - link.href = url - link.download = filename - link.click() - - URL.revokeObjectURL(url) - } else { - notifications.error("Error exporting the app.") - } } catch (error) { notifications.error(error.message || "Error downloading the exported app") } diff --git a/packages/frontend-core/src/utils/download.js b/packages/frontend-core/src/utils/download.js index 89c8572253..f3701b357b 100644 --- a/packages/frontend-core/src/utils/download.js +++ b/packages/frontend-core/src/utils/download.js @@ -34,3 +34,34 @@ export async function downloadStream(streamResponse) { URL.revokeObjectURL(blobUrl) } + +export async function downloadFile(url, body) { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }) + + if (response.ok) { + const contentDisposition = response.headers.get("Content-Disposition") + + const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( + contentDisposition + ) + + const filename = matches[1].replace(/['"]/g, "") + + const url = URL.createObjectURL(await response.blob()) + + const link = document.createElement("a") + link.href = url + link.download = filename + link.click() + + URL.revokeObjectURL(url) + } else { + notifications.error("Error exporting the app.") + } +} From 1a7e845c5648df17bf42e4ae997c213e36f18b70 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 22 Mar 2024 11:40:27 +0100 Subject: [PATCH 04/60] Remove notifications from frontend-core --- .../components/start/ExportAppModal.svelte | 6 ++- packages/frontend-core/src/utils/download.js | 39 ++++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/builder/src/components/start/ExportAppModal.svelte b/packages/builder/src/components/start/ExportAppModal.svelte index 8cf2025c39..3a995be7ae 100644 --- a/packages/builder/src/components/start/ExportAppModal.svelte +++ b/packages/builder/src/components/start/ExportAppModal.svelte @@ -56,11 +56,15 @@ const exportApp = async () => { const id = published ? app.prodId : app.devId const url = `/api/backups/export?appId=${id}` + try { - await downloadFile(url, { + const downloaded = await downloadFile(url, { excludeRows: !includeInternalTablesRows, encryptPassword: password, }) + if (!downloaded) { + notifications.error("Error exporting the app.") + } } catch (error) { notifications.error(error.message || "Error downloading the exported app") } diff --git a/packages/frontend-core/src/utils/download.js b/packages/frontend-core/src/utils/download.js index f3701b357b..b887122969 100644 --- a/packages/frontend-core/src/utils/download.js +++ b/packages/frontend-core/src/utils/download.js @@ -44,24 +44,25 @@ export async function downloadFile(url, body) { body: JSON.stringify(body), }) - if (response.ok) { - const contentDisposition = response.headers.get("Content-Disposition") - - const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( - contentDisposition - ) - - const filename = matches[1].replace(/['"]/g, "") - - const url = URL.createObjectURL(await response.blob()) - - const link = document.createElement("a") - link.href = url - link.download = filename - link.click() - - URL.revokeObjectURL(url) - } else { - notifications.error("Error exporting the app.") + if (!response.ok) { + return false } + + const contentDisposition = response.headers.get("Content-Disposition") + + const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( + contentDisposition + ) + + const filename = matches[1].replace(/['"]/g, "") + + const url = URL.createObjectURL(await response.blob()) + + const link = document.createElement("a") + link.href = url + link.download = filename + link.click() + + URL.revokeObjectURL(url) + return true } From 19caf3cddfb6e93890f52aad5ace602c542ad754 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 22 Mar 2024 11:44:32 +0100 Subject: [PATCH 05/60] Copy --- .../controls/ButtonActionEditor/manifest.json | 2 +- packages/client/src/utils/buttonActions.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json index 6d1794c991..2840a0d662 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/manifest.json @@ -163,7 +163,7 @@ "component": "ClearRowSelection" }, { - "name": "Download file", + "name": "Download File", "type": "data", "component": "DownloadFile" } diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 68478b76ac..a4471ac4aa 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -400,6 +400,23 @@ const closeSidePanelHandler = () => { sidePanelStore.actions.close() } +const downloadFileHandler = (action, context) => { + download(action.parameters.value, `file.jpg`) + // const x = processStringSync(action.parameters.value, context) + // console.warn(x) + + // // Built total context for this action + // const totalContext = { + // ...context, + // state: get(stateStore), + // actions: buttonContext, + // } + + // action = enrichDataBindings(action, totalContext) + + // console.error(action) +} + const handlerMap = { ["Fetch Row"]: fetchRowHandler, ["Save Row"]: saveRowHandler, @@ -418,6 +435,7 @@ const handlerMap = { ["Prompt User"]: promptUserHandler, ["Open Side Panel"]: openSidePanelHandler, ["Close Side Panel"]: closeSidePanelHandler, + ["Download File"]: downloadFileHandler, } const confirmTextMap = { From df05cf23454c3ce1635d44087bb414923d2a1fb5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 25 Mar 2024 10:24:20 +0100 Subject: [PATCH 06/60] Lint --- packages/frontend-core/src/utils/download.js | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/frontend-core/src/utils/download.js b/packages/frontend-core/src/utils/download.js index b887122969..55ba899ee6 100644 --- a/packages/frontend-core/src/utils/download.js +++ b/packages/frontend-core/src/utils/download.js @@ -46,23 +46,23 @@ export async function downloadFile(url, body) { if (!response.ok) { return false + } else { + const contentDisposition = response.headers.get("Content-Disposition") + + const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( + contentDisposition + ) + + const filename = matches[1].replace(/['"]/g, "") + + const url = URL.createObjectURL(await response.blob()) + + const link = document.createElement("a") + link.href = url + link.download = filename + link.click() + + URL.revokeObjectURL(url) + return true } - - const contentDisposition = response.headers.get("Content-Disposition") - - const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec( - contentDisposition - ) - - const filename = matches[1].replace(/['"]/g, "") - - const url = URL.createObjectURL(await response.blob()) - - const link = document.createElement("a") - link.href = url - link.download = filename - link.click() - - URL.revokeObjectURL(url) - return true } From 12f9b47954e987aa8acbc549a78fe56a3fc19949 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 25 Mar 2024 12:29:38 +0100 Subject: [PATCH 07/60] Implement download by url --- .../actions/DownloadFile.svelte | 74 +++++++++++++++++-- packages/client/src/utils/buttonActions.js | 26 ++++--- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte index 741b21a768..702f0cc911 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/DownloadFile.svelte @@ -1,7 +1,9 @@
- (parameters.value = e.detail)} + table.label} + getOptionValue={table => table.resourceId} + /> + + input within the builder/client. + */ OPTIONS = "options", - // a primitive type, stores a number, as a floating point, called Number within Budibase. - // this type will always represent numbers as reals/floating point - there is no integer only - // type within Budibase. + /** + * a primitive type, stores a number, as a floating point, called Number within Budibase. + * this type will always represent numbers as reals/floating point - there is no integer only + * type within Budibase. + */ NUMBER = "number", - // a primitive type, stores a boolean, called Boolean within Budibase. This is often represented - // as a toggle or checkbox within forms/grids. + /** + * a primitive type, stores a boolean, called Boolean within Budibase. This is often represented + * as a toggle or checkbox within forms/grids. + */ BOOLEAN = "boolean", - // a JSON type, this type is always an array of strings, called Multi-select within Budibase. - // This type can be compared to the options type, as it functions similarly, but allows picking - // multiple options rather than a single option. + /** + * a JSON type, this type is always an array of strings, called Multi-select within Budibase. + * This type can be compared to the options type, as it functions similarly, but allows picking + * multiple options rather than a single option. + */ ARRAY = "array", - // a string type, this is always a string when input/returned from the API, called Date/Time within - // Budibase. We utilise ISO date strings for representing dates, this type has a range of sub-types - // to restrict it to date only, time only and ignore timezone capabilities. + /** + * a string type, this is always a string when input/returned from the API, called Date/Time within + * Budibase. We utilise ISO date strings for representing dates, this type has a range of subtypes + * to restrict it to date only, time only and ignore timezone capabilities. + */ DATETIME = "datetime", - // a JSON type, an array of metadata about files held in object storage, called Attachment List within - // Budibase. To utilise this type there is an API for uploading files to Budibase, which returns metadata - // that can be stored against columns of this type. Currently this is not supported on external databases. + /** + * a JSON type, an array of metadata about files held in object storage, called Attachment List within + * Budibase. To utilise this type there is an API for uploading files to Budibase, which returns metadata + * that can be stored against columns of this type. Currently this is not supported on external databases. + */ ATTACHMENTS = "attachment", - // a JSON type, similar to the attachments type, called Attachment within Budibase. This type functions - // much the same as the attachment list, but only holds a single attachment metadata as an object. - // This simpifies the binding experience of using this column type. + /** + * a JSON type, similar to the attachments type, called Attachment within Budibase. This type functions + * much the same as the attachment list, but only holds a single attachment metadata as an object. + * This simplifies the binding experience of using this column type. + */ ATTACHMENT_SINGLE = "attachment_single", - // a complex type, called Relationships within Budibase. This is the most complex type of Budibase, - // nothing should be stored against rows under link columns; this type simply represents the - // relationship between tables as part of the table schema. When rows are input to the Budibase API - // relationships to be made are represented as a list of row IDs to link. When rows are returned - // from the Budibase API it will contain a list of row IDs and display column values of the related rows. + /** + * a complex type, called Relationships within Budibase. This is the most complex type of Budibase, + * nothing should be stored against rows under link columns; this type simply represents the + * relationship between tables as part of the table schema. When rows are input to the Budibase API + * relationships to be made are represented as a list of row IDs to link. When rows are returned + * from the Budibase API it will contain a list of row IDs and display column values of the related rows. + */ LINK = "link", - // a complex type, called Formulas within Budibase. This type has two variants, static and dynamic, with - // static only being supported against internal tables. Dynamic formulas calculate a provided HBS/JS binding - // based on the row context and enrich it when rows are being returned from the API. Static bindings calculate - // this when rows are being stored, so that the formula output can be searched upon within the DB. + /** + * a complex type, called Formulas within Budibase. This type has two variants, static and dynamic, with + * static only being supported against internal tables. Dynamic formulas calculate a provided HBS/JS binding + * based on the row context and enrich it when rows are being returned from the API. Static bindings calculate + * this when rows are being stored, so that the formula output can be searched upon within the DB. + */ FORMULA = "formula", - // a complex type, called Auto Column within Budibase. This type has a few variants, with options such as a - // date for created at/updated at, an auto ID column with auto-increments as rows are saved and a user - // relationship type which stores the created by/updated by user details. This sub-types all depend on the - // date, number of link types respectively. + /** + * a complex type, called Auto Column within Budibase. This type has a few variants, with options such as a + * date for created at/updated at, an auto ID column with auto-increments as rows are saved and a user + * relationship type which stores the created by/updated by user details. This sub-types all depend on the + * date, number of link types respectively. + */ AUTO = "auto", - // a JSON type, called JSON within Budibase. This type allows any arbitrary JSON to be input to this column - // type, which will be represented a string in the row. This type depends on a schema being provided to make the - // JSON searchable/bindable, the JSON cannot be fully dynamic. + /** + * a JSON type, called JSON within Budibase. This type allows any arbitrary JSON to be input to this column + * type, which will be represented as a JSON object in the row. This type depends on a schema being + * provided to make the JSON searchable/bindable, the JSON cannot be fully dynamic. + */ JSON = "json", - // an internal type, this is an old deprecated type which is no longer used - still represented to note it - // could appear in very old tables. + /** + * @deprecated an internal type, this is an old deprecated type which is no longer used - still represented to note it + * could appear in very old tables. + */ INTERNAL = "internal", - // a string type, called Barcode/QR within Budibase. This type is used to denote to forms to that this column - // should be filled in using a camera to read a barcode, there is a form component which will be used when this - // type is found. The column will contain the contents of any barcode scanned. + /** + * a string type, called Barcode/QR within Budibase. This type is used to denote to forms to that this column + * should be filled in using a camera to read a barcode, there is a form component which will be used when this + * type is found. The column will contain the contents of any barcode scanned. + */ BARCODEQR = "barcodeqr", - // a string type, this allows representing very large integers, but they are held/managed within Budibase as - // strings. When stored in external databases Budibase will attempt to use a real big integer type and depend - // on the database parsing the string to this type as part of saving. + /** + * a string type, this allows representing very large integers, but they are held/managed within Budibase as + * strings. When stored in external databases Budibase will attempt to use a real big integer type and depend + * on the database parsing the string to this type as part of saving. + */ BIGINT = "bigint", - // a JSON type, called User within Budibase. This type is used to represent a link to an internal Budibase - // resource, like a user or group, today only users are supported. This type will be represented as an - // array of internal resource IDs (e.g. user IDs) within the row - this ID list will be enriched with - // the full resources when rows are returned from the API. The full resources can be input to the API, or - // an array of resource IDs, the API will squash these down and validate them before saving the row. + /** + * a JSON type, called User within Budibase. This type is used to represent a link to an internal Budibase + * resource, like a user or group, today only users are supported. This type will be represented as an + * array of internal resource IDs (e.g. user IDs) within the row - this ID list will be enriched with + * the full resources when rows are returned from the API. The full resources can be input to the API, or + * an array of resource IDs, the API will squash these down and validate them before saving the row. + */ BB_REFERENCE = "bb_reference", } From fea6cd623cbe823955fd52061adcf9a64666ea76 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 15 Apr 2024 17:07:08 +0100 Subject: [PATCH 60/60] Final change. --- packages/types/src/documents/app/row.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/types/src/documents/app/row.ts b/packages/types/src/documents/app/row.ts index 4f2f9f99ef..865ab4ba64 100644 --- a/packages/types/src/documents/app/row.ts +++ b/packages/types/src/documents/app/row.ts @@ -71,8 +71,9 @@ export enum FieldType { /** * a complex type, called Auto Column within Budibase. This type has a few variants, with options such as a * date for created at/updated at, an auto ID column with auto-increments as rows are saved and a user - * relationship type which stores the created by/updated by user details. This sub-types all depend on the - * date, number of link types respectively. + * relationship type which stores the created by/updated by user details. These subtypes all depend on the + * date, number of link types respectively. There is one case where these will be executed in the browser, + * that is part of the initial formula definition, the formula will be live evaluated in the browser. */ AUTO = "auto", /**