From 0d67f000f03e1c27692e92dcf866cd36b55435cd Mon Sep 17 00:00:00 2001 From: Dean Date: Wed, 18 Oct 2023 12:19:24 +0100 Subject: [PATCH 01/37] Initial reflow of the block settings --- packages/client/manifest.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 8d0a4e456f..d5fca15fd7 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5288,17 +5288,17 @@ }, "settings": [ { - "type": "select", + "type": "table", + "label": "Data", + "key": "dataSource" + }, + { + "type": "radio", "label": "Type", "key": "actionType", "options": ["Create", "Update", "View"], "defaultValue": "Create" }, - { - "type": "table", - "label": "Data", - "key": "dataSource" - }, { "type": "text", "label": "Title", @@ -5323,7 +5323,7 @@ }, { "type": "text", - "label": "Empty text", + "label": "No rows found", "key": "noRowsMessage", "defaultValue": "We couldn't find a row to display", "nested": true From f59d6222912443484cb98fb666dd92442199abc7 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 19 Oct 2023 12:28:28 +0100 Subject: [PATCH 02/37] Moved buttons section below fields --- packages/client/manifest.json | 102 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index d5fca15fd7..1919f4ccd2 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5330,57 +5330,6 @@ } ] }, - { - "section": true, - "name": "Buttons", - "dependsOn": { - "setting": "actionType", - "value": "View", - "invert": true - }, - "settings": [ - { - "type": "text", - "key": "saveButtonLabel", - "label": "Save button", - "nested": true, - "defaultValue": "Save" - }, - { - "type": "text", - "key": "deleteButtonLabel", - "label": "Delete button", - "nested": true, - "defaultValue": "Delete", - "dependsOn": { - "setting": "actionType", - "value": "Update" - } - }, - { - "type": "url", - "label": "Navigate after button press", - "key": "actionUrl", - "placeholder": "Choose a screen", - "dependsOn": { - "setting": "actionType", - "value": "View", - "invert": true - } - }, - { - "type": "boolean", - "label": "Hide notifications", - "key": "notificationOverride", - "defaultValue": false, - "dependsOn": { - "setting": "actionType", - "value": "View", - "invert": true - } - } - ] - }, { "section": true, "name": "Fields", @@ -5436,6 +5385,57 @@ } } ] + }, + { + "section": true, + "name": "Buttons", + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + }, + "settings": [ + { + "type": "text", + "key": "saveButtonLabel", + "label": "Save button", + "nested": true, + "defaultValue": "Save" + }, + { + "type": "text", + "key": "deleteButtonLabel", + "label": "Delete button", + "nested": true, + "defaultValue": "Delete", + "dependsOn": { + "setting": "actionType", + "value": "Update" + } + }, + { + "type": "url", + "label": "Navigate after button press", + "key": "actionUrl", + "placeholder": "Choose a screen", + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + } + }, + { + "type": "boolean", + "label": "Hide notifications", + "key": "notificationOverride", + "defaultValue": false, + "dependsOn": { + "setting": "actionType", + "value": "View", + "invert": true + } + } + ] } ], "context": [ From d0ea6edad39e1d608e0c84efc5d3c4fc7658c7a5 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Fri, 27 Oct 2023 10:55:19 +0100 Subject: [PATCH 03/37] Added selected class to data provider options. --- .../settings/controls/DataSourceSelect.svelte | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 29f32aa345..15ed945576 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -284,7 +284,7 @@
    {#each tables as table} -
  • handleSelected(table)}>{table.label}
  • +
  • handleSelected(table)}>{table.label}
  • {/each}
{#if views?.length} @@ -294,7 +294,7 @@
    {#each views as view} -
  • handleSelected(view)}>{view.label}
  • +
  • handleSelected(view)}>{view.label}
  • {/each}
{/if} @@ -306,7 +306,7 @@
    {#each queries as query}
  • handleSelected(query)} > {query.label} @@ -321,7 +321,7 @@
      {#each links as link} -
    • handleSelected(link)}>{link.label}
    • +
    • handleSelected(link)}>{link.label}
    • {/each}
    {/if} @@ -332,7 +332,7 @@
      {#each fields as field} -
    • handleSelected(field)}>{field.label}
    • +
    • handleSelected(field)}>{field.label}
    • {/each}
    {/if} @@ -343,7 +343,7 @@
      {#each jsonArrays as field} -
    • handleSelected(field)}>{field.label}
    • +
    • handleSelected(field)}>{field.label}
    • {/each}
    {/if} @@ -355,7 +355,7 @@
      {#each dataProviders as provider}
    • handleSelected(provider)} > {provider.label} @@ -368,7 +368,7 @@ Other
        -
      • handleSelected(custom)}>{custom.label}
      • +
      • handleSelected(custom)}>{custom.label}
      • {#if otherSources?.length} {#each otherSources as source}
      • handleSelected(source)}>{source.label}
      • From 2b691c169f2c7653a4a14752a1fbff6c36c0c2e8 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Fri, 27 Oct 2023 11:13:24 +0100 Subject: [PATCH 04/37] Ran Prettier to fix linting issue. --- .../settings/controls/DataSourceSelect.svelte | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 15ed945576..414d7b75d0 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -284,7 +284,12 @@
          {#each tables as table} -
        • handleSelected(table)}>{table.label}
        • +
        • handleSelected(table)} + > + {table.label} +
        • {/each}
        {#if views?.length} @@ -294,7 +299,12 @@
          {#each views as view} -
        • handleSelected(view)}>{view.label}
        • +
        • handleSelected(view)} + > + {view.label} +
        • {/each}
        {/if} @@ -321,7 +331,12 @@
          {#each links as link} -
        • handleSelected(link)}>{link.label}
        • +
        • handleSelected(link)} + > + {link.label} +
        • {/each}
        {/if} @@ -332,7 +347,12 @@
          {#each fields as field} -
        • handleSelected(field)}>{field.label}
        • +
        • handleSelected(field)} + > + {field.label} +
        • {/each}
        {/if} @@ -343,7 +363,12 @@
          {#each jsonArrays as field} -
        • handleSelected(field)}>{field.label}
        • +
        • handleSelected(field)} + > + {field.label} +
        • {/each}
        {/if} @@ -368,7 +393,12 @@ Other
          -
        • handleSelected(custom)}>{custom.label}
        • +
        • handleSelected(custom)} + > + {custom.label} +
        • {#if otherSources?.length} {#each otherSources as source}
        • handleSelected(source)}>{source.label}
        • From d9f52295ee88dced451edabc7d32bdd07df63815 Mon Sep 17 00:00:00 2001 From: Dean Date: Fri, 27 Oct 2023 11:36:45 +0100 Subject: [PATCH 05/37] Moved the description block out of the header to ensure it's visible for the view mode --- .../components/app/blocks/form/InnerFormBlock.svelte | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte b/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte index e65d2cf90b..f7e9a0d2ed 100644 --- a/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte +++ b/packages/client/src/components/app/blocks/form/InnerFormBlock.svelte @@ -220,15 +220,11 @@ {/if} - {#if description} - - {/if} {/if} + {#if description} + + {/if} {#key fields} {#each fields as field, idx} From 0461d8654564060b868c23eb412937fa58ed3478 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Mon, 30 Oct 2023 09:57:08 +0000 Subject: [PATCH 06/37] Refactored select to match designs used elsewhere. --- .../settings/controls/DataSourceSelect.svelte | 163 ++++++++++++++---- 1 file changed, 134 insertions(+), 29 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 414d7b75d0..10b79b986e 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -282,13 +282,26 @@
          Tables
          -
            +
              {#each tables as table}
            • handleSelected(table)} > - {table.label} + + {table.label} + +
            • {/each}
            @@ -297,13 +310,26 @@
            Views
            -
              +
                {#each views as view}
              • handleSelected(view)} > - {view.label} + + {view.label} + +
              • {/each}
              @@ -313,13 +339,26 @@
              Queries
              -
                +
                  {#each queries as query}
                • handleSelected(query)} > - {query.label} + + {query.label} + +
                • {/each}
                @@ -329,13 +368,26 @@
                Relationships
                -
                  +
                    {#each links as link}
                  • handleSelected(link)} > - {link.label} + + {link.label} + +
                  • {/each}
                  @@ -345,13 +397,26 @@
                  Fields
                  -
                    +
                      {#each fields as field}
                    • handleSelected(field)} > - {field.label} + + {field.label} + +
                    • {/each}
                    @@ -361,13 +426,26 @@
                    JSON Arrays
                    -
                      +
                        {#each jsonArrays as field}
                      • handleSelected(field)} > - {field.label} + + {field.label} + +
                      • {/each}
                      @@ -377,13 +455,26 @@
                      Data Providers
                      -
                        +
                          {#each dataProviders as provider}
                        • handleSelected(provider)} > - {provider.label} + + {provider.label} + +
                        • {/each}
                        @@ -392,19 +483,32 @@
                        Other
                        -
                          +
                          • handleSelected(custom)} > - {custom.label} + + {custom.label} + +
                          • - {#if otherSources?.length} - {#each otherSources as source} -
                          • handleSelected(source)}>{source.label}
                          • - {/each} - {/if}
                          + {#if otherSources?.length} + {#each otherSources as source} +
                        • handleSelected(source)}>{source.label}
                        • + {/each} + {/if} @@ -438,6 +542,7 @@ list-style: none; padding-left: 0px; margin: 0px; + width: 100%; } li { From 8f5646a1ed4cfabff4253a6524057131bec021bc Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Mon, 30 Oct 2023 10:15:53 +0000 Subject: [PATCH 07/37] Fixed linting issue. --- .../design/settings/controls/DataSourceSelect.svelte | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 10b79b986e..e7f12fd042 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -552,10 +552,6 @@ font-size: var(--font-size-m); } - .selected { - color: var(--spectrum-global-color-blue-600); - } - li:hover { background-color: var(--spectrum-global-color-gray-200); } From e9f0baa12f61c6d934acd54cadad1833f8f79400 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Mon, 30 Oct 2023 12:17:36 +0000 Subject: [PATCH 08/37] Added conditional logic to prevent checkmark from appearing on other selects outside of types. --- .../settings/controls/DataSourceSelect.svelte | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index e7f12fd042..545165a25c 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -286,7 +286,8 @@ {#each tables as table}
                        • Date: Tue, 31 Oct 2023 13:43:54 +0000 Subject: [PATCH 09/37] Fix issue with directional relationship being swapped --- .../backend/Datasources/CreateEditRelationship.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte b/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte index abec380b46..f6621c1508 100644 --- a/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte +++ b/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte @@ -30,15 +30,15 @@ part2: PrettyRelationshipDefinitions.MANY, }, [RelationshipType.MANY_TO_ONE]: { - part1: PrettyRelationshipDefinitions.ONE, - part2: PrettyRelationshipDefinitions.MANY, + part1: PrettyRelationshipDefinitions.MANY, + part2: PrettyRelationshipDefinitions.ONE, }, } let relationshipOpts1 = Object.values(PrettyRelationshipDefinitions) let relationshipOpts2 = Object.values(PrettyRelationshipDefinitions) - let relationshipPart1 = PrettyRelationshipDefinitions.MANY - let relationshipPart2 = PrettyRelationshipDefinitions.ONE + let relationshipPart1 = PrettyRelationshipDefinitions.ONE + let relationshipPart2 = PrettyRelationshipDefinitions.MANY let originalFromColumnName = toRelationship.name, originalToColumnName = fromRelationship.name From bb19e48a6d90f7230504ea3609c47d73afe36a1d Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 31 Oct 2023 14:22:15 +0000 Subject: [PATCH 10/37] Added new DataSourceSelect component. --- .../settings/controls/DataSourceSelect.svelte | 287 ++++-------------- .../DataSourceSelectItem/SelectItem.svelte | 60 ++++ 2 files changed, 123 insertions(+), 224 deletions(-) create mode 100644 packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 545165a25c..a56614e4e5 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -32,6 +32,7 @@ import IntegrationQueryEditor from "components/integration/index.svelte" import { makePropSafe as safe } from "@budibase/string-templates" import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" + import DataSourceSelect from "components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte" import { API } from "api" export let value = {} @@ -279,243 +280,81 @@
                        • handleSelected(source)}>{source.label}
                        • - {/each} + {/if} diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte new file mode 100644 index 0000000000..1fda2da634 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte @@ -0,0 +1,60 @@ + + +{#if dividerState} + +{/if} +{#if heading.length > 0} +
                          + {heading} +
                          +{/if} +
                            + {#each dataSet as data} +
                          • onSelect(data)} + on:keydown={e => { + if (e.key === "Enter" || e.key === "Space") { + onSelect(data) + } + }} + > + + {data.label} + + +
                          • + {/each} +
                          + + From df688b059669dc29d5cc5e374077e033012c084f Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 31 Oct 2023 14:36:50 +0000 Subject: [PATCH 11/37] Fixed linting issues. --- .../settings/controls/DataSourceSelect.svelte | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index a56614e4e5..0d8e728403 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -7,10 +7,8 @@ import { Button, Popover, - Divider, Select, Layout, - Heading, Drawer, DrawerContent, Icon, @@ -381,27 +379,6 @@ z-index: 99999999; overflow-y: scroll; } - .title { - padding: 0 var(--spacing-m) var(--spacing-s) var(--spacing-m); - } - - ul { - list-style: none; - padding-left: 0px; - margin: 0px; - width: 100%; - } - - li { - cursor: pointer; - margin: 0px; - padding: var(--spacing-s) var(--spacing-m); - font-size: var(--font-size-m); - } - - li:hover { - background-color: var(--spectrum-global-color-gray-200); - } .icon { margin-left: 8px; From 7e33aacbb1a77b0fa989d8647d9bf680c9b9ddfe Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 31 Oct 2023 14:48:23 +0000 Subject: [PATCH 12/37] Stop the sample data being identified as an external source. --- packages/server/src/integrations/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index b4fff0737a..33895e4fe1 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -11,6 +11,7 @@ import { InvalidColumns, NoEmptyFilterStrings } from "../constants" import { helpers } from "@budibase/shared-core" import * as external from "../api/controllers/table/external" import * as internal from "../api/controllers/table/internal" +import { DEFAULT_BB_DATASOURCE_ID } from "../db/defaultData/datasource_bb_default" const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}` const ROW_ID_REGEX = /^\[.*]$/g @@ -96,7 +97,8 @@ export function isInternalTableID(tableId: string) { export function isExternalTable(table: Table) { if ( table?.sourceId && - table.sourceId.includes(DocumentType.DATASOURCE + SEPARATOR) + table.sourceId.includes(DocumentType.DATASOURCE + SEPARATOR) && + table?.sourceId !== DEFAULT_BB_DATASOURCE_ID ) { return true } else if (table?.sourceType === TableSourceType.EXTERNAL) { From df6f8dad7e725e5c208bd65682e7db61a3a72d03 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 31 Oct 2023 16:56:19 +0000 Subject: [PATCH 13/37] Updating bull parameters to see if this helps with queue stalling. --- .../backend-core/src/queue/inMemoryQueue.ts | 2 +- packages/backend-core/src/queue/queue.ts | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/backend-core/src/queue/inMemoryQueue.ts b/packages/backend-core/src/queue/inMemoryQueue.ts index af2ec6dbaa..a8add7ecb6 100644 --- a/packages/backend-core/src/queue/inMemoryQueue.ts +++ b/packages/backend-core/src/queue/inMemoryQueue.ts @@ -36,7 +36,7 @@ class InMemoryQueue { * @param opts This is not used by the in memory queue as there is no real use * case when in memory, but is the same API as Bull */ - constructor(name: string, opts = null) { + constructor(name: string, opts?: any) { this._name = name this._opts = opts this._messages = [] diff --git a/packages/backend-core/src/queue/queue.ts b/packages/backend-core/src/queue/queue.ts index 0658147709..c6b02921bf 100644 --- a/packages/backend-core/src/queue/queue.ts +++ b/packages/backend-core/src/queue/queue.ts @@ -2,10 +2,16 @@ import env from "../environment" import { getRedisOptions } from "../redis/utils" import { JobQueue } from "./constants" import InMemoryQueue from "./inMemoryQueue" -import BullQueue from "bull" +import BullQueue, { QueueOptions } from "bull" import { addListeners, StalledFn } from "./listeners" import * as timers from "../timers" +import * as Redis from "ioredis" +// the queue lock is held for 5 minutes +const QUEUE_LOCK_MS = 300000 +// queue lock is refreshed every 30 seconds +const QUEUE_LOCK_RENEW_INTERNAL_MS = 30000 +// cleanup the queue every 60 seconds const CLEANUP_PERIOD_MS = 60 * 1000 let QUEUES: BullQueue.Queue[] | InMemoryQueue[] = [] let cleanupInterval: NodeJS.Timeout @@ -21,7 +27,14 @@ export function createQueue( opts: { removeStalledCb?: StalledFn } = {} ): BullQueue.Queue { const { opts: redisOpts, redisProtocolUrl } = getRedisOptions() - const queueConfig: any = redisProtocolUrl || { redis: redisOpts } + const queueConfig: QueueOptions = { + redis: redisProtocolUrl! || (redisOpts as Redis.RedisOptions), + settings: { + maxStalledCount: 0, + lockDuration: QUEUE_LOCK_MS, + lockRenewTime: QUEUE_LOCK_RENEW_INTERNAL_MS, + }, + } let queue: any if (!env.isTest()) { queue = new BullQueue(jobQueue, queueConfig) From 17319a6981a79ef41abe8fe4f7a26a6b02d4f9cd Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 31 Oct 2023 17:52:39 +0000 Subject: [PATCH 14/37] Moving things around so that DEFAULT_BB_DATASOURCE_ID can be imported without cyclics occurring. --- .../server/src/api/controllers/application.ts | 7 ++----- packages/server/src/constants/index.ts | 5 +++++ .../src/db/defaultData/datasource_bb_default.ts | 16 +++++++++------- packages/server/src/integrations/utils.ts | 9 +++++---- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 4afd7b23f9..4e4c66858e 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -32,11 +32,8 @@ import { tenancy, users, } from "@budibase/backend-core" -import { USERS_TABLE_SCHEMA } from "../../constants" -import { - buildDefaultDocs, - DEFAULT_BB_DATASOURCE_ID, -} from "../../db/defaultData/datasource_bb_default" +import { USERS_TABLE_SCHEMA, DEFAULT_BB_DATASOURCE_ID } from "../../constants" +import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default" import { removeAppFromUserRoles } from "../../utilities/workerRequests" import { stringToReadStream } from "../../utilities" import { doesUserHaveLock } from "../../utilities/redis" diff --git a/packages/server/src/constants/index.ts b/packages/server/src/constants/index.ts index 1104fb9b29..fb5c42e7b8 100644 --- a/packages/server/src/constants/index.ts +++ b/packages/server/src/constants/index.ts @@ -172,3 +172,8 @@ export enum AutomationErrors { export const ObjectStoreBuckets = objectStore.ObjectStoreBuckets export const MAX_AUTOMATION_RECURRING_ERRORS = 5 export const GOOGLE_SHEETS_PRIMARY_KEY = "rowNumber" +export const DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs" +export const DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory" +export const DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses" +export const DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee" +export const DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default" diff --git a/packages/server/src/db/defaultData/datasource_bb_default.ts b/packages/server/src/db/defaultData/datasource_bb_default.ts index 584b76f879..b430f9ffb6 100644 --- a/packages/server/src/db/defaultData/datasource_bb_default.ts +++ b/packages/server/src/db/defaultData/datasource_bb_default.ts @@ -1,4 +1,12 @@ -import { AutoFieldSubTypes, FieldTypes } from "../../constants" +import { + AutoFieldSubTypes, + FieldTypes, + DEFAULT_BB_DATASOURCE_ID, + DEFAULT_INVENTORY_TABLE_ID, + DEFAULT_EMPLOYEE_TABLE_ID, + DEFAULT_EXPENSES_TABLE_ID, + DEFAULT_JOBS_TABLE_ID, +} from "../../constants" import { importToRows } from "../../api/controllers/table/utils" import { cloneDeep } from "lodash/fp" import LinkDocument from "../linkedRows/LinkDocument" @@ -16,12 +24,6 @@ import { TableSourceType, } from "@budibase/types" -export const DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs" -export const DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory" -export const DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses" -export const DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee" -export const DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default" - const defaultDatasource = { _id: DEFAULT_BB_DATASOURCE_ID, type: dbCore.BUDIBASE_DATASOURCE_TYPE, diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index 33895e4fe1..fe8a9055b0 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -7,11 +7,12 @@ import { TableSourceType, } from "@budibase/types" import { DocumentType, SEPARATOR } from "../db/utils" -import { InvalidColumns, NoEmptyFilterStrings } from "../constants" +import { + InvalidColumns, + NoEmptyFilterStrings, + DEFAULT_BB_DATASOURCE_ID, +} from "../constants" import { helpers } from "@budibase/shared-core" -import * as external from "../api/controllers/table/external" -import * as internal from "../api/controllers/table/internal" -import { DEFAULT_BB_DATASOURCE_ID } from "../db/defaultData/datasource_bb_default" const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}` const ROW_ID_REGEX = /^\[.*]$/g From e05821d6d7c78320fe427abd8237738c61c88e31 Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Tue, 31 Oct 2023 18:16:58 +0000 Subject: [PATCH 15/37] License Management Test This test retrieves plans, creates checkout session, and updates license Essential changes have been made to linkStripeCustomer & updatePlan functions to support the test Modified "test:self:ci" to include 'licensing' instead of 'license' Modified environment.ts to include STRIPE_SECRET_KEY --- qa-core/package.json | 2 +- .../src/account-api/api/apis/LicenseAPI.ts | 10 +- qa-core/src/account-api/api/apis/StripeAPI.ts | 13 +- .../tests/licensing/license.manage.spec.ts | 113 ++++++++++++++++++ qa-core/src/environment.ts | 1 + 5 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 qa-core/src/account-api/tests/licensing/license.manage.spec.ts diff --git a/qa-core/package.json b/qa-core/package.json index d266ca9def..cfccd5e650 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -17,7 +17,7 @@ "test:notify": "node scripts/testResultsWebhook", "test:cloud:prod": "yarn run test --testPathIgnorePatterns=\\.integration\\.", "test:cloud:qa": "yarn run test", - "test:self:ci": "yarn run test --testPathIgnorePatterns=\\.integration\\. \\.cloud\\. \\.license\\.", + "test:self:ci": "yarn run test --testPathIgnorePatterns=\\.integration\\. \\.cloud\\. \\.licensing\\.", "serve:test:self:ci": "start-server-and-test dev:built http://localhost:4001/health test:self:ci", "serve": "start-server-and-test dev:built http://localhost:4001/health", "dev:built": "cd ../ && yarn dev:built" diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index b371f00f05..b3b54c5102 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -99,9 +99,15 @@ export default class LicenseAPI extends BaseAPI { }, opts) } - async updatePlan(opts: APIRequestOpts = { status: 200 }) { + async updatePlan( + priceId: string, + opts: APIRequestOpts = { status: 200 } + ) { return this.doRequest(() => { - return this.client.put(`/api/license/plan`) + return this.client.put(`/api/license/plan`, + { + body: { priceId }, + }) }, opts) } diff --git a/qa-core/src/account-api/api/apis/StripeAPI.ts b/qa-core/src/account-api/api/apis/StripeAPI.ts index c9c776e89b..6fef944206 100644 --- a/qa-core/src/account-api/api/apis/StripeAPI.ts +++ b/qa-core/src/account-api/api/apis/StripeAPI.ts @@ -38,9 +38,18 @@ export default class StripeAPI extends BaseAPI { }, opts) } - async linkStripeCustomer(opts: APIRequestOpts = { status: 200 }) { + async linkStripeCustomer( + accountId: string, + stripeCustomerId: string, + opts: APIRequestOpts = { status: 200 }) { return this.doRequest(() => { - return this.client.post(`/api/stripe/link`) + return this.client.post(`/api/stripe/link`, { + body: { + accountId, + stripeCustomerId + }, + internal: true, + }) }, opts) } diff --git a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts new file mode 100644 index 0000000000..a62b733c24 --- /dev/null +++ b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts @@ -0,0 +1,113 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import {Hosting, PlanType} from "@budibase/types" + +describe("license management", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("retrieves plans, creates checkout session, and updates license", async () => { + // Create cloud account + const createAccountRequest = fixtures.accounts.generateAccount({ + hosting: Hosting.CLOUD, + }) + const [createAccountRes, account] = + await config.accountsApi.accounts.create(createAccountRequest, { + autoVerify: true, + }) + + // Self response has free license + await config.doInNewState(async () => { + await config.loginAsAccount(createAccountRequest) + const [selfRes, selfBody] = await config.api.accounts.self() + expect(selfBody.license.plan.type).toBe(PlanType.FREE) + }) + + // Retrieve plans + const [plansRes, planBody] = await config.api.licenses.getPlans() + + // Select priceId from premium plan + let premiumPriceId = null + let businessPriceId = '' + for (const plan of planBody) { + if (plan.type === PlanType.PREMIUM) { + premiumPriceId = plan.prices[0].priceId + } + if (plan.type === PlanType.BUSINESS) { + businessPriceId = plan.prices[0].priceId + } + } + + // Create checkout session for price + const checkoutSessionRes = await config.api.stripe.createCheckoutSession( + premiumPriceId + ) + const checkoutSessionUrl = checkoutSessionRes[1].url + expect(checkoutSessionUrl).toContain("checkout.stripe.com") + + // Create stripe customer + const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) + const customer = await stripe.customers.create({ + email: createAccountRequest.email + }) + + // Create payment method + const paymentMethod = await stripe.paymentMethods.create({ + type: 'card', + card: { + token: 'tok_visa' // Test Visa Card + }, + }) + + // Attach payment method to customer + await stripe.paymentMethods.attach(paymentMethod.id, { + customer: customer.id, + }) + + // Update customer + await stripe.customers.update(customer.id, { + invoice_settings: { + default_payment_method: paymentMethod.id, + }, + }) + + // Create subscription for premium plan + const subscription = await stripe.subscriptions.create({ + customer: customer.id, + items: [ + { + price: premiumPriceId, + quantity: 1, + }, + ], + default_payment_method: paymentMethod.id, + collection_method: 'charge_automatically', + }) + + await config.doInNewState(async () => { + // License updated from Free to Premium + await config.loginAsAccount(createAccountRequest) + await config.api.stripe.linkStripeCustomer(account.accountId, customer.id) + const [_, selfBodyPremium] = await config.api.accounts.self() + expect(selfBodyPremium.license.plan.type).toBe(PlanType.PREMIUM) + + // Create portal session - Check URL + const [portalRes, portalSessionBody] = await config.api.stripe.createPortalSession(customer.id) + expect(portalSessionBody.url).toContain("billing.stripe.com") + + // Update subscription from premium to business license + await config.api.licenses.updatePlan(businessPriceId) + + // License updated to Business + const [selfRes, selfBodyBusiness] = await config.api.accounts.self() + expect(selfBodyBusiness.license.plan.type).toBe(PlanType.BUSINESS) + }) + }) +}) diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts index 0257b10831..a805503474 100644 --- a/qa-core/src/environment.ts +++ b/qa-core/src/environment.ts @@ -28,6 +28,7 @@ const env = { MARIADB_DB: process.env.MARIADB_DB, MARIADB_USER: process.env.MARIADB_USER, MARIADB_PASSWORD: process.env.MARIADB_PASSWORD, + STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY, } export = env From 84079450f973ad957d8bd031329832d155603b1b Mon Sep 17 00:00:00 2001 From: Mitch-Budibase Date: Tue, 31 Oct 2023 18:20:27 +0000 Subject: [PATCH 16/37] lint --- .../src/account-api/api/apis/LicenseAPI.ts | 12 +- qa-core/src/account-api/api/apis/StripeAPI.ts | 9 +- .../tests/licensing/license.manage.spec.ts | 205 +++++++++--------- 3 files changed, 112 insertions(+), 114 deletions(-) diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index b3b54c5102..a9b0a35269 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -99,15 +99,11 @@ export default class LicenseAPI extends BaseAPI { }, opts) } - async updatePlan( - priceId: string, - opts: APIRequestOpts = { status: 200 } - ) { + async updatePlan(priceId: string, opts: APIRequestOpts = { status: 200 }) { return this.doRequest(() => { - return this.client.put(`/api/license/plan`, - { - body: { priceId }, - }) + return this.client.put(`/api/license/plan`, { + body: { priceId }, + }) }, opts) } diff --git a/qa-core/src/account-api/api/apis/StripeAPI.ts b/qa-core/src/account-api/api/apis/StripeAPI.ts index 6fef944206..5a4e810655 100644 --- a/qa-core/src/account-api/api/apis/StripeAPI.ts +++ b/qa-core/src/account-api/api/apis/StripeAPI.ts @@ -39,14 +39,15 @@ export default class StripeAPI extends BaseAPI { } async linkStripeCustomer( - accountId: string, - stripeCustomerId: string, - opts: APIRequestOpts = { status: 200 }) { + accountId: string, + stripeCustomerId: string, + opts: APIRequestOpts = { status: 200 } + ) { return this.doRequest(() => { return this.client.post(`/api/stripe/link`, { body: { accountId, - stripeCustomerId + stripeCustomerId, }, internal: true, }) diff --git a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts index a62b733c24..a9109dad3a 100644 --- a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts +++ b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts @@ -1,113 +1,114 @@ import TestConfiguration from "../../config/TestConfiguration" import * as fixtures from "../../fixtures" -import {Hosting, PlanType} from "@budibase/types" +import { Hosting, PlanType } from "@budibase/types" describe("license management", () => { - const config = new TestConfiguration() + const config = new TestConfiguration() - beforeAll(async () => { - await config.beforeAll() + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("retrieves plans, creates checkout session, and updates license", async () => { + // Create cloud account + const createAccountRequest = fixtures.accounts.generateAccount({ + hosting: Hosting.CLOUD, + }) + const [createAccountRes, account] = + await config.accountsApi.accounts.create(createAccountRequest, { + autoVerify: true, + }) + + // Self response has free license + await config.doInNewState(async () => { + await config.loginAsAccount(createAccountRequest) + const [selfRes, selfBody] = await config.api.accounts.self() + expect(selfBody.license.plan.type).toBe(PlanType.FREE) }) - afterAll(async () => { - await config.afterAll() + // Retrieve plans + const [plansRes, planBody] = await config.api.licenses.getPlans() + + // Select priceId from premium plan + let premiumPriceId = null + let businessPriceId = "" + for (const plan of planBody) { + if (plan.type === PlanType.PREMIUM) { + premiumPriceId = plan.prices[0].priceId + } + if (plan.type === PlanType.BUSINESS) { + businessPriceId = plan.prices[0].priceId + } + } + + // Create checkout session for price + const checkoutSessionRes = await config.api.stripe.createCheckoutSession( + premiumPriceId + ) + const checkoutSessionUrl = checkoutSessionRes[1].url + expect(checkoutSessionUrl).toContain("checkout.stripe.com") + + // Create stripe customer + const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY) + const customer = await stripe.customers.create({ + email: createAccountRequest.email, }) - it("retrieves plans, creates checkout session, and updates license", async () => { - // Create cloud account - const createAccountRequest = fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }) - const [createAccountRes, account] = - await config.accountsApi.accounts.create(createAccountRequest, { - autoVerify: true, - }) - - // Self response has free license - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - const [selfRes, selfBody] = await config.api.accounts.self() - expect(selfBody.license.plan.type).toBe(PlanType.FREE) - }) - - // Retrieve plans - const [plansRes, planBody] = await config.api.licenses.getPlans() - - // Select priceId from premium plan - let premiumPriceId = null - let businessPriceId = '' - for (const plan of planBody) { - if (plan.type === PlanType.PREMIUM) { - premiumPriceId = plan.prices[0].priceId - } - if (plan.type === PlanType.BUSINESS) { - businessPriceId = plan.prices[0].priceId - } - } - - // Create checkout session for price - const checkoutSessionRes = await config.api.stripe.createCheckoutSession( - premiumPriceId - ) - const checkoutSessionUrl = checkoutSessionRes[1].url - expect(checkoutSessionUrl).toContain("checkout.stripe.com") - - // Create stripe customer - const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) - const customer = await stripe.customers.create({ - email: createAccountRequest.email - }) - - // Create payment method - const paymentMethod = await stripe.paymentMethods.create({ - type: 'card', - card: { - token: 'tok_visa' // Test Visa Card - }, - }) - - // Attach payment method to customer - await stripe.paymentMethods.attach(paymentMethod.id, { - customer: customer.id, - }) - - // Update customer - await stripe.customers.update(customer.id, { - invoice_settings: { - default_payment_method: paymentMethod.id, - }, - }) - - // Create subscription for premium plan - const subscription = await stripe.subscriptions.create({ - customer: customer.id, - items: [ - { - price: premiumPriceId, - quantity: 1, - }, - ], - default_payment_method: paymentMethod.id, - collection_method: 'charge_automatically', - }) - - await config.doInNewState(async () => { - // License updated from Free to Premium - await config.loginAsAccount(createAccountRequest) - await config.api.stripe.linkStripeCustomer(account.accountId, customer.id) - const [_, selfBodyPremium] = await config.api.accounts.self() - expect(selfBodyPremium.license.plan.type).toBe(PlanType.PREMIUM) - - // Create portal session - Check URL - const [portalRes, portalSessionBody] = await config.api.stripe.createPortalSession(customer.id) - expect(portalSessionBody.url).toContain("billing.stripe.com") - - // Update subscription from premium to business license - await config.api.licenses.updatePlan(businessPriceId) - - // License updated to Business - const [selfRes, selfBodyBusiness] = await config.api.accounts.self() - expect(selfBodyBusiness.license.plan.type).toBe(PlanType.BUSINESS) - }) + // Create payment method + const paymentMethod = await stripe.paymentMethods.create({ + type: "card", + card: { + token: "tok_visa", // Test Visa Card + }, }) + + // Attach payment method to customer + await stripe.paymentMethods.attach(paymentMethod.id, { + customer: customer.id, + }) + + // Update customer + await stripe.customers.update(customer.id, { + invoice_settings: { + default_payment_method: paymentMethod.id, + }, + }) + + // Create subscription for premium plan + const subscription = await stripe.subscriptions.create({ + customer: customer.id, + items: [ + { + price: premiumPriceId, + quantity: 1, + }, + ], + default_payment_method: paymentMethod.id, + collection_method: "charge_automatically", + }) + + await config.doInNewState(async () => { + // License updated from Free to Premium + await config.loginAsAccount(createAccountRequest) + await config.api.stripe.linkStripeCustomer(account.accountId, customer.id) + const [_, selfBodyPremium] = await config.api.accounts.self() + expect(selfBodyPremium.license.plan.type).toBe(PlanType.PREMIUM) + + // Create portal session - Check URL + const [portalRes, portalSessionBody] = + await config.api.stripe.createPortalSession(customer.id) + expect(portalSessionBody.url).toContain("billing.stripe.com") + + // Update subscription from premium to business license + await config.api.licenses.updatePlan(businessPriceId) + + // License updated to Business + const [selfRes, selfBodyBusiness] = await config.api.accounts.self() + expect(selfBodyBusiness.license.plan.type).toBe(PlanType.BUSINESS) + }) + }) }) From 6cf1b13a0c7383b7f7576b25f242378e3da40827 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 1 Nov 2023 09:30:54 +0000 Subject: [PATCH 17/37] Feedback related amends. --- .../design/settings/controls/DataSourceSelect.svelte | 1 - .../controls/DataSourceSelectItem/SelectItem.svelte | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte index 0d8e728403..af4da10466 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte @@ -348,7 +348,6 @@ {#if otherSources?.length} {/if} -{#if heading.length > 0} +{#if heading}
                          {heading}
                          @@ -26,11 +26,6 @@ aria-selected="true" tabindex="0" on:click={() => onSelect(data)} - on:keydown={e => { - if (e.key === "Enter" || e.key === "Space") { - onSelect(data) - } - }} > {data.label} From 9c71ccd2c48876618819066cc5946ca2f3128b5e Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 1 Nov 2023 09:34:10 +0000 Subject: [PATCH 18/37] Moved DataSourceSelect into related folder. Changed SelectedItem name. Updated DataSourceSelect imports. --- .../design/settings/componentSettings.js | 2 +- ...tItem.svelte => DataSourceCategory.svelte} | 0 .../DataSourceSelect.svelte | 20 +++++++++---------- .../settings/controls/SchemaSelect.svelte | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) rename packages/builder/src/components/design/settings/controls/DataSourceSelectItem/{SelectItem.svelte => DataSourceCategory.svelte} (100%) rename packages/builder/src/components/design/settings/controls/{ => DataSourceSelectItem}/DataSourceSelect.svelte (96%) diff --git a/packages/builder/src/components/design/settings/componentSettings.js b/packages/builder/src/components/design/settings/componentSettings.js index 232b4bef31..b81361dfa5 100644 --- a/packages/builder/src/components/design/settings/componentSettings.js +++ b/packages/builder/src/components/design/settings/componentSettings.js @@ -1,5 +1,5 @@ import { Checkbox, Select, RadioGroup, Stepper, Input } from "@budibase/bbui" -import DataSourceSelect from "./controls/DataSourceSelect.svelte" +import DataSourceSelect from "./controls/DataSourceSelectItem/DataSourceSelect.svelte" import S3DataSourceSelect from "./controls/S3DataSourceSelect.svelte" import DataProviderSelect from "./controls/DataProviderSelect.svelte" import ButtonActionEditor from "./controls/ButtonActionEditor/ButtonActionEditor.svelte" diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/DataSourceCategory.svelte similarity index 100% rename from packages/builder/src/components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte rename to packages/builder/src/components/design/settings/controls/DataSourceSelectItem/DataSourceCategory.svelte diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/DataSourceSelect.svelte similarity index 96% rename from packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte rename to packages/builder/src/components/design/settings/controls/DataSourceSelectItem/DataSourceSelect.svelte index af4da10466..1f059ee972 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelectItem/DataSourceSelect.svelte @@ -30,7 +30,7 @@ import IntegrationQueryEditor from "components/integration/index.svelte" import { makePropSafe as safe } from "@budibase/string-templates" import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" - import DataSourceSelect from "components/design/settings/controls/DataSourceSelectItem/SelectItem.svelte" + import DataSourceCategory from "components/design/settings/controls/DataSourceSelectItem/DataSourceCategory.svelte" import { API } from "api" export let value = {} @@ -278,14 +278,14 @@