Merge remote-tracking branch 'origin/master' into feat/pwa-apps

This commit is contained in:
Peter Clement 2025-04-02 10:06:19 +01:00
commit 104731a885
44 changed files with 1333 additions and 154 deletions

View File

@ -211,9 +211,12 @@ const localeDateFormat = new Intl.DateTimeFormat()
// Formats a dayjs date according to schema flags
export const getDateDisplayValue = (
value: dayjs.Dayjs | null,
value: dayjs.Dayjs | string | null,
{ enableTime = true, timeOnly = false } = {}
): string => {
if (typeof value === "string") {
value = dayjs(value)
}
if (!value?.isValid()) {
return ""
}

View File

@ -80,5 +80,6 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 4px;
}
</style>

View File

@ -22,6 +22,7 @@ import ValidationEditor from "./controls/ValidationEditor/ValidationEditor.svelt
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
import ColumnEditor from "./controls/ColumnEditor/ColumnEditor.svelte"
import BasicColumnEditor from "./controls/ColumnEditor/BasicColumnEditor.svelte"
import TopLevelColumnEditor from "./controls/ColumnEditor/TopLevelColumnEditor.svelte"
import GridColumnEditor from "./controls/GridColumnConfiguration/GridColumnConfiguration.svelte"
import BarButtonList from "./controls/BarButtonList.svelte"
import FieldConfiguration from "./controls/FieldConfiguration/FieldConfiguration.svelte"
@ -62,7 +63,10 @@ const componentMap = {
stepConfiguration: FormStepConfiguration,
formStepControls: FormStepControls,
columns: ColumnEditor,
// "Basic" actually includes nested JSON and relationship fields
"columns/basic": BasicColumnEditor,
// "Top level" is only the top level schema fields
"columns/toplevel": TopLevelColumnEditor,
"columns/grid": GridColumnEditor,
tableConditions: TableConditionEditor,
"field/sortable": SortableFieldSelect,

View File

@ -145,7 +145,7 @@
<div class="column">
<div class="wide">
<Body size="S">
By default, all columns will automatically be shown.
The default column configuration will automatically be shown.
<br />
You can manually control which columns are included by adding them
below.

View File

@ -10,10 +10,18 @@
} from "@/dataBinding"
import { selectedScreen, tables } from "@/stores/builder"
export let componentInstance
const getSearchableFields = (schema, tableList) => {
return search.getFields(tableList, Object.values(schema || {}), {
allowLinks: true,
})
}
export let componentInstance = undefined
export let value = []
export let allowCellEditing = true
export let allowReorder = true
export let getSchemaFields = getSearchableFields
export let placeholder = "All columns"
const dispatch = createEventDispatcher()
@ -28,13 +36,7 @@
: enrichedSchemaFields?.map(field => field.name)
$: sanitisedValue = getValidColumns(value, options)
$: updateBoundValue(sanitisedValue)
$: enrichedSchemaFields = search.getFields(
$tables.list,
Object.values(schema || {}),
{
allowLinks: true,
}
)
$: enrichedSchemaFields = getSchemaFields(schema, $tables.list)
$: {
value = (value || []).filter(
@ -44,7 +46,7 @@
const getText = value => {
if (!value?.length) {
return "All columns"
return placeholder
}
let text = `${value.length} column`
if (value.length !== 1) {

View File

@ -0,0 +1,15 @@
<script lang="ts">
import ColumnEditor from "./ColumnEditor.svelte"
import type { TableSchema } from "@budibase/types"
const getTopLevelSchemaFields = (schema: TableSchema) => {
return Object.values(schema).filter(fieldSchema => !fieldSchema.nestedJSON)
}
</script>
<ColumnEditor
{...$$props}
on:change
allowCellEditing={false}
getSchemaFields={getTopLevelSchemaFields}
/>

View File

@ -71,4 +71,5 @@ export const AutoScreenTypes = {
BLANK: "blank",
TABLE: "table",
FORM: "form",
PDF: "pdf",
}

View File

@ -26,7 +26,7 @@ import {
getJsHelperList,
} from "@budibase/string-templates"
import { TableNames } from "./constants"
import { JSONUtils, Constants } from "@budibase/frontend-core"
import { JSONUtils, Constants, SchemaUtils } from "@budibase/frontend-core"
import ActionDefinitions from "@/components/design/settings/controls/ButtonActionEditor/manifest.json"
import { environment, licensing } from "@/stores/portal"
import { convertOldFieldFormat } from "@/components/design/settings/controls/FieldConfiguration/utils"
@ -1026,25 +1026,7 @@ export const getSchemaForDatasource = (asset, datasource, options) => {
// Check for any JSON fields so we can add any top level properties
if (schema) {
let jsonAdditions = {}
Object.keys(schema).forEach(fieldKey => {
const fieldSchema = schema[fieldKey]
if (fieldSchema?.type === "json") {
const jsonSchema = JSONUtils.convertJSONSchemaToTableSchema(
fieldSchema,
{
squashObjects: true,
}
)
Object.keys(jsonSchema).forEach(jsonKey => {
jsonAdditions[`${fieldKey}.${jsonKey}`] = {
type: jsonSchema[jsonKey].type,
nestedJSON: true,
}
})
}
})
schema = { ...schema, ...jsonAdditions }
schema = SchemaUtils.addNestedJSONSchemaFields(schema)
}
// Determine if we should add ID and rev to the schema

View File

@ -16,6 +16,7 @@
import { getBindableProperties } from "@/dataBinding"
import BarButtonList from "@/components/design/settings/controls/BarButtonList.svelte"
import URLVariableTestInput from "@/components/design/settings/controls/URLVariableTestInput.svelte"
import { DrawerBindableInput } from "@/components/common/bindings"
$: bindings = getBindableProperties($selectedScreen, null)
$: screenSettings = getScreenSettings($selectedScreen)
@ -23,7 +24,59 @@
let errors = {}
const getScreenSettings = screen => {
let settings = [
// Determine correct screen settings for the top level component
let screenComponentSettings = []
switch ($selectedScreen.props._component) {
case "@budibase/standard-components/pdf":
screenComponentSettings = [
{
key: "props.fileName",
label: "PDF title",
defaultValue: "Report",
control: DrawerBindableInput,
},
{
key: "props.buttonText",
label: "Button text",
defaultValue: "Download PDF",
control: DrawerBindableInput,
},
]
break
default:
screenComponentSettings = [
{
key: "width",
label: "Width",
control: Select,
props: {
options: ["Extra small", "Small", "Medium", "Large", "Max"],
placeholder: "Default",
disabled: !!screen.layoutId,
},
},
{
key: "props.layout",
label: "Layout",
defaultValue: "flex",
control: BarButtonList,
props: {
options: [
{
barIcon: "ModernGridView",
value: "flex",
},
{
barIcon: "ViewGrid",
value: "grid",
},
],
},
},
]
}
return [
{
key: "routing.homeScreen",
control: Checkbox,
@ -66,34 +119,7 @@
label: "On screen load",
control: ButtonActionEditor,
},
{
key: "width",
label: "Width",
control: Select,
props: {
options: ["Extra small", "Small", "Medium", "Large", "Max"],
placeholder: "Default",
disabled: !!screen.layoutId,
},
},
{
key: "props.layout",
label: "Layout",
defaultValue: "flex",
control: BarButtonList,
props: {
options: [
{
barIcon: "ModernGridView",
value: "flex",
},
{
barIcon: "ViewGrid",
value: "grid",
},
],
},
},
...screenComponentSettings,
{
key: "urlTest",
control: URLVariableTestInput,
@ -102,8 +128,6 @@
},
},
]
return settings
}
const routeTaken = url => {

View File

@ -26,7 +26,9 @@
<div class="info">
<Icon name="InfoOutline" size="S" />
<Body size="S">These settings apply to all screens</Body>
<Body size="S">
These settings apply to all screens. PDFs are always light theme.
</Body>
</div>
<Layout noPadding gap="S">
<Layout noPadding gap="XS">

View File

@ -58,7 +58,7 @@
// Get initial set of allowed components
let allowedComponents = []
const definition = componentStore.getDefinition(component?._component)
if (definition.legalDirectChildren?.length) {
if (definition?.legalDirectChildren?.length) {
allowedComponents = definition.legalDirectChildren.map(x => {
return `@budibase/standard-components/${x}`
})
@ -67,7 +67,7 @@
}
// Build up list of illegal children from ancestors
let illegalChildren = definition.illegalChildren || []
let illegalChildren = definition?.illegalChildren || []
path.forEach(ancestor => {
// Sidepanels and modals can be nested anywhere in the component tree, but really they are always rendered at the top level.
// Because of this, it doesn't make sense to carry over any parent illegal children to them, so the array is reset here.
@ -144,11 +144,6 @@
}
})
// Swap blocks and plugins
let tmp = enrichedStructure[1]
enrichedStructure[1] = enrichedStructure[0]
enrichedStructure[0] = tmp
return enrichedStructure
}

View File

@ -20,9 +20,11 @@
"name": "Data",
"icon": "Data",
"children": [
"singlerowprovider",
"dataprovider",
"repeater",
"gridblock",
"pdftable",
"spreadsheet",
"dynamicfilter",
"daterangepicker"

View File

@ -1,10 +1,13 @@
<script>
import DevicePreviewSelect from "./DevicePreviewSelect.svelte"
import AppPreview from "./AppPreview.svelte"
import { screenStore, appStore } from "@/stores/builder"
import { screenStore, appStore, selectedScreen } from "@/stores/builder"
import UndoRedoControl from "@/components/common/UndoRedoControl.svelte"
import ScreenErrorsButton from "./ScreenErrorsButton.svelte"
import { Divider } from "@budibase/bbui"
import { ScreenVariant } from "@budibase/types"
$: isPDF = $selectedScreen?.variant === ScreenVariant.PDF
</script>
<div class="app-panel">
@ -14,10 +17,12 @@
<UndoRedoControl store={screenStore.history} />
</div>
<div class="header-right">
{#if $appStore.clientFeatures.devicePreview}
<DevicePreviewSelect />
{#if !isPDF}
{#if $appStore.clientFeatures.devicePreview}
<DevicePreviewSelect />
{/if}
<Divider vertical />
{/if}
<Divider vertical />
<ScreenErrorsButton />
</div>
</div>

View File

@ -53,7 +53,7 @@
// Otherwise choose a datasource
datasourceModal.show()
}
} else if (mode === AutoScreenTypes.BLANK) {
} else if (mode === AutoScreenTypes.BLANK || mode === AutoScreenTypes.PDF) {
screenDetailsModal.show()
} else {
throw new Error("Invalid mode provided")
@ -101,8 +101,11 @@
}
}
const createBlankScreen = async ({ route }) => {
const screenTemplates = screenTemplating.blank({ route, screens })
const createBasicScreen = async ({ route }) => {
const screenTemplates =
mode === AutoScreenTypes.BLANK
? screenTemplating.blank({ route, screens })
: screenTemplating.pdf({ route, screens })
const newScreens = await createScreens(screenTemplates)
loadNewScreen(newScreens[0])
}
@ -243,7 +246,7 @@
</Modal>
<Modal bind:this={screenDetailsModal}>
<ScreenDetailsModal onConfirm={createBlankScreen} />
<ScreenDetailsModal onConfirm={createBasicScreen} />
</Modal>
<Modal bind:this={formTypeModal}>

View File

@ -0,0 +1,38 @@
<svg width="118" height="65" viewBox="0 0 118 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1099_17726)">
<g clip-path="url(#clip1_1099_17726)" filter="url(#filter0_d_1099_17726)">
<rect width="118" height="65" fill="#D8B500"/>
<mask id="mask0_1099_17726" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="118" height="65">
<rect width="118" height="65" fill="white"/>
</mask>
<g mask="url(#mask0_1099_17726)">
</g>
</g>
<rect x="38.0762" y="22.3271" width="41.6766" height="42.6718" fill="white" fill-opacity="0.5"/>
<rect x="23.1543" y="11.4121" width="71.3021" height="53.5878" fill="url(#paint0_linear_1099_17726)"/>
<rect x="23.6543" y="11.9121" width="70.3021" height="52.5878" stroke="white" stroke-opacity="0.2"/>
<path d="M44.1365 45.7637V34.0637H48.4205C49.2725 34.0637 50.0585 34.1837 50.7785 34.4237C51.4985 34.6637 52.0745 35.0657 52.5065 35.6297C52.9505 36.1937 53.1725 36.9677 53.1725 37.9517C53.1725 38.8997 52.9505 39.6797 52.5065 40.2917C52.0745 40.8917 51.4985 41.3357 50.7785 41.6237C50.0705 41.9117 49.3085 42.0557 48.4925 42.0557H47.2325V45.7637H44.1365ZM47.2325 39.6077H48.3485C48.9605 39.6077 49.4105 39.4637 49.6985 39.1757C49.9985 38.8757 50.1485 38.4677 50.1485 37.9517C50.1485 37.4237 49.9865 37.0517 49.6625 36.8357C49.3385 36.6197 48.8765 36.5117 48.2765 36.5117H47.2325V39.6077ZM55.0877 45.7637V34.0637H58.5437C59.7317 34.0637 60.7757 34.2617 61.6757 34.6577C62.5877 35.0417 63.2957 35.6597 63.7997 36.5117C64.3037 37.3637 64.5557 38.4797 64.5557 39.8597C64.5557 41.2397 64.3037 42.3677 63.7997 43.2437C63.2957 44.1077 62.6057 44.7437 61.7297 45.1517C60.8537 45.5597 59.8517 45.7637 58.7237 45.7637H55.0877ZM58.1837 43.2797H58.3637C58.9277 43.2797 59.4377 43.1837 59.8937 42.9917C60.3497 42.7997 60.7097 42.4577 60.9737 41.9657C61.2497 41.4737 61.3877 40.7717 61.3877 39.8597C61.3877 38.9477 61.2497 38.2577 60.9737 37.7897C60.7097 37.3097 60.3497 36.9857 59.8937 36.8177C59.4377 36.6377 58.9277 36.5477 58.3637 36.5477H58.1837V43.2797ZM66.6365 45.7637V34.0637H74.2685V36.6557H69.7325V38.8877H73.6205V41.4797H69.7325V45.7637H66.6365Z" fill="white"/>
</g>
<defs>
<filter id="filter0_d_1099_17726" x="-10" y="-6" width="138" height="85" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1099_17726"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1099_17726" result="shape"/>
</filter>
<linearGradient id="paint0_linear_1099_17726" x1="23.1543" y1="11.4121" x2="94.0187" y2="65.5726" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.6"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_1099_17726">
<rect width="118" height="65" fill="white"/>
</clipPath>
<clipPath id="clip1_1099_17726">
<rect width="118" height="65" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -4,8 +4,10 @@
import blank from "./images/blank.svg"
import table from "./images/tableInline.svg"
import form from "./images/formUpdate.svg"
import pdf from "./images/pdf.svg"
import CreateScreenModal from "./CreateScreenModal.svelte"
import { screenStore } from "@/stores/builder"
import { AutoScreenTypes } from "@/constants"
export let onClose = null
@ -27,32 +29,54 @@
</div>
<div class="cards">
<div class="card" on:click={() => createScreenModal.show("blank")}>
<div
class="card"
on:click={() => createScreenModal.show(AutoScreenTypes.BLANK)}
>
<div class="image">
<img alt="A blank screen" src={blank} />
</div>
<div class="text">
<Body size="S">Blank</Body>
<Body size="M">Blank</Body>
<Body size="XS">Add an empty blank screen</Body>
</div>
</div>
<div class="card" on:click={() => createScreenModal.show("table")}>
<div
class="card"
on:click={() => createScreenModal.show(AutoScreenTypes.TABLE)}
>
<div class="image">
<img alt="A table of data" src={table} />
</div>
<div class="text">
<Body size="S">Table</Body>
<Body size="M">Table</Body>
<Body size="XS">List rows in a table</Body>
</div>
</div>
<div class="card" on:click={() => createScreenModal.show("form")}>
<div
class="card"
on:click={() => createScreenModal.show(AutoScreenTypes.PDF)}
>
<div class="image">
<img alt="A form containing data" src={pdf} width="185" />
</div>
<div class="text">
<Body size="M">PDF</Body>
<Body size="XS">Create, edit and export your PDF</Body>
</div>
</div>
<div
class="card"
on:click={() => createScreenModal.show(AutoScreenTypes.FORM)}
>
<div class="image">
<img alt="A form containing data" src={form} />
</div>
<div class="text">
<Body size="S">Form</Body>
<Body size="M">Form</Body>
<Body size="XS">Capture data from your users</Body>
</div>
</div>
@ -111,14 +135,13 @@
.text {
border: 1px solid var(--grey-4);
border-radius: 0 0 4px 4px;
padding: 8px 16px 13px 16px;
}
.text :global(p:nth-child(1)) {
margin-bottom: 6px;
padding: 12px 16px 12px 16px;
display: flex;
flex-direction: column;
gap: 2px;
}
.text :global(p:nth-child(2)) {
color: var(--grey-6);
color: var(--spectrum-global-color-gray-600);
}
</style>

View File

@ -4,22 +4,24 @@ import { Helpers } from "@budibase/bbui"
import { RoleUtils, Utils } from "@budibase/frontend-core"
import { findAllMatchingComponents } from "@/helpers/components"
import {
layoutStore,
appStore,
componentStore,
layoutStore,
navigationStore,
previewStore,
selectedComponent,
} from "@/stores/builder"
import { createHistoryStore, HistoryStore } from "@/stores/builder/history"
import { API } from "@/api"
import { BudiStore } from "../BudiStore"
import {
FetchAppPackageResponse,
DeleteScreenResponse,
Screen,
Component,
SaveScreenResponse,
ComponentDefinition,
DeleteScreenResponse,
FetchAppPackageResponse,
SaveScreenResponse,
Screen,
ScreenVariant,
} from "@budibase/types"
interface ScreenState {
@ -115,6 +117,14 @@ export class ScreenStore extends BudiStore<ScreenState> {
state.selectedScreenId = screen._id
return state
})
// If this is a PDF screen, ensure we're on desktop
if (
screen.variant === ScreenVariant.PDF &&
get(previewStore).previewDevice !== "desktop"
) {
previewStore.setDevice("desktop")
}
}
/**

View File

@ -1,5 +1,6 @@
import { BaseStructure } from "../BaseStructure"
import { Helpers } from "@budibase/bbui"
import { ScreenVariant } from "@budibase/types"
export class Screen extends BaseStructure {
constructor() {
@ -81,3 +82,25 @@ export class Screen extends BaseStructure {
return this
}
}
export class PDFScreen extends Screen {
constructor() {
super()
this._json.variant = ScreenVariant.PDF
this._json.width = "Max"
this._json.showNavigation = false
this._json.props = {
_id: Helpers.uuid(),
_component: "@budibase/standard-components/pdf",
_styles: {
normal: {},
hover: {},
active: {},
selected: {},
},
_children: [],
_instanceName: "PDF",
title: "PDF",
}
}
}

View File

@ -1,3 +1,4 @@
export { default as blank } from "./blank"
export { default as form } from "./form"
export { default as table } from "./table"
export { default as pdf } from "./pdf"

View File

@ -0,0 +1,20 @@
import { PDFScreen } from "./Screen"
import { capitalise } from "@/helpers"
import getValidRoute from "./getValidRoute"
import { Roles } from "@/constants/backend"
const pdf = ({ route, screens }) => {
const validRoute = getValidRoute(screens, route, Roles.BASIC)
const template = new PDFScreen().role(Roles.BASIC).route(validRoute).json()
return [
{
data: template,
navigationLinkLabel:
validRoute === "/" ? null : capitalise(validRoute.split("/")[1]),
},
]
}
export default pdf

View File

@ -8017,6 +8017,32 @@
"key": "text",
"wide": true
},
{
"type": "select",
"label": "Size",
"key": "size",
"defaultValue": "14px",
"showInBar": true,
"placeholder": "Default",
"options": [
{
"label": "Small",
"value": "12px"
},
{
"label": "Medium",
"value": "14px"
},
{
"label": "Large",
"value": "18px"
},
{
"label": "Extra large",
"value": "24px"
}
]
},
{
"type": "select",
"label": "Alignment",
@ -8058,5 +8084,133 @@
"showInBar": true
}
]
},
"pdf": {
"name": "PDF Generator",
"icon": "Document",
"hasChildren": true,
"showEmptyState": false,
"illegalChildren": ["sidepanel", "modal", "gridblock"],
"grid": {
"hAlign": "center",
"vAlign": "start"
},
"size": {
"width": 800,
"height": 1200
},
"description": "A component to render PDFs from other Budibase components",
"settings": [
{
"type": "text",
"label": "PDF title",
"key": "fileName",
"defaultValue": "Report"
},
{
"type": "text",
"label": "Button text",
"key": "buttonText",
"defaultValue": "Download PDF"
}
]
},
"pdftable": {
"name": "PDF Table",
"icon": "Table",
"styles": ["size"],
"size": {
"width": 600,
"height": 304
},
"grid": {
"hAlign": "stretch",
"vAlign": "stretch"
},
"settings": [
{
"type": "dataSource",
"label": "Data",
"key": "datasource",
"required": true
},
{
"type": "filter",
"label": "Filtering",
"key": "filter",
"resetOn": "datasource",
"dependsOn": {
"setting": "datasource.type",
"value": "custom",
"invert": true
}
},
{
"type": "field/sortable",
"label": "Sort column",
"key": "sortColumn",
"placeholder": "Default",
"resetOn": "datasource",
"dependsOn": {
"setting": "datasource.type",
"value": "custom",
"invert": true
}
},
{
"type": "select",
"label": "Sort order",
"key": "sortOrder",
"resetOn": "datasource",
"options": ["Ascending", "Descending"],
"defaultValue": "Ascending",
"dependsOn": "sortColumn"
},
{
"type": "columns/toplevel",
"label": "Columns",
"key": "columns",
"resetOn": "datasource",
"placeholder": "First 3 columns"
},
{
"type": "number",
"label": "Limit",
"key": "limit",
"defaultValue": 10
}
]
},
"singlerowprovider": {
"name": "Single Row Provider",
"icon": "SQLQuery",
"hasChildren": true,
"actions": ["RefreshDatasource"],
"size": {
"width": 500,
"height": 200
},
"grid": {
"hAlign": "stretch",
"vAlign": "stretch"
},
"settings": [
{
"type": "table",
"label": "Datasource",
"key": "datasource",
"required": true
},
{
"type": "text",
"label": "Row ID",
"key": "rowId",
"required": true,
"resetOn": "datasource"
}
],
"context": {
"type": "schema"
}
}
}

View File

@ -29,6 +29,7 @@
"apexcharts": "^3.48.0",
"dayjs": "^1.10.8",
"downloadjs": "1.4.7",
"html2pdf.js": "^0.9.3",
"html5-qrcode": "^2.3.8",
"leaflet": "^1.7.1",
"sanitize-html": "^2.13.0",

View File

@ -1,20 +1,20 @@
<script>
import { getContext, onDestroy } from "svelte"
import { generate } from "shortid"
import { builderStore } from "../stores/builder"
import { builderStore } from "@/stores/builder"
import Component from "@/components/Component.svelte"
export let type
export let props
export let styles
export let context
export let name
export let props = undefined
export let styles = undefined
export let context = undefined
export let name = undefined
export let order = 0
export let containsSlot = false
// ID is only exposed as a prop so that it can be bound to from parent
// block components
export let id
export let id = undefined
const component = getContext("component")
const block = getContext("block")

View File

@ -196,8 +196,6 @@
}
// Metadata to pass into grid action to apply CSS
const checkGrid = x =>
x?._component?.endsWith("/container") && x?.layout === "grid"
$: insideGrid = checkGrid(parent)
$: isGrid = checkGrid(instance)
$: gridMetadata = {
@ -601,6 +599,18 @@
}
}
const checkGrid = x => {
// Check for a grid container
if (x?._component?.endsWith("/container") && x?.layout === "grid") {
return true
}
// Check for a PDF (always grid)
if (x?._component?.endsWith("/pdf")) {
return true
}
return false
}
onMount(() => {
// Register this component instance for external access
if ($appStore.isDevApp) {

View File

@ -1,12 +1,18 @@
<script>
import { themeStore } from "@/stores"
import { setContext } from "svelte"
import { Context } from "@budibase/bbui"
import { Context, Helpers } from "@budibase/bbui"
setContext(Context.PopoverRoot, "#theme-root")
export let popoverRoot = true
const id = Helpers.uuid()
if (popoverRoot) {
setContext(Context.PopoverRoot, `#id`)
}
</script>
<div style={$themeStore.customThemeCss} id="theme-root">
<div style={$themeStore.customThemeCss} {id}>
<slot />
</div>

View File

@ -0,0 +1,46 @@
<script lang="ts">
import { getContext } from "svelte"
import type { Row, TableDatasource, ViewDatasource } from "@budibase/types"
export let datasource: TableDatasource | ViewDatasource
export let rowId: string
const component = getContext("component")
const { styleable, API, Provider, ActionTypes } = getContext("sdk")
let row: Row | undefined
$: datasourceId =
datasource.type === "table" ? datasource.tableId : datasource.id
$: fetchRow(datasourceId, rowId)
$: actions = [
{
type: ActionTypes.RefreshDatasource,
callback: () => fetchRow(datasourceId, rowId),
metadata: { dataSource: datasource },
},
]
const fetchRow = async (datasourceId: string, rowId: string) => {
try {
row = await API.fetchRow(datasourceId, rowId)
} catch (e) {
row = undefined
}
}
</script>
<div use:styleable={$component.styles}>
<Provider {actions} data={row ?? null}>
<slot />
</Provider>
</div>
<style>
div {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
</style>

View File

@ -5,12 +5,13 @@
export let text: any = ""
export let color: string | undefined = undefined
export let align: "left" | "center" | "right" | "justify" = "left"
export let size: string | undefined = "14px"
const component = getContext("component")
const { styleable } = getContext("sdk")
// Add in certain settings to styles
$: styles = enrichStyles($component.styles, color, align)
$: styles = enrichStyles($component.styles, color, align, size)
// Ensure we're always passing in a string value to the markdown editor
$: safeText = stringify(text)
@ -18,10 +19,12 @@
const enrichStyles = (
styles: any,
colorStyle: typeof color,
alignStyle: typeof align
alignStyle: typeof align,
size: string | undefined
) => {
let additions: Record<string, string> = {
"text-align": alignStyle,
"font-size": size || "14px",
}
if (colorStyle) {
additions.color = colorStyle

View File

@ -135,12 +135,18 @@
use:styleable={$styles}
data-cols={GridColumns}
data-col-size={colSize}
data-required-rows={requiredRows}
on:click={onClick}
>
{#if inBuilder}
<div class="underlay">
{#each { length: GridColumns * rows } as _, idx}
<div class="placeholder" class:first-col={idx % GridColumns === 0} />
<div class="underlay-h">
{#each { length: rows } as _}
<div class="placeholder-h" />
{/each}
</div>
<div class="underlay-v">
{#each { length: GridColumns } as _}
<div class="placeholder-v" />
{/each}
</div>
{/if}
@ -151,7 +157,8 @@
<style>
.grid,
.underlay {
.underlay-h,
.underlay-v {
height: var(--height) !important;
min-height: var(--min-height) !important;
max-height: none !important;
@ -161,37 +168,45 @@
grid-template-columns: repeat(var(--cols), calc(var(--col-size) * 1px));
position: relative;
}
.underlay {
.clickable {
cursor: pointer;
}
/* Underlay grid lines */
.underlay-h,
.underlay-v {
z-index: 0;
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-top: 1px solid var(--spectrum-global-color-gray-900);
opacity: 0.1;
pointer-events: none;
}
.underlay {
z-index: 0;
}
.placeholder {
.placeholder-h {
border-bottom: 1px solid var(--spectrum-global-color-gray-900);
grid-column: 1 / -1;
}
.placeholder-h:first-child {
border-top: 1px solid var(--spectrum-global-color-gray-900);
}
.placeholder-v {
border-right: 1px solid var(--spectrum-global-color-gray-900);
grid-row: 1 / -1;
}
.placeholder.first-col {
.placeholder-v:first-child {
border-left: 1px solid var(--spectrum-global-color-gray-900);
}
.clickable {
cursor: pointer;
}
/* Highlight grid lines when resizing children */
:global(.grid.highlight > .underlay) {
:global(.grid.highlight > .underlay-h),
:global(.grid.highlight > .underlay-v) {
display: grid;
}
/* Highlight sibling borders when resizing childern */
/* Highlight sibling borders when resizing children */
:global(.grid.highlight > .component:not(.dragging)) {
outline: 2px solid var(--spectrum-global-color-static-blue-200);
pointer-events: none !important;

View File

@ -36,10 +36,12 @@ export { default as sidepanel } from "./SidePanel.svelte"
export { default as modal } from "./Modal.svelte"
export { default as gridblock } from "./GridBlock.svelte"
export { default as textv2 } from "./Text.svelte"
export { default as singlerowprovider } from "./SingleRowProvider.svelte"
export * from "./charts"
export * from "./forms"
export * from "./blocks"
export * from "./dynamic-filter"
export * from "./pdf"
// Deprecated component left for compatibility in old apps
export * from "./deprecated/table"

View File

@ -0,0 +1,191 @@
<script lang="ts">
import { getContext, onMount, tick } from "svelte"
import { Heading, Button } from "@budibase/bbui"
import { htmlToPdf, pxToPt, A4HeightPx, type PDFOptions } from "./pdf"
import { GridRowHeight } from "@/constants"
import CustomThemeWrapper from "@/components/CustomThemeWrapper.svelte"
const component = getContext("component")
const { styleable, Block, BlockComponent } = getContext("sdk")
export let fileName: string | undefined
export let buttonText: string | undefined
// Derive dimension calculations
const DesiredRows = 40
const innerPageHeightPx = GridRowHeight * DesiredRows
const doubleMarginPx = A4HeightPx - innerPageHeightPx
const marginPt = pxToPt(doubleMarginPx / 2)
let rendering = false
let pageCount = 1
let ref: HTMLElement
let gridRef: HTMLElement
$: safeName = fileName || "Report"
$: safeButtonText = buttonText || "Download PDF"
$: heightPx = pageCount * innerPageHeightPx + doubleMarginPx
$: pageStyle = `--height:${heightPx}px; --margin:${marginPt}pt;`
$: gridMinHeight = pageCount * DesiredRows * GridRowHeight
const generatePDF = async () => {
rendering = true
await tick()
preprocessCSS()
try {
const opts: PDFOptions = {
fileName: safeName,
marginPt,
footer: true,
}
await htmlToPdf(ref, opts)
} catch (error) {
console.error("Error rendering PDF", error)
}
rendering = false
}
const preprocessCSS = () => {
const els = document.getElementsByClassName("grid-child")
for (let el of els) {
if (!(el instanceof HTMLElement)) {
return
}
// Get the computed values and assign them back to the style, simplifying
// the CSS that gets handled by HTML2PDF
const styles = window.getComputedStyle(el)
el.style.setProperty("grid-column-end", styles.gridColumnEnd, "important")
}
}
const getDividerStyle = (idx: number) => {
const top = (idx + 1) * innerPageHeightPx + doubleMarginPx / 2
return `--idx:"${idx + 1}"; --top:${top}px;`
}
const handleGridMutation = () => {
const rows = parseInt(gridRef.dataset.requiredRows || "1")
const nextPageCount = Math.max(1, Math.ceil(rows / DesiredRows))
if (nextPageCount > pageCount || !gridRef.classList.contains("highlight")) {
pageCount = nextPageCount
}
}
onMount(() => {
// Observe required content rows and use this to determine required pages
const gridDOMID = `${$component.id}-grid-dom`
gridRef = document.getElementsByClassName(gridDOMID)[0] as HTMLElement
const mutationObserver = new MutationObserver(handleGridMutation)
mutationObserver.observe(gridRef, {
attributes: true,
attributeFilter: ["data-required-rows", "class"],
})
return () => {
mutationObserver.disconnect()
}
})
</script>
<Block>
<div class="wrapper" style="--margin:{marginPt}pt;">
<div class="container" use:styleable={$component.styles}>
<div class="title">
<Heading size="M">{safeName}</Heading>
<Button disabled={rendering} cta on:click={generatePDF}>
{safeButtonText}
</Button>
</div>
<div class="page" style={pageStyle}>
{#if pageCount > 1}
{#each { length: pageCount } as _, idx}
<div
class="divider"
class:last={idx === pageCount - 1}
style={getDividerStyle(idx)}
/>
{/each}
{/if}
<div
class="spectrum spectrum--medium spectrum--light pageContent"
bind:this={ref}
>
<CustomThemeWrapper popoverRoot={false}>
<BlockComponent
type="container"
props={{ layout: "grid" }}
styles={{
normal: {
height: `${gridMinHeight}px`,
},
}}
context="grid"
>
<slot />
</BlockComponent>
</CustomThemeWrapper>
</div>
</div>
</div>
</div>
</Block>
<style>
.wrapper {
width: 100%;
height: 100%;
padding: 64px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
}
.container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
width: 595.28pt;
gap: var(--spacing-xl);
align-self: center;
}
.title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.page {
width: 595.28pt;
min-height: var(--height);
padding: var(--margin);
background-color: white;
flex: 0 0 auto;
display: flex;
justify-content: flex-start;
align-items: stretch;
box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.1);
flex-direction: column;
margin: 0 auto;
position: relative;
}
.pageContent {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
background: white;
}
.divider {
width: 100%;
height: 2px;
background: var(--spectrum-global-color-static-gray-400);
position: absolute;
left: 0;
top: var(--top);
transform: translateY(-50%);
}
.divider.last {
top: calc(var(--top) + var(--margin));
background: transparent;
}
</style>

View File

@ -0,0 +1,143 @@
<script lang="ts">
import type {
DataFetchDatasource,
FieldSchema,
GroupUserDatasource,
SortOrder,
TableSchema,
UISearchFilter,
UserDatasource,
} from "@budibase/types"
import { fetchData, QueryUtils, stringifyRow } from "@budibase/frontend-core"
import { getContext } from "svelte"
type ProviderDatasource = Exclude<
DataFetchDatasource,
UserDatasource | GroupUserDatasource
>
type ChosenColumns = Array<{ name: string; displayName?: string }> | undefined
type Schema = { [key: string]: FieldSchema & { displayName: string } }
export let datasource: ProviderDatasource
export let filter: UISearchFilter | undefined = undefined
export let sortColumn: string | undefined = undefined
export let sortOrder: SortOrder | undefined = undefined
export let columns: ChosenColumns = undefined
export let limit: number = 20
const component = getContext("component")
const { styleable, API } = getContext("sdk")
$: query = QueryUtils.buildQuery(filter)
$: fetch = createFetch(datasource)
$: fetch.update({
query,
sortColumn,
sortOrder,
limit,
})
$: schema = sanitizeSchema($fetch.schema, columns)
$: columnCount = Object.keys(schema).length
$: rowCount = $fetch.rows?.length || 0
$: stringifiedRows = ($fetch?.rows || []).map(row =>
stringifyRow(row, schema)
)
const createFetch = (datasource: ProviderDatasource) => {
return fetchData({
API,
datasource,
options: {
query,
sortColumn,
sortOrder,
limit,
paginate: false,
},
})
}
const sanitizeSchema = (
schema: TableSchema | null,
columns: ChosenColumns
): Schema => {
if (!schema) {
return {}
}
let sanitized: Schema = {}
// Clean out hidden fields and ensure we have
Object.entries(schema).forEach(([field, fieldSchema]) => {
if (fieldSchema.visible !== false) {
sanitized[field] = {
...fieldSchema,
displayName: field,
}
}
})
// Clean out unselected columns.
// Default to first 3 columns if none specified, as we are width contrained.
if (!columns?.length) {
columns = Object.values(sanitized).slice(0, 3)
}
let pruned: Schema = {}
for (let col of columns) {
if (sanitized[col.name]) {
pruned[col.name] = {
...sanitized[col.name],
displayName: col.displayName || sanitized[col.name].displayName,
}
}
}
sanitized = pruned
return sanitized
}
</script>
<div class="vars" style="--cols:{columnCount}; --rows:{rowCount};">
<div class="table" class:valid={!!schema} use:styleable={$component.styles}>
{#if schema}
{#each Object.keys(schema) as col}
<div class="cell header">{schema[col].displayName}</div>
{/each}
{#each stringifiedRows as row}
{#each Object.keys(schema) as col}
<div class="cell">{row[col]}</div>
{/each}
{/each}
{/if}
</div>
</div>
<style>
.vars {
display: contents;
--border-color: var(--spectrum-global-color-gray-300);
}
.table {
display: grid;
grid-template-columns: repeat(var(--cols), minmax(40px, auto));
grid-template-rows: repeat(var(--rows), max-content);
overflow: hidden;
background: var(--spectrum-global-color-gray-50);
}
.table.valid {
border-left: 1px solid var(--border-color);
border-top: 1px solid var(--border-color);
}
.cell {
border-right: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
padding: var(--spacing-xs) var(--spacing-s);
overflow: hidden;
word-break: break-word;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
.cell.header {
font-weight: 600;
}
</style>

View File

@ -0,0 +1,2 @@
export { default as pdf } from "./PDF.svelte"
export { default as pdftable } from "./PDFTable.svelte"

View File

@ -0,0 +1,78 @@
// @ts-ignore
import html2pdf from "html2pdf.js"
export const pxToPt = (px: number) => (px / 4) * 3
export const ptToPx = (pt: number) => (pt / 3) * 4
export const A4HeightPx = ptToPx(841.92) + 1
export interface PDFOptions {
fileName?: string
marginPt?: number
orientation?: "portrait" | "landscape"
htmlScale?: number
footer?: boolean
}
export async function htmlToPdf(el: HTMLElement, opts: PDFOptions = {}) {
const userOpts: Required<PDFOptions> = {
fileName: "file.pdf",
marginPt: 60,
orientation: "portrait",
htmlScale: 1,
footer: true,
...opts,
}
return new Promise(resolve => {
// Sanity check title
let fileName = userOpts.fileName
if (!fileName.endsWith(".pdf")) {
fileName += ".pdf"
}
// Config
const options = {
margin: userOpts.marginPt,
filename: fileName,
image: { type: "jpeg", quality: 0.95 },
html2canvas: { dpi: 192, scale: 2, useCORS: true },
jsPDF: {
orientation: userOpts.orientation,
unit: "pt",
format: "a4",
},
pagebreak: { avoid: ".no-break" },
// Custom params
htmlScale: userOpts.htmlScale,
}
let worker = html2pdf().set(options).from(el).toPdf()
// Add footer if required
if (opts.footer) {
worker = worker.get("pdf").then((pdf: any) => {
const totalPages = pdf.internal.getNumberOfPages()
for (let i = 1; i <= totalPages; i++) {
pdf.setPage(i)
pdf.setFontSize(10)
pdf.setTextColor(200)
pdf.text(
`Page ${i} of ${totalPages}`,
pdf.internal.pageSize.getWidth() - options.margin,
pdf.internal.pageSize.getHeight() - options.margin / 2,
"right"
)
pdf.text(
options.filename.replace(".pdf", ""),
options.margin,
pdf.internal.pageSize.getHeight() - options.margin / 2
)
}
})
}
worker.save().then(resolve)
})
}

View File

@ -31,6 +31,8 @@ import {
} from "@budibase/types"
import { ActionTypes } from "@/constants"
import { APIClient } from "@budibase/frontend-core"
import BlockComponent from "./components/BlockComponent.svelte"
import Block from "./components/Block.svelte"
if (typeof window !== "undefined") {
window.addEventListener("beforeinstallprompt", e => {
@ -99,6 +101,8 @@ export interface SDK {
notificationStore: typeof notificationStore
environmentStore: typeof environmentStore
appStore: typeof appStore
Block: typeof Block
BlockComponent: typeof BlockComponent
}
let app: ClientApp

View File

@ -8,6 +8,7 @@ import { RoleUtils } from "@budibase/frontend-core"
import { findComponentById, findComponentParent } from "../utils/components.js"
import { Helpers } from "@budibase/bbui"
import { DNDPlaceholderID, ScreenslotID, ScreenslotType } from "@/constants"
import { ScreenVariant } from "@budibase/types"
const createScreenStore = () => {
const store = derived(
@ -193,5 +194,8 @@ const createScreenStore = () => {
export const screenStore = createScreenStore()
export const isGridScreen = derived(screenStore, $screenStore => {
return $screenStore.activeScreen?.props?.layout === "grid"
return (
$screenStore.activeScreen?.props?.layout === "grid" ||
$screenStore.activeScreen?.variant === ScreenVariant.PDF
)
})

View File

@ -116,6 +116,9 @@ export const gridLayout = (node: HTMLDivElement, metadata: GridMetadata) => {
return
}
// Add a unique class to elements we mutate so we can easily find them later
node.classList.add("grid-child")
// Callback to select the component when clicking on the wrapper
selectComponent = (e: Event) => {
e.stopPropagation()

View File

@ -1,8 +1,5 @@
<script context="module">
const NumberFormatter = Intl.NumberFormat()
</script>
<script>
import { formatNumber } from "@budibase/frontend-core"
import TextCell from "./TextCell.svelte"
export let api
@ -13,18 +10,6 @@
const newValue = isNaN(float) ? null : float
onChange(newValue)
}
const formatNumber = value => {
const type = typeof value
if (type !== "string" && type !== "number") {
return ""
}
if (type === "string" && !value.trim().length) {
return ""
}
const res = NumberFormatter.format(value)
return res === "NaN" ? value : res
}
</script>
<TextCell

View File

@ -0,0 +1,149 @@
import {
BBReferenceFieldSubType,
FieldSchema,
FieldType,
Row,
TableSchema,
} from "@budibase/types"
import { Helpers } from "@budibase/bbui"
// Singleton formatter to save us creating one every time
const NumberFormatter = Intl.NumberFormat()
export type StringifiedRow = { [key: string]: string }
// Formats a number according to the locale
export const formatNumber = (value: any): string => {
const type = typeof value
if (type !== "string" && type !== "number") {
return ""
}
if (type === "string" && !value.trim().length) {
return ""
}
const res = NumberFormatter.format(value)
return res === "NaN" ? stringifyValue(value) : res
}
// Attempts to stringify any type of value
const stringifyValue = (value: any): string => {
if (value == null) {
return ""
}
if (typeof value === "string") {
return value
}
if (typeof value.toString === "function") {
return stringifyValue(value.toString())
}
try {
return JSON.stringify(value)
} catch (e) {
return ""
}
}
const stringifyField = (value: any, schema: FieldSchema): string => {
switch (schema.type) {
// Auto should not exist as it should always be typed by its underlying
// real type, like date or user
case FieldType.AUTO:
return ""
// Just state whether signatures exist or not
case FieldType.SIGNATURE_SINGLE:
return value ? "Yes" : "No"
// Extract attachment names
case FieldType.ATTACHMENT_SINGLE:
case FieldType.ATTACHMENTS: {
if (!value) {
return ""
}
const arrayValue = Array.isArray(value) ? value : [value]
return arrayValue
.map(x => x.name)
.filter(x => !!x)
.join(", ")
}
// Extract primary displays from relationships
case FieldType.LINK: {
if (!value) {
return ""
}
const arrayValue = Array.isArray(value) ? value : [value]
return arrayValue
.map(x => x.primaryDisplay)
.filter(x => !!x)
.join(", ")
}
// Stringify JSON blobs
case FieldType.JSON:
return value ? JSON.stringify(value) : ""
// User is the only BB reference subtype right now
case FieldType.BB_REFERENCE:
case FieldType.BB_REFERENCE_SINGLE: {
if (
schema.subtype !== BBReferenceFieldSubType.USERS &&
schema.subtype !== BBReferenceFieldSubType.USER
) {
return ""
}
if (!value) {
return ""
}
const arrayVal = Array.isArray(value) ? value : [value]
return arrayVal?.map((user: any) => user.primaryDisplay).join(", ") || ""
}
// Join arrays with commas
case FieldType.ARRAY:
return value?.join(", ") || ""
// Just capitalise booleans
case FieldType.BOOLEAN:
return Helpers.capitalise(value?.toString() || "false")
// Format dates into something readable
case FieldType.DATETIME: {
return Helpers.getDateDisplayValue(value, {
enableTime: !schema.dateOnly,
timeOnly: schema.timeOnly,
})
}
// Format numbers using a locale string
case FieldType.NUMBER:
return formatNumber(value)
// Simple string types
case FieldType.STRING:
case FieldType.LONGFORM:
case FieldType.BIGINT:
case FieldType.OPTIONS:
case FieldType.AI:
case FieldType.BARCODEQR:
return value || ""
// Fallback for unknown types or future column types that we forget to add
case FieldType.FORMULA:
default:
return stringifyValue(value)
}
}
// Stringifies every property of a row, ensuring they are all human-readable
// strings for display
export const stringifyRow = (row: Row, schema: TableSchema): StringifiedRow => {
let stringified: StringifiedRow = {}
Object.entries(schema).forEach(([field, fieldSchema]) => {
stringified[field] = stringifyField(
Helpers.deepGet(row, field),
fieldSchema
)
})
return stringified
}

View File

@ -15,3 +15,4 @@ export * from "./relatedColumns"
export * from "./table"
export * from "./components"
export * from "./validation"
export * from "./formatting"

View File

@ -1,5 +1,6 @@
import { helpers } from "@budibase/shared-core"
import { TypeIconMap } from "../constants"
import { convertJSONSchemaToTableSchema } from "./json"
export const getColumnIcon = column => {
// For some reason we have remix icons saved under this property sometimes,
@ -24,3 +25,25 @@ export const getColumnIcon = column => {
return result || "Text"
}
export const addNestedJSONSchemaFields = schema => {
if (!schema) {
return schema
}
let jsonAdditions = {}
Object.keys(schema).forEach(fieldKey => {
const fieldSchema = schema[fieldKey]
if (fieldSchema?.type === "json") {
const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, {
squashObjects: true,
})
Object.keys(jsonSchema).forEach(jsonKey => {
jsonAdditions[`${fieldKey}.${jsonKey}`] = {
type: jsonSchema[jsonKey].type,
nestedJSON: true,
}
})
}
})
return { ...schema, ...jsonAdditions }
}

View File

@ -144,9 +144,11 @@ export async function find(ctx: UserCtx<void, FindRowResponse>) {
const { tableId, viewId } = utils.getSourceId(ctx)
const sourceId = viewId || tableId
const rowId = ctx.params.rowId
const response = await sdk.rows.find(sourceId, rowId)
ctx.body = response
try {
ctx.body = await sdk.rows.find(sourceId, rowId)
} catch (e) {
ctx.throw(404, "That row couldn't be found")
}
}
function isDeleteRows(input: any): input is DeleteRows {

View File

@ -15,6 +15,10 @@ export interface ScreenRouting {
homeScreen?: boolean
}
export enum ScreenVariant {
PDF = "pdf",
}
export interface Screen extends Document {
layoutId?: string
showNavigation?: boolean
@ -24,6 +28,7 @@ export interface Screen extends Document {
name?: string
pluginAdded?: boolean
onLoad?: EventHandler[]
variant?: ScreenVariant
}
export interface ScreenRoutesViewOutput extends Document {

View File

@ -207,6 +207,8 @@ export interface BaseFieldSchema extends UIFieldMetadata {
autocolumn?: boolean
autoReason?: AutoReason.FOREIGN_KEY
subtype?: never
// added when enriching nested JSON fields into schema
nestedJSON?: boolean
}
interface OtherFieldMetadata extends BaseFieldSchema {

216
yarn.lock
View File

@ -7534,6 +7534,11 @@ a-sync-waterfall@^1.0.0:
resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7"
integrity sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==
abab@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
integrity sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==
abab@^2.0.3, abab@^2.0.5, abab@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
@ -7605,6 +7610,13 @@ accepts@^1.3.5, accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.8:
mime-types "~2.1.34"
negotiator "0.6.3"
acorn-globals@^1.0.4:
version "1.0.9"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-1.0.9.tgz#55bb5e98691507b74579d0513413217c380c54cf"
integrity sha512-j3/4pkfih8W4NK22gxVSXcEonTpAHOHh0hu5BoZrKcOsW/4oBPxTi4Yk3SAj+FhC1f3+bRTkXdm4019gw1vg9g==
dependencies:
acorn "^2.1.0"
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@ -7643,6 +7655,11 @@ acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0:
dependencies:
acorn "^8.11.0"
acorn@^2.1.0, acorn@^2.4.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7"
integrity sha512-pXK8ez/pVjqFdAgBkF1YPVRacuLQ9EXBKaKWaeh58WNfMkCmZhOZzu+NtKSPD5PHmCCHheQ5cD29qM1K4QTxIg==
acorn@^5.2.1:
version "5.7.4"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
@ -7958,6 +7975,11 @@ array-differ@^3.0.0:
resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
array-equal@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.2.tgz#a8572e64e822358271250b9156d20d96ef5dec04"
integrity sha512-gUHx76KtnhEgB3HOuFYiCm3FIdEs6ocM2asHvNTkfu/Y09qQVrrVVaOKENmS2KkSaGoxgXNqC+ZVtR/n0MOkSA==
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@ -8378,6 +8400,11 @@ base62@^1.1.0:
resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428"
integrity sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -8860,6 +8887,16 @@ caniuse-lite@^1.0.30001449:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz#31d2e26f0a2309860ed3eff154e03890d9d851a7"
integrity sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==
canvg@^1.0:
version "1.5.3"
resolved "https://registry.yarnpkg.com/canvg/-/canvg-1.5.3.tgz#aad17915f33368bf8eb80b25d129e3ae922ddc5f"
integrity sha512-7Gn2IuQzvUQWPIuZuFHrzsTM0gkPz2RRT9OcbdmA03jeKk8kltrD8gqUzNX15ghY/4PV5bbe5lmD6yDLDY6Ybg==
dependencies:
jsdom "^8.1.0"
rgbcolor "^1.0.1"
stackblur-canvas "^1.4.1"
xmldom "^0.1.22"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
@ -8870,6 +8907,11 @@ catering@^2.0.0, catering@^2.1.0:
resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510"
integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==
cf-blob.js@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/cf-blob.js/-/cf-blob.js-0.0.1.tgz#f5ab7e12e798caf08ccf828c69aba0f063d83f99"
integrity sha512-KkUmNT/rgVK+KehG7cSvbLwMb+OS5Qby6ADB4LP12jtx6rfVvHCdyqFUjAeQnDpGpQNNwvpi0R/tluT2J6P99Q==
chai@^4.3.7:
version "4.5.0"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8"
@ -9708,6 +9750,13 @@ crypto-randomuuid@^1.0.0:
resolved "https://registry.yarnpkg.com/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz#acf583e5e085e867ae23e107ff70279024f9e9e7"
integrity sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==
css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
dependencies:
utrie "^1.0.2"
css-tree@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20"
@ -9726,15 +9775,22 @@ cssesc@^3.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0", cssom@~0.3.6:
version "0.3.8"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
cssom@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==
cssom@~0.3.6:
version "0.3.8"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
"cssstyle@>= 0.2.34 < 0.3.0":
version "0.2.37"
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
integrity sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA==
dependencies:
cssom "0.3.x"
cssstyle@^2.3.0:
version "2.3.0"
@ -11046,6 +11102,11 @@ es6-error@^4.0.1, es6-error@^4.1.1:
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
es6-promise@^4.2.5:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
esbuild-node-externals@^1.14.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/esbuild-node-externals/-/esbuild-node-externals-1.14.0.tgz#fc2950c67a068dc2b538fd1381ad7d8e20a6f54d"
@ -11112,6 +11173,18 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escodegen@^1.6.1:
version "1.14.3"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
dependencies:
esprima "^4.0.1"
estraverse "^4.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.6.1"
escodegen@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
@ -11389,7 +11462,7 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
@ -11790,6 +11863,11 @@ file-entry-cache@^8.0.0:
dependencies:
flat-cache "^4.0.0"
file-saver@1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==
file-type@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8"
@ -12997,6 +13075,23 @@ html-tag@^2.0.0:
is-self-closing "^1.0.1"
kind-of "^6.0.0"
html2canvas@^1.0.0-alpha.12:
version "1.4.1"
resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
dependencies:
css-line-break "^2.1.0"
text-segmentation "^1.0.3"
html2pdf.js@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/html2pdf.js/-/html2pdf.js-0.9.3.tgz#e7fc6143f748ce253670eaae403987342b66b15c"
integrity sha512-M254g3Z+ZsjtQFDxJlU6E8Zgb8xOpCBQQM1lFPn4Lq+myAdWoYtMFnwlVo/eOI9R1cG75+YmMSDQofkugwOV/Q==
dependencies:
es6-promise "^4.2.5"
html2canvas "^1.0.0-alpha.12"
jspdf "1.4.1"
html5-qrcode@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz#0b0cdf7a9926cfd4be530e13a51db47592adfa0d"
@ -13147,7 +13242,7 @@ ical-generator@4.1.0:
dependencies:
uuid-random "^1.3.2"
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.5:
iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.24, iconv-lite@^0.4.5:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -14636,6 +14731,29 @@ jsdom@^24.1.1:
ws "^8.18.0"
xml-name-validator "^5.0.0"
jsdom@^8.1.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-8.5.0.tgz#d4d8f5dbf2768635b62a62823b947cf7071ebc98"
integrity sha512-rvWfcn2O8SrXPaX5fTYIfPVwvnbU8DnZkjAXK305wfP67csyaJBhgg0F2aU6imqJ+lZmj9EmrBAXy6rWHf2/9Q==
dependencies:
abab "^1.0.0"
acorn "^2.4.0"
acorn-globals "^1.0.4"
array-equal "^1.0.0"
cssom ">= 0.3.0 < 0.4.0"
cssstyle ">= 0.2.34 < 0.3.0"
escodegen "^1.6.1"
iconv-lite "^0.4.13"
nwmatcher ">= 1.3.7 < 2.0.0"
parse5 "^1.5.1"
request "^2.55.0"
sax "^1.1.4"
symbol-tree ">= 3.1.0 < 4.0.0"
tough-cookie "^2.2.0"
webidl-conversions "^3.0.1"
whatwg-url "^2.0.1"
xml-name-validator ">= 2.0.1 < 3.0.0"
jsesc@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
@ -14755,6 +14873,17 @@ jsonwebtoken@9.0.2, jsonwebtoken@^9.0.0:
ms "^2.1.1"
semver "^7.5.4"
jspdf@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-1.4.1.tgz#8dbd437986346d65efe20ede5361927666b8e4ca"
integrity sha512-2vYVdrvrQUdKKPyWHw81t1jEYYAJ6uFJ/HtTcGbI4qXIQEdl18dLEuL2wTeSv2GzeQLSgUvEvwsXsszuHK+PTw==
dependencies:
canvg "^1.0"
cf-blob.js "0.0.1"
file-saver "1.3.8"
omggif "1.0.7"
stackblur "^1.0.0"
jsprim@^1.2.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
@ -16801,6 +16930,11 @@ nunjucks@^3.2.3:
asap "^2.0.3"
commander "^5.1.0"
"nwmatcher@>= 1.3.7 < 2.0.0":
version "1.4.4"
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e"
integrity sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==
nwsapi@^2.2.0, nwsapi@^2.2.4:
version "2.2.12"
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8"
@ -16982,6 +17116,11 @@ obliterator@^1.6.1:
resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3"
integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==
omggif@1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.7.tgz#59d2eecb0263de84635b3feb887c0c9973f1e49d"
integrity sha512-KVVUF85EHKUB9kxxT2D8CksGgfayZKxWtH/+i34zbyDdxFHvsqQs+O756usW7uri2YBD8jE/8GgAsA6wVA1tjg==
omggif@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19"
@ -17452,6 +17591,11 @@ parse5@6.0.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
parse5@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
integrity sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA==
parse5@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32"
@ -19015,7 +19159,7 @@ remixicon@2.5.0:
resolved "https://registry.yarnpkg.com/remixicon/-/remixicon-2.5.0.tgz#b5e245894a1550aa23793f95daceadbf96ad1a41"
integrity sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww==
request@^2.88.0:
request@^2.55.0, request@^2.88.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@ -19180,6 +19324,11 @@ rfdc@^1.3.0, rfdc@^1.3.1:
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca"
integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
rgbcolor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d"
integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==
rimraf@3.0.2, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -19405,6 +19554,11 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
sax@^1.1.4:
version "1.4.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
saxes@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
@ -20067,6 +20221,16 @@ stackback@0.0.2:
resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b"
integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==
stackblur-canvas@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/stackblur-canvas/-/stackblur-canvas-1.4.1.tgz#849aa6f94b272ff26f6471fa4130ed1f7e47955b"
integrity sha512-TfbTympL5C1K+F/RizDkMBqH18EkUKU8V+4PphIXR+fWhZwwRi3bekP04gy2TOwOT3R6rJQJXAXFrbcZde7wow==
stackblur@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/stackblur/-/stackblur-1.0.0.tgz#b407a7e05c93b08d66883bb808d7cba3a503f12f"
integrity sha512-K92JX8alrs0pTox5U2arVBqB8tJmak9dh9i4Xausy94TnnGMdLfTn7P2Dp/NOzlmxvEs7lDzeryo8YqOy0BHRQ==
standard-as-callback@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
@ -20626,7 +20790,7 @@ swagger-parser@10.0.2:
dependencies:
"@apidevtools/swagger-parser" "10.0.2"
symbol-tree@^3.2.4:
"symbol-tree@>= 3.1.0 < 4.0.0", symbol-tree@^3.2.4:
version "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==
@ -20811,6 +20975,13 @@ text-hex@1.0.x:
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
text-segmentation@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
dependencies:
utrie "^1.0.2"
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -21004,7 +21175,7 @@ touch@^3.1.0:
dependencies:
nopt "~1.0.10"
tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@^4.1.4, tough-cookie@~2.5.0:
tough-cookie@4.1.3, tough-cookie@^2.2.0, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@^4.1.4, tough-cookie@~2.5.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
@ -21616,6 +21787,13 @@ utils-merge@1.0.1, utils-merge@1.x.x, utils-merge@^1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
utrie@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
dependencies:
base64-arraybuffer "^1.0.2"
uue@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.2.tgz#e99368414e87200012eb37de4dbaebaa1c742ad2"
@ -21867,7 +22045,7 @@ webfinger@^0.4.2:
step "0.0.x"
xml2js "0.1.x"
webidl-conversions@^3.0.0:
webidl-conversions@^3.0.0, webidl-conversions@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
@ -21947,6 +22125,14 @@ whatwg-url@^14.0.0:
tr46 "^5.0.0"
webidl-conversions "^7.0.0"
whatwg-url@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-2.0.1.tgz#5396b2043f020ee6f704d9c45ea8519e724de659"
integrity sha512-sX+FT4N6iR0ZiqGqyDEKklyfMGR99zvxZD+LQ8IGae5uVGswQ7DOeLPB5KgJY8FzkwSzwqOXLQeVQvtOTSQU9Q==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
@ -22236,6 +22422,11 @@ xhr@^2.4.1:
parse-headers "^2.0.0"
xtend "^4.0.0"
"xml-name-validator@>= 2.0.1 < 3.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
integrity sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA==
xml-name-validator@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
@ -22274,6 +22465,11 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xmldom@^0.1.22:
version "0.1.31"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"