Merge remote-tracking branch 'origin/master' into feature/monolith-js-refactor
This commit is contained in:
commit
ce9de420e2
|
@ -1,4 +1,4 @@
|
|||
name: Tag release
|
||||
name: Release
|
||||
concurrency:
|
||||
group: tag-release
|
||||
cancel-in-progress: false
|
||||
|
@ -19,6 +19,8 @@ on:
|
|||
jobs:
|
||||
tag-release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.tag-release.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Fail if branch is not master
|
||||
|
@ -33,6 +35,7 @@ jobs:
|
|||
|
||||
- run: cd scripts && yarn
|
||||
- name: Tag release
|
||||
id: tag-release
|
||||
run: |
|
||||
cd scripts
|
||||
# setup the username and email.
|
||||
|
@ -41,3 +44,23 @@ jobs:
|
|||
BUMP_TYPE_INPUT=${{ github.event.inputs.versioning }}
|
||||
BUMP_TYPE=${BUMP_TYPE_INPUT:-"patch"}
|
||||
./versionCommit.sh $BUMP_TYPE
|
||||
|
||||
cd ..
|
||||
new_version=$(./scripts/getCurrentVersion.sh)
|
||||
echo "version=$new_version" >> $GITHUB_OUTPUT
|
||||
|
||||
trigger-release:
|
||||
needs: [tag-release]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
repository: budibase/budibase-deploys
|
||||
event-type: release-prod
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
client-payload: |-
|
||||
{
|
||||
"TAG": "${{ needs.tag-release.outputs.version }}"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -2,16 +2,18 @@ server {
|
|||
listen 443 ssl default_server;
|
||||
listen [::]:443 ssl default_server;
|
||||
server_name _;
|
||||
ssl_certificate /etc/letsencrypt/live/CUSTOM_DOMAIN/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/CUSTOM_DOMAIN/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
error_log /dev/stderr warn;
|
||||
access_log /dev/stdout main;
|
||||
client_max_body_size 1000m;
|
||||
ignore_invalid_headers off;
|
||||
proxy_buffering off;
|
||||
# port_in_redirect off;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/CUSTOM_DOMAIN/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/CUSTOM_DOMAIN/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
default_type "text/plain";
|
||||
root /var/www/html;
|
||||
|
@ -47,6 +49,24 @@ server {
|
|||
rewrite ^/worker/(.*)$ /$1 break;
|
||||
}
|
||||
|
||||
location /api/backups/ {
|
||||
# calls to export apps are limited
|
||||
limit_req zone=ratelimit burst=20 nodelay;
|
||||
|
||||
# 1800s timeout for app export requests
|
||||
proxy_read_timeout 1800s;
|
||||
proxy_connect_timeout 1800s;
|
||||
proxy_send_timeout 1800s;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_pass http://127.0.0.1:4001;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
# calls to the API are rate limited with bursting
|
||||
limit_req zone=ratelimit burst=20 nodelay;
|
||||
|
@ -70,18 +90,49 @@ server {
|
|||
rewrite ^/db/(.*)$ /$1 break;
|
||||
}
|
||||
|
||||
location /socket/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_pass http://127.0.0.1:4001;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_connect_timeout 300;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
chunked_transfer_encoding off;
|
||||
|
||||
proxy_pass http://127.0.0.1:9000;
|
||||
}
|
||||
|
||||
location /files/signed/ {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# IMPORTANT: Signed urls will inspect the host header of the request.
|
||||
# Normally a signed url will need to be generated with a specified client host in mind.
|
||||
# To support dynamic hosts, e.g. some unknown self-hosted installation url,
|
||||
# use a predefined host header. The host 'minio-service' is also used at the time of url signing.
|
||||
proxy_set_header Host minio-service;
|
||||
|
||||
proxy_connect_timeout 300;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
chunked_transfer_encoding off;
|
||||
|
||||
proxy_pass http://127.0.0.1:9000;
|
||||
rewrite ^/files/signed/(.*)$ /$1 break;
|
||||
}
|
||||
|
||||
client_header_timeout 60;
|
||||
client_body_timeout 60;
|
||||
keepalive_timeout 60;
|
||||
|
|
|
@ -57,8 +57,8 @@
|
|||
--spectrum-global-color-gray-600: rgb(144,144,144);
|
||||
--spectrum-global-color-gray-900: rgb(255,255,255);
|
||||
--spectrum-global-color-gray-800: rgb(227,227,227);
|
||||
--spectrum-global-color-static-blue-600: rgb(20,115,230);
|
||||
--spectrum-global-color-static-blue-hover: rgb( 18, 103, 207);
|
||||
--bb-indigo: #6E56FF;
|
||||
--bb-indigo-light: #9F8FFF;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
@ -90,15 +90,8 @@
|
|||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: left;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.info {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
color: var(--spectrum-global-color-gray-600)
|
||||
}
|
||||
|
@ -113,13 +106,14 @@
|
|||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.homeButton {
|
||||
background-color: var(--spectrum-global-color-static-blue-600);
|
||||
background-color: var(--bb-indigo);
|
||||
}
|
||||
.homeButton:hover {
|
||||
background-color: var(--spectrum-global-color-static-blue-hover);
|
||||
background-color: var(--bb-indigo-light);
|
||||
}
|
||||
.statusButton {
|
||||
background-color: transparent;
|
||||
|
@ -127,20 +121,30 @@
|
|||
border: none;
|
||||
}
|
||||
.hero {
|
||||
height: 160px;
|
||||
width: 160px;
|
||||
margin-right: 80px;
|
||||
height: 60px;
|
||||
margin: 10px 40px 10px 0;
|
||||
}
|
||||
.hero img {
|
||||
height: 100%;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-end;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 40px;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -152,16 +156,15 @@
|
|||
<div class="main">
|
||||
<div class="content">
|
||||
<div class="hero">
|
||||
<img src="https://raw.githubusercontent.com/Budibase/budibase/master/packages/builder/assets/bb-space-man.svg" alt="Budibase Logo">
|
||||
<img src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" alt="Budibase Logo">
|
||||
</div>
|
||||
<div class="info">
|
||||
<div>
|
||||
<h4 id="status" class="status"></h4>
|
||||
<h4 id="status" class="status"> </h4>
|
||||
<h1 class="title">
|
||||
Houston we have a problem!
|
||||
</h1>
|
||||
<h3 id="message" class="message">
|
||||
</h3>
|
||||
<h3 id="message" class="message"> </h3>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="homeButton" onclick=goHome()>Return home</button>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p align="center">
|
||||
<a href="https://www.budibase.com">
|
||||
<img alt="Budibase" src="https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" width="60" />
|
||||
<img alt="Budibase" src="https://res.cloudinary.com/daog6scxm/image/upload/v1696515725/Branding/Assets/Symbol/RGB/Full%20Colour/Budibase_Symbol_RGB_FullColour_cbqvha_1_z5cwq2.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.12.12",
|
||||
"version": "2.13.3",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -30,6 +30,7 @@ export * as timers from "./timers"
|
|||
export { default as env } from "./environment"
|
||||
export * as blacklist from "./blacklist"
|
||||
export * as docUpdates from "./docUpdates"
|
||||
export * from "./utils/Duration"
|
||||
export { SearchParams } from "./db"
|
||||
// Add context to tenancy for backwards compatibility
|
||||
// only do this for external usages to prevent internal
|
||||
|
|
|
@ -36,7 +36,7 @@ class InMemoryQueue {
|
|||
* @param opts This is not used by the in memory queue as there is no real use
|
||||
* case when in memory, but is the same API as Bull
|
||||
*/
|
||||
constructor(name: string, opts = null) {
|
||||
constructor(name: string, opts?: any) {
|
||||
this._name = name
|
||||
this._opts = opts
|
||||
this._messages = []
|
||||
|
|
|
@ -2,11 +2,17 @@ import env from "../environment"
|
|||
import { getRedisOptions } from "../redis/utils"
|
||||
import { JobQueue } from "./constants"
|
||||
import InMemoryQueue from "./inMemoryQueue"
|
||||
import BullQueue from "bull"
|
||||
import BullQueue, { QueueOptions } from "bull"
|
||||
import { addListeners, StalledFn } from "./listeners"
|
||||
import { Duration } from "../utils"
|
||||
import * as timers from "../timers"
|
||||
|
||||
const CLEANUP_PERIOD_MS = 60 * 1000
|
||||
// the queue lock is held for 5 minutes
|
||||
const QUEUE_LOCK_MS = Duration.fromMinutes(5).toMs()
|
||||
// queue lock is refreshed every 30 seconds
|
||||
const QUEUE_LOCK_RENEW_INTERNAL_MS = Duration.fromSeconds(30).toMs()
|
||||
// cleanup the queue every 60 seconds
|
||||
const CLEANUP_PERIOD_MS = Duration.fromSeconds(60).toMs()
|
||||
let QUEUES: BullQueue.Queue[] | InMemoryQueue[] = []
|
||||
let cleanupInterval: NodeJS.Timeout
|
||||
|
||||
|
@ -20,8 +26,15 @@ export function createQueue<T>(
|
|||
jobQueue: JobQueue,
|
||||
opts: { removeStalledCb?: StalledFn } = {}
|
||||
): BullQueue.Queue<T> {
|
||||
const { opts: redisOpts, redisProtocolUrl } = getRedisOptions()
|
||||
const queueConfig: any = redisProtocolUrl || { redis: redisOpts }
|
||||
const redisOpts = getRedisOptions()
|
||||
const queueConfig: QueueOptions = {
|
||||
redis: redisOpts,
|
||||
settings: {
|
||||
maxStalledCount: 0,
|
||||
lockDuration: QUEUE_LOCK_MS,
|
||||
lockRenewTime: QUEUE_LOCK_RENEW_INTERNAL_MS,
|
||||
},
|
||||
}
|
||||
let queue: any
|
||||
if (!env.isTest()) {
|
||||
queue = new BullQueue(jobQueue, queueConfig)
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
getRedisOptions,
|
||||
SEPARATOR,
|
||||
SelectableDatabase,
|
||||
getRedisConnectionDetails,
|
||||
} from "./utils"
|
||||
import * as timers from "../timers"
|
||||
|
||||
|
@ -91,12 +92,11 @@ function init(selectDb = DEFAULT_SELECT_DB) {
|
|||
if (client) {
|
||||
client.disconnect()
|
||||
}
|
||||
const { redisProtocolUrl, opts, host, port } = getRedisOptions()
|
||||
const { host, port } = getRedisConnectionDetails()
|
||||
const opts = getRedisOptions()
|
||||
|
||||
if (CLUSTERED) {
|
||||
client = new RedisCore.Cluster([{ host, port }], opts)
|
||||
} else if (redisProtocolUrl) {
|
||||
client = new RedisCore(redisProtocolUrl)
|
||||
} else {
|
||||
client = new RedisCore(opts)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import env from "../environment"
|
||||
import * as Redis from "ioredis"
|
||||
|
||||
const SLOT_REFRESH_MS = 2000
|
||||
const CONNECT_TIMEOUT_MS = 10000
|
||||
|
@ -42,7 +43,7 @@ export enum Databases {
|
|||
export enum SelectableDatabase {
|
||||
DEFAULT = 0,
|
||||
SOCKET_IO = 1,
|
||||
UNUSED_1 = 2,
|
||||
RATE_LIMITING = 2,
|
||||
UNUSED_2 = 3,
|
||||
UNUSED_3 = 4,
|
||||
UNUSED_4 = 5,
|
||||
|
@ -58,7 +59,7 @@ export enum SelectableDatabase {
|
|||
UNUSED_14 = 15,
|
||||
}
|
||||
|
||||
export function getRedisOptions() {
|
||||
export function getRedisConnectionDetails() {
|
||||
let password = env.REDIS_PASSWORD
|
||||
let url: string[] | string = env.REDIS_URL.split("//")
|
||||
// get rid of the protocol
|
||||
|
@ -74,28 +75,34 @@ export function getRedisOptions() {
|
|||
}
|
||||
const [host, port] = url.split(":")
|
||||
|
||||
let redisProtocolUrl
|
||||
|
||||
// fully qualified redis URL
|
||||
if (/rediss?:\/\//.test(env.REDIS_URL)) {
|
||||
redisProtocolUrl = env.REDIS_URL
|
||||
return {
|
||||
host,
|
||||
password,
|
||||
port: parseInt(port),
|
||||
}
|
||||
}
|
||||
|
||||
const opts: any = {
|
||||
export function getRedisOptions() {
|
||||
const { host, password, port } = getRedisConnectionDetails()
|
||||
let redisOpts: Redis.RedisOptions = {
|
||||
connectTimeout: CONNECT_TIMEOUT_MS,
|
||||
port: port,
|
||||
host,
|
||||
password,
|
||||
}
|
||||
let opts: Redis.ClusterOptions | Redis.RedisOptions = redisOpts
|
||||
if (env.REDIS_CLUSTERED) {
|
||||
opts.redisOptions = {}
|
||||
opts.redisOptions.tls = {}
|
||||
opts.redisOptions.password = password
|
||||
opts.slotsRefreshTimeout = SLOT_REFRESH_MS
|
||||
opts.dnsLookup = (address: string, callback: any) => callback(null, address)
|
||||
} else {
|
||||
opts.host = host
|
||||
opts.port = port
|
||||
opts.password = password
|
||||
opts = {
|
||||
connectTimeout: CONNECT_TIMEOUT_MS,
|
||||
redisOptions: {
|
||||
...redisOpts,
|
||||
tls: {},
|
||||
},
|
||||
slotsRefreshTimeout: SLOT_REFRESH_MS,
|
||||
dnsLookup: (address: string, callback: any) => callback(null, address),
|
||||
} as Redis.ClusterOptions
|
||||
}
|
||||
return { opts, host, port: parseInt(port), redisProtocolUrl }
|
||||
return opts
|
||||
}
|
||||
|
||||
export function addDbPrefix(db: string, key: string) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
export enum DurationType {
|
||||
MILLISECONDS = "milliseconds",
|
||||
SECONDS = "seconds",
|
||||
MINUTES = "minutes",
|
||||
HOURS = "hours",
|
||||
DAYS = "days",
|
||||
}
|
||||
|
||||
const conversion: Record<DurationType, number> = {
|
||||
milliseconds: 1,
|
||||
seconds: 1000,
|
||||
minutes: 60 * 1000,
|
||||
hours: 60 * 60 * 1000,
|
||||
days: 24 * 60 * 60 * 1000,
|
||||
}
|
||||
|
||||
export class Duration {
|
||||
static convert(from: DurationType, to: DurationType, duration: number) {
|
||||
const milliseconds = duration * conversion[from]
|
||||
return milliseconds / conversion[to]
|
||||
}
|
||||
|
||||
static from(from: DurationType, duration: number) {
|
||||
return {
|
||||
to: (to: DurationType) => {
|
||||
return Duration.convert(from, to, duration)
|
||||
},
|
||||
toMs: () => {
|
||||
return Duration.convert(from, DurationType.MILLISECONDS, duration)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
static fromSeconds(duration: number) {
|
||||
return Duration.from(DurationType.SECONDS, duration)
|
||||
}
|
||||
|
||||
static fromMinutes(duration: number) {
|
||||
return Duration.from(DurationType.MINUTES, duration)
|
||||
}
|
||||
|
||||
static fromHours(duration: number) {
|
||||
return Duration.from(DurationType.HOURS, duration)
|
||||
}
|
||||
|
||||
static fromDays(duration: number) {
|
||||
return Duration.from(DurationType.DAYS, duration)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./hashing"
|
||||
export * from "./utils"
|
||||
export * from "./stringUtils"
|
||||
export * from "./Duration"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Duration, DurationType } from "../Duration"
|
||||
|
||||
describe("duration", () => {
|
||||
it("should convert minutes to milliseconds", () => {
|
||||
expect(Duration.fromMinutes(5).toMs()).toBe(300000)
|
||||
})
|
||||
|
||||
it("should convert seconds to milliseconds", () => {
|
||||
expect(Duration.fromSeconds(30).toMs()).toBe(30000)
|
||||
})
|
||||
|
||||
it("should convert days to milliseconds", () => {
|
||||
expect(Duration.fromDays(1).toMs()).toBe(86400000)
|
||||
})
|
||||
|
||||
it("should convert minutes to days", () => {
|
||||
expect(Duration.fromMinutes(1440).to(DurationType.DAYS)).toBe(1)
|
||||
})
|
||||
})
|
|
@ -8,6 +8,7 @@
|
|||
export let id = null
|
||||
export let text = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let size
|
||||
export let indeterminate = false
|
||||
|
||||
|
@ -24,6 +25,7 @@
|
|||
class:is-invalid={!!error}
|
||||
class:checked={value}
|
||||
class:is-indeterminate={indeterminate}
|
||||
class:readonly
|
||||
>
|
||||
<input
|
||||
checked={value}
|
||||
|
@ -68,4 +70,7 @@
|
|||
.spectrum-Checkbox-input {
|
||||
opacity: 0;
|
||||
}
|
||||
.readonly {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export let options = []
|
||||
export let error = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
|
||||
|
@ -34,6 +35,7 @@
|
|||
title={getOptionLabel(option)}
|
||||
class="spectrum-Checkbox spectrum-FieldGroup-item"
|
||||
class:is-invalid={!!error}
|
||||
class:readonly
|
||||
>
|
||||
<label
|
||||
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-FieldGroup-item"
|
||||
|
@ -66,4 +68,7 @@
|
|||
.spectrum-Checkbox-input {
|
||||
opacity: 0;
|
||||
}
|
||||
.readonly {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
export let id = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let error = null
|
||||
export let enableTime = true
|
||||
export let value = null
|
||||
|
@ -186,7 +187,7 @@
|
|||
>
|
||||
<div
|
||||
id={flatpickrId}
|
||||
class:is-disabled={disabled}
|
||||
class:is-disabled={disabled || readonly}
|
||||
class:is-invalid={!!error}
|
||||
class="flatpickr spectrum-InputGroup spectrum-Datepicker"
|
||||
class:is-focused={open}
|
||||
|
@ -211,6 +212,7 @@
|
|||
{/if}
|
||||
<input
|
||||
{disabled}
|
||||
{readonly}
|
||||
data-input
|
||||
type="text"
|
||||
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
||||
|
|
|
@ -386,7 +386,7 @@
|
|||
}
|
||||
.compact .placeholder,
|
||||
.compact img {
|
||||
margin: 10px 16px;
|
||||
margin: 8px 16px;
|
||||
}
|
||||
.compact img {
|
||||
height: 90px;
|
||||
|
@ -456,6 +456,12 @@
|
|||
color: var(--red);
|
||||
}
|
||||
|
||||
.spectrum-Dropzone {
|
||||
height: 220px;
|
||||
}
|
||||
.compact .spectrum-Dropzone {
|
||||
height: 40px;
|
||||
}
|
||||
.spectrum-Dropzone.disabled {
|
||||
pointer-events: none;
|
||||
background-color: var(--spectrum-global-color-gray-200);
|
||||
|
@ -463,10 +469,6 @@
|
|||
.disabled .spectrum-Heading--sizeL {
|
||||
color: var(--spectrum-alias-text-color-disabled);
|
||||
}
|
||||
.compact .spectrum-Dropzone {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.compact .spectrum-IllustratedMessage-description {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -477,7 +479,6 @@
|
|||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tag {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export let options = []
|
||||
export let error = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
export let getOptionTitle = option => option
|
||||
|
@ -40,6 +41,7 @@
|
|||
title={getOptionTitle(option)}
|
||||
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
|
||||
class:is-invalid={!!error}
|
||||
class:readonly
|
||||
>
|
||||
<input
|
||||
on:change={onChange}
|
||||
|
@ -62,4 +64,7 @@
|
|||
.spectrum-Radio-input {
|
||||
opacity: 0;
|
||||
}
|
||||
.readonly {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
export let value = ""
|
||||
export let placeholder = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let error = null
|
||||
export let height = null
|
||||
export let id = null
|
||||
|
@ -20,6 +21,7 @@
|
|||
{fullScreenOffset}
|
||||
{disabled}
|
||||
{easyMDEOptions}
|
||||
{readonly}
|
||||
on:change
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
export let value = ""
|
||||
export let placeholder = null
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let error = null
|
||||
export let id = null
|
||||
export let height = null
|
||||
|
@ -61,6 +62,7 @@
|
|||
class="spectrum-Textfield-input"
|
||||
style={align ? `text-align: ${align}` : ""}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{id}
|
||||
on:focus={() => (focus = true)}
|
||||
on:blur={onChange}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
export let label = null
|
||||
export let labelPosition = "above"
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let error = null
|
||||
export let enableTime = true
|
||||
export let timeOnly = false
|
||||
|
@ -33,6 +34,7 @@
|
|||
<DatePicker
|
||||
{error}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{value}
|
||||
{placeholder}
|
||||
{enableTime}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export let id = null
|
||||
export let fullScreenOffset = 0
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let easyMDEOptions
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
@ -19,6 +20,9 @@
|
|||
// control
|
||||
$: checkValue(value)
|
||||
$: mde?.codemirror.on("change", debouncedUpdate)
|
||||
$: if (readonly || disabled) {
|
||||
mde?.togglePreview()
|
||||
}
|
||||
|
||||
const checkValue = val => {
|
||||
if (mde && val !== latestValue) {
|
||||
|
@ -54,6 +58,7 @@
|
|||
easyMDEOptions={{
|
||||
initialValue: value,
|
||||
placeholder,
|
||||
toolbar: disabled || readonly ? false : undefined,
|
||||
...easyMDEOptions,
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
--background: #ffffff;
|
||||
--ink: #000000;
|
||||
|
||||
/* Brand colours */
|
||||
--bb-coral: #FF4E4E;
|
||||
--bb-coral-light: #F97777;
|
||||
--bb-indigo: #6E56FF;
|
||||
--bb-indigo-light: #9F8FFF;
|
||||
--bb-lime: #ECFFB5;
|
||||
--bb-forest-green: #053835;
|
||||
--bb-beige: #F6EFEA;
|
||||
|
||||
--grey-1: #fafafa;
|
||||
--grey-2: #f5f5f5;
|
||||
--grey-3: #eeeeee;
|
||||
|
|
|
@ -1,80 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#000000;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#4285F4;}
|
||||
</style>
|
||||
<rect x="-152.17" y="-24.17" class="st0" width="96.17" height="96.17"/>
|
||||
<path class="st1" d="M-83.19,48h-41.79c-1.76,0-3.19-1.43-3.19-3.19V3.02c0-1.76,1.43-3.19,3.19-3.19h41.79
|
||||
c1.76,0,3.19,1.43,3.19,3.19v41.79C-80,46.57-81.43,48-83.19,48z"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M-99.62,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35h-4.89V12.57H-99.62z
|
||||
M-93.46,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C-93.55,28.92-93.46,28.52-93.46,28.11z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M-114.76,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58
|
||||
c0.86,0.39,1.59,0.91,2.19,1.57c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89
|
||||
c-0.35,0.9-0.84,1.68-1.47,2.35c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35
|
||||
h-4.89V12.57H-114.76z M-108.6,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C-108.68,28.92-108.6,28.52-108.6,28.11z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st2" d="M44.81,159H3.02c-1.76,0-3.19-1.43-3.19-3.19v-41.79c0-1.76,1.43-3.19,3.19-3.19h41.79
|
||||
c1.76,0,3.19,1.43,3.19,3.19v41.79C48,157.57,46.57,159,44.81,159z"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st1" d="M28.38,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146h-4.89v-22.43H28.38z
|
||||
M34.54,139.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C34.45,139.92,34.54,139.52,34.54,139.11z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M13.24,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146H8.35v-22.43H13.24z M19.4,139.11
|
||||
c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69c-0.38-0.17-0.79-0.26-1.24-0.26
|
||||
c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01c-0.17,0.39-0.26,0.8-0.26,1.23
|
||||
c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68c0.39,0.17,0.8,0.26,1.23,0.26
|
||||
c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1C19.32,139.92,19.4,139.52,19.4,139.11z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M44,48H4c-2.21,0-4-1.79-4-4V4c0-2.21,1.79-4,4-4h40c2.21,0,4,1.79,4,4v40C48,46.21,46.21,48,44,48z"/>
|
||||
<g>
|
||||
<path class="st1" d="M28.48,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
|
||||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
|
||||
c-0.64,0.7-1.4,1.25-2.28,1.66C34.8,35.8,33.86,36,32.84,36c-1.84,0-3.3-0.69-4.37-2.07v1.62h-5V12H28.48z M34.78,28.31
|
||||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
|
||||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
|
||||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
|
||||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C34.69,29.16,34.78,28.75,34.78,28.31z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M13,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
|
||||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
|
||||
c-0.64,0.7-1.4,1.25-2.28,1.66C19.32,35.8,18.38,36,17.37,36c-1.84,0-3.3-0.69-4.37-2.07v1.62H8V12H13z M19.3,28.31
|
||||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
|
||||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
|
||||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
|
||||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C19.21,29.16,19.3,28.75,19.3,28.31z"/>
|
||||
</g>
|
||||
<svg width="265" height="265" viewBox="0 0 265 265" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1_1799)">
|
||||
<path d="M158.2 8.6V116.6C158.2 121.3 162 125.2 166.8 125.2H213.8C218 125.2 222 123.2 224.6 119.8L262.9 68.9C265.7 65.2 265.7 60.1 262.9 56.4L224.6 5.4C222 2 218 0 213.8 0H166.8C162 0 158.2 3.8 158.2 8.6Z" fill="#FF4E4E"/>
|
||||
<path d="M158.2 148.4V256.4C158.2 261.1 162 265 166.8 265H213.8C218 265 222 263 224.6 259.6L262.9 208.7C265.7 205 265.7 199.9 262.9 196.2L224.6 145.3C222.1 141.9 218.1 139.9 213.8 139.9H166.8C162 139.8 158.2 143.7 158.2 148.4Z" fill="#6E56FF"/>
|
||||
<path d="M0 8.6V116.6C0 121.3 3.8 125.2 8.6 125.2H109.6C113.8 125.2 117.8 123.2 120.4 119.8L155.9 72.5C160.3 66.6 160.3 58.5 155.9 52.6L120.3 5.4C117.8 2 113.8 0 109.5 0H8.6C3.8 0 0 3.8 0 8.6Z" fill="#F97777"/>
|
||||
<path d="M0 148.4V256.4C0 261.1 3.8 265 8.6 265H109.6C113.8 265 117.8 263 120.4 259.6L155.9 212.3C160.3 206.4 160.3 198.3 155.9 192.4L120.4 145.1C117.9 141.7 113.9 139.7 109.6 139.7H8.6C3.8 139.8 0 143.7 0 148.4Z" fill="#9F8FFF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1_1799">
|
||||
<rect width="265" height="265" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 46.39 46.39" style="enable-background:new 0 0 46.39 46.39;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M45.28,22.9c-0.49,28.44-42.79,28.43-43.27,0C2.5-5.54,44.8-5.54,45.28,22.9z"/>
|
||||
<path d="M23.65,45.45c-29.64-0.48-29.63-44.63,0-45.1C53.28,0.82,53.28,44.98,23.65,45.45z M23.65,2.18
|
||||
c-27.09,0.09-27.09,41.36,0,41.44C50.74,43.53,50.74,2.26,23.65,2.18z"/>
|
||||
<path d="M41.94,21.07C38.86,8.69,3.47,8.77,5.01,24.45C5.74,49.51,46.24,46.16,41.94,21.07z"/>
|
||||
<path class="st0" d="M14.69,22.35c0.06,4.27-6.65,4.27-6.58,0C8.05,18.08,14.76,18.08,14.69,22.35z"/>
|
||||
<path class="st0" d="M11.07,28.39c0.02,1.7-2.65,1.7-2.62,0C8.42,26.68,11.09,26.68,11.07,28.39z"/>
|
||||
<path class="st0" d="M30.56,16.2c0.28-1.27,6.76,0.79,8.45,5.64c1.69,4.84-2.11,12.22-3.52,11.43
|
||||
C36.02,25.33,37.44,22.84,30.56,16.2z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 34.41 34.41" style="enable-background:new 0 0 34.41 34.41;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;stroke:url(#SVGID_1_);stroke-miterlimit:10;}
|
||||
.st1{fill:url(#SVGID_2_);}
|
||||
.st2{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0.9311" y1="17.2025" x2="33.4739" y2="17.2025">
|
||||
<stop offset="0" style="stop-color:#9E99FF"/>
|
||||
<stop offset="1" style="stop-color:#5C45FF"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M17.2,33.2c-21.03-0.34-21.03-31.67,0-32C38.23,1.54,38.23,32.87,17.2,33.2z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="3.9435" y1="20.058" x2="30.407" y2="20.058">
|
||||
<stop offset="0" style="stop-color:#9E99FF"/>
|
||||
<stop offset="1" style="stop-color:#5C45FF"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M30.18,15.91C27.99,7.12,2.89,7.18,3.98,18.3C4.5,36.09,33.23,33.71,30.18,15.91z"/>
|
||||
<path class="st2" d="M6.42,21.1c-0.02-1.21,1.88-1.21,1.86,0C8.29,22.3,6.4,22.3,6.42,21.1z"/>
|
||||
<path class="st2" d="M6.18,16.81c-0.04-3.03,4.72-3.03,4.67,0C10.89,19.84,6.13,19.84,6.18,16.81z"/>
|
||||
<path class="st2" d="M25.61,24.56c0.38-5.63,1.38-7.4-3.5-12.11c0.2-0.9,4.8,0.56,6,4C29.3,19.88,26.61,25.12,25.61,24.56z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 3.9 KiB |
|
@ -44,6 +44,8 @@
|
|||
const NUMBER_TYPE = FIELDS.NUMBER.type
|
||||
const JSON_TYPE = FIELDS.JSON.type
|
||||
const DATE_TYPE = FIELDS.DATETIME.type
|
||||
const USER_TYPE = FIELDS.USER.subtype
|
||||
const USERS_TYPE = FIELDS.USERS.subtype
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const PROHIBITED_COLUMN_NAMES = ["type", "_id", "_rev", "tableId"]
|
||||
|
@ -287,6 +289,14 @@
|
|||
if (saveColumn.type !== LINK_TYPE) {
|
||||
delete saveColumn.fieldName
|
||||
}
|
||||
if (isUsersColumn(saveColumn)) {
|
||||
if (saveColumn.subtype === USER_TYPE) {
|
||||
saveColumn.relationshipType = RelationshipType.ONE_TO_MANY
|
||||
} else if (saveColumn.subtype === USERS_TYPE) {
|
||||
saveColumn.relationshipType = RelationshipType.MANY_TO_MANY
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await tables.saveField({
|
||||
originalName,
|
||||
|
|
|
@ -4,123 +4,33 @@
|
|||
</script>
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
viewBox="0 0 265 265"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 48 48"
|
||||
style="enable-background:new 0 0 48 48;"
|
||||
xml:space="preserve"
|
||||
{height}
|
||||
{width}
|
||||
>
|
||||
<style type="text/css">
|
||||
.st0 {
|
||||
fill: #393c44;
|
||||
}
|
||||
.st1 {
|
||||
fill: #ffffff;
|
||||
}
|
||||
.st2 {
|
||||
fill: #4285f4;
|
||||
}
|
||||
</style>
|
||||
<rect x="-152.17" y="-24.17" class="st0" width="96.17" height="96.17" />
|
||||
<path
|
||||
class="st1"
|
||||
d="M-83.19,48h-41.79c-1.76,0-3.19-1.43-3.19-3.19V3.02c0-1.76,1.43-3.19,3.19-3.19h41.79
|
||||
c1.76,0,3.19,1.43,3.19,3.19v41.79C-80,46.57-81.43,48-83.19,48z"
|
||||
/>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
class="st0"
|
||||
d="M-99.62,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35h-4.89V12.57H-99.62z
|
||||
M-93.46,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C-93.55,28.92-93.46,28.52-93.46,28.11z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
class="st0"
|
||||
d="M-114.76,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58
|
||||
c0.86,0.39,1.59,0.91,2.19,1.57c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89
|
||||
c-0.35,0.9-0.84,1.68-1.47,2.35c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35
|
||||
h-4.89V12.57H-114.76z M-108.6,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C-108.68,28.92-108.6,28.52-108.6,28.11z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
class="st2"
|
||||
d="M44.81,159H3.02c-1.76,0-3.19-1.43-3.19-3.19v-41.79c0-1.76,1.43-3.19,3.19-3.19h41.79
|
||||
c1.76,0,3.19,1.43,3.19,3.19v41.79C48,157.57,46.57,159,44.81,159z"
|
||||
/>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
class="st1"
|
||||
d="M28.38,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146h-4.89v-22.43H28.38z
|
||||
M34.54,139.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
|
||||
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
|
||||
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
|
||||
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
|
||||
C34.45,139.92,34.54,139.52,34.54,139.11z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
class="st1"
|
||||
d="M13.24,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
|
||||
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
|
||||
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146H8.35v-22.43H13.24z M19.4,139.11
|
||||
c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69c-0.38-0.17-0.79-0.26-1.24-0.26
|
||||
c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01c-0.17,0.39-0.26,0.8-0.26,1.23
|
||||
c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68c0.39,0.17,0.8,0.26,1.23,0.26
|
||||
c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1C19.32,139.92,19.4,139.52,19.4,139.11z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g clip-path="url(#clip0_1_1799)">
|
||||
<path
|
||||
class="st0"
|
||||
d="M44,48H4c-2.21,0-4-1.79-4-4V4c0-2.21,1.79-4,4-4h40c2.21,0,4,1.79,4,4v40C48,46.21,46.21,48,44,48z"
|
||||
d="M158.2 8.6V116.6C158.2 121.3 162 125.2 166.8 125.2H213.8C218 125.2 222 123.2 224.6 119.8L262.9 68.9C265.7 65.2 265.7 60.1 262.9 56.4L224.6 5.4C222 2 218 0 213.8 0H166.8C162 0 158.2 3.8 158.2 8.6Z"
|
||||
fill="#FF4E4E"
|
||||
/>
|
||||
<path
|
||||
d="M158.2 148.4V256.4C158.2 261.1 162 265 166.8 265H213.8C218 265 222 263 224.6 259.6L262.9 208.7C265.7 205 265.7 199.9 262.9 196.2L224.6 145.3C222.1 141.9 218.1 139.9 213.8 139.9H166.8C162 139.8 158.2 143.7 158.2 148.4Z"
|
||||
fill="#6E56FF"
|
||||
/>
|
||||
<path
|
||||
d="M0 8.6V116.6C0 121.3 3.8 125.2 8.6 125.2H109.6C113.8 125.2 117.8 123.2 120.4 119.8L155.9 72.5C160.3 66.6 160.3 58.5 155.9 52.6L120.3 5.4C117.8 2 113.8 0 109.5 0H8.6C3.8 0 0 3.8 0 8.6Z"
|
||||
fill="#F97777"
|
||||
/>
|
||||
<path
|
||||
d="M0 148.4V256.4C0 261.1 3.8 265 8.6 265H109.6C113.8 265 117.8 263 120.4 259.6L155.9 212.3C160.3 206.4 160.3 198.3 155.9 192.4L120.4 145.1C117.9 141.7 113.9 139.7 109.6 139.7H8.6C3.8 139.8 0 143.7 0 148.4Z"
|
||||
fill="#9F8FFF"
|
||||
/>
|
||||
<g>
|
||||
<path
|
||||
class="st1"
|
||||
d="M28.48,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
|
||||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
|
||||
c-0.64,0.7-1.4,1.25-2.28,1.66C34.8,35.8,33.86,36,32.84,36c-1.84,0-3.3-0.69-4.37-2.07v1.62h-5V12H28.48z M34.78,28.31
|
||||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
|
||||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
|
||||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
|
||||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C34.69,29.16,34.78,28.75,34.78,28.31z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
class="st1"
|
||||
d="M13,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
|
||||
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
|
||||
c-0.64,0.7-1.4,1.25-2.28,1.66C19.32,35.8,18.38,36,17.37,36c-1.84,0-3.3-0.69-4.37-2.07v1.62H8V12H13z M19.3,28.31
|
||||
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
|
||||
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
|
||||
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
|
||||
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C19.21,29.16,19.3,28.75,19.3,28.31z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1_1799">
|
||||
<rect width="265" height="265" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
|
@ -90,13 +90,17 @@
|
|||
|
||||
.openMenu {
|
||||
cursor: pointer;
|
||||
background-color: #6a1dc8;
|
||||
background-color: var(--bb-indigo);
|
||||
border-radius: 100px;
|
||||
color: white;
|
||||
border: none;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding: 10px 18px;
|
||||
transition: background-color 130ms ease-out;
|
||||
}
|
||||
.openMenu:hover {
|
||||
background-color: var(--bb-indigo-light);
|
||||
}
|
||||
|
||||
.helpMenu {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
let open = false
|
||||
|
||||
// Auto hide the component when another item is selected
|
||||
$: if (open && $draggable.selected != componentInstance._id) {
|
||||
$: if (open && $draggable.selected !== componentInstance._id) {
|
||||
popover.hide()
|
||||
}
|
||||
|
||||
|
@ -95,13 +95,13 @@
|
|||
}}
|
||||
on:close={() => {
|
||||
open = false
|
||||
if ($draggable.selected == componentInstance._id) {
|
||||
if ($draggable.selected === componentInstance._id) {
|
||||
$draggable.actions.select()
|
||||
}
|
||||
}}
|
||||
{anchor}
|
||||
align="left-outside"
|
||||
showPopover={drawers.length == 0}
|
||||
showPopover={drawers.length === 0}
|
||||
clickOutsideOverride={drawers.length > 0}
|
||||
maxHeight={600}
|
||||
handlePostionUpdate={customPositionHandler}
|
||||
|
@ -110,6 +110,7 @@
|
|||
<Layout noPadding noGap>
|
||||
<slot name="header" />
|
||||
<ComponentSettingsSection
|
||||
includeHidden
|
||||
{componentInstance}
|
||||
componentDefinition={parsedComponentDef}
|
||||
isScreen={false}
|
||||
|
|
|
@ -112,9 +112,9 @@
|
|||
}
|
||||
await usersFetch.update({
|
||||
query: {
|
||||
appId: query || !filterByAppAccess ? null : prodAppId,
|
||||
email: query,
|
||||
string: { email: query },
|
||||
},
|
||||
appId: query || !filterByAppAccess ? null : prodAppId,
|
||||
limit: 50,
|
||||
paginate: query || !filterByAppAccess ? null : false,
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
||||
import Panel from "components/design/Panel.svelte"
|
||||
import { isActive, redirect, goto, params } from "@roxi/routify"
|
||||
import BetaButton from "./_components/BetaButton.svelte"
|
||||
import { datasources } from "stores/builder"
|
||||
|
||||
$: {
|
||||
|
@ -30,7 +29,6 @@
|
|||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
<BetaButton />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -16,16 +16,18 @@
|
|||
export let isScreen = false
|
||||
export let onUpdateSetting
|
||||
export let showSectionTitle = true
|
||||
export let includeHidden = false
|
||||
export let tag
|
||||
|
||||
$: sections = getSections(
|
||||
componentInstance,
|
||||
componentDefinition,
|
||||
isScreen,
|
||||
tag
|
||||
tag,
|
||||
includeHidden
|
||||
)
|
||||
|
||||
const getSections = (instance, definition, isScreen, tag) => {
|
||||
const getSections = (instance, definition, isScreen, tag, includeHidden) => {
|
||||
const settings = definition?.settings ?? []
|
||||
const generalSettings = settings.filter(
|
||||
setting => !setting.section && setting.tag === tag
|
||||
|
@ -52,7 +54,12 @@
|
|||
return
|
||||
}
|
||||
section.settings.forEach(setting => {
|
||||
setting.visible = canRenderControl(instance, setting, isScreen)
|
||||
setting.visible = canRenderControl(
|
||||
instance,
|
||||
setting,
|
||||
isScreen,
|
||||
includeHidden
|
||||
)
|
||||
})
|
||||
section.visible =
|
||||
section.name === "General" ||
|
||||
|
@ -122,16 +129,20 @@
|
|||
})
|
||||
}
|
||||
|
||||
const canRenderControl = (instance, setting, isScreen) => {
|
||||
const canRenderControl = (instance, setting, isScreen, includeHidden) => {
|
||||
// Prevent rendering on click setting for screens
|
||||
if (setting?.type === "event" && isScreen) {
|
||||
return false
|
||||
}
|
||||
// Check we have a component to render for this setting
|
||||
const control = getComponentForSetting(setting)
|
||||
if (!control) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if setting is hidden
|
||||
if (setting.hidden && !includeHidden) {
|
||||
return false
|
||||
}
|
||||
return shouldDisplay(instance, setting)
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -9,12 +9,18 @@
|
|||
let searchString
|
||||
let searching = false
|
||||
|
||||
$: filteredApps = $apps.filter(app => {
|
||||
return (
|
||||
!searchString ||
|
||||
app.name.toLowerCase().includes(searchString.toLowerCase())
|
||||
)
|
||||
})
|
||||
$: filteredApps = $apps
|
||||
.filter(app => {
|
||||
return (
|
||||
!searchString ||
|
||||
app.name.toLowerCase().includes(searchString.toLowerCase())
|
||||
)
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const lowerA = a.name.toLowerCase()
|
||||
const lowerB = b.name.toLowerCase()
|
||||
return lowerA > lowerB ? 1 : -1
|
||||
})
|
||||
|
||||
const startSearching = async () => {
|
||||
searching = true
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
</script>
|
||||
|
||||
<div class="header">
|
||||
<img
|
||||
alt="Budibase Logo"
|
||||
class="budibaseLogo"
|
||||
src={"https://i.imgur.com/Xhdt1YP.png"}
|
||||
/>
|
||||
<img alt="Budibase Logo" class="budibaseLogo" src="/builder/bblogo.png" />
|
||||
<div class="headingAndBack">
|
||||
{#if onBack}
|
||||
<button on:click={onBack}>
|
||||
|
|
|
@ -2589,6 +2589,17 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "Initial form step",
|
||||
|
@ -2738,6 +2749,17 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
|
@ -2776,6 +2798,35 @@
|
|||
"barTitle": "Justify text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2829,10 +2880,50 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/number",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2885,6 +2976,35 @@
|
|||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2942,6 +3062,35 @@
|
|||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3049,6 +3198,17 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Options source",
|
||||
|
@ -3110,6 +3270,35 @@
|
|||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3174,6 +3363,17 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Type",
|
||||
|
@ -3272,6 +3472,35 @@
|
|||
"type": "validation/array",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3348,10 +3577,50 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/boolean",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3427,10 +3696,50 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3508,10 +3817,50 @@
|
|||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/datetime",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3598,6 +3947,22 @@
|
|||
"value": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Preferred camera",
|
||||
"key": "preferredCamera",
|
||||
"defaultValue": "environment",
|
||||
"options": [
|
||||
{
|
||||
"label": "Front",
|
||||
"value": "user"
|
||||
},
|
||||
{
|
||||
"label": "Back",
|
||||
"value": "environment"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"label": "On change",
|
||||
|
@ -3613,6 +3978,35 @@
|
|||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3781,7 +4175,7 @@
|
|||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Disabled",
|
||||
"label": "Read only",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
|
@ -3789,6 +4183,35 @@
|
|||
"type": "validation/attachment",
|
||||
"label": "Validation",
|
||||
"key": "validation"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3857,6 +4280,46 @@
|
|||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3909,6 +4372,46 @@
|
|||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Read only",
|
||||
"key": "readonly",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "disabled",
|
||||
"value": true,
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -5530,12 +6033,7 @@
|
|||
"type": "boolean",
|
||||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "actionType",
|
||||
"value": "View",
|
||||
"invert": true
|
||||
}
|
||||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -5590,23 +6088,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tag": "style",
|
||||
"type": "select",
|
||||
"label": "Align labels",
|
||||
"key": "labelPosition",
|
||||
"defaultValue": "left",
|
||||
"options": [
|
||||
{
|
||||
"label": "Left",
|
||||
"value": "left"
|
||||
},
|
||||
{
|
||||
"label": "Above",
|
||||
"value": "above"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tag": "style",
|
||||
"type": "select",
|
||||
|
@ -5921,6 +6402,35 @@
|
|||
"label": "Disabled",
|
||||
"key": "disabled",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Layout",
|
||||
"key": "span",
|
||||
"defaultValue": 6,
|
||||
"hidden": true,
|
||||
"showInBar": true,
|
||||
"barStyle": "buttons",
|
||||
"options": [
|
||||
{
|
||||
"label": "1 column",
|
||||
"value": 6,
|
||||
"barIcon": "Stop",
|
||||
"barTitle": "1 column"
|
||||
},
|
||||
{
|
||||
"label": "2 columns",
|
||||
"value": 3,
|
||||
"barIcon": "ColumnTwoA",
|
||||
"barTitle": "2 columns"
|
||||
},
|
||||
{
|
||||
"label": "3 columns",
|
||||
"value": 2,
|
||||
"barIcon": "ViewColumn",
|
||||
"barTitle": "3 columns"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -26,15 +26,15 @@
|
|||
$: parentId = $component?.id
|
||||
$: inBuilder = $builderStore.inBuilder
|
||||
$: instance = {
|
||||
...props,
|
||||
_component: getComponent(type),
|
||||
_id: id,
|
||||
_instanceName: getInstanceName(name, type),
|
||||
_containsSlot: containsSlot,
|
||||
_styles: {
|
||||
...styles,
|
||||
normal: styles?.normal || {},
|
||||
},
|
||||
_containsSlot: containsSlot,
|
||||
...props,
|
||||
}
|
||||
|
||||
// Register this block component if we're inside the builder so it can be
|
||||
|
|
|
@ -140,6 +140,7 @@
|
|||
interactive &&
|
||||
!isLayout &&
|
||||
!isRoot &&
|
||||
!isBlock &&
|
||||
definition?.draggable !== false
|
||||
$: droppable = interactive
|
||||
$: builderHidden =
|
||||
|
@ -194,6 +195,7 @@
|
|||
interactive,
|
||||
draggable,
|
||||
editable,
|
||||
isBlock,
|
||||
},
|
||||
empty: emptyState,
|
||||
selected,
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
export let size
|
||||
export let disabled
|
||||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let description
|
||||
export let showDeleteButton
|
||||
|
@ -97,7 +96,6 @@
|
|||
size,
|
||||
disabled,
|
||||
fields: fieldsOrDefault,
|
||||
labelPosition,
|
||||
title,
|
||||
description,
|
||||
saveButtonLabel: saveLabel,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import BlockComponent from "components/BlockComponent.svelte"
|
||||
import Placeholder from "components/app/Placeholder.svelte"
|
||||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
export let dataSource
|
||||
export let actionUrl
|
||||
|
@ -9,7 +10,6 @@
|
|||
export let size
|
||||
export let disabled
|
||||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let description
|
||||
export let saveButtonLabel
|
||||
|
@ -33,6 +33,7 @@
|
|||
barcodeqr: "codescanner",
|
||||
bb_reference: "bbreferencefield",
|
||||
}
|
||||
const context = getContext("context")
|
||||
|
||||
let formId
|
||||
|
||||
|
@ -136,7 +137,8 @@
|
|||
actionType: actionType === "Create" ? "Create" : "Update",
|
||||
dataSource,
|
||||
size,
|
||||
disabled: disabled || actionType === "View",
|
||||
disabled,
|
||||
readonly: !disabled && actionType === "View",
|
||||
}}
|
||||
styles={{
|
||||
normal: {
|
||||
|
@ -226,16 +228,20 @@
|
|||
<BlockComponent type="text" props={{ text: description }} order={1} />
|
||||
{/if}
|
||||
{#key fields}
|
||||
<BlockComponent type="fieldgroup" props={{ labelPosition }} order={1}>
|
||||
{#each fields as field, idx}
|
||||
{#if getComponentForField(field) && field.active}
|
||||
<BlockComponent
|
||||
type={getComponentForField(field)}
|
||||
props={getPropsForField(field)}
|
||||
order={idx}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
<BlockComponent type="container">
|
||||
<div class="form-block fields" class:mobile={$context.device.mobile}>
|
||||
{#each fields as field, idx}
|
||||
{#if getComponentForField(field) && field.active}
|
||||
<BlockComponent
|
||||
type={getComponentForField(field)}
|
||||
props={getPropsForField(field)}
|
||||
order={idx}
|
||||
interactive
|
||||
name={field?.field}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</BlockComponent>
|
||||
{/key}
|
||||
</BlockComponent>
|
||||
|
@ -245,3 +251,14 @@
|
|||
text="Choose your table and add some fields to your form to get started"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.fields {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 8px 16px;
|
||||
}
|
||||
.fields.mobile :global(.spectrum-Form-item) {
|
||||
grid-column: span 6 !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
const { linkable, styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
// BB emblem: https://i.imgur.com/Xhdt1YP.png
|
||||
// Space logo: https://i.imgur.com/Dn7Xt1G.png
|
||||
|
||||
export let logoUrl
|
||||
export let hideLogo
|
||||
</script>
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
export let field
|
||||
export let label
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let compact = false
|
||||
export let validation
|
||||
export let extensions
|
||||
export let onChange
|
||||
export let maximum = undefined
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -71,33 +73,27 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{span}
|
||||
type="attachment"
|
||||
bind:fieldState
|
||||
bind:fieldApi
|
||||
defaultValue={[]}
|
||||
>
|
||||
<div class="minHeightWrapper">
|
||||
{#if fieldState}
|
||||
<CoreDropzone
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
on:change={handleChange}
|
||||
{processFiles}
|
||||
{deleteAttachments}
|
||||
{handleFileTooLarge}
|
||||
{handleTooManyFiles}
|
||||
{maximum}
|
||||
{extensions}
|
||||
{compact}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if fieldState}
|
||||
<CoreDropzone
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled || fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
on:change={handleChange}
|
||||
{processFiles}
|
||||
{deleteAttachments}
|
||||
{handleFileTooLarge}
|
||||
{handleTooManyFiles}
|
||||
{maximum}
|
||||
{extensions}
|
||||
{compact}
|
||||
/>
|
||||
{/if}
|
||||
</Field>
|
||||
|
||||
<style>
|
||||
.minHeightWrapper {
|
||||
min-height: 80px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let label
|
||||
export let text
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let size
|
||||
export let validation
|
||||
export let defaultValue
|
||||
|
@ -39,6 +40,7 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
defaultValue={isTruthy(defaultValue)}
|
||||
type="boolean"
|
||||
|
@ -49,6 +51,7 @@
|
|||
<CoreCheckbox
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{size}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
export let beepOnScan = false
|
||||
export let beepFrequency = 2637
|
||||
export let customFrequency = 1046
|
||||
export let preferredCamera = "environment"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
@ -20,7 +21,7 @@
|
|||
let cameraEnabled
|
||||
let cameraStarted = false
|
||||
let html5QrCode
|
||||
let cameraSetting = { facingMode: "environment" }
|
||||
let cameraSetting = { facingMode: preferredCamera }
|
||||
let cameraConfig = {
|
||||
fps: 25,
|
||||
qrbox: { width: 250, height: 250 },
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let label
|
||||
export let type = "barcodeqr"
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let defaultValue = ""
|
||||
export let onChange
|
||||
|
@ -14,6 +15,7 @@
|
|||
export let beepOnScan
|
||||
export let beepFrequency
|
||||
export let customFrequency
|
||||
export let preferredCamera
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -32,6 +34,7 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
{type}
|
||||
|
@ -42,12 +45,13 @@
|
|||
<CodeScanner
|
||||
value={fieldState.value}
|
||||
on:change={handleUpdate}
|
||||
disabled={fieldState.disabled}
|
||||
disabled={fieldState.disabled || fieldState.readonly}
|
||||
{allowManualEntry}
|
||||
scanButtonText={scanText}
|
||||
{beepOnScan}
|
||||
{beepFrequency}
|
||||
{customFrequency}
|
||||
{preferredCamera}
|
||||
/>
|
||||
{/if}
|
||||
</Field>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let enableTime = true
|
||||
export let timeOnly = false
|
||||
export let time24hr = false
|
||||
|
@ -13,6 +14,7 @@
|
|||
export let validation
|
||||
export let defaultValue
|
||||
export let onChange
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -29,8 +31,10 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
{span}
|
||||
type="datetime"
|
||||
bind:fieldState
|
||||
bind:fieldApi
|
||||
|
@ -40,6 +44,7 @@
|
|||
value={fieldState.value}
|
||||
on:change={handleChange}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
appendTo={document.getElementById("flatpickr-root")}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import Placeholder from "../Placeholder.svelte"
|
||||
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
||||
import { getContext, onDestroy } from "svelte"
|
||||
|
||||
export let label
|
||||
|
@ -11,7 +10,9 @@
|
|||
export let defaultValue
|
||||
export let type
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let span = 6
|
||||
|
||||
// Get contexts
|
||||
const formContext = getContext("form")
|
||||
|
@ -29,6 +30,7 @@
|
|||
type,
|
||||
defaultValue,
|
||||
disabled,
|
||||
readonly,
|
||||
validation,
|
||||
formStep
|
||||
)
|
||||
|
@ -62,40 +64,59 @@
|
|||
})
|
||||
</script>
|
||||
|
||||
<FieldGroupFallback>
|
||||
<div class="spectrum-Form-item" use:styleable={$component.styles}>
|
||||
{#key $component.editing}
|
||||
<label
|
||||
bind:this={labelNode}
|
||||
contenteditable={$component.editing}
|
||||
on:blur={$component.editing ? updateLabel : null}
|
||||
class:hidden={!label}
|
||||
for={fieldState?.fieldId}
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelClass}`}
|
||||
>
|
||||
{label || " "}
|
||||
</label>
|
||||
{/key}
|
||||
<div class="spectrum-Form-itemField">
|
||||
{#if !formContext}
|
||||
<Placeholder text="Form components need to be wrapped in a form" />
|
||||
{:else if !fieldState}
|
||||
<Placeholder />
|
||||
{:else if schemaType && schemaType !== type && !["options", "longform"].includes(type)}
|
||||
<Placeholder
|
||||
text="This Field setting is the wrong data type for this component"
|
||||
/>
|
||||
{:else}
|
||||
<slot />
|
||||
{#if fieldState.error}
|
||||
<div class="error">{fieldState.error}</div>
|
||||
{/if}
|
||||
<div
|
||||
class="spectrum-Form-item"
|
||||
class:span-2={span === 2}
|
||||
class:span-3={span === 3}
|
||||
class:span-6={span === 6 || !span}
|
||||
use:styleable={$component.styles}
|
||||
class:above={labelPos === "above"}
|
||||
>
|
||||
{#key $component.editing}
|
||||
<label
|
||||
bind:this={labelNode}
|
||||
contenteditable={$component.editing}
|
||||
on:blur={$component.editing ? updateLabel : null}
|
||||
class:hidden={!label}
|
||||
class:readonly
|
||||
for={fieldState?.fieldId}
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelClass}`}
|
||||
>
|
||||
{label || " "}
|
||||
</label>
|
||||
{/key}
|
||||
<div class="spectrum-Form-itemField">
|
||||
{#if !formContext}
|
||||
<Placeholder text="Form components need to be wrapped in a form" />
|
||||
{:else if !fieldState}
|
||||
<Placeholder />
|
||||
{:else if schemaType && schemaType !== type && !["options", "longform"].includes(type)}
|
||||
<Placeholder
|
||||
text="This Field setting is the wrong data type for this component"
|
||||
/>
|
||||
{:else}
|
||||
<slot />
|
||||
{#if fieldState.error}
|
||||
<div class="error">{fieldState.error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</FieldGroupFallback>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(.form-block .spectrum-Form-item.span-2) {
|
||||
grid-column: span 2;
|
||||
}
|
||||
:global(.form-block .spectrum-Form-item.span-3) {
|
||||
grid-column: span 3;
|
||||
}
|
||||
:global(.form-block .spectrum-Form-item.span-6) {
|
||||
grid-column: span 6;
|
||||
}
|
||||
.spectrum-Form-item.above {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -118,4 +139,7 @@
|
|||
.spectrum-FieldLabel--left {
|
||||
padding-right: var(--spectrum-global-dimension-size-200);
|
||||
}
|
||||
.readonly {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export let theme
|
||||
export let size
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let actionType = "Create"
|
||||
export let initialFormStep = 1
|
||||
|
||||
|
@ -39,7 +40,7 @@
|
|||
$: schemaKey = generateSchemaKey(schema)
|
||||
$: initialValues = getInitialValues(actionType, dataSource, $context)
|
||||
$: resetKey = Helpers.hashString(
|
||||
schemaKey + JSON.stringify(initialValues) + disabled
|
||||
schemaKey + JSON.stringify(initialValues) + disabled + readonly
|
||||
)
|
||||
|
||||
// Returns the closes data context which isn't a built in context
|
||||
|
@ -97,6 +98,7 @@
|
|||
{theme}
|
||||
{size}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{actionType}
|
||||
{schema}
|
||||
{table}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
export let dataSource
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let initialValues
|
||||
export let size
|
||||
export let schema
|
||||
|
@ -148,6 +149,7 @@
|
|||
type,
|
||||
defaultValue = null,
|
||||
fieldDisabled = false,
|
||||
fieldReadOnly = false,
|
||||
validationRules,
|
||||
step = 1
|
||||
) => {
|
||||
|
@ -205,6 +207,7 @@
|
|||
error: initialError,
|
||||
disabled:
|
||||
disabled || fieldDisabled || (isAutoColumn && !editAutoColumns),
|
||||
readonly: readonly || fieldReadOnly,
|
||||
defaultValue,
|
||||
validator,
|
||||
lastUpdate: Date.now(),
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let defaultValue = ""
|
||||
export let onChange
|
||||
|
||||
|
@ -48,6 +49,7 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
type="json"
|
||||
|
@ -60,6 +62,7 @@
|
|||
value={serialiseValue(fieldState.value)}
|
||||
on:change={handleChange}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let defaultValue = ""
|
||||
export let format = "auto"
|
||||
|
@ -58,6 +59,7 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
type="longform"
|
||||
|
@ -71,6 +73,7 @@
|
|||
value={fieldState.value}
|
||||
on:change={handleChange}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
|
@ -88,6 +91,7 @@
|
|||
value={fieldState.value}
|
||||
on:change={handleChange}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let defaultValue
|
||||
export let optionsSource = "schema"
|
||||
|
@ -17,6 +18,7 @@
|
|||
export let onChange
|
||||
export let optionsType = "select"
|
||||
export let direction = "vertical"
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -55,7 +57,9 @@
|
|||
{field}
|
||||
{label}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{span}
|
||||
defaultValue={expandedDefaultValue}
|
||||
type="array"
|
||||
bind:fieldState
|
||||
|
@ -71,6 +75,7 @@
|
|||
getOptionValue={flatOptions ? x => x : x => x.value}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
on:change={handleChange}
|
||||
{placeholder}
|
||||
{options}
|
||||
|
@ -81,6 +86,7 @@
|
|||
value={fieldState.value || []}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
{options}
|
||||
{direction}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let optionsType = "select"
|
||||
export let validation
|
||||
export let defaultValue
|
||||
|
@ -18,6 +19,7 @@
|
|||
export let direction = "vertical"
|
||||
export let onChange
|
||||
export let sort = true
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -45,8 +47,10 @@
|
|||
{field}
|
||||
{label}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
{span}
|
||||
type="options"
|
||||
bind:fieldState
|
||||
bind:fieldApi
|
||||
|
@ -58,6 +62,7 @@
|
|||
value={fieldState.value}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
{options}
|
||||
{placeholder}
|
||||
|
@ -72,6 +77,7 @@
|
|||
value={fieldState.value}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
{options}
|
||||
{direction}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
export let label
|
||||
export let placeholder
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let autocomplete = true
|
||||
export let defaultValue
|
||||
|
@ -18,6 +19,7 @@
|
|||
export let filter
|
||||
export let datasourceType = "table"
|
||||
export let primaryDisplay
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -137,7 +139,9 @@
|
|||
typeof value === "object" ? value._id : value
|
||||
)
|
||||
// Make sure field state is valid
|
||||
fieldApi.setValue(values)
|
||||
if (values?.length > 0) {
|
||||
fieldApi.setValue(values)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
|
@ -183,9 +187,11 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
defaultValue={expandedDefaultValue}
|
||||
{type}
|
||||
{span}
|
||||
bind:fieldState
|
||||
bind:fieldApi
|
||||
bind:fieldSchema
|
||||
|
@ -200,6 +206,7 @@
|
|||
on:loadMore={loadMore}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
getOptionLabel={getDisplayName}
|
||||
getOptionValue={option => option._id}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
export let placeholder
|
||||
export let type = "text"
|
||||
export let disabled = false
|
||||
export let readonly = false
|
||||
export let validation
|
||||
export let defaultValue = ""
|
||||
export let align
|
||||
export let onChange
|
||||
export let span
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -27,8 +29,10 @@
|
|||
{label}
|
||||
{field}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{validation}
|
||||
{defaultValue}
|
||||
{span}
|
||||
type={type === "number" ? "number" : "string"}
|
||||
bind:fieldState
|
||||
bind:fieldApi
|
||||
|
@ -39,6 +43,7 @@
|
|||
value={fieldState.value}
|
||||
on:change={handleChange}
|
||||
disabled={fieldState.disabled}
|
||||
readonly={fieldState.readonly}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
|
|
|
@ -40,6 +40,7 @@ export const styleable = (node, styles = {}) => {
|
|||
|
||||
const componentId = newStyles.id
|
||||
const customStyles = newStyles.custom || ""
|
||||
const { isBlock } = newStyles
|
||||
const normalStyles = { ...baseStyles, ...newStyles.normal }
|
||||
const hoverStyles = {
|
||||
...normalStyles,
|
||||
|
@ -76,6 +77,9 @@ export const styleable = (node, styles = {}) => {
|
|||
// Handler to start editing a component (if applicable) when double
|
||||
// clicking in the builder preview
|
||||
editComponent = event => {
|
||||
if (isBlock) {
|
||||
return
|
||||
}
|
||||
if (newStyles.interactive && newStyles.editable) {
|
||||
builderStore.actions.setEditMode(true)
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ export default class UserFetch extends DataFetch {
|
|||
let finalQuery
|
||||
// convert old format to new one - we now allow use of the lucene format
|
||||
const { appId, paginated, ...rest } = query
|
||||
if (!LuceneUtils.hasFilters(query) && rest.email) {
|
||||
if (!LuceneUtils.hasFilters(query) && rest.email != null) {
|
||||
finalQuery = { string: { email: rest.email } }
|
||||
} else {
|
||||
finalQuery = rest
|
||||
|
|
|
@ -254,7 +254,7 @@ export const exportRows = async (
|
|||
|
||||
const format = ctx.query.format
|
||||
|
||||
const { rows, columns, query } = ctx.request.body
|
||||
const { rows, columns, query, sort, sortOrder } = ctx.request.body
|
||||
if (typeof format !== "string" || !exporters.isFormat(format)) {
|
||||
ctx.throw(
|
||||
400,
|
||||
|
@ -272,6 +272,8 @@ export const exportRows = async (
|
|||
rowIds: rows,
|
||||
columns,
|
||||
query,
|
||||
sort,
|
||||
sortOrder,
|
||||
})
|
||||
ctx.attachment(fileName)
|
||||
return apiFileReturn(content)
|
||||
|
|
|
@ -147,7 +147,7 @@ export const serveApp = async function (ctx: Ctx) {
|
|||
const { head, html, css } = App.render({
|
||||
metaImage:
|
||||
branding?.metaImageUrl ||
|
||||
"https://res.cloudinary.com/daog6scxm/image/upload/v1666109324/meta-images/budibase-meta-image_uukc1m.png",
|
||||
"https://res.cloudinary.com/daog6scxm/image/upload/v1698759482/meta-images/plain-branded-meta-image-coral_ocxmgu.png",
|
||||
metaDescription: branding?.metaDescription || "",
|
||||
metaTitle:
|
||||
branding?.metaTitle || `${appInfo.name} - built with Budibase`,
|
||||
|
@ -185,7 +185,7 @@ export const serveApp = async function (ctx: Ctx) {
|
|||
metaTitle: branding?.metaTitle,
|
||||
metaImage:
|
||||
branding?.metaImageUrl ||
|
||||
"https://res.cloudinary.com/daog6scxm/image/upload/v1666109324/meta-images/budibase-meta-image_uukc1m.png",
|
||||
"https://res.cloudinary.com/daog6scxm/image/upload/v1698759482/meta-images/plain-branded-meta-image-coral_ocxmgu.png",
|
||||
metaDescription: branding?.metaDescription || "",
|
||||
favicon:
|
||||
branding.faviconUrl !== ""
|
||||
|
|
|
@ -15,6 +15,16 @@ import env from "../../../environment"
|
|||
const Router = require("@koa/router")
|
||||
const { RateLimit, Stores } = require("koa2-ratelimit")
|
||||
import { middleware, redis } from "@budibase/backend-core"
|
||||
import { SelectableDatabase } from "@budibase/backend-core/src/redis/utils"
|
||||
|
||||
interface KoaRateLimitOptions {
|
||||
socket: {
|
||||
host: string
|
||||
port: number
|
||||
}
|
||||
password?: string
|
||||
database?: number
|
||||
}
|
||||
|
||||
const PREFIX = "/api/public/v1"
|
||||
// allow a lot more requests when in test
|
||||
|
@ -29,32 +39,21 @@ function getApiLimitPerSecond(): number {
|
|||
|
||||
let rateLimitStore: any = null
|
||||
if (!env.isTest()) {
|
||||
const REDIS_OPTS = redis.utils.getRedisOptions()
|
||||
let options
|
||||
if (REDIS_OPTS.redisProtocolUrl) {
|
||||
// fully qualified redis URL
|
||||
options = {
|
||||
url: REDIS_OPTS.redisProtocolUrl,
|
||||
}
|
||||
} else {
|
||||
options = {
|
||||
socket: {
|
||||
host: REDIS_OPTS.host,
|
||||
port: REDIS_OPTS.port,
|
||||
},
|
||||
}
|
||||
const { password, host, port } = redis.utils.getRedisConnectionDetails()
|
||||
let options: KoaRateLimitOptions = {
|
||||
socket: {
|
||||
host: host,
|
||||
port: port,
|
||||
},
|
||||
}
|
||||
|
||||
if (REDIS_OPTS.opts?.password || REDIS_OPTS.opts.redisOptions?.password) {
|
||||
// @ts-ignore
|
||||
options.password =
|
||||
REDIS_OPTS.opts.password || REDIS_OPTS.opts.redisOptions.password
|
||||
}
|
||||
if (password) {
|
||||
options.password = password
|
||||
}
|
||||
|
||||
if (!env.REDIS_CLUSTERED) {
|
||||
// @ts-ignore
|
||||
// Can't set direct redis db in clustered env
|
||||
options.database = 1
|
||||
}
|
||||
if (!env.REDIS_CLUSTERED) {
|
||||
// Can't set direct redis db in clustered env
|
||||
options.database = SelectableDatabase.RATE_LIMITING
|
||||
}
|
||||
rateLimitStore = new Stores.Redis(options)
|
||||
RateLimit.defaultOptions({
|
||||
|
|
|
@ -563,6 +563,56 @@ describe.each([
|
|||
await assertRowUsage(rowUsage)
|
||||
await assertQueryUsage(queryUsage)
|
||||
})
|
||||
|
||||
it("should not overwrite links if those links are not set", async () => {
|
||||
let linkField: FieldSchema = {
|
||||
type: FieldType.LINK,
|
||||
name: "",
|
||||
fieldName: "",
|
||||
constraints: {
|
||||
type: "array",
|
||||
presence: false,
|
||||
},
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
tableId: InternalTable.USER_METADATA,
|
||||
}
|
||||
|
||||
let table = await config.api.table.create({
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
schema: {
|
||||
user1: { ...linkField, name: "user1", fieldName: "user1" },
|
||||
user2: { ...linkField, name: "user2", fieldName: "user2" },
|
||||
},
|
||||
})
|
||||
|
||||
let user1 = await config.createUser()
|
||||
let user2 = await config.createUser()
|
||||
|
||||
let row = await config.api.row.save(table._id!, {
|
||||
user1: [{ _id: user1._id }],
|
||||
user2: [{ _id: user2._id }],
|
||||
})
|
||||
|
||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
||||
|
||||
let patchResp = await config.api.row.patch(table._id!, {
|
||||
_id: row._id!,
|
||||
_rev: row._rev!,
|
||||
tableId: table._id!,
|
||||
user1: [{ _id: user2._id }],
|
||||
})
|
||||
expect(patchResp.user1[0]._id).toEqual(user2._id)
|
||||
expect(patchResp.user2[0]._id).toEqual(user2._id)
|
||||
|
||||
getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
||||
})
|
||||
})
|
||||
|
||||
describe("destroy", () => {
|
||||
|
|
|
@ -36,7 +36,7 @@ describe("Run through some parts of the automations system", () => {
|
|||
it("should be able to init in builder", async () => {
|
||||
const automation: Automation = {
|
||||
...basicAutomation(),
|
||||
appId: config.appId,
|
||||
appId: config.appId!,
|
||||
}
|
||||
const fields: any = { a: 1, appId: config.appId }
|
||||
await triggers.externalTrigger(automation, fields)
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
const setup = require("./utilities")
|
||||
|
||||
describe("test the update row action", () => {
|
||||
let table, row, inputs
|
||||
let config = setup.getConfig()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.init()
|
||||
table = await config.createTable()
|
||||
row = await config.createRow()
|
||||
inputs = {
|
||||
rowId: row._id,
|
||||
row: {
|
||||
...row,
|
||||
name: "Updated name",
|
||||
// put a falsy option in to be removed
|
||||
description: "",
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
afterAll(setup.afterAll)
|
||||
|
||||
it("should be able to run the action", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, inputs)
|
||||
expect(res.success).toEqual(true)
|
||||
const updatedRow = await config.getRow(table._id, res.id)
|
||||
expect(updatedRow.name).toEqual("Updated name")
|
||||
expect(updatedRow.description).not.toEqual("")
|
||||
})
|
||||
|
||||
it("should check invalid inputs return an error", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {})
|
||||
expect(res.success).toEqual(false)
|
||||
})
|
||||
|
||||
it("should return an error when table doesn't exist", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||
row: { _id: "invalid" },
|
||||
rowId: "invalid",
|
||||
})
|
||||
expect(res.success).toEqual(false)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,169 @@
|
|||
import {
|
||||
FieldSchema,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
InternalTable,
|
||||
RelationshipType,
|
||||
Row,
|
||||
Table,
|
||||
TableSourceType,
|
||||
} from "@budibase/types"
|
||||
|
||||
import * as setup from "./utilities"
|
||||
import * as uuid from "uuid"
|
||||
|
||||
describe("test the update row action", () => {
|
||||
let table: Table, row: Row, inputs: any
|
||||
let config = setup.getConfig()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.init()
|
||||
table = await config.createTable()
|
||||
row = await config.createRow()
|
||||
inputs = {
|
||||
rowId: row._id,
|
||||
row: {
|
||||
...row,
|
||||
name: "Updated name",
|
||||
// put a falsy option in to be removed
|
||||
description: "",
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
afterAll(setup.afterAll)
|
||||
|
||||
it("should be able to run the action", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, inputs)
|
||||
expect(res.success).toEqual(true)
|
||||
const updatedRow = await config.getRow(table._id!, res.id)
|
||||
expect(updatedRow.name).toEqual("Updated name")
|
||||
expect(updatedRow.description).not.toEqual("")
|
||||
})
|
||||
|
||||
it("should check invalid inputs return an error", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {})
|
||||
expect(res.success).toEqual(false)
|
||||
})
|
||||
|
||||
it("should return an error when table doesn't exist", async () => {
|
||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||
row: { _id: "invalid" },
|
||||
rowId: "invalid",
|
||||
})
|
||||
expect(res.success).toEqual(false)
|
||||
})
|
||||
|
||||
it("should not overwrite links if those links are not set", async () => {
|
||||
let linkField: FieldSchema = {
|
||||
type: FieldType.LINK,
|
||||
name: "",
|
||||
fieldName: "",
|
||||
constraints: {
|
||||
type: "array",
|
||||
presence: false,
|
||||
},
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
tableId: InternalTable.USER_METADATA,
|
||||
}
|
||||
|
||||
let table = await config.api.table.create({
|
||||
name: uuid.v4(),
|
||||
type: "table",
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
schema: {
|
||||
user1: { ...linkField, name: "user1", fieldName: uuid.v4() },
|
||||
user2: { ...linkField, name: "user2", fieldName: uuid.v4() },
|
||||
},
|
||||
})
|
||||
|
||||
let user1 = await config.createUser()
|
||||
let user2 = await config.createUser()
|
||||
|
||||
let row = await config.api.row.save(table._id!, {
|
||||
user1: [{ _id: user1._id }],
|
||||
user2: [{ _id: user2._id }],
|
||||
})
|
||||
|
||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
||||
|
||||
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||
rowId: row._id,
|
||||
row: {
|
||||
_id: row._id,
|
||||
_rev: row._rev,
|
||||
tableId: row.tableId,
|
||||
user1: [user2._id],
|
||||
user2: "",
|
||||
},
|
||||
})
|
||||
expect(stepResp.success).toEqual(true)
|
||||
|
||||
getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
||||
})
|
||||
|
||||
it("should overwrite links if those links are not set and we ask it do", async () => {
|
||||
let linkField: FieldSchema = {
|
||||
type: FieldType.LINK,
|
||||
name: "",
|
||||
fieldName: "",
|
||||
constraints: {
|
||||
type: "array",
|
||||
presence: false,
|
||||
},
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
tableId: InternalTable.USER_METADATA,
|
||||
}
|
||||
|
||||
let table = await config.api.table.create({
|
||||
name: uuid.v4(),
|
||||
type: "table",
|
||||
sourceType: TableSourceType.INTERNAL,
|
||||
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||
schema: {
|
||||
user1: { ...linkField, name: "user1", fieldName: uuid.v4() },
|
||||
user2: { ...linkField, name: "user2", fieldName: uuid.v4() },
|
||||
},
|
||||
})
|
||||
|
||||
let user1 = await config.createUser()
|
||||
let user2 = await config.createUser()
|
||||
|
||||
let row = await config.api.row.save(table._id!, {
|
||||
user1: [{ _id: user1._id }],
|
||||
user2: [{ _id: user2._id }],
|
||||
})
|
||||
|
||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
||||
|
||||
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||
rowId: row._id,
|
||||
row: {
|
||||
_id: row._id,
|
||||
_rev: row._rev,
|
||||
tableId: row.tableId,
|
||||
user1: [user2._id],
|
||||
user2: "",
|
||||
},
|
||||
meta: {
|
||||
fields: {
|
||||
user2: {
|
||||
clearRelationships: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(stepResp.success).toEqual(true)
|
||||
|
||||
getResp = await config.api.row.get(table._id!, row._id!)
|
||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
||||
expect(getResp.body.user2).toBeUndefined()
|
||||
})
|
||||
})
|
|
@ -4,11 +4,11 @@ import { BUILTIN_ACTION_DEFINITIONS, getAction } from "../../actions"
|
|||
import emitter from "../../../events/index"
|
||||
import env from "../../../environment"
|
||||
|
||||
let config: any
|
||||
let config: TestConfig
|
||||
|
||||
export function getConfig() {
|
||||
export function getConfig(): TestConfig {
|
||||
if (!config) {
|
||||
config = new TestConfig(false)
|
||||
config = new TestConfig(true)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { Row, SearchFilters, SearchParams } from "@budibase/types"
|
||||
import {
|
||||
Row,
|
||||
SearchFilters,
|
||||
SearchParams,
|
||||
SortOrder,
|
||||
SortType,
|
||||
} from "@budibase/types"
|
||||
import { isExternalTableID } from "../../../integrations/utils"
|
||||
import * as internal from "./search/internal"
|
||||
import * as external from "./search/external"
|
||||
|
@ -32,6 +38,8 @@ export interface ExportRowsParams {
|
|||
rowIds?: string[]
|
||||
columns?: string[]
|
||||
query?: SearchFilters
|
||||
sort?: string
|
||||
sortOrder?: SortOrder
|
||||
}
|
||||
|
||||
export interface ExportRowsResult {
|
||||
|
|
|
@ -98,12 +98,12 @@ export async function search(options: SearchParams) {
|
|||
export async function exportRows(
|
||||
options: ExportRowsParams
|
||||
): Promise<ExportRowsResult> {
|
||||
const { tableId, format, columns, rowIds } = options
|
||||
const { tableId, format, columns, rowIds, query, sort, sortOrder } = options
|
||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
|
||||
let query: SearchFilters = {}
|
||||
let requestQuery: SearchFilters = {}
|
||||
if (rowIds?.length) {
|
||||
query = {
|
||||
requestQuery = {
|
||||
oneOf: {
|
||||
_id: rowIds.map((row: string) => {
|
||||
const ids = JSON.parse(
|
||||
|
@ -119,6 +119,8 @@ export async function exportRows(
|
|||
}),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
requestQuery = query || {}
|
||||
}
|
||||
|
||||
const datasource = await sdk.datasources.get(datasourceId!)
|
||||
|
@ -126,7 +128,7 @@ export async function exportRows(
|
|||
throw new HTTPError("Datasource has not been configured for plus API.", 400)
|
||||
}
|
||||
|
||||
let result = await search({ tableId, query })
|
||||
let result = await search({ tableId, query: requestQuery, sort, sortOrder })
|
||||
let rows: Row[] = []
|
||||
|
||||
// Filter data to only specified columns if required
|
||||
|
|
|
@ -84,7 +84,7 @@ export async function search(options: SearchParams) {
|
|||
export async function exportRows(
|
||||
options: ExportRowsParams
|
||||
): Promise<ExportRowsResult> {
|
||||
const { tableId, format, rowIds, columns, query } = options
|
||||
const { tableId, format, rowIds, columns, query, sort, sortOrder } = options
|
||||
const db = context.getAppDB()
|
||||
const table = await sdk.tables.getTable(tableId)
|
||||
|
||||
|
@ -99,7 +99,12 @@ export async function exportRows(
|
|||
|
||||
result = await outputProcessing(table, response)
|
||||
} else if (query) {
|
||||
let searchResponse = await search({ tableId, query })
|
||||
let searchResponse = await search({
|
||||
tableId,
|
||||
query,
|
||||
sort,
|
||||
sortOrder,
|
||||
})
|
||||
result = searchResponse.rows
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,15 @@ export class TableAPI extends TestAPI {
|
|||
.send(data)
|
||||
.set(this.config.defaultHeaders())
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(expectStatus)
|
||||
|
||||
if (res.status !== expectStatus) {
|
||||
throw new Error(
|
||||
`Expected status ${expectStatus} but got ${
|
||||
res.status
|
||||
} with body ${JSON.stringify(res.body)}`
|
||||
)
|
||||
}
|
||||
|
||||
return res.body
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { SearchFilters, SearchParams } from "../../../sdk"
|
||||
import { Row } from "../../../documents"
|
||||
import { SortOrder } from "../../../api"
|
||||
import { ReadStream } from "fs"
|
||||
|
||||
export interface SaveRowRequest extends Row {}
|
||||
|
@ -34,6 +35,8 @@ export interface ExportRowsRequest {
|
|||
rows: string[]
|
||||
columns?: string[]
|
||||
query?: SearchFilters
|
||||
sort?: string
|
||||
sortOrder?: SortOrder
|
||||
}
|
||||
|
||||
export type ExportRowsResponse = ReadStream
|
||||
|
|
|
@ -102,6 +102,7 @@ export interface BBReferenceFieldMetadata
|
|||
extends Omit<BaseFieldSchema, "subtype"> {
|
||||
type: FieldType.BB_REFERENCE
|
||||
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
relationshipType?: RelationshipType
|
||||
}
|
||||
|
||||
export interface FieldConstraints {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
|
||||
a {
|
||||
color: #3869D4 !important;
|
||||
color: #6E56FF !important;
|
||||
}
|
||||
|
||||
a img {
|
||||
|
@ -109,11 +109,11 @@
|
|||
/* Buttons ------------------------------ */
|
||||
|
||||
.button {
|
||||
background-color: #3869D4;
|
||||
border-top: 10px solid #3869D4;
|
||||
border-right: 18px solid #3869D4;
|
||||
border-bottom: 10px solid #3869D4;
|
||||
border-left: 18px solid #3869D4;
|
||||
background-color: #6E56FF;
|
||||
border-top: 10px solid #6E56FF;
|
||||
border-right: 18px solid #6E56FF;
|
||||
border-bottom: 10px solid #6E56FF;
|
||||
border-left: 18px solid #6E56FF;
|
||||
display: inline-block;
|
||||
color: #FFF !important;
|
||||
text-decoration: none !important;
|
||||
|
|
|
@ -16,15 +16,11 @@
|
|||
cellspacing="0"
|
||||
>
|
||||
<img
|
||||
width="32"
|
||||
height="32"
|
||||
style="margin-right:16px; vertical-align: middle;"
|
||||
alt="Budibase Logo"
|
||||
src="https://i.imgur.com/Xhdt1YP.png"
|
||||
src="https://res.cloudinary.com/daog6scxm/image/upload/v1696521007/Branding/Assets/Logo/RGB/Full%20Colour/Budibase_Logo_RGB_FullColour_Negative_e9yziz_1_u6oxzg.png"
|
||||
/>
|
||||
<strong style="vertical-align: middle; font-size: 1.1em">
|
||||
Budibase
|
||||
</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -31,10 +31,6 @@ import destroyable from "server-destroy"
|
|||
import { initPro } from "./initPro"
|
||||
import { handleScimBody } from "./middleware/handleScimBody"
|
||||
|
||||
// configure events to use the pro audit log write
|
||||
// can't integrate directly into backend-core due to cyclic issues
|
||||
events.processors.init(proSdk.auditLogs.write)
|
||||
|
||||
if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE) {
|
||||
console.warn(
|
||||
"Warning: ENABLE_SSO_MAINTENANCE_MODE is set. It is recommended this flag is disabled if maintenance is not in progress"
|
||||
|
@ -93,6 +89,9 @@ export default server.listen(parseInt(env.PORT || "4002"), async () => {
|
|||
console.log(`Worker running on ${JSON.stringify(server.address())}`)
|
||||
await initPro()
|
||||
await redis.init()
|
||||
// configure events to use the pro audit log write
|
||||
// can't integrate directly into backend-core due to cyclic issues
|
||||
await events.processors.init(proSdk.auditLogs.write)
|
||||
})
|
||||
|
||||
process.on("uncaughtException", err => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## Description
|
||||
_Describe the problem or feature in addition to a link to the relevant github issues._
|
||||
|
||||
### Addresses:
|
||||
## Addresses
|
||||
- `<Enter the Link to the issue(s) this PR addresses>`
|
||||
- ...more if required
|
||||
|
||||
|
|
Loading…
Reference in New Issue