Merge branch 'develop' of github.com:Budibase/budibase into more-grid-tweaks
This commit is contained in:
commit
defcc7a273
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"packages": ["packages/*"],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -24,7 +24,7 @@
|
|||
"dependencies": {
|
||||
"@budibase/nano": "10.1.2",
|
||||
"@budibase/pouchdb-replication-stream": "1.2.10",
|
||||
"@budibase/types": "2.5.6-alpha.26",
|
||||
"@budibase/types": "2.5.6-alpha.32",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-cloudfront-sign": "2.2.0",
|
||||
|
@ -47,6 +47,8 @@
|
|||
"passport-jwt": "4.0.0",
|
||||
"passport-local": "1.0.0",
|
||||
"passport-oauth2-refresh": "^2.1.0",
|
||||
"pino": "8.11.0",
|
||||
"pino-http": "8.3.3",
|
||||
"posthog-node": "1.3.0",
|
||||
"pouchdb": "7.3.0",
|
||||
"pouchdb-find": "7.2.2",
|
||||
|
@ -80,7 +82,6 @@
|
|||
"jest-serial-runner": "^1.2.1",
|
||||
"koa": "2.13.4",
|
||||
"nodemon": "2.0.16",
|
||||
"pino": "7.11.0",
|
||||
"pino-pretty": "10.0.0",
|
||||
"pouchdb-adapter-memory": "7.2.2",
|
||||
"timekeeper": "2.2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,8 +38,8 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
||||
"@budibase/shared-core": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/shared-core": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@spectrum-css/accordion": "3.0.24",
|
||||
"@spectrum-css/actionbutton": "1.0.1",
|
||||
"@spectrum-css/actiongroup": "1.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -58,11 +58,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.26",
|
||||
"@budibase/client": "2.5.6-alpha.26",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.26",
|
||||
"@budibase/shared-core": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/bbui": "2.5.6-alpha.32",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.32",
|
||||
"@budibase/shared-core": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
|
|
|
@ -10,7 +10,10 @@ import { auth } from "./stores/portal"
|
|||
export const API = createAPIClient({
|
||||
attachHeaders: headers => {
|
||||
// Attach app ID header from store
|
||||
headers["x-budibase-app-id"] = get(store).appId
|
||||
let appId = get(store).appId
|
||||
if (appId) {
|
||||
headers["x-budibase-app-id"] = appId
|
||||
}
|
||||
|
||||
// Add csrf token if authenticated
|
||||
const user = get(auth).user
|
||||
|
|
|
@ -134,6 +134,7 @@ export const getFrontendStore = () => {
|
|||
previousTopNavPath: {},
|
||||
version: application.version,
|
||||
revertableVersion: application.revertableVersion,
|
||||
upgradableVersion: application.upgradableVersion,
|
||||
navigation: application.navigation || {},
|
||||
usedPlugins: application.usedPlugins || [],
|
||||
}))
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
} from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import { API } from "api"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
|
||||
export function show() {
|
||||
updateModal.show()
|
||||
|
@ -25,9 +24,9 @@
|
|||
|
||||
$: appId = $store.appId
|
||||
$: updateAvailable =
|
||||
clientPackage.version &&
|
||||
$store.upgradableVersion &&
|
||||
$store.version &&
|
||||
clientPackage.version !== $store.version
|
||||
$store.upgradableVersion !== $store.version
|
||||
$: revertAvailable = $store.revertableVersion != null
|
||||
|
||||
const refreshAppPackage = async () => {
|
||||
|
@ -46,7 +45,7 @@
|
|||
// Don't wait for the async refresh, since this causes modal flashing
|
||||
refreshAppPackage()
|
||||
notifications.success(
|
||||
`App updated successfully to version ${clientPackage.version}`
|
||||
`App updated successfully to version ${$store.upgradableVersion}`
|
||||
)
|
||||
} catch (err) {
|
||||
notifications.error(`Error updating app: ${err}`)
|
||||
|
@ -91,7 +90,7 @@
|
|||
{#if updateAvailable}
|
||||
<Body size="S">
|
||||
This app is currently using version <b>{$store.version}</b>, but version
|
||||
<b>{clientPackage.version}</b> is available. Updates can contain new features,
|
||||
<b>{$store.upgradableVersion}</b> is available. Updates can contain new features,
|
||||
performance improvements and bug fixes.
|
||||
</Body>
|
||||
{:else}
|
||||
|
|
|
@ -21,6 +21,7 @@ import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCom
|
|||
import ColumnEditor from "./controls/ColumnEditor/ColumnEditor.svelte"
|
||||
import BasicColumnEditor from "./controls/ColumnEditor/BasicColumnEditor.svelte"
|
||||
import BarButtonList from "./controls/BarButtonList.svelte"
|
||||
import FieldConfiguration from "./controls/FieldConfiguration/FieldConfiguration.svelte"
|
||||
|
||||
const componentMap = {
|
||||
text: DrawerBindableCombobox,
|
||||
|
@ -43,6 +44,7 @@ const componentMap = {
|
|||
section: SectionSelect,
|
||||
filter: FilterEditor,
|
||||
url: URLSelect,
|
||||
fieldConfiguration: FieldConfiguration,
|
||||
columns: ColumnEditor,
|
||||
"columns/basic": BasicColumnEditor,
|
||||
"field/sortable": SortableFieldSelect,
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<script>
|
||||
import { Button, ActionButton, Drawer } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import ColumnDrawer from "./ColumnDrawer.svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import {
|
||||
getDatasourceForProvider,
|
||||
getSchemaForDatasource,
|
||||
} from "builderStore/dataBinding"
|
||||
import { currentAsset } from "builderStore"
|
||||
import { getFields } from "helpers/searchFields"
|
||||
|
||||
export let componentInstance
|
||||
export let value = []
|
||||
export let allowCellEditing = true
|
||||
export let subject = "Table"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let drawer
|
||||
let boundValue
|
||||
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchema($currentAsset, datasource)
|
||||
$: options = allowCellEditing
|
||||
? Object.keys(schema || {})
|
||||
: enrichedSchemaFields?.map(field => field.name)
|
||||
$: sanitisedValue = getValidColumns(value, options)
|
||||
$: updateBoundValue(sanitisedValue)
|
||||
$: enrichedSchemaFields = getFields(Object.values(schema || {}), {
|
||||
allowLinks: true,
|
||||
})
|
||||
|
||||
const getSchema = (asset, datasource) => {
|
||||
const schema = getSchemaForDatasource(asset, datasource).schema
|
||||
|
||||
// Don't show ID and rev in tables
|
||||
if (schema) {
|
||||
delete schema._id
|
||||
delete schema._rev
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
const updateBoundValue = value => {
|
||||
boundValue = cloneDeep(value)
|
||||
}
|
||||
|
||||
const getValidColumns = (columns, options) => {
|
||||
if (!Array.isArray(columns) || !columns.length) {
|
||||
return []
|
||||
}
|
||||
// We need to account for legacy configs which would just be an array
|
||||
// of strings
|
||||
if (typeof columns[0] === "string") {
|
||||
columns = columns.map(col => ({
|
||||
name: col,
|
||||
displayName: col,
|
||||
}))
|
||||
}
|
||||
return columns.filter(column => {
|
||||
return options.includes(column.name)
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
updateBoundValue(sanitisedValue)
|
||||
drawer.show()
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
dispatch("change", getValidColumns(boundValue, options))
|
||||
drawer.hide()
|
||||
}
|
||||
</script>
|
||||
|
||||
<ActionButton on:click={open}>Configure columns</ActionButton>
|
||||
<Drawer bind:this={drawer} title="{subject} Columns">
|
||||
<svelte:fragment slot="description">
|
||||
Configure the columns in your {subject.toLowerCase()}.
|
||||
</svelte:fragment>
|
||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
<ColumnDrawer
|
||||
slot="body"
|
||||
bind:columns={boundValue}
|
||||
{options}
|
||||
{schema}
|
||||
{allowCellEditing}
|
||||
/>
|
||||
</Drawer>
|
|
@ -0,0 +1,26 @@
|
|||
<script>
|
||||
import { DrawerContent, Drawer, Button, Icon } from "@budibase/bbui"
|
||||
import ValidationDrawer from "components/design/settings/controls/ValidationEditor/ValidationDrawer.svelte"
|
||||
export let column
|
||||
export let type
|
||||
|
||||
let drawer
|
||||
</script>
|
||||
|
||||
<Icon name="Settings" hoverable size="S" on:click={drawer.show} />
|
||||
<Drawer bind:this={drawer} title="Field Validation">
|
||||
<svelte:fragment slot="description">
|
||||
"{column.name}" field validation
|
||||
</svelte:fragment>
|
||||
<Button cta slot="buttons" on:click={drawer.hide}>Save</Button>
|
||||
<DrawerContent slot="body">
|
||||
<div class="container">
|
||||
<ValidationDrawer
|
||||
slot="body"
|
||||
bind:rules={column.validation}
|
||||
fieldName={column.name}
|
||||
{type}
|
||||
/>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
|
@ -0,0 +1,202 @@
|
|||
<script>
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
DrawerContent,
|
||||
Layout,
|
||||
Select,
|
||||
Label,
|
||||
Body,
|
||||
Input,
|
||||
} from "@budibase/bbui"
|
||||
import { flip } from "svelte/animate"
|
||||
import { dndzone } from "svelte-dnd-action"
|
||||
import { generate } from "shortid"
|
||||
import CellEditor from "./CellEditor.svelte"
|
||||
|
||||
export let columns = []
|
||||
export let options = []
|
||||
export let schema = {}
|
||||
|
||||
const flipDurationMs = 150
|
||||
let dragDisabled = true
|
||||
|
||||
$: unselectedColumns = getUnselectedColumns(options, columns)
|
||||
$: columns.forEach(column => {
|
||||
if (!column.id) {
|
||||
column.id = generate()
|
||||
}
|
||||
})
|
||||
|
||||
const getUnselectedColumns = (allColumns, selectedColumns) => {
|
||||
let optionsObj = {}
|
||||
allColumns.forEach(option => {
|
||||
optionsObj[option] = true
|
||||
})
|
||||
selectedColumns?.forEach(column => {
|
||||
delete optionsObj[column.name]
|
||||
})
|
||||
return Object.keys(optionsObj)
|
||||
}
|
||||
|
||||
const getRemainingColumnOptions = selectedColumn => {
|
||||
if (!selectedColumn || unselectedColumns.includes(selectedColumn)) {
|
||||
return unselectedColumns
|
||||
}
|
||||
return [selectedColumn, ...unselectedColumns]
|
||||
}
|
||||
|
||||
const addColumn = () => {
|
||||
columns = [...columns, {}]
|
||||
}
|
||||
|
||||
const removeColumn = id => {
|
||||
columns = columns.filter(column => column.id !== id)
|
||||
}
|
||||
|
||||
const updateColumnOrder = e => {
|
||||
columns = e.detail.items
|
||||
}
|
||||
|
||||
const handleFinalize = e => {
|
||||
updateColumnOrder(e)
|
||||
dragDisabled = true
|
||||
}
|
||||
|
||||
const addAllColumns = () => {
|
||||
let newColumns = columns || []
|
||||
options.forEach(field => {
|
||||
const fieldSchema = schema[field]
|
||||
const hasCol = columns && columns.findIndex(x => x.name === field) !== -1
|
||||
if (!fieldSchema?.autocolumn && !hasCol) {
|
||||
newColumns.push({
|
||||
name: field,
|
||||
displayName: field,
|
||||
})
|
||||
}
|
||||
})
|
||||
columns = newColumns
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
columns = []
|
||||
}
|
||||
|
||||
const getFieldType = column => {
|
||||
return `validation/${schema[column.name]?.type}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<DrawerContent>
|
||||
<div class="container">
|
||||
<Layout noPadding gap="S">
|
||||
{#if columns?.length}
|
||||
<Layout noPadding gap="XS">
|
||||
<div class="column">
|
||||
<div />
|
||||
<Label size="L">Column</Label>
|
||||
<Label size="L">Label</Label>
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
<div
|
||||
class="columns"
|
||||
use:dndzone={{
|
||||
items: columns,
|
||||
flipDurationMs,
|
||||
dropTargetStyle: { outline: "none" },
|
||||
dragDisabled,
|
||||
}}
|
||||
on:finalize={handleFinalize}
|
||||
on:consider={updateColumnOrder}
|
||||
>
|
||||
{#each columns as column (column.id)}
|
||||
<div class="column" animate:flip={{ duration: flipDurationMs }}>
|
||||
<div
|
||||
class="handle"
|
||||
aria-label="drag-handle"
|
||||
style={dragDisabled ? "cursor: grab" : "cursor: grabbing"}
|
||||
on:mousedown={() => (dragDisabled = false)}
|
||||
>
|
||||
<Icon name="DragHandle" size="XL" />
|
||||
</div>
|
||||
<Select
|
||||
bind:value={column.name}
|
||||
placeholder="Column"
|
||||
options={getRemainingColumnOptions(column.name)}
|
||||
on:change={e => (column.displayName = e.detail)}
|
||||
/>
|
||||
<Input bind:value={column.displayName} placeholder="Label" />
|
||||
<CellEditor type={getFieldType(column)} bind:column />
|
||||
<Icon
|
||||
name="Close"
|
||||
hoverable
|
||||
size="S"
|
||||
on:click={() => removeColumn(column.id)}
|
||||
disabled={columns.length === 1}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Layout>
|
||||
{:else}
|
||||
<div class="column">
|
||||
<div class="wide">
|
||||
<Body size="S">Add columns to be included in your form below.</Body>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="column">
|
||||
<div class="buttons wide">
|
||||
<Button secondary icon="Add" on:click={addColumn}>Add column</Button>
|
||||
<Button secondary quiet on:click={addAllColumns}>
|
||||
Add all columns
|
||||
</Button>
|
||||
{#if columns?.length}
|
||||
<Button secondary quiet on:click={reset}>Reset columns</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.columns {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
.column {
|
||||
gap: var(--spacing-l);
|
||||
display: grid;
|
||||
grid-template-columns: 20px 1fr 1fr 16px 16px;
|
||||
align-items: center;
|
||||
border-radius: var(--border-radius-s);
|
||||
transition: background-color ease-in-out 130ms;
|
||||
}
|
||||
.column:hover {
|
||||
background-color: var(--spectrum-global-color-gray-100);
|
||||
}
|
||||
.handle {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.wide {
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,89 @@
|
|||
<script>
|
||||
import { Button, ActionButton, Drawer } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import ColumnDrawer from "./ColumnDrawer.svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import {
|
||||
getDatasourceForProvider,
|
||||
getSchemaForDatasource,
|
||||
} from "builderStore/dataBinding"
|
||||
import { currentAsset } from "builderStore"
|
||||
import { getFields } from "helpers/searchFields"
|
||||
|
||||
export let componentInstance
|
||||
export let value = []
|
||||
|
||||
const convertOldColumnFormat = oldColumns => {
|
||||
if (typeof oldColumns?.[0] === "string") {
|
||||
value = oldColumns.map(field => ({ name: field, displayName: field }))
|
||||
}
|
||||
}
|
||||
|
||||
$: convertOldColumnFormat(value)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let drawer
|
||||
let boundValue
|
||||
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchema($currentAsset, datasource)
|
||||
$: options = Object.keys(schema || {})
|
||||
$: sanitisedValue = getValidColumns(value, options)
|
||||
$: updateBoundValue(sanitisedValue)
|
||||
$: enrichedSchemaFields = getFields(Object.values(schema || {}), {
|
||||
allowLinks: true,
|
||||
})
|
||||
|
||||
const getSchema = (asset, datasource) => {
|
||||
const schema = getSchemaForDatasource(asset, datasource).schema
|
||||
|
||||
// Don't show ID and rev in tables
|
||||
if (schema) {
|
||||
delete schema._id
|
||||
delete schema._rev
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
const updateBoundValue = value => {
|
||||
boundValue = cloneDeep(value)
|
||||
}
|
||||
|
||||
const getValidColumns = (columns, options) => {
|
||||
if (!Array.isArray(columns) || !columns.length) {
|
||||
return []
|
||||
}
|
||||
// We need to account for legacy configs which would just be an array
|
||||
// of strings
|
||||
if (typeof columns[0] === "string") {
|
||||
columns = columns.map(col => ({
|
||||
name: col,
|
||||
displayName: col,
|
||||
}))
|
||||
}
|
||||
return columns.filter(column => {
|
||||
return options.includes(column.name)
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
updateBoundValue(sanitisedValue)
|
||||
drawer.show()
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
dispatch("change", getValidColumns(boundValue, options))
|
||||
drawer.hide()
|
||||
}
|
||||
</script>
|
||||
|
||||
<ActionButton on:click={open}>Configure fields</ActionButton>
|
||||
<Drawer bind:this={drawer} title="Form Fields">
|
||||
<svelte:fragment slot="description">
|
||||
Configure the fields in your form.
|
||||
</svelte:fragment>
|
||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
<ColumnDrawer slot="body" bind:columns={boundValue} {options} {schema} />
|
||||
</Drawer>
|
|
@ -16,6 +16,7 @@
|
|||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||
import { generate } from "shortid"
|
||||
|
||||
export let fieldName = null
|
||||
export let rules = []
|
||||
export let bindings = []
|
||||
export let type
|
||||
|
@ -124,7 +125,7 @@
|
|||
}
|
||||
|
||||
$: dataSourceSchema = getDataSourceSchema($currentAsset, $selectedComponent)
|
||||
$: field = $selectedComponent?.field
|
||||
$: field = fieldName || $selectedComponent?.field
|
||||
$: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {})
|
||||
$: fieldType = type?.split("/")[1] || "string"
|
||||
$: constraintOptions = getConstraintsForType(fieldType)
|
||||
|
@ -140,8 +141,12 @@
|
|||
const formParent = findClosestMatchingComponent(
|
||||
asset.props,
|
||||
component._id,
|
||||
component => component._component.endsWith("/form")
|
||||
component =>
|
||||
component._component.endsWith("/form") ||
|
||||
component._component.endsWith("/formblock") ||
|
||||
component._component.endsWith("/tableblock")
|
||||
)
|
||||
|
||||
return getSchemaForDatasource(asset, formParent?.dataSource)
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<Panel title={$selectedLayout?.name} icon="Experience" borderLeft>
|
||||
<Panel title={$selectedLayout?.name} icon="Experience" borderLeft wide>
|
||||
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||
<Banner type="warning" showCloseButton={false}>
|
||||
Custom layouts are being deprecated. They will be removed in a future
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<Panel borderLeft title="Navigation" icon="InfoOutline">
|
||||
<Panel borderLeft title="Navigation" icon="InfoOutline" wide>
|
||||
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||
{#if $selectedScreen.layoutId}
|
||||
<Banner
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
title={$selectedScreen.routing.route}
|
||||
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"}
|
||||
borderLeft
|
||||
wide
|
||||
>
|
||||
<Layout gap="S" paddingX="L" paddingY="XL">
|
||||
{#if $selectedScreen.layoutId}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { Body, Layout } from "@budibase/bbui"
|
||||
</script>
|
||||
|
||||
<Panel borderLeft title="Theme" icon="InfoOutline">
|
||||
<Panel borderLeft title="Theme" icon="InfoOutline" wide>
|
||||
<Layout paddingX="L" paddingY="XL">
|
||||
<Body size="S">
|
||||
Your theme is set across all the screens within your app.
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
import * as routify from "@roxi/routify"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
// Keep URL and state in sync for selected screen ID
|
||||
// Keep URL and state in sync for selected app ID
|
||||
const stopSyncing = syncURLToState({
|
||||
urlParam: "appId",
|
||||
stateKey: "selectedAppId",
|
||||
|
@ -47,6 +47,7 @@
|
|||
let deletionModal
|
||||
let exportPublishedVersion = false
|
||||
let deletionConfirmationAppName
|
||||
let loaded = false
|
||||
|
||||
$: app = $overview.selectedApp
|
||||
$: appId = $overview.selectedAppId
|
||||
|
@ -56,10 +57,12 @@
|
|||
$: lockedByYou = $auth.user.email === app?.lockedBy?.email
|
||||
|
||||
const initialiseApp = async appId => {
|
||||
loaded = false
|
||||
try {
|
||||
const pkg = await API.fetchAppPackage(appId)
|
||||
await store.actions.initialise(pkg)
|
||||
await API.syncApp(appId)
|
||||
loaded = true
|
||||
} catch (error) {
|
||||
notifications.error("Error initialising app overview")
|
||||
$goto("../../")
|
||||
|
@ -228,7 +231,9 @@
|
|||
active={$isActive("./version")}
|
||||
/>
|
||||
</SideNav>
|
||||
<slot />
|
||||
{#if loaded}
|
||||
<slot />
|
||||
{/if}
|
||||
</Content>
|
||||
</Layout>
|
||||
</Page>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
import { processStringSync } from "@budibase/string-templates"
|
||||
import { users, auth, apps, groups, overview } from "stores/portal"
|
||||
import { fetchData } from "@budibase/frontend-core"
|
||||
|
@ -40,7 +39,7 @@
|
|||
},
|
||||
},
|
||||
})
|
||||
$: updateAvailable = clientPackage.version !== $store.version
|
||||
$: updateAvailable = $store.upgradableVersion !== $store.version
|
||||
$: isPublished = app?.status === AppStatus.DEPLOYED
|
||||
$: appEditorId = !app?.updatedBy ? $auth.user._id : app?.updatedBy
|
||||
$: appEditorText = appEditor?.firstName || appEditor?.email
|
||||
|
@ -172,8 +171,8 @@
|
|||
<Heading size="XS">{$store.version}</Heading>
|
||||
{#if updateAvailable}
|
||||
<div class="version-status">
|
||||
New version <strong>{clientPackage.version}</strong> is available
|
||||
-
|
||||
New version <strong>{$store.upgradableVersion}</strong> is
|
||||
available -
|
||||
<Link
|
||||
on:click={() => {
|
||||
$goto("./version")
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
<script>
|
||||
import { Layout, Heading, Body, Divider, Button } from "@budibase/bbui"
|
||||
import { store } from "builderStore"
|
||||
import clientPackage from "@budibase/client/package.json"
|
||||
import VersionModal from "components/deploy/VersionModal.svelte"
|
||||
|
||||
let versionModal
|
||||
|
||||
$: updateAvailable = clientPackage.version !== $store.version
|
||||
$: updateAvailable = $store.upgradableVersion !== $store.version
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
|
@ -18,7 +17,7 @@
|
|||
{#if updateAvailable}
|
||||
<Body>
|
||||
The app is currently using version <strong>{$store.version}</strong>
|
||||
but version <strong>{clientPackage.version}</strong> is available.
|
||||
but version <strong>{$store.upgradableVersion}</strong> is available.
|
||||
<br />
|
||||
Updates can contain new features, performance improvements and bug fixes.
|
||||
</Body>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
|
@ -29,9 +29,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/types": "2.5.6-alpha.26",
|
||||
"@budibase/backend-core": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@budibase/types": "2.5.6-alpha.32",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -4435,6 +4435,48 @@
|
|||
"key": "row"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Fields",
|
||||
"type": "fieldConfiguration",
|
||||
"key": "sidePanelFields",
|
||||
"nested": true,
|
||||
"dependsOn": {
|
||||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Show delete",
|
||||
"type": "boolean",
|
||||
"key": "sidePanelShowDelete",
|
||||
"nested": true,
|
||||
"dependsOn": {
|
||||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Save label",
|
||||
"type": "text",
|
||||
"key": "sidePanelSaveLabel",
|
||||
"defaultValue": "Save",
|
||||
"nested": true,
|
||||
"dependsOn": {
|
||||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Delete label",
|
||||
"type": "text",
|
||||
"key": "sidePanelDeleteLabel",
|
||||
"defaultValue": "Delete",
|
||||
"nested": true,
|
||||
"dependsOn": {
|
||||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -4979,7 +5021,7 @@
|
|||
"name": "Fields",
|
||||
"settings": [
|
||||
{
|
||||
"type": "multifield",
|
||||
"type": "fieldConfiguration",
|
||||
"label": "Fields",
|
||||
"key": "fields",
|
||||
"selectAllFields": true
|
||||
|
@ -5028,6 +5070,17 @@
|
|||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "saveButtonLabel",
|
||||
"label": "Save button label",
|
||||
"nested": true,
|
||||
"defaultValue": "Save",
|
||||
"dependsOn": {
|
||||
"setting": "showSaveButton",
|
||||
"value": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Allow delete",
|
||||
|
@ -5038,6 +5091,17 @@
|
|||
"value": "Update"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deleteButtonLabel",
|
||||
"label": "Delete button label",
|
||||
"nested": true,
|
||||
"defaultValue": "Delete",
|
||||
"dependsOn": {
|
||||
"setting": "showDeleteButton",
|
||||
"value": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "url",
|
||||
"label": "Navigate after button press",
|
||||
|
@ -5161,36 +5225,5 @@
|
|||
"type": "schema",
|
||||
"suffix": "repeater"
|
||||
}
|
||||
},
|
||||
"spreadsheet": {
|
||||
"name": "Spreadsheet",
|
||||
"icon": "ViewGrid",
|
||||
"settings": [
|
||||
{
|
||||
"key": "table",
|
||||
"type": "table",
|
||||
"label": "Table"
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"label": "Filtering",
|
||||
"key": "filter"
|
||||
},
|
||||
{
|
||||
"type": "field/sortable",
|
||||
"label": "Sort Column",
|
||||
"key": "sortColumn"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Sort Order",
|
||||
"key": "sortOrder",
|
||||
"options": [
|
||||
"Ascending",
|
||||
"Descending"
|
||||
],
|
||||
"defaultValue": "Ascending"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,11 +19,11 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.26",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.26",
|
||||
"@budibase/shared-core": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/types": "2.5.6-alpha.26",
|
||||
"@budibase/bbui": "2.5.6-alpha.32",
|
||||
"@budibase/frontend-core": "2.5.6-alpha.32",
|
||||
"@budibase/shared-core": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@budibase/types": "2.5.6-alpha.32",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
export let titleButtonClickBehaviour
|
||||
export let onClickTitleButton
|
||||
export let noRowsMessage
|
||||
export let sidePanelFields
|
||||
export let sidePanelShowDelete
|
||||
export let sidePanelSaveLabel
|
||||
export let sidePanelDeleteLabel
|
||||
|
||||
const { fetchDatasourceSchema, API } = getContext("sdk")
|
||||
const stateKey = `ID_${generate()}`
|
||||
|
@ -241,10 +245,12 @@
|
|||
props={{
|
||||
dataSource,
|
||||
showSaveButton: true,
|
||||
showDeleteButton: true,
|
||||
showDeleteButton: sidePanelShowDelete,
|
||||
saveButtonLabel: sidePanelSaveLabel,
|
||||
deleteButtonLabel: sidePanelDeleteLabel,
|
||||
actionType: "Update",
|
||||
rowId: `{{ ${safe("state")}.${safe(stateKey)} }}`,
|
||||
fields: normalFields,
|
||||
fields: sidePanelFields || normalFields,
|
||||
title: editTitle,
|
||||
labelPosition: "left",
|
||||
}}
|
||||
|
@ -266,8 +272,9 @@
|
|||
dataSource,
|
||||
showSaveButton: true,
|
||||
showDeleteButton: false,
|
||||
saveButtonLabel: sidePanelSaveLabel,
|
||||
actionType: "Create",
|
||||
fields: normalFields,
|
||||
fields: sidePanelFields || normalFields,
|
||||
title: "Create Row",
|
||||
labelPosition: "left",
|
||||
}}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let saveButtonLabel
|
||||
export let deleteButtonLabel
|
||||
export let showSaveButton
|
||||
export let showDeleteButton
|
||||
export let rowId
|
||||
|
@ -20,10 +22,40 @@
|
|||
|
||||
const { fetchDatasourceSchema } = getContext("sdk")
|
||||
|
||||
const convertOldFieldFormat = fields => {
|
||||
if (typeof fields?.[0] === "string") {
|
||||
return fields.map(field => ({ name: field, displayName: field }))
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
const getDefaultFields = (fields, schema) => {
|
||||
if (schema && (!fields || fields.length === 0)) {
|
||||
const defaultFields = []
|
||||
|
||||
Object.values(schema).forEach(field => {
|
||||
if (field.autocolumn) return
|
||||
|
||||
defaultFields.push({
|
||||
name: field.name,
|
||||
displayName: field.name,
|
||||
})
|
||||
})
|
||||
|
||||
return defaultFields
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
let schema
|
||||
let providerId
|
||||
let repeaterId
|
||||
|
||||
$: formattedFields = convertOldFieldFormat(fields)
|
||||
$: fieldsOrDefault = getDefaultFields(formattedFields, schema)
|
||||
|
||||
$: fetchSchema(dataSource)
|
||||
$: dataProvider = `{{ literal ${safe(providerId)} }}`
|
||||
$: filter = [
|
||||
|
@ -46,9 +78,11 @@
|
|||
actionType,
|
||||
size,
|
||||
disabled,
|
||||
fields,
|
||||
fields: fieldsOrDefault,
|
||||
labelPosition,
|
||||
title,
|
||||
saveButtonLabel,
|
||||
deleteButtonLabel,
|
||||
showSaveButton,
|
||||
showDeleteButton,
|
||||
schema,
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
export let fields
|
||||
export let labelPosition
|
||||
export let title
|
||||
export let saveButtonLabel
|
||||
export let deleteButtonLabel
|
||||
export let showSaveButton
|
||||
export let showDeleteButton
|
||||
export let schema
|
||||
|
@ -33,6 +35,12 @@
|
|||
let formId
|
||||
|
||||
$: onSave = [
|
||||
{
|
||||
"##eventHandlerType": "Validate Form",
|
||||
parameters: {
|
||||
componentId: formId,
|
||||
},
|
||||
},
|
||||
{
|
||||
"##eventHandlerType": "Save Row",
|
||||
parameters: {
|
||||
|
@ -163,7 +171,7 @@
|
|||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: "Delete",
|
||||
text: deleteButtonLabel || "Delete",
|
||||
onClick: onDelete,
|
||||
quiet: true,
|
||||
type: "secondary",
|
||||
|
@ -175,7 +183,7 @@
|
|||
<BlockComponent
|
||||
type="button"
|
||||
props={{
|
||||
text: "Save",
|
||||
text: saveButtonLabel || "Save",
|
||||
onClick: onSave,
|
||||
type: "cta",
|
||||
}}
|
||||
|
@ -188,14 +196,14 @@
|
|||
{/if}
|
||||
<BlockComponent type="fieldgroup" props={{ labelPosition }} order={1}>
|
||||
{#each fields as field, idx}
|
||||
{#if getComponentForField(field)}
|
||||
{#if getComponentForField(field.name)}
|
||||
<BlockComponent
|
||||
type={getComponentForField(field)}
|
||||
type={getComponentForField(field.name)}
|
||||
props={{
|
||||
field,
|
||||
label: field,
|
||||
placeholder: field,
|
||||
disabled,
|
||||
validation: field.validation,
|
||||
field: field.name,
|
||||
label: field.displayName,
|
||||
placeholder: field.displayName,
|
||||
}}
|
||||
order={idx}
|
||||
/>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.5.6-alpha.26",
|
||||
"@budibase/shared-core": "2.5.6-alpha.26",
|
||||
"@budibase/bbui": "2.5.6-alpha.32",
|
||||
"@budibase/shared-core": "2.5.6-alpha.32",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash": "^4.17.21",
|
||||
"socket.io-client": "^4.6.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/sdk",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase Public API SDK",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -45,12 +45,12 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "2.5.6-alpha.26",
|
||||
"@budibase/client": "2.5.6-alpha.26",
|
||||
"@budibase/pro": "2.5.6-alpha.26",
|
||||
"@budibase/shared-core": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/types": "2.5.6-alpha.26",
|
||||
"@budibase/backend-core": "2.5.6-alpha.32",
|
||||
"@budibase/client": "2.5.6-alpha.32",
|
||||
"@budibase/pro": "2.5.6-alpha.32",
|
||||
"@budibase/shared-core": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@budibase/types": "2.5.6-alpha.32",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -223,7 +223,7 @@ export async function fetchAppPackage(ctx: UserCtx) {
|
|||
)
|
||||
|
||||
ctx.body = {
|
||||
application,
|
||||
application: { ...application, upgradableVersion: envCore.VERSION },
|
||||
screens,
|
||||
layouts,
|
||||
clientLibPath,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/shared-core",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Shared data utils",
|
||||
"main": "dist/cjs/src/index.js",
|
||||
"types": "dist/mjs/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"dev:builder": "yarn prebuild && concurrently \"tsc -p tsconfig.build.json --watch\" \"tsc -p tsconfig-cjs.build.json --watch\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "2.5.6-alpha.26"
|
||||
"@budibase/types": "2.5.6-alpha.32"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^7.6.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/cjs/index.js",
|
||||
"types": "dist/mjs/index.d.ts",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { QuotaUsage } from "../../documents"
|
||||
import { LicenseOverrides, QuotaUsage } from "../../documents"
|
||||
import { PlanType } from "../../sdk"
|
||||
|
||||
export interface GetLicenseRequest {
|
||||
// All fields should be optional to cater for
|
||||
|
@ -20,3 +21,8 @@ export interface QuotaTriggeredRequest {
|
|||
export interface LicenseActivateRequest {
|
||||
installVersion?: string
|
||||
}
|
||||
|
||||
export interface UpdateLicenseRequest {
|
||||
planType?: PlanType
|
||||
overrides?: LicenseOverrides
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Feature, Hosting, License, PlanType, Quotas } from "../../sdk"
|
||||
import { DeepPartial } from "../../shared"
|
||||
import { QuotaUsage } from "../global"
|
||||
|
||||
export interface CreateAccount {
|
||||
|
@ -25,7 +26,7 @@ export const isCreatePasswordAccount = (
|
|||
|
||||
export interface LicenseOverrides {
|
||||
features?: Feature[]
|
||||
quotas?: Quotas
|
||||
quotas?: DeepPartial<Quotas>
|
||||
}
|
||||
|
||||
export interface Account extends CreateAccount {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from "./typeUtils"
|
|
@ -0,0 +1,3 @@
|
|||
export type DeepPartial<T> = {
|
||||
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.5.6-alpha.26",
|
||||
"version": "2.5.6-alpha.32",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -37,10 +37,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.5.6-alpha.26",
|
||||
"@budibase/pro": "2.5.6-alpha.26",
|
||||
"@budibase/string-templates": "2.5.6-alpha.26",
|
||||
"@budibase/types": "2.5.6-alpha.26",
|
||||
"@budibase/backend-core": "2.5.6-alpha.32",
|
||||
"@budibase/pro": "2.5.6-alpha.32",
|
||||
"@budibase/string-templates": "2.5.6-alpha.32",
|
||||
"@budibase/types": "2.5.6-alpha.32",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Account, AccountMetadata } from "@budibase/types"
|
||||
import { Account, AccountMetadata, Ctx } from "@budibase/types"
|
||||
import * as accounts from "../../../sdk/accounts"
|
||||
|
||||
export const save = async (ctx: any) => {
|
||||
export const save = async (ctx: Ctx<Account, AccountMetadata>) => {
|
||||
const account = ctx.request.body as Account
|
||||
let metadata: AccountMetadata = {
|
||||
_id: accounts.metadata.formatAccountMetadataId(account.accountId),
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
cellspacing="0"
|
||||
>
|
||||
<img
|
||||
width="32px"
|
||||
width="32"
|
||||
height="32"
|
||||
style="margin-right:16px; vertical-align: middle;"
|
||||
alt="Budibase Logo"
|
||||
src="https://i.imgur.com/Xhdt1YP.png"
|
||||
|
|
|
@ -8,8 +8,10 @@ function init() {
|
|||
const envFileJson = {
|
||||
BUDIBASE_URL: "http://localhost:10000",
|
||||
ACCOUNT_PORTAL_URL: "http://localhost:10001",
|
||||
ACCOUNT_PORTAL_API_KEY: "budibase",
|
||||
BB_ADMIN_USER_EMAIL: "admin",
|
||||
BB_ADMIN_USER_PASSWORD: "admin",
|
||||
LOG_LEVEL: "info",
|
||||
}
|
||||
let envFile = ""
|
||||
Object.keys(envFileJson).forEach(key => {
|
||||
|
|
|
@ -8,6 +8,7 @@ interface ApiOptions {
|
|||
method?: APIMethod
|
||||
body?: object
|
||||
headers?: HeadersInit | undefined
|
||||
internal?: boolean
|
||||
}
|
||||
|
||||
export default class AccountInternalAPIClient {
|
||||
|
@ -18,6 +19,9 @@ export default class AccountInternalAPIClient {
|
|||
if (!env.ACCOUNT_PORTAL_URL) {
|
||||
throw new Error("Must set ACCOUNT_PORTAL_URL env var")
|
||||
}
|
||||
if (!env.ACCOUNT_PORTAL_API_KEY) {
|
||||
throw new Error("Must set ACCOUNT_PORTAL_API_KEY env var")
|
||||
}
|
||||
this.host = `${env.ACCOUNT_PORTAL_URL}`
|
||||
this.state = state
|
||||
}
|
||||
|
@ -39,6 +43,13 @@ export default class AccountInternalAPIClient {
|
|||
credentials: "include",
|
||||
}
|
||||
|
||||
if (options.internal) {
|
||||
requestOptions.headers = {
|
||||
...requestOptions.headers,
|
||||
...{ "x-budibase-api-key": env.ACCOUNT_PORTAL_API_KEY },
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const response = await fetch(`${this.host}${url}`, requestOptions)
|
||||
|
||||
|
@ -50,15 +61,20 @@ export default class AccountInternalAPIClient {
|
|||
body = await response.text()
|
||||
}
|
||||
|
||||
const message = `${method} ${url} - ${response.status}
|
||||
Response body: ${JSON.stringify(body)}
|
||||
Request body: ${requestOptions.body}`
|
||||
const data = {
|
||||
request: requestOptions.body,
|
||||
response: body,
|
||||
}
|
||||
const message = `${method} ${url} - ${response.status}`
|
||||
|
||||
if (response.status > 499) {
|
||||
console.error(message)
|
||||
console.error(message, data)
|
||||
} else if (response.status >= 400) {
|
||||
console.warn(message)
|
||||
console.warn(message, data)
|
||||
} else {
|
||||
console.debug(message, data)
|
||||
}
|
||||
|
||||
return [response, body]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import AccountInternalAPIClient from "../AccountInternalAPIClient"
|
||||
import { Account, UpdateLicenseRequest } from "@budibase/types"
|
||||
import { Response } from "node-fetch"
|
||||
|
||||
export default class LicenseAPI {
|
||||
client: AccountInternalAPIClient
|
||||
|
@ -6,4 +8,18 @@ export default class LicenseAPI {
|
|||
constructor(client: AccountInternalAPIClient) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async updateLicense(
|
||||
accountId: string,
|
||||
body: UpdateLicenseRequest
|
||||
): Promise<[Response, Account]> {
|
||||
const [response, json] = await this.client.put(
|
||||
`/api/accounts/${accountId}/license`,
|
||||
{
|
||||
body,
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
return [response, json]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ if (!LOADED) {
|
|||
const env = {
|
||||
BUDIBASE_URL: process.env.BUDIBASE_URL,
|
||||
ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL,
|
||||
ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY,
|
||||
BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL,
|
||||
BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD,
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ class BudibaseInternalAPIClient {
|
|||
if (!env.BUDIBASE_URL) {
|
||||
throw new Error("Must set BUDIBASE_URL env var")
|
||||
}
|
||||
this.host = `${env.ACCOUNT_PORTAL_URL}/api`
|
||||
this.host = `${env.BUDIBASE_URL}/api`
|
||||
this.state = state
|
||||
}
|
||||
|
@ -53,14 +52,18 @@ class BudibaseInternalAPIClient {
|
|||
body = await response.text()
|
||||
}
|
||||
|
||||
const message = `${method} ${url} - ${response.status}
|
||||
Response body: ${JSON.stringify(body)}
|
||||
Request body: ${requestOptions.body}`
|
||||
const data = {
|
||||
request: requestOptions.body,
|
||||
response: body,
|
||||
}
|
||||
const message = `${method} ${url} - ${response.status}`
|
||||
|
||||
if (response.status > 499) {
|
||||
console.error(message)
|
||||
console.error(message, data)
|
||||
} else if (response.status >= 400) {
|
||||
console.warn(message)
|
||||
console.warn(message, data)
|
||||
} else {
|
||||
console.debug(message, data)
|
||||
}
|
||||
|
||||
return [response, body]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { DEFAULT_TENANT_ID, logging } from "@budibase/backend-core"
|
||||
import { AccountInternalAPI } from "../account-api"
|
||||
import * as fixtures from "../internal-api/fixtures"
|
||||
import { BudibaseInternalAPI } from "../internal-api"
|
||||
import { DEFAULT_TENANT_ID, logging } from "@budibase/backend-core"
|
||||
import { CreateAccountRequest } from "@budibase/types"
|
||||
import { CreateAccountRequest, Feature } from "@budibase/types"
|
||||
import env from "../environment"
|
||||
import { APIRequestOpts } from "../types"
|
||||
|
||||
|
@ -22,10 +22,35 @@ async function createAccount() {
|
|||
const account = fixtures.accounts.generateAccount()
|
||||
await accountsApi.accounts.validateEmail(account.email, API_OPTS)
|
||||
await accountsApi.accounts.validateTenantId(account.tenantId, API_OPTS)
|
||||
await accountsApi.accounts.create(account, API_OPTS)
|
||||
const [res, newAccount] = await accountsApi.accounts.create(account, API_OPTS)
|
||||
await updateLicense(newAccount.accountId)
|
||||
return account
|
||||
}
|
||||
|
||||
const UNLIMITED = { value: -1 }
|
||||
|
||||
async function updateLicense(accountId: string) {
|
||||
await accountsApi.licenses.updateLicense(accountId, {
|
||||
overrides: {
|
||||
// add all features
|
||||
features: Object.values(Feature),
|
||||
quotas: {
|
||||
usage: {
|
||||
monthly: {
|
||||
automations: UNLIMITED,
|
||||
},
|
||||
static: {
|
||||
rows: UNLIMITED,
|
||||
users: UNLIMITED,
|
||||
userGroups: UNLIMITED,
|
||||
plugins: UNLIMITED,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function loginAsAdmin() {
|
||||
const username = env.BB_ADMIN_USER_EMAIL!
|
||||
const password = env.BB_ADMIN_USER_PASSWORD!
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
import { logging } from "@budibase/backend-core"
|
||||
logging.LOG_CONTEXT = false
|
||||
|
||||
jest.setTimeout(60000)
|
||||
|
|
|
@ -51,14 +51,18 @@ class BudibasePublicAPIClient {
|
|||
body = await response.text()
|
||||
}
|
||||
|
||||
const message = `${method} ${url} - ${response.status}
|
||||
Response body: ${JSON.stringify(body)}
|
||||
Request body: ${requestOptions.body}`
|
||||
const data = {
|
||||
request: requestOptions.body,
|
||||
response: body,
|
||||
}
|
||||
const message = `${method} ${url} - ${response.status}`
|
||||
|
||||
if (response.status > 499) {
|
||||
console.error(message)
|
||||
console.error(message, data)
|
||||
} else if (response.status >= 400) {
|
||||
console.warn(message)
|
||||
console.warn(message, data)
|
||||
} else {
|
||||
console.debug(message, data)
|
||||
}
|
||||
|
||||
return [response, body]
|
||||
|
|
|
@ -3,9 +3,6 @@ import { AccountInternalAPI } from "../account-api"
|
|||
import { CreateAppRequest, State } from "../types"
|
||||
import * as fixtures from "../internal-api/fixtures"
|
||||
|
||||
// TEMP
|
||||
import setup from "../jest/globalSetup"
|
||||
|
||||
export default class BudibaseTestConfiguration {
|
||||
// apis
|
||||
internalApi: BudibaseInternalAPI
|
||||
|
@ -23,11 +20,6 @@ export default class BudibaseTestConfiguration {
|
|||
// LIFECYCLE
|
||||
|
||||
async beforeAll() {
|
||||
// TEMP - move back to single tenant when we integrate licensing with
|
||||
// the test run - need to use multiple tenants in cloud to get around
|
||||
// app limit restrictions
|
||||
await setup()
|
||||
|
||||
// @ts-ignore
|
||||
this.state.tenantId = global.qa.tenantId
|
||||
// @ts-ignore
|
||||
|
|
95
yarn.lock
95
yarn.lock
|
@ -1486,15 +1486,15 @@
|
|||
pouchdb-promise "^6.0.4"
|
||||
through2 "^2.0.0"
|
||||
|
||||
"@budibase/pro@2.5.6-alpha.25":
|
||||
version "2.5.6-alpha.25"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.5.6-alpha.25.tgz#bfe99536060422adb60da2f195acb05b24898c98"
|
||||
integrity sha512-LEQec9N9gS+j5gt/eKwGzci5oKW1sRTIG8oUvH7faCoJjD7BWIhmNuQNFrNfg70C/zkxYy4CL/2s1P9oVR1B3g==
|
||||
"@budibase/pro@2.5.6-alpha.32":
|
||||
version "2.5.6-alpha.32"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.5.6-alpha.32.tgz#6d52da231efcacbb163a5af0cfe8284199ff659e"
|
||||
integrity sha512-XzM55VcxpxTXCxYhLUOYvYqlCAPRPASJBbNonuRV6qUtXZxE5xSSEDnHQehhD8TrNP3QQ94DlCJ5DQCm/f3yJQ==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "2.5.6-alpha.25"
|
||||
"@budibase/backend-core" "2.5.6-alpha.32"
|
||||
"@budibase/shared-core" "2.4.44-alpha.1"
|
||||
"@budibase/string-templates" "2.4.44-alpha.1"
|
||||
"@budibase/types" "2.5.6-alpha.25"
|
||||
"@budibase/types" "2.5.6-alpha.32"
|
||||
"@koa/router" "8.0.8"
|
||||
bull "4.10.1"
|
||||
joi "17.6.0"
|
||||
|
@ -11129,7 +11129,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
|||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||
|
||||
fast-redact@^3.0.0:
|
||||
fast-redact@^3.0.0, fast-redact@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa"
|
||||
integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==
|
||||
|
@ -19203,7 +19203,7 @@ pinkie@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==
|
||||
|
||||
pino-abstract-transport@^1.0.0:
|
||||
pino-abstract-transport@^1.0.0, pino-abstract-transport@v1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3"
|
||||
integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==
|
||||
|
@ -19219,6 +19219,16 @@ pino-abstract-transport@v0.5.0:
|
|||
duplexify "^4.1.2"
|
||||
split2 "^4.0.0"
|
||||
|
||||
pino-http@8.3.3:
|
||||
version "8.3.3"
|
||||
resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-8.3.3.tgz#2b140e734bfc6babe0df272a43bb8f36f2b525c0"
|
||||
integrity sha512-p4umsNIXXVu95HD2C8wie/vXH7db5iGRpc+yj1/ZQ3sRtTQLXNjoS6Be5+eI+rQbqCRxen/7k/KSN+qiZubGDw==
|
||||
dependencies:
|
||||
get-caller-file "^2.0.5"
|
||||
pino "^8.0.0"
|
||||
pino-std-serializers "^6.0.0"
|
||||
process-warning "^2.0.0"
|
||||
|
||||
pino-http@^6.5.0:
|
||||
version "6.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-6.6.0.tgz#d0a1deacada8c93327fdaa48f5bdc94bc43d3407"
|
||||
|
@ -19264,7 +19274,42 @@ pino-std-serializers@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-5.6.0.tgz#31b141155d6520967c5ec72944d08fb45c490fd3"
|
||||
integrity sha512-VdUXCw8gO+xhir7sFuoYSjTnzB+TMDGxhAC/ph3YS3sdHnXNdsK0wMtADNUltfeGkn2KDxEM21fnjF3RwXyC8A==
|
||||
|
||||
pino@7.11.0, pino@^7.5.0:
|
||||
pino-std-serializers@^6.0.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.0.tgz#169048c0df3f61352fce56aeb7fb962f1b66ab43"
|
||||
integrity sha512-IWgSzUL8X1w4BIWTwErRgtV8PyOGOOi60uqv0oKuS/fOA8Nco/OeI6lBuc4dyP8MMfdFwyHqTMcBIA7nDiqEqA==
|
||||
|
||||
pino@8.11.0, pino@^8.0.0:
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/pino/-/pino-8.11.0.tgz#2a91f454106b13e708a66c74ebc1c2ab7ab38498"
|
||||
integrity sha512-Z2eKSvlrl2rH8p5eveNUnTdd4AjJk8tAsLkHYZQKGHP4WTh2Gi1cOSOs3eWPqaj+niS3gj4UkoreoaWgF3ZWYg==
|
||||
dependencies:
|
||||
atomic-sleep "^1.0.0"
|
||||
fast-redact "^3.1.1"
|
||||
on-exit-leak-free "^2.1.0"
|
||||
pino-abstract-transport v1.0.0
|
||||
pino-std-serializers "^6.0.0"
|
||||
process-warning "^2.0.0"
|
||||
quick-format-unescaped "^4.0.3"
|
||||
real-require "^0.2.0"
|
||||
safe-stable-stringify "^2.3.1"
|
||||
sonic-boom "^3.1.0"
|
||||
thread-stream "^2.0.0"
|
||||
|
||||
pino@^6.11.2:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78"
|
||||
integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==
|
||||
dependencies:
|
||||
fast-redact "^3.0.0"
|
||||
fast-safe-stringify "^2.0.8"
|
||||
flatstr "^1.0.12"
|
||||
pino-std-serializers "^3.1.0"
|
||||
process-warning "^1.0.0"
|
||||
quick-format-unescaped "^4.0.3"
|
||||
sonic-boom "^1.0.2"
|
||||
|
||||
pino@^7.5.0:
|
||||
version "7.11.0"
|
||||
resolved "https://registry.yarnpkg.com/pino/-/pino-7.11.0.tgz#0f0ea5c4683dc91388081d44bff10c83125066f6"
|
||||
integrity sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==
|
||||
|
@ -19281,19 +19326,6 @@ pino@7.11.0, pino@^7.5.0:
|
|||
sonic-boom "^2.2.1"
|
||||
thread-stream "^0.15.1"
|
||||
|
||||
pino@^6.11.2:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78"
|
||||
integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==
|
||||
dependencies:
|
||||
fast-redact "^3.0.0"
|
||||
fast-safe-stringify "^2.0.8"
|
||||
flatstr "^1.0.12"
|
||||
pino-std-serializers "^3.1.0"
|
||||
process-warning "^1.0.0"
|
||||
quick-format-unescaped "^4.0.3"
|
||||
sonic-boom "^1.0.2"
|
||||
|
||||
pirates@^4.0.1, pirates@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b"
|
||||
|
@ -20169,6 +20201,11 @@ process-warning@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616"
|
||||
integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==
|
||||
|
||||
process-warning@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626"
|
||||
integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==
|
||||
|
||||
process@^0.11.10:
|
||||
version "0.11.10"
|
||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||
|
@ -20772,6 +20809,11 @@ real-require@^0.1.0:
|
|||
resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381"
|
||||
integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==
|
||||
|
||||
real-require@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78"
|
||||
integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==
|
||||
|
||||
recast@^0.10.1:
|
||||
version "0.10.43"
|
||||
resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f"
|
||||
|
@ -22151,7 +22193,7 @@ sonic-boom@^2.2.1:
|
|||
dependencies:
|
||||
atomic-sleep "^1.0.0"
|
||||
|
||||
sonic-boom@^3.0.0:
|
||||
sonic-boom@^3.0.0, sonic-boom@^3.1.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.3.0.tgz#cffab6dafee3b2bcb88d08d589394198bee1838c"
|
||||
integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==
|
||||
|
@ -23323,6 +23365,13 @@ thread-stream@^0.15.1:
|
|||
dependencies:
|
||||
real-require "^0.1.0"
|
||||
|
||||
thread-stream@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33"
|
||||
integrity sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==
|
||||
dependencies:
|
||||
real-require "^0.2.0"
|
||||
|
||||
throat@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
|
||||
|
|
Loading…
Reference in New Issue