Merge remote-tracking branch 'origin/master' into feat/pwa-apps
This commit is contained in:
commit
104731a885
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -80,5 +80,6 @@
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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}
|
||||
/>
|
|
@ -71,4 +71,5 @@ export const AutoScreenTypes = {
|
|||
BLANK: "blank",
|
||||
TABLE: "table",
|
||||
FORM: "form",
|
||||
PDF: "pdf",
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
"name": "Data",
|
||||
"icon": "Data",
|
||||
"children": [
|
||||
"singlerowprovider",
|
||||
"dataprovider",
|
||||
"repeater",
|
||||
"gridblock",
|
||||
"pdftable",
|
||||
"spreadsheet",
|
||||
"dynamicfilter",
|
||||
"daterangepicker"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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 |
|
@ -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>
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as pdf } from "./PDF.svelte"
|
||||
export { default as pdftable } from "./PDFTable.svelte"
|
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -15,3 +15,4 @@ export * from "./relatedColumns"
|
|||
export * from "./table"
|
||||
export * from "./components"
|
||||
export * from "./validation"
|
||||
export * from "./formatting"
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
216
yarn.lock
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue