Merge remote-tracking branch 'origin/master' into feature/add-buttongroup-to-formblock

This commit is contained in:
Dean 2023-11-23 09:13:08 +00:00
commit 105e9db00e
319 changed files with 2244 additions and 1118 deletions

View File

@ -57,7 +57,10 @@
"destructuredArrayIgnorePattern": "^_"
}
],
"import/no-relative-packages": "error"
"import/no-relative-packages": "error",
"import/export": "error",
"import/no-duplicates": "error",
"import/newline-after-import": "error"
},
"globals": {
"GeolocationPositionError": true

View File

@ -12,6 +12,13 @@ on:
- master
pull_request:
workflow_dispatch:
workflow_call:
inputs:
run_as_oss:
type: boolean
required: false
description: Force running checks as if it was an OSS contributor
default: false
env:
BRANCH: ${{ github.event.pull_request.head.ref }}
@ -19,7 +26,7 @@ env:
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
NX_BASE_BRANCH: origin/${{ github.base_ref }}
USE_NX_AFFECTED: ${{ github.event_name == 'pull_request' }}
IS_OSS_CONTRIBUTOR: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != 'Budibase/budibase' }}
IS_OSS_CONTRIBUTOR: ${{ inputs.run_as_oss == true || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != 'Budibase/budibase') }}
jobs:
lint:

View File

@ -0,0 +1,35 @@
name: OSS contributor checks
on:
workflow_dispatch:
schedule:
- cron: "0 8,16 * * 1-5" # on weekdays at 8am and 4pm
jobs:
run-checks:
name: Publish server and worker docker images
uses: ./.github/workflows/budibase_ci.yml
with:
run_as_oss: true
secrets: inherit
notify-error:
needs: ["run-checks"]
if: ${{ failure() }}
name: Notify error
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set commit SHA
id: set_sha
run: echo "::set-output name=sha::$(git rev-parse --short ${{ github.sha }})"
- name: Notify error
uses: tsickert/discord-webhook@v5.3.0
with:
webhook-url: ${{ secrets.OSS_CHECKS_WEBHOOK_URL }}
embed-title: 🚨 OSS checks failed in master
embed-url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
embed-description: |
Git sha: `${{ steps.set_sha.outputs.sha }}`

View File

@ -7,6 +7,7 @@ on:
jobs:
release:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

View File

@ -1,13 +1,11 @@
node_modules
dist
*.spec.js
packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
packages/server/builder
packages/server/coverage
packages/worker/coverage
packages/backend-core/coverage
packages/server/client
packages/server/src/definitions/openapi.ts
packages/worker/coverage
packages/backend-core/coverage
packages/builder/.routify
packages/sdk/sdk
packages/pro/coverage

View File

@ -46,11 +46,9 @@ spec:
image: minio/minio
imagePullPolicy: ""
livenessProbe:
exec:
command:
- curl
- -f
- http://localhost:9000/minio/health/live
httpGet:
path: /minio/health/live
port: 9000
failureThreshold: 3
periodSeconds: 30
timeoutSeconds: 20

View File

@ -1,24 +0,0 @@
#!/bin/bash
echo ${TARGETBUILD} > /buildtarget.txt
if [[ "${TARGETBUILD}" = "aas" ]]; then
# Azure AppService uses /home for persistent data & SSH on port 2222
DATA_DIR="${DATA_DIR:-/home}"
WEBSITES_ENABLE_APP_SERVICE_STORAGE=true
mkdir -p $DATA_DIR/{search,minio,couch}
mkdir -p $DATA_DIR/couch/{dbs,views}
chown -R couchdb:couchdb $DATA_DIR/couch/
apt update
apt-get install -y openssh-server
echo "root:Docker!" | chpasswd
mkdir -p /tmp
chmod +x /tmp/ssh_setup.sh \
&& (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null)
cp /etc/sshd_config /etc/ssh/sshd_config
/etc/init.d/ssh restart
sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini
sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini
else
sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini
sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini
fi

View File

@ -25,7 +25,7 @@ if [[ $(curl -s -w "%{http_code}\n" http://localhost:4002/health -o /dev/null) -
healthy=false
fi
if [[ $(curl -s -w "%{http_code}\n" http://localhost:5984/ -o /dev/null) -ne 200 ]]; then
if [[ $(curl -s -w "%{http_code}\n" http://localhost:5984/_up -o /dev/null) -ne 200 ]]; then
echo 'ERROR: CouchDB is not running';
healthy=false
fi

View File

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

View File

@ -1,5 +1,6 @@
const _passport = require("koa-passport")
const LocalStrategy = require("passport-local").Strategy
import { getGlobalDB } from "../context"
import { Cookie } from "../constants"
import { getSessionsForUser, invalidateSessions } from "../security/sessions"
@ -26,6 +27,7 @@ import { clearCookie, getCookie } from "../utils"
import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso"
const refresh = require("passport-oauth2-refresh")
export {
auditLog,
authError,

View File

@ -17,7 +17,6 @@ import { DocumentType, SEPARATOR } from "../constants"
import { CacheKey, TTL, withCache } from "../cache"
import * as context from "../context"
import env from "../environment"
import environment from "../environment"
// UTILS
@ -181,10 +180,10 @@ export async function getGoogleDatasourceConfig(): Promise<
}
export function getDefaultGoogleConfig(): GoogleInnerConfig | undefined {
if (environment.GOOGLE_CLIENT_ID && environment.GOOGLE_CLIENT_SECRET) {
if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
return {
clientID: environment.GOOGLE_CLIENT_ID!,
clientSecret: environment.GOOGLE_CLIENT_SECRET!,
clientID: env.GOOGLE_CLIENT_ID!,
clientSecret: env.GOOGLE_CLIENT_SECRET!,
activated: true,
}
}

View File

@ -1,4 +1,5 @@
import { prefixed, DocumentType } from "@budibase/types"
export {
SEPARATOR,
UNICODE_MAX,

View File

@ -5,7 +5,6 @@ const { getDB } = require("../db")
describe("db", () => {
describe("getDB", () => {
it("returns a db", async () => {
const dbName = structures.db.id()
const db = getDB(dbName)
expect(db).toBeDefined()

View File

@ -6,6 +6,7 @@ import { AppState, DeletedApp, getAppMetadata } from "../cache/appMetadata"
import { isDevApp, isDevAppID, getProdAppID } from "../docIds/conversions"
import { App, Database } from "@budibase/types"
import { getStartEndKeyURL } from "../docIds"
export * from "../docIds"
/**

View File

@ -1,5 +1,6 @@
import { APP_DEV_PREFIX, APP_PREFIX } from "../constants"
import { App } from "@budibase/types"
const NO_APP_ERROR = "No app provided"
export function isDevAppID(appId?: string) {

View File

@ -1,2 +1,3 @@
import PosthogProcessor from "./PosthogProcessor"
export default PosthogProcessor

View File

@ -1,7 +1,9 @@
import { testEnv } from "../../../../../tests/extra"
import PosthogProcessor from "../PosthogProcessor"
import { Event, IdentityType, Hosting } from "@budibase/types"
const tk = require("timekeeper")
import * as cache from "../../../../cache/generic"
import { CacheKey } from "../../../../cache/generic"
import * as context from "../../../../context"

View File

@ -1,5 +1,6 @@
import env from "../environment"
import * as context from "../context"
export * from "./installation"
/**

View File

@ -38,6 +38,7 @@ export * as docIds from "./docIds"
// circular dependencies
import * as context from "./context"
import * as _tenancy from "./tenancy"
export const tenancy = {
..._tenancy,
...context,

View File

@ -1,7 +1,6 @@
import { newid } from "./utils"
import * as events from "./events"
import { StaticDatabases } from "./db"
import { doWithDB } from "./db"
import { StaticDatabases, doWithDB } from "./db"
import { Installation, IdentityType, Database } from "@budibase/types"
import * as context from "./context"
import semver from "semver"

View File

@ -1,4 +1,5 @@
import { Header } from "../../constants"
const correlator = require("correlation-id")
export const setHeader = (headers: any) => {

View File

@ -1,5 +1,6 @@
import { Header } from "../../constants"
import { v4 as uuid } from "uuid"
const correlator = require("correlation-id")
const correlation = (ctx: any, next: any) => {

View File

@ -1,9 +1,12 @@
import env from "../../environment"
import { logger } from "./logger"
import { IncomingMessage } from "http"
const pino = require("koa-pino-logger")
import { Options } from "pino-http"
import { Ctx } from "@budibase/types"
const correlator = require("correlation-id")
export function pinoSettings(): Options {

View File

@ -2,6 +2,7 @@ export * as local from "./passport/local"
export * as google from "./passport/sso/google"
export * as oidc from "./passport/sso/oidc"
import * as datasourceGoogle from "./passport/datasource/google"
export const datasource = {
google: datasourceGoogle,
}

View File

@ -8,6 +8,7 @@ import {
SaveSSOUserFunction,
GoogleInnerConfig,
} from "@budibase/types"
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
export function buildVerifyFn(saveUserFn: SaveSSOUserFunction) {

View File

@ -6,6 +6,7 @@ const mockStrategy = require("passport-google-oauth").OAuth2Strategy
jest.mock("../sso")
import * as _sso from "../sso"
const sso = jest.mocked(_sso)
const mockSaveUserFn = jest.fn()

View File

@ -11,6 +11,7 @@ const mockSaveUser = jest.fn()
jest.mock("../../../../users")
import * as _users from "../../../../users"
const users = jest.mocked(_users)
const getErrorMessage = () => {

View File

@ -5,6 +5,7 @@ import { structures } from "../../../tests"
import { ContextUser, ServiceType } from "@budibase/types"
import { doInAppContext } from "../../context"
import env from "../../environment"
env._set("SERVICE_TYPE", ServiceType.APPS)
const appId = "app_aaa"

View File

@ -1,4 +1,5 @@
const sanitize = require("sanitize-s3-objectkey")
import AWS from "aws-sdk"
import stream, { Readable } from "stream"
import fetch from "node-fetch"

View File

@ -3,6 +3,7 @@ import { getLockClient } from "./init"
import { LockOptions, LockType } from "@budibase/types"
import * as context from "../context"
import env from "../environment"
import { logWarn } from "../logging"
async function getClient(
type: LockType,
@ -116,7 +117,7 @@ export async function doWithLock<T>(
const result = await task()
return { executed: true, result }
} catch (e: any) {
console.warn("lock error")
logWarn(`lock type: ${opts.type} error`, e)
// lock limit exceeded
if (e.name === "LockError") {
if (opts.type === LockType.TRY_ONCE) {
@ -124,11 +125,9 @@ export async function doWithLock<T>(
// due to retry count (0) exceeded
return { executed: false }
} else {
console.error(e)
throw e
}
} else {
console.error(e)
throw e
}
} finally {

View File

@ -75,10 +75,12 @@ export function getRedisConnectionDetails() {
}
const [host, port] = url.split(":")
const portNumber = parseInt(port)
return {
host,
password,
port: parseInt(port),
// assume default port for redis if invalid found
port: isNaN(portNumber) ? 6379 : portNumber,
}
}

View File

@ -1,7 +1,12 @@
import { BuiltinPermissionID, PermissionLevel } from "./permissions"
import { prefixRoleID, getRoleParams, DocumentType, SEPARATOR } from "../db"
import {
prefixRoleID,
getRoleParams,
DocumentType,
SEPARATOR,
doWithDB,
} from "../db"
import { getAppDB } from "../context"
import { doWithDB } from "../db"
import { Screen, Role as RoleDoc } from "@budibase/types"
import cloneDeep from "lodash/fp/cloneDeep"

View File

@ -1,6 +1,7 @@
const redis = require("../redis/init")
const { v4: uuidv4 } = require("uuid")
const { logWarn } = require("../logging")
import env from "../environment"
import {
Session,

View File

@ -1,9 +1,8 @@
import env from "../environment"
import * as eventHelpers from "./events"
import * as accounts from "../accounts"
import * as accountSdk from "../accounts"
import * as cache from "../cache"
import { getGlobalDB, getIdentity, getTenantId } from "../context"
import { doInTenant, getGlobalDB, getIdentity, getTenantId } from "../context"
import * as dbUtils from "../db"
import { EmailUnavailableError, HTTPError } from "../errors"
import * as platform from "../platform"
@ -11,12 +10,10 @@ import * as sessions from "../security/sessions"
import * as usersCore from "./users"
import {
Account,
AllDocsResponse,
BulkUserCreated,
BulkUserDeleted,
isSSOAccount,
isSSOUser,
RowResponse,
SaveUserOpts,
User,
UserStatus,
@ -467,7 +464,7 @@ export class UserDB {
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
// root account holder can't be deleted from inside budibase
const email = dbUser.email
const account = await accounts.getAccount(email)
const account = await accountSdk.getAccount(email)
if (account) {
if (dbUser.userId === getIdentity()!._id) {
throw new HTTPError('Please visit "Account" to delete this user', 400)
@ -488,6 +485,37 @@ export class UserDB {
await sessions.invalidateSessions(userId, { reason: "deletion" })
}
static async createAdminUser(
email: string,
password: string,
tenantId: string,
opts?: { ssoId?: string; hashPassword?: boolean; requirePassword?: boolean }
) {
const user: User = {
email: email,
password: password,
createdAt: Date.now(),
roles: {},
builder: {
global: true,
},
admin: {
global: true,
},
tenantId,
}
if (opts?.ssoId) {
user.ssoId = opts.ssoId
}
// always bust checklist beforehand, if an error occurs but can proceed, don't get
// stuck in a cycle
await cache.bustCache(cache.CacheKey.CHECKLIST)
return await UserDB.save(user, {
hashPassword: opts?.hashPassword,
requirePassword: opts?.requirePassword,
})
}
static async getGroups(groupIds: string[]) {
return await this.groups.getBulk(groupIds)
}

View File

@ -43,7 +43,7 @@ function removeUserPassword(users: User | User[]) {
return users
}
export const isSupportedUserSearch = (query: SearchQuery) => {
export function isSupportedUserSearch(query: SearchQuery) {
const allowed = [
{ op: SearchQueryOperators.STRING, key: "email" },
{ op: SearchQueryOperators.EQUAL, key: "_id" },
@ -68,10 +68,10 @@ export const isSupportedUserSearch = (query: SearchQuery) => {
return true
}
export const bulkGetGlobalUsersById = async (
export async function bulkGetGlobalUsersById(
userIds: string[],
opts?: GetOpts
) => {
) {
const db = getGlobalDB()
let users = (
await db.allDocs({
@ -85,7 +85,7 @@ export const bulkGetGlobalUsersById = async (
return users
}
export const getAllUserIds = async () => {
export async function getAllUserIds() {
const db = getGlobalDB()
const startKey = `${DocumentType.USER}${SEPARATOR}`
const response = await db.allDocs({
@ -95,7 +95,7 @@ export const getAllUserIds = async () => {
return response.rows.map(row => row.id)
}
export const bulkUpdateGlobalUsers = async (users: User[]) => {
export async function bulkUpdateGlobalUsers(users: User[]) {
const db = getGlobalDB()
return (await db.bulkDocs(users)) as BulkDocsResponse
}
@ -113,10 +113,10 @@ export async function getById(id: string, opts?: GetOpts): Promise<User> {
* Given an email address this will use a view to search through
* all the users to find one with this email address.
*/
export const getGlobalUserByEmail = async (
export async function getGlobalUserByEmail(
email: String,
opts?: GetOpts
): Promise<User | undefined> => {
): Promise<User | undefined> {
if (email == null) {
throw "Must supply an email address to view"
}
@ -139,11 +139,23 @@ export const getGlobalUserByEmail = async (
return user
}
export const searchGlobalUsersByApp = async (
export async function doesUserExist(email: string) {
try {
const user = await getGlobalUserByEmail(email)
if (Array.isArray(user) || user != null) {
return true
}
} catch (err) {
return false
}
return false
}
export async function searchGlobalUsersByApp(
appId: any,
opts: DatabaseQueryOpts,
getOpts?: GetOpts
) => {
) {
if (typeof appId !== "string") {
throw new Error("Must provide a string based app ID")
}
@ -167,10 +179,10 @@ export const searchGlobalUsersByApp = async (
Return any user who potentially has access to the application
Admins, developers and app users with the explicitly role.
*/
export const searchGlobalUsersByAppAccess = async (
export async function searchGlobalUsersByAppAccess(
appId: any,
opts?: { limit?: number }
) => {
) {
const roleSelector = `roles.${appId}`
let orQuery: any[] = [
@ -205,7 +217,7 @@ export const searchGlobalUsersByAppAccess = async (
return resp.rows
}
export const getGlobalUserByAppPage = (appId: string, user: User) => {
export function getGlobalUserByAppPage(appId: string, user: User) {
if (!user) {
return
}
@ -215,11 +227,11 @@ export const getGlobalUserByAppPage = (appId: string, user: User) => {
/**
* Performs a starts with search on the global email view.
*/
export const searchGlobalUsersByEmail = async (
export async function searchGlobalUsersByEmail(
email: string | unknown,
opts: any,
getOpts?: GetOpts
) => {
) {
if (typeof email !== "string") {
throw new Error("Must provide a string to search by")
}
@ -242,12 +254,12 @@ export const searchGlobalUsersByEmail = async (
}
const PAGE_LIMIT = 8
export const paginatedUsers = async ({
export async function paginatedUsers({
bookmark,
query,
appId,
limit,
}: SearchUsersRequest = {}) => {
}: SearchUsersRequest = {}) {
const db = getGlobalDB()
const pageSize = limit ?? PAGE_LIMIT
const pageLimit = pageSize + 1

View File

@ -1,4 +1,5 @@
import env from "../environment"
export * from "../docIds/newid"
const bcrypt = env.JS_BCRYPT ? require("bcryptjs") : require("bcrypt")

View File

@ -11,6 +11,7 @@ import {
TenantResolutionStrategy,
} from "@budibase/types"
import type { SetOption } from "cookies"
const jwt = require("jsonwebtoken")
const APP_PREFIX = DocumentType.APP + SEPARATOR

View File

@ -1,5 +1,5 @@
const _ = require('lodash/fp')
const {structures} = require("../../../tests")
const _ = require("lodash/fp")
const { structures } = require("../../../tests")
jest.mock("../../../src/context")
jest.mock("../../../src/db")
@ -7,10 +7,9 @@ jest.mock("../../../src/db")
const context = require("../../../src/context")
const db = require("../../../src/db")
const {getCreatorCount} = require('../../../src/users/users')
const { getCreatorCount } = require("../../../src/users/users")
describe("Users", () => {
let getGlobalDBMock
let getGlobalUserParamsMock
let paginationMock
@ -26,26 +25,26 @@ describe("Users", () => {
it("Retrieves the number of creators", async () => {
const getUsers = (offset, limit, creators = false) => {
const range = _.range(offset, limit)
const opts = creators ? {builder: {global: true}} : undefined
const opts = creators ? { builder: { global: true } } : undefined
return range.map(() => structures.users.user(opts))
}
const page1Data = getUsers(0, 8)
const page2Data = getUsers(8, 12, true)
getGlobalDBMock.mockImplementation(() => ({
name : "fake-db",
name: "fake-db",
allDocs: () => ({
rows: [...page1Data, ...page2Data]
})
rows: [...page1Data, ...page2Data],
}),
}))
paginationMock.mockImplementationOnce(() => ({
data: page1Data,
hasNextPage: true,
nextPage: "1"
nextPage: "1",
}))
paginationMock.mockImplementation(() => ({
data: page2Data,
hasNextPage: false,
nextPage: undefined
nextPage: undefined,
}))
const creatorsCount = await getCreatorCount()
expect(creatorsCount).toBe(4)

View File

@ -1,3 +1,4 @@
jest.mock("../../../../src/logging/alerts")
import * as _alerts from "../../../../src/logging/alerts"
export const alerts = jest.mocked(_alerts)

View File

@ -1,5 +1,6 @@
jest.mock("../../../../src/accounts")
import * as _accounts from "../../../../src/accounts"
export const accounts = jest.mocked(_accounts)
export * as date from "./date"

View File

@ -1,2 +1,3 @@
import Chance from "./Chance"
export const generator = new Chance()

View File

@ -9,6 +9,7 @@ mocks.fetch.enable()
// mock all dates to 2020-01-01T00:00:00.000Z
// use tk.reset() to use real dates in individual tests
import tk from "timekeeper"
tk.freeze(mocks.date.MOCK_DATE)
if (!process.env.DEBUG) {

View File

@ -1,5 +1,6 @@
<script>
import "@spectrum-css/actiongroup/dist/index-vars.css"
export let vertical = false
export let justified = false
export let quiet = false

View File

@ -1,5 +1,6 @@
<script>
import "@spectrum-css/avatar/dist/index-vars.css"
let sizes = new Map([
["XXS", "--spectrum-alias-avatar-size-50"],
["XS", "--spectrum-alias-avatar-size-75"],

View File

@ -1,5 +1,6 @@
<script>
import "@spectrum-css/buttongroup/dist/index-vars.css"
export let vertical = false
export let gap = ""

View File

@ -1,5 +1,6 @@
<script>
import "@spectrum-css/divider/dist/index-vars.css"
export let size = "M"
export let vertical = false

View File

@ -3,8 +3,7 @@
import Button from "../Button/Button.svelte"
import Body from "../Typography/Body.svelte"
import Heading from "../Typography/Heading.svelte"
import { setContext } from "svelte"
import { createEventDispatcher } from "svelte"
import { setContext, createEventDispatcher } from "svelte"
import { generate } from "shortid"
export let title

View File

@ -10,6 +10,7 @@
export let disabled = false
export let error = null
export let size = "M"
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -18,6 +19,6 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Checkbox {error} {disabled} {text} {value} {size} on:change={onChange} />
</Field>

View File

@ -11,6 +11,7 @@
export let error = null
export let placeholder = "Choose an option or type"
export let options = []
export let helpText = null
export let getOptionLabel = option => extractProperty(option, "label")
export let getOptionValue = option => extractProperty(option, "value")
@ -27,7 +28,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Combobox
{error}
{disabled}

View File

@ -4,7 +4,6 @@
import { createEventDispatcher } from "svelte"
export let value = false
export let error = null
export let id = null
export let text = null
export let disabled = false
@ -22,7 +21,6 @@
<label
class="spectrum-Checkbox spectrum-Checkbox--emphasized {sizeClass}"
class:is-invalid={!!error}
class:checked={value}
class:is-indeterminate={indeterminate}
class:readonly

View File

@ -6,7 +6,6 @@
export let direction = "vertical"
export let value = []
export let options = []
export let error = null
export let disabled = false
export let readonly = false
export let getOptionLabel = option => option
@ -34,7 +33,6 @@
<div
title={getOptionLabel(option)}
class="spectrum-Checkbox spectrum-FieldGroup-item"
class:is-invalid={!!error}
class:readonly
>
<label

View File

@ -10,7 +10,6 @@
export let placeholder = "Choose an option or type"
export let disabled = false
export let readonly = false
export let error = null
export let options = []
export let getOptionLabel = option => option
export let getOptionValue = option => option
@ -39,12 +38,10 @@
<div
class="spectrum-InputGroup"
class:is-focused={open || focus}
class:is-invalid={!!error}
class:is-disabled={disabled}
>
<div
class="spectrum-Textfield spectrum-InputGroup-textfield"
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={open || focus}
>

View File

@ -10,7 +10,6 @@
export let id = null
export let disabled = false
export let readonly = false
export let error = null
export let enableTime = true
export let value = null
export let placeholder = null
@ -188,7 +187,6 @@
<div
id={flatpickrId}
class:is-disabled={disabled || readonly}
class:is-invalid={!!error}
class="flatpickr spectrum-InputGroup spectrum-Datepicker"
class:is-focused={open}
aria-readonly="false"
@ -199,17 +197,7 @@
on:click={flatpickr?.open}
class="spectrum-Textfield spectrum-InputGroup-textfield"
class:is-disabled={disabled}
class:is-invalid={!!error}
>
{#if !!error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<input
{disabled}
{readonly}
@ -227,7 +215,6 @@
class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
tabindex="-1"
class:is-disabled={disabled}
class:is-invalid={!!error}
on:click={flatpickr?.open}
>
<svg

View File

@ -22,7 +22,6 @@
export let handleFileTooLarge = null
export let handleTooManyFiles = null
export let gallery = true
export let error = null
export let fileTags = []
export let maximum = null
export let extensions = "*"
@ -222,7 +221,6 @@
{#if showDropzone}
<div
class="spectrum-Dropzone"
class:is-invalid={!!error}
class:disabled
role="region"
tabindex="0"
@ -351,9 +349,6 @@
.spectrum-Dropzone {
user-select: none;
}
.spectrum-Dropzone.is-invalid {
border-color: var(--spectrum-global-color-red-400);
}
input[type="file"] {
display: none;
}

View File

@ -14,7 +14,6 @@
export let disabled = false
export let readonly = false
export let updateOnChange = true
export let error = null
export let options = []
export let getOptionLabel = option => extractProperty(option, "label")
export let getOptionValue = option => extractProperty(option, "value")
@ -111,27 +110,12 @@
}
</script>
<div
class="spectrum-InputGroup"
class:is-invalid={!!error}
class:is-disabled={disabled}
>
<div class="spectrum-InputGroup" class:is-disabled={disabled}>
<div
class="spectrum-Textfield spectrum-InputGroup-textfield"
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={focus}
>
{#if error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<input
{id}
on:click

View File

@ -6,7 +6,6 @@
export let id = null
export let placeholder = null
export let disabled = false
export let error = null
export let options = []
export let getOptionLabel = option => option
export let getOptionValue = option => option
@ -84,7 +83,6 @@
<Picker
on:loadMore
{id}
{error}
{disabled}
{readonly}
{fieldText}

View File

@ -14,7 +14,6 @@
export let id = null
export let disabled = false
export let error = null
export let fieldText = ""
export let fieldIcon = ""
export let fieldColour = ""
@ -113,7 +112,6 @@
class="spectrum-Picker spectrum-Picker--sizeM"
class:spectrum-Picker--quiet={quiet}
{disabled}
class:is-invalid={!!error}
class:is-open={open}
aria-haspopup="listbox"
on:click={onClick}
@ -142,16 +140,6 @@
>
{fieldText}
</span>
{#if error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
focusable="false"
aria-hidden="true"
aria-label="Folder"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<svg
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
focusable="false"

View File

@ -16,7 +16,6 @@
export let id = null
export let placeholder = "Choose an option or type"
export let disabled = false
export let error = null
export let secondaryOptions = []
export let primaryOptions = []
export let secondaryFieldText = ""
@ -105,14 +104,9 @@
}
</script>
<div
class="spectrum-InputGroup"
class:is-invalid={!!error}
class:is-disabled={disabled}
>
<div class="spectrum-InputGroup" class:is-disabled={disabled}>
<div
class="spectrum-Textfield spectrum-InputGroup-textfield"
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={focus}
class:is-full-width={!secondaryOptions.length}

View File

@ -6,7 +6,6 @@
export let direction = "vertical"
export let value = null
export let options = []
export let error = null
export let disabled = false
export let readonly = false
export let getOptionLabel = option => option
@ -40,7 +39,6 @@
<div
title={getOptionTitle(option)}
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
class:is-invalid={!!error}
class:readonly
>
<input

View File

@ -5,14 +5,13 @@
export let placeholder = null
export let disabled = false
export let readonly = false
export let error = null
export let height = null
export let id = null
export let fullScreenOffset = null
export let easyMDEOptions = null
</script>
<div class:error>
<div>
<MarkdownEditor
{value}
{placeholder}
@ -27,18 +26,4 @@
</div>
<style>
.error :global(.EasyMDEContainer .editor-toolbar) {
border-top-color: var(--spectrum-semantic-negative-color-default);
border-left-color: var(--spectrum-semantic-negative-color-default);
border-right-color: var(--spectrum-semantic-negative-color-default);
}
.error :global(.EasyMDEContainer .CodeMirror) {
border-bottom-color: var(--spectrum-semantic-negative-color-default);
border-left-color: var(--spectrum-semantic-negative-color-default);
border-right-color: var(--spectrum-semantic-negative-color-default);
}
.error :global(.EasyMDEContainer .editor-preview-side) {
border-bottom-color: var(--spectrum-semantic-negative-color-default);
border-right-color: var(--spectrum-semantic-negative-color-default);
}
</style>

View File

@ -6,7 +6,6 @@
export let id = null
export let placeholder = "Choose an option"
export let disabled = false
export let error = null
export let options = []
export let getOptionLabel = option => option
export let getOptionValue = option => option
@ -71,7 +70,6 @@
on:loadMore
{quiet}
{id}
{error}
{disabled}
{readonly}
{fieldText}

View File

@ -7,7 +7,6 @@
export let value = null
export let placeholder = null
export let disabled = false
export let error = null
export let id = null
export let readonly = false
export let updateOnChange = true
@ -98,20 +97,9 @@
<div
class="spectrum-Stepper"
class:spectrum-Stepper--quiet={quiet}
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={focus}
>
{#if error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<div class="spectrum-Textfield spectrum-Stepper-textfield">
<input
{disabled}

View File

@ -6,7 +6,6 @@
export let placeholder = null
export let disabled = false
export let readonly = false
export let error = null
export let id = null
export let height = null
export let minHeight = null
@ -41,20 +40,9 @@
<div
style={`${heightString}${minHeightString}`}
class="spectrum-Textfield spectrum-Textfield--multiline"
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={focus}
>
{#if error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM
spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<!-- prettier-ignore -->
<textarea
bind:this={textarea}

View File

@ -6,7 +6,6 @@
export let placeholder = null
export let type = "text"
export let disabled = false
export let error = null
export let id = null
export let readonly = false
export let updateOnChange = true
@ -78,19 +77,9 @@
<div
class="spectrum-Textfield"
class:spectrum-Textfield--quiet={quiet}
class:is-invalid={!!error}
class:is-disabled={disabled}
class:is-focused={focus}
>
{#if error}
<svg
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-Alert" />
</svg>
{/if}
<input
bind:this={field}
{disabled}

View File

@ -16,6 +16,7 @@
export let appendTo = undefined
export let ignoreTimezones = false
export let range = false
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -30,7 +31,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<DatePicker
{error}
{disabled}

View File

@ -17,6 +17,7 @@
export let fileTags = []
export let maximum = undefined
export let compact = false
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -25,7 +26,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<CoreDropzone
{error}
{disabled}

View File

@ -16,6 +16,7 @@
export let autofocus
export let variables
export let showModal
export let helpText = null
export let environmentVariablesEnabled
export let handleUpgradePanel
const dispatch = createEventDispatcher()
@ -25,7 +26,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<EnvDropdown
{updateOnChange}
{error}

View File

@ -1,11 +1,13 @@
<script>
import "@spectrum-css/fieldlabel/dist/index-vars.css"
import FieldLabel from "./FieldLabel.svelte"
import Icon from "../Icon/Icon.svelte"
export let id = null
export let label = null
export let labelPosition = "above"
export let error = null
export let helpText = null
export let tooltip = ""
</script>
@ -17,6 +19,10 @@
<slot />
{#if error}
<div class="error">{error}</div>
{:else if helpText}
<div class="helpText">
<Icon name="HelpOutline" /> <span>{helpText}</span>
</div>
{/if}
</div>
</div>
@ -39,4 +45,21 @@
font-size: var(--spectrum-global-dimension-font-size-75);
margin-top: var(--spectrum-global-dimension-size-75);
}
.helpText {
display: flex;
margin-top: var(--spectrum-global-dimension-size-75);
align-items: center;
}
.helpText :global(svg) {
width: 14px;
color: var(--grey-5);
margin-right: 6px;
}
.helpText span {
color: var(--grey-7);
font-size: var(--spectrum-global-dimension-font-size-75);
}
</style>

View File

@ -14,6 +14,7 @@
export let title = null
export let value = null
export let tooltip = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -22,7 +23,7 @@
}
</script>
<Field {label} {labelPosition} {error} {tooltip}>
<Field {helpText} {label} {labelPosition} {error} {tooltip}>
<CoreFile
{error}
{disabled}

View File

@ -15,6 +15,7 @@
export let quiet = false
export let autofocus
export let autocomplete
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -23,7 +24,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<TextField
{updateOnChange}
{error}

View File

@ -15,6 +15,7 @@
export let updateOnChange = true
export let quiet = false
export let autofocus
export let helpText = null
export let options = []
const dispatch = createEventDispatcher()
@ -29,7 +30,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<InputDropdown
{updateOnChange}
{error}

View File

@ -18,6 +18,7 @@
export let autocomplete = false
export let searchTerm = null
export let customPopoverHeight
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -26,7 +27,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Multiselect
{error}
{disabled}

View File

@ -26,6 +26,7 @@
export let secondaryOptions = []
export let searchTerm
export let showClearIcon = true
export let helpText = null
let primaryLabel
let secondaryLabel
@ -93,7 +94,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<PickerDropdown
{searchTerm}
{autocomplete}

View File

@ -13,6 +13,7 @@
export let getOptionLabel = option => extractProperty(option, "label")
export let getOptionValue = option => extractProperty(option, "value")
export let getOptionTitle = option => extractProperty(option, "label")
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -27,7 +28,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<RadioGroup
{error}
{disabled}

View File

@ -13,6 +13,7 @@
export let id = null
export let fullScreenOffset = null
export let easyMDEOptions = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -21,7 +22,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<RichTextField
{error}
{disabled}

View File

@ -11,6 +11,7 @@
export let updateOnChange = true
export let quiet = false
export let inputRef
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -19,7 +20,7 @@
}
</script>
<Field {label} {labelPosition}>
<Field {helpText} {label} {labelPosition}>
<Search
{updateOnChange}
{disabled}

View File

@ -26,6 +26,7 @@
export let align
export let footer = null
export let tag = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
value = e.detail
@ -40,7 +41,7 @@
}
</script>
<Field {label} {labelPosition} {error} {tooltip}>
<Field {helpText} {label} {labelPosition} {error} {tooltip}>
<Select
{quiet}
{error}

View File

@ -11,6 +11,7 @@
export let step = 1
export let disabled = false
export let error = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -19,6 +20,6 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Slider {disabled} {value} {min} {max} {step} on:change={onChange} />
</Field>

View File

@ -15,6 +15,7 @@
export let min = null
export let max = null
export let step = 1
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -23,7 +24,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Stepper
{updateOnChange}
{error}

View File

@ -12,6 +12,7 @@
export let getCaretPosition = null
export let height = null
export let minHeight = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -20,7 +21,7 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<TextArea
bind:getCaretPosition
{error}

View File

@ -9,6 +9,7 @@
export let text = null
export let disabled = false
export let error = null
export let helpText = null
const dispatch = createEventDispatcher()
const onChange = e => {
@ -17,6 +18,6 @@
}
</script>
<Field {label} {labelPosition} {error}>
<Field {helpText} {label} {labelPosition} {error}>
<Switch {error} {disabled} {text} {value} on:change={onChange} />
</Field>

View File

@ -16,10 +16,9 @@
const dispatch = createEventDispatcher()
const onClick = e => {
const onClick = () => {
if (!disabled) {
dispatch("click")
e.stopPropagation()
}
}
</script>

View File

@ -1,5 +1,6 @@
<script>
import Input from "../Form/Input.svelte"
let value = ""
</script>

View File

@ -4,6 +4,7 @@
import Icon from "../Icon/Icon.svelte"
import Popover from "../Popover/Popover.svelte"
import { onMount } from "svelte"
const flipDurationMs = 150
export let constraints

View File

@ -1,11 +1,10 @@
<script>
import "@spectrum-css/popover/dist/index-vars.css"
import Portal from "svelte-portal"
import { createEventDispatcher } from "svelte"
import { createEventDispatcher, getContext } from "svelte"
import positionDropdown from "../Actions/position_dropdown"
import clickOutside from "../Actions/click_outside"
import { fly } from "svelte/transition"
import { getContext } from "svelte"
import Context from "../context"
const dispatch = createEventDispatcher()

View File

@ -1,7 +1,9 @@
<script>
import { getContext } from "svelte"
const multilevel = getContext("sidenav-type")
import Badge from "../Badge/Badge.svelte"
export let href = ""
export let external = false
export let heading = ""

View File

@ -1,6 +1,7 @@
<script>
import { setContext } from "svelte"
import "@spectrum-css/sidenav/dist/index-vars.css"
export let multilevel = false
setContext("sidenav-type", multilevel)
</script>

View File

@ -1,6 +1,7 @@
<script>
import "@spectrum-css/label/dist/index-vars.css"
import Badge from "../Badge/Badge.svelte"
export let value
const displayLimit = 5

View File

@ -1,6 +1,7 @@
<script>
import { getContext, onMount, createEventDispatcher } from "svelte"
import Portal from "svelte-portal"
export let title
export let icon = ""
export let id

View File

@ -1,4 +1,5 @@
import { helpers } from "@budibase/shared-core"
export const deepGet = helpers.deepGet
/**

View File

@ -1090,17 +1090,18 @@ export const removeBindings = (obj, replacement = "Invalid binding") => {
* When converting from readable to runtime it can sometimes add too many square brackets,
* this makes sure that doesn't happen.
*/
const shouldReplaceBinding = (currentValue, convertFrom, convertTo) => {
if (!currentValue?.includes(convertFrom)) {
const shouldReplaceBinding = (currentValue, from, convertTo, binding) => {
if (!currentValue?.includes(from)) {
return false
}
if (convertTo === "readableBinding") {
return true
// Dont replace if the value already matches the readable binding
return currentValue.indexOf(binding.readableBinding) === -1
}
// remove all the spaces, if the input is surrounded by spaces e.g. [ Auto ID ] then
// this makes sure it is detected
const noSpaces = currentValue.replace(/\s+/g, "")
const fromNoSpaces = convertFrom.replace(/\s+/g, "")
const fromNoSpaces = from.replace(/\s+/g, "")
const invalids = [
`[${fromNoSpaces}]`,
`"${fromNoSpaces}"`,
@ -1152,8 +1153,11 @@ const bindingReplacement = (
// in the search, working from longest to shortest so always use best match first
let searchString = newBoundValue
for (let from of convertFromProps) {
if (isJS || shouldReplaceBinding(newBoundValue, from, convertTo)) {
const binding = bindableProperties.find(el => el[convertFrom] === from)
const binding = bindableProperties.find(el => el[convertFrom] === from)
if (
isJS ||
shouldReplaceBinding(newBoundValue, from, convertTo, binding)
) {
let idx
do {
// see if any instances of this binding exist in the search string

View File

@ -4,11 +4,10 @@ import { getTemporalStore } from "./store/temporal"
import { getThemeStore } from "./store/theme"
import { getUserStore } from "./store/users"
import { getDeploymentStore } from "./store/deployments"
import { derived, writable } from "svelte/store"
import { derived, writable, get } from "svelte/store"
import { findComponent, findComponentPath } from "./componentUtils"
import { RoleUtils } from "@budibase/frontend-core"
import { createHistoryStore } from "builderStore/store/history"
import { get } from "svelte/store"
export const store = getFrontendStore()
export const automationStore = getAutomationStore()

View File

@ -0,0 +1,86 @@
import { expect, describe, it, vi } from "vitest"
import {
runtimeToReadableBinding,
readableToRuntimeBinding,
} 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 }}.`)
})
})

View File

@ -7,11 +7,9 @@ import {
} from "builderStore"
import { datasources, tables } from "stores/backend"
import { get } from "svelte/store"
import { auth } from "stores/portal"
import { SocketEvent, BuilderSocketEvent } from "@budibase/shared-core"
import { apps } from "stores/portal"
import { auth, apps } from "stores/portal"
import { SocketEvent, BuilderSocketEvent, helpers } from "@budibase/shared-core"
import { notifications } from "@budibase/bbui"
import { helpers } from "@budibase/shared-core"
export const createBuilderWebsocket = appId => {
const socket = createWebsocket("/socket/builder")

View File

@ -1,5 +1,9 @@
<script>
import { automationStore, selectedAutomation } from "builderStore"
import {
automationStore,
selectedAutomation,
automationHistoryStore,
} from "builderStore"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import FlowItem from "./FlowItem.svelte"
import TestDataModal from "./TestDataModal.svelte"
@ -8,7 +12,6 @@
import { Icon, notifications, Modal } from "@budibase/bbui"
import { ActionStepID } from "constants/backend/automations"
import UndoRedoControl from "components/common/UndoRedoControl.svelte"
import { automationHistoryStore } from "builderStore"
export let automation

View File

@ -1,7 +1,7 @@
<script>
import { automationStore } from "builderStore"
import { notifications } from "@budibase/bbui"
import {
notifications,
Input,
InlineAlert,
ModalContent,

View File

@ -1,7 +1,12 @@
<script>
import { automationStore } from "builderStore"
import { notifications } from "@budibase/bbui"
import { Icon, Input, ModalContent, Modal } from "@budibase/bbui"
import {
notifications,
Icon,
Input,
ModalContent,
Modal,
} from "@budibase/bbui"
export let automation
export let onCancel = undefined

View File

@ -38,12 +38,11 @@
EditorModes,
} from "components/common/CodeEditor"
import FilterDrawer from "components/design/settings/controls/FilterEditor/FilterDrawer.svelte"
import { LuceneUtils } from "@budibase/frontend-core"
import { LuceneUtils, Utils } from "@budibase/frontend-core"
import {
getSchemaForDatasourcePlus,
getEnvironmentBindings,
} from "builderStore/dataBinding"
import { Utils } from "@budibase/frontend-core"
import { TriggerStepID, ActionStepID } from "constants/backend/automations"
import { onMount } from "svelte"
import { cloneDeep } from "lodash/fp"

View File

@ -2,6 +2,7 @@
import { Button, Select, Input, Label } from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte"
import { flags } from "stores/backend"
const dispatch = createEventDispatcher()
export let value

View File

@ -1,8 +1,7 @@
<script>
import { Icon, notifications } from "@budibase/bbui"
import { Icon, notifications, ModalContent } from "@budibase/bbui"
import { automationStore, selectedAutomation } from "builderStore"
import WebhookDisplay from "./WebhookDisplay.svelte"
import { ModalContent } from "@budibase/bbui"
import { onMount, onDestroy } from "svelte"
const POLL_RATE_MS = 2500

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