Merge branch 'master' of github.com:Budibase/budibase into fix/cypress-fixes
This commit is contained in:
commit
1e9ce62261
66
README.md
66
README.md
|
@ -30,9 +30,6 @@
|
|||
<a href="https://github.com/Budibase/budibase/releases">
|
||||
<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Budibase/budibase">
|
||||
</a>
|
||||
<a href="https://discord.gg/rCYayfe">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/733030666647765003">
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=budibase">
|
||||
<img src="https://img.shields.io/twitter/follow/budibase?style=social" alt="Follow @budibase" />
|
||||
</a>
|
||||
|
@ -52,8 +49,6 @@
|
|||
<a href="https://github.com/Budibase/budibase/issues">Report a bug</a>
|
||||
<span> · </span>
|
||||
Support: <a href="https://github.com/Budibase/budibase/discussions">Discussions</a>
|
||||
<span> & </span>
|
||||
<a href="https://discord.gg/rCYayfe">Discord</a>
|
||||
</h3>
|
||||
|
||||
|
||||
|
@ -61,7 +56,7 @@
|
|||
|
||||
- **Build and ship real software.** Unlike other platforms, with Budibase you build and ship single page applications. Budibase applications have performance baked in and can be designed responsively, providing your users with a great experience.
|
||||
|
||||
- **Open source and extensable.** Budibase is open-source - licensed as GPL v3. This should fill you with confidence that Budibase will always be around. You can also code against Budibase or fork it and make changes as you please, providing a developer-friendly experience.
|
||||
- **Open source and extensible.** Budibase is open-source - licensed as GPL v3. This should fill you with confidence that Budibase will always be around. You can also code against Budibase or fork it and make changes as you please, providing a developer-friendly experience.
|
||||
|
||||
- **Load data or start from scratch.** Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, mySQL, Airtable, S3, DyanmoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
|
||||
|
||||
|
@ -79,28 +74,6 @@
|
|||
---
|
||||
|
||||
|
||||
## ⌛ Status
|
||||
- [x] Alpha: We are demoing Budibase to users and receiving feedback
|
||||
- [x] Private Beta: We are testing Budibase with a closed set of customers
|
||||
- [x] Public Beta: Anyone can [get started](https://docs.budibase.com/getting-started).
|
||||
- [ ] Official Launch
|
||||
|
||||
Watch "releases" of this repo to get notified of major updates, and give the star button a click whilst you're there.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://i.imgur.com/cJpgqm8.png">
|
||||
</p>
|
||||
|
||||
### Stargazers over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/Budibase/budibase.svg)](https://starchart.cc/Budibase/budibase)
|
||||
|
||||
If you are having issues between updates of the builder, please use the guide [here](https://github.com/Budibase/budibase/blob/HEAD/.github/CONTRIBUTING.md#troubleshooting) to clear down your environment.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 🏁 Getting Started with Budibase in 5 minutes
|
||||
|
||||
To get started, you must have docker and docker compose installed on your machine.
|
||||
|
@ -141,21 +114,40 @@ Done! You are now ready to build powerful internal tools in minutes. For additio
|
|||
|
||||
The Budibase [documentation lives here](https://docs.budibase.com).
|
||||
|
||||
You can also follow a quick tutorial on [how to build a CRM with Budibase](https://docs.budibase.com/tutorial/tutorial-introduction)
|
||||
|
||||
---
|
||||
|
||||
## ⌛ Status
|
||||
- [x] Alpha: We are demoing Budibase to users and receiving feedback
|
||||
- [x] Private Beta: We are testing Budibase with a closed set of customers
|
||||
- [x] Public Beta: Anyone can [get started](https://docs.budibase.com/getting-started).
|
||||
- [ ] Official Launch
|
||||
|
||||
Watch "releases" of this repo to get notified of major updates, and give the star button a click whilst you're there.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://i.imgur.com/cJpgqm8.png">
|
||||
</p>
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/Budibase/budibase.svg)](https://starchart.cc/Budibase/budibase)
|
||||
|
||||
If you are having issues between updates of the builder, please use the guide [here](https://github.com/Budibase/budibase/blob/HEAD/.github/CONTRIBUTING.md#troubleshooting) to clear down your environment.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Roadmap
|
||||
|
||||
Checkout our [Public Roadmap](https://github.com/Budibase/budibase/projects/10). If you would like to discuss some of the items on the roadmap, please feel to reach out on [Discord](https://discord.gg/rCYayfe), or via [Github discussions](https://github.com/Budibase/budibase/discussions)
|
||||
|
||||
|
||||
## ❗ Code of Conduct
|
||||
|
||||
Budibase is dedicated to providing a welcoming, diverse, and harrassment-free experience for everyone. We expect everyone in the Budibase community to abide by our [**Code of Conduct**](https://github.com/Budibase/budibase/blob/HEAD/.github/CODE_OF_CONDUCT.md). Please read it.
|
||||
|
||||
---
|
||||
|
||||
## 🙌 Contributing to Budibase
|
||||
|
||||
From opening a bug report to creating a pull request: every contribution is appreciated and welcomed. If you're planning to implement a new feature or change the API please create an issue first. This way we can ensure your work is not in vain.
|
||||
|
@ -188,11 +180,7 @@ Budibase is open-source. The builder is licensed [AGPL v3](https://www.gnu.org/l
|
|||
|
||||
## 💬 Get in touch
|
||||
|
||||
If you have a question or would like to talk with other Budibase users, please hop over to [Github discussions](https://github.com/Budibase/budibase/discussions) or join our Discord server:
|
||||
|
||||
[Discord chatroom](https://discord.gg/rCYayfe)
|
||||
|
||||
![Discord Shield](https://discordapp.com/api/guilds/733030666647765003/widget.png?style=shield)
|
||||
If you have a question or would like to talk with other Budibase users and join our community, please hop over to [Github discussions](https://github.com/Budibase/budibase/discussions)
|
||||
|
||||
|
||||
---
|
||||
|
|
|
@ -24,6 +24,8 @@ services:
|
|||
ENABLE_ANALYTICS: "true"
|
||||
REDIS_URL: redis-service:6379
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||
volumes:
|
||||
- ./logs:/logs
|
||||
depends_on:
|
||||
- worker-service
|
||||
|
||||
|
@ -46,6 +48,8 @@ services:
|
|||
INTERNAL_API_KEY: ${INTERNAL_API_KEY}
|
||||
REDIS_URL: redis-service:6379
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||
volumes:
|
||||
- ./logs:/logs
|
||||
depends_on:
|
||||
- redis-service
|
||||
- minio-service
|
||||
|
@ -110,6 +114,21 @@ services:
|
|||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
watchtower-service:
|
||||
image: containrrr/watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --debug --http-api-update budibase/apps budibase/worker
|
||||
environment:
|
||||
- WATCHTOWER_HTTP_API=true
|
||||
- WATCHTOWER_HTTP_API_TOKEN=budibase
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
ports:
|
||||
- 6161:8080
|
||||
|
||||
|
||||
volumes:
|
||||
couchdb3_data:
|
||||
driver: local
|
||||
|
|
|
@ -133,4 +133,3 @@ static_resources:
|
|||
socket_address:
|
||||
address: {{ address }}
|
||||
port_value: 4002
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ static_resources:
|
|||
cluster: app-service
|
||||
prefix_rewrite: "/"
|
||||
|
||||
- match: { path: "/v1/update" }
|
||||
route:
|
||||
cluster: watchtower-service
|
||||
|
||||
- match: { prefix: "/builder/" }
|
||||
route:
|
||||
cluster: app-service
|
||||
|
@ -123,3 +127,17 @@ static_resources:
|
|||
address: couchdb-service
|
||||
port_value: 5984
|
||||
|
||||
- name: watchtower-service
|
||||
connect_timeout: 0.25s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: watchtower-service
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: watchtower-service
|
||||
port_value: 6161
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/auth",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"description": "Authentication middlewares for budibase builder and apps",
|
||||
"main": "src/index.js",
|
||||
"author": "Budibase",
|
||||
|
|
|
@ -2,7 +2,7 @@ const passport = require("koa-passport")
|
|||
const LocalStrategy = require("passport-local").Strategy
|
||||
const JwtStrategy = require("passport-jwt").Strategy
|
||||
const { StaticDatabases } = require("./db/utils")
|
||||
const { jwt, local, authenticated, google } = require("./middleware")
|
||||
const { jwt, local, authenticated, google, auditLog } = require("./middleware")
|
||||
const { setDB, getDB } = require("./db")
|
||||
|
||||
// Strategies
|
||||
|
@ -45,6 +45,7 @@ module.exports = {
|
|||
passport,
|
||||
google,
|
||||
jwt: require("jsonwebtoken"),
|
||||
auditLog,
|
||||
},
|
||||
StaticDatabases,
|
||||
constants: require("./constants"),
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = async (ctx, next) => {
|
||||
// Placeholder for audit log middleware
|
||||
return next()
|
||||
}
|
|
@ -2,10 +2,12 @@ const jwt = require("./passport/jwt")
|
|||
const local = require("./passport/local")
|
||||
const google = require("./passport/google")
|
||||
const authenticated = require("./authenticated")
|
||||
const auditLog = require("./auditLog")
|
||||
|
||||
module.exports = {
|
||||
google,
|
||||
jwt,
|
||||
local,
|
||||
authenticated,
|
||||
auditLog,
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ exports.upload = async ({
|
|||
* Similar to the upload function but can be used to send a file stream
|
||||
* through to the object store.
|
||||
*/
|
||||
exports.streamUpload = async (bucketName, filename, stream) => {
|
||||
exports.streamUpload = async (bucketName, filename, stream, extra = {}) => {
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||
|
||||
|
@ -167,6 +167,7 @@ exports.streamUpload = async (bucketName, filename, stream) => {
|
|||
Bucket: sanitizeBucket(bucketName),
|
||||
Key: sanitizeKey(filename),
|
||||
Body: stream,
|
||||
...extra,
|
||||
}
|
||||
return objectStore.upload(params).promise()
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ const BUILTIN_IDS = {
|
|||
POWER: "POWER",
|
||||
BASIC: "BASIC",
|
||||
PUBLIC: "PUBLIC",
|
||||
BUILDER: "BUILDER",
|
||||
}
|
||||
|
||||
// exclude internal roles like builder
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"license": "AGPL-3.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
|
|
@ -37,3 +37,9 @@
|
|||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spectrum-Radio-input {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -65,10 +65,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.21",
|
||||
"@budibase/client": "^0.9.21",
|
||||
"@budibase/bbui": "^0.9.27",
|
||||
"@budibase/client": "^0.9.27",
|
||||
"@budibase/colorpicker": "1.1.2",
|
||||
"@budibase/string-templates": "^0.9.21",
|
||||
"@budibase/string-templates": "^0.9.27",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -136,7 +136,7 @@ const getContextBindings = (asset, componentId) => {
|
|||
if (!datasource) {
|
||||
return
|
||||
}
|
||||
const info = getSchemaForDatasource(datasource)
|
||||
const info = getSchemaForDatasource(asset, datasource)
|
||||
schema = info.schema
|
||||
readablePrefix = info.table?.name
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ const getContextBindings = (asset, componentId) => {
|
|||
*/
|
||||
const getUserBindings = () => {
|
||||
let bindings = []
|
||||
const { schema } = getSchemaForDatasource({
|
||||
const { schema } = getSchemaForDatasource(null, {
|
||||
type: "table",
|
||||
tableId: TableNames.USERS,
|
||||
})
|
||||
|
@ -244,11 +244,15 @@ const getUrlBindings = asset => {
|
|||
/**
|
||||
* Gets a schema for a datasource object.
|
||||
*/
|
||||
export const getSchemaForDatasource = (datasource, isForm = false) => {
|
||||
export const getSchemaForDatasource = (asset, datasource, isForm = false) => {
|
||||
let schema, table
|
||||
if (datasource) {
|
||||
const { type } = datasource
|
||||
if (type === "query") {
|
||||
if (type === "provider") {
|
||||
const component = findComponent(asset.props, datasource.providerId)
|
||||
const source = getDatasourceForProvider(asset, component)
|
||||
return getSchemaForDatasource(asset, source, isForm)
|
||||
} else if (type === "query") {
|
||||
const queries = get(queriesStores).list
|
||||
table = queries.find(query => query._id === datasource._id)
|
||||
} else {
|
||||
|
|
|
@ -174,7 +174,7 @@ const fieldTypeToComponentMap = {
|
|||
}
|
||||
|
||||
export function makeDatasourceFormComponents(datasource) {
|
||||
const { schema } = getSchemaForDatasource(datasource, true)
|
||||
const { schema } = getSchemaForDatasource(null, datasource, true)
|
||||
let components = []
|
||||
let fields = Object.keys(schema || {})
|
||||
fields.forEach(field => {
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
}
|
||||
|
||||
let originalName = field.name
|
||||
const linkEditDisabled = originalName != null
|
||||
let primaryDisplay =
|
||||
$tables.selected.primaryDisplay == null ||
|
||||
$tables.selected.primaryDisplay === field.name
|
||||
|
@ -198,7 +199,7 @@
|
|||
<Input
|
||||
label="Name"
|
||||
bind:value={field.name}
|
||||
disabled={uneditable || field.type === LINK_TYPE}
|
||||
disabled={uneditable || (linkEditDisabled && field.type === LINK_TYPE)}
|
||||
/>
|
||||
|
||||
<Select
|
||||
|
@ -285,6 +286,7 @@
|
|||
{:else if field.type === "link"}
|
||||
<Select
|
||||
label="Table"
|
||||
disabled={linkEditDisabled}
|
||||
bind:value={field.tableId}
|
||||
options={tableOptions}
|
||||
getOptionLabel={table => table.name}
|
||||
|
@ -292,7 +294,7 @@
|
|||
/>
|
||||
{#if relationshipOptions && relationshipOptions.length > 0}
|
||||
<RadioGroup
|
||||
disabled={originalName != null}
|
||||
disabled={linkEditDisabled}
|
||||
label="Define the relationship"
|
||||
bind:value={field.relationshipType}
|
||||
options={relationshipOptions}
|
||||
|
@ -300,7 +302,11 @@
|
|||
getOptionValue={option => option.value}
|
||||
/>
|
||||
{/if}
|
||||
<Input label={`Column name in other table`} bind:value={field.fieldName} />
|
||||
<Input
|
||||
disabled={linkEditDisabled}
|
||||
label={`Column name in other table`}
|
||||
bind:value={field.fieldName}
|
||||
/>
|
||||
{:else if field.type === FORMULA_TYPE}
|
||||
<ModalBindableInput
|
||||
title="Handlebars Formula"
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"longformfield",
|
||||
"datetimefield",
|
||||
"attachmentfield",
|
||||
"relationshipfield"
|
||||
"relationshipfield",
|
||||
"daterangepicker"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<script>
|
||||
import { getBindableProperties } from "builderStore/dataBinding"
|
||||
import {
|
||||
getBindableProperties,
|
||||
getDataProviderComponents,
|
||||
} from "builderStore/dataBinding"
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
|
@ -61,6 +64,17 @@
|
|||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: dataProviders = getDataProviderComponents(
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
).map(provider => ({
|
||||
label: provider._instanceName,
|
||||
name: provider._instanceName,
|
||||
providerId: provider._id,
|
||||
value: `{{ literal [${provider._id}] }}`,
|
||||
type: "provider",
|
||||
schema: provider.schema,
|
||||
}))
|
||||
$: queryBindableProperties = bindableProperties.map(property => ({
|
||||
...property,
|
||||
category: property.type === "instance" ? "Component" : "Table",
|
||||
|
@ -182,7 +196,20 @@
|
|||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<Divider size="S" />
|
||||
<div class="title">
|
||||
<Heading size="XS">Data Providers</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each dataProviders as provider}
|
||||
<li
|
||||
class:selected={value === provider}
|
||||
on:click={() => handleSelected(provider)}
|
||||
>
|
||||
{provider.label}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{#if otherSources?.length}
|
||||
<Divider size="S" />
|
||||
<div class="title">
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: schemaFields = getSchemaFields(parameters?.tableId)
|
||||
$: schemaFields = getSchemaFields($currentAsset, parameters?.tableId)
|
||||
$: tableOptions = $tables.list || []
|
||||
|
||||
const getSchemaFields = tableId => {
|
||||
const { schema } = getSchemaForDatasource({ type: "table", tableId })
|
||||
const getSchemaFields = (asset, tableId) => {
|
||||
const { schema } = getSchemaForDatasource(asset, { type: "table", tableId })
|
||||
return Object.values(schema || {})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@ import ExecuteQuery from "./ExecuteQuery.svelte"
|
|||
import TriggerAutomation from "./TriggerAutomation.svelte"
|
||||
import ValidateForm from "./ValidateForm.svelte"
|
||||
|
||||
// defines what actions are available, when adding a new one
|
||||
// the component is the setup panel for the action
|
||||
// NOTE that the "name" is used by the client library,
|
||||
// so if you want to change it, you must change it client lib too
|
||||
|
||||
// Defines which actions are available to configure in the front end.
|
||||
// Unfortunately the "name" property is used as the identifier so please don't
|
||||
// change them.
|
||||
// The client library removes any spaces when processing actions, so they can
|
||||
// be considered as camel case too.
|
||||
// There is technical debt here to sanitize all these and standardise them
|
||||
// across the packages but it's a breaking change to existing apps.
|
||||
export default [
|
||||
{
|
||||
name: "Save Row",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
const dispatch = createEventDispatcher()
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchemaForDatasource(datasource).schema
|
||||
$: schema = getSchemaForDatasource($currentAsset, datasource).schema
|
||||
$: options = Object.keys(schema || {})
|
||||
$: boundValue = getValidValue(value, options)
|
||||
|
||||
|
|
|
@ -27,19 +27,16 @@
|
|||
? tempValue.length
|
||||
: Object.keys(tempValue || {}).length
|
||||
$: dataSource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchemaForDatasource(dataSource)?.schema
|
||||
$: schema = getSchemaForDatasource($currentAsset, dataSource)?.schema
|
||||
$: schemaFields = Object.values(schema || {})
|
||||
$: internalTable = dataSource?.type === "table"
|
||||
|
||||
// Reset value if value is wrong type for the datasource.
|
||||
// Lucene editor needs an array, and simple editor needs an object.
|
||||
$: {
|
||||
if (internalTable && !Array.isArray(value)) {
|
||||
if (!Array.isArray(value)) {
|
||||
tempValue = []
|
||||
dispatch("change", [])
|
||||
} else if (!internalTable && Array.isArray(value)) {
|
||||
tempValue = {}
|
||||
dispatch("change", {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,28 +60,7 @@
|
|||
constaints.
|
||||
{/if}
|
||||
</Body>
|
||||
{#if internalTable}
|
||||
<LuceneFilterBuilder bind:value={tempValue} {schemaFields} />
|
||||
{:else}
|
||||
<div class="fields">
|
||||
<SaveFields
|
||||
parameterFields={Array.isArray(value) ? {} : value}
|
||||
{schemaFields}
|
||||
valueLabel="Equals"
|
||||
on:change={e => (tempValue = e.detail)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<LuceneFilterBuilder bind:value={tempValue} {schemaFields} />
|
||||
</Layout>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<style>
|
||||
.fields {
|
||||
display: grid;
|
||||
column-gap: var(--spacing-l);
|
||||
row-gap: var(--spacing-s);
|
||||
align-items: center;
|
||||
grid-template-columns: auto 1fr auto 1fr auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
component => component._component === "@budibase/standard-components/form"
|
||||
)
|
||||
$: datasource = getDatasourceForProvider($currentAsset, form)
|
||||
$: schema = getSchemaForDatasource(datasource, true).schema
|
||||
$: schema = getSchemaForDatasource($currentAsset, datasource, true).schema
|
||||
$: options = getOptions(schema, type)
|
||||
|
||||
const getOptions = (schema, fieldType) => {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
const dispatch = createEventDispatcher()
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchemaForDatasource(datasource).schema
|
||||
$: schema = getSchemaForDatasource($currentAsset, datasource).schema
|
||||
$: options = Object.keys(schema || {})
|
||||
$: boundValue = getValidOptions(value, options)
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
title: "Theming",
|
||||
href: "/builder/portal/settings/theming",
|
||||
},
|
||||
{
|
||||
title: "Updates",
|
||||
href: "/builder/portal/settings/update",
|
||||
},
|
||||
])
|
||||
} else {
|
||||
menu = menu.concat([
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { auth, organisation } from "stores/portal"
|
||||
import { post } from "builderStore/api"
|
||||
import { post, get } from "builderStore/api"
|
||||
import analytics from "analytics"
|
||||
import { writable } from "svelte/store"
|
||||
import { redirect } from "@roxi/routify"
|
||||
|
@ -130,10 +130,10 @@
|
|||
<Toggle text="" bind:value={$values.analytics} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button disabled={loading} on:click={saveConfig} cta>Save</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
<div>
|
||||
<Button disabled={loading} on:click={saveConfig} cta>Save</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<script>
|
||||
import {
|
||||
Layout,
|
||||
Heading,
|
||||
Body,
|
||||
Button,
|
||||
Divider,
|
||||
Label,
|
||||
Input,
|
||||
Toggle,
|
||||
Dropzone,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { auth, organisation } from "stores/portal"
|
||||
import { post, get } from "builderStore/api"
|
||||
import analytics from "analytics"
|
||||
import { writable } from "svelte/store"
|
||||
import { redirect } from "@roxi/routify"
|
||||
|
||||
// Only admins allowed here
|
||||
$: {
|
||||
if (!$auth.isAdmin) {
|
||||
$redirect("../../portal")
|
||||
}
|
||||
}
|
||||
|
||||
async function updateBudibase() {
|
||||
try {
|
||||
notifications.info("Updating budibase..")
|
||||
const response = await fetch("/v1/update", {
|
||||
headers: {
|
||||
Authorization: "Bearer budibase",
|
||||
},
|
||||
})
|
||||
notifications.success("Your budibase installation is up to date.")
|
||||
} catch (err) {
|
||||
notifications.error(`Error installing budibase update ${err}`)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $auth.isAdmin}
|
||||
<Layout>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="M">Update</Heading>
|
||||
<Body>
|
||||
Keep your budibase installation up to date to take advantage of the
|
||||
latest features, security updates and much more.
|
||||
</Body>
|
||||
</Layout>
|
||||
<Divider size="S" />
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<Button cta on:click={updateBudibase}>Check For Updates</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.fields {
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-m);
|
||||
}
|
||||
.field {
|
||||
display: grid;
|
||||
grid-template-columns: 33% 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -18,13 +18,13 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/string-templates": "^0.9.21",
|
||||
"@budibase/string-templates": "^0.9.27",
|
||||
"regexparam": "^1.3.0",
|
||||
"shortid": "^2.2.15",
|
||||
"svelte-spa-router": "^3.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@budibase/standard-components": "^0.9.21",
|
||||
"@budibase/standard-components": "^0.9.27",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"fs-extra": "^8.1.0",
|
||||
|
|
|
@ -55,13 +55,13 @@
|
|||
}
|
||||
|
||||
// Enriches any string component props using handlebars
|
||||
const updateComponentProps = async (definition, context) => {
|
||||
const updateComponentProps = (definition, context) => {
|
||||
// Record the timestamp so we can reference it after enrichment
|
||||
latestUpdateTime = Date.now()
|
||||
const enrichmentTime = latestUpdateTime
|
||||
|
||||
// Enrich props with context
|
||||
const enrichedProps = await enrichProps(definition, context)
|
||||
const enrichedProps = enrichProps(definition, context)
|
||||
|
||||
// Abandon this update if a newer update has started
|
||||
if (enrichmentTime !== latestUpdateTime) {
|
||||
|
|
|
@ -5,4 +5,5 @@ export const TableNames = {
|
|||
export const ActionTypes = {
|
||||
ValidateForm: "ValidateForm",
|
||||
RefreshDatasource: "RefreshDatasource",
|
||||
SetDataProviderQuery: "SetDataProviderQuery",
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
import { styleable } from "./utils/styleable"
|
||||
import transition from "./utils/transition"
|
||||
import { linkable } from "./utils/linkable"
|
||||
import { getAction } from "./utils/getAction"
|
||||
import Provider from "./components/Provider.svelte"
|
||||
import { ActionTypes } from "./constants"
|
||||
|
||||
|
@ -22,6 +23,7 @@ export default {
|
|||
styleable,
|
||||
transition,
|
||||
linkable,
|
||||
getAction,
|
||||
Provider,
|
||||
ActionTypes,
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export const propsAreSame = (a, b) => {
|
|||
* Enriches component props.
|
||||
* Data bindings are enriched, and button actions are enriched.
|
||||
*/
|
||||
export const enrichProps = async (props, context) => {
|
||||
export const enrichProps = (props, context) => {
|
||||
// Exclude all private props that start with an underscore
|
||||
let validProps = {}
|
||||
Object.entries(props)
|
||||
|
@ -41,7 +41,7 @@ export const enrichProps = async (props, context) => {
|
|||
}
|
||||
|
||||
// Enrich all data bindings in top level props
|
||||
let enrichedProps = await enrichDataBindings(validProps, totalContext)
|
||||
let enrichedProps = enrichDataBindings(validProps, totalContext)
|
||||
|
||||
// Enrich click actions if they exist
|
||||
if (enrichedProps.onClick) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { cloneDeep } from "lodash/fp"
|
||||
import { processString, processObject } from "@budibase/string-templates"
|
||||
import { processString, processObjectSync } from "@budibase/string-templates"
|
||||
|
||||
// Regex to test inputs with to see if they are likely candidates for template strings
|
||||
const looksLikeTemplate = /{{.*}}/
|
||||
|
@ -23,6 +23,6 @@ export const enrichDataBinding = async (input, context) => {
|
|||
* Recursively enriches all props in a props object and returns the new props.
|
||||
* Props are deeply cloned so that no mutation is done to the source object.
|
||||
*/
|
||||
export const enrichDataBindings = async (props, context) => {
|
||||
return await processObject(cloneDeep(props), context)
|
||||
export const enrichDataBindings = (props, context) => {
|
||||
return processObjectSync(cloneDeep(props), context)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { get } from "svelte/store"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
/**
|
||||
* Gets a component action.
|
||||
* @param id The component ID that provides the action
|
||||
* @param type The action type to get
|
||||
* @returns {null|*} The action function
|
||||
*/
|
||||
export const getAction = (id, type) => {
|
||||
if (!id || !type) {
|
||||
return null
|
||||
}
|
||||
const context = getContext("context")
|
||||
if (!context) {
|
||||
return null
|
||||
}
|
||||
return get(context)?.[`${id}_${type}`]
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/electron.js",
|
||||
"repository": {
|
||||
|
@ -55,9 +55,9 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.21",
|
||||
"@budibase/client": "^0.9.21",
|
||||
"@budibase/string-templates": "^0.9.21",
|
||||
"@budibase/auth": "^0.9.27",
|
||||
"@budibase/client": "^0.9.27",
|
||||
"@budibase/string-templates": "^0.9.27",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
"@koa/router": "8.0.0",
|
||||
"@sendgrid/mail": "7.1.1",
|
||||
|
@ -109,7 +109,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.4",
|
||||
"@budibase/standard-components": "^0.9.21",
|
||||
"@budibase/standard-components": "^0.9.27",
|
||||
"@jest/test-sequencer": "^24.8.0",
|
||||
"babel-jest": "^27.0.2",
|
||||
"docker-compose": "^0.23.6",
|
||||
|
|
|
@ -99,12 +99,18 @@ async function createInstance(template) {
|
|||
// replicate the template data to the instance DB
|
||||
// this is currently very hard to test, downloading and importing template files
|
||||
/* istanbul ignore next */
|
||||
let _rev
|
||||
if (template && template.useTemplate === "true") {
|
||||
const { ok } = await db.load(await getTemplateStream(template))
|
||||
if (!ok) {
|
||||
throw "Error loading database dump from template."
|
||||
}
|
||||
var { _rev } = await db.get(DocumentTypes.APP_METADATA)
|
||||
try {
|
||||
const response = await db.get(DocumentTypes.APP_METADATA)
|
||||
_rev = response._rev
|
||||
} catch (err) {
|
||||
_rev = null
|
||||
}
|
||||
} else {
|
||||
// create the users table
|
||||
await db.put(USERS_TABLE_SCHEMA)
|
||||
|
|
|
@ -5,7 +5,7 @@ const { getFullUser } = require("../../utilities/users")
|
|||
|
||||
exports.fetchSelf = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const { userId } = ctx.user
|
||||
let userId = ctx.user.userId || ctx.user._id
|
||||
/* istanbul ignore next */
|
||||
if (!userId) {
|
||||
ctx.body = {}
|
||||
|
|
|
@ -63,10 +63,6 @@ exports.fetch = async ctx => {
|
|||
exports.clientFetch = async ctx => {
|
||||
const routing = await getRoutingStructure(ctx.appId)
|
||||
let roleId = ctx.user.role._id
|
||||
// builder is a special case, always return the full routing structure
|
||||
if (roleId === BUILTIN_ROLE_IDS.BUILDER) {
|
||||
roleId = BUILTIN_ROLE_IDS.ADMIN
|
||||
}
|
||||
const roleIds = await getUserRoleHierarchy(ctx.appId, roleId)
|
||||
for (let topLevel of Object.values(routing.routes)) {
|
||||
for (let subpathKey of Object.keys(topLevel.subpaths)) {
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
|
@ -41,9 +40,9 @@
|
|||
</svelte:head>
|
||||
|
||||
<body id="app">
|
||||
<script src={clientLibPath}>
|
||||
<script type="application/javascript" src={clientLibPath}>
|
||||
</script>
|
||||
<script>
|
||||
<script type="application/javascript">
|
||||
loadBudibase()
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -4,7 +4,6 @@ const {
|
|||
getUserMetadataParams,
|
||||
} = require("../../db/utils")
|
||||
const { InternalTables } = require("../../db/utils")
|
||||
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
||||
const {
|
||||
getGlobalUsers,
|
||||
addAppRoleToUser,
|
||||
|
@ -47,10 +46,6 @@ exports.fetchMetadata = async function (ctx) {
|
|||
exports.updateSelfMetadata = async function (ctx) {
|
||||
// overwrite the ID with current users
|
||||
ctx.request.body._id = ctx.user._id
|
||||
if (ctx.user.builder && ctx.user.builder.global) {
|
||||
// specific case, update self role in global user
|
||||
await addAppRoleToUser(ctx, ctx.appId, BUILTIN_ROLE_IDS.ADMIN)
|
||||
}
|
||||
// make sure no stale rev
|
||||
delete ctx.request.body._rev
|
||||
await exports.updateMetadata(ctx)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Router = require("@koa/router")
|
||||
const { buildAuthMiddleware } = require("@budibase/auth").auth
|
||||
const { buildAuthMiddleware, auditLog } = require("@budibase/auth").auth
|
||||
const currentApp = require("../middleware/currentapp")
|
||||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
|
@ -37,6 +37,7 @@ router
|
|||
})
|
||||
)
|
||||
.use(currentApp)
|
||||
.use(auditLog)
|
||||
|
||||
// error handling middleware
|
||||
router.use(async (ctx, next) => {
|
||||
|
|
|
@ -28,9 +28,7 @@ describe("/routing", () => {
|
|||
it("returns the correct routing for basic user", async () => {
|
||||
workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => {
|
||||
return {
|
||||
roles: {
|
||||
[appId]: BUILTIN_ROLE_IDS.BASIC,
|
||||
}
|
||||
roleId: BUILTIN_ROLE_IDS.BASIC,
|
||||
}
|
||||
})
|
||||
const res = await request
|
||||
|
|
|
@ -2,6 +2,7 @@ const rowController = require("../../../controllers/row")
|
|||
const appController = require("../../../controllers/application")
|
||||
const CouchDB = require("../../../../db")
|
||||
const { AppStatus } = require("../../../../db/utils")
|
||||
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
||||
|
||||
function Request(appId, params) {
|
||||
this.appId = appId
|
||||
|
@ -77,11 +78,17 @@ exports.checkPermissionsEndpoint = async ({
|
|||
.set(passHeader)
|
||||
.expect(200)
|
||||
|
||||
user = await config.createUser("fail@budibase.com", password, failRole)
|
||||
const failHeader = await config.login("fail@budibase.com", password, {
|
||||
roleId: failRole,
|
||||
userId: user.globalId,
|
||||
})
|
||||
let failHeader
|
||||
if (failRole === BUILTIN_ROLE_IDS.PUBLIC) {
|
||||
failHeader = config.publicHeaders()
|
||||
} else {
|
||||
user = await config.createUser("fail@budibase.com", password, failRole)
|
||||
failHeader = await config.login("fail@budibase.com", password, {
|
||||
roleId: failRole,
|
||||
userId: user.globalId,
|
||||
builder: false,
|
||||
})
|
||||
}
|
||||
|
||||
await exports
|
||||
.createRequest(config.request, method, url, body)
|
||||
|
|
|
@ -5,7 +5,7 @@ require("@budibase/auth").init(CouchDB)
|
|||
const Koa = require("koa")
|
||||
const destroyable = require("server-destroy")
|
||||
const koaBody = require("koa-body")
|
||||
const logger = require("koa-pino-logger")
|
||||
const pino = require("koa-pino-logger")
|
||||
const http = require("http")
|
||||
const api = require("./api")
|
||||
const eventEmitter = require("./events")
|
||||
|
@ -29,7 +29,7 @@ app.use(
|
|||
)
|
||||
|
||||
app.use(
|
||||
logger({
|
||||
pino({
|
||||
prettyPrint: {
|
||||
levelFirst: true,
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@ const createRow = require("./steps/createRow")
|
|||
const updateRow = require("./steps/updateRow")
|
||||
const deleteRow = require("./steps/deleteRow")
|
||||
const executeScript = require("./steps/executeScript")
|
||||
const bash = require("./steps/bash")
|
||||
const executeQuery = require("./steps/executeQuery")
|
||||
const outgoingWebhook = require("./steps/outgoingWebhook")
|
||||
const env = require("../environment")
|
||||
|
@ -21,6 +22,7 @@ const BUILTIN_ACTIONS = {
|
|||
DELETE_ROW: deleteRow.run,
|
||||
OUTGOING_WEBHOOK: outgoingWebhook.run,
|
||||
EXECUTE_SCRIPT: executeScript.run,
|
||||
EXECUTE_BASH: bash.run,
|
||||
EXECUTE_QUERY: executeQuery.run,
|
||||
}
|
||||
const BUILTIN_DEFINITIONS = {
|
||||
|
@ -32,6 +34,7 @@ const BUILTIN_DEFINITIONS = {
|
|||
OUTGOING_WEBHOOK: outgoingWebhook.definition,
|
||||
EXECUTE_SCRIPT: executeScript.definition,
|
||||
EXECUTE_QUERY: executeQuery.definition,
|
||||
EXECUTE_BASH: bash.definition,
|
||||
}
|
||||
|
||||
let MANIFEST = null
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
const { execSync } = require("child_process")
|
||||
const { processStringSync } = require("@budibase/string-templates")
|
||||
|
||||
module.exports.definition = {
|
||||
name: "Bash Scripting",
|
||||
tagline: "Execute a bash command",
|
||||
icon: "ri-terminal-box-line",
|
||||
description: "Run a bash script",
|
||||
type: "ACTION",
|
||||
stepId: "EXECUTE_BASH",
|
||||
inputs: {},
|
||||
schema: {
|
||||
inputs: {
|
||||
properties: {
|
||||
code: {
|
||||
type: "string",
|
||||
customType: "code",
|
||||
title: "Code",
|
||||
},
|
||||
},
|
||||
required: ["code"],
|
||||
},
|
||||
outputs: {
|
||||
properties: {
|
||||
stdout: {
|
||||
type: "string",
|
||||
description: "Standard output of your bash command or script.",
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["stdout"],
|
||||
},
|
||||
}
|
||||
|
||||
module.exports.run = async function ({ inputs, context }) {
|
||||
if (inputs.code == null) {
|
||||
return {
|
||||
stdout: "Budibase bash automation failed: Invalid inputs",
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const command = processStringSync(inputs.code, context)
|
||||
|
||||
let stdout
|
||||
try {
|
||||
stdout = execSync(command, { timeout: 500 })
|
||||
} catch (err) {
|
||||
stdout = err.message
|
||||
}
|
||||
|
||||
return {
|
||||
stdout,
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
return {
|
||||
success: false,
|
||||
response: err,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
const scriptController = require("../../api/controllers/script")
|
||||
|
||||
module.exports.definition = {
|
||||
name: "Scripting",
|
||||
name: "JS Scripting",
|
||||
tagline: "Execute JavaScript Code",
|
||||
icon: "ri-terminal-box-line",
|
||||
description: "Run a piece of JavaScript code in your automation",
|
||||
|
|
|
@ -33,7 +33,7 @@ module.exports = async (ctx, next) => {
|
|||
updateCookie = true
|
||||
appId = requestAppId
|
||||
// retrieving global user gets the right role
|
||||
roleId = globalUser.roleId
|
||||
roleId = globalUser.roleId || BUILTIN_ROLE_IDS.PUBLIC
|
||||
} else if (appCookie != null) {
|
||||
appId = appCookie.appId
|
||||
roleId = appCookie.roleId || BUILTIN_ROLE_IDS.PUBLIC
|
||||
|
|
|
@ -101,7 +101,7 @@ class TestConfiguration {
|
|||
userId: GLOBAL_USER_ID,
|
||||
}
|
||||
const app = {
|
||||
roleId: BUILTIN_ROLE_IDS.BUILDER,
|
||||
roleId: BUILTIN_ROLE_IDS.ADMIN,
|
||||
appId: this.appId,
|
||||
}
|
||||
const authToken = jwt.sign(auth, env.JWT_SECRET)
|
||||
|
@ -306,12 +306,9 @@ class TestConfiguration {
|
|||
return await this._req(config, null, controllers.layout.save)
|
||||
}
|
||||
|
||||
async createUser(roleId = BUILTIN_ROLE_IDS.POWER) {
|
||||
async createUser() {
|
||||
const globalId = `us_${Math.random()}`
|
||||
const resp = await this.globalUser(
|
||||
globalId,
|
||||
roleId === BUILTIN_ROLE_IDS.BUILDER
|
||||
)
|
||||
const resp = await this.globalUser(globalId)
|
||||
return {
|
||||
...resp,
|
||||
globalId,
|
||||
|
@ -319,7 +316,6 @@ class TestConfiguration {
|
|||
}
|
||||
|
||||
async login(email, password, { roleId, userId, builder } = {}) {
|
||||
roleId = !roleId ? BUILTIN_ROLE_IDS.BUILDER : roleId
|
||||
userId = !userId ? `us_uuid1` : userId
|
||||
if (!this.request) {
|
||||
throw "Server has not been opened, cannot login."
|
||||
|
|
|
@ -30,5 +30,7 @@ exports.uploadClientLibrary = async appId => {
|
|||
const sourcepath = require.resolve("@budibase/client")
|
||||
const destPath = join(appId, "budibase-client.js")
|
||||
|
||||
await streamUpload(BUCKET_NAME, destPath, fs.createReadStream(sourcepath))
|
||||
await streamUpload(BUCKET_NAME, destPath, fs.createReadStream(sourcepath), {
|
||||
ContentType: "application/javascript",
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,12 +12,8 @@ exports.init = async () => {
|
|||
}
|
||||
|
||||
exports.shutdown = async () => {
|
||||
if (devAppClient != null) {
|
||||
await devAppClient.finish()
|
||||
}
|
||||
if (debounceClient != null) {
|
||||
await debounceClient.finish()
|
||||
}
|
||||
if (devAppClient) await devAppClient.finish()
|
||||
if (debounceClient) await debounceClient.finish()
|
||||
}
|
||||
|
||||
exports.doesUserHaveLock = async (devAppId, user) => {
|
||||
|
|
|
@ -169,9 +169,14 @@ exports.inputProcessing = (user = {}, table, row) => {
|
|||
let clonedRow = cloneDeep(row)
|
||||
// need to copy the table so it can be differenced on way out
|
||||
const copiedTable = cloneDeep(table)
|
||||
const dontCleanseKeys = ["type", "_id", "_rev", "tableId"]
|
||||
for (let [key, value] of Object.entries(clonedRow)) {
|
||||
const field = table.schema[key]
|
||||
// cleanse fields that aren't in the schema
|
||||
if (!field) {
|
||||
if (dontCleanseKeys.indexOf(key) === -1) {
|
||||
delete clonedRow[key]
|
||||
}
|
||||
continue
|
||||
}
|
||||
clonedRow[key] = exports.coerce(value, field.type)
|
||||
|
|
|
@ -9,19 +9,26 @@ function getAppRole(appId, user) {
|
|||
if (!user.roles) {
|
||||
return user
|
||||
}
|
||||
// always use the deployed app
|
||||
user.roleId = user.roles[getDeployedAppID(appId)]
|
||||
if (!user.roleId) {
|
||||
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
||||
if (user.builder && user.builder.global) {
|
||||
user.roleId = BUILTIN_ROLE_IDS.ADMIN
|
||||
} else {
|
||||
// always use the deployed app
|
||||
user.roleId = user.roles[getDeployedAppID(appId)]
|
||||
if (!user.roleId) {
|
||||
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
||||
}
|
||||
}
|
||||
delete user.roles
|
||||
return user
|
||||
}
|
||||
|
||||
function request(ctx, request) {
|
||||
function request(ctx, request, noApiKey) {
|
||||
if (!request.headers) {
|
||||
request.headers = {}
|
||||
}
|
||||
if (!noApiKey) {
|
||||
request.headers["x-budibase-api-key"] = env.INTERNAL_API_KEY
|
||||
}
|
||||
if (request.body && Object.keys(request.body).length > 0) {
|
||||
request.headers["Content-Type"] = "application/json"
|
||||
request.body =
|
||||
|
@ -44,9 +51,6 @@ exports.sendSmtpEmail = async (to, from, subject, contents) => {
|
|||
checkSlashesInUrl(env.WORKER_URL + `/api/admin/email/send`),
|
||||
request(null, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-budibase-api-key": env.INTERNAL_API_KEY,
|
||||
},
|
||||
body: {
|
||||
email: to,
|
||||
from,
|
||||
|
@ -86,16 +90,6 @@ exports.getDeployedApps = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.deleteGlobalUser = async (ctx, globalId) => {
|
||||
const endpoint = `/api/admin/users/${globalId}`
|
||||
const reqCfg = { method: "DELETE" }
|
||||
const response = await fetch(
|
||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||
request(ctx, reqCfg)
|
||||
)
|
||||
return response.json()
|
||||
}
|
||||
|
||||
exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
|
||||
const endpoint = globalId
|
||||
? `/api/admin/users/${globalId}`
|
||||
|
@ -121,7 +115,8 @@ exports.getGlobalSelf = async (ctx, appId = null) => {
|
|||
const endpoint = `/api/admin/users/self`
|
||||
const response = await fetch(
|
||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||
request(ctx, { method: "GET" })
|
||||
// we don't want to use API key when getting self
|
||||
request(ctx, { method: "GET" }, true)
|
||||
)
|
||||
if (response.status !== 200) {
|
||||
ctx.throw(400, "Unable to get self globally.")
|
||||
|
@ -172,9 +167,6 @@ exports.removeAppFromUserRoles = async appId => {
|
|||
checkSlashesInUrl(env.WORKER_URL + `/api/admin/roles/${deployedAppId}`),
|
||||
request(null, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"x-budibase-api-key": env.INTERNAL_API_KEY,
|
||||
},
|
||||
})
|
||||
)
|
||||
if (response.status !== 200) {
|
||||
|
|
|
@ -1505,5 +1505,38 @@
|
|||
"context": {
|
||||
"type": "schema"
|
||||
}
|
||||
},
|
||||
"daterangepicker": {
|
||||
"name": "Date Range",
|
||||
"icon": "Date",
|
||||
"styleable": true,
|
||||
"hasChildren": false,
|
||||
"info": "Your data provider will be automatically filtered to the given date range.",
|
||||
"settings": [
|
||||
{
|
||||
"type": "dataProvider",
|
||||
"label": "Provider",
|
||||
"key": "dataProvider"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"label": "Date field",
|
||||
"key": "field"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Default range",
|
||||
"key": "defaultValue",
|
||||
"options": [
|
||||
"Last 1 day",
|
||||
"Last 7 days",
|
||||
"Last 30 days",
|
||||
"Last 3 months",
|
||||
"Last 6 months",
|
||||
"Last 1 year"
|
||||
],
|
||||
"defaultValue": "Last 30 days"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,14 +29,15 @@
|
|||
"keywords": [
|
||||
"svelte"
|
||||
],
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"license": "MIT",
|
||||
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.21",
|
||||
"@budibase/bbui": "^0.9.27",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
"apexcharts": "^3.22.1",
|
||||
"dayjs": "^1.10.5",
|
||||
"svelte-apexcharts": "^1.0.2",
|
||||
"svelte-flatpickr": "^3.1.0"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
||||
import {
|
||||
buildLuceneQuery,
|
||||
luceneQuery,
|
||||
luceneSort,
|
||||
luceneLimit,
|
||||
} from "./lucene"
|
||||
|
||||
export let dataSource
|
||||
export let filter
|
||||
|
@ -25,9 +31,11 @@
|
|||
let schema = {}
|
||||
let bookmarks = [null]
|
||||
let pageNumber = 0
|
||||
let query = null
|
||||
|
||||
$: query = buildLuceneQuery(filter)
|
||||
$: internalTable = dataSource?.type === "table"
|
||||
$: query = internalTable ? buildLuceneQuery(filter) : null
|
||||
$: nestedProvider = dataSource?.type === "provider"
|
||||
$: hasNextPage = bookmarks[pageNumber + 1] != null
|
||||
$: hasPrevPage = pageNumber > 0
|
||||
$: getSchema(dataSource)
|
||||
|
@ -48,22 +56,38 @@
|
|||
}
|
||||
}
|
||||
$: {
|
||||
// Sort and limit rows in memory when we aren't searching internal tables
|
||||
if (internalTable) {
|
||||
// Internal tables are already processed server-side
|
||||
rows = allRows
|
||||
} else {
|
||||
const sortedRows = sortRows(allRows, sortColumn, sortOrder)
|
||||
rows = limitRows(sortedRows, limit)
|
||||
// For anything else we use client-side implementations to filter, sort
|
||||
// and limit
|
||||
const filtered = luceneQuery(allRows, query)
|
||||
const sorted = luceneSort(filtered, sortColumn, sortOrder, sortType)
|
||||
rows = luceneLimit(sorted, limit)
|
||||
}
|
||||
}
|
||||
$: actions = [
|
||||
{
|
||||
type: ActionTypes.RefreshDatasource,
|
||||
callback: () => fetchData(dataSource),
|
||||
callback: () => refresh(),
|
||||
metadata: { dataSource },
|
||||
},
|
||||
{
|
||||
type: ActionTypes.SetDataProviderQuery,
|
||||
callback: newQuery => (query = newQuery),
|
||||
},
|
||||
]
|
||||
$: dataContext = { rows, schema, rowsLength: rows.length }
|
||||
$: dataContext = {
|
||||
rows,
|
||||
schema,
|
||||
rowsLength: rows.length,
|
||||
|
||||
// Undocumented properties. These aren't supposed to be used in builder
|
||||
// bindings, but are used internally by other components
|
||||
id: $component?.id,
|
||||
state: { query },
|
||||
}
|
||||
|
||||
const getSortType = (schema, sortColumn) => {
|
||||
if (!schema || !sortColumn || !schema[sortColumn]) {
|
||||
|
@ -73,36 +97,18 @@
|
|||
return type === "number" ? "number" : "string"
|
||||
}
|
||||
|
||||
const buildLuceneQuery = filter => {
|
||||
let query = {
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
const refresh = async () => {
|
||||
if (schemaLoaded && !nestedProvider) {
|
||||
fetchData(
|
||||
dataSource,
|
||||
query,
|
||||
limit,
|
||||
sortColumn,
|
||||
sortOrder,
|
||||
sortType,
|
||||
paginate
|
||||
)
|
||||
}
|
||||
if (Array.isArray(filter)) {
|
||||
filter.forEach(({ operator, field, type, value }) => {
|
||||
if (operator.startsWith("range")) {
|
||||
if (!query.range[field]) {
|
||||
query.range[field] = {
|
||||
low: type === "number" ? Number.MIN_SAFE_INTEGER : "0000",
|
||||
high: type === "number" ? Number.MAX_SAFE_INTEGER : "9999",
|
||||
}
|
||||
}
|
||||
if (operator === "rangeLow") {
|
||||
query.range[field].low = value
|
||||
} else if (operator === "rangeHigh") {
|
||||
query.range[field].high = value
|
||||
}
|
||||
} else if (query[operator]) {
|
||||
query[operator][field] = value
|
||||
}
|
||||
})
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
const fetchData = async (
|
||||
|
@ -116,6 +122,7 @@
|
|||
) => {
|
||||
loading = true
|
||||
if (dataSource?.type === "table") {
|
||||
// For internal tables we use server-side processing
|
||||
const res = await API.searchTable({
|
||||
tableId: dataSource.tableId,
|
||||
query,
|
||||
|
@ -132,55 +139,27 @@
|
|||
} else {
|
||||
bookmarks = [null]
|
||||
}
|
||||
} else if (dataSource?.type === "provider") {
|
||||
// For providers referencing another provider, just use the rows it
|
||||
// provides
|
||||
allRows = dataSource?.value?.rows ?? []
|
||||
} else {
|
||||
const rows = await API.fetchDatasource(dataSource)
|
||||
allRows = inMemoryFilterRows(rows, filter)
|
||||
// For other data sources like queries or views, fetch all rows from the
|
||||
// server
|
||||
allRows = await API.fetchDatasource(dataSource)
|
||||
}
|
||||
loading = false
|
||||
loaded = true
|
||||
}
|
||||
|
||||
const inMemoryFilterRows = (rows, filter) => {
|
||||
let filteredData = [...rows]
|
||||
Object.entries(filter || {}).forEach(([field, value]) => {
|
||||
if (value != null && value !== "") {
|
||||
filteredData = filteredData.filter(row => {
|
||||
return row[field] === value
|
||||
})
|
||||
}
|
||||
})
|
||||
return filteredData
|
||||
}
|
||||
|
||||
const sortRows = (rows, sortColumn, sortOrder) => {
|
||||
if (!sortColumn || !sortOrder) {
|
||||
return rows
|
||||
}
|
||||
return rows.slice().sort((a, b) => {
|
||||
const colA = a[sortColumn]
|
||||
const colB = b[sortColumn]
|
||||
if (sortOrder === "Descending") {
|
||||
return colA > colB ? -1 : 1
|
||||
} else {
|
||||
return colA > colB ? 1 : -1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const limitRows = (rows, limit) => {
|
||||
const numLimit = parseFloat(limit)
|
||||
if (isNaN(numLimit)) {
|
||||
return rows
|
||||
}
|
||||
return rows.slice(0, numLimit)
|
||||
}
|
||||
|
||||
const getSchema = async dataSource => {
|
||||
if (dataSource?.schema) {
|
||||
schema = dataSource.schema
|
||||
} else if (dataSource?.tableId) {
|
||||
const definition = await API.fetchTableDefinition(dataSource.tableId)
|
||||
schema = definition?.schema ?? {}
|
||||
} else if (dataSource?.type === "provider") {
|
||||
schema = dataSource.value?.schema ?? {}
|
||||
} else {
|
||||
schema = {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<script>
|
||||
import { Select } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
import dayjs from "dayjs"
|
||||
import utc from "dayjs/plugin/utc"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
dayjs.extend(utc)
|
||||
|
||||
export let dataProvider
|
||||
export let field
|
||||
export let defaultValue
|
||||
|
||||
const dataContext = getContext("context")
|
||||
const component = getContext("component")
|
||||
const { styleable, builderStore, ActionTypes, getAction } = getContext("sdk")
|
||||
|
||||
const setQuery = getAction(dataProvider?.id, ActionTypes.SetDataProviderQuery)
|
||||
const options = [
|
||||
"Last 1 day",
|
||||
"Last 7 days",
|
||||
"Last 30 days",
|
||||
"Last 3 months",
|
||||
"Last 6 months",
|
||||
"Last 1 year",
|
||||
]
|
||||
let value = options.includes(defaultValue) ? defaultValue : "Last 30 days"
|
||||
|
||||
const updateDateRange = option => {
|
||||
const query = dataProvider?.state?.query
|
||||
if (!query || !setQuery) {
|
||||
return
|
||||
}
|
||||
|
||||
value = option
|
||||
let low = dayjs.utc().subtract(1, "year")
|
||||
let high = dayjs.utc().add(1, "day")
|
||||
|
||||
if (option === "Last 1 day") {
|
||||
low = dayjs.utc().subtract(1, "day")
|
||||
} else if (option === "Last 7 days") {
|
||||
low = dayjs.utc().subtract(7, "days")
|
||||
} else if (option === "Last 30 days") {
|
||||
low = dayjs.utc().subtract(30, "days")
|
||||
} else if (option === "Last 3 months") {
|
||||
low = dayjs.utc().subtract(3, "months")
|
||||
} else if (option === "Last 6 months") {
|
||||
low = dayjs.utc().subtract(6, "months")
|
||||
}
|
||||
|
||||
// Update data provider query with the new filter
|
||||
setQuery({
|
||||
...query,
|
||||
range: {
|
||||
...query.range,
|
||||
[field]: {
|
||||
high: high.format(),
|
||||
low: low.format(),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Update the range on mount to the initial value
|
||||
onMount(() => {
|
||||
updateDateRange(value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<div use:styleable={$component.styles}>
|
||||
<Select
|
||||
placeholder={null}
|
||||
{options}
|
||||
{value}
|
||||
on:change={e => updateDateRange(e.detail)}
|
||||
/>
|
||||
</div>
|
|
@ -22,6 +22,7 @@
|
|||
>
|
||||
{#if fieldState}
|
||||
<CoreTextField
|
||||
updateOnChange={false}
|
||||
value={$fieldState.value}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
disabled={$fieldState.disabled}
|
||||
|
|
|
@ -27,6 +27,7 @@ export { default as cardhorizontal } from "./CardHorizontal.svelte"
|
|||
export { default as cardstat } from "./CardStat.svelte"
|
||||
export { default as icon } from "./Icon.svelte"
|
||||
export { default as backgroundimage } from "./BackgroundImage.svelte"
|
||||
export { default as daterangepicker } from "./DateRangePicker.svelte"
|
||||
export * from "./charts"
|
||||
export * from "./forms"
|
||||
export * from "./table"
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* Builds a lucene JSON query from the filter structure generated in the builder
|
||||
* @param filter the builder filter structure
|
||||
*/
|
||||
export const buildLuceneQuery = filter => {
|
||||
let query = {
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
}
|
||||
if (Array.isArray(filter)) {
|
||||
filter.forEach(({ operator, field, type, value }) => {
|
||||
if (operator.startsWith("range")) {
|
||||
if (!query.range[field]) {
|
||||
query.range[field] = {
|
||||
low:
|
||||
type === "number"
|
||||
? Number.MIN_SAFE_INTEGER
|
||||
: "0000-00-00T00:00:00.000Z",
|
||||
high:
|
||||
type === "number"
|
||||
? Number.MAX_SAFE_INTEGER
|
||||
: "9999-00-00T00:00:00.000Z",
|
||||
}
|
||||
}
|
||||
if (operator === "rangeLow" && value != null && value !== "") {
|
||||
query.range[field].low = value
|
||||
} else if (operator === "rangeHigh" && value != null && value !== "") {
|
||||
query.range[field].high = value
|
||||
}
|
||||
} else if (query[operator]) {
|
||||
query[operator][field] = value
|
||||
}
|
||||
})
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a client-side lucene search on an array of data
|
||||
* @param docs the data
|
||||
* @param query the JSON lucene query
|
||||
*/
|
||||
export const luceneQuery = (docs, query) => {
|
||||
if (!query) {
|
||||
return docs
|
||||
}
|
||||
|
||||
// Iterates over a set of filters and evaluates a fail function against a doc
|
||||
const match = (type, failFn) => doc => {
|
||||
const filters = Object.entries(query[type] || {})
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
if (failFn(filters[i][0], filters[i][1], doc)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Process a string match (fails if the value does not start with the string)
|
||||
const stringMatch = match("string", (key, value, doc) => {
|
||||
return !doc[key] || !doc[key].startsWith(value)
|
||||
})
|
||||
|
||||
// Process a range match
|
||||
const rangeMatch = match("range", (key, value, doc) => {
|
||||
return !doc[key] || doc[key] < value.low || doc[key] > value.high
|
||||
})
|
||||
|
||||
// Process an equal match (fails if the value is different)
|
||||
const equalMatch = match("equal", (key, value, doc) => {
|
||||
return doc[key] !== value
|
||||
})
|
||||
|
||||
// Process a not-equal match (fails if the value is the same)
|
||||
const notEqualMatch = match("notEqual", (key, value, doc) => {
|
||||
return doc[key] === value
|
||||
})
|
||||
|
||||
// Process an empty match (fails if the value is not empty)
|
||||
const emptyMatch = match("empty", (key, value, doc) => {
|
||||
return doc[key] != null && doc[key] !== ""
|
||||
})
|
||||
|
||||
// Process a not-empty match (fails is the value is empty)
|
||||
const notEmptyMatch = match("notEmpty", (key, value, doc) => {
|
||||
return doc[key] == null || doc[key] === ""
|
||||
})
|
||||
|
||||
// Match a document against all criteria
|
||||
const docMatch = doc => {
|
||||
return (
|
||||
stringMatch(doc) &&
|
||||
rangeMatch(doc) &&
|
||||
equalMatch(doc) &&
|
||||
notEqualMatch(doc) &&
|
||||
emptyMatch(doc) &&
|
||||
notEmptyMatch(doc)
|
||||
)
|
||||
}
|
||||
|
||||
// Process all docs
|
||||
return docs.filter(docMatch)
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a client-side sort from the equivalent server-side lucene sort
|
||||
* parameters.
|
||||
* @param docs the data
|
||||
* @param sort the sort column
|
||||
* @param sortOrder the sort order ("ascending" or "descending")
|
||||
* @param sortType the type of sort ("string" or "number")
|
||||
*/
|
||||
export const luceneSort = (docs, sort, sortOrder, sortType = "string") => {
|
||||
if (!sort || !sortOrder || !sortType) {
|
||||
return docs
|
||||
}
|
||||
const parse = sortType === "string" ? x => `${x}` : x => parseFloat(x)
|
||||
return docs.slice().sort((a, b) => {
|
||||
const colA = parse(a[sort])
|
||||
const colB = parse(b[sort])
|
||||
if (sortOrder === "Descending") {
|
||||
return colA > colB ? -1 : 1
|
||||
} else {
|
||||
return colA > colB ? 1 : -1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the specified docs to the specified number of rows from the equivalent
|
||||
* server-side lucene limit parameters.
|
||||
* @param docs the data
|
||||
* @param limit the number of docs to limit to
|
||||
*/
|
||||
export const luceneLimit = (docs, limit) => {
|
||||
const numLimit = parseFloat(limit)
|
||||
if (isNaN(numLimit)) {
|
||||
return docs
|
||||
}
|
||||
return docs.slice(0, numLimit)
|
||||
}
|
|
@ -2,6 +2,59 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@adobe/spectrum-css-workflow-icons@^1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4"
|
||||
integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w==
|
||||
|
||||
"@budibase/bbui@^0.9.12":
|
||||
version "0.9.16"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.16.tgz#6cf454790d3e8d776d4d642379958a56260b0840"
|
||||
integrity sha512-8hV4Vj3h3clzLclNTvVxPdOK9f02xTIcXA/lW1QPD9HZLOUxDogphujpDpb+E0/NevPlPYMHaX68kVtefNL5Jw==
|
||||
dependencies:
|
||||
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
|
||||
"@spectrum-css/actionbutton" "^1.0.1"
|
||||
"@spectrum-css/actiongroup" "^1.0.1"
|
||||
"@spectrum-css/avatar" "^3.0.2"
|
||||
"@spectrum-css/button" "^3.0.1"
|
||||
"@spectrum-css/buttongroup" "^3.0.2"
|
||||
"@spectrum-css/checkbox" "^3.0.2"
|
||||
"@spectrum-css/dialog" "^3.0.1"
|
||||
"@spectrum-css/divider" "^1.0.1"
|
||||
"@spectrum-css/dropzone" "^3.0.2"
|
||||
"@spectrum-css/fieldgroup" "^3.0.2"
|
||||
"@spectrum-css/fieldlabel" "^3.0.1"
|
||||
"@spectrum-css/icon" "^3.0.1"
|
||||
"@spectrum-css/illustratedmessage" "^3.0.2"
|
||||
"@spectrum-css/inputgroup" "^3.0.2"
|
||||
"@spectrum-css/label" "^2.0.10"
|
||||
"@spectrum-css/link" "^3.1.1"
|
||||
"@spectrum-css/menu" "^3.0.1"
|
||||
"@spectrum-css/modal" "^3.0.1"
|
||||
"@spectrum-css/pagination" "^3.0.3"
|
||||
"@spectrum-css/picker" "^1.0.1"
|
||||
"@spectrum-css/popover" "^3.0.1"
|
||||
"@spectrum-css/progressbar" "^1.0.2"
|
||||
"@spectrum-css/progresscircle" "^1.0.2"
|
||||
"@spectrum-css/radio" "^3.0.2"
|
||||
"@spectrum-css/search" "^3.0.2"
|
||||
"@spectrum-css/sidenav" "^3.0.2"
|
||||
"@spectrum-css/statuslight" "^3.0.2"
|
||||
"@spectrum-css/switch" "^1.0.2"
|
||||
"@spectrum-css/table" "^3.0.1"
|
||||
"@spectrum-css/tabs" "^3.0.1"
|
||||
"@spectrum-css/tags" "^3.0.2"
|
||||
"@spectrum-css/textfield" "^3.0.1"
|
||||
"@spectrum-css/toast" "^3.0.1"
|
||||
"@spectrum-css/tooltip" "^3.0.3"
|
||||
"@spectrum-css/treeview" "^3.0.2"
|
||||
"@spectrum-css/typography" "^3.0.1"
|
||||
"@spectrum-css/underlay" "^2.0.9"
|
||||
"@spectrum-css/vars" "^3.0.1"
|
||||
dayjs "^1.10.4"
|
||||
svelte-flatpickr "^3.1.0"
|
||||
svelte-portal "^1.0.0"
|
||||
|
||||
"@rollup/pluginutils@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.0.tgz#0dcc61c780e39257554feb7f77207dceca13c838"
|
||||
|
@ -10,6 +63,98 @@
|
|||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@spectrum-css/actionbutton@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.3.tgz#8f7342a69b303c5acdcfa0a59f5e9267b9f3cb30"
|
||||
integrity sha512-P9qoCPSiZ1SB6ZYqK5hub0vGty00YYqonQE0KTjtb1i+T1nYR/87vWqVPERx9j63uhgZncjwFYaThTvRqye7eQ==
|
||||
|
||||
"@spectrum-css/actiongroup@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.3.tgz#4713ce65e6f5c72c404a7b638fbc3b4fd7e3874f"
|
||||
integrity sha512-NlB9Q4ZlWixXxymoPIYG6g2hkwAGKFodHWPFfxHD8ddkjXWRB9G2akUP7cfsJ4DcYn4VisUORCOYQwqDiSmboQ==
|
||||
|
||||
"@spectrum-css/avatar@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95"
|
||||
integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ==
|
||||
|
||||
"@spectrum-css/button@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84"
|
||||
integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg==
|
||||
|
||||
"@spectrum-css/buttongroup@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.3.tgz#719d868845ac9d2c4f939c1b9f6044507902d5aa"
|
||||
integrity sha512-eXl8U4QWMWXqyTu654FdQdEGnmczgOYlpIFSHyCMVjhtPqZp2xwnLFiGh6LKw+bLio6eeOZ0L+vpk1GcoYqgkw==
|
||||
|
||||
"@spectrum-css/checkbox@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.3.tgz#8577067fc8b97e4609f92bd242364937a533a7bb"
|
||||
integrity sha512-QVG9uMHq+lh70Dh6mDNnY+vEvNz2p7VC6xgLfDYfijp2qeiqYPq72fQK6p/SiyqPk96ZACzNRwgeROU6Xf6Wgg==
|
||||
|
||||
"@spectrum-css/dialog@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.3.tgz#7715a4ea435e753afb623d99ca5917ed1bcd6f34"
|
||||
integrity sha512-AhmKgfRIVyTe3ABiJ8lLUQL34VB/H6fN16na2LlbDRJvyRMzkdN1Xf2i6U3f4OMd3qQ8Gm5xat4BvMxIQPBAUQ==
|
||||
|
||||
"@spectrum-css/divider@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385"
|
||||
integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA==
|
||||
dependencies:
|
||||
"@spectrum-css/vars" "^3.0.2"
|
||||
|
||||
"@spectrum-css/dropzone@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.3.tgz#aee71697a2c195947599d7541b858c3c198741dc"
|
||||
integrity sha512-ujrswdtB6bHigklyHsm6zomFd6rUnKJ3xVVRjroVF4+ouK4DxK5tX0iVd0EW6AOfOjx4Cc28uyFot3fpxp+MQw==
|
||||
|
||||
"@spectrum-css/fieldgroup@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.3.tgz#85d85da048d08200f25ceab378026dd2b11e0bb2"
|
||||
integrity sha512-wXUXTXN1CPnR7M4Ltd+3uh7BfcNGUV1+Xe0/h0tCpq/j+S2Sd4xo7/pUMdU19sIDrAAtpEFp1tt+nouHcU5HGQ==
|
||||
|
||||
"@spectrum-css/fieldlabel@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449"
|
||||
integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ==
|
||||
|
||||
"@spectrum-css/icon@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.3.tgz#5c612822380927087aebd526855d82ed2c3e2cba"
|
||||
integrity sha512-hyloKOejPCXhP3MBNsm3SjR9j8xT1R1S19p32KW/0Qhj+VMUtfyEPmevyFptpn7wcovQccdl/vZVIVDuML/imw==
|
||||
|
||||
"@spectrum-css/illustratedmessage@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0"
|
||||
integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA==
|
||||
|
||||
"@spectrum-css/inputgroup@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.3.tgz#00c9a370ddc2c55cf0f37dd6069faa9501fd7eb5"
|
||||
integrity sha512-FqRJTiLL7jiGfzDVXWUGVLqHryJjCcqQIrqAi+Tq0oenapzsBe2qc/zIrKgh2wtMI+NTIBLXTECvij3L1HlqAg==
|
||||
|
||||
"@spectrum-css/label@^2.0.10":
|
||||
version "2.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001"
|
||||
integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ==
|
||||
|
||||
"@spectrum-css/link@^3.1.1":
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.3.tgz#b0e560a7e0acdb4a2b329b6669696aa3438f5993"
|
||||
integrity sha512-8Pmy5d73MwKcATTPaj+fSrZYnIw7GmfX40AvpC1xx5LauOxsbUb4AVNp1kn2H8rrOBmxF7czyhoBBhEiv66QUg==
|
||||
|
||||
"@spectrum-css/menu@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.3.tgz#46a9b221bb5f470a2f8a934bdfd512d84d2fdc4d"
|
||||
integrity sha512-qKA9J/MrikNKIpCEHsAazG2vY3im5tjGCmo6p9Pdnu8/aQMsiuZDHZayukeCttJUZkrb9guDVL9OIHlK5RZvcQ==
|
||||
|
||||
"@spectrum-css/modal@^3.0.1":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.2.tgz#58b6621cab65f90788d310374f40df1f7090473f"
|
||||
integrity sha512-YnIivJhoaao7Otu+HV7sgebPyFbO6sd/oMvTN/Rb2wwgnaMnIIuIRdGandSrcgotN2uNgs+P0knG6mv/xA1/dg==
|
||||
|
||||
"@spectrum-css/page@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.1.tgz#5e1c3dd5b1a1ee591f9d636b75f03665f542d846"
|
||||
|
@ -17,11 +162,111 @@
|
|||
dependencies:
|
||||
"@spectrum-css/vars" "^3.0.1"
|
||||
|
||||
"@spectrum-css/pagination@^3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65"
|
||||
integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw==
|
||||
|
||||
"@spectrum-css/picker@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.3.tgz#21379bcf8ae94277deeb6ad65dcd9e2bbfacb487"
|
||||
integrity sha512-oHLGxBx5BwVCSGo7/T1C9PTHX1+/5AmVjyLiTJ4UoIdSJmOERw9YcRZbcGZgBJNWbxcjr4TyGtwj1EcSjEy97w==
|
||||
|
||||
"@spectrum-css/popover@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.3.tgz#6fb69873474fb968afb738eacb9e121f93e83a09"
|
||||
integrity sha512-KvmXv4TV19FBx39KfmgVlDYtvtBqv/8RRK7RRLDDHGViTxZtShjVsVpwIgfkfgn4iJztCnXpWzFqRXWUu2XCpQ==
|
||||
|
||||
"@spectrum-css/progressbar@^1.0.2":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.3.tgz#f70bcc38a2a21cff2f422ec825724ebbb9455e67"
|
||||
integrity sha512-vJHplefUuy8+NjCw1X7fLbqHVGNVBpvGFXNAeaIj4SFf4ygxiUq/5c9iRhhsCQixEsJlfD/b7BnGXU7BUDkr6Q==
|
||||
|
||||
"@spectrum-css/progresscircle@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c"
|
||||
integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ==
|
||||
|
||||
"@spectrum-css/radio@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.3.tgz#25c3bc5e9c30a8a8ae728717b7c7fb736cdae640"
|
||||
integrity sha512-LaLGfz/eGNR2iyqouXYILIA+pKRqF769iPdwM0REm5RpWvMQDD7rPZ/kWlg18owjaFsyllEp25gEjmhRJIIVOw==
|
||||
|
||||
"@spectrum-css/search@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.3.tgz#3415dc106aca0d5dd996e87084a1b47c2b95a882"
|
||||
integrity sha512-kdLpKTt0obljuhS1q1tukujRlvSs8sBwij76D4Qp8KpMzwePfZyvv1kYzuWPNZfTeISxWsmyZ6Wxd1uvzjn+UA==
|
||||
|
||||
"@spectrum-css/sidenav@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.3.tgz#132141fbd2500a927c312fa4e1d712c438b3d597"
|
||||
integrity sha512-cQ+CgwjxGftrcc79i1XnGd66QTl7H7zopSU0UTV4Qq7hvqfrjjWxfZ6b+3tezrrhNlDope1ff9o8sm67PsPXtg==
|
||||
|
||||
"@spectrum-css/statuslight@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5"
|
||||
integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w==
|
||||
|
||||
"@spectrum-css/switch@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44"
|
||||
integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ==
|
||||
|
||||
"@spectrum-css/table@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf"
|
||||
integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg==
|
||||
|
||||
"@spectrum-css/tabs@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.0.3.tgz#51dd6f168c897b0fdc3a7e9f901df7bd2288b4fc"
|
||||
integrity sha512-iLP1I72bJWz9APdQB1jiw+pOv5a7N+hYOCJvRoc56Us/hJKVzowkyGRe3uH+8v36nCG9bHxiAQNLoU8eXisVrg==
|
||||
|
||||
"@spectrum-css/tags@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac"
|
||||
integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw==
|
||||
|
||||
"@spectrum-css/textfield@^3.0.1":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.2.tgz#907f62d2dc82852dd6236a820be99e252b531631"
|
||||
integrity sha512-nkFgAb0cP4jUodkUBErMNfyF78jJLtgL1Mrr9/rvGpGobo10IAbb8zZY4CkZ64o8XmMy/85+wZTKcx+KHatqpg==
|
||||
|
||||
"@spectrum-css/toast@^3.0.1":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f"
|
||||
integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w==
|
||||
|
||||
"@spectrum-css/tooltip@^3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281"
|
||||
integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A==
|
||||
|
||||
"@spectrum-css/treeview@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046"
|
||||
integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw==
|
||||
|
||||
"@spectrum-css/typography@^3.0.1":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38"
|
||||
integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA==
|
||||
|
||||
"@spectrum-css/underlay@^2.0.9":
|
||||
version "2.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.10.tgz#8b75b646605a311850f6620caa18d4996cd64ed7"
|
||||
integrity sha512-PmsmkzeGD/rY4pp3ILXHt9w8BW7uaEqXe08hQRS7rGki7wqCpG4mE0/8N3yEcA3QxWQclmG9gdkg5uz6wMmYzA==
|
||||
|
||||
"@spectrum-css/vars@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.1.tgz#561fd69098f896a647242dd8d6108af603bfa31e"
|
||||
integrity sha512-l4oRcCOqInChYXZN6OQhpe3isk6l4OE6Ys8cgdlsiKp53suNoQxyyd9p/eGRbCjZgH3xQ8nK0t4DHa7QYC0S6w==
|
||||
|
||||
"@spectrum-css/vars@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999"
|
||||
integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw==
|
||||
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.0-next.5":
|
||||
version "1.0.0-next.5"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.5.tgz#8cf608f7a3c33dfa5b648397aae1ba90e6a4883f"
|
||||
|
@ -80,6 +325,11 @@ colorette@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
|
||||
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
|
||||
|
||||
dayjs@^1.10.4, dayjs@^1.10.5:
|
||||
version "1.10.5"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
|
||||
integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==
|
||||
|
||||
debug@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
|
@ -226,6 +476,11 @@ svelte-hmr@^0.13.3:
|
|||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.13.3.tgz#fba5739b477ea44caf70e542a24a4352bee2b897"
|
||||
integrity sha512-gagW62pLQ2lULmvNA3pIZu9pBCYOaGu3rQikUOv6Nokz5VxUgT9/mQLfMxj9phDEKHCg/lgr3i6PkqZDbO9P2Q==
|
||||
|
||||
svelte-portal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3"
|
||||
integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q==
|
||||
|
||||
svelte@^3.38.2:
|
||||
version "3.38.2"
|
||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -33,7 +33,7 @@ function testObject(object) {
|
|||
*/
|
||||
module.exports.processObject = async (object, context) => {
|
||||
testObject(object)
|
||||
for (let key of Object.keys(object)) {
|
||||
for (let key of Object.keys(object || {})) {
|
||||
if (object[key] != null) {
|
||||
let val = object[key]
|
||||
if (typeof val === "string") {
|
||||
|
@ -68,7 +68,7 @@ module.exports.processString = async (string, context) => {
|
|||
*/
|
||||
module.exports.processObjectSync = (object, context) => {
|
||||
testObject(object)
|
||||
for (let key of Object.keys(object)) {
|
||||
for (let key of Object.keys(object || {})) {
|
||||
let val = object[key]
|
||||
if (typeof val === "string") {
|
||||
object[key] = module.exports.processStringSync(object[key], context)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.27",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
|
@ -21,8 +21,8 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.21",
|
||||
"@budibase/string-templates": "^0.9.21",
|
||||
"@budibase/auth": "^0.9.27",
|
||||
"@budibase/string-templates": "^0.9.27",
|
||||
"@koa/router": "^8.0.0",
|
||||
"aws-sdk": "^2.811.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
|
|
|
@ -2,7 +2,7 @@ const Router = require("@koa/router")
|
|||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
const { routes } = require("./routes")
|
||||
const { buildAuthMiddleware } = require("@budibase/auth").auth
|
||||
const { buildAuthMiddleware, auditLog } = require("@budibase/auth").auth
|
||||
|
||||
const PUBLIC_ENDPOINTS = [
|
||||
{
|
||||
|
@ -62,6 +62,7 @@ router
|
|||
}
|
||||
return next()
|
||||
})
|
||||
.use(auditLog)
|
||||
|
||||
// error handling middleware
|
||||
router.use(async (ctx, next) => {
|
||||
|
|
|
@ -51,12 +51,8 @@ exports.init = async () => {
|
|||
* make sure redis connection is closed.
|
||||
*/
|
||||
exports.shutdown = async () => {
|
||||
if (pwResetClient != null) {
|
||||
await pwResetClient.finish()
|
||||
}
|
||||
if (invitationClient != null) {
|
||||
await invitationClient.finish()
|
||||
}
|
||||
if (pwResetClient) await pwResetClient.finish()
|
||||
if (invitationClient) await invitationClient.finish()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -910,7 +910,7 @@ array-unique@^0.3.2:
|
|||
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
|
||||
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
|
||||
|
||||
asn1@~0.2.3:
|
||||
asn1@~0.2.0, asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
|
@ -1076,7 +1076,7 @@ base@^0.11.1:
|
|||
mixin-deep "^1.2.0"
|
||||
pascalcase "^0.1.1"
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
|
@ -1093,6 +1093,15 @@ binary-extensions@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||
|
||||
bl@^4.0.3:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
|
||||
dependencies:
|
||||
buffer "^5.5.0"
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
boxen@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
||||
|
@ -1337,6 +1346,11 @@ chokidar@^3.2.2:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.1"
|
||||
|
||||
chownr@^1.1.1:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||
|
||||
ci-info@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||
|
@ -1773,6 +1787,24 @@ diff-sequences@^26.6.2:
|
|||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
|
||||
integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==
|
||||
|
||||
docker-modem@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.0.tgz#cb912ad8daed42f858269fb3be6944df281ec12d"
|
||||
integrity sha512-WwFajJ8I5geZ/dDZ5FDMDA6TBkWa76xWwGIGw8uzUjNUGCN0to83wJ8Oi1AxrJTC0JBn+7fvIxUctnawtlwXeg==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
readable-stream "^3.5.0"
|
||||
split-ca "^1.0.1"
|
||||
ssh2 "^0.8.7"
|
||||
|
||||
dockerode@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.0.tgz#bedaf48ef9fa9124275a54a9881a92374c51008e"
|
||||
integrity sha512-St08lfOjpYCOXEM8XA0VLu3B3hRjtddODphNW5GFoA0AS3JHgoPQKOz0Qmdzg3P+hUPxhb02g1o1Cu1G+U3lRg==
|
||||
dependencies:
|
||||
docker-modem "^3.0.0"
|
||||
tar-fs "~2.0.1"
|
||||
|
||||
domexception@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
|
||||
|
@ -1857,7 +1889,7 @@ encoding-down@^6.3.0:
|
|||
level-codec "^9.0.0"
|
||||
level-errors "^2.0.0"
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
|
||||
|
@ -2238,6 +2270,11 @@ fresh@~0.5.2:
|
|||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
|
@ -3998,6 +4035,11 @@ mixin-deep@^1.2.0:
|
|||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mkdirp-classic@^0.5.2:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
|
||||
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
|
||||
|
||||
mkdirp@^0.5.0:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||
|
@ -4829,7 +4871,7 @@ readable-stream@1.1.14:
|
|||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
|
@ -5326,6 +5368,11 @@ spdx-license-ids@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
|
||||
integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
|
||||
|
||||
split-ca@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
|
||||
integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||
|
@ -5345,6 +5392,22 @@ sprintf-js@~1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
ssh2-streams@~0.4.10:
|
||||
version "0.4.10"
|
||||
resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.10.tgz#48ef7e8a0e39d8f2921c30521d56dacb31d23a34"
|
||||
integrity sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==
|
||||
dependencies:
|
||||
asn1 "~0.2.0"
|
||||
bcrypt-pbkdf "^1.0.2"
|
||||
streamsearch "~0.1.2"
|
||||
|
||||
ssh2@^0.8.7:
|
||||
version "0.8.9"
|
||||
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.9.tgz#54da3a6c4ba3daf0d8477a538a481326091815f3"
|
||||
integrity sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==
|
||||
dependencies:
|
||||
ssh2-streams "~0.4.10"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
|
@ -5390,6 +5453,11 @@ stealthy-require@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
||||
|
||||
streamsearch@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||
|
||||
string-length@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
|
||||
|
@ -5529,6 +5597,27 @@ symbol-tree@^3.2.4:
|
|||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
|
||||
|
||||
tar-fs@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2"
|
||||
integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==
|
||||
dependencies:
|
||||
chownr "^1.1.1"
|
||||
mkdirp-classic "^0.5.2"
|
||||
pump "^3.0.0"
|
||||
tar-stream "^2.0.0"
|
||||
|
||||
tar-stream@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
|
||||
integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
|
||||
dependencies:
|
||||
bl "^4.0.3"
|
||||
end-of-stream "^1.4.1"
|
||||
fs-constants "^1.0.0"
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
term-size@^2.1.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
|
||||
|
|
Loading…
Reference in New Issue