Merge branch 'master' of github.com:Budibase/budibase into feature/sql-query-aliasing

This commit is contained in:
mike12345567 2024-02-19 16:29:29 +00:00
commit 19090dd547
487 changed files with 10499 additions and 4811 deletions

View File

@ -10,4 +10,5 @@ packages/builder/.routify
packages/sdk/sdk packages/sdk/sdk
packages/account-portal/packages/server/build packages/account-portal/packages/server/build
packages/account-portal/packages/ui/.routify packages/account-portal/packages/ui/.routify
packages/account-portal/packages/ui/build packages/account-portal/packages/ui/build
**/*.ivm.bundle.js

View File

@ -43,7 +43,8 @@
"no-useless-escape": "off", "no-useless-escape": "off",
"no-undef": "off", "no-undef": "off",
"no-prototype-builtins": "off", "no-prototype-builtins": "off",
"local-rules/no-budibase-imports": "error" "local-rules/no-budibase-imports": "error",
"local-rules/no-test-com": "error"
} }
}, },
{ {
@ -53,7 +54,7 @@
"packages/frontend-core/**/*" "packages/frontend-core/**/*"
], ],
"rules": { "rules": {
"no-console": ["error", { "allow": ["warn", "error", "debug"] } ] "no-console": ["error", { "allow": ["warn", "error", "debug"] }]
} }
} }
], ],

View File

@ -11,4 +11,5 @@ packages/sdk/sdk
packages/pro/coverage packages/pro/coverage
packages/account-portal/packages/ui/build packages/account-portal/packages/ui/build
packages/account-portal/packages/ui/.routify packages/account-portal/packages/ui/.routify
packages/account-portal/packages/server/build packages/account-portal/packages/server/build
**/*.ivm.bundle.js

View File

@ -18,4 +18,37 @@ module.exports = {
} }
}, },
}, },
"no-test-com": {
meta: {
type: "problem",
docs: {
description:
"disallow the use of 'test.com' in strings and replace it with 'example.com'",
category: "Possible Errors",
recommended: false,
},
schema: [], // no options
fixable: "code", // Indicates that this rule supports automatic fixing
},
create: function (context) {
return {
Literal(node) {
if (
typeof node.value === "string" &&
node.value.includes("test.com")
) {
context.report({
node,
message:
"test.com is a privately owned domain and could point anywhere, use example.com instead.",
fix: function (fixer) {
const newText = node.raw.replace(/test\.com/g, "example.com")
return fixer.replaceText(node, newText)
},
})
}
},
}
},
},
} }

View File

@ -98,7 +98,6 @@ services:
couchdb-service: couchdb-service:
restart: unless-stopped restart: unless-stopped
image: budibase/couchdb image: budibase/couchdb
pull_policy: always
environment: environment:
- COUCHDB_PASSWORD=${COUCH_DB_PASSWORD} - COUCHDB_PASSWORD=${COUCH_DB_PASSWORD}
- COUCHDB_USER=${COUCH_DB_USER} - COUCHDB_USER=${COUCH_DB_USER}

View File

@ -124,6 +124,8 @@ HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh
# must set this just before running # must set this just before running
ENV NODE_ENV=production ENV NODE_ENV=production
# this is required for isolated-vm to work on Node 20+
ENV NODE_OPTIONS="--no-node-snapshot"
WORKDIR / WORKDIR /
CMD ["./runner.sh"] CMD ["./runner.sh"]

View File

@ -1,5 +1,5 @@
{ {
"version": "2.17.3", "version": "2.19.6",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*", "packages/*",

View File

@ -58,7 +58,7 @@
"lint": "yarn run lint:eslint && yarn run lint:prettier", "lint": "yarn run lint:eslint && yarn run lint:prettier",
"lint:fix:eslint": "eslint --fix --max-warnings=0 packages qa-core", "lint:fix:eslint": "eslint --fix --max-warnings=0 packages qa-core",
"lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --write \"qa-core/**/*.{js,ts,svelte}\"", "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --write \"qa-core/**/*.{js,ts,svelte}\"",
"lint:fix": "yarn run lint:fix:prettier && yarn run lint:fix:eslint", "lint:fix": "yarn run lint:fix:eslint && yarn run lint:fix:prettier",
"build:specs": "lerna run --stream specs", "build:specs": "lerna run --stream specs",
"build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild", "build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild",
"build:docker:airgap:single": "SINGLE_IMAGE=1 node hosting/scripts/airgapped/airgappedDockerBuild", "build:docker:airgap:single": "SINGLE_IMAGE=1 node hosting/scripts/airgapped/airgappedDockerBuild",
@ -97,7 +97,16 @@
"@budibase/backend-core": "0.0.0", "@budibase/backend-core": "0.0.0",
"@budibase/shared-core": "0.0.0", "@budibase/shared-core": "0.0.0",
"@budibase/string-templates": "0.0.0", "@budibase/string-templates": "0.0.0",
"@budibase/types": "0.0.0" "@budibase/types": "0.0.0",
"tough-cookie": "4.1.3",
"node-fetch": "2.6.7",
"semver": "7.5.3",
"http-cache-semantics": "4.1.1",
"msgpackr": "1.10.1",
"axios": "1.6.3",
"xml2js": "0.6.2",
"unset-value": "2.0.1",
"passport": "0.6.0"
}, },
"engines": { "engines": {
"node": ">=20.0.0 <21.0.0" "node": ">=20.0.0 <21.0.0"

@ -1 +1 @@
Subproject commit cc12291732ee902dc832bc7d93cf2086ffdf0cff Subproject commit 8c446c4ba385592127fa31755d3b64467b291882

View File

@ -25,19 +25,19 @@
"@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/pouchdb-replication-stream": "1.2.10",
"@budibase/shared-core": "0.0.0", "@budibase/shared-core": "0.0.0",
"@budibase/types": "0.0.0", "@budibase/types": "0.0.0",
"@techpass/passport-openidconnect": "0.3.2", "@govtechsg/passport-openidconnect": "^1.0.2",
"aws-cloudfront-sign": "3.0.2", "aws-cloudfront-sign": "3.0.2",
"aws-sdk": "2.1030.0", "aws-sdk": "2.1030.0",
"bcrypt": "5.1.0", "bcrypt": "5.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"bull": "4.10.1", "bull": "4.10.1",
"correlation-id": "4.0.0", "correlation-id": "4.0.0",
"dd-trace": "5.0.0", "dd-trace": "5.2.0",
"dotenv": "16.0.1", "dotenv": "16.0.1",
"ioredis": "5.3.2", "ioredis": "5.3.2",
"joi": "17.6.0", "joi": "17.6.0",
"jsonwebtoken": "9.0.2", "jsonwebtoken": "9.0.2",
"koa-passport": "4.1.4", "koa-passport": "^6.0.0",
"koa-pino-logger": "4.0.0", "koa-pino-logger": "4.0.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"node-fetch": "2.6.7", "node-fetch": "2.6.7",
@ -52,9 +52,9 @@
"redlock": "4.2.0", "redlock": "4.2.0",
"rotating-file-stream": "3.1.0", "rotating-file-stream": "3.1.0",
"sanitize-s3-objectkey": "0.0.1", "sanitize-s3-objectkey": "0.0.1",
"semver": "7.3.7", "semver": "^7.5.4",
"tar-fs": "2.1.1", "tar-fs": "2.1.1",
"uuid": "8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@shopify/jest-koa-mocks": "5.1.1", "@shopify/jest-koa-mocks": "5.1.1",

View File

@ -1,4 +1,4 @@
import { IdentityContext } from "@budibase/types" import { IdentityContext, VM } from "@budibase/types"
import { ExecutionTimeTracker } from "../timers" import { ExecutionTimeTracker } from "../timers"
// keep this out of Budibase types, don't want to expose context info // keep this out of Budibase types, don't want to expose context info
@ -11,4 +11,5 @@ export type ContextMap = {
automationId?: string automationId?: string
isMigrating?: boolean isMigrating?: boolean
jsExecutionTracker?: ExecutionTimeTracker jsExecutionTracker?: ExecutionTimeTracker
vm?: VM
} }

View File

@ -3,6 +3,7 @@ import {
Event, Event,
Datasource, Datasource,
Query, Query,
QueryPreview,
QueryCreatedEvent, QueryCreatedEvent,
QueryUpdatedEvent, QueryUpdatedEvent,
QueryDeletedEvent, QueryDeletedEvent,
@ -68,9 +69,9 @@ const run = async (count: number, timestamp?: string | number) => {
await publishEvent(Event.QUERIES_RUN, properties, timestamp) await publishEvent(Event.QUERIES_RUN, properties, timestamp)
} }
const previewed = async (datasource: Datasource, query: Query) => { const previewed = async (datasource: Datasource, query: QueryPreview) => {
const properties: QueryPreviewedEvent = { const properties: QueryPreviewedEvent = {
queryId: query._id, queryId: query.queryId,
datasourceId: datasource._id as string, datasourceId: datasource._id as string,
source: datasource.source, source: datasource.source,
queryVerb: query.queryVerb, queryVerb: query.queryVerb,

View File

@ -6,6 +6,7 @@ import * as context from "./context"
import semver from "semver" import semver from "semver"
import { bustCache, withCache, TTL, CacheKey } from "./cache/generic" import { bustCache, withCache, TTL, CacheKey } from "./cache/generic"
import environment from "./environment" import environment from "./environment"
import { logAlert } from "./logging"
export const getInstall = async (): Promise<Installation> => { export const getInstall = async (): Promise<Installation> => {
return withCache(CacheKey.INSTALLATION, TTL.ONE_DAY, getInstallFromDB, { return withCache(CacheKey.INSTALLATION, TTL.ONE_DAY, getInstallFromDB, {
@ -80,27 +81,35 @@ export const checkInstallVersion = async (): Promise<void> => {
const currentVersion = install.version const currentVersion = install.version
const newVersion = environment.VERSION const newVersion = environment.VERSION
if (currentVersion !== newVersion) { try {
const isUpgrade = semver.gt(newVersion, currentVersion) if (currentVersion !== newVersion) {
const isDowngrade = semver.lt(newVersion, currentVersion) const isUpgrade = semver.gt(newVersion, currentVersion)
const isDowngrade = semver.lt(newVersion, currentVersion)
const success = await updateVersion(newVersion) const success = await updateVersion(newVersion)
if (success) { if (success) {
await context.doInIdentityContext( await context.doInIdentityContext(
{ {
_id: install.installId, _id: install.installId,
type: IdentityType.INSTALLATION, type: IdentityType.INSTALLATION,
}, },
async () => { async () => {
if (isUpgrade) { if (isUpgrade) {
await events.installation.upgraded(currentVersion, newVersion) await events.installation.upgraded(currentVersion, newVersion)
} else if (isDowngrade) { } else if (isDowngrade) {
await events.installation.downgraded(currentVersion, newVersion) await events.installation.downgraded(currentVersion, newVersion)
}
} }
} )
) await events.identification.identifyInstallationGroup(install.installId)
await events.identification.identifyInstallationGroup(install.installId) }
}
} catch (err: any) {
if (err?.message?.includes("Invalid Version")) {
logAlert(`Invalid version "${newVersion}" - is it semver?`)
} else {
logAlert("Failed to retrieve version", err)
} }
} }
} }

View File

@ -2,11 +2,12 @@ import { Header } from "../../constants"
const correlator = require("correlation-id") const correlator = require("correlation-id")
export const setHeader = (headers: any) => { export const setHeader = (headers: Record<string, string>) => {
const correlationId = correlator.getId() const correlationId = correlator.getId()
if (correlationId) { if (!correlationId) {
headers[Header.CORRELATION_ID] = correlationId return
} }
headers[Header.CORRELATION_ID] = correlationId
} }
export function getId() { export function getId() {

View File

@ -255,7 +255,8 @@ export async function listAllObjects(bucketName: string, path: string) {
objects = objects.concat(response.Contents) objects = objects.concat(response.Contents)
} }
isTruncated = !!response.IsTruncated isTruncated = !!response.IsTruncated
} while (isTruncated) token = response.NextContinuationToken
} while (isTruncated && token)
return objects return objects
} }

View File

@ -2,7 +2,7 @@ import env from "../environment"
import { getRedisOptions } from "../redis/utils" import { getRedisOptions } from "../redis/utils"
import { JobQueue } from "./constants" import { JobQueue } from "./constants"
import InMemoryQueue from "./inMemoryQueue" import InMemoryQueue from "./inMemoryQueue"
import BullQueue, { QueueOptions } from "bull" import BullQueue, { QueueOptions, JobOptions } from "bull"
import { addListeners, StalledFn } from "./listeners" import { addListeners, StalledFn } from "./listeners"
import { Duration } from "../utils" import { Duration } from "../utils"
import * as timers from "../timers" import * as timers from "../timers"
@ -24,17 +24,24 @@ async function cleanup() {
export function createQueue<T>( export function createQueue<T>(
jobQueue: JobQueue, jobQueue: JobQueue,
opts: { removeStalledCb?: StalledFn } = {} opts: {
removeStalledCb?: StalledFn
maxStalledCount?: number
jobOptions?: JobOptions
} = {}
): BullQueue.Queue<T> { ): BullQueue.Queue<T> {
const redisOpts = getRedisOptions() const redisOpts = getRedisOptions()
const queueConfig: QueueOptions = { const queueConfig: QueueOptions = {
redis: redisOpts, redis: redisOpts,
settings: { settings: {
maxStalledCount: 0, maxStalledCount: opts.maxStalledCount ? opts.maxStalledCount : 0,
lockDuration: QUEUE_LOCK_MS, lockDuration: QUEUE_LOCK_MS,
lockRenewTime: QUEUE_LOCK_RENEW_INTERNAL_MS, lockRenewTime: QUEUE_LOCK_RENEW_INTERNAL_MS,
}, },
} }
if (opts.jobOptions) {
queueConfig.defaultJobOptions = opts.jobOptions
}
let queue: any let queue: any
if (!env.isTest()) { if (!env.isTest()) {
queue = new BullQueue(jobQueue, queueConfig) queue = new BullQueue(jobQueue, queueConfig)

View File

@ -44,11 +44,11 @@ describe("utils", () => {
it("gets appId from url", async () => { it("gets appId from url", async () => {
await config.doInTenant(async () => { await config.doInTenant(async () => {
const url = "http://test.com" const url = "http://example.com"
env._set("PLATFORM_URL", url) env._set("PLATFORM_URL", url)
const ctx = structures.koa.newContext() const ctx = structures.koa.newContext()
ctx.host = `${config.tenantId}.test.com` ctx.host = `${config.tenantId}.example.com`
const expected = db.generateAppID(config.tenantId) const expected = db.generateAppID(config.tenantId)
const app = structures.apps.app(expected) const app = structures.apps.app(expected)
@ -89,7 +89,7 @@ describe("utils", () => {
const ctx = structures.koa.newContext() const ctx = structures.koa.newContext()
const expected = db.generateAppID() const expected = db.generateAppID()
ctx.request.headers = { ctx.request.headers = {
referer: `http://test.com/builder/app/${expected}/design/screen_123/screens`, referer: `http://example.com/builder/app/${expected}/design/screen_123/screens`,
} }
const actual = await utils.getAppIdFromCtx(ctx) const actual = await utils.getAppIdFromCtx(ctx)
@ -100,7 +100,7 @@ describe("utils", () => {
const ctx = structures.koa.newContext() const ctx = structures.koa.newContext()
const appId = db.generateAppID() const appId = db.generateAppID()
ctx.request.headers = { ctx.request.headers = {
referer: `http://test.com/foo/app/${appId}/bar`, referer: `http://example.com/foo/app/${appId}/bar`,
} }
const actual = await utils.getAppIdFromCtx(ctx) const actual = await utils.getAppIdFromCtx(ctx)

View File

@ -3,5 +3,5 @@ import { v4 as uuid } from "uuid"
export { v4 as uuid } from "uuid" export { v4 as uuid } from "uuid"
export const email = () => { export const email = () => {
return `${uuid()}@test.com` return `${uuid()}@example.com`
} }

View File

@ -61,7 +61,7 @@ export function ssoProfile(user?: User): SSOProfile {
}, },
_json: { _json: {
email: user.email, email: user.email,
picture: "http://test.com", picture: "http://example.com",
}, },
provider: generator.string(), provider: generator.string(),
} }

View File

@ -25,7 +25,7 @@ export const user = (userProps?: Partial<Omit<User, "userId">>): User => {
roles: { app_test: "admin" }, roles: { app_test: "admin" },
firstName: generator.first(), firstName: generator.first(),
lastName: generator.last(), lastName: generator.last(),
pictureUrl: "http://test.com", pictureUrl: "http://example.com",
tenantId: tenant.id(), tenantId: tenant.id(),
...userProps, ...userProps,
} }

View File

@ -184,7 +184,7 @@
{#if environmentVariablesEnabled} {#if environmentVariablesEnabled}
<div on:click={() => showModal()} class="add-variable"> <div on:click={() => showModal()} class="add-variable">
<svg <svg
class="spectrum-Icon spectrum-Icon--sizeS " class="spectrum-Icon spectrum-Icon--sizeS"
focusable="false" focusable="false"
aria-hidden="true" aria-hidden="true"
> >
@ -195,7 +195,7 @@
{:else} {:else}
<div on:click={() => handleUpgradePanel()} class="add-variable"> <div on:click={() => handleUpgradePanel()} class="add-variable">
<svg <svg
class="spectrum-Icon spectrum-Icon--sizeS " class="spectrum-Icon spectrum-Icon--sizeS"
focusable="false" focusable="false"
aria-hidden="true" aria-hidden="true"
> >

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -23,7 +23,6 @@
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/fileMock.js", "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/fileMock.js",
"\\.(css|less|sass|scss)$": "identity-obj-proxy", "\\.(css|less|sass|scss)$": "identity-obj-proxy",
"components(.*)$": "<rootDir>/src/components$1", "components(.*)$": "<rootDir>/src/components$1",
"builderStore(.*)$": "<rootDir>/src/builderStore$1",
"stores(.*)$": "<rootDir>/src/stores$1", "stores(.*)$": "<rootDir>/src/stores$1",
"analytics(.*)$": "<rootDir>/src/analytics$1", "analytics(.*)$": "<rootDir>/src/analytics$1",
"constants/backend": "<rootDir>/src/constants/backend/index.js" "constants/backend": "<rootDir>/src/constants/backend/index.js"

View File

@ -3,14 +3,14 @@ import {
CookieUtils, CookieUtils,
Constants, Constants,
} from "@budibase/frontend-core" } from "@budibase/frontend-core"
import { store } from "./builderStore" import { appStore } from "stores/builder"
import { get } from "svelte/store" import { get } from "svelte/store"
import { auth, navigation } from "./stores/portal" import { auth, navigation } from "./stores/portal"
export const API = createAPIClient({ export const API = createAPIClient({
attachHeaders: headers => { attachHeaders: headers => {
// Attach app ID header from store // Attach app ID header from store
let appId = get(store).appId let appId = get(appStore).appId
if (appId) { if (appId) {
headers["x-budibase-app-id"] = appId headers["x-budibase-app-id"] = appId
} }

View File

@ -1,158 +0,0 @@
import { getFrontendStore } from "./store/frontend"
import { getAutomationStore } from "./store/automation"
import { getTemporalStore } from "./store/temporal"
import { getThemeStore } from "./store/theme"
import { getUserStore } from "./store/users"
import { getDeploymentStore } from "./store/deployments"
import { derived, get } from "svelte/store"
import { findComponent, findComponentPath } from "./componentUtils"
import { RoleUtils } from "@budibase/frontend-core"
import { createHistoryStore } from "builderStore/store/history"
import { cloneDeep } from "lodash/fp"
import { getHoverStore } from "./store/hover"
export const store = getFrontendStore()
export const automationStore = getAutomationStore()
export const themeStore = getThemeStore()
export const temporalStore = getTemporalStore()
export const userStore = getUserStore()
export const deploymentStore = getDeploymentStore()
export const hoverStore = getHoverStore()
// Setup history for screens
export const screenHistoryStore = createHistoryStore({
getDoc: id => get(store).screens?.find(screen => screen._id === id),
selectDoc: store.actions.screens.select,
afterAction: () => {
// Ensure a valid component is selected
if (!get(selectedComponent)) {
store.update(state => ({
...state,
selectedComponentId: get(selectedScreen)?.props._id,
}))
}
},
})
store.actions.screens.save = screenHistoryStore.wrapSaveDoc(
store.actions.screens.save
)
store.actions.screens.delete = screenHistoryStore.wrapDeleteDoc(
store.actions.screens.delete
)
// Setup history for automations
export const automationHistoryStore = createHistoryStore({
getDoc: automationStore.actions.getDefinition,
selectDoc: automationStore.actions.select,
})
automationStore.actions.save = automationHistoryStore.wrapSaveDoc(
automationStore.actions.save
)
automationStore.actions.delete = automationHistoryStore.wrapDeleteDoc(
automationStore.actions.delete
)
export const selectedScreen = derived(store, $store => {
return $store.screens.find(screen => screen._id === $store.selectedScreenId)
})
export const selectedLayout = derived(store, $store => {
return $store.layouts?.find(layout => layout._id === $store.selectedLayoutId)
})
export const selectedComponent = derived(
[store, selectedScreen],
([$store, $selectedScreen]) => {
if (
$selectedScreen &&
$store.selectedComponentId?.startsWith(`${$selectedScreen._id}-`)
) {
return $selectedScreen?.props
}
if (!$selectedScreen || !$store.selectedComponentId) {
return null
}
const selected = findComponent(
$selectedScreen?.props,
$store.selectedComponentId
)
const clone = selected ? cloneDeep(selected) : selected
store.actions.components.migrateSettings(clone)
return clone
}
)
// For legacy compatibility only, but with the new design UI this is just
// the selected screen
export const currentAsset = selectedScreen
export const sortedScreens = derived(store, $store => {
return $store.screens.slice().sort((a, b) => {
// Sort by role first
const roleA = RoleUtils.getRolePriority(a.routing.roleId)
const roleB = RoleUtils.getRolePriority(b.routing.roleId)
if (roleA !== roleB) {
return roleA > roleB ? -1 : 1
}
// Then put home screens first
const homeA = !!a.routing.homeScreen
const homeB = !!b.routing.homeScreen
if (homeA !== homeB) {
return homeA ? -1 : 1
}
// Then sort alphabetically by each URL param
const aParams = a.routing.route.split("/")
const bParams = b.routing.route.split("/")
let minParams = Math.min(aParams.length, bParams.length)
for (let i = 0; i < minParams; i++) {
if (aParams[i] === bParams[i]) {
continue
}
return aParams[i] < bParams[i] ? -1 : 1
}
// Then sort by the fewest amount of URL params
return aParams.length < bParams.length ? -1 : 1
})
})
export const selectedComponentPath = derived(
[store, selectedScreen],
([$store, $selectedScreen]) => {
return findComponentPath(
$selectedScreen?.props,
$store.selectedComponentId
).map(component => component._id)
}
)
// Derived automation state
export const selectedAutomation = derived(automationStore, $automationStore => {
if (!$automationStore.selectedAutomationId) {
return null
}
return $automationStore.automations?.find(
x => x._id === $automationStore.selectedAutomationId
)
})
// Derive map of resource IDs to other users.
// We only ever care about a single user in each resource, so if multiple users
// share the same datasource we can just overwrite them.
export const userSelectedResourceMap = derived(userStore, $userStore => {
let map = {}
$userStore.forEach(user => {
const resource = user.builderMetadata?.selectedResourceId
if (resource) {
if (!map[resource]) {
map[resource] = []
}
map[resource].push(user)
}
})
return map
})
export const isOnlyUser = derived(userStore, $userStore => {
return $userStore.length < 2
})

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
import { get, writable } from "svelte/store"
import { store as builder } from "builderStore"
export const getHoverStore = () => {
const initialValue = {
componentId: null,
}
const store = writable(initialValue)
const update = (componentId, notifyClient = true) => {
if (componentId === get(store).componentId) {
return
}
store.update(state => {
state.componentId = componentId
return state
})
if (notifyClient) {
builder.actions.preview.sendEvent("hover-component", componentId)
}
}
return {
subscribe: store.subscribe,
actions: { update },
}
}

View File

@ -1,545 +0,0 @@
import { expect, describe, it, vi } from "vitest"
import {
runtimeToReadableBinding,
readableToRuntimeBinding,
updateReferencesInObject,
} from "../dataBinding"
vi.mock("@budibase/frontend-core")
vi.mock("builderStore/componentUtils")
vi.mock("builderStore/store")
vi.mock("builderStore/store/theme")
vi.mock("builderStore/store/temporal")
describe("runtimeToReadableBinding", () => {
const bindableProperties = [
{
category: "Current User",
icon: "User",
providerId: "user",
readableBinding: "Current User.firstName",
runtimeBinding: "[user].[firstName]",
type: "context",
},
{
category: "Bindings",
icon: "Brackets",
readableBinding: "Binding.count",
runtimeBinding: "count",
type: "context",
},
]
it("should convert a runtime binding to a readable one", () => {
const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ count }}.`
expect(
runtimeToReadableBinding(
bindableProperties,
textWithBindings,
"readableBinding"
)
).toEqual(
`Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
)
})
it("should not convert to readable binding if it is already readable", () => {
const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ Binding.count }}.`
expect(
runtimeToReadableBinding(
bindableProperties,
textWithBindings,
"readableBinding"
)
).toEqual(
`Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
)
})
})
describe("readableToRuntimeBinding", () => {
const bindableProperties = [
{
category: "Current User",
icon: "User",
providerId: "user",
readableBinding: "Current User.firstName",
runtimeBinding: "[user].[firstName]",
type: "context",
},
{
category: "Bindings",
icon: "Brackets",
readableBinding: "Binding.count",
runtimeBinding: "count",
type: "context",
},
]
it("should convert a readable binding to a runtime one", () => {
const textWithBindings = `Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
expect(
readableToRuntimeBinding(
bindableProperties,
textWithBindings,
"runtimeBinding"
)
).toEqual(`Hello {{ [user].[firstName] }}! The count is {{ count }}.`)
})
})
describe("updateReferencesInObject", () => {
it("should increment steps in sequence on 'add'", () => {
let obj = [
{
id: "a0",
parameters: {
text: "Alpha",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "add",
label: "actions",
})
expect(obj).toEqual([
{
id: "a0",
parameters: {
text: "Alpha",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.2.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.2.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.4.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.5.row }}",
},
},
])
})
it("should decrement steps in sequence on 'delete'", () => {
let obj = [
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "delete",
label: "actions",
})
expect(obj).toEqual([
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
])
})
it("should handle on 'move' to a lower index", () => {
let obj = [
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 4,
})
expect(obj).toEqual([
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
])
})
it("should handle on 'move' to a higher index", () => {
let obj = [
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 0,
})
expect(obj).toEqual([
{
id: "b2",
parameters: {
text: "Banana {{ actions.2.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.2.row }}",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.1.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
])
})
it("should handle on 'move' of action being referenced, dragged to a higher index", () => {
let obj = [
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.1.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 1,
})
expect(obj).toEqual([
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.2.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
])
})
it("should handle on 'move' of action being referenced, dragged to a lower index", () => {
let obj = [
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.4.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
]
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "move",
label: "actions",
originalIndex: 4,
})
expect(obj).toEqual([
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.0.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
])
})
})

View File

@ -1,5 +1,5 @@
<script> <script>
import { selectedAutomation } from "builderStore" import { selectedAutomation } from "stores/builder"
import Flowchart from "./FlowChart/FlowChart.svelte" import Flowchart from "./FlowChart/FlowChart.svelte"
</script> </script>

View File

@ -9,11 +9,11 @@
Tags, Tags,
Tag, Tag,
} from "@budibase/bbui" } from "@budibase/bbui"
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation } from "stores/builder"
import { admin, licensing } from "stores/portal" import { admin, licensing } from "stores/portal"
import { externalActions } from "./ExternalActions" import { externalActions } from "./ExternalActions"
import { TriggerStepID, ActionStepID } from "constants/backend/automations" import { TriggerStepID, ActionStepID } from "constants/backend/automations"
import { checkForCollectStep } from "builderStore/utils" import { checkForCollectStep } from "helpers/utils"
export let blockIdx export let blockIdx
export let lastStep export let lastStep
@ -128,10 +128,10 @@
> >
<div class="item-body"> <div class="item-body">
<img <img
width="20" width={20}
height="20" height={20}
src={externalActions[action.stepId].icon} src={externalActions[action.stepId].icon}
alt="zapier" alt={externalActions[action.stepId].name}
/> />
<span class="icon-spacing"> <span class="icon-spacing">
<Body size="XS"> <Body size="XS">

View File

@ -1,7 +1,7 @@
<script> <script>
import { processStringSync } from "@budibase/string-templates" import { processStringSync } from "@budibase/string-templates"
import { get } from "lodash/fp" import { get } from "lodash/fp"
import { tables } from "stores/backend" import { tables } from "stores/builder"
export let block export let block

View File

@ -1,5 +1,6 @@
import DiscordLogo from "assets/discord.svg" import DiscordLogo from "assets/discord.svg"
import ZapierLogo from "assets/zapier.png" import ZapierLogo from "assets/zapier.png"
import n8nLogo from "assets/n8n_square.png"
import MakeLogo from "assets/make.svg" import MakeLogo from "assets/make.svg"
import SlackLogo from "assets/slack.svg" import SlackLogo from "assets/slack.svg"
@ -8,4 +9,5 @@ export const externalActions = {
discord: { name: "discord", icon: DiscordLogo }, discord: { name: "discord", icon: DiscordLogo },
slack: { name: "slack", icon: SlackLogo }, slack: { name: "slack", icon: SlackLogo },
integromat: { name: "integromat", icon: MakeLogo }, integromat: { name: "integromat", icon: MakeLogo },
n8n: { name: "n8n", icon: n8nLogo },
} }

View File

@ -3,7 +3,7 @@
automationStore, automationStore,
selectedAutomation, selectedAutomation,
automationHistoryStore, automationHistoryStore,
} from "builderStore" } from "stores/builder"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import FlowItem from "./FlowItem.svelte" import FlowItem from "./FlowItem.svelte"
import TestDataModal from "./TestDataModal.svelte" import TestDataModal from "./TestDataModal.svelte"

View File

@ -1,5 +1,9 @@
<script> <script>
import { automationStore, selectedAutomation } from "builderStore" import {
automationStore,
selectedAutomation,
permissions,
} from "stores/builder"
import { import {
Icon, Icon,
Divider, Divider,
@ -17,7 +21,6 @@
import FlowItemHeader from "./FlowItemHeader.svelte" import FlowItemHeader from "./FlowItemHeader.svelte"
import RoleSelect from "components/design/settings/controls/RoleSelect.svelte" import RoleSelect from "components/design/settings/controls/RoleSelect.svelte"
import { ActionStepID, TriggerStepID } from "constants/backend/automations" import { ActionStepID, TriggerStepID } from "constants/backend/automations"
import { permissions } from "stores/backend"
export let block export let block
export let testDataModal export let testDataModal

View File

@ -1,6 +1,6 @@
<script> <script>
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation } from "stores/builder"
import { Icon, Body, StatusLight, AbsTooltip } from "@budibase/bbui" import { Icon, Body, AbsTooltip, StatusLight } from "@budibase/bbui"
import { externalActions } from "./ExternalActions" import { externalActions } from "./ExternalActions"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { Features } from "constants/backend/automations" import { Features } from "constants/backend/automations"

View File

@ -5,7 +5,7 @@
notifications, notifications,
ActionButton, ActionButton,
} from "@budibase/bbui" } from "@budibase/bbui"
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation } from "stores/builder"
import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte" import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"

View File

@ -1,7 +1,7 @@
<script> <script>
import { Icon, Divider } from "@budibase/bbui" import { Icon, Divider } from "@budibase/bbui"
import TestDisplay from "./TestDisplay.svelte" import TestDisplay from "./TestDisplay.svelte"
import { automationStore } from "builderStore" import { automationStore } from "stores/builder"
export let automation export let automation
</script> </script>

View File

@ -4,7 +4,7 @@
automationStore, automationStore,
selectedAutomation, selectedAutomation,
userSelectedResourceMap, userSelectedResourceMap,
} from "builderStore" } from "stores/builder"
import NavItem from "components/common/NavItem.svelte" import NavItem from "components/common/NavItem.svelte"
import EditAutomationPopover from "./EditAutomationPopover.svelte" import EditAutomationPopover from "./EditAutomationPopover.svelte"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"

View File

@ -7,7 +7,7 @@
automationStore, automationStore,
selectedAutomation, selectedAutomation,
userSelectedResourceMap, userSelectedResourceMap,
} from "builderStore" } from "stores/builder"
import NavItem from "components/common/NavItem.svelte" import NavItem from "components/common/NavItem.svelte"
import EditAutomationPopover from "./EditAutomationPopover.svelte" import EditAutomationPopover from "./EditAutomationPopover.svelte"

View File

@ -1,5 +1,5 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "stores/builder"
import { import {
notifications, notifications,
Input, Input,

View File

@ -1,5 +1,5 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "stores/builder"
import { ActionMenu, MenuItem, notifications, Icon } from "@budibase/bbui" import { ActionMenu, MenuItem, notifications, Icon } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import UpdateAutomationModal from "components/automation/AutomationPanel/UpdateAutomationModal.svelte" import UpdateAutomationModal from "components/automation/AutomationPanel/UpdateAutomationModal.svelte"

View File

@ -1,5 +1,5 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "stores/builder"
import { import {
notifications, notifications,
Icon, Icon,

View File

@ -17,8 +17,7 @@
DatePicker, DatePicker,
} from "@budibase/bbui" } from "@budibase/bbui"
import CreateWebhookModal from "components/automation/Shared/CreateWebhookModal.svelte" import CreateWebhookModal from "components/automation/Shared/CreateWebhookModal.svelte"
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation, tables } from "stores/builder"
import { tables } from "stores/backend"
import { environment, licensing } from "stores/portal" import { environment, licensing } from "stores/portal"
import WebhookDisplay from "../Shared/WebhookDisplay.svelte" import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
@ -44,7 +43,7 @@
import { import {
getSchemaForDatasourcePlus, getSchemaForDatasourcePlus,
getEnvironmentBindings, getEnvironmentBindings,
} from "builderStore/dataBinding" } from "dataBinding"
import { TriggerStepID, ActionStepID } from "constants/backend/automations" import { TriggerStepID, ActionStepID } from "constants/backend/automations"
import { onMount } from "svelte" import { onMount } from "svelte"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
@ -80,6 +79,7 @@
disableWrapping: true, disableWrapping: true,
}) })
$: editingJs = codeMode === EditorModes.JS $: editingJs = codeMode === EditorModes.JS
$: requiredProperties = block.schema.inputs.required || []
$: stepCompletions = $: stepCompletions =
codeMode === EditorModes.Handlebars codeMode === EditorModes.Handlebars
@ -360,6 +360,11 @@
) )
} }
function getFieldLabel(key, value) {
const requiredSuffix = requiredProperties.includes(key) ? "*" : ""
return `${value.title || (key === "row" ? "Table" : key)} ${requiredSuffix}`
}
onMount(async () => { onMount(async () => {
try { try {
await environment.loadVariables() await environment.loadVariables()
@ -377,7 +382,7 @@
<Label <Label
tooltip={value.title === "Binding / Value" tooltip={value.title === "Binding / Value"
? "If using the String input type, please use a comma or newline separated string" ? "If using the String input type, please use a comma or newline separated string"
: null}>{value.title || (key === "row" ? "Table" : key)}</Label : null}>{getFieldLabel(key, value)}</Label
> >
{/if} {/if}
<div class:field-width={shouldRenderField(value)}> <div class:field-width={shouldRenderField(value)}>

View File

@ -1,7 +1,7 @@
<script> <script>
import { Select, Label } from "@budibase/bbui" import { Select, Label } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation } from "stores/builder"
import { TriggerStepID } from "constants/backend/automations" import { TriggerStepID } from "constants/backend/automations"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte" import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"

View File

@ -1,16 +1,35 @@
<script> <script>
import { Button, Select, Input, Label } from "@budibase/bbui" import { Button, Select, Input, Label } from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import { flags } from "stores/backend" import { flags } from "stores/builder"
import { helpers, REBOOT_CRON } from "@budibase/shared-core"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let value export let value
let error
$: {
const exists = CRON_EXPRESSIONS.some(cron => cron.value === value)
const customIndex = CRON_EXPRESSIONS.findIndex(
cron => cron.label === "Custom"
)
if (!exists && customIndex === -1) {
CRON_EXPRESSIONS[0] = { label: "Custom", value: value }
} else if (exists && customIndex !== -1) {
CRON_EXPRESSIONS.splice(customIndex, 1)
}
}
const onChange = e => { const onChange = e => {
if (e.detail === value) { if (value !== REBOOT_CRON) {
error = helpers.cron.validate(e.detail).err
}
if (e.detail === value || error) {
return return
} }
value = e.detail value = e.detail
dispatch("change", e.detail) dispatch("change", e.detail)
} }
@ -41,7 +60,7 @@
if (!$flags.cloud) { if (!$flags.cloud) {
CRON_EXPRESSIONS.push({ CRON_EXPRESSIONS.push({
label: "Every Budibase Reboot", label: "Every Budibase Reboot",
value: "@reboot", value: REBOOT_CRON,
}) })
} }
}) })
@ -49,6 +68,7 @@
<div class="block-field"> <div class="block-field">
<Input <Input
{error}
on:change={onChange} on:change={onChange}
{value} {value}
on:blur={() => (touched = true)} on:blur={() => (touched = true)}
@ -64,7 +84,7 @@
{#if presets} {#if presets}
<Select <Select
on:change={onChange} on:change={onChange}
{value} value={value || "Custom"}
secondary secondary
extraThin extraThin
label="Presets" label="Presets"

View File

@ -1,6 +1,6 @@
<script> <script>
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { queries } from "stores/backend" import { queries } from "stores/builder"
import { Select, Label } from "@budibase/bbui" import { Select, Label } from "@budibase/bbui"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte" import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"

View File

@ -1,5 +1,5 @@
<script> <script>
import { queries } from "stores/backend" import { queries } from "stores/builder"
import { Select } from "@budibase/bbui" import { Select } from "@budibase/bbui"
export let value export let value

View File

@ -1,5 +1,5 @@
<script> <script>
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { Select, Checkbox, Label } from "@budibase/bbui" import { Select, Checkbox, Label } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import RowSelectorTypes from "./RowSelectorTypes.svelte" import RowSelectorTypes from "./RowSelectorTypes.svelte"

View File

@ -1,5 +1,5 @@
<script> <script>
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { Select } from "@budibase/bbui" import { Select } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { TableNames } from "constants" import { TableNames } from "constants"

View File

@ -1,6 +1,6 @@
<script> <script>
import { Icon, notifications, ModalContent } from "@budibase/bbui" import { Icon, notifications, ModalContent } from "@budibase/bbui"
import { automationStore, selectedAutomation } from "builderStore" import { automationStore, selectedAutomation } from "stores/builder"
import WebhookDisplay from "./WebhookDisplay.svelte" import WebhookDisplay from "./WebhookDisplay.svelte"
import { onMount, onDestroy } from "svelte" import { onMount, onDestroy } from "svelte"

View File

@ -1,7 +1,7 @@
<script> <script>
import { API } from "api" import { API } from "api"
import Table from "./Table.svelte" import Table from "./Table.svelte"
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
export let tableId export let tableId

View File

@ -1,10 +1,9 @@
<script> <script>
import { datasources, tables, integrations } from "stores/backend" import { datasources, tables, integrations, appStore } from "stores/builder"
import EditRolesButton from "./buttons/EditRolesButton.svelte" import EditRolesButton from "./buttons/EditRolesButton.svelte"
import { TableNames } from "constants" import { TableNames } from "constants"
import { Grid } from "@budibase/frontend-core" import { Grid } from "@budibase/frontend-core"
import { API } from "api" import { API } from "api"
import { store } from "builderStore"
import GridAddColumnModal from "components/backend/DataTable/modals/grid/GridCreateColumnModal.svelte" import GridAddColumnModal from "components/backend/DataTable/modals/grid/GridCreateColumnModal.svelte"
import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte" import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte"
import GridEditUserModal from "components/backend/DataTable/modals/grid/GridEditUserModal.svelte" import GridEditUserModal from "components/backend/DataTable/modals/grid/GridEditUserModal.svelte"
@ -59,14 +58,14 @@
datasource={gridDatasource} datasource={gridDatasource}
canAddRows={!isUsersTable} canAddRows={!isUsersTable}
canDeleteRows={!isUsersTable} canDeleteRows={!isUsersTable}
canEditRows={!isUsersTable || !$store.features.disableUserMetadata} canEditRows={!isUsersTable || !$appStore.features.disableUserMetadata}
canEditColumns={!isUsersTable || !$store.features.disableUserMetadata} canEditColumns={!isUsersTable || !$appStore.features.disableUserMetadata}
schemaOverrides={isUsersTable ? userSchemaOverrides : null} schemaOverrides={isUsersTable ? userSchemaOverrides : null}
showAvatars={false} showAvatars={false}
on:updatedatasource={handleGridTableUpdate} on:updatedatasource={handleGridTableUpdate}
> >
<svelte:fragment slot="filter"> <svelte:fragment slot="filter">
{#if isUsersTable && $store.features.disableUserMetadata} {#if isUsersTable && $appStore.features.disableUserMetadata}
<GridUsersTableButton /> <GridUsersTableButton />
{/if} {/if}
<GridFilterButton /> <GridFilterButton />

View File

@ -1,6 +1,6 @@
<script> <script>
import { API } from "api" import { API } from "api"
import { tables } from "stores/backend" import { tables } from "stores/builder"
import Table from "./Table.svelte" import Table from "./Table.svelte"
import CalculateButton from "./buttons/CalculateButton.svelte" import CalculateButton from "./buttons/CalculateButton.svelte"

View File

@ -1,5 +1,5 @@
<script> <script>
import { viewsV2 } from "stores/backend" import { viewsV2 } from "stores/builder"
import { Grid } from "@budibase/frontend-core" import { Grid } from "@budibase/frontend-core"
import { API } from "api" import { API } from "api"
import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte" import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte"

View File

@ -1,10 +1,8 @@
<script> <script>
import { ActionButton, notifications } from "@budibase/bbui" import { ActionButton, notifications } from "@budibase/bbui"
import CreateEditRelationshipModal from "../../Datasources/CreateEditRelationshipModal.svelte" import CreateEditRelationshipModal from "../../Datasources/CreateEditRelationshipModal.svelte"
import {
datasources, import { datasources, tables as tablesStore } from "stores/builder"
tables as tablesStore,
} from "../../../../stores/backend"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
export let table export let table

View File

@ -1,6 +1,6 @@
<script> <script>
import { ActionButton, Modal } from "@budibase/bbui" import { ActionButton, Modal } from "@budibase/bbui"
import { permissions } from "stores/backend" import { permissions } from "stores/builder"
import ManageAccessModal from "../modals/ManageAccessModal.svelte" import ManageAccessModal from "../modals/ManageAccessModal.svelte"
export let resourceId export let resourceId

View File

@ -1,5 +1,5 @@
<script> <script>
import { roles } from "stores/backend" import { roles } from "stores/builder"
export let value export let value

View File

@ -1,5 +1,5 @@
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { get as svelteGet } from "svelte/store" import { get as svelteGet } from "svelte/store"
// currently supported level of relationship depth (server side) // currently supported level of relationship depth (server side)

View File

@ -1,6 +1,6 @@
<script> <script>
import { Select, Label, notifications, ModalContent } from "@budibase/bbui" import { Select, Label, notifications, ModalContent } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/builder"
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
const CALCULATIONS = [ const CALCULATIONS = [

View File

@ -15,7 +15,7 @@
} from "@budibase/bbui" } from "@budibase/bbui"
import { createEventDispatcher, getContext, onMount } from "svelte" import { createEventDispatcher, getContext, onMount } from "svelte"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { tables, datasources } from "stores/backend" import { tables, datasources } from "stores/builder"
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants" import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
import { import {
FIELDS, FIELDS,
@ -28,7 +28,7 @@
PrettyRelationshipDefinitions, PrettyRelationshipDefinitions,
DB_TYPE_EXTERNAL, DB_TYPE_EXTERNAL,
} from "constants/backend" } from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils" import { getAutoColumnInformation, buildAutoColumn } from "helpers/utils"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte" import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
import { getBindings } from "components/backend/DataTable/formula" import { getBindings } from "components/backend/DataTable/formula"

View File

@ -1,6 +1,6 @@
<script> <script>
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { ModalContent, keepOpen, notifications } from "@budibase/bbui" import { ModalContent, keepOpen, notifications } from "@budibase/bbui"
import RowFieldControl from "../RowFieldControl.svelte" import RowFieldControl from "../RowFieldControl.svelte"
import { API } from "api" import { API } from "api"

View File

@ -1,6 +1,6 @@
<script> <script>
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { tables, roles } from "stores/backend" import { tables, roles } from "stores/builder"
import { import {
notifications, notifications,
keepOpen, keepOpen,

View File

@ -10,7 +10,7 @@
import { onMount } from "svelte" import { onMount } from "svelte"
import { API } from "api" import { API } from "api"
import ErrorsBox from "components/common/ErrorsBox.svelte" import ErrorsBox from "components/common/ErrorsBox.svelte"
import { roles } from "stores/backend" import { roles } from "stores/builder"
const BASE_ROLE = { _id: "", inherits: "BASIC", permissionId: "write" } const BASE_ROLE = { _id: "", inherits: "BASIC", permissionId: "write" }

View File

@ -10,7 +10,7 @@
notifications, notifications,
Icon, Icon,
} from "@budibase/bbui" } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/builder"
const CONDITIONS = [ const CONDITIONS = [
{ {

View File

@ -1,6 +1,6 @@
<script> <script>
import { Select, ModalContent, notifications } from "@budibase/bbui" import { Select, ModalContent, notifications } from "@budibase/bbui"
import { tables, views } from "stores/backend" import { tables, views } from "stores/builder"
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
export let view = {} export let view = {}

View File

@ -13,7 +13,7 @@
} from "@budibase/bbui" } from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import { FIELDS } from "constants/backend" import { FIELDS } from "constants/backend"
import { generate } from "builderStore/schemaGenerator" import { generate } from "helpers/schemaGenerator"
export let schema = {} export let schema = {}
export let json export let json

View File

@ -1,6 +1,6 @@
<script> <script>
import { PermissionSource } from "@budibase/types" import { PermissionSource } from "@budibase/types"
import { roles, permissions as permissionsStore } from "stores/backend" import { roles, permissions as permissionsStore } from "stores/builder"
import { import {
Label, Label,
Input, Input,

View File

@ -2,7 +2,7 @@
import { getContext } from "svelte" import { getContext } from "svelte"
import { Input, notifications, ModalContent } from "@budibase/bbui" import { Input, notifications, ModalContent } from "@budibase/bbui"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { viewsV2 } from "stores/backend" import { viewsV2 } from "stores/builder"
const { filter, sort, definition } = getContext("grid") const { filter, sort, definition } = getContext("grid")

View File

@ -1,15 +1,12 @@
<script> <script>
import { ActionButton, Popover, Heading, Body, Button } from "@budibase/bbui" import { ActionButton, Popover, Heading, Body, Button } from "@budibase/bbui"
import { store } from "builderStore" import { builderStore } from "stores/builder"
let anchor let anchor
let open = false let open = false
const openSidePanel = () => { const openSidePanel = () => {
store.update(state => ({ builderStore.showBuilderSidePanel()
...state,
builderSidePanel: true,
}))
open = false open = false
} }
</script> </script>

View File

@ -3,13 +3,13 @@
import { Layout } from "@budibase/bbui" import { Layout } from "@budibase/bbui"
import { BUDIBASE_INTERNAL_DB_ID } from "constants/backend" import { BUDIBASE_INTERNAL_DB_ID } from "constants/backend"
import { import {
database,
datasources, datasources,
queries, queries,
tables, tables,
views, views,
viewsV2, viewsV2,
} from "stores/backend" userSelectedResourceMap,
} from "stores/builder"
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte" import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
import EditQueryPopover from "./popovers/EditQueryPopover.svelte" import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
import NavItem from "components/common/NavItem.svelte" import NavItem from "components/common/NavItem.svelte"
@ -21,7 +21,6 @@
} from "helpers/data/utils" } from "helpers/data/utils"
import IntegrationIcon from "./IntegrationIcon.svelte" import IntegrationIcon from "./IntegrationIcon.svelte"
import { TableNames } from "constants" import { TableNames } from "constants"
import { userSelectedResourceMap } from "builderStore"
import { enrichDatasources } from "./datasourceUtils" import { enrichDatasources } from "./datasourceUtils"
import { onMount } from "svelte" import { onMount } from "svelte"
@ -75,69 +74,67 @@
searchTerm && !showAppUsersTable && !enrichedDataSources.find(ds => ds.show) searchTerm && !showAppUsersTable && !enrichedDataSources.find(ds => ds.show)
</script> </script>
{#if $database?._id} <div class="hierarchy-items-container">
<div class="hierarchy-items-container"> {#if showAppUsersTable}
{#if showAppUsersTable} <NavItem
<NavItem icon="UserGroup"
icon="UserGroup" text={appUsersTableName}
text={appUsersTableName} selected={$isActive("./table/:tableId") &&
selected={$isActive("./table/:tableId") && $tables.selected?._id === TableNames.USERS}
$tables.selected?._id === TableNames.USERS} on:click={() => selectTable(TableNames.USERS)}
on:click={() => selectTable(TableNames.USERS)} selectedBy={$userSelectedResourceMap[TableNames.USERS]}
selectedBy={$userSelectedResourceMap[TableNames.USERS]} />
/> {/if}
{/if} {#each enrichedDataSources.filter(ds => ds.show) as datasource}
{#each enrichedDataSources.filter(ds => ds.show) as datasource} <NavItem
<NavItem border
border text={datasource.name}
text={datasource.name} opened={datasource.open}
opened={datasource.open} selected={$isActive("./datasource") && datasource.selected}
selected={$isActive("./datasource") && datasource.selected} withArrow={true}
withArrow={true} on:click={() => selectDatasource(datasource)}
on:click={() => selectDatasource(datasource)} on:iconClick={() => toggleNode(datasource)}
on:iconClick={() => toggleNode(datasource)} selectedBy={$userSelectedResourceMap[datasource._id]}
selectedBy={$userSelectedResourceMap[datasource._id]} >
> <div class="datasource-icon" slot="icon">
<div class="datasource-icon" slot="icon"> <IntegrationIcon
<IntegrationIcon integrationType={datasource.source}
integrationType={datasource.source} schema={datasource.schema}
schema={datasource.schema} size="18"
size="18" />
/> </div>
</div> {#if datasource._id !== BUDIBASE_INTERNAL_DB_ID}
{#if datasource._id !== BUDIBASE_INTERNAL_DB_ID} <EditDatasourcePopover {datasource} />
<EditDatasourcePopover {datasource} />
{/if}
</NavItem>
{#if datasource.open}
<TableNavigator tables={datasource.tables} {selectTable} />
{#each datasource.queries as query}
<NavItem
indentLevel={1}
icon="SQLQuery"
iconText={customQueryIconText(datasource, query)}
iconColor={customQueryIconColor(datasource, query)}
text={customQueryText(datasource, query)}
selected={$isActive("./query/:queryId") &&
$queries.selectedQueryId === query._id}
on:click={() => $goto(`./query/${query._id}`)}
selectedBy={$userSelectedResourceMap[query._id]}
>
<EditQueryPopover {query} />
</NavItem>
{/each}
{/if} {/if}
{/each} </NavItem>
{#if showNoResults}
<Layout paddingY="none" paddingX="L"> {#if datasource.open}
<div class="no-results"> <TableNavigator tables={datasource.tables} {selectTable} />
There aren't any datasources matching that name {#each datasource.queries as query}
</div> <NavItem
</Layout> indentLevel={1}
icon="SQLQuery"
iconText={customQueryIconText(datasource, query)}
iconColor={customQueryIconColor(datasource, query)}
text={customQueryText(datasource, query)}
selected={$isActive("./query/:queryId") &&
$queries.selectedQueryId === query._id}
on:click={() => $goto(`./query/${query._id}`)}
selectedBy={$userSelectedResourceMap[query._id]}
>
<EditQueryPopover {query} />
</NavItem>
{/each}
{/if} {/if}
</div> {/each}
{/if} {#if showNoResults}
<Layout paddingY="none" paddingX="L">
<div class="no-results">
There aren't any datasources matching that name
</div>
</Layout>
{/if}
</div>
<style> <style>
.hierarchy-items-container { .hierarchy-items-container {

View File

@ -16,7 +16,7 @@ import Firebase from "./Firebase.svelte"
import Redis from "./Redis.svelte" import Redis from "./Redis.svelte"
import Snowflake from "./Snowflake.svelte" import Snowflake from "./Snowflake.svelte"
import Custom from "./Custom.svelte" import Custom from "./Custom.svelte"
import { integrations } from "stores/backend" import { integrations } from "stores/builder"
import { get } from "svelte/store" import { get } from "svelte/store"
const ICONS = { const ICONS = {

View File

@ -12,7 +12,7 @@
TextArea, TextArea,
Dropzone, Dropzone,
} from "@budibase/bbui" } from "@budibase/bbui"
import { datasources, queries } from "stores/backend" import { datasources, queries } from "stores/builder"
import { writable } from "svelte/store" import { writable } from "svelte/store"
export let navigateDatasource = false export let navigateDatasource = false

View File

@ -1,6 +1,6 @@
<script> <script>
import { get } from "svelte/store" import { get } from "svelte/store"
import { datasources, integrations } from "stores/backend" import { datasources, integrations } from "stores/builder"
import { notifications, Input, ModalContent, Modal } from "@budibase/bbui" import { notifications, Input, ModalContent, Modal } from "@budibase/bbui"
import { integrationForDatasource } from "stores/selectors" import { integrationForDatasource } from "stores/selectors"

View File

@ -1,6 +1,6 @@
<script> <script>
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { datasources } from "stores/backend" import { datasources } from "stores/builder"
import { notifications, ActionMenu, MenuItem, Icon } from "@budibase/bbui" import { notifications, ActionMenu, MenuItem, Icon } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import UpdateDatasourceModal from "components/backend/DatasourceNavigator/modals/UpdateDatasourceModal.svelte" import UpdateDatasourceModal from "components/backend/DatasourceNavigator/modals/UpdateDatasourceModal.svelte"

View File

@ -2,7 +2,7 @@
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { ActionMenu, MenuItem, Icon, notifications } from "@budibase/bbui" import { ActionMenu, MenuItem, Icon, notifications } from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { datasources, queries } from "stores/backend" import { datasources, queries } from "stores/builder"
export let query export let query

View File

@ -13,7 +13,7 @@
Body, Body,
Helpers, Helpers,
} from "@budibase/bbui" } from "@budibase/bbui"
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { RelationshipErrorChecker } from "./relationshipErrors" import { RelationshipErrorChecker } from "./relationshipErrors"
import { onMount } from "svelte" import { onMount } from "svelte"
import RelationshipSelector from "components/common/RelationshipSelector.svelte" import RelationshipSelector from "components/common/RelationshipSelector.svelte"

View File

@ -2,7 +2,7 @@
import { Modal } from "@budibase/bbui" import { Modal } from "@budibase/bbui"
import { get } from "svelte/store" import { get } from "svelte/store"
import CreateEditRelationship from "./CreateEditRelationship.svelte" import CreateEditRelationship from "./CreateEditRelationship.svelte"
import { integrations, datasources } from "stores/backend" import { integrations, datasources } from "stores/builder"
import { integrationForDatasource } from "stores/selectors" import { integrationForDatasource } from "stores/selectors"
export let datasource export let datasource

View File

@ -1,6 +1,6 @@
import { derived, writable, get } from "svelte/store" import { derived, writable, get } from "svelte/store"
import { keepOpen, notifications } from "@budibase/bbui" import { keepOpen, notifications } from "@budibase/bbui"
import { datasources, tables } from "stores/backend" import { datasources, tables } from "stores/builder"
export const createTableSelectionStore = (integration, datasource) => { export const createTableSelectionStore = (integration, datasource) => {
const tableNamesStore = writable([]) const tableNamesStore = writable([])

View File

@ -3,14 +3,13 @@
tables as tablesStore, tables as tablesStore,
views, views,
viewsV2, viewsV2,
database, userSelectedResourceMap,
} from "stores/backend" } from "stores/builder"
import { TableNames } from "constants" import { TableNames } from "constants"
import EditTablePopover from "./popovers/EditTablePopover.svelte" import EditTablePopover from "./popovers/EditTablePopover.svelte"
import EditViewPopover from "./popovers/EditViewPopover.svelte" import EditViewPopover from "./popovers/EditViewPopover.svelte"
import NavItem from "components/common/NavItem.svelte" import NavItem from "components/common/NavItem.svelte"
import { goto, isActive } from "@roxi/routify" import { goto, isActive } from "@roxi/routify"
import { userSelectedResourceMap } from "builderStore"
export let tables export let tables
export let selectTable export let selectTable
@ -29,42 +28,40 @@
} }
</script> </script>
{#if $database?._id} <div class="hierarchy-items-container">
<div class="hierarchy-items-container"> {#each sortedTables as table, idx}
{#each sortedTables as table, idx} <NavItem
indentLevel={1}
border={idx > 0}
icon={table._id === TableNames.USERS ? "UserGroup" : "Table"}
text={table.name}
selected={$isActive("./table/:tableId") &&
$tablesStore.selected?._id === table._id}
on:click={() => selectTable(table._id)}
selectedBy={$userSelectedResourceMap[table._id]}
>
{#if table._id !== TableNames.USERS}
<EditTablePopover {table} />
{/if}
</NavItem>
{#each [...Object.entries(table.views || {})].sort() as [name, view], idx (idx)}
<NavItem <NavItem
indentLevel={1} indentLevel={2}
border={idx > 0} icon="Remove"
icon={table._id === TableNames.USERS ? "UserGroup" : "Table"} text={name}
text={table.name} selected={isViewActive(view, $isActive, $views, $viewsV2)}
selected={$isActive("./table/:tableId") && on:click={() => {
$tablesStore.selected?._id === table._id} if (view.version === 2) {
on:click={() => selectTable(table._id)} $goto(`./view/v2/${encodeURIComponent(view.id)}`)
selectedBy={$userSelectedResourceMap[table._id]} } else {
$goto(`./view/v1/${encodeURIComponent(name)}`)
}
}}
selectedBy={$userSelectedResourceMap[name] ||
$userSelectedResourceMap[view.id]}
> >
{#if table._id !== TableNames.USERS} <EditViewPopover {view} />
<EditTablePopover {table} />
{/if}
</NavItem> </NavItem>
{#each [...Object.entries(table.views || {})].sort() as [name, view], idx (idx)}
<NavItem
indentLevel={2}
icon="Remove"
text={name}
selected={isViewActive(view, $isActive, $views, $viewsV2)}
on:click={() => {
if (view.version === 2) {
$goto(`./view/v2/${encodeURIComponent(view.id)}`)
} else {
$goto(`./view/v1/${encodeURIComponent(name)}`)
}
}}
selectedBy={$userSelectedResourceMap[name] ||
$userSelectedResourceMap[view.id]}
>
<EditViewPopover {view} />
</NavItem>
{/each}
{/each} {/each}
</div> {/each}
{/if} </div>

View File

@ -1,6 +1,6 @@
<script> <script>
import { goto, url } from "@roxi/routify" import { goto, url } from "@roxi/routify"
import { tables, datasources } from "stores/backend" import { tables, datasources } from "stores/builder"
import { import {
notifications, notifications,
Input, Input,

View File

@ -1,8 +1,7 @@
<script> <script>
import { goto, params } from "@roxi/routify" import { goto, params } from "@roxi/routify"
import { store } from "builderStore"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { tables, datasources } from "stores/backend" import { tables, datasources, screenStore } from "stores/builder"
import { import {
ActionMenu, ActionMenu,
Icon, Icon,
@ -32,7 +31,7 @@
$: allowDeletion = !externalTable || table?.created $: allowDeletion = !externalTable || table?.created
function showDeleteModal() { function showDeleteModal() {
templateScreens = $store.screens.filter( templateScreens = $screenStore.screens.filter(
screen => screen.autoTableId === table._id screen => screen.autoTableId === table._id
) )
willBeDeleted = ["All table data"].concat( willBeDeleted = ["All table data"].concat(
@ -47,7 +46,7 @@
await tables.delete(table) await tables.delete(table)
// Screens need deleted one at a time because of undo/redo // Screens need deleted one at a time because of undo/redo
for (let screen of templateScreens) { for (let screen of templateScreens) {
await store.actions.screens.delete(screen) await screenStore.delete(screen)
} }
if (table.sourceType === DB_TYPE_EXTERNAL) { if (table.sourceType === DB_TYPE_EXTERNAL) {
await datasources.fetch() await datasources.fetch()

View File

@ -1,5 +1,5 @@
<script> <script>
import { views, viewsV2 } from "stores/backend" import { views, viewsV2 } from "stores/builder"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { import {

View File

@ -10,12 +10,17 @@
import { API } from "api" import { API } from "api"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { import {
store,
sortedScreens,
automationStore, automationStore,
themeStore, previewStore,
} from "builderStore" builderStore,
import { datasources, queries, tables, views } from "stores/backend" sortedScreens,
appStore,
datasources,
queries,
tables,
views,
} from "stores/builder"
import { themeStore } from "stores/portal"
import { getContext } from "svelte" import { getContext } from "svelte"
import { Constants } from "@budibase/frontend-core" import { Constants } from "@budibase/frontend-core"
@ -26,8 +31,7 @@
name: "Invite users and manage app access", name: "Invite users and manage app access",
description: "", description: "",
icon: "User", icon: "User",
action: () => action: () => builderStore.showBuilderSidePanel(),
store.update(state => ({ ...state, builderSidePanel: true })),
}, },
{ {
type: "Navigate", type: "Navigate",
@ -69,13 +73,13 @@
name: "App", name: "App",
description: "", description: "",
icon: "Play", icon: "Play",
action: () => store.update(state => ({ ...state, showPreview: true })), action: () => previewStore.showPreview(true),
}, },
{ {
type: "Preview", type: "Preview",
name: "Published App", name: "Published App",
icon: "Play", icon: "Play",
action: () => window.open(`/app${$store.url}`), action: () => window.open(`/app${$appStore.url}`),
}, },
{ {
type: "Support", type: "Support",
@ -216,7 +220,7 @@
async function deployApp() { async function deployApp() {
try { try {
await API.publishAppChanges($store.appId) await API.publishAppChanges($appStore.appId)
notifications.success("App published successfully") notifications.success("App published successfully")
} catch (error) { } catch (error) {
notifications.error("Error publishing app") notifications.error("Error publishing app")

View File

@ -43,7 +43,7 @@
import { Compartment } from "@codemirror/state" import { Compartment } from "@codemirror/state"
import { javascript } from "@codemirror/lang-javascript" import { javascript } from "@codemirror/lang-javascript"
import { EditorModes, getDefaultTheme } from "./" import { EditorModes, getDefaultTheme } from "./"
import { themeStore } from "builderStore" import { themeStore } from "stores/portal"
export let label export let label
export let completions = [] export let completions = []

View File

@ -286,7 +286,13 @@ export const hbInsert = (value, from, to, text) => {
return parsedInsert return parsedInsert
} }
export function jsInsert(value, from, to, text, { helper, disableWrapping }) { export function jsInsert(
value,
from,
to,
text,
{ helper, disableWrapping } = {}
) {
let parsedInsert = "" let parsedInsert = ""
const left = from ? value.substring(0, from) : "" const left = from ? value.substring(0, from) : ""

View File

@ -27,7 +27,7 @@
<script> <script>
import { Label } from "@budibase/bbui" import { Label } from "@budibase/bbui"
import CodeMirror from "components/integration/codemirror" import CodeMirror from "components/integration/codemirror"
import { themeStore } from "builderStore" import { themeStore } from "stores/portal"
import { createEventDispatcher, onMount } from "svelte" import { createEventDispatcher, onMount } from "svelte"
export let mode = EditorModes.JS export let mode = EditorModes.JS

View File

@ -1,8 +1,8 @@
<script> <script>
import { tables } from "stores/backend" import { tables } from "stores/builder"
import { API } from "api" import { API } from "api"
import { Select, Label, Multiselect } from "@budibase/bbui" import { Select, Label, Multiselect } from "@budibase/bbui"
import { capitalise } from "../../helpers" import { capitalise } from "helpers"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
export let schema export let schema

View File

@ -1,6 +1,6 @@
<script> <script>
import { Select, FancySelect } from "@budibase/bbui" import { Select, FancySelect } from "@budibase/bbui"
import { roles } from "stores/backend" import { roles } from "stores/builder"
import { licensing } from "stores/portal" import { licensing } from "stores/portal"
import { Constants, RoleUtils } from "@budibase/frontend-core" import { Constants, RoleUtils } from "@budibase/frontend-core"

View File

@ -3,7 +3,7 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { isJSBinding } from "@budibase/string-templates" import { isJSBinding } from "@budibase/string-templates"

View File

@ -19,7 +19,7 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import { admin } from "stores/portal" import { admin } from "stores/portal"
import CodeEditor from "../CodeEditor/CodeEditor.svelte" import CodeEditor from "../CodeEditor/CodeEditor.svelte"

View File

@ -3,7 +3,7 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
import { createEventDispatcher, setContext } from "svelte" import { createEventDispatcher, setContext } from "svelte"
import { isJSBinding } from "@budibase/string-templates" import { isJSBinding } from "@budibase/string-templates"

View File

@ -3,11 +3,12 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
import { createEventDispatcher, setContext } from "svelte" import { createEventDispatcher, setContext } from "svelte"
import { isJSBinding } from "@budibase/string-templates" import { isJSBinding } from "@budibase/string-templates"
import { builderStore } from "stores/builder"
export let panel = ClientBindingPanel export let panel = ClientBindingPanel
export let value = "" export let value = ""
@ -21,6 +22,7 @@
export let allowHelpers = true export let allowHelpers = true
export let updateOnChange = true export let updateOnChange = true
export let drawerLeft export let drawerLeft
export let key
export let disableBindings = false export let disableBindings = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -35,6 +37,7 @@
const saveBinding = () => { const saveBinding = () => {
onChange(tempValue) onChange(tempValue)
onBlur() onBlur()
builderStore.propertyFocus()
bindingDrawer.hide() bindingDrawer.hide()
} }
@ -50,6 +53,11 @@
const onBlur = () => { const onBlur = () => {
dispatch("blur", currentVal) dispatch("blur", currentVal)
} }
const onDrawerHide = e => {
builderStore.propertyFocus()
dispatch("drawerHide", e.detail)
}
</script> </script>
<div class="control" class:disabled> <div class="control" class:disabled>
@ -67,6 +75,7 @@
<div <div
class="icon" class="icon"
on:click={() => { on:click={() => {
builderStore.propertyFocus(key)
bindingDrawer.show() bindingDrawer.show()
}} }}
> >
@ -75,7 +84,7 @@
{/if} {/if}
</div> </div>
<Drawer <Drawer
on:drawerHide on:drawerHide={onDrawerHide}
on:drawerShow on:drawerShow
{fillWidth} {fillWidth}
bind:this={bindingDrawer} bind:this={bindingDrawer}

View File

@ -3,7 +3,7 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
import { createEventDispatcher, setContext } from "svelte" import { createEventDispatcher, setContext } from "svelte"

View File

@ -3,7 +3,7 @@
import { import {
readableToRuntimeBinding, readableToRuntimeBinding,
runtimeToReadableBinding, runtimeToReadableBinding,
} from "builderStore/dataBinding" } from "dataBinding"
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte" import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { isJSBinding } from "@budibase/string-templates" import { isJSBinding } from "@budibase/string-templates"

View File

@ -1,9 +1,6 @@
<script> <script>
import { Layout, Input } from "@budibase/bbui" import { Layout, Input } from "@budibase/bbui"
import { import { createValidationStore, requiredValidator } from "helpers/validation"
createValidationStore,
requiredValidator,
} from "../../../helpers/validation"
export let password export let password
export let error export let error

View File

@ -21,11 +21,14 @@
import { API } from "api" import { API } from "api"
import { apps } from "stores/portal" import { apps } from "stores/portal"
import { import {
deploymentStore, previewStore,
store, builderStore,
isOnlyUser, isOnlyUser,
appStore,
deploymentStore,
initialise,
sortedScreens, sortedScreens,
} from "builderStore" } from "stores/builder"
import TourWrap from "components/portal/onboarding/TourWrap.svelte" import TourWrap from "components/portal/onboarding/TourWrap.svelte"
import { TOUR_STEP_KEYS } from "components/portal/onboarding/tours.js" import { TOUR_STEP_KEYS } from "components/portal/onboarding/tours.js"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
@ -50,15 +53,15 @@
$: isPublished = $: isPublished =
selectedApp?.status === "published" && latestDeployments?.length > 0 selectedApp?.status === "published" && latestDeployments?.length > 0
$: updateAvailable = $: updateAvailable =
$store.upgradableVersion && $appStore.upgradableVersion &&
$store.version && $appStore.version &&
$store.upgradableVersion !== $store.version $appStore.upgradableVersion !== $appStore.version
$: canPublish = !publishing && loaded && $sortedScreens.length > 0 $: canPublish = !publishing && loaded && $sortedScreens.length > 0
$: lastDeployed = getLastDeployedString($deploymentStore) $: lastDeployed = getLastDeployedString($deploymentStore)
const initialiseApp = async () => { const initialiseApp = async () => {
const applicationPkg = await API.fetchAppPackage($store.devId) const applicationPkg = await API.fetchAppPackage($appStore.devId)
await store.actions.initialise(applicationPkg) await initialise(applicationPkg)
} }
const getLastDeployedString = deployments => { const getLastDeployedString = deployments => {
@ -71,10 +74,7 @@
} }
const previewApp = () => { const previewApp = () => {
store.update(state => ({ previewStore.showPreview(true)
...state,
showPreview: true,
}))
} }
const viewApp = () => { const viewApp = () => {
@ -92,7 +92,7 @@
async function publishApp() { async function publishApp() {
try { try {
publishing = true publishing = true
await API.publishAppChanges($store.appId) await API.publishAppChanges($appStore.appId)
notifications.send("App published successfully", { notifications.send("App published successfully", {
type: "success", type: "success",
icon: "GlobeCheck", icon: "GlobeCheck",
@ -101,7 +101,13 @@
} catch (error) { } catch (error) {
console.error(error) console.error(error)
analytics.captureException(error) analytics.captureException(error)
notifications.error("Error publishing app") const baseMsg = "Error publishing app"
const message = error.message
if (message) {
notifications.error(`${baseMsg} - ${message}`)
} else {
notifications.error(baseMsg)
}
} }
publishing = false publishing = false
} }
@ -136,7 +142,7 @@
const completePublish = async () => { const completePublish = async () => {
try { try {
await apps.load() await apps.load()
await deploymentStore.actions.load() await deploymentStore.load()
} catch (err) { } catch (err) {
notifications.error("Error refreshing app") notifications.error("Error refreshing app")
} }
@ -156,7 +162,7 @@
</div> </div>
{/if} {/if}
<TourWrap <TourWrap
tourStepKey={$store.onboarding tourStepKey={$builderStore.onboarding
? TOUR_STEP_KEYS.BUILDER_USER_MANAGEMENT ? TOUR_STEP_KEYS.BUILDER_USER_MANAGEMENT
: TOUR_STEP_KEYS.FEATURE_USER_MANAGEMENT} : TOUR_STEP_KEYS.FEATURE_USER_MANAGEMENT}
> >
@ -166,10 +172,7 @@
quiet quiet
icon="UserGroup" icon="UserGroup"
on:click={() => { on:click={() => {
store.update(state => { builderStore.showBuilderSidePanel()
state.builderSidePanel = true
return state
})
}} }}
> >
Users Users
@ -242,7 +245,7 @@
} }
}} }}
> >
{$store.url} {$appStore.url}
{#if isPublished} {#if isPublished}
<Icon size="S" name="LinkOut" /> <Icon size="S" name="LinkOut" />
{:else} {:else}
@ -323,10 +326,10 @@
<Modal bind:this={updateAppModal} padding={false} width="600px"> <Modal bind:this={updateAppModal} padding={false} width="600px">
<UpdateAppModal <UpdateAppModal
app={{ app={{
name: $store.name, name: $appStore.name,
url: $store.url, url: $appStore.url,
icon: $store.icon, icon: $appStore.icon,
appId: $store.appId, appId: $appStore.appId,
}} }}
onUpdateComplete={async () => { onUpdateComplete={async () => {
await initialiseApp() await initialiseApp()

View File

@ -1,5 +1,5 @@
<script> <script>
import { automationStore } from "builderStore" import { automationStore } from "stores/builder"
import { ModalContent } from "@budibase/bbui" import { ModalContent } from "@budibase/bbui"
import { onMount } from "svelte" import { onMount } from "svelte"
import WebhookDisplay from "../automation/Shared/WebhookDisplay.svelte" import WebhookDisplay from "../automation/Shared/WebhookDisplay.svelte"

View File

@ -1,9 +1,9 @@
<script> <script>
import { Input, notifications } from "@budibase/bbui" import { Input, notifications } from "@budibase/bbui"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { store } from "builderStore"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { apps } from "stores/portal" import { apps } from "stores/portal"
import { appStore } from "stores/builder"
import { API } from "api" import { API } from "api"
export const show = () => { export const show = () => {
@ -19,7 +19,7 @@
const deleteApp = async () => { const deleteApp = async () => {
try { try {
await API.deleteApp($store.appId) await API.deleteApp($appStore.appId)
apps.load() apps.load()
notifications.success("App deleted successfully") notifications.success("App deleted successfully")
$goto("/builder") $goto("/builder")
@ -35,11 +35,14 @@
okText="Delete" okText="Delete"
onOk={deleteApp} onOk={deleteApp}
onCancel={() => (deletionConfirmationAppName = null)} onCancel={() => (deletionConfirmationAppName = null)}
disabled={deletionConfirmationAppName !== $store.name} disabled={deletionConfirmationAppName !== $appStore.name}
> >
Are you sure you want to delete <b>{$store.name}</b>? Are you sure you want to delete <b>{$appStore.name}</b>?
<br /> <br />
Please enter the app name below to confirm. Please enter the app name below to confirm.
<br /><br /> <br /><br />
<Input bind:value={deletionConfirmationAppName} placeholder={$store.name} /> <Input
bind:value={deletionConfirmationAppName}
placeholder={$appStore.name}
/>
</ConfirmDialog> </ConfirmDialog>

View File

@ -1,6 +1,6 @@
<script> <script>
import { Input, Modal, notifications, ModalContent } from "@budibase/bbui" import { Input, Modal, notifications, ModalContent } from "@budibase/bbui"
import { store } from "builderStore" import { appStore, initialise } from "stores/builder"
import { API } from "api" import { API } from "api"
export let onComplete = () => {} export let onComplete = () => {}
@ -8,7 +8,7 @@
let revertModal let revertModal
let appName let appName
$: appId = $store.appId $: appId = $appStore.appId
const revert = async () => { const revert = async () => {
try { try {
@ -16,7 +16,7 @@
// Reset frontend state after revert // Reset frontend state after revert
const applicationPkg = await API.fetchAppPackage(appId) const applicationPkg = await API.fetchAppPackage(appId)
await store.actions.initialise(applicationPkg) await initialise(applicationPkg)
notifications.info("Changes reverted successfully") notifications.info("Changes reverted successfully")
onComplete() onComplete()
} catch (error) { } catch (error) {
@ -38,7 +38,7 @@
title="Revert Changes" title="Revert Changes"
confirmText="Revert" confirmText="Revert"
onConfirm={revert} onConfirm={revert}
disabled={appName !== $store.name} disabled={appName !== $appStore.name}
> >
<span <span
>The changes you have made will be deleted and the application reverted >The changes you have made will be deleted and the application reverted

View File

@ -7,7 +7,7 @@
Button, Button,
StatusLight, StatusLight,
} from "@budibase/bbui" } from "@budibase/bbui"
import { store } from "builderStore" import { appStore, initialise } from "stores/builder"
import { API } from "api" import { API } from "api"
export function show() { export function show() {
@ -23,17 +23,17 @@
let updateModal let updateModal
$: appId = $store.appId $: appId = $appStore.appId
$: updateAvailable = $: updateAvailable =
$store.upgradableVersion && $appStore.upgradableVersion &&
$store.version && $appStore.version &&
$store.upgradableVersion !== $store.version $appStore.upgradableVersion !== $appStore.version
$: revertAvailable = $store.revertableVersion != null $: revertAvailable = $appStore.revertableVersion != null
const refreshAppPackage = async () => { const refreshAppPackage = async () => {
try { try {
const pkg = await API.fetchAppPackage(appId) const pkg = await API.fetchAppPackage(appId)
await store.actions.initialise(pkg) await initialise(pkg)
} catch (error) { } catch (error) {
notifications.error("Error fetching app package") notifications.error("Error fetching app package")
} }
@ -46,7 +46,7 @@
// Don't wait for the async refresh, since this causes modal flashing // Don't wait for the async refresh, since this causes modal flashing
refreshAppPackage() refreshAppPackage()
notifications.success( notifications.success(
`App updated successfully to version ${$store.upgradableVersion}` `App updated successfully to version ${$appStore.upgradableVersion}`
) )
onComplete() onComplete()
} catch (err) { } catch (err) {
@ -62,7 +62,7 @@
// Don't wait for the async refresh, since this causes modal flashing // Don't wait for the async refresh, since this causes modal flashing
refreshAppPackage() refreshAppPackage()
notifications.success( notifications.success(
`App reverted successfully to version ${$store.revertableVersion}` `App reverted successfully to version ${$appStore.revertableVersion}`
) )
} catch (err) { } catch (err) {
notifications.error(`Error reverting app: ${err}`) notifications.error(`Error reverting app: ${err}`)
@ -89,20 +89,21 @@
</div> </div>
{#if updateAvailable} {#if updateAvailable}
<Body size="S"> <Body size="S">
This app is currently using version <b>{$store.version}</b>, but version This app is currently using version <b>{$appStore.version}</b>, but
<b>{$store.upgradableVersion}</b> is available. Updates can contain new features, version
performance improvements and bug fixes. <b>{$appStore.upgradableVersion}</b> is available. Updates can contain new
features, performance improvements and bug fixes.
</Body> </Body>
{:else} {:else}
<Body size="S"> <Body size="S">
This app is currently using version <b>{$store.version}</b> which is the This app is currently using version <b>{$appStore.version}</b> which is the
latest version available. latest version available.
</Body> </Body>
{/if} {/if}
{#if revertAvailable} {#if revertAvailable}
<Body size="S"> <Body size="S">
You can revert this app to version You can revert this app to version
<b>{$store.revertableVersion}</b> <b>{$appStore.revertableVersion}</b>
if you're experiencing issues with the current version. if you're experiencing issues with the current version.
</Body> </Body>
{/if} {/if}

Some files were not shown because too many files have changed in this diff Show More