diff --git a/lerna.json b/lerna.json index 99d61cf6dc..4b2ef30117 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "npmClient": "yarn", "packages": [ "packages/backend-core", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 1296f45c54..fe23105596 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -22,7 +22,7 @@ "dependencies": { "@budibase/nano": "10.1.2", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.5.6-alpha.28", + "@budibase/types": "2.5.6-alpha.42", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", @@ -45,6 +45,8 @@ "passport-jwt": "4.0.0", "passport-local": "1.0.0", "passport-oauth2-refresh": "^2.1.0", + "pino": "8.11.0", + "pino-http": "8.3.3", "posthog-node": "1.3.0", "pouchdb": "7.3.0", "pouchdb-find": "7.2.2", @@ -78,7 +80,6 @@ "jest-serial-runner": "^1.2.1", "koa": "2.13.4", "nodemon": "2.0.16", - "pino": "7.11.0", "pino-pretty": "10.0.0", "pouchdb-adapter-memory": "7.2.2", "timekeeper": "2.2.0", diff --git a/packages/backend-core/src/events/publishers/license.ts b/packages/backend-core/src/events/publishers/license.ts index aff3286c87..d1ff4d7609 100644 --- a/packages/backend-core/src/events/publishers/license.ts +++ b/packages/backend-core/src/events/publishers/license.ts @@ -3,7 +3,6 @@ import { Event, LicenseActivatedEvent, LicensePlanChangedEvent, - LicenseTierChangedEvent, PlanType, Account, LicensePortalOpenedEvent, @@ -11,22 +10,22 @@ import { LicenseCheckoutOpenedEvent, LicensePaymentFailedEvent, LicensePaymentRecoveredEvent, + PriceDuration, } from "@budibase/types" -async function tierChanged(account: Account, from: number, to: number) { - const properties: LicenseTierChangedEvent = { - accountId: account.accountId, - to, - from, - } - await publishEvent(Event.LICENSE_TIER_CHANGED, properties) -} - -async function planChanged(account: Account, from: PlanType, to: PlanType) { +async function planChanged( + account: Account, + from: PlanType, + to: PlanType, + quantity: number | undefined, + duration: PriceDuration | undefined +) { const properties: LicensePlanChangedEvent = { accountId: account.accountId, to, from, + quantity, + duration, } await publishEvent(Event.LICENSE_PLAN_CHANGED, properties) } @@ -74,7 +73,6 @@ async function paymentRecovered(account: Account) { } export default { - tierChanged, planChanged, activated, checkoutOpened, diff --git a/packages/backend-core/tests/core/utilities/mocks/events.ts b/packages/backend-core/tests/core/utilities/mocks/events.ts index dacf7dcce8..81de1f8175 100644 --- a/packages/backend-core/tests/core/utilities/mocks/events.ts +++ b/packages/backend-core/tests/core/utilities/mocks/events.ts @@ -123,7 +123,6 @@ beforeAll(async () => { jest.spyOn(events.plugin, "imported") jest.spyOn(events.plugin, "deleted") - jest.spyOn(events.license, "tierChanged") jest.spyOn(events.license, "planChanged") jest.spyOn(events.license, "activated") jest.spyOn(events.license, "checkoutOpened") diff --git a/packages/backend-core/tests/core/utilities/structures/licenses.ts b/packages/backend-core/tests/core/utilities/structures/licenses.ts index 24b120451e..810f31cf4f 100644 --- a/packages/backend-core/tests/core/utilities/structures/licenses.ts +++ b/packages/backend-core/tests/core/utilities/structures/licenses.ts @@ -7,16 +7,29 @@ import { PlanType, PriceDuration, PurchasedPlan, + PurchasedPrice, Quotas, Subscription, } from "@budibase/types" +export function price(): PurchasedPrice { + return { + amount: 10000, + amountMonthly: 10000, + currency: "usd", + duration: PriceDuration.MONTHLY, + priceId: "price_123", + dayPasses: undefined, + isPerUser: true, + } +} + export const plan = (type: PlanType = PlanType.FREE): PurchasedPlan => { return { type, usesInvoicing: false, - minUsers: 1, model: PlanModel.PER_USER, + price: price(), } } diff --git a/packages/bbui/package.json b/packages/bbui/package.json index b46e5c3b7d..ff82bbc2c4 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,8 +38,8 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "1.2.1", - "@budibase/shared-core": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", + "@budibase/shared-core": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 4009a401e7..0015174bcf 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,11 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.5.6-alpha.28", - "@budibase/client": "2.5.6-alpha.28", - "@budibase/frontend-core": "2.5.6-alpha.28", - "@budibase/shared-core": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", + "@budibase/bbui": "2.5.6-alpha.42", + "@budibase/frontend-core": "2.5.6-alpha.42", + "@budibase/shared-core": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 3fc0eb769e..e264dc099b 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -134,6 +134,7 @@ export const getFrontendStore = () => { previousTopNavPath: {}, version: application.version, revertableVersion: application.revertableVersion, + upgradableVersion: application.upgradableVersion, navigation: application.navigation || {}, usedPlugins: application.usedPlugins || [], })) diff --git a/packages/builder/src/components/deploy/VersionModal.svelte b/packages/builder/src/components/deploy/VersionModal.svelte index f357cc7820..75acc974ce 100644 --- a/packages/builder/src/components/deploy/VersionModal.svelte +++ b/packages/builder/src/components/deploy/VersionModal.svelte @@ -9,7 +9,6 @@ } from "@budibase/bbui" import { store } from "builderStore" import { API } from "api" - import clientPackage from "@budibase/client/package.json" export function show() { updateModal.show() @@ -25,9 +24,9 @@ $: appId = $store.appId $: updateAvailable = - clientPackage.version && + $store.upgradableVersion && $store.version && - clientPackage.version !== $store.version + $store.upgradableVersion !== $store.version $: revertAvailable = $store.revertableVersion != null const refreshAppPackage = async () => { @@ -46,7 +45,7 @@ // Don't wait for the async refresh, since this causes modal flashing refreshAppPackage() notifications.success( - `App updated successfully to version ${clientPackage.version}` + `App updated successfully to version ${$store.upgradableVersion}` ) } catch (err) { notifications.error(`Error updating app: ${err}`) @@ -91,7 +90,7 @@ {#if updateAvailable} This app is currently using version {$store.version}, but version - {clientPackage.version} is available. Updates can contain new features, + {$store.upgradableVersion} is available. Updates can contain new features, performance improvements and bug fixes. {:else} diff --git a/packages/builder/src/components/usage/Usage.svelte b/packages/builder/src/components/usage/Usage.svelte index 6e81abfe63..23d8ddc2f3 100644 --- a/packages/builder/src/components/usage/Usage.svelte +++ b/packages/builder/src/components/usage/Usage.svelte @@ -27,7 +27,7 @@ onMount(() => { unlimited = isUnlimited() percentage = getPercentage() - if (warnWhenFull && percentage === 100) { + if (warnWhenFull && percentage >= 100) { showWarning = true } }) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte index 8e6ac603e7..bfc2f94f43 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte @@ -35,7 +35,7 @@ } - + Custom layouts are being deprecated. They will be removed in a future diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte index dbd23c462f..614e1eed80 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte @@ -9,7 +9,7 @@ } - + {#if $selectedScreen.layoutId} {#if $selectedScreen.layoutId} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte index 9593f0bff5..c3325852c8 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte @@ -3,7 +3,7 @@ import { Body, Layout } from "@budibase/bbui" - + Your theme is set across all the screens within your app. diff --git a/packages/builder/src/pages/builder/portal/account/usage.svelte b/packages/builder/src/pages/builder/portal/account/usage.svelte index 80e42d52a8..8dc02c6c80 100644 --- a/packages/builder/src/pages/builder/portal/account/usage.svelte +++ b/packages/builder/src/pages/builder/portal/account/usage.svelte @@ -43,12 +43,18 @@ } $: quotaUsage = $licensing.quotaUsage + $: license = $auth.user?.license + $: plan = license?.plan + $: usesInvoicing = plan?.usesInvoicing + $: accountPortalAccess = $auth?.user?.accountPortalAccess $: quotaReset = quotaUsage?.quotaReset $: canManagePlan = ($admin.cloud && accountPortalAccess) || (!$admin.cloud && $auth.isAdmin) + $: showButton = !usesInvoicing && accountPortalAccess + const setMonthlyUsage = () => { monthlyUsage = [] if (quotaUsage.monthly) { @@ -121,7 +127,7 @@ const setTextRows = () => { textRows = [] - if (cancelAt) { + if (cancelAt && !usesInvoicing) { textRows.push({ message: "Subscription has been cancelled" }) textRows.push({ message: `${getDaysRemaining(cancelAt)} days remaining`, @@ -213,7 +219,7 @@ description="YOUR CURRENT PLAN" title={planTitle()} {primaryActionText} - primaryAction={accountPortalAccess ? goToAccountPortal : undefined} + primaryAction={showButton ? goToAccountPortal : undefined} {textRows} >
@@ -224,33 +230,23 @@
{/each} + + Monthly limits +
+ + + Resets in {daysRemainingInMonth} days + + +
+
+ + {#each monthlyUsage as usage} + + {/each} +
- - {#if monthlyUsage.length} -
- - - Monthly limits -
- - - Resets in {daysRemainingInMonth} days - - -
-
- - {#each monthlyUsage as usage} - - {/each} - -
-
- {/if}
diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte index 4ff9ea386a..77d76c9609 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte @@ -176,7 +176,7 @@ Backups {#if !$licensing.backupsEnabled} - Pro plan + Premium {/if} diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte index 2d2b6775fb..c049a610b6 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte @@ -13,7 +13,6 @@ notifications, } from "@budibase/bbui" import { store } from "builderStore" - import clientPackage from "@budibase/client/package.json" import { processStringSync } from "@budibase/string-templates" import { users, auth, apps, groups, overview } from "stores/portal" import { fetchData } from "@budibase/frontend-core" @@ -40,7 +39,7 @@ }, }, }) - $: updateAvailable = clientPackage.version !== $store.version + $: updateAvailable = $store.upgradableVersion !== $store.version $: isPublished = app?.status === AppStatus.DEPLOYED $: appEditorId = !app?.updatedBy ? $auth.user._id : app?.updatedBy $: appEditorText = appEditor?.firstName || appEditor?.email @@ -172,8 +171,8 @@ {$store.version} {#if updateAvailable}
- New version {clientPackage.version} is available - - + New version {$store.upgradableVersion} is + available - { $goto("./version") diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/version.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/version.svelte index 676d0b4f59..723e32984d 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/version.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/version.svelte @@ -1,12 +1,11 @@ @@ -18,7 +17,7 @@ {#if updateAvailable} The app is currently using version {$store.version} - but version {clientPackage.version} is available. + but version {$store.upgradableVersion} is available.
Updates can contain new features, performance improvements and bug fixes. diff --git a/packages/builder/src/pages/builder/portal/settings/auth/index.svelte b/packages/builder/src/pages/builder/portal/settings/auth/index.svelte index 60f84049a3..38f5e0788b 100644 --- a/packages/builder/src/pages/builder/portal/settings/auth/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/auth/index.svelte @@ -378,7 +378,7 @@
{#if !$licensing.enforceableSSO} - Enterprise plan + Enterprise {/if} diff --git a/packages/builder/src/pages/builder/portal/settings/branding.svelte b/packages/builder/src/pages/builder/portal/settings/branding.svelte index 2184280e89..ae22d310a1 100644 --- a/packages/builder/src/pages/builder/portal/settings/branding.svelte +++ b/packages/builder/src/pages/builder/portal/settings/branding.svelte @@ -213,7 +213,7 @@ {/if} {#if isCloud && !brandingEnabled} - Pro + Premium {/if} diff --git a/packages/builder/src/pages/builder/portal/users/groups/index.svelte b/packages/builder/src/pages/builder/portal/users/groups/index.svelte index 1a0bad7b11..6abc63811f 100644 --- a/packages/builder/src/pages/builder/portal/users/groups/index.svelte +++ b/packages/builder/src/pages/builder/portal/users/groups/index.svelte @@ -94,7 +94,7 @@ Groups {#if !$licensing.groupsEnabled} - Pro plan + Business {/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 be0023ec21..b35c6c998f 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 @@ -25,7 +25,7 @@ $: invalidEmails = [] $: userCount = $licensing.userCount + userEmails.length - $: willExceed = userCount > $licensing.userLimit + $: willExceed = licensing.willExceedUserLimit(userCount) $: importDisabled = !userEmails.length || !validEmails(userEmails) || !usersRole || willExceed diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index d223239f67..898d47c0e2 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -114,11 +114,13 @@ export function createUsersStore() { const getUserRole = ({ admin, builder }) => admin?.global ? "admin" : builder?.global ? "developer" : "appUser" - const refreshUsage = fn => async args => { - const response = await fn(args) - await licensing.setQuotaUsage() - return response - } + const refreshUsage = + fn => + async (...args) => { + const response = await fn(...args) + await licensing.setQuotaUsage() + return response + } return { subscribe, @@ -133,7 +135,7 @@ export function createUsersStore() { updateInvite, getUserCountByApp, // any operation that adds or deletes users - acceptInvite: refreshUsage(acceptInvite), + acceptInvite, create: refreshUsage(create), save: refreshUsage(save), bulkDelete: refreshUsage(bulkDelete), diff --git a/packages/cli/package.json b/packages/cli/package.json index 321c9b6a35..87f8885baa 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "dist/index.js", "bin": { @@ -29,9 +29,9 @@ "outputPath": "build" }, "dependencies": { - "@budibase/backend-core": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", - "@budibase/types": "2.5.6-alpha.28", + "@budibase/backend-core": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", + "@budibase/types": "2.5.6-alpha.42", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 84ffca314c..71637723c1 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5225,36 +5225,5 @@ "type": "schema", "suffix": "repeater" } - }, - "spreadsheet": { - "name": "Spreadsheet", - "icon": "ViewGrid", - "settings": [ - { - "key": "table", - "type": "table", - "label": "Table" - }, - { - "type": "filter", - "label": "Filtering", - "key": "filter" - }, - { - "type": "field/sortable", - "label": "Sort Column", - "key": "sortColumn" - }, - { - "type": "select", - "label": "Sort Order", - "key": "sortOrder", - "options": [ - "Ascending", - "Descending" - ], - "defaultValue": "Ascending" - } - ] } } diff --git a/packages/client/package.json b/packages/client/package.json index b953eee349..7ff0ddae9c 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,11 +19,11 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "2.5.6-alpha.28", - "@budibase/frontend-core": "2.5.6-alpha.28", - "@budibase/shared-core": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", - "@budibase/types": "2.5.6-alpha.28", + "@budibase/bbui": "2.5.6-alpha.42", + "@budibase/frontend-core": "2.5.6-alpha.42", + "@budibase/shared-core": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", + "@budibase/types": "2.5.6-alpha.42", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index ff830b0cb5..c0b60cb091 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,13 +1,13 @@ { "name": "@budibase/frontend-core", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.5.6-alpha.28", - "@budibase/shared-core": "2.5.6-alpha.28", + "@budibase/bbui": "2.5.6-alpha.42", + "@budibase/shared-core": "2.5.6-alpha.42", "dayjs": "^1.11.7", "lodash": "^4.17.21", "socket.io-client": "^4.6.1", diff --git a/packages/frontend-core/src/components/grid/cells/DataCell.svelte b/packages/frontend-core/src/components/grid/cells/DataCell.svelte index 5a2e02340f..0aa0cd54f4 100644 --- a/packages/frontend-core/src/components/grid/cells/DataCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/DataCell.svelte @@ -19,6 +19,7 @@ export let updateValue = rows.actions.updateValue export let invertX = false export let invertY = false + export let contentLines = 1 const emptyError = writable(null) @@ -84,5 +85,7 @@ {readonly} {invertY} {invertX} + {contentLines} /> + diff --git a/packages/frontend-core/src/components/grid/cells/GridCell.svelte b/packages/frontend-core/src/components/grid/cells/GridCell.svelte index dfc53f6f0c..6589c18d07 100644 --- a/packages/frontend-core/src/components/grid/cells/GridCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/GridCell.svelte @@ -117,6 +117,9 @@ .cell.error { --cell-color: var(--spectrum-global-color-red-500); } + .cell.readonly { + --cell-color: var(--spectrum-global-color-gray-600); + } .cell:not(.focused) { user-select: none; } diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte index 165711c51f..72b0ad0ff1 100644 --- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte @@ -37,6 +37,8 @@ $: sortedBy = column.name === $sort.column $: canMoveLeft = orderable && idx > 0 $: canMoveRight = orderable && idx < $renderedColumns.length - 1 + $: ascendingLabel = column.schema?.type === "number" ? "low-high" : "A-Z" + $: descendingLabel = column.schema?.type === "number" ? "high-low" : "Z-A" const editColumn = () => { dispatch("edit-column", column.schema) @@ -179,14 +181,14 @@ on:click={sortAscending} disabled={column.name === $sort.column && $sort.order === "ascending"} > - Sort A-Z + Sort {ascendingLabel} - Sort Z-A + Sort {descendingLabel} Move left diff --git a/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte b/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte index 00e12dc6a3..886d4ef8b0 100644 --- a/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte @@ -1,5 +1,6 @@ - + diff --git a/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte b/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte index f3b6b9b59d..9399617eb7 100644 --- a/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte @@ -1,5 +1,5 @@ + +
+ {#each parsedKeys as key} +
+ {key} +
+ {/each} +
+ + diff --git a/packages/frontend-core/src/components/grid/layout/NewRow.svelte b/packages/frontend-core/src/components/grid/layout/NewRow.svelte index 54fef78301..71c390c946 100644 --- a/packages/frontend-core/src/components/grid/layout/NewRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewRow.svelte @@ -7,6 +7,7 @@ import { GutterWidth } from "../lib/constants" import { NewRowID } from "../lib/constants" import GutterCell from "../cells/GutterCell.svelte" + import KeyboardShortcut from "./KeyboardShortcut.svelte" const { hoveredRowId, @@ -27,13 +28,14 @@ columnHorizontalInversionIndex, } = getContext("grid") + let visible = false let isAdding = false let newRow = {} let offset = 0 $: firstColumn = $stickyColumn || $renderedColumns[0] $: width = GutterWidth + ($stickyColumn?.width || 0) - $: $tableId, (isAdding = false) + $: $tableId, (visible = false) $: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows) const shouldInvertY = (offset, inversionIndex, rows) => { @@ -45,7 +47,8 @@ const addRow = async () => { // Blur the active cell and tick to let final value updates propagate - $focusedCellAPI?.blur() + isAdding = true + $focusedCellId = null await tick() // Create row @@ -60,17 +63,19 @@ $focusedCellId = `${savedRow._id}-${firstColumn.name}` } } + isAdding = false } const clear = () => { isAdding = false + visible = false $focusedCellId = null $hoveredRowId = null document.removeEventListener("keydown", handleKeyPress) } const startAdding = async () => { - if (isAdding) { + if (visible) { return } @@ -95,7 +100,7 @@ // Update state and select initial cell newRow = {} - isAdding = true + visible = true $hoveredRowId = NewRowID if (firstColumn) { $focusedCellId = `${NewRowID}-${firstColumn.name}` @@ -115,7 +120,7 @@ } const handleKeyPress = e => { - if (!isAdding) { + if (!visible) { return } if (e.key === "Escape") { @@ -137,7 +142,7 @@ -{#if isAdding} +{#if visible}
0} @@ -148,6 +153,9 @@
+ {#if isAdding} +
+ {/if} {#if $stickyColumn} {@const cellId = `${NewRowID}-${$stickyColumn.name}`} @@ -161,7 +169,14 @@ {updateValue} rowIdx={0} {invertY} - /> + > + {#if $stickyColumn?.schema?.autocolumn} +
Can't edit auto column
+ {/if} + {#if isAdding} +
+ {/if} + {/if}
@@ -181,15 +196,32 @@ rowIdx={0} invertX={columnIdx >= $columnHorizontalInversionIndex} {invertY} - /> + > + {#if column?.schema?.autocolumn} +
Can't edit auto column
+ {/if} + {#if isAdding} +
+ {/if} + {/key} {/each}
- - + +
{/if} @@ -240,6 +272,14 @@ top: calc(var(--row-height) + var(--offset) + 24px); left: var(--gutter-width); } + .button-with-keys { + display: flex; + gap: 6px; + align-items: center; + } + .button-with-keys :global(> div) { + padding-top: 2px; + } /* Sticky column styles */ .sticky-column { @@ -262,4 +302,33 @@ width: 0; display: flex; } + + /* Readonly cell overlay */ + .readonly-overlay { + position: absolute; + top: 0; + left: 0; + height: var(--row-height); + width: 100%; + padding: var(--cell-padding); + font-style: italic; + color: var(--spectrum-global-color-gray-600); + z-index: 1; + user-select: none; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + /* Overlay while row is being added */ + .loading-overlay { + position: absolute; + top: 0; + left: 0; + height: var(--row-height); + width: 100%; + z-index: 1; + background: var(--spectrum-global-color-gray-400); + opacity: 0.25; + } diff --git a/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte b/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte index 6f10c30695..6301112110 100644 --- a/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte +++ b/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte @@ -7,6 +7,7 @@ import HeaderCell from "../cells/HeaderCell.svelte" import { GutterWidth, BlankRowID } from "../lib/constants" import GutterCell from "../cells/GutterCell.svelte" + import KeyboardShortcut from "./KeyboardShortcut.svelte" const { rows, @@ -21,6 +22,7 @@ focusedRow, scrollLeft, dispatch, + contentLines, } = getContext("grid") $: rowCount = $rows.length @@ -85,6 +87,7 @@ selectedUser={$selectedCellMap[cellId]} width={$stickyColumn.width} column={$stickyColumn} + contentLines={$contentLines} /> {/if}
@@ -103,7 +106,9 @@ + > + + {/if}
{/if} diff --git a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte index e0e842dc16..f0f56118d9 100644 --- a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte +++ b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte @@ -15,8 +15,22 @@ selectedRows, } = getContext("grid") + const ignoredOriginSelectors = [ + ".spectrum-Modal", + "#builder-side-panel-container", + ] + // Global key listener which intercepts all key events const handleKeyDown = e => { + // Avoid processing events sourced from certain origins + if (e.target?.closest) { + for (let selector of ignoredOriginSelectors) { + if (e.target.closest(selector)) { + return + } + } + } + // If nothing selected avoid processing further key presses if (!$focusedCellId) { if (e.key === "Tab" || e.key?.startsWith("Arrow")) { @@ -60,11 +74,6 @@ return } } - - // Avoid processing events sourced from modals - if (e.target?.closest?.(".spectrum-Modal")) { - return - } e.preventDefault() // Handle the key ourselves diff --git a/packages/sdk/package.json b/packages/sdk/package.json index a8dff3da10..13cc20f9e9 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 1cd28f6829..cc8a8208dc 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -45,12 +45,12 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "10.0.3", - "@budibase/backend-core": "2.5.6-alpha.28", - "@budibase/client": "2.5.6-alpha.28", - "@budibase/pro": "2.5.6-alpha.28", - "@budibase/shared-core": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", - "@budibase/types": "2.5.6-alpha.28", + "@budibase/backend-core": "2.5.6-alpha.42", + "@budibase/client": "2.5.6-alpha.42", + "@budibase/pro": "2.5.6-alpha.42", + "@budibase/shared-core": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", + "@budibase/types": "2.5.6-alpha.42", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index ec68ca4c72..ff0dbe015b 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -223,7 +223,7 @@ export async function fetchAppPackage(ctx: UserCtx) { ) ctx.body = { - application, + application: { ...application, upgradableVersion: envCore.VERSION }, screens, layouts, clientLibPath, diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 3d41cd89af..b61b168980 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -12,7 +12,15 @@ import { getIntegration } from "../../integrations" import { getDatasourceAndQuery } from "./row/utils" import { invalidateDynamicVariables } from "../../threads/utils" import { db as dbCore, context, events } from "@budibase/backend-core" -import { UserCtx, Datasource, Row } from "@budibase/types" +import { + UserCtx, + Datasource, + Row, + CreateDatasourceResponse, + UpdateDatasourceResponse, + UpdateDatasourceRequest, + CreateDatasourceRequest, +} from "@budibase/types" import sdk from "../../sdk" export async function fetch(ctx: UserCtx) { @@ -146,7 +154,7 @@ async function invalidateVariables( await invalidateDynamicVariables(toInvalidate) } -export async function update(ctx: UserCtx) { +export async function update(ctx: UserCtx) { const db = context.getAppDB() const datasourceId = ctx.params.datasourceId let datasource = await sdk.datasources.get(datasourceId) @@ -187,15 +195,17 @@ export async function update(ctx: UserCtx) { } } -export async function save(ctx: UserCtx) { +export async function save( + ctx: UserCtx +) { const db = context.getAppDB() const plus = ctx.request.body.datasource.plus const fetchSchema = ctx.request.body.fetchSchema const datasource = { _id: generateDatasourceID({ plus }), - type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE, ...ctx.request.body.datasource, + type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE, } let schemaError = null @@ -218,7 +228,7 @@ export async function save(ctx: UserCtx) { } } - const response: any = { + const response: CreateDatasourceResponse = { datasource: await sdk.datasources.removeSecretSingle(datasource), } if (schemaError) { diff --git a/packages/server/src/db/utils.ts b/packages/server/src/db/utils.ts index 50341e4abc..e08392c3a1 100644 --- a/packages/server/src/db/utils.ts +++ b/packages/server/src/db/utils.ts @@ -27,6 +27,7 @@ export const isProdAppID = dbCore.isProdAppID export const USER_METDATA_PREFIX = `${DocumentType.ROW}${SEPARATOR}${dbCore.InternalTable.USER_METADATA}${SEPARATOR}` export const LINK_USER_METADATA_PREFIX = `${DocumentType.LINK}${SEPARATOR}${dbCore.InternalTable.USER_METADATA}${SEPARATOR}` export const TABLE_ROW_PREFIX = `${DocumentType.ROW}${SEPARATOR}${DocumentType.TABLE}` +export const AUTOMATION_LOG_PREFIX = `${DocumentType.AUTOMATION_LOG}${SEPARATOR}` export const ViewName = dbCore.ViewName export const InternalTables = dbCore.InternalTable export const UNICODE_MAX = dbCore.UNICODE_MAX diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 36285e2831..78075b4e54 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -349,7 +349,7 @@ describe("row api - postgres", () => { }, plus: true, source: "POSTGRES", - type: "datasource", + type: "datasource_plus", _id: expect.any(String), _rev: expect.any(String), createdAt: expect.any(String), diff --git a/packages/server/src/sdk/app/backups/exports.ts b/packages/server/src/sdk/app/backups/exports.ts index 27a907fceb..57342e7462 100644 --- a/packages/server/src/sdk/app/backups/exports.ts +++ b/packages/server/src/sdk/app/backups/exports.ts @@ -3,6 +3,7 @@ import { budibaseTempDir } from "../../../utilities/budibaseDir" import { streamFile, createTempFolder } from "../../../utilities/fileSystem" import { ObjectStoreBuckets } from "../../../constants" import { + AUTOMATION_LOG_PREFIX, LINK_USER_METADATA_PREFIX, TABLE_ROW_PREFIX, USER_METDATA_PREFIX, @@ -20,11 +21,15 @@ const uuid = require("uuid/v4") const tar = require("tar") const MemoryStream = require("memorystream") -type ExportOpts = { +interface DBDumpOpts { filter?: any exportPath?: string +} + +interface ExportOpts extends DBDumpOpts { tar?: boolean excludeRows?: boolean + excludeLogs?: boolean } function tarFilesToTmp(tmpDir: string, files: string[]) { @@ -49,7 +54,7 @@ function tarFilesToTmp(tmpDir: string, files: string[]) { * a filter function or the name of the export. * @return {*} either a readable stream or a string */ -export async function exportDB(dbName: string, opts: ExportOpts = {}) { +export async function exportDB(dbName: string, opts: DBDumpOpts = {}) { const exportOpts = { filter: opts?.filter, batch_size: 1000, @@ -76,11 +81,14 @@ export async function exportDB(dbName: string, opts: ExportOpts = {}) { }) } -function defineFilter(excludeRows?: boolean) { +function defineFilter(excludeRows?: boolean, excludeLogs?: boolean) { const ids = [USER_METDATA_PREFIX, LINK_USER_METADATA_PREFIX] if (excludeRows) { ids.push(TABLE_ROW_PREFIX) } + if (excludeLogs) { + ids.push(AUTOMATION_LOG_PREFIX) + } return (doc: any) => !ids.map(key => doc._id.includes(key)).reduce((prev, curr) => prev || curr) } @@ -130,8 +138,7 @@ export async function exportApp(appId: string, config?: ExportOpts) { // enforce an export of app DB to the tmp path const dbPath = join(tmpPath, DB_EXPORT_FILE) await exportDB(appId, { - ...config, - filter: defineFilter(config?.excludeRows), + filter: defineFilter(config?.excludeRows, config?.excludeLogs), exportPath: dbPath, }) // if tar requested, return where the tarball is @@ -155,6 +162,10 @@ export async function exportApp(appId: string, config?: ExportOpts) { * @returns {*} a readable stream of the backup which is written in real time */ export async function streamExportApp(appId: string, excludeRows: boolean) { - const tmpPath = await exportApp(appId, { excludeRows, tar: true }) + const tmpPath = await exportApp(appId, { + excludeRows, + excludeLogs: true, + tar: true, + }) return streamFile(tmpPath) } diff --git a/packages/shared-core/package.json b/packages/shared-core/package.json index 2d9ab33701..4ea3deea5f 100644 --- a/packages/shared-core/package.json +++ b/packages/shared-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/shared-core", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Shared data utils", "main": "dist/cjs/src/index.js", "types": "dist/mjs/src/index.d.ts", @@ -20,7 +20,7 @@ "dev:builder": "yarn prebuild && concurrently \"tsc -p tsconfig.build.json --watch\" \"tsc -p tsconfig-cjs.build.json --watch\"" }, "dependencies": { - "@budibase/types": "2.5.6-alpha.28" + "@budibase/types": "2.5.6-alpha.42" }, "devDependencies": { "concurrently": "^7.6.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index d9b9adcfbd..e1397182dc 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 76ebca7e05..3068068d4c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase types", "main": "dist/cjs/index.js", "types": "dist/mjs/index.d.ts", diff --git a/packages/types/src/api/account/license.ts b/packages/types/src/api/account/license.ts index 2ea564ea39..a867358559 100644 --- a/packages/types/src/api/account/license.ts +++ b/packages/types/src/api/account/license.ts @@ -1,4 +1,5 @@ -import { QuotaUsage } from "../../documents" +import { LicenseOverrides, QuotaUsage } from "../../documents" +import { PlanType } from "../../sdk" export interface GetLicenseRequest { // All fields should be optional to cater for @@ -20,3 +21,8 @@ export interface QuotaTriggeredRequest { export interface LicenseActivateRequest { installVersion?: string } + +export interface UpdateLicenseRequest { + planType?: PlanType + overrides?: LicenseOverrides +} diff --git a/packages/types/src/api/web/app/datasource.ts b/packages/types/src/api/web/app/datasource.ts new file mode 100644 index 0000000000..d54259eab5 --- /dev/null +++ b/packages/types/src/api/web/app/datasource.ts @@ -0,0 +1,19 @@ +import { Datasource } from "../../../documents" + +export interface CreateDatasourceResponse { + datasource: Datasource + error?: any +} + +export interface UpdateDatasourceResponse { + datasource: Datasource +} + +export interface CreateDatasourceRequest { + datasource: Datasource + fetchSchema?: boolean +} + +export interface UpdateDatasourceRequest extends Datasource { + datasource: Datasource +} diff --git a/packages/types/src/api/web/app/index.ts b/packages/types/src/api/web/app/index.ts index 1d73755cb6..9be15ecfe3 100644 --- a/packages/types/src/api/web/app/index.ts +++ b/packages/types/src/api/web/app/index.ts @@ -1 +1,2 @@ export * from "./backup" +export * from "./datasource" diff --git a/packages/types/src/documents/account/account.ts b/packages/types/src/documents/account/account.ts index 24d6606916..dad8abed30 100644 --- a/packages/types/src/documents/account/account.ts +++ b/packages/types/src/documents/account/account.ts @@ -1,4 +1,5 @@ import { Feature, Hosting, License, PlanType, Quotas } from "../../sdk" +import { DeepPartial } from "../../shared" import { QuotaUsage } from "../global" export interface CreateAccount { @@ -25,7 +26,7 @@ export const isCreatePasswordAccount = ( export interface LicenseOverrides { features?: Feature[] - quotas?: Quotas + quotas?: DeepPartial } export interface Account extends CreateAccount { @@ -38,6 +39,7 @@ export interface Account extends CreateAccount { // licensing tier: string // deprecated planType?: PlanType + /** @deprecated */ planTier?: number license?: License installId?: string @@ -46,6 +48,7 @@ export interface Account extends CreateAccount { stripeCustomerId?: string licenseKey?: string licenseKeyActivatedAt?: number + licenseRequestedAt?: number licenseOverrides?: LicenseOverrides quotaUsage?: QuotaUsage } diff --git a/packages/types/src/documents/app/query.ts b/packages/types/src/documents/app/query.ts index 72b6c288a5..31a3a3ba09 100644 --- a/packages/types/src/documents/app/query.ts +++ b/packages/types/src/documents/app/query.ts @@ -42,3 +42,10 @@ export interface PaginationValues { page: string | number | null limit: number | null } + +export interface PreviewQueryRequest extends Omit { + parameters: {} + flags?: { + urlName?: boolean + } +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index c4990f869b..0d0b166253 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -138,7 +138,6 @@ export enum Event { // LICENSE LICENSE_PLAN_CHANGED = "license:plan:changed", - LICENSE_TIER_CHANGED = "license:tier:changed", LICENSE_ACTIVATED = "license:activated", LICENSE_PAYMENT_FAILED = "license:payment:failed", LICENSE_PAYMENT_RECOVERED = "license:payment:recovered", @@ -328,7 +327,6 @@ export const AuditedEventFriendlyName: Record = { // LICENSE - NOT AUDITED [Event.LICENSE_PLAN_CHANGED]: undefined, - [Event.LICENSE_TIER_CHANGED]: undefined, [Event.LICENSE_ACTIVATED]: undefined, [Event.LICENSE_PAYMENT_FAILED]: undefined, [Event.LICENSE_PAYMENT_RECOVERED]: undefined, diff --git a/packages/types/src/sdk/events/license.ts b/packages/types/src/sdk/events/license.ts index a12fc6bbb5..b92c556cc8 100644 --- a/packages/types/src/sdk/events/license.ts +++ b/packages/types/src/sdk/events/license.ts @@ -1,15 +1,15 @@ -import { PlanType } from "../licensing" - -export interface LicenseTierChangedEvent { - accountId: string - from: number - to: number -} +import { PlanType, PriceDuration } from "../licensing" export interface LicensePlanChangedEvent { accountId: string from: PlanType to: PlanType + // may not be on historical events + // free plans won't have a duration + duration: PriceDuration | undefined + // may not be on historical events + // free plans won't have a quantity + quantity: number | undefined } export interface LicenseActivatedEvent { diff --git a/packages/types/src/sdk/licensing/plan.ts b/packages/types/src/sdk/licensing/plan.ts index 360d7d08e5..3e214a01ff 100644 --- a/packages/types/src/sdk/licensing/plan.ts +++ b/packages/types/src/sdk/licensing/plan.ts @@ -17,7 +17,6 @@ export enum PriceDuration { export interface AvailablePlan { type: PlanType maxUsers: number - minUsers: number prices: AvailablePrice[] } @@ -38,7 +37,6 @@ export interface PurchasedPlan { type: PlanType model: PlanModel usesInvoicing: boolean - minUsers: number price?: PurchasedPrice } diff --git a/packages/types/src/sdk/licensing/quota.ts b/packages/types/src/sdk/licensing/quota.ts index ea51f7a490..73afa1ed05 100644 --- a/packages/types/src/sdk/licensing/quota.ts +++ b/packages/types/src/sdk/licensing/quota.ts @@ -55,12 +55,6 @@ export const isConstantQuota = ( return quotaType === QuotaType.CONSTANT } -export interface Minimums { - users: number -} - -export type PlanMinimums = { [key in PlanType]: Minimums } - export type PlanQuotas = { [key in PlanType]: Quotas | undefined } export type MonthlyQuotas = { diff --git a/packages/types/src/shared/index.ts b/packages/types/src/shared/index.ts new file mode 100644 index 0000000000..f8f5c5cc25 --- /dev/null +++ b/packages/types/src/shared/index.ts @@ -0,0 +1 @@ +export * from "./typeUtils" diff --git a/packages/types/src/shared/typeUtils.ts b/packages/types/src/shared/typeUtils.ts new file mode 100644 index 0000000000..71fadfc7aa --- /dev/null +++ b/packages/types/src/shared/typeUtils.ts @@ -0,0 +1,3 @@ +export type DeepPartial = { + [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] +} diff --git a/packages/worker/package.json b/packages/worker/package.json index 9a4411222a..ae9358f084 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.5.6-alpha.28", + "version": "2.5.6-alpha.42", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -37,10 +37,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.5.6-alpha.28", - "@budibase/pro": "2.5.6-alpha.28", - "@budibase/string-templates": "2.5.6-alpha.28", - "@budibase/types": "2.5.6-alpha.28", + "@budibase/backend-core": "2.5.6-alpha.42", + "@budibase/pro": "2.5.6-alpha.42", + "@budibase/string-templates": "2.5.6-alpha.42", + "@budibase/types": "2.5.6-alpha.42", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 8db2d29691..d9ebc87517 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -424,7 +424,9 @@ export const inviteAccept = async ( if (err.code === ErrorCode.USAGE_LIMIT_EXCEEDED) { // explicitly re-throw limit exceeded errors ctx.throw(400, err) + return } + console.warn("Error inviting user", err) ctx.throw(400, "Unable to create new user, invitation invalid.") } } diff --git a/packages/worker/src/api/controllers/system/accounts.ts b/packages/worker/src/api/controllers/system/accounts.ts index 10b809c0b5..7e6d1b51b8 100644 --- a/packages/worker/src/api/controllers/system/accounts.ts +++ b/packages/worker/src/api/controllers/system/accounts.ts @@ -1,7 +1,7 @@ -import { Account, AccountMetadata } from "@budibase/types" +import { Account, AccountMetadata, Ctx } from "@budibase/types" import * as accounts from "../../../sdk/accounts" -export const save = async (ctx: any) => { +export const save = async (ctx: Ctx) => { const account = ctx.request.body as Account let metadata: AccountMetadata = { _id: accounts.metadata.formatAccountMetadataId(account.accountId), diff --git a/packages/worker/src/constants/templates/core.hbs b/packages/worker/src/constants/templates/core.hbs index b7f9658d8c..0b8b8cbde7 100644 --- a/packages/worker/src/constants/templates/core.hbs +++ b/packages/worker/src/constants/templates/core.hbs @@ -16,7 +16,8 @@ cellspacing="0" > Budibase Logo { diff --git a/qa-core/src/account-api/api/AccountInternalAPIClient.ts b/qa-core/src/account-api/api/AccountInternalAPIClient.ts index 7438059a8c..df58ab0ce3 100644 --- a/qa-core/src/account-api/api/AccountInternalAPIClient.ts +++ b/qa-core/src/account-api/api/AccountInternalAPIClient.ts @@ -8,6 +8,7 @@ interface ApiOptions { method?: APIMethod body?: object headers?: HeadersInit | undefined + internal?: boolean } export default class AccountInternalAPIClient { @@ -18,6 +19,9 @@ export default class AccountInternalAPIClient { if (!env.ACCOUNT_PORTAL_URL) { throw new Error("Must set ACCOUNT_PORTAL_URL env var") } + if (!env.ACCOUNT_PORTAL_API_KEY) { + throw new Error("Must set ACCOUNT_PORTAL_API_KEY env var") + } this.host = `${env.ACCOUNT_PORTAL_URL}` this.state = state } @@ -39,6 +43,13 @@ export default class AccountInternalAPIClient { credentials: "include", } + if (options.internal) { + requestOptions.headers = { + ...requestOptions.headers, + ...{ "x-budibase-api-key": env.ACCOUNT_PORTAL_API_KEY }, + } + } + // @ts-ignore const response = await fetch(`${this.host}${url}`, requestOptions) @@ -50,15 +61,20 @@ export default class AccountInternalAPIClient { body = await response.text() } - const message = `${method} ${url} - ${response.status} - Response body: ${JSON.stringify(body)} - Request body: ${requestOptions.body}` + const data = { + request: requestOptions.body, + response: body, + } + const message = `${method} ${url} - ${response.status}` if (response.status > 499) { - console.error(message) + console.error(message, data) } else if (response.status >= 400) { - console.warn(message) + console.warn(message, data) + } else { + console.debug(message, data) } + return [response, body] } diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index 080c22a4ff..f726eb5682 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -1,4 +1,6 @@ import AccountInternalAPIClient from "../AccountInternalAPIClient" +import { Account, UpdateLicenseRequest } from "@budibase/types" +import { Response } from "node-fetch" export default class LicenseAPI { client: AccountInternalAPIClient @@ -6,4 +8,18 @@ export default class LicenseAPI { constructor(client: AccountInternalAPIClient) { this.client = client } + + async updateLicense( + accountId: string, + body: UpdateLicenseRequest + ): Promise<[Response, Account]> { + const [response, json] = await this.client.put( + `/api/accounts/${accountId}/license`, + { + body, + internal: true, + } + ) + return [response, json] + } } diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts index 9377461a24..0257b10831 100644 --- a/qa-core/src/environment.ts +++ b/qa-core/src/environment.ts @@ -11,8 +11,23 @@ if (!LOADED) { const env = { BUDIBASE_URL: process.env.BUDIBASE_URL, ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL, + ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY, BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL, BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD, + POSTGRES_HOST: process.env.POSTGRES_HOST, + POSTGRES_PORT: process.env.POSTGRES_PORT, + POSTGRES_DB: process.env.POSTGRES_DB, + POSTGRES_USER: process.env.POSTGRES_USER, + POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD, + MONGODB_CONNECTION_STRING: process.env.MONGODB_CONNECTION_STRING, + MONGODB_DB: process.env.MONGODB_DB, + REST_API_BASE_URL: process.env.REST_API_BASE_URL, + REST_API_KEY: process.env.REST_API_KEY, + MARIADB_HOST: process.env.MARIADB_HOST, + MARIADB_PORT: process.env.MARIADB_PORT, + MARIADB_DB: process.env.MARIADB_DB, + MARIADB_USER: process.env.MARIADB_USER, + MARIADB_PASSWORD: process.env.MARIADB_PASSWORD, } export = env diff --git a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts b/qa-core/src/internal-api/api/BudibaseInternalAPI.ts index 5bb6b72ef0..316775b1b9 100644 --- a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts +++ b/qa-core/src/internal-api/api/BudibaseInternalAPI.ts @@ -7,6 +7,10 @@ import ScreenAPI from "./apis/ScreenAPI" import SelfAPI from "./apis/SelfAPI" import TableAPI from "./apis/TableAPI" import UserAPI from "./apis/UserAPI" +import DatasourcesAPI from "./apis/DatasourcesAPI" +import IntegrationsAPI from "./apis/IntegrationsAPI" +import QueriesAPI from "./apis/QueriesAPI" +import PermissionsAPI from "./apis/PermissionsAPI" import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient" import { State } from "../../types" @@ -22,6 +26,10 @@ export default class BudibaseInternalAPI { self: SelfAPI tables: TableAPI users: UserAPI + datasources: DatasourcesAPI + integrations: IntegrationsAPI + queries: QueriesAPI + permissions: PermissionsAPI constructor(state: State) { this.client = new BudibaseInternalAPIClient(state) @@ -35,5 +43,9 @@ export default class BudibaseInternalAPI { this.self = new SelfAPI(this.client) this.tables = new TableAPI(this.client) this.users = new UserAPI(this.client) + this.datasources = new DatasourcesAPI(this.client) + this.integrations = new IntegrationsAPI(this.client) + this.queries = new QueriesAPI(this.client) + this.permissions = new PermissionsAPI(this.client) } } diff --git a/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts b/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts index ab6c5f065e..a6921a75b2 100644 --- a/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts +++ b/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts @@ -18,7 +18,6 @@ class BudibaseInternalAPIClient { if (!env.BUDIBASE_URL) { throw new Error("Must set BUDIBASE_URL env var") } - this.host = `${env.ACCOUNT_PORTAL_URL}/api` this.host = `${env.BUDIBASE_URL}/api` this.state = state } @@ -53,14 +52,18 @@ class BudibaseInternalAPIClient { body = await response.text() } - const message = `${method} ${url} - ${response.status} - Response body: ${JSON.stringify(body)} - Request body: ${requestOptions.body}` + const data = { + request: requestOptions.body, + response: body, + } + const message = `${method} ${url} - ${response.status}` if (response.status > 499) { - console.error(message) + console.error(message, data) } else if (response.status >= 400) { - console.warn(message) + console.warn(message, data) + } else { + console.debug(message, data) } return [response, body] diff --git a/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts b/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts new file mode 100644 index 0000000000..f29bb9d6bc --- /dev/null +++ b/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts @@ -0,0 +1,95 @@ +import { Response } from "node-fetch" +import { + Datasource, + CreateDatasourceResponse, + UpdateDatasourceResponse, +} from "@budibase/types" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" + +export default class DatasourcesAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async getIntegrations(): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/integrations`) + expect(response).toHaveStatusCode(200) + const integrationsCount = Object.keys(json).length + expect(integrationsCount).toBe(16) + return [response, json] + } + + async getAll(): Promise<[Response, Datasource[]]> { + const [response, json] = await this.client.get(`/datasources`) + expect(response).toHaveStatusCode(200) + expect(json.length).toBeGreaterThan(0) + return [response, json] + } + + async getTable(dataSourceId: string): Promise<[Response, Datasource]> { + const [response, json] = await this.client.get( + `/datasources/${dataSourceId}` + ) + expect(response).toHaveStatusCode(200) + expect(json._id).toEqual(dataSourceId) + return [response, json] + } + + async add(body: any): Promise<[Response, CreateDatasourceResponse]> { + const [response, json] = await this.client.post(`/datasources`, { body }) + expect(response).toHaveStatusCode(200) + expect(json.datasource._id).toBeDefined() + expect(json.datasource._rev).toBeDefined() + + return [response, json] + } + + async update(body: any): Promise<[Response, UpdateDatasourceResponse]> { + const [response, json] = await this.client.put(`/datasources/${body._id}`, { + body, + }) + expect(response).toHaveStatusCode(200) + expect(json.datasource._id).toBeDefined() + expect(json.datasource._rev).toBeDefined() + + return [response, json] + } + + async previewQuery(body: any): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries/preview`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async saveQuery(body: any): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async getQuery(queryId: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/queries/${queryId}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async getQueryPermissions(queryId: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/permissions/${queryId}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async delete(dataSourceId: string, revId: string): Promise { + const [response, json] = await this.client.del( + `/datasources/${dataSourceId}/${revId}` + ) + expect(response).toHaveStatusCode(200) + return response + } +} diff --git a/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts b/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts new file mode 100644 index 0000000000..2478823bfa --- /dev/null +++ b/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts @@ -0,0 +1,18 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" + +export default class IntegrationsAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async getAll(): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/integrations`) + expect(response).toHaveStatusCode(200) + const integrationsCount = Object.keys(json).length + expect(integrationsCount).toBeGreaterThan(0) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/api/apis/PermissionsAPI.ts b/qa-core/src/internal-api/api/apis/PermissionsAPI.ts new file mode 100644 index 0000000000..e78ef7560d --- /dev/null +++ b/qa-core/src/internal-api/api/apis/PermissionsAPI.ts @@ -0,0 +1,16 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" + +export default class PermissionsAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async getAll(id: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/permissions/${id}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/api/apis/QueriesAPI.ts b/qa-core/src/internal-api/api/apis/QueriesAPI.ts new file mode 100644 index 0000000000..5c8ac9883e --- /dev/null +++ b/qa-core/src/internal-api/api/apis/QueriesAPI.ts @@ -0,0 +1,33 @@ +import { Response } from "node-fetch" +import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" +import { PreviewQueryRequest, Query } from "@budibase/types" + +export default class DatasourcesAPI { + client: BudibaseInternalAPIClient + + constructor(client: BudibaseInternalAPIClient) { + this.client = client + } + + async preview(body: PreviewQueryRequest): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries/preview`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async save(body: Query): Promise<[Response, any]> { + const [response, json] = await this.client.post(`/queries`, { + body, + }) + expect(response).toHaveStatusCode(200) + return [response, json] + } + + async get(queryId: string): Promise<[Response, any]> { + const [response, json] = await this.client.get(`/queries/${queryId}`) + expect(response).toHaveStatusCode(200) + return [response, json] + } +} diff --git a/qa-core/src/internal-api/fixtures/datasources.ts b/qa-core/src/internal-api/fixtures/datasources.ts new file mode 100644 index 0000000000..dcf6af824a --- /dev/null +++ b/qa-core/src/internal-api/fixtures/datasources.ts @@ -0,0 +1,71 @@ +// Add information about the data source to the fixtures file from 1password +export const mongoDB = () => { + return { + datasource: { + name: "MongoDB", + source: "MONGODB", + type: "datasource", + config: { + connectionString: process.env.MONGODB_CONNECTION_STRING, + db: process.env.MONGODB_DB, + }, + }, + + fetchSchema: false, + } +} + +export const postgresSQL = () => { + return { + datasource: { + name: "PostgresSQL", + plus: true, + source: "POSTGRES", + type: "datasource", + config: { + database: process.env.POSTGRES_DB, + host: process.env.POSTGRES_HOST, + password: process.env.POSTGRES_PASSWORD, + port: process.env.POSTGRES_PORT, + schema: "public", + user: process.env.POSTGRES_USER, + }, + }, + fetchSchema: true, + } +} +export const mariaDB = () => { + return { + datasource: { + name: "MariaDB", + plus: true, + source: "MYSQL", + type: "datasource", + config: { + database: process.env.MARIADB_DB, + host: process.env.MARIADB_HOST, + password: process.env.MARIADB_PASSWORD, + port: process.env.MARIADB_PORT, + schema: "public", + user: process.env.MARIADB_USER, + }, + }, + fetchSchema: true, + } +} + +export const restAPI = () => { + return { + datasource: { + name: "RestAPI", + source: "REST", + type: "datasource", + config: { + defaultHeaders: {}, + rejectUnauthorized: true, + url: process.env.REST_API_BASE_URL, + }, + }, + fetchSchema: false, + } +} diff --git a/qa-core/src/internal-api/fixtures/index.ts b/qa-core/src/internal-api/fixtures/index.ts index d97c5f76b7..38291052b8 100644 --- a/qa-core/src/internal-api/fixtures/index.ts +++ b/qa-core/src/internal-api/fixtures/index.ts @@ -4,3 +4,5 @@ export * as rows from "./rows" export * as screens from "./screens" export * as tables from "./tables" export * as users from "./users" +export * as datasources from "./datasources" +export * as queries from "./queries" diff --git a/qa-core/src/internal-api/fixtures/queries.ts b/qa-core/src/internal-api/fixtures/queries.ts new file mode 100644 index 0000000000..83839a0b41 --- /dev/null +++ b/qa-core/src/internal-api/fixtures/queries.ts @@ -0,0 +1,123 @@ +import { PreviewQueryRequest } from "@budibase/types" + +const query = (datasourceId: string, fields: any): any => { + return { + datasourceId: datasourceId, + fields: fields, + name: "Query 1", + parameters: {}, + queryVerb: "read", + schema: {}, + transformer: "return data", + } +} + +export const mariaDB = (datasourceId: string): PreviewQueryRequest => { + const fields = { + sql: "SELECT * FROM employees LIMIT 10;", + } + return query(datasourceId, fields) +} + +export const mongoDB = (datasourceId: string): PreviewQueryRequest => { + const fields = { + extra: { + collection: "movies", + actionType: "find", + }, + json: "", + } + return query(datasourceId, fields) +} + +export const postgres = (datasourceId: string): PreviewQueryRequest => { + const fields = { + sql: "SELECT * FROM customers;", + } + return query(datasourceId, fields) +} + +export const expectedSchemaFields = { + mariaDB: { + birth_date: "string", + emp_no: "number", + first_name: "string", + gender: "string", + hire_date: "string", + last_name: "string", + }, + mongoDB: { + directors: "array", + genres: "array", + image: "string", + plot: "string", + rank: "number", + rating: "number", + release_date: "string", + running_time_secs: "number", + title: "string", + year: "number", + _id: "json", + }, + postgres: { + address: "string", + city: "string", + company_name: "string", + contact_name: "string", + contact_title: "string", + country: "string", + customer_id: "string", + fax: "string", + phone: "string", + postal_code: "string", + region: "string", + }, + restAPI: { + abilities: "array", + base_experience: "number", + forms: "array", + game_indices: "array", + height: "number", + held_items: "array", + id: "number", + is_default: "string", + location_area_encounters: "string", + moves: "array", + name: "string", + order: "number", + past_types: "array", + species: "json", + sprites: "json", + stats: "array", + types: "array", + weight: "number", + }, +} + +const request = (datasourceId: string, fields: any, flags: any): any => { + return { + datasourceId: datasourceId, + fields: fields, + flags: flags, + name: "Query 1", + parameters: {}, + queryVerb: "read", + schema: {}, + transformer: "return data", + } +} +export const restAPI = (datasourceId: string): PreviewQueryRequest => { + const fields = { + authConfigId: null, + bodyType: "none", + disabledHeaders: {}, + headers: {}, + pagination: {}, + path: `${process.env.REST_API_BASE_URL}/pokemon/ditto`, + queryString: "", + } + const flags = { + urlName: true, + } + return request(datasourceId, fields, flags) +} diff --git a/qa-core/src/internal-api/tests/dataSources/example.spec.ts b/qa-core/src/internal-api/tests/dataSources/example.spec.ts deleted file mode 100644 index 0b8bc38a45..0000000000 --- a/qa-core/src/internal-api/tests/dataSources/example.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" - -describe("Internal API - Data Sources", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Create an app with a data source", async () => { - // Create app - await config.createApp() - - // Create Screen - const roleArray = ["BASIC", "POWER", "ADMIN", "PUBLIC"] - for (let role in roleArray) { - const [response, screen] = await config.api.screens.create( - fixtures.screens.generateScreen(roleArray[role]) - ) - } - }) -}) diff --git a/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts b/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts new file mode 100644 index 0000000000..44c2c03c8b --- /dev/null +++ b/qa-core/src/internal-api/tests/dataSources/mariaDB.spec.ts @@ -0,0 +1,69 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" + +describe("Internal API - Data Sources: MariaDB", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("Create an app with a data source - MariaDB", async () => { + // Create app + await config.createApp() + + // Get all integrations + await config.api.integrations.getAll() + + // Add data source + const [dataSourceResponse, dataSourceJson] = + await config.api.datasources.add(fixtures.datasources.mariaDB()) + + // Update data source + const newDataSourceInfo = { + ...dataSourceJson.datasource, + name: "MariaDB2", + } + const [updatedDataSourceResponse, updatedDataSourceJson] = + await config.api.datasources.update(newDataSourceInfo) + + // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!) + ) + + expect(queryJson.rows.length).toEqual(10) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.mariaDB + ) + + // Save query + const datasourcetoSave: Query = { + ...fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!), + parameters: [], + } + + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) + // Get Query + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id + ) + + // Get Query permissions + const [getQueryPermissionsResponse, getQueryPermissionsJson] = + await config.api.permissions.getAll(saveQueryJson._id!) + + // Delete data source + const deleteResponse = await config.api.datasources.delete( + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! + ) + }) +}) diff --git a/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts b/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts new file mode 100644 index 0000000000..ed5178b57c --- /dev/null +++ b/qa-core/src/internal-api/tests/dataSources/mongoDB.spec.ts @@ -0,0 +1,69 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" + +describe("Internal API - Data Sources: MongoDB", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("Create an app with a data source - MongoDB", async () => { + // Create app + await config.createApp() + + // Get all integrations + await config.api.integrations.getAll() + + // Add data source + const [dataSourceResponse, dataSourceJson] = + await config.api.datasources.add(fixtures.datasources.mongoDB()) + + // Update data source + const newDataSourceInfo = { + ...dataSourceJson.datasource, + name: "MongoDB2", + } + const [updatedDataSourceResponse, updatedDataSourceJson] = + await config.api.datasources.update(newDataSourceInfo) + + // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!) + ) + + expect(queryJson.rows.length).toBeGreaterThan(10) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.mongoDB + ) + + // Save query + const datasourcetoSave: Query = { + ...fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!), + parameters: [], + } + + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) + // Get Query + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id + ) + + // Get Query permissions + const [getQueryPermissionsResponse, getQueryPermissionsJson] = + await config.api.permissions.getAll(saveQueryJson._id!) + + // Delete data source + const deleteResponse = await config.api.datasources.delete( + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! + ) + }) +}) diff --git a/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts b/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts new file mode 100644 index 0000000000..bc8d86b862 --- /dev/null +++ b/qa-core/src/internal-api/tests/dataSources/postgresSQL.spec.ts @@ -0,0 +1,69 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" + +describe("Internal API - Data Sources: PostgresSQL", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("Create an app with a data source - PostgresSQL", async () => { + // Create app + await config.createApp() + + // Get all integrations + await config.api.integrations.getAll() + + // Add data source + const [dataSourceResponse, dataSourceJson] = + await config.api.datasources.add(fixtures.datasources.postgresSQL()) + + // Update data source + const newDataSourceInfo = { + ...dataSourceJson.datasource, + name: "PostgresSQL2", + } + const [updatedDataSourceResponse, updatedDataSourceJson] = + await config.api.datasources.update(newDataSourceInfo) + + // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.postgres(updatedDataSourceJson.datasource._id!) + ) + + expect(queryJson.rows.length).toEqual(91) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.postgres + ) + + // Save query + const datasourcetoSave: Query = { + ...fixtures.queries.postgres(updatedDataSourceJson.datasource._id!), + parameters: [], + } + + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) + // Get Query + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id! + ) + + // Get Query permissions + const [getQueryPermissionsResponse, getQueryPermissionsJson] = + await config.api.permissions.getAll(saveQueryJson._id!) + + // Delete data source + const deleteResponse = await config.api.datasources.delete( + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! + ) + }) +}) diff --git a/qa-core/src/internal-api/tests/dataSources/restAPI.spec.ts b/qa-core/src/internal-api/tests/dataSources/restAPI.spec.ts new file mode 100644 index 0000000000..d7b75db514 --- /dev/null +++ b/qa-core/src/internal-api/tests/dataSources/restAPI.spec.ts @@ -0,0 +1,69 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { Query } from "@budibase/types" + +describe("Internal API - Data Sources: REST API", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("Create an app with a data source - REST API", async () => { + // Create app + await config.createApp() + + // Get all integrations + await config.api.integrations.getAll() + + // Add data source + const [dataSourceResponse, dataSourceJson] = + await config.api.datasources.add(fixtures.datasources.restAPI()) + + // Update data source + const newDataSourceInfo = { + ...dataSourceJson.datasource, + name: "RestAPI - Updated", + } + const [updatedDataSourceResponse, updatedDataSourceJson] = + await config.api.datasources.update(newDataSourceInfo) + + // Query data source + const [queryResponse, queryJson] = await config.api.queries.preview( + fixtures.queries.restAPI(updatedDataSourceJson.datasource._id!) + ) + + expect(queryJson.rows.length).toEqual(1) + expect(queryJson.schemaFields).toEqual( + fixtures.queries.expectedSchemaFields.restAPI + ) + + // Save query + const datasourcetoSave: Query = { + ...fixtures.queries.postgres(updatedDataSourceJson.datasource._id!), + parameters: [], + } + + const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( + datasourcetoSave + ) + // Get Query + const [getQueryResponse, getQueryJson] = await config.api.queries.get( + saveQueryJson._id! + ) + + // Get Query permissions + const [getQueryPermissionsResponse, getQueryPermissionsJson] = + await config.api.permissions.getAll(saveQueryJson._id!) + + // Delete data source + const deleteResponse = await config.api.datasources.delete( + updatedDataSourceJson.datasource._id!, + updatedDataSourceJson.datasource._rev! + ) + }) +}) diff --git a/qa-core/src/jest/globalSetup.ts b/qa-core/src/jest/globalSetup.ts index a25c483173..e222e7c043 100644 --- a/qa-core/src/jest/globalSetup.ts +++ b/qa-core/src/jest/globalSetup.ts @@ -1,8 +1,8 @@ +import { DEFAULT_TENANT_ID, logging } from "@budibase/backend-core" import { AccountInternalAPI } from "../account-api" import * as fixtures from "../internal-api/fixtures" import { BudibaseInternalAPI } from "../internal-api" -import { DEFAULT_TENANT_ID, logging } from "@budibase/backend-core" -import { CreateAccountRequest } from "@budibase/types" +import { CreateAccountRequest, Feature } from "@budibase/types" import env from "../environment" import { APIRequestOpts } from "../types" @@ -22,10 +22,35 @@ async function createAccount() { const account = fixtures.accounts.generateAccount() await accountsApi.accounts.validateEmail(account.email, API_OPTS) await accountsApi.accounts.validateTenantId(account.tenantId, API_OPTS) - await accountsApi.accounts.create(account, API_OPTS) + const [res, newAccount] = await accountsApi.accounts.create(account, API_OPTS) + await updateLicense(newAccount.accountId) return account } +const UNLIMITED = { value: -1 } + +async function updateLicense(accountId: string) { + await accountsApi.licenses.updateLicense(accountId, { + overrides: { + // add all features + features: Object.values(Feature), + quotas: { + usage: { + monthly: { + automations: UNLIMITED, + }, + static: { + rows: UNLIMITED, + users: UNLIMITED, + userGroups: UNLIMITED, + plugins: UNLIMITED, + }, + }, + }, + }, + }) +} + async function loginAsAdmin() { const username = env.BB_ADMIN_USER_EMAIL! const password = env.BB_ADMIN_USER_PASSWORD! diff --git a/qa-core/src/jest/jestSetup.ts b/qa-core/src/jest/jestSetup.ts index 7f0aeddaa3..5c86d5fd24 100644 --- a/qa-core/src/jest/jestSetup.ts +++ b/qa-core/src/jest/jestSetup.ts @@ -1 +1,4 @@ +import { logging } from "@budibase/backend-core" +logging.LOG_CONTEXT = false + jest.setTimeout(60000) diff --git a/qa-core/src/public-api/api/BudibasePublicAPIClient.ts b/qa-core/src/public-api/api/BudibasePublicAPIClient.ts index d5fd6b9ef4..f4fe978812 100644 --- a/qa-core/src/public-api/api/BudibasePublicAPIClient.ts +++ b/qa-core/src/public-api/api/BudibasePublicAPIClient.ts @@ -51,14 +51,18 @@ class BudibasePublicAPIClient { body = await response.text() } - const message = `${method} ${url} - ${response.status} - Response body: ${JSON.stringify(body)} - Request body: ${requestOptions.body}` + const data = { + request: requestOptions.body, + response: body, + } + const message = `${method} ${url} - ${response.status}` if (response.status > 499) { - console.error(message) + console.error(message, data) } else if (response.status >= 400) { - console.warn(message) + console.warn(message, data) + } else { + console.debug(message, data) } return [response, body] diff --git a/qa-core/src/shared/BudibaseTestConfiguration.ts b/qa-core/src/shared/BudibaseTestConfiguration.ts index 6adc1bf5c4..12a0f16138 100644 --- a/qa-core/src/shared/BudibaseTestConfiguration.ts +++ b/qa-core/src/shared/BudibaseTestConfiguration.ts @@ -3,9 +3,6 @@ import { AccountInternalAPI } from "../account-api" import { CreateAppRequest, State } from "../types" import * as fixtures from "../internal-api/fixtures" -// TEMP -import setup from "../jest/globalSetup" - export default class BudibaseTestConfiguration { // apis internalApi: BudibaseInternalAPI @@ -23,11 +20,6 @@ export default class BudibaseTestConfiguration { // LIFECYCLE async beforeAll() { - // TEMP - move back to single tenant when we integrate licensing with - // the test run - need to use multiple tenants in cloud to get around - // app limit restrictions - await setup() - // @ts-ignore this.state.tenantId = global.qa.tenantId // @ts-ignore diff --git a/qa-core/src/types/index.ts b/qa-core/src/types/index.ts index bc75da46f8..6c3740200c 100644 --- a/qa-core/src/types/index.ts +++ b/qa-core/src/types/index.ts @@ -8,6 +8,7 @@ export * from "./responseMessage" export * from "./routing" export * from "./state" export * from "./unpublishAppResponse" +export * from "./addedDatasource" // re-export public api types export * from "@budibase/server/api/controllers/public/mapping/types" diff --git a/yarn.lock b/yarn.lock index ed87f491f1..91c6f6b135 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1386,6 +1386,45 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@budibase/backend-core@2.5.6-alpha.26": + version "2.5.6-alpha.26" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.5.6-alpha.26.tgz#72029afe5a85402fa996e92b84ad56cb8c6bde45" + integrity sha512-ktP2SWwLjaDzJYLnadU1BcZlrfQkvhRb3T+v1SEciTBWi0vF7MUa7k5OW0EKwECpGA3VA576sbI7FgGu7m7Sxw== + dependencies: + "@budibase/nano" "10.1.2" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.5.6-alpha.26" + "@shopify/jest-koa-mocks" "5.0.1" + "@techpass/passport-openidconnect" "0.3.2" + aws-cloudfront-sign "2.2.0" + aws-sdk "2.1030.0" + bcrypt "5.0.1" + bcryptjs "2.4.3" + bull "4.10.1" + correlation-id "4.0.0" + dotenv "16.0.1" + emitter-listener "1.1.2" + ioredis "4.28.0" + joi "17.6.0" + jsonwebtoken "9.0.0" + koa-passport "4.1.4" + koa-pino-logger "4.0.0" + lodash "4.17.21" + lodash.isarguments "3.1.0" + node-fetch "2.6.7" + passport-google-oauth "2.0.0" + passport-jwt "4.0.0" + passport-local "1.0.0" + passport-oauth2-refresh "^2.1.0" + posthog-node "1.3.0" + pouchdb "7.3.0" + pouchdb-find "7.2.2" + redlock "4.2.0" + sanitize-s3-objectkey "0.0.1" + semver "7.3.7" + tar-fs "2.1.1" + uuid "8.3.2" + "@budibase/bbui@^0.9.139": version "0.9.190" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.190.tgz#e1ec400ac90f556bfbc80fc23a04506f1585ea81" @@ -1486,15 +1525,15 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.5.6-alpha.28": - version "2.5.6-alpha.28" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.5.6-alpha.28.tgz#54af46014c08c570ffd4f347cc56c1b9e1226304" - integrity sha512-12ZGhTXoZRCmVbxHcOO78aOuAml7S3/NGy063c3ZQUyPJoAi3O+rokj0yDb0t7TAgs06gkiiFUumMhWn35Jaxw== +"@budibase/pro@2.5.6-alpha.42": + version "2.5.6-alpha.42" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.5.6-alpha.42.tgz#15ec86d9918b7d58e3236240afda31309f3162ae" + integrity sha512-aes19IVAEGqf0YPLJMnOKHv99AR6LO8jMpPVCbSZcZODS3byxh9kC2+sWH1mAd781zymyN79HnwGrVJNOdV8jw== dependencies: - "@budibase/backend-core" "2.5.6-alpha.28" + "@budibase/backend-core" "2.5.6-alpha.42" "@budibase/shared-core" "2.4.44-alpha.1" "@budibase/string-templates" "2.4.44-alpha.1" - "@budibase/types" "2.5.6-alpha.28" + "@budibase/types" "2.5.6-alpha.42" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1547,6 +1586,13 @@ resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.44-alpha.1.tgz#1679657aa180d9c59afa1dffa611bff0638bd933" integrity sha512-Sq+8HfM75EBMoOvKYFwELdlxmVN6wNZMofDjT/2G+9aF+Zfe5Tzw69C+unmdBgcGGjGCHEYWSz4mF0v8FPAGbg== +"@budibase/types@2.5.6-alpha.26": + version "2.5.6-alpha.26" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.5.6-alpha.26.tgz#09ac8f1e4f4dfd5e7e109839cd9db36d5c563dc4" + integrity sha512-C1eHWj4tRwsQb2dJbMdukxRFVqiyzRBhwIMuCSIdJg763sbn9TXTqWTBbljyG7ppH+Dwge+py9KtiFP2MpMCfQ== + dependencies: + scim-patch "^0.7.0" + "@bull-board/api@3.7.0": version "3.7.0" resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-3.7.0.tgz#231f687187c0cb34e0b97f463917b6aaeb4ef6af" @@ -3007,7 +3053,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -3717,7 +3763,7 @@ dependencies: slash "^3.0.0" -"@rollup/plugin-commonjs@^16.0.0": +"@rollup/plugin-commonjs@16.0.0", "@rollup/plugin-commonjs@^16.0.0": version "16.0.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f" integrity sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw== @@ -3800,6 +3846,22 @@ "@rollup/pluginutils" "^3.1.0" magic-string "^0.25.7" +"@rollup/plugin-replace@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz#45f53501b16311feded2485e98419acb8448c61d" + integrity sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA== + dependencies: + "@rollup/pluginutils" "^5.0.1" + magic-string "^0.27.0" + +"@rollup/plugin-typescript@8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz#bc1077fa5897b980fc27e376c4e377882c63e68b" + integrity sha512-I5FpSvLbtAdwJ+naznv+B4sjXZUcIvLLceYpITAn7wAP8W0wqc5noLdGIp9HGVntNhRWXctwPYrSSFQxtl0FPA== + dependencies: + "@rollup/pluginutils" "^3.1.0" + resolve "^1.17.0" + "@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" @@ -11129,7 +11191,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-redact@^3.0.0: +fast-redact@^3.0.0, fast-redact@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa" integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw== @@ -11698,7 +11760,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -16688,6 +16750,13 @@ magic-string@^0.26.2: dependencies: sourcemap-codec "^1.4.8" +magic-string@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" + integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + make-dir@3.1.0, make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -19203,7 +19272,7 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -pino-abstract-transport@^1.0.0: +pino-abstract-transport@^1.0.0, pino-abstract-transport@v1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== @@ -19219,6 +19288,16 @@ pino-abstract-transport@v0.5.0: duplexify "^4.1.2" split2 "^4.0.0" +pino-http@8.3.3: + version "8.3.3" + resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-8.3.3.tgz#2b140e734bfc6babe0df272a43bb8f36f2b525c0" + integrity sha512-p4umsNIXXVu95HD2C8wie/vXH7db5iGRpc+yj1/ZQ3sRtTQLXNjoS6Be5+eI+rQbqCRxen/7k/KSN+qiZubGDw== + dependencies: + get-caller-file "^2.0.5" + pino "^8.0.0" + pino-std-serializers "^6.0.0" + process-warning "^2.0.0" + pino-http@^6.5.0: version "6.6.0" resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-6.6.0.tgz#d0a1deacada8c93327fdaa48f5bdc94bc43d3407" @@ -19264,7 +19343,42 @@ pino-std-serializers@^5.0.0: resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-5.6.0.tgz#31b141155d6520967c5ec72944d08fb45c490fd3" integrity sha512-VdUXCw8gO+xhir7sFuoYSjTnzB+TMDGxhAC/ph3YS3sdHnXNdsK0wMtADNUltfeGkn2KDxEM21fnjF3RwXyC8A== -pino@7.11.0, pino@^7.5.0: +pino-std-serializers@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.0.tgz#169048c0df3f61352fce56aeb7fb962f1b66ab43" + integrity sha512-IWgSzUL8X1w4BIWTwErRgtV8PyOGOOi60uqv0oKuS/fOA8Nco/OeI6lBuc4dyP8MMfdFwyHqTMcBIA7nDiqEqA== + +pino@8.11.0, pino@^8.0.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-8.11.0.tgz#2a91f454106b13e708a66c74ebc1c2ab7ab38498" + integrity sha512-Z2eKSvlrl2rH8p5eveNUnTdd4AjJk8tAsLkHYZQKGHP4WTh2Gi1cOSOs3eWPqaj+niS3gj4UkoreoaWgF3ZWYg== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.1.1" + on-exit-leak-free "^2.1.0" + pino-abstract-transport v1.0.0 + pino-std-serializers "^6.0.0" + process-warning "^2.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^3.1.0" + thread-stream "^2.0.0" + +pino@^6.11.2: + version "6.14.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78" + integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== + dependencies: + fast-redact "^3.0.0" + fast-safe-stringify "^2.0.8" + flatstr "^1.0.12" + pino-std-serializers "^3.1.0" + process-warning "^1.0.0" + quick-format-unescaped "^4.0.3" + sonic-boom "^1.0.2" + +pino@^7.5.0: version "7.11.0" resolved "https://registry.yarnpkg.com/pino/-/pino-7.11.0.tgz#0f0ea5c4683dc91388081d44bff10c83125066f6" integrity sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg== @@ -19281,19 +19395,6 @@ pino@7.11.0, pino@^7.5.0: sonic-boom "^2.2.1" thread-stream "^0.15.1" -pino@^6.11.2: - version "6.14.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78" - integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== - dependencies: - fast-redact "^3.0.0" - fast-safe-stringify "^2.0.8" - flatstr "^1.0.12" - pino-std-serializers "^3.1.0" - process-warning "^1.0.0" - quick-format-unescaped "^4.0.3" - sonic-boom "^1.0.2" - pirates@^4.0.1, pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" @@ -20169,6 +20270,11 @@ process-warning@^1.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== +process-warning@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626" + integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg== + process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" @@ -20772,6 +20878,11 @@ real-require@^0.1.0: resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + recast@^0.10.1: version "0.10.43" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" @@ -21417,6 +21528,13 @@ rollup-pluginutils@^2.3.1, rollup-pluginutils@^2.5.0, rollup-pluginutils@^2.6.0, dependencies: estree-walker "^0.6.1" +rollup@2.45.2: + version "2.45.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48" + integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ== + optionalDependencies: + fsevents "~2.3.1" + rollup@^2.36.2, rollup@^2.44.0, rollup@^2.45.2, rollup@^2.79.1: version "2.79.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" @@ -22151,7 +22269,7 @@ sonic-boom@^2.2.1: dependencies: atomic-sleep "^1.0.0" -sonic-boom@^3.0.0: +sonic-boom@^3.0.0, sonic-boom@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.3.0.tgz#cffab6dafee3b2bcb88d08d589394198bee1838c" integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g== @@ -23323,6 +23441,13 @@ thread-stream@^0.15.1: dependencies: real-require "^0.1.0" +thread-stream@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33" + integrity sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA== + dependencies: + real-require "^0.2.0" + throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -23379,7 +23504,7 @@ timed-out@^4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== -timekeeper@2.2.0: +timekeeper@2.2.0, timekeeper@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368" integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==