Merge remote-tracking branch 'origin/develop' into feature/automation-collaboration
This commit is contained in:
commit
e2311b8a55
|
@ -28,3 +28,4 @@ BB_ADMIN_USER_PASSWORD=
|
|||
|
||||
# A path that is watched for plugin bundles. Any bundles found are imported automatically/
|
||||
PLUGINS_DIR=
|
||||
ROLLING_LOG_MAX_SIZE=
|
|
@ -22,6 +22,16 @@ server {
|
|||
proxy_pass http://127.0.0.1:4001;
|
||||
}
|
||||
|
||||
location /embed {
|
||||
rewrite /embed/(.*) /app/$1 break;
|
||||
proxy_pass http://127.0.0.1:4001;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header x-budibase-embed "true";
|
||||
add_header x-budibase-embed "true";
|
||||
add_header Content-Security-Policy "frame-ancestors *";
|
||||
}
|
||||
|
||||
location = / {
|
||||
proxy_pass http://127.0.0.1:4001;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.8.3-alpha.1",
|
||||
"version": "2.8.10-alpha.2",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
12
nx.json
12
nx.json
|
@ -1,9 +1,13 @@
|
|||
{
|
||||
"tasksRunnerOptions": {
|
||||
"default": {
|
||||
"runner": "nx/tasks-runners/default",
|
||||
"runner": "nx-cloud",
|
||||
"options": {
|
||||
"cacheableOperations": ["build", "test"]
|
||||
"cacheableOperations": [
|
||||
"build",
|
||||
"test"
|
||||
],
|
||||
"accessToken": "YWNiYzc5NTEtMzMzZC00NDhjLTgyNjktZTllMjI1MzM4OGQxfHJlYWQtd3JpdGU="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -11,7 +15,9 @@
|
|||
"dev:builder": {
|
||||
"dependsOn": [
|
||||
{
|
||||
"projects": ["@budibase/string-templates"],
|
||||
"projects": [
|
||||
"@budibase/string-templates"
|
||||
],
|
||||
"target": "build"
|
||||
}
|
||||
]
|
||||
|
|
19
package.json
19
package.json
|
@ -3,7 +3,7 @@
|
|||
"private": true,
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
||||
"@nx/js": "16.2.1",
|
||||
"@nx/js": "16.4.3",
|
||||
"@rollup/plugin-json": "^4.0.2",
|
||||
"@typescript-eslint/parser": "5.45.0",
|
||||
"esbuild": "^0.17.18",
|
||||
|
@ -13,9 +13,11 @@
|
|||
"husky": "^8.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"kill-port": "^1.6.1",
|
||||
"lerna": "7.0.2",
|
||||
"lerna": "7.1.1",
|
||||
"madge": "^6.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"nx": "16.4.3",
|
||||
"nx-cloud": "16.0.5",
|
||||
"prettier": "2.8.8",
|
||||
"prettier-plugin-svelte": "^2.3.0",
|
||||
"rimraf": "^3.0.2",
|
||||
|
@ -44,15 +46,15 @@
|
|||
"restore": "yarn run clean && yarn run bootstrap && yarn run build",
|
||||
"nuke": "yarn run nuke:packages && yarn run nuke:docker",
|
||||
"nuke:packages": "yarn run restore",
|
||||
"nuke:docker": "lerna run --stream --parallel dev:stack:nuke",
|
||||
"nuke:docker": "lerna run --stream dev:stack:nuke",
|
||||
"clean": "lerna clean",
|
||||
"kill-builder": "kill-port 3000",
|
||||
"kill-server": "kill-port 4001 4002",
|
||||
"kill-all": "yarn run kill-builder && yarn run kill-server",
|
||||
"dev": "yarn run kill-all && lerna run --stream --parallel dev:builder --stream",
|
||||
"dev:noserver": "yarn run kill-builder && lerna run --stream dev:stack:up && lerna run --stream --parallel dev:builder --ignore @budibase/backend-core --ignore @budibase/server --ignore @budibase/worker",
|
||||
"dev:server": "yarn run kill-server && yarn build --projects=@budibase/client && lerna run --stream --parallel dev:builder --scope @budibase/worker --scope @budibase/server",
|
||||
"dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream --parallel dev:built",
|
||||
"dev": "yarn run kill-all && lerna run --stream dev:builder --stream",
|
||||
"dev:noserver": "yarn run kill-builder && lerna run --stream dev:stack:up && lerna run --stream dev:builder --ignore @budibase/backend-core --ignore @budibase/server --ignore @budibase/worker",
|
||||
"dev:server": "yarn run kill-server && yarn build --projects=@budibase/client && lerna run --stream dev:builder --scope @budibase/worker --scope @budibase/server",
|
||||
"dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream dev:built",
|
||||
"dev:docker": "yarn build:docker:pre && docker-compose -f hosting/docker-compose.build.yaml -f hosting/docker-compose.dev.yaml --env-file hosting/.env up --build --scale proxy-service=0",
|
||||
"test": "lerna run --stream test --stream",
|
||||
"lint:eslint": "eslint packages qa-core --max-warnings=0",
|
||||
|
@ -106,6 +108,5 @@
|
|||
"@budibase/string-templates": "0.0.0",
|
||||
"@budibase/types": "0.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
}
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"pouchdb": "7.3.0",
|
||||
"pouchdb-find": "7.2.2",
|
||||
"redlock": "4.2.0",
|
||||
"rotating-file-stream": "3.1.0",
|
||||
"sanitize-s3-objectkey": "0.0.1",
|
||||
"semver": "7.3.7",
|
||||
"tar-fs": "2.1.1",
|
||||
|
|
|
@ -433,6 +433,9 @@ export class QueryBuilder<T> {
|
|||
if (!value) {
|
||||
return null
|
||||
}
|
||||
if (typeof value === "boolean") {
|
||||
return `(*:* AND !${key}:${value})`
|
||||
}
|
||||
return `!${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
||||
})
|
||||
}
|
||||
|
|
|
@ -47,7 +47,10 @@ function httpLogging() {
|
|||
return process.env.HTTP_LOGGING
|
||||
}
|
||||
|
||||
function findVersion() {
|
||||
function getPackageJsonFields(): {
|
||||
VERSION: string
|
||||
SERVICE_NAME: string
|
||||
} {
|
||||
function findFileInAncestors(
|
||||
fileName: string,
|
||||
currentDir: string
|
||||
|
@ -69,10 +72,14 @@ function findVersion() {
|
|||
try {
|
||||
const packageJsonFile = findFileInAncestors("package.json", process.cwd())
|
||||
const content = readFileSync(packageJsonFile!, "utf-8")
|
||||
return JSON.parse(content).version
|
||||
const parsedContent = JSON.parse(content)
|
||||
return {
|
||||
VERSION: parsedContent.version,
|
||||
SERVICE_NAME: parsedContent.name,
|
||||
}
|
||||
} catch {
|
||||
// throwing an error here is confusing/causes backend-core to be hard to import
|
||||
return undefined
|
||||
return { VERSION: "", SERVICE_NAME: "" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,13 +161,14 @@ const environment = {
|
|||
ENABLE_SSO_MAINTENANCE_MODE: selfHosted
|
||||
? process.env.ENABLE_SSO_MAINTENANCE_MODE
|
||||
: false,
|
||||
VERSION: findVersion(),
|
||||
...getPackageJsonFields(),
|
||||
DISABLE_PINO_LOGGER: process.env.DISABLE_PINO_LOGGER,
|
||||
_set(key: any, value: any) {
|
||||
process.env[key] = value
|
||||
// @ts-ignore
|
||||
environment[key] = value
|
||||
},
|
||||
ROLLING_LOG_MAX_SIZE: process.env.ROLLING_LOG_MAX_SIZE || "10M",
|
||||
}
|
||||
|
||||
// clean up any environment variable edge cases
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export * as correlation from "./correlation/correlation"
|
||||
export { logger } from "./pino/logger"
|
||||
export * from "./alerts"
|
||||
export * as system from "./system"
|
||||
|
||||
// turn off or on context logging i.e. tenantId, appId etc
|
||||
export let LOG_CONTEXT = true
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import env from "../../environment"
|
||||
import pino, { LoggerOptions } from "pino"
|
||||
import pinoPretty from "pino-pretty"
|
||||
|
||||
import { IdentityType } from "@budibase/types"
|
||||
|
||||
import env from "../../environment"
|
||||
import * as context from "../../context"
|
||||
import * as correlation from "../correlation"
|
||||
import { IdentityType } from "@budibase/types"
|
||||
import { LOG_CONTEXT } from "../index"
|
||||
|
||||
import { localFileDestination } from "../system"
|
||||
|
||||
// LOGGER
|
||||
|
||||
let pinoInstance: pino.Logger | undefined
|
||||
|
@ -16,22 +21,27 @@ if (!env.DISABLE_PINO_LOGGER) {
|
|||
return { level: label.toUpperCase() }
|
||||
},
|
||||
bindings: () => {
|
||||
return {}
|
||||
return {
|
||||
service: env.SERVICE_NAME,
|
||||
}
|
||||
},
|
||||
},
|
||||
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
|
||||
}
|
||||
|
||||
const destinations: pino.DestinationStream[] = []
|
||||
|
||||
if (env.isDev()) {
|
||||
pinoOptions.transport = {
|
||||
target: "pino-pretty",
|
||||
options: {
|
||||
singleLine: true,
|
||||
},
|
||||
}
|
||||
destinations.push(pinoPretty({ singleLine: true }))
|
||||
}
|
||||
|
||||
pinoInstance = pino(pinoOptions)
|
||||
if (env.SELF_HOSTED) {
|
||||
destinations.push(localFileDestination())
|
||||
}
|
||||
|
||||
pinoInstance = destinations.length
|
||||
? pino(pinoOptions, pino.multistream(destinations))
|
||||
: pino(pinoOptions)
|
||||
|
||||
// CONSOLE OVERRIDES
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import fs from "fs"
|
||||
import path from "path"
|
||||
import * as rfs from "rotating-file-stream"
|
||||
|
||||
import env from "../environment"
|
||||
import { budibaseTempDir } from "../objectStore"
|
||||
|
||||
const logsFileName = `budibase.log`
|
||||
const budibaseLogsHistoryFileName = "budibase-logs-history.txt"
|
||||
|
||||
const logsPath = path.join(budibaseTempDir(), "systemlogs")
|
||||
|
||||
function getFullPath(fileName: string) {
|
||||
return path.join(logsPath, fileName)
|
||||
}
|
||||
|
||||
export function getSingleFileMaxSizeInfo(totalMaxSize: string) {
|
||||
const regex = /(\d+)([A-Za-z])/
|
||||
const match = totalMaxSize?.match(regex)
|
||||
if (!match) {
|
||||
console.warn(`totalMaxSize does not have a valid value`, {
|
||||
totalMaxSize,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
|
||||
const size = +match[1]
|
||||
const unit = match[2]
|
||||
if (size === 1) {
|
||||
switch (unit) {
|
||||
case "B":
|
||||
return { size: `${size}B`, totalHistoryFiles: 1 }
|
||||
case "K":
|
||||
return { size: `${(size * 1000) / 2}B`, totalHistoryFiles: 1 }
|
||||
case "M":
|
||||
return { size: `${(size * 1000) / 2}K`, totalHistoryFiles: 1 }
|
||||
case "G":
|
||||
return { size: `${(size * 1000) / 2}M`, totalHistoryFiles: 1 }
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (size % 2 === 0) {
|
||||
return { size: `${size / 2}${unit}`, totalHistoryFiles: 1 }
|
||||
}
|
||||
|
||||
return { size: `1${unit}`, totalHistoryFiles: size - 1 }
|
||||
}
|
||||
|
||||
export function localFileDestination() {
|
||||
const fileInfo = getSingleFileMaxSizeInfo(env.ROLLING_LOG_MAX_SIZE)
|
||||
const outFile = rfs.createStream(logsFileName, {
|
||||
// As we have a rolling size, we want to half the max size
|
||||
size: fileInfo?.size,
|
||||
path: logsPath,
|
||||
maxFiles: fileInfo?.totalHistoryFiles || 1,
|
||||
immutable: true,
|
||||
history: budibaseLogsHistoryFileName,
|
||||
initialRotation: false,
|
||||
})
|
||||
|
||||
return outFile
|
||||
}
|
||||
|
||||
export function getLogReadStream() {
|
||||
const streams = []
|
||||
const historyFile = getFullPath(budibaseLogsHistoryFileName)
|
||||
if (fs.existsSync(historyFile)) {
|
||||
const fileContent = fs.readFileSync(historyFile, "utf-8")
|
||||
const historyFiles = fileContent.split("\n")
|
||||
for (const historyFile of historyFiles.filter(x => x)) {
|
||||
streams.push(fs.readFileSync(historyFile))
|
||||
}
|
||||
}
|
||||
|
||||
streams.push(fs.readFileSync(getFullPath(logsFileName)))
|
||||
|
||||
const combinedContent = Buffer.concat(streams)
|
||||
return combinedContent
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import { getSingleFileMaxSizeInfo } from "../system"
|
||||
|
||||
describe("system", () => {
|
||||
describe("getSingleFileMaxSizeInfo", () => {
|
||||
it.each([
|
||||
["100B", "50B"],
|
||||
["200K", "100K"],
|
||||
["20M", "10M"],
|
||||
["4G", "2G"],
|
||||
])(
|
||||
"Halving even number (%s) returns halved size and 1 history file (%s)",
|
||||
(totalValue, expectedMaxSize) => {
|
||||
const result = getSingleFileMaxSizeInfo(totalValue)
|
||||
expect(result).toEqual({
|
||||
size: expectedMaxSize,
|
||||
totalHistoryFiles: 1,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it.each([
|
||||
["5B", "1B", 4],
|
||||
["17K", "1K", 16],
|
||||
["21M", "1M", 20],
|
||||
["3G", "1G", 2],
|
||||
])(
|
||||
"Halving an odd number (%s) returns as many files as size (-1) (%s)",
|
||||
(totalValue, expectedMaxSize, totalHistoryFiles) => {
|
||||
const result = getSingleFileMaxSizeInfo(totalValue)
|
||||
expect(result).toEqual({
|
||||
size: expectedMaxSize,
|
||||
totalHistoryFiles,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it.each([
|
||||
["1B", "1B"],
|
||||
["1K", "500B"],
|
||||
["1M", "500K"],
|
||||
["1G", "500M"],
|
||||
])(
|
||||
"Halving '%s' returns halved unit (%s)",
|
||||
(totalValue, expectedMaxSize) => {
|
||||
const result = getSingleFileMaxSizeInfo(totalValue)
|
||||
expect(result).toEqual({
|
||||
size: expectedMaxSize,
|
||||
totalHistoryFiles: 1,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it.each([[undefined], [""], ["50"], ["wrongvalue"]])(
|
||||
"Halving wrongly formatted value ('%s') returns undefined",
|
||||
totalValue => {
|
||||
const result = getSingleFileMaxSizeInfo(totalValue!)
|
||||
expect(result).toBeUndefined()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import "@spectrum-css/button/dist/index-vars.css"
|
||||
import Tooltip from "../Tooltip/Tooltip.svelte"
|
||||
import AbsTooltip from "../Tooltip/AbsTooltip.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let type
|
||||
export let disabled = false
|
||||
|
@ -16,48 +17,53 @@
|
|||
export let tooltip = undefined
|
||||
export let newStyles = true
|
||||
export let id
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<button
|
||||
{id}
|
||||
{type}
|
||||
class:spectrum-Button--cta={cta}
|
||||
class:spectrum-Button--primary={primary}
|
||||
class:spectrum-Button--secondary={secondary}
|
||||
class:spectrum-Button--warning={warning}
|
||||
class:spectrum-Button--overBackground={overBackground}
|
||||
class:spectrum-Button--quiet={quiet}
|
||||
class:new-styles={newStyles}
|
||||
class:active
|
||||
class:disabled
|
||||
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
||||
{disabled}
|
||||
on:click|preventDefault
|
||||
>
|
||||
{#if icon}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label={icon}
|
||||
>
|
||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||
</svg>
|
||||
{/if}
|
||||
{#if $$slots}
|
||||
<span class="spectrum-Button-label"><slot /></span>
|
||||
{/if}
|
||||
{#if tooltip}
|
||||
<div class="tooltip">
|
||||
<Tooltip textWrapping={true} direction={"bottom"} text={tooltip} />
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
<AbsTooltip text={tooltip}>
|
||||
<button
|
||||
{id}
|
||||
{type}
|
||||
class:spectrum-Button--cta={cta}
|
||||
class:spectrum-Button--primary={primary}
|
||||
class:spectrum-Button--secondary={secondary}
|
||||
class:spectrum-Button--warning={warning}
|
||||
class:spectrum-Button--overBackground={overBackground}
|
||||
class:spectrum-Button--quiet={quiet}
|
||||
class:new-styles={newStyles}
|
||||
class:active
|
||||
class:is-disabled={disabled}
|
||||
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
||||
on:click|preventDefault={() => {
|
||||
if (!disabled) {
|
||||
dispatch("click")
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if icon}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label={icon}
|
||||
>
|
||||
<use xlink:href="#spectrum-icon-18-{icon}" />
|
||||
</svg>
|
||||
{/if}
|
||||
{#if $$slots}
|
||||
<span class="spectrum-Button-label"><slot /></span>
|
||||
{/if}
|
||||
</button>
|
||||
</AbsTooltip>
|
||||
|
||||
<style>
|
||||
button {
|
||||
position: relative;
|
||||
}
|
||||
button.is-disabled {
|
||||
cursor: default;
|
||||
}
|
||||
.spectrum-Button-label {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
@ -66,23 +72,6 @@
|
|||
.active {
|
||||
color: var(--spectrum-global-color-blue-600) !important;
|
||||
}
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
width: 160px;
|
||||
text-align: center;
|
||||
transform: translateX(-50%);
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 130ms ease-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
button:hover .tooltip {
|
||||
opacity: 1;
|
||||
}
|
||||
.spectrum-Button--primary.new-styles {
|
||||
background: var(--spectrum-global-color-gray-800);
|
||||
border-color: transparent;
|
||||
|
@ -96,10 +85,10 @@
|
|||
border-color: transparent;
|
||||
color: var(--spectrum-global-color-gray-900);
|
||||
}
|
||||
.spectrum-Button--secondary.new-styles:not(.disabled):hover {
|
||||
.spectrum-Button--secondary.new-styles:not(.is-disabled):hover {
|
||||
background: var(--spectrum-global-color-gray-300);
|
||||
}
|
||||
.spectrum-Button--secondary.new-styles.disabled {
|
||||
.spectrum-Button--secondary.new-styles.is-disabled {
|
||||
color: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -90,6 +90,6 @@
|
|||
.spectrum-Popover {
|
||||
min-width: var(--spectrum-global-dimension-size-2000);
|
||||
border-color: var(--spectrum-global-color-gray-300);
|
||||
overflow: visible;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
<script context="module">
|
||||
export const TooltipPosition = {
|
||||
Top: "top",
|
||||
Right: "right",
|
||||
Bottom: "bottom",
|
||||
Left: "left",
|
||||
}
|
||||
export const TooltipType = {
|
||||
Default: "default",
|
||||
Info: "info",
|
||||
Positive: "positive",
|
||||
Negative: "negative",
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import Portal from "svelte-portal"
|
||||
import { fade } from "svelte/transition"
|
||||
import "@spectrum-css/tooltip/dist/index-vars.css"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
export let position = TooltipPosition.Top
|
||||
export let type = TooltipType.Default
|
||||
export let text = ""
|
||||
export let fixed = false
|
||||
export let color = null
|
||||
|
||||
let wrapper
|
||||
let hovered = false
|
||||
let left
|
||||
let top
|
||||
let visible = false
|
||||
let timeout
|
||||
let interval
|
||||
|
||||
$: {
|
||||
if (hovered || fixed) {
|
||||
// Debounce showing by 200ms to avoid flashing tooltip
|
||||
timeout = setTimeout(show, 200)
|
||||
} else {
|
||||
hide()
|
||||
}
|
||||
}
|
||||
$: tooltipStyle = color ? `background:${color};` : null
|
||||
$: tipStyle = color ? `border-top-color:${color};` : null
|
||||
|
||||
// Computes the position of the tooltip
|
||||
const updateTooltipPosition = () => {
|
||||
const node = wrapper?.children?.[0]
|
||||
if (!node) {
|
||||
left = null
|
||||
top = null
|
||||
return
|
||||
}
|
||||
const bounds = node.getBoundingClientRect()
|
||||
|
||||
// Determine where to render tooltip based on position prop
|
||||
if (position === TooltipPosition.Top) {
|
||||
left = bounds.left + bounds.width / 2
|
||||
top = bounds.top
|
||||
} else if (position === TooltipPosition.Right) {
|
||||
left = bounds.left + bounds.width
|
||||
top = bounds.top + bounds.height / 2
|
||||
} else if (position === TooltipPosition.Bottom) {
|
||||
left = bounds.left + bounds.width / 2
|
||||
top = bounds.top + bounds.height
|
||||
} else if (position === TooltipPosition.Left) {
|
||||
left = bounds.left
|
||||
top = bounds.top + bounds.height / 2
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the position of the tooltip then shows it.
|
||||
// We set up a poll to frequently update the position of the tooltip in case
|
||||
// the target moves.
|
||||
const show = () => {
|
||||
updateTooltipPosition()
|
||||
interval = setInterval(updateTooltipPosition, 100)
|
||||
visible = true
|
||||
}
|
||||
|
||||
// Hides the tooltip
|
||||
const hide = () => {
|
||||
clearTimeout(timeout)
|
||||
clearInterval(interval)
|
||||
visible = false
|
||||
}
|
||||
|
||||
// Ensure we clean up interval and timeout
|
||||
onDestroy(hide)
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={wrapper}
|
||||
class="abs-tooltip"
|
||||
on:focus={null}
|
||||
on:mouseover={() => (hovered = true)}
|
||||
on:mouseleave={() => (hovered = false)}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{#if visible && text && left != null && top != null}
|
||||
<Portal target=".spectrum">
|
||||
<span
|
||||
class="spectrum-Tooltip spectrum-Tooltip--{type} spectrum-Tooltip--{position} is-open"
|
||||
style={`left:${left}px;top:${top}px;${tooltipStyle}`}
|
||||
transition:fade|local={{ duration: 130 }}
|
||||
>
|
||||
<span class="spectrum-Tooltip-label">{text}</span>
|
||||
<span class="spectrum-Tooltip-tip" style={tipStyle} />
|
||||
</span>
|
||||
</Portal>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.abs-tooltip {
|
||||
display: contents;
|
||||
}
|
||||
.spectrum-Tooltip {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
margin: 0;
|
||||
max-width: 280px;
|
||||
transition: top 130ms ease-out, left 130ms ease-out;
|
||||
}
|
||||
.spectrum-Tooltip-label {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Colour overrides for default type */
|
||||
.spectrum-Tooltip--default {
|
||||
background: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
.spectrum-Tooltip--default .spectrum-Tooltip-tip {
|
||||
border-top-color: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
|
||||
/* Position styles */
|
||||
.spectrum-Tooltip--top {
|
||||
transform: translateX(-50%) translateY(calc(-100% - 8px));
|
||||
}
|
||||
.spectrum-Tooltip--right {
|
||||
transform: translateX(8px) translateY(-50%);
|
||||
}
|
||||
.spectrum-Tooltip--bottom {
|
||||
transform: translateX(-50%) translateY(8px);
|
||||
}
|
||||
.spectrum-Tooltip--left {
|
||||
transform: translateX(calc(-100% - 8px)) translateY(-50%);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,39 @@
|
|||
<script>
|
||||
import AbsTooltip from "./AbsTooltip.svelte"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
export let text = null
|
||||
export let condition = true
|
||||
export let duration = 3000
|
||||
export let position
|
||||
export let type
|
||||
|
||||
let visible = false
|
||||
let timeout
|
||||
|
||||
$: {
|
||||
if (condition) {
|
||||
showTooltip()
|
||||
} else {
|
||||
hideTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
const showTooltip = () => {
|
||||
visible = true
|
||||
timeout = setTimeout(() => {
|
||||
visible = false
|
||||
}, duration)
|
||||
}
|
||||
|
||||
const hideTooltip = () => {
|
||||
visible = false
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
|
||||
onDestroy(hideTooltip)
|
||||
</script>
|
||||
|
||||
<AbsTooltip {position} {type} text={visible ? text : null} fixed={visible}>
|
||||
<slot />
|
||||
</AbsTooltip>
|
|
@ -36,6 +36,12 @@ export { default as Layout } from "./Layout/Layout.svelte"
|
|||
export { default as Page } from "./Layout/Page.svelte"
|
||||
export { default as Link } from "./Link/Link.svelte"
|
||||
export { default as Tooltip } from "./Tooltip/Tooltip.svelte"
|
||||
export { default as TempTooltip } from "./Tooltip/TempTooltip.svelte"
|
||||
export {
|
||||
default as AbsTooltip,
|
||||
TooltipPosition,
|
||||
TooltipType,
|
||||
} from "./Tooltip/AbsTooltip.svelte"
|
||||
export { default as TooltipWrapper } from "./Tooltip/TooltipWrapper.svelte"
|
||||
export { default as Menu } from "./Menu/Menu.svelte"
|
||||
export { default as MenuSection } from "./Menu/Section.svelte"
|
||||
|
|
|
@ -127,8 +127,12 @@ export const selectedAutomation = derived(automationStore, $automationStore => {
|
|||
export const userSelectedResourceMap = derived(userStore, $userStore => {
|
||||
let map = {}
|
||||
$userStore.forEach(user => {
|
||||
if (user.builderMetadata?.selectedResourceId) {
|
||||
map[user.builderMetadata?.selectedResourceId] = user
|
||||
const resource = user.builderMetadata?.selectedResourceId
|
||||
if (resource) {
|
||||
if (!map[resource]) {
|
||||
map[resource] = []
|
||||
}
|
||||
map[resource].push(user)
|
||||
}
|
||||
})
|
||||
return map
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
$: text = getText(filters)
|
||||
|
||||
const getText = filters => {
|
||||
const count = filters?.length
|
||||
const count = filters?.filter(filter => filter.field)?.length
|
||||
return count ? `Filter (${count})` : "Filter"
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,21 +2,13 @@
|
|||
import { goto, url } from "@roxi/routify"
|
||||
import { tables } from "stores/backend"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
import {
|
||||
Input,
|
||||
Label,
|
||||
ModalContent,
|
||||
Toggle,
|
||||
Divider,
|
||||
Layout,
|
||||
} from "@budibase/bbui"
|
||||
import { Input, Label, ModalContent, Layout } from "@budibase/bbui"
|
||||
import { datasources } from "stores/backend"
|
||||
import TableDataImport from "../TableDataImport.svelte"
|
||||
import {
|
||||
BUDIBASE_INTERNAL_DB_ID,
|
||||
BUDIBASE_DATASOURCE_TYPE,
|
||||
} from "constants/backend"
|
||||
import { buildAutoColumn, getAutoColumnInformation } from "builderStore/utils"
|
||||
|
||||
$: tableNames = $tables.list.map(table => table.name)
|
||||
$: selectedSource = $datasources.list.find(
|
||||
|
@ -43,28 +35,12 @@
|
|||
}
|
||||
|
||||
let error = ""
|
||||
let autoColumns = getAutoColumnInformation()
|
||||
|
||||
let schema = {}
|
||||
let rows = []
|
||||
let allValid = true
|
||||
let displayColumn = null
|
||||
|
||||
function getAutoColumns() {
|
||||
const selectedAutoColumns = {}
|
||||
|
||||
Object.entries(autoColumns).forEach(([subtype, column]) => {
|
||||
if (column.enabled) {
|
||||
selectedAutoColumns[column.name] = buildAutoColumn(
|
||||
name,
|
||||
column.name,
|
||||
subtype
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return selectedAutoColumns
|
||||
}
|
||||
|
||||
function checkValid(evt) {
|
||||
const tableName = evt.target.value
|
||||
if (tableNames.includes(tableName)) {
|
||||
|
@ -77,7 +53,7 @@
|
|||
async function saveTable() {
|
||||
let newTable = {
|
||||
name,
|
||||
schema: { ...schema, ...getAutoColumns() },
|
||||
schema: { ...schema },
|
||||
rows,
|
||||
type: "internal",
|
||||
sourceId: targetDatasourceId,
|
||||
|
@ -118,21 +94,6 @@
|
|||
bind:value={name}
|
||||
{error}
|
||||
/>
|
||||
<div class="autocolumns">
|
||||
<Label extraSmall grey>Auto Columns</Label>
|
||||
<div class="toggles">
|
||||
<div class="toggle-1">
|
||||
<Toggle text="Created by" bind:value={autoColumns.createdBy.enabled} />
|
||||
<Toggle text="Created at" bind:value={autoColumns.createdAt.enabled} />
|
||||
<Toggle text="Auto ID" bind:value={autoColumns.autoID.enabled} />
|
||||
</div>
|
||||
<div class="toggle-2">
|
||||
<Toggle text="Updated by" bind:value={autoColumns.updatedBy.enabled} />
|
||||
<Toggle text="Updated at" bind:value={autoColumns.updatedAt.enabled} />
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
<div>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Label grey extraSmall
|
||||
|
@ -148,24 +109,3 @@
|
|||
</Layout>
|
||||
</div>
|
||||
</ModalContent>
|
||||
|
||||
<style>
|
||||
.autocolumns {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
.toggles {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.toggle-1 :global(> *) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.toggle-2 :global(> *) {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<script>
|
||||
import { Icon, Heading } from "@budibase/bbui"
|
||||
|
||||
export let showClose = false
|
||||
export let onClose = () => {}
|
||||
export let heading = ""
|
||||
</script>
|
||||
|
||||
<section class="page">
|
||||
<div class="closeButton">
|
||||
{#if showClose}
|
||||
<Icon hoverable name="Close" on:click={onClose} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="heading">
|
||||
<Heading weight="light">{heading}</Heading>
|
||||
</div>
|
||||
<slot />
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.heading {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
height: 38px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -2,6 +2,7 @@
|
|||
import { Icon } from "@budibase/bbui"
|
||||
import { createEventDispatcher, getContext } from "svelte"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
import UserAvatars from "../../pages/builder/app/[application]/_components/UserAvatars.svelte"
|
||||
|
||||
export let icon
|
||||
export let withArrow = false
|
||||
|
@ -98,21 +99,25 @@
|
|||
<Icon color={iconColor} size="S" name={icon} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="text" title={showTooltip ? text : null}>{text}</div>
|
||||
<div class="text" title={showTooltip ? text : null}>
|
||||
{text}
|
||||
{#if selectedBy}
|
||||
<UserAvatars size="XS" users={selectedBy} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if withActions}
|
||||
<div class="actions">
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.right}
|
||||
<div class="right">
|
||||
<slot name="right" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if selectedBy}
|
||||
<div class="selected-by-label">{helpers.getUserLabel(selectedBy)}</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -136,13 +141,16 @@
|
|||
}
|
||||
.nav-item.highlighted {
|
||||
background-color: var(--spectrum-global-color-gray-200);
|
||||
--avatars-background: var(--spectrum-global-color-gray-200);
|
||||
}
|
||||
.nav-item.selected {
|
||||
background-color: var(--spectrum-global-color-gray-300);
|
||||
--avatars-background: var(--spectrum-global-color-gray-300);
|
||||
color: var(--ink);
|
||||
}
|
||||
.nav-item:hover {
|
||||
background-color: var(--spectrum-global-color-gray-300);
|
||||
--avatars-background: var(--spectrum-global-color-gray-300);
|
||||
}
|
||||
.nav-item:hover .actions {
|
||||
visibility: visible;
|
||||
|
@ -159,37 +167,6 @@
|
|||
padding-left: var(--spacing-l);
|
||||
}
|
||||
|
||||
/* Selected user styles */
|
||||
.nav-item.selectedBy:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(100% - 4px);
|
||||
height: 28px;
|
||||
border: 2px solid var(--selected-by-color);
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.selected-by-label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background: var(--selected-by-color);
|
||||
padding: 2px 4px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
transform: translateY(calc(1px - 100%));
|
||||
border-top-right-radius: 2px;
|
||||
border-top-left-radius: 2px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 130ms ease-out;
|
||||
}
|
||||
.nav-item.selectedBy:hover .selected-by-label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Needed to fully display the actions icon */
|
||||
.nav-item.scrollable .nav-item-content {
|
||||
padding-right: 1px;
|
||||
|
@ -245,6 +222,9 @@
|
|||
color: var(--spectrum-global-color-gray-900);
|
||||
order: 2;
|
||||
width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.scrollable .text {
|
||||
flex: 0 0 auto;
|
||||
|
|
|
@ -208,7 +208,9 @@
|
|||
<div class="syntax-error">
|
||||
Current Handlebars syntax is invalid, please check the
|
||||
guide
|
||||
<a href="https://handlebarsjs.com/guide/">here</a>
|
||||
<a href="https://handlebarsjs.com/guide/" target="_blank"
|
||||
>here</a
|
||||
>
|
||||
for more details.
|
||||
</div>
|
||||
{:else}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
Link,
|
||||
Modal,
|
||||
StatusLight,
|
||||
AbsTooltip,
|
||||
} from "@budibase/bbui"
|
||||
import RevertModal from "components/deploy/RevertModal.svelte"
|
||||
import VersionModal from "components/deploy/VersionModal.svelte"
|
||||
|
@ -250,15 +251,20 @@
|
|||
<Link quiet on:click={unpublishApp}>Unpublish</Link>
|
||||
</span>
|
||||
<span class="revert-link">
|
||||
<Link
|
||||
disabled={!$isOnlyUser}
|
||||
quiet
|
||||
secondary
|
||||
on:click={revertApp}
|
||||
tooltip="Unavailable - another user is editing this app"
|
||||
<AbsTooltip
|
||||
text={$isOnlyUser
|
||||
? null
|
||||
: "Unavailable - another user is editing this app"}
|
||||
>
|
||||
Revert
|
||||
</Link>
|
||||
<Link
|
||||
disabled={!$isOnlyUser}
|
||||
quiet
|
||||
secondary
|
||||
on:click={revertApp}
|
||||
>
|
||||
Revert
|
||||
</Link>
|
||||
</AbsTooltip>
|
||||
</span>
|
||||
{:else}
|
||||
<span class="status-text unpublished">Not published</span>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
makeStateBinding,
|
||||
} from "builderStore/dataBinding"
|
||||
import { currentAsset, store } from "builderStore"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
|
||||
const flipDurationMs = 150
|
||||
const EVENT_TYPE_KEY = "##eventHandlerType"
|
||||
|
@ -29,6 +30,26 @@
|
|||
let actionQuery
|
||||
let selectedAction = actions?.length ? actions[0] : null
|
||||
|
||||
const setUpdateActions = actions => {
|
||||
return actions
|
||||
? cloneDeep(actions)
|
||||
.filter(action => {
|
||||
return (
|
||||
action[EVENT_TYPE_KEY] === "Update State" &&
|
||||
action.parameters?.type === "set" &&
|
||||
action.parameters.key
|
||||
)
|
||||
})
|
||||
.reduce((acc, action) => {
|
||||
acc[action.id] = action
|
||||
return acc
|
||||
}, {})
|
||||
: []
|
||||
}
|
||||
|
||||
// Snapshot original action state
|
||||
let updateStateActions = setUpdateActions(actions)
|
||||
|
||||
$: {
|
||||
// Ensure parameters object is never null
|
||||
if (selectedAction && !selectedAction.parameters) {
|
||||
|
@ -125,8 +146,9 @@
|
|||
actions = e.detail.items
|
||||
}
|
||||
|
||||
const getAllBindings = (bindings, eventContextBindings, actions) => {
|
||||
const getAllBindings = (actionBindings, eventContextBindings, actions) => {
|
||||
let allBindings = []
|
||||
let cloneActionBindings = cloneDeep(actionBindings)
|
||||
if (!actions) {
|
||||
return []
|
||||
}
|
||||
|
@ -144,11 +166,19 @@
|
|||
.forEach(action => {
|
||||
// Check we have a binding for this action, and generate one if not
|
||||
const stateBinding = makeStateBinding(action.parameters.key)
|
||||
const hasKey = bindings.some(binding => {
|
||||
const hasKey = actionBindings.some(binding => {
|
||||
return binding.runtimeBinding === stateBinding.runtimeBinding
|
||||
})
|
||||
if (!hasKey) {
|
||||
bindings.push(stateBinding)
|
||||
let existing = updateStateActions[action.id]
|
||||
if (existing) {
|
||||
const existingBinding = makeStateBinding(existing.parameters.key)
|
||||
cloneActionBindings = cloneActionBindings.filter(
|
||||
binding =>
|
||||
binding.runtimeBinding !== existingBinding.runtimeBinding
|
||||
)
|
||||
}
|
||||
allBindings.push(stateBinding)
|
||||
}
|
||||
})
|
||||
// Get which indexes are asynchronous automations as we want to filter them out from the bindings
|
||||
|
@ -164,15 +194,16 @@
|
|||
.filter(index => index !== undefined)
|
||||
|
||||
// Based on the above, filter out the asynchronous automations from the bindings
|
||||
if (asynchronousAutomationIndexes) {
|
||||
allBindings = eventContextBindings
|
||||
.filter((binding, index) => {
|
||||
let contextBindings = asynchronousAutomationIndexes
|
||||
? eventContextBindings.filter((binding, index) => {
|
||||
return !asynchronousAutomationIndexes.includes(index)
|
||||
})
|
||||
.concat(bindings)
|
||||
} else {
|
||||
allBindings = eventContextBindings.concat(bindings)
|
||||
}
|
||||
: eventContextBindings
|
||||
|
||||
allBindings = contextBindings
|
||||
.concat(cloneActionBindings)
|
||||
.concat(allBindings)
|
||||
|
||||
return allBindings
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -70,8 +70,9 @@
|
|||
} set`
|
||||
</script>
|
||||
|
||||
<div class="action-count">{actionText}</div>
|
||||
<ActionButton on:click={openDrawer}>Define actions</ActionButton>
|
||||
<div class="action-editor">
|
||||
<ActionButton on:click={openDrawer}>{actionText}</ActionButton>
|
||||
</div>
|
||||
|
||||
<Drawer bind:this={drawer} title={"Actions"}>
|
||||
<svelte:fragment slot="description">
|
||||
|
@ -89,9 +90,7 @@
|
|||
</Drawer>
|
||||
|
||||
<style>
|
||||
.action-count {
|
||||
padding-top: 6px;
|
||||
padding-bottom: var(--spacing-s);
|
||||
font-weight: 600;
|
||||
.action-editor :global(.spectrum-ActionButton) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
let drawer
|
||||
let boundValue
|
||||
|
||||
$: text = getText(value)
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchema($currentAsset, datasource)
|
||||
$: options = allowCellEditing
|
||||
|
@ -31,6 +32,17 @@
|
|||
allowLinks: true,
|
||||
})
|
||||
|
||||
const getText = value => {
|
||||
if (!value?.length) {
|
||||
return "All columns"
|
||||
}
|
||||
let text = `${value.length} column`
|
||||
if (value.length !== 1) {
|
||||
text += "s"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const getSchema = (asset, datasource) => {
|
||||
const schema = getSchemaForDatasource(asset, datasource).schema
|
||||
|
||||
|
@ -76,7 +88,7 @@
|
|||
</script>
|
||||
|
||||
<div class="column-editor">
|
||||
<ActionButton on:click={open}>Configure columns</ActionButton>
|
||||
<ActionButton on:click={open}>{text}</ActionButton>
|
||||
</div>
|
||||
<Drawer bind:this={drawer} title="Columns">
|
||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
|
|
|
@ -12,25 +12,36 @@
|
|||
export let componentInstance
|
||||
export let value = []
|
||||
|
||||
const convertOldColumnFormat = oldColumns => {
|
||||
if (typeof oldColumns?.[0] === "string") {
|
||||
value = oldColumns.map(field => ({ name: field, displayName: field }))
|
||||
}
|
||||
}
|
||||
|
||||
$: convertOldColumnFormat(value)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let drawer
|
||||
let boundValue
|
||||
|
||||
$: text = getText(value)
|
||||
$: convertOldColumnFormat(value)
|
||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchema($currentAsset, datasource)
|
||||
$: options = Object.keys(schema || {})
|
||||
$: sanitisedValue = getValidColumns(value, options)
|
||||
$: updateBoundValue(sanitisedValue)
|
||||
|
||||
const getText = value => {
|
||||
if (!value?.length) {
|
||||
return "All fields"
|
||||
}
|
||||
let text = `${value.length} field`
|
||||
if (value.length !== 1) {
|
||||
text += "s"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const convertOldColumnFormat = oldColumns => {
|
||||
if (typeof oldColumns?.[0] === "string") {
|
||||
value = oldColumns.map(field => ({ name: field, displayName: field }))
|
||||
}
|
||||
}
|
||||
|
||||
const getSchema = (asset, datasource) => {
|
||||
const schema = getSchemaForDatasource(asset, datasource).schema
|
||||
|
||||
|
@ -75,7 +86,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<ActionButton on:click={open}>Configure fields</ActionButton>
|
||||
<div class="field-configuration">
|
||||
<ActionButton on:click={open}>{text}</ActionButton>
|
||||
</div>
|
||||
|
||||
<Drawer bind:this={drawer} title="Form Fields">
|
||||
<svelte:fragment slot="description">
|
||||
Configure the fields in your form.
|
||||
|
@ -83,3 +97,9 @@
|
|||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
<ColumnDrawer slot="body" bind:columns={boundValue} {options} {schema} />
|
||||
</Drawer>
|
||||
|
||||
<style>
|
||||
.field-configuration :global(.spectrum-ActionButton) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchemaForDatasource($currentAsset, datasource)?.schema
|
||||
$: schemaFields = Object.values(schema || {})
|
||||
$: text = getText(value)
|
||||
$: text = getText(value?.filter(filter => filter.field))
|
||||
|
||||
async function saveFilter() {
|
||||
dispatch("change", tempValue)
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
<script>
|
||||
import { Tooltip } from "@budibase/bbui"
|
||||
|
||||
export let text
|
||||
export let url
|
||||
export let active = false
|
||||
export let disabled = false
|
||||
export let tooltip = null
|
||||
</script>
|
||||
|
||||
<div class="side-nav-item">
|
||||
|
@ -18,11 +15,6 @@
|
|||
{text || ""}
|
||||
</div>
|
||||
{/if}
|
||||
{#if tooltip}
|
||||
<div class="tooltip">
|
||||
<Tooltip textWrapping direction="right" text={tooltip} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -45,17 +37,4 @@
|
|||
pointer-events: none;
|
||||
color: var(--spectrum-global-color-gray-500) !important;
|
||||
}
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
transform: translateY(-50%);
|
||||
left: 100%;
|
||||
top: 50%;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 130ms ease-out;
|
||||
z-index: 100;
|
||||
}
|
||||
.side-nav-item:hover .tooltip {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
import { createValidationStore } from "helpers/validation/yup"
|
||||
import * as appValidation from "helpers/validation/yup/app"
|
||||
import TemplateCard from "components/common/TemplateCard.svelte"
|
||||
import createFromScratchScreen from "builderStore/store/screenTemplates/createFromScratchScreen"
|
||||
import { Roles } from "constants/backend"
|
||||
import { lowercase } from "helpers"
|
||||
|
||||
export let template
|
||||
|
@ -142,21 +140,6 @@
|
|||
// Create user
|
||||
await auth.setInitInfo({})
|
||||
|
||||
// Create a default home screen if no template was selected
|
||||
if (template == null) {
|
||||
let defaultScreenTemplate = createFromScratchScreen.create()
|
||||
defaultScreenTemplate.routing.route = "/home"
|
||||
defaultScreenTemplate.routing.roldId = Roles.BASIC
|
||||
try {
|
||||
await store.actions.screens.save(defaultScreenTemplate)
|
||||
} catch (err) {
|
||||
console.error("Could not create a default application screen", err)
|
||||
notifications.warning(
|
||||
"Encountered an issue creating the default screen."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
$goto(`/builder/app/${createdApp.instance._id}`)
|
||||
} catch (error) {
|
||||
creating = false
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
}
|
||||
|
||||
onMount(() => {
|
||||
window.isBuilder = true
|
||||
window.closePreview = () => {
|
||||
store.update(state => ({
|
||||
...state,
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<script>
|
||||
import { UserAvatar } from "@budibase/frontend-core"
|
||||
import { TooltipPosition, Avatar } from "@budibase/bbui"
|
||||
|
||||
export let users = []
|
||||
export let order = "ltr"
|
||||
export let size = "S"
|
||||
export let tooltipPosition = TooltipPosition.Top
|
||||
|
||||
$: uniqueUsers = unique(users)
|
||||
$: uniqueUsers = unique(users, order)
|
||||
$: avatars = getAvatars(uniqueUsers, order)
|
||||
|
||||
const unique = users => {
|
||||
let uniqueUsers = {}
|
||||
|
@ -12,17 +17,51 @@
|
|||
})
|
||||
return Object.values(uniqueUsers)
|
||||
}
|
||||
|
||||
const getAvatars = (users, order) => {
|
||||
const avatars = users.slice(0, 3)
|
||||
if (users.length > 3) {
|
||||
const overflow = {
|
||||
_id: "overflow",
|
||||
label: `+${users.length - 3}`,
|
||||
}
|
||||
if (order === "ltr") {
|
||||
avatars.push(overflow)
|
||||
} else {
|
||||
avatars.unshift(overflow)
|
||||
}
|
||||
}
|
||||
return avatars.map((user, idx) => ({
|
||||
...user,
|
||||
zIndex: order === "ltr" ? idx : uniqueUsers.length - idx,
|
||||
}))
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="avatars">
|
||||
{#each uniqueUsers as user}
|
||||
<UserAvatar {user} tooltipDirection="bottom" />
|
||||
{#each avatars as user}
|
||||
<span style="z-index:{user.zIndex};">
|
||||
{#if user._id === "overflow"}
|
||||
<Avatar
|
||||
{size}
|
||||
initials={user.label}
|
||||
color="var(--spectrum-global-color-gray-500)"
|
||||
/>
|
||||
{:else}
|
||||
<UserAvatar {size} {user} {tooltipPosition} />
|
||||
{/if}
|
||||
</span>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatars {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
span:not(:first-of-type) {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.avatars :global(.spectrum-Avatar) {
|
||||
border: 2px solid var(--avatars-background, var(--background));
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
Heading,
|
||||
Modal,
|
||||
notifications,
|
||||
TooltipPosition,
|
||||
} from "@budibase/bbui"
|
||||
import AppActions from "components/deploy/AppActions.svelte"
|
||||
import { API } from "api"
|
||||
|
@ -172,7 +173,11 @@
|
|||
</div>
|
||||
<div class="toprightnav">
|
||||
<span>
|
||||
<UserAvatars users={$userStore} />
|
||||
<UserAvatars
|
||||
users={$userStore}
|
||||
order="rtl"
|
||||
tooltipPosition={TooltipPosition.Bottom}
|
||||
/>
|
||||
</span>
|
||||
<AppActions {application} {loaded} />
|
||||
</div>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
import { Button, Modal } from "@budibase/bbui"
|
||||
import ImportQueriesModal from "./RestImportQueriesModal.svelte"
|
||||
|
||||
export let datasourceId
|
||||
let importQueriesModal
|
||||
</script>
|
||||
|
||||
<Modal bind:this={importQueriesModal}>
|
||||
<ImportQueriesModal createDatasource={false} datasourceId={"todo"} />
|
||||
<ImportQueriesModal createDatasource={false} {datasourceId} />
|
||||
</Modal>
|
||||
|
||||
<div class="button">
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
} from "stores/backend"
|
||||
|
||||
import { hasData } from "stores/selectors"
|
||||
import { Icon, notifications, Heading, Body } from "@budibase/bbui"
|
||||
import { notifications, Body, Icon, AbsTooltip } from "@budibase/bbui"
|
||||
import { params, goto } from "@roxi/routify"
|
||||
import CreateExternalDatasourceModal from "./_components/CreateExternalDatasourceModal/index.svelte"
|
||||
import CreateInternalTableModal from "./_components/CreateInternalTableModal.svelte"
|
||||
import DatasourceOption from "./_components/DatasourceOption.svelte"
|
||||
import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte"
|
||||
import CreationPage from "components/common/CreationPage.svelte"
|
||||
import ICONS from "components/backend/DatasourceNavigator/icons/index.js"
|
||||
import FontAwesomeIcon from "components/common/FontAwesomeIcon.svelte"
|
||||
|
||||
let internalTableModal
|
||||
let externalDatasourceModal
|
||||
|
@ -46,25 +46,16 @@
|
|||
bind:this={externalDatasourceModal}
|
||||
/>
|
||||
|
||||
<div class="page">
|
||||
<div class="closeButton">
|
||||
{#if hasData($datasources, $tables)}
|
||||
<Icon hoverable name="Close" on:click={$goto("./table")} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="heading">
|
||||
<Heading weight="light">Add new data source</Heading>
|
||||
</div>
|
||||
|
||||
<CreationPage
|
||||
showClose={hasData($datasources, $tables)}
|
||||
onClose={() => $goto("./table")}
|
||||
heading="Add new data source"
|
||||
>
|
||||
<div class="subHeading">
|
||||
<Body>Get started with our Budibase DB</Body>
|
||||
<div
|
||||
role="tooltip"
|
||||
title="Budibase DB is built with CouchDB"
|
||||
class="tooltip"
|
||||
>
|
||||
<FontAwesomeIcon name="fa-solid fa-circle-info" />
|
||||
</div>
|
||||
<AbsTooltip text="Budibase DB is built with CouchDB">
|
||||
<Icon name="Info" size="S" />
|
||||
</AbsTooltip>
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
|
@ -113,37 +104,19 @@
|
|||
</DatasourceOption>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</CreationPage>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
height: 38px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.subHeading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 36px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
margin-left: 6px;
|
||||
.subHeading :global(p) {
|
||||
color: var(--spectrum-global-color-gray-600) !important;
|
||||
}
|
||||
|
||||
.options {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
<script>
|
||||
import { tables } from "stores/backend"
|
||||
import { ModalContent, Body, Layout, Icon, Heading } from "@budibase/bbui"
|
||||
import blankScreenPreview from "./blankScreenPreview.png"
|
||||
import listScreenPreview from "./listScreenPreview.png"
|
||||
|
||||
export let onConfirm
|
||||
export let onCancel
|
||||
|
||||
let listScreenModeKey = "autoCreate"
|
||||
let blankScreenModeKey = "blankScreen"
|
||||
|
||||
let selectedScreenMode
|
||||
|
||||
const confirmScreenSelection = async () => {
|
||||
await onConfirm(selectedScreenMode)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<ModalContent
|
||||
title="Add screens"
|
||||
confirmText="Continue"
|
||||
cancelText="Cancel"
|
||||
onConfirm={confirmScreenSelection}
|
||||
{onCancel}
|
||||
disabled={!selectedScreenMode}
|
||||
size="M"
|
||||
>
|
||||
<Layout noPadding gap="S">
|
||||
<div
|
||||
class="screen-type item blankView"
|
||||
class:selected={selectedScreenMode == blankScreenModeKey}
|
||||
on:click={() => {
|
||||
selectedScreenMode = blankScreenModeKey
|
||||
}}
|
||||
>
|
||||
<div class="content screen-type-wrap">
|
||||
<img
|
||||
alt="blank screen preview"
|
||||
class="preview"
|
||||
src={blankScreenPreview}
|
||||
/>
|
||||
<div class="screen-type-text">
|
||||
<Heading size="XS">Blank screen</Heading>
|
||||
<Body size="S">Add an empty blank screen</Body>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="color: var(--spectrum-global-color-green-600); float: right"
|
||||
>
|
||||
<div
|
||||
class={`checkmark-spacing ${
|
||||
selectedScreenMode == blankScreenModeKey ? "visible" : ""
|
||||
}`}
|
||||
>
|
||||
<Icon size="S" name="CheckmarkCircle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="listViewTitle">
|
||||
<Heading size="XS">Quickly create a screen from your data</Heading>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="screen-type item"
|
||||
class:selected={selectedScreenMode == listScreenModeKey}
|
||||
on:click={() => {
|
||||
selectedScreenMode = listScreenModeKey
|
||||
}}
|
||||
class:disabled={!$tables.list.filter(table => table._id !== "ta_users")
|
||||
.length}
|
||||
>
|
||||
<div class="content screen-type-wrap">
|
||||
<img
|
||||
alt="list screen preview"
|
||||
class="preview"
|
||||
src={listScreenPreview}
|
||||
/>
|
||||
<div class="screen-type-text">
|
||||
<Heading size="XS">List view</Heading>
|
||||
<Body size="S">
|
||||
Create, edit and view your data in a list view screen with side
|
||||
panel
|
||||
</Body>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="color: var(--spectrum-global-color-green-600); float: right"
|
||||
>
|
||||
<div
|
||||
class={`checkmark-spacing ${
|
||||
selectedScreenMode == listScreenModeKey ? "visible" : ""
|
||||
}`}
|
||||
>
|
||||
<Icon size="S" name="CheckmarkCircle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</ModalContent>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.screen-type-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
.disabled {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.checkmark-spacing {
|
||||
margin-right: var(--spacing-m);
|
||||
opacity: 0;
|
||||
}
|
||||
.content {
|
||||
letter-spacing: 0px;
|
||||
}
|
||||
.item {
|
||||
cursor: pointer;
|
||||
grid-gap: var(--spectrum-alias-grid-margin-xsmall);
|
||||
background: var(--spectrum-alias-background-color-secondary);
|
||||
transition: 0.3s all;
|
||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||
border-radius: 4px;
|
||||
border-width: 1px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.item:hover,
|
||||
.selected {
|
||||
background: var(--spectrum-alias-background-color-tertiary);
|
||||
}
|
||||
.screen-type-wrap .screen-type-text {
|
||||
padding-left: var(--spectrum-alias-item-padding-xl);
|
||||
}
|
||||
.screen-type-wrap .screen-type-text :global(h1) {
|
||||
padding-bottom: var(--spacing-xs);
|
||||
}
|
||||
.screen-type-wrap :global(.spectrum-Icon) {
|
||||
min-width: var(--spectrum-icon-size-m);
|
||||
}
|
||||
.screen-type-wrap :global(.spectrum-Heading) {
|
||||
padding-bottom: var(--spectrum-alias-item-padding-s);
|
||||
}
|
||||
.preview {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.listViewTitle {
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
.blankView {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
|
@ -9,7 +9,7 @@
|
|||
Helpers,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import ScreenDetailsModal from "./ScreenDetailsModal.svelte"
|
||||
import ScreenDetailsModal from "components/design/ScreenDetailsModal.svelte"
|
||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||
import { makeComponentUnique } from "builderStore/componentUtils"
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<script>
|
||||
import { Search, Layout, Select, Body, Button } from "@budibase/bbui"
|
||||
import Panel from "components/design/Panel.svelte"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { roles } from "stores/backend"
|
||||
import { store, sortedScreens, userSelectedResourceMap } from "builderStore"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte"
|
||||
import ScreenWizard from "./ScreenWizard.svelte"
|
||||
import RoleIndicator from "./RoleIndicator.svelte"
|
||||
import { RoleUtils } from "@budibase/frontend-core"
|
||||
|
||||
let searchString
|
||||
let accessRole = "all"
|
||||
let showNewScreenModal
|
||||
|
||||
$: filteredScreens = getFilteredScreens(
|
||||
$sortedScreens,
|
||||
|
@ -31,7 +30,7 @@
|
|||
|
||||
<Panel title="Screens" borderRight>
|
||||
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||
<Button on:click={showNewScreenModal} cta>Add screen</Button>
|
||||
<Button on:click={() => $goto("../../new")} cta>Add screen</Button>
|
||||
<Search
|
||||
placeholder="Search"
|
||||
value={searchString}
|
||||
|
@ -74,5 +73,3 @@
|
|||
</Layout>
|
||||
{/if}
|
||||
</Panel>
|
||||
|
||||
<ScreenWizard bind:showModal={showNewScreenModal} />
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
Binary file not shown.
Before Width: | Height: | Size: 106 KiB |
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import ScreenDetailsModal from "./ScreenDetailsModal.svelte"
|
||||
import NewScreenModal from "./NewScreenModal.svelte"
|
||||
import ScreenDetailsModal from "components/design/ScreenDetailsModal.svelte"
|
||||
import DatasourceModal from "./DatasourceModal.svelte"
|
||||
import ScreenRoleModal from "./ScreenRoleModal.svelte"
|
||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||
|
@ -11,11 +10,11 @@
|
|||
import { tables } from "stores/backend"
|
||||
import { Roles } from "constants/backend"
|
||||
import { capitalise } from "helpers"
|
||||
import { goto } from "@roxi/routify"
|
||||
|
||||
let pendingScreen
|
||||
|
||||
// Modal refs
|
||||
let newScreenModal
|
||||
let screenDetailsModal
|
||||
let datasourceModal
|
||||
let screenAccessRoleModal
|
||||
|
@ -26,16 +25,6 @@
|
|||
let blankScreenUrl = null
|
||||
let screenMode = null
|
||||
|
||||
// External handler to show the screen wizard
|
||||
export const showModal = () => {
|
||||
selectedTemplates = null
|
||||
blankScreenUrl = null
|
||||
screenMode = null
|
||||
pendingScreen = null
|
||||
screenAccessRole = Roles.BASIC
|
||||
newScreenModal.show()
|
||||
}
|
||||
|
||||
// Creates an array of screens, checking and sanitising their URLs
|
||||
const createScreens = async ({ screens, screenAccessRole }) => {
|
||||
if (!screens?.length) {
|
||||
|
@ -43,6 +32,8 @@
|
|||
}
|
||||
|
||||
try {
|
||||
let screenId
|
||||
|
||||
for (let screen of screens) {
|
||||
// Check we aren't clashing with an existing URL
|
||||
if (hasExistingUrl(screen.routing.route)) {
|
||||
|
@ -64,7 +55,8 @@
|
|||
screen.routing.roleId = screenAccessRole
|
||||
|
||||
// Create the screen
|
||||
await store.actions.screens.save(screen)
|
||||
const response = await store.actions.screens.save(screen)
|
||||
screenId = response._id
|
||||
|
||||
// Add link in layout for list screens
|
||||
if (screen.props._instanceName.endsWith("List")) {
|
||||
|
@ -74,7 +66,10 @@
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
$goto(`./${screenId}`)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
notifications.error("Error creating screens")
|
||||
}
|
||||
}
|
||||
|
@ -104,18 +99,24 @@
|
|||
}
|
||||
|
||||
// Handler for NewScreenModal
|
||||
const confirmScreenSelection = async mode => {
|
||||
export const show = mode => {
|
||||
selectedTemplates = null
|
||||
blankScreenUrl = null
|
||||
screenMode = mode
|
||||
pendingScreen = null
|
||||
screenAccessRole = Roles.BASIC
|
||||
|
||||
if (mode === "autoCreate") {
|
||||
if (mode === "table") {
|
||||
datasourceModal.show()
|
||||
} else {
|
||||
} else if (mode === "blank") {
|
||||
let templates = getTemplates($store, $tables.list)
|
||||
const blankScreenTemplate = templates.find(
|
||||
t => t.id === "createFromScratch"
|
||||
)
|
||||
pendingScreen = blankScreenTemplate.create()
|
||||
screenDetailsModal.show()
|
||||
} else {
|
||||
throw new Error("Invalid mode provided")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,7 +156,7 @@
|
|||
|
||||
// Submit screen config for creation.
|
||||
const confirmScreenCreation = async () => {
|
||||
if (screenMode === "blankScreen") {
|
||||
if (screenMode === "blank") {
|
||||
confirmBlankScreenCreation({
|
||||
screenUrl: blankScreenUrl,
|
||||
screenAccessRole,
|
||||
|
@ -166,7 +167,7 @@
|
|||
}
|
||||
|
||||
const roleSelectBack = () => {
|
||||
if (screenMode === "blankScreen") {
|
||||
if (screenMode === "blank") {
|
||||
screenDetailsModal.show()
|
||||
} else {
|
||||
datasourceModal.show()
|
||||
|
@ -174,14 +175,9 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:this={newScreenModal}>
|
||||
<NewScreenModal onConfirm={confirmScreenSelection} />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={datasourceModal}>
|
||||
<DatasourceModal
|
||||
onConfirm={confirmScreenDatasources}
|
||||
onCancel={() => newScreenModal.show()}
|
||||
initalScreens={!selectedTemplates ? [] : [...selectedTemplates]}
|
||||
/>
|
||||
</Modal>
|
||||
|
@ -198,7 +194,6 @@
|
|||
<Modal bind:this={screenDetailsModal}>
|
||||
<ScreenDetailsModal
|
||||
onConfirm={confirmScreenBlank}
|
||||
onCancel={() => newScreenModal.show()}
|
||||
initialUrl={blankScreenUrl}
|
||||
/>
|
||||
</Modal>
|
|
@ -40,14 +40,14 @@
|
|||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Autogenerated screens"
|
||||
title="Access"
|
||||
confirmText="Done"
|
||||
cancelText="Back"
|
||||
{onConfirm}
|
||||
{onCancel}
|
||||
disabled={!!error}
|
||||
>
|
||||
Select which level of access you want your screens to have
|
||||
Select the level of access required to see these screens
|
||||
<Select
|
||||
bind:value={screenAccessRole}
|
||||
on:change={onChangeRole}
|
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -1,67 +1,12 @@
|
|||
<script>
|
||||
import { store, selectedScreen } from "builderStore"
|
||||
import { onMount } from "svelte"
|
||||
import { redirect } from "@roxi/routify"
|
||||
import { Layout, Button, Detail, notifications } from "@budibase/bbui"
|
||||
import Logo from "assets/bb-space-man.svg"
|
||||
import createFromScratchScreen from "builderStore/store/screenTemplates/createFromScratchScreen"
|
||||
import { Roles } from "constants/backend"
|
||||
import { store as frontendStore } from "builderStore"
|
||||
|
||||
let loaded = false
|
||||
|
||||
const createFirstScreen = async () => {
|
||||
let screen = createFromScratchScreen.create()
|
||||
screen.routing.route = "/home"
|
||||
screen.routing.roldId = Roles.BASIC
|
||||
screen.routing.homeScreen = true
|
||||
try {
|
||||
const savedScreen = await store.actions.screens.save(screen)
|
||||
notifications.success("Screen created successfully")
|
||||
$redirect(`./${savedScreen._id}`)
|
||||
} catch (err) {
|
||||
console.error("Could not create screen", err)
|
||||
notifications.error("Error creating screen")
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if ($selectedScreen) {
|
||||
$redirect(`./${$selectedScreen._id}`)
|
||||
} else if ($store.screens?.length) {
|
||||
$redirect(`./${$store.screens[0]._id}`)
|
||||
$: {
|
||||
if ($frontendStore.screens.length > 0) {
|
||||
$redirect(`./${$frontendStore.screens[0]._id}`)
|
||||
} else {
|
||||
loaded = true
|
||||
$redirect("./new")
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<div class="centered">
|
||||
<Layout gap="S" justifyItems="center">
|
||||
<img class="img-size" alt="logo" src={Logo} />
|
||||
<div class="new-screen-text">
|
||||
<Detail size="L">LET’S BRING THIS APP TO LIFE</Detail>
|
||||
</div>
|
||||
<Button on:click={createFirstScreen} size="M" cta icon="Add">
|
||||
Create first screen
|
||||
</Button>
|
||||
</Layout>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.centered {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.new-screen-text {
|
||||
width: 150px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
.img-size {
|
||||
width: 170px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<script>
|
||||
import { Body } from "@budibase/bbui"
|
||||
import CreationPage from "components/common/CreationPage.svelte"
|
||||
import blankImage from "./blank.png"
|
||||
import tableImage from "./table.png"
|
||||
import CreateScreenModal from "./_components/CreateScreenModal.svelte"
|
||||
import { store } from "builderStore"
|
||||
import { goto } from "@roxi/routify"
|
||||
|
||||
let createScreenModal
|
||||
|
||||
$: hasScreens = $store.screens?.length
|
||||
</script>
|
||||
|
||||
<div class="page">
|
||||
<CreationPage
|
||||
showClose={$store.screens.length > 0}
|
||||
onClose={() => $goto(`./${$store.screens[0]._id}`)}
|
||||
heading={hasScreens ? "Create new screen" : "Create your first screen"}
|
||||
>
|
||||
<div class="subHeading">
|
||||
<Body>Start from scratch or create screens from your data</Body>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
<div class="card" on:click={() => createScreenModal.show("blank")}>
|
||||
<div class="image">
|
||||
<img alt="" src={blankImage} />
|
||||
</div>
|
||||
<div class="text">
|
||||
<Body size="S">Blank screen</Body>
|
||||
<Body size="XS">Add an empty blank screen</Body>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" on:click={() => createScreenModal.show("table")}>
|
||||
<div class="image">
|
||||
<img alt="" src={tableImage} />
|
||||
</div>
|
||||
<div class="text">
|
||||
<Body size="S">Table</Body>
|
||||
<Body size="XS">View, edit and delete rows on a table</Body>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CreationPage>
|
||||
</div>
|
||||
|
||||
<CreateScreenModal bind:this={createScreenModal} />
|
||||
|
||||
<style>
|
||||
.page {
|
||||
padding: 28px 40px 40px 40px;
|
||||
}
|
||||
|
||||
.subHeading :global(p) {
|
||||
text-align: center;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 36px;
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.card {
|
||||
max-width: 235px;
|
||||
transition: filter 150ms;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
filter: brightness(1.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image {
|
||||
border-radius: 4px 4px 0 0;
|
||||
width: 100%;
|
||||
max-height: 127px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.text :global(p:nth-child(2)) {
|
||||
color: var(--grey-6);
|
||||
}
|
||||
</style>
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { Content, SideNav, SideNavItem } from "components/portal/page"
|
||||
import { Page, Layout } from "@budibase/bbui"
|
||||
import { Page, Layout, AbsTooltip, TooltipPosition } from "@budibase/bbui"
|
||||
import { url, isActive } from "@roxi/routify"
|
||||
import DeleteModal from "components/deploy/DeleteModal.svelte"
|
||||
import { isOnlyUser } from "builderStore"
|
||||
|
@ -45,16 +45,20 @@
|
|||
active={$isActive("./version")}
|
||||
/>
|
||||
<div class="delete-action">
|
||||
<SideNavItem
|
||||
text="Delete app"
|
||||
on:click={() => {
|
||||
deleteModal.show()
|
||||
}}
|
||||
disabled={!$isOnlyUser}
|
||||
tooltip={$isOnlyUser
|
||||
<AbsTooltip
|
||||
position={TooltipPosition.Bottom}
|
||||
text={$isOnlyUser
|
||||
? null
|
||||
: "Unavailable - another user is editing this app"}
|
||||
/>
|
||||
>
|
||||
<SideNavItem
|
||||
text="Delete app"
|
||||
disabled={!$isOnlyUser}
|
||||
on:click={() => {
|
||||
deleteModal.show()
|
||||
}}
|
||||
/>
|
||||
</AbsTooltip>
|
||||
</div>
|
||||
</SideNav>
|
||||
<slot />
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
Heading,
|
||||
Body,
|
||||
Modal,
|
||||
AbsTooltip,
|
||||
TooltipPosition,
|
||||
} from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import CreateRestoreModal from "./CreateRestoreModal.svelte"
|
||||
|
@ -46,16 +48,18 @@
|
|||
</div>
|
||||
|
||||
{#if row.type !== "restore"}
|
||||
<MenuItem
|
||||
on:click={restoreDialog.show}
|
||||
icon="Revert"
|
||||
disabled={!$isOnlyUser}
|
||||
tooltip={$isOnlyUser
|
||||
? null
|
||||
: "Unavailable - another user is editing this app"}
|
||||
<AbsTooltip
|
||||
position={TooltipPosition.Left}
|
||||
text="Unavailable - another user is editing this app"
|
||||
>
|
||||
Restore
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
on:click={restoreDialog.show}
|
||||
icon="Revert"
|
||||
disabled={!$isOnlyUser}
|
||||
>
|
||||
Restore
|
||||
</MenuItem>
|
||||
</AbsTooltip>
|
||||
<MenuItem on:click={deleteDialog.show} icon="Delete">Delete</MenuItem>
|
||||
<MenuItem on:click={downloadExport} icon="Download">Download</MenuItem>
|
||||
{/if}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import { Layout, Body, Button } from "@budibase/bbui"
|
||||
import { downloadStream } from "@budibase/frontend-core"
|
||||
import Spinner from "components/common/Spinner.svelte"
|
||||
|
||||
import { API } from "api"
|
||||
|
||||
let loading = false
|
||||
|
||||
async function download() {
|
||||
loading = true
|
||||
try {
|
||||
await downloadStream(await API.getSystemLogs())
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
<Body>Download your latest logs to share with the Budibase team</Body>
|
||||
<div class="download-button">
|
||||
<Button cta on:click={download} disabled={loading}>
|
||||
<div class="button-content">
|
||||
{#if loading}
|
||||
<Spinner size="10" />
|
||||
{/if}
|
||||
Download system logs
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.button-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -7,8 +7,6 @@
|
|||
import { API } from "api"
|
||||
import { store, automationStore } from "builderStore"
|
||||
import { auth, admin } from "stores/portal"
|
||||
import createFromScratchScreen from "builderStore/store/screenTemplates/createFromScratchScreen"
|
||||
import { Roles } from "constants/backend"
|
||||
|
||||
let name = "My first app"
|
||||
let url = "my-first-app"
|
||||
|
@ -38,11 +36,6 @@
|
|||
// Create user
|
||||
await auth.setInitInfo({})
|
||||
|
||||
let defaultScreenTemplate = createFromScratchScreen.create()
|
||||
defaultScreenTemplate.routing.route = "/home"
|
||||
defaultScreenTemplate.routing.roldId = Roles.BASIC
|
||||
await store.actions.screens.save(defaultScreenTemplate)
|
||||
|
||||
appId = createdApp.instance._id
|
||||
return createdApp
|
||||
}
|
||||
|
|
|
@ -85,6 +85,13 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
|
|||
title: "Audit Logs",
|
||||
href: "/builder/portal/account/auditLogs",
|
||||
})
|
||||
|
||||
if (!$admin.cloud) {
|
||||
accountSubPages.push({
|
||||
title: "System Logs",
|
||||
href: "/builder/portal/account/systemLogs",
|
||||
})
|
||||
}
|
||||
}
|
||||
if ($admin.cloud && $auth?.user?.accountPortalAccess) {
|
||||
accountSubPages.push({
|
||||
|
|
|
@ -3223,6 +3223,46 @@
|
|||
"key": "allowManualEntry",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Play sound on scan",
|
||||
"key": "beepOnScan",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"label": "Sound pitch",
|
||||
"key": "beepFrequency",
|
||||
"dependsOn": "beepOnScan",
|
||||
"defaultValue": 2637,
|
||||
"options": [
|
||||
{
|
||||
"label": "Low",
|
||||
"value": 2096
|
||||
},
|
||||
{
|
||||
"label": "Regular",
|
||||
"value": 2637
|
||||
},
|
||||
{
|
||||
"label": "High",
|
||||
"value": 3136
|
||||
},
|
||||
{ "label": "Custom", "value": "custom" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "Sound frequency (Hz)",
|
||||
"key": "customFrequency",
|
||||
"defaultValue": 1046,
|
||||
"min": 20,
|
||||
"max": 8000,
|
||||
"dependsOn": {
|
||||
"setting": "beepFrequency",
|
||||
"value": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "validation/string",
|
||||
"label": "Validation",
|
||||
|
@ -4541,6 +4581,16 @@
|
|||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Hide notifications",
|
||||
"key": "notificationOverride",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "clickBehaviour",
|
||||
"value": "details"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -5178,6 +5228,16 @@
|
|||
"value": "View",
|
||||
"invert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "Hide notifications",
|
||||
"key": "notificationOverride",
|
||||
"defaultValue": false,
|
||||
"dependsOn": {
|
||||
"setting": "showSaveButton",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
export let sidePanelShowDelete
|
||||
export let sidePanelSaveLabel
|
||||
export let sidePanelDeleteLabel
|
||||
export let notificationOverride
|
||||
|
||||
const { fetchDatasourceSchema, API } = getContext("sdk")
|
||||
const stateKey = `ID_${generate()}`
|
||||
|
@ -253,6 +254,7 @@
|
|||
fields: sidePanelFields || normalFields,
|
||||
title: editTitle,
|
||||
labelPosition: "left",
|
||||
notificationOverride,
|
||||
}}
|
||||
/>
|
||||
</BlockComponent>
|
||||
|
@ -277,6 +279,7 @@
|
|||
fields: sidePanelFields || normalFields,
|
||||
title: "Create Row",
|
||||
labelPosition: "left",
|
||||
notificationOverride,
|
||||
}}
|
||||
/>
|
||||
</BlockComponent>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
export let rowId
|
||||
export let actionUrl
|
||||
export let noRowsMessage
|
||||
export let notificationOverride
|
||||
|
||||
const { fetchDatasourceSchema } = getContext("sdk")
|
||||
|
||||
|
@ -87,6 +88,7 @@
|
|||
showDeleteButton,
|
||||
schema,
|
||||
repeaterId,
|
||||
notificationOverride,
|
||||
}
|
||||
|
||||
const fetchSchema = async () => {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
export let showDeleteButton
|
||||
export let schema
|
||||
export let repeaterId
|
||||
export let notificationOverride
|
||||
|
||||
const FieldTypeToComponentMap = {
|
||||
string: "stringfield",
|
||||
|
@ -47,6 +48,7 @@
|
|||
parameters: {
|
||||
providerId: formId,
|
||||
tableId: dataSource?.tableId,
|
||||
notificationOverride,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
export let disabled = false
|
||||
export let allowManualEntry = false
|
||||
export let scanButtonText = "Scan code"
|
||||
export let beepOnScan = false
|
||||
export let beepFrequency = 2637
|
||||
export let customFrequency = 1046
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let videoEle
|
||||
|
@ -21,8 +25,13 @@
|
|||
fps: 25,
|
||||
qrbox: { width: 250, height: 250 },
|
||||
}
|
||||
const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
|
||||
|
||||
const onScanSuccess = decodedText => {
|
||||
if (value != decodedText) {
|
||||
if (beepOnScan) {
|
||||
beep()
|
||||
}
|
||||
dispatch("change", decodedText)
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +93,27 @@
|
|||
}
|
||||
camModal.hide()
|
||||
}
|
||||
|
||||
const beep = () => {
|
||||
const oscillator = audioCtx.createOscillator()
|
||||
const gainNode = audioCtx.createGain()
|
||||
|
||||
oscillator.connect(gainNode)
|
||||
gainNode.connect(audioCtx.destination)
|
||||
|
||||
const frequency =
|
||||
beepFrequency === "custom" ? customFrequency : beepFrequency
|
||||
oscillator.frequency.value = frequency
|
||||
oscillator.type = "square"
|
||||
|
||||
const duration = 420
|
||||
const endTime = audioCtx.currentTime + duration / 1000
|
||||
gainNode.gain.setValueAtTime(1, audioCtx.currentTime)
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.001, endTime)
|
||||
|
||||
oscillator.start()
|
||||
oscillator.stop(endTime)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="scanner-video-wrapper">
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
export let onChange
|
||||
export let allowManualEntry
|
||||
export let scanButtonText
|
||||
export let beepOnScan
|
||||
export let beepFrequency
|
||||
export let customFrequency
|
||||
|
||||
let fieldState
|
||||
let fieldApi
|
||||
|
@ -42,6 +45,9 @@
|
|||
disabled={fieldState.disabled}
|
||||
{allowManualEntry}
|
||||
scanButtonText={scanText}
|
||||
{beepOnScan}
|
||||
{beepFrequency}
|
||||
{customFrequency}
|
||||
/>
|
||||
{/if}
|
||||
</Field>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { Heading, Select, ActionButton } from "@budibase/bbui"
|
||||
import { devToolsStore } from "../../stores"
|
||||
import { devToolsStore, appStore } from "../../stores"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const context = getContext("context")
|
||||
|
@ -45,27 +45,41 @@
|
|||
icon="Code"
|
||||
on:click={() => devToolsStore.actions.setVisible(!$devToolsStore.visible)}
|
||||
>
|
||||
{$devToolsStore.visible ? "Close" : "Open"} DevTools
|
||||
DevTools
|
||||
</ActionButton>
|
||||
{/if}
|
||||
{#if window.parent.isBuilder}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="LinkOut"
|
||||
on:click={() => {
|
||||
window.parent.closePreview?.()
|
||||
window.open(`/${$appStore.appId}`, "_blank")
|
||||
}}
|
||||
>
|
||||
Fullscreen
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="Close"
|
||||
on:click={() => window.parent.closePreview?.()}
|
||||
>
|
||||
Close
|
||||
</ActionButton>
|
||||
{/if}
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="Close"
|
||||
on:click={() => window.parent.closePreview?.()}
|
||||
>
|
||||
Close preview
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dev-preview-header {
|
||||
flex: 0 0 60px;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
background-color: black;
|
||||
padding: 0 var(--spacing-xl);
|
||||
grid-template-columns: 1fr auto auto auto;
|
||||
grid-gap: var(--spacing-xl);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xl);
|
||||
}
|
||||
.dev-preview-header :global(.spectrum-Heading) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.dev-preview-header.mobile {
|
||||
grid-template-columns: 1fr auto auto;
|
||||
|
|
|
@ -30,6 +30,7 @@ import { buildBackupsEndpoints } from "./backups"
|
|||
import { buildEnvironmentVariableEndpoints } from "./environmentVariables"
|
||||
import { buildEventEndpoints } from "./events"
|
||||
import { buildAuditLogsEndpoints } from "./auditLogs"
|
||||
import { buildLogsEndpoints } from "./logs"
|
||||
|
||||
/**
|
||||
* Random identifier to uniquely identify a session in a tab. This is
|
||||
|
@ -277,5 +278,6 @@ export const createAPIClient = config => {
|
|||
...buildEnvironmentVariableEndpoints(API),
|
||||
...buildEventEndpoints(API),
|
||||
...buildAuditLogsEndpoints(API),
|
||||
...buildLogsEndpoints(API),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
export const buildLogsEndpoints = API => ({
|
||||
/**
|
||||
* Gets a stream for the system logs.
|
||||
*/
|
||||
getSystemLogs: async () => {
|
||||
return await API.get({
|
||||
url: "/api/system/logs",
|
||||
json: false,
|
||||
parseResponse: async response => {
|
||||
return response
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
|
@ -1,60 +1,23 @@
|
|||
<script>
|
||||
import { Avatar, Tooltip } from "@budibase/bbui"
|
||||
import { Avatar, AbsTooltip, TooltipPosition } from "@budibase/bbui"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
|
||||
export let user
|
||||
export let size
|
||||
export let tooltipDirection = "top"
|
||||
export let size = "S"
|
||||
export let tooltipPosition = TooltipPosition.Top
|
||||
export let showTooltip = true
|
||||
|
||||
$: tooltipStyle = getTooltipStyle(tooltipDirection)
|
||||
|
||||
const getTooltipStyle = direction => {
|
||||
if (!direction) {
|
||||
return ""
|
||||
}
|
||||
if (direction === "top") {
|
||||
return "transform: translateX(-50%) translateY(-100%);"
|
||||
} else if (direction === "bottom") {
|
||||
return "transform: translateX(-50%) translateY(100%);"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if user}
|
||||
<div class="user-avatar">
|
||||
<AbsTooltip
|
||||
text={showTooltip ? helpers.getUserLabel(user) : null}
|
||||
position={tooltipPosition}
|
||||
color={helpers.getUserColor(user)}
|
||||
>
|
||||
<Avatar
|
||||
{size}
|
||||
initials={helpers.getUserInitials(user)}
|
||||
color={helpers.getUserColor(user)}
|
||||
/>
|
||||
{#if showTooltip}
|
||||
<div class="tooltip" style={tooltipStyle}>
|
||||
<Tooltip
|
||||
direction={tooltipDirection}
|
||||
textWrapping
|
||||
text={helpers.getUserLabel(user)}
|
||||
size="S"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</AbsTooltip>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.user-avatar {
|
||||
position: relative;
|
||||
}
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 130ms ease-out;
|
||||
}
|
||||
.user-avatar:hover .tooltip {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<script>
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const { config, dispatch } = getContext("grid")
|
||||
</script>
|
||||
|
||||
<ActionButton
|
||||
icon="TableColumnAddRight"
|
||||
quiet
|
||||
size="M"
|
||||
on:click={() => dispatch("add-column")}
|
||||
disabled={!$config.allowSchemaChanges}
|
||||
>
|
||||
Add column
|
||||
</ActionButton>
|
|
@ -1,18 +0,0 @@
|
|||
<script>
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const { dispatch, columns, stickyColumn, config, loaded } = getContext("grid")
|
||||
</script>
|
||||
|
||||
<ActionButton
|
||||
icon="TableRowAddBottom"
|
||||
quiet
|
||||
size="M"
|
||||
on:click={() => dispatch("add-row-inline")}
|
||||
disabled={!loaded ||
|
||||
!$config.allowAddRows ||
|
||||
(!$columns.length && !$stickyColumn)}
|
||||
>
|
||||
Add row
|
||||
</ActionButton>
|
|
@ -71,6 +71,7 @@
|
|||
contentLines,
|
||||
gridFocused,
|
||||
error,
|
||||
canAddRows,
|
||||
} = context
|
||||
|
||||
// Keep config store up to date with props
|
||||
|
@ -143,7 +144,7 @@
|
|||
<HeaderRow />
|
||||
<GridBody />
|
||||
</div>
|
||||
{#if allowAddRows}
|
||||
{#if $canAddRows}
|
||||
<NewRow />
|
||||
{/if}
|
||||
<div class="overlays">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
renderedRows,
|
||||
renderedColumns,
|
||||
rowVerticalInversionIndex,
|
||||
config,
|
||||
canAddRows,
|
||||
hoveredRowId,
|
||||
dispatch,
|
||||
isDragging,
|
||||
|
@ -43,7 +43,7 @@
|
|||
invertY={idx >= $rowVerticalInversionIndex}
|
||||
/>
|
||||
{/each}
|
||||
{#if $config.allowAddRows && $renderedColumns.length}
|
||||
{#if $canAddRows}
|
||||
<div
|
||||
class="blank"
|
||||
class:highlighted={$hoveredRowId === BlankRowID}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { getContext } from "svelte"
|
||||
import GridScrollWrapper from "./GridScrollWrapper.svelte"
|
||||
import HeaderCell from "../cells/HeaderCell.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { Icon, TempTooltip, TooltipType } from "@budibase/bbui"
|
||||
|
||||
const {
|
||||
renderedColumns,
|
||||
|
@ -11,10 +11,13 @@
|
|||
hiddenColumnsWidth,
|
||||
width,
|
||||
config,
|
||||
hasNonAutoColumn,
|
||||
tableId,
|
||||
loading,
|
||||
} = getContext("grid")
|
||||
|
||||
$: columnsWidth = $renderedColumns.reduce(
|
||||
(total, col) => (total += col.width),
|
||||
(total, col) => total + col.width,
|
||||
0
|
||||
)
|
||||
$: end = $hiddenColumnsWidth + columnsWidth - 1 - $scroll.left
|
||||
|
@ -30,13 +33,21 @@
|
|||
</div>
|
||||
</GridScrollWrapper>
|
||||
{#if $config.allowSchemaChanges}
|
||||
<div
|
||||
class="add"
|
||||
style="left:{left}px"
|
||||
on:click={() => dispatch("add-column")}
|
||||
>
|
||||
<Icon name="Add" />
|
||||
</div>
|
||||
{#key $tableId}
|
||||
<TempTooltip
|
||||
text="Click here to create your first column"
|
||||
type={TooltipType.Info}
|
||||
condition={!$hasNonAutoColumn && !$loading}
|
||||
>
|
||||
<div
|
||||
class="add"
|
||||
style="left:{left}px;"
|
||||
on:click={() => dispatch("add-column")}
|
||||
>
|
||||
<Icon name="Add" />
|
||||
</div>
|
||||
</TempTooltip>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { getContext, onDestroy, onMount, tick } from "svelte"
|
||||
import { Icon, Button } from "@budibase/bbui"
|
||||
import { Icon, Button, TempTooltip, TooltipType } from "@budibase/bbui"
|
||||
import GridScrollWrapper from "./GridScrollWrapper.svelte"
|
||||
import DataCell from "../cells/DataCell.svelte"
|
||||
import { fade } from "svelte/transition"
|
||||
|
@ -27,7 +27,8 @@
|
|||
rowVerticalInversionIndex,
|
||||
columnHorizontalInversionIndex,
|
||||
selectedRows,
|
||||
config,
|
||||
loading,
|
||||
canAddRows,
|
||||
} = getContext("grid")
|
||||
|
||||
let visible = false
|
||||
|
@ -40,6 +41,7 @@
|
|||
$: $tableId, (visible = false)
|
||||
$: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
|
||||
$: selectedRowCount = Object.values($selectedRows).length
|
||||
$: hasNoRows = !$rows.length
|
||||
|
||||
const shouldInvertY = (offset, inversionIndex, rows) => {
|
||||
if (offset === 0) {
|
||||
|
@ -147,16 +149,22 @@
|
|||
</script>
|
||||
|
||||
<!-- New row FAB -->
|
||||
{#if !visible && !selectedRowCount && $config.allowAddRows && firstColumn}
|
||||
<div
|
||||
class="new-row-fab"
|
||||
on:click={() => dispatch("add-row-inline")}
|
||||
transition:fade|local={{ duration: 130 }}
|
||||
class:offset={!$stickyColumn}
|
||||
>
|
||||
<Icon name="Add" size="S" />
|
||||
</div>
|
||||
{/if}
|
||||
<TempTooltip
|
||||
text="Click here to create your first row"
|
||||
condition={hasNoRows && !$loading}
|
||||
type={TooltipType.Info}
|
||||
>
|
||||
{#if !visible && !selectedRowCount && $canAddRows}
|
||||
<div
|
||||
class="new-row-fab"
|
||||
on:click={() => dispatch("add-row-inline")}
|
||||
transition:fade|local={{ duration: 130 }}
|
||||
class:offset={!$stickyColumn}
|
||||
>
|
||||
<Icon name="Add" size="S" />
|
||||
</div>
|
||||
{/if}
|
||||
</TempTooltip>
|
||||
|
||||
<!-- Only show new row functionality if we have any columns -->
|
||||
{#if visible}
|
||||
|
|
|
@ -13,11 +13,10 @@
|
|||
rows,
|
||||
selectedRows,
|
||||
stickyColumn,
|
||||
renderedColumns,
|
||||
renderedRows,
|
||||
focusedCellId,
|
||||
hoveredRowId,
|
||||
config,
|
||||
canAddRows,
|
||||
selectedCellMap,
|
||||
focusedRow,
|
||||
scrollLeft,
|
||||
|
@ -93,7 +92,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if $config.allowAddRows && ($renderedColumns.length || $stickyColumn)}
|
||||
{#if $canAddRows}
|
||||
<div
|
||||
class="row new"
|
||||
on:mouseenter={$isDragging
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
config,
|
||||
menu,
|
||||
gridFocused,
|
||||
canAddRows,
|
||||
} = getContext("grid")
|
||||
|
||||
const ignoredOriginSelectors = [
|
||||
|
@ -45,7 +46,7 @@
|
|||
e.preventDefault()
|
||||
focusFirstCell()
|
||||
} else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
||||
if ($config.allowAddRows) {
|
||||
if ($canAddRows) {
|
||||
e.preventDefault()
|
||||
dispatch("add-row-inline")
|
||||
}
|
||||
|
@ -99,7 +100,7 @@
|
|||
}
|
||||
break
|
||||
case "Enter":
|
||||
if ($config.allowAddRows) {
|
||||
if ($canAddRows) {
|
||||
dispatch("add-row-inline")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
focusedCellAPI,
|
||||
focusedRowId,
|
||||
notifications,
|
||||
canAddRows,
|
||||
} = getContext("grid")
|
||||
|
||||
$: style = makeStyle($menu)
|
||||
|
@ -93,7 +94,7 @@
|
|||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="Duplicate"
|
||||
disabled={isNewRow || !$config.allowAddRows}
|
||||
disabled={isNewRow || !$canAddRows}
|
||||
on:click={duplicate}
|
||||
>
|
||||
Duplicate row
|
||||
|
|
|
@ -83,6 +83,21 @@ export const deriveStores = context => {
|
|||
await saveChanges()
|
||||
}
|
||||
|
||||
// Derive if we have any normal columns
|
||||
const hasNonAutoColumn = derived(
|
||||
[columns, stickyColumn],
|
||||
([$columns, $stickyColumn]) => {
|
||||
let allCols = $columns || []
|
||||
if ($stickyColumn) {
|
||||
allCols = [...allCols, $stickyColumn]
|
||||
}
|
||||
const normalCols = allCols.filter(column => {
|
||||
return !column.schema?.autocolumn
|
||||
})
|
||||
return normalCols.length > 0
|
||||
}
|
||||
)
|
||||
|
||||
// Persists column changes by saving metadata against table schema
|
||||
const saveChanges = async () => {
|
||||
const $columns = get(columns)
|
||||
|
@ -128,6 +143,7 @@ export const deriveStores = context => {
|
|||
}
|
||||
|
||||
return {
|
||||
hasNonAutoColumn,
|
||||
columns: {
|
||||
...columns,
|
||||
actions: {
|
||||
|
|
|
@ -70,6 +70,8 @@ export const deriveStores = context => {
|
|||
rowHeight,
|
||||
stickyColumn,
|
||||
width,
|
||||
hasNonAutoColumn,
|
||||
config,
|
||||
} = context
|
||||
|
||||
// Derive the row that contains the selected cell
|
||||
|
@ -112,7 +114,16 @@ export const deriveStores = context => {
|
|||
return ($stickyColumn?.width || 0) + $width + GutterWidth < 1100
|
||||
})
|
||||
|
||||
// Derive if we're able to add rows
|
||||
const canAddRows = derived(
|
||||
[config, hasNonAutoColumn],
|
||||
([$config, $hasNonAutoColumn]) => {
|
||||
return $config.allowAddRows && $hasNonAutoColumn
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
canAddRows,
|
||||
focusedRow,
|
||||
contentLines,
|
||||
compact,
|
||||
|
|
|
@ -11,3 +11,26 @@ export function downloadText(filename, text) {
|
|||
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
export async function downloadStream(streamResponse) {
|
||||
const blob = await streamResponse.blob()
|
||||
|
||||
const contentDisposition = streamResponse.headers.get("Content-Disposition")
|
||||
|
||||
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(
|
||||
contentDisposition
|
||||
)
|
||||
|
||||
const filename = matches[1].replace(/['"]/g, "")
|
||||
|
||||
const resBlob = new Blob([blob])
|
||||
|
||||
const blobUrl = URL.createObjectURL(resBlob)
|
||||
|
||||
const link = document.createElement("a")
|
||||
link.href = blobUrl
|
||||
link.download = filename
|
||||
link.click()
|
||||
|
||||
URL.revokeObjectURL(blobUrl)
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ export * as RoleUtils from "./roles"
|
|||
export * as Utils from "./utils"
|
||||
export { memo, derivedMemo } from "./memo"
|
||||
export { createWebsocket } from "./websocket"
|
||||
export { downloadText } from "./download"
|
||||
export * from "./download"
|
||||
|
|
|
@ -27,11 +27,14 @@ const DEFAULT_SCHEMA = "dbo"
|
|||
|
||||
import { ConfidentialClientApplication } from "@azure/msal-node"
|
||||
|
||||
import { utils } from "@budibase/shared-core"
|
||||
|
||||
enum MSSQLConfigAuthType {
|
||||
ACTIVE_DIRECTORY = "Active Directory",
|
||||
AZURE_ACTIVE_DIRECTORY = "Azure Active Directory",
|
||||
NTLM = "NTLM",
|
||||
}
|
||||
|
||||
interface MSSQLConfig {
|
||||
interface BasicMSSQLConfig {
|
||||
user: string
|
||||
password: string
|
||||
server: string
|
||||
|
@ -40,13 +43,30 @@ interface MSSQLConfig {
|
|||
schema: string
|
||||
encrypt?: boolean
|
||||
authType?: MSSQLConfigAuthType
|
||||
adConfig?: {
|
||||
}
|
||||
|
||||
interface AzureADMSSQLConfig extends BasicMSSQLConfig {
|
||||
authType: MSSQLConfigAuthType.AZURE_ACTIVE_DIRECTORY
|
||||
adConfig: {
|
||||
clientId: string
|
||||
clientSecret: string
|
||||
tenantId: string
|
||||
}
|
||||
}
|
||||
|
||||
interface NTLMMSSQLConfig extends BasicMSSQLConfig {
|
||||
authType: MSSQLConfigAuthType.NTLM
|
||||
ntlmConfig: {
|
||||
domain?: string
|
||||
trustServerCertificate?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
type MSSQLConfig =
|
||||
| (BasicMSSQLConfig & { authType?: undefined })
|
||||
| AzureADMSSQLConfig
|
||||
| NTLMMSSQLConfig
|
||||
|
||||
const SCHEMA: Integration = {
|
||||
docs: "https://github.com/tediousjs/node-mssql",
|
||||
plus: true,
|
||||
|
@ -93,13 +113,18 @@ const SCHEMA: Integration = {
|
|||
authType: {
|
||||
type: DatasourceFieldType.SELECT,
|
||||
display: "Advanced auth",
|
||||
config: { options: [MSSQLConfigAuthType.ACTIVE_DIRECTORY] },
|
||||
config: {
|
||||
options: [
|
||||
MSSQLConfigAuthType.AZURE_ACTIVE_DIRECTORY,
|
||||
MSSQLConfigAuthType.NTLM,
|
||||
],
|
||||
},
|
||||
},
|
||||
adConfig: {
|
||||
type: DatasourceFieldType.FIELD_GROUP,
|
||||
default: true,
|
||||
display: "Configure Active Directory",
|
||||
hidden: "'{{authType}}' !== 'Active Directory'",
|
||||
hidden: `'{{authType}}' !== '${MSSQLConfigAuthType.AZURE_ACTIVE_DIRECTORY}'`,
|
||||
config: {
|
||||
openByDefault: true,
|
||||
nestedFields: true,
|
||||
|
@ -122,6 +147,28 @@ const SCHEMA: Integration = {
|
|||
},
|
||||
},
|
||||
},
|
||||
ntlmConfig: {
|
||||
type: DatasourceFieldType.FIELD_GROUP,
|
||||
default: true,
|
||||
display: "Configure NTLM",
|
||||
hidden: `'{{authType}}' !== '${MSSQLConfigAuthType.NTLM}'`,
|
||||
config: {
|
||||
openByDefault: true,
|
||||
nestedFields: true,
|
||||
},
|
||||
fields: {
|
||||
domain: {
|
||||
type: DatasourceFieldType.STRING,
|
||||
required: false,
|
||||
display: "Domain",
|
||||
},
|
||||
trustServerCertificate: {
|
||||
type: DatasourceFieldType.BOOLEAN,
|
||||
required: false,
|
||||
display: "Trust server certificate",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
|
@ -199,26 +246,43 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
|
|||
}
|
||||
delete clientCfg.encrypt
|
||||
|
||||
if (this.config.authType === MSSQLConfigAuthType.ACTIVE_DIRECTORY) {
|
||||
const { clientId, tenantId, clientSecret } = this.config.adConfig!
|
||||
const clientApp = new ConfidentialClientApplication({
|
||||
auth: {
|
||||
clientId,
|
||||
authority: `https://login.microsoftonline.com/${tenantId}`,
|
||||
clientSecret,
|
||||
},
|
||||
})
|
||||
switch (this.config.authType) {
|
||||
case MSSQLConfigAuthType.AZURE_ACTIVE_DIRECTORY:
|
||||
const { clientId, tenantId, clientSecret } = this.config.adConfig
|
||||
const clientApp = new ConfidentialClientApplication({
|
||||
auth: {
|
||||
clientId,
|
||||
authority: `https://login.microsoftonline.com/${tenantId}`,
|
||||
clientSecret,
|
||||
},
|
||||
})
|
||||
|
||||
const response = await clientApp.acquireTokenByClientCredential({
|
||||
scopes: ["https://database.windows.net/.default"],
|
||||
})
|
||||
const response = await clientApp.acquireTokenByClientCredential({
|
||||
scopes: ["https://database.windows.net/.default"],
|
||||
})
|
||||
|
||||
clientCfg.authentication = {
|
||||
type: "azure-active-directory-access-token",
|
||||
options: {
|
||||
token: response!.accessToken,
|
||||
},
|
||||
}
|
||||
clientCfg.authentication = {
|
||||
type: "azure-active-directory-access-token",
|
||||
options: {
|
||||
token: response!.accessToken,
|
||||
},
|
||||
}
|
||||
break
|
||||
case MSSQLConfigAuthType.NTLM:
|
||||
const { domain, trustServerCertificate } = this.config.ntlmConfig
|
||||
clientCfg.authentication = {
|
||||
type: "ntlm",
|
||||
options: {
|
||||
domain,
|
||||
},
|
||||
}
|
||||
clientCfg.options ??= {}
|
||||
clientCfg.options.trustServerCertificate = trustServerCertificate
|
||||
break
|
||||
case undefined:
|
||||
break
|
||||
default:
|
||||
utils.unreachable(this.config)
|
||||
}
|
||||
|
||||
const pool = new sqlServer.ConnectionPool(clientCfg)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { UserCtx } from "@budibase/types"
|
||||
import { installation, logging } from "@budibase/backend-core"
|
||||
|
||||
export async function getLogs(ctx: UserCtx) {
|
||||
const logReadStream = logging.system.getLogReadStream()
|
||||
|
||||
const { installId } = await installation.getInstall()
|
||||
|
||||
const fileName = `${installId}-${Date.now()}.log`
|
||||
|
||||
ctx.set("content-disposition", `attachment; filename=${fileName}`)
|
||||
ctx.body = logReadStream
|
||||
}
|
|
@ -16,6 +16,9 @@ import licenseRoutes from "./global/license"
|
|||
import migrationRoutes from "./system/migrations"
|
||||
import accountRoutes from "./system/accounts"
|
||||
import restoreRoutes from "./system/restore"
|
||||
import systemLogRoutes from "./system/logs"
|
||||
|
||||
import env from "../../environment"
|
||||
|
||||
export const routes: Router[] = [
|
||||
configRoutes,
|
||||
|
@ -38,3 +41,7 @@ export const routes: Router[] = [
|
|||
eventRoutes,
|
||||
pro.scim,
|
||||
]
|
||||
|
||||
if (env.SELF_HOSTED) {
|
||||
routes.push(systemLogRoutes)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import Router from "@koa/router"
|
||||
import { middleware } from "@budibase/backend-core"
|
||||
import * as controller from "../../controllers/system/logs"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get("/api/system/logs", middleware.adminOnly, controller.getLogs)
|
||||
|
||||
export default router
|
|
@ -1,4 +1,5 @@
|
|||
import { logging } from "@budibase/backend-core"
|
||||
logging.LOG_CONTEXT = false
|
||||
|
||||
jest.retryTimes(2)
|
||||
jest.setTimeout(60000)
|
||||
|
|
375
yarn.lock
375
yarn.lock
|
@ -4487,21 +4487,21 @@
|
|||
path-to-regexp "1.x"
|
||||
urijs "^1.19.2"
|
||||
|
||||
"@lerna/child-process@7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.0.2.tgz#0ea270dcc34cbece6b5319f1d4a24733060883bd"
|
||||
integrity sha512-15lMrNBL/pvREMJPSfIPieaBtyyapDco/TNjALLEL53JGzO9g8rj5PipfE9h5ILx8aq/GaP17XCh209aVCun/w==
|
||||
"@lerna/child-process@7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.1.1.tgz#60eddd6dc4b6ba0fd51851c78b6dbdc4e1614220"
|
||||
integrity sha512-mR8PaTkckYPLmEBG2VsVsJq2UuzEvjXevOB1rKLKUZ/dPCGcottVhbiEzTxickc+s7Y/1dTTLn/1BKj3B1a5BA==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
execa "^5.0.0"
|
||||
strong-log-transformer "^2.1.0"
|
||||
|
||||
"@lerna/create@7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.0.2.tgz#a9335b889b54a456b3efc953f109aaf1d134b40a"
|
||||
integrity sha512-1arGpEpWbWmci1MyaGKvP2SqCAPFWpLqZp0swckianX1kx1mso9B16BWFvcHhU57zCD0Co/z+jX+02UEzZGP7Q==
|
||||
"@lerna/create@7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.1.1.tgz#2af94afb01971c1b594c06347b6998607aefe5c4"
|
||||
integrity sha512-1PY2OgwGxp7b91JzLKEhONVl69mCt1IyYEc6pzKy3Sv+UOdeK2QFq1SX/85hNOR3iitiyZ75bNWUTcBly1ZlZg==
|
||||
dependencies:
|
||||
"@lerna/child-process" "7.0.2"
|
||||
"@lerna/child-process" "7.1.1"
|
||||
dedent "0.7.0"
|
||||
fs-extra "^11.1.1"
|
||||
init-package-json "5.0.0"
|
||||
|
@ -4694,13 +4694,6 @@
|
|||
read-package-json-fast "^3.0.0"
|
||||
which "^3.0.0"
|
||||
|
||||
"@nrwl/devkit@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.2.1.tgz#2da4dbe5826b0721cae547635554b6e411a069f6"
|
||||
integrity sha512-yeNEccQzDuL+/thbS2XTq8MtD0KDrI92gXIPSrS/Q6QnDNJGz6T2kRe/mJWrcfrDFm/L61MsAlGXobElhceNMw==
|
||||
dependencies:
|
||||
"@nx/devkit" "16.2.1"
|
||||
|
||||
"@nrwl/devkit@16.2.2":
|
||||
version "16.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.2.2.tgz#fd7d0a19b4be3ba35cc0d3dd9e4154f9812f432f"
|
||||
|
@ -4708,19 +4701,26 @@
|
|||
dependencies:
|
||||
"@nx/devkit" "16.2.2"
|
||||
|
||||
"@nrwl/js@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/js/-/js-16.2.1.tgz#6eacfa1f0658ca1e288da86b6c38be4846f2779a"
|
||||
integrity sha512-+XCgHocQzqn/wQauzTuWv/ioyuuiC3FfE3H+wg2FgfYuJLYuGyGx4qDhuiGvaaLqOK1dJQxLBsZW9Gjk77qe1g==
|
||||
"@nrwl/devkit@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.4.3.tgz#036be0d478ef7156e55c1cfb4d13da080983503d"
|
||||
integrity sha512-sDGv3RX5DHBMFFiHdd91e4YFXb87X5jsKkEg5Y2jmFtz/OilBKA9yoRhZ8t+iLBOmbgUngC5ZYPHc+Ykd2U3nA==
|
||||
dependencies:
|
||||
"@nx/js" "16.2.1"
|
||||
"@nx/devkit" "16.4.3"
|
||||
|
||||
"@nrwl/tao@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.2.1.tgz#08bb3dae81e958777268747c385c32a608452c3e"
|
||||
integrity sha512-mhLkMxGFbnR4hu9UbjMvzdePDXmUpV33mImt1myewP/cY9YZdzv5ntqT+9U+zzVg7Q2ZGosiGQE+IYRm6yeWog==
|
||||
"@nrwl/js@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/js/-/js-16.4.3.tgz#2f0d7c824a4abe6d55912c0e4abcc18a390aab25"
|
||||
integrity sha512-hA26y1aZfnjIJVlVtEMdK8BFFtKTZVZ6VWOgtUhCMmbtxpE4tpTssRItzq5dkQi9Et/dry8ClWqRWPqlW7LqxQ==
|
||||
dependencies:
|
||||
nx "16.2.1"
|
||||
"@nx/js" "16.4.3"
|
||||
|
||||
"@nrwl/nx-cloud@16.0.5":
|
||||
version "16.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/nx-cloud/-/nx-cloud-16.0.5.tgz#c963480a71c4afa964fbbe9e4d6bbf222764e9cd"
|
||||
integrity sha512-1p82ym8WE9ziejwgPslstn19iV/VkHfHfKr/5YOnfCHQS+NxUf92ogcYhHXtqWLblVZ9Zs4W4pkSXK4e04wCmQ==
|
||||
dependencies:
|
||||
nx-cloud "16.0.5"
|
||||
|
||||
"@nrwl/tao@16.3.2":
|
||||
version "16.3.2"
|
||||
|
@ -4729,24 +4729,19 @@
|
|||
dependencies:
|
||||
nx "16.3.2"
|
||||
|
||||
"@nrwl/workspace@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/workspace/-/workspace-16.2.1.tgz#22e83a4b545e563fd157c407b387113a6bc639bc"
|
||||
integrity sha512-k9CUsGNBC5gTnTMcPDHFkxIPzzhhm47DhmNV3xueuwSAyZbvnekCtmkFRdwe4jtOFjB6+MpTsol9p37vKfXVLA==
|
||||
"@nrwl/tao@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.4.3.tgz#8a72e8c1c903d8d7e1d9a298c28f03a000a925d8"
|
||||
integrity sha512-h+/UdXtdVuH9K2+Rx1HK5AHXGtgXNIqdLIH1KRL+74fiQ+JNO2Xuz9wqiD+rZ5tmtL/4hZpePCMkTz2FusKvbA==
|
||||
dependencies:
|
||||
"@nx/workspace" "16.2.1"
|
||||
nx "16.4.3"
|
||||
|
||||
"@nx/devkit@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.2.1.tgz#f937604149272b46927cad5645ecc444973f97f2"
|
||||
integrity sha512-OrnFkU+lrSP/MdQW6C07aMlLyMp98oZMyfZ6h721T66zvuDfchhG2RXLX/Rb2t1lgZ+oMBKwvxxUKMRpHKPekA==
|
||||
"@nrwl/workspace@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nrwl/workspace/-/workspace-16.4.3.tgz#5d8bd06d2d1650318237dd9eb786e6695ebe7802"
|
||||
integrity sha512-8FKqGgB8IFeMebCZeaD2Ta0/wSqWMFEX0FWCj1piuJNosgfImdQZUgYfLorsAjyR69GBP+59OkmsxDClZcCPMw==
|
||||
dependencies:
|
||||
"@nrwl/devkit" "16.2.1"
|
||||
ejs "^3.1.7"
|
||||
ignore "^5.0.4"
|
||||
semver "7.3.4"
|
||||
tmp "~0.2.1"
|
||||
tslib "^2.3.0"
|
||||
"@nx/workspace" "16.4.3"
|
||||
|
||||
"@nx/devkit@16.2.2", "@nx/devkit@>=16.1.3 < 17":
|
||||
version "16.2.2"
|
||||
|
@ -4760,10 +4755,22 @@
|
|||
tmp "~0.2.1"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@nx/js@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/js/-/js-16.2.1.tgz#41c8c2d610131fa064bbb2b6bb25bd67ed06be79"
|
||||
integrity sha512-WpK8yqVCrkCRTbNxSuRuQFpBXyX+doynixVv8yuB8HKPfE/wx6252eUMT43DWQJ+stmd5IhoH4THGyqpf+aaHg==
|
||||
"@nx/devkit@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.4.3.tgz#a5e691f1fd49b5b0d8bb0a4347b3501b11e33056"
|
||||
integrity sha512-5LHtia3Ioy4uwWDIpnCbslFwxNdRJ2cWWmzq4oDINZnUMzNsjatVowKkOUBeG4Xh++6Dvui/VSdKZ6J0MUoQzw==
|
||||
dependencies:
|
||||
"@nrwl/devkit" "16.4.3"
|
||||
ejs "^3.1.7"
|
||||
ignore "^5.0.4"
|
||||
semver "7.5.3"
|
||||
tmp "~0.2.1"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@nx/js@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/js/-/js-16.4.3.tgz#3d5aa519cd5f769c69a14b1c6418ab2bb43de519"
|
||||
integrity sha512-0Uia5j+BOybXN0Fpfl1729m+bot+6g0tKKR3WLh715QCuXoKPtprTYgp/GEi+dUCUNrmHzCAduztMvsH0RY9Kw==
|
||||
dependencies:
|
||||
"@babel/core" "^7.15.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.14.5"
|
||||
|
@ -4772,124 +4779,131 @@
|
|||
"@babel/preset-env" "^7.15.0"
|
||||
"@babel/preset-typescript" "^7.15.0"
|
||||
"@babel/runtime" "^7.14.8"
|
||||
"@nrwl/js" "16.2.1"
|
||||
"@nx/devkit" "16.2.1"
|
||||
"@nx/workspace" "16.2.1"
|
||||
"@nrwl/js" "16.4.3"
|
||||
"@nx/devkit" "16.4.3"
|
||||
"@nx/workspace" "16.4.3"
|
||||
"@phenomnomnominal/tsquery" "~5.0.1"
|
||||
babel-plugin-const-enum "^1.0.1"
|
||||
babel-plugin-macros "^2.8.0"
|
||||
babel-plugin-transform-typescript-metadata "^0.3.1"
|
||||
chalk "^4.1.0"
|
||||
detect-port "^1.5.1"
|
||||
fast-glob "3.2.7"
|
||||
fs-extra "^11.1.0"
|
||||
ignore "^5.0.4"
|
||||
js-tokens "^4.0.0"
|
||||
minimatch "3.0.5"
|
||||
semver "7.5.3"
|
||||
source-map-support "0.5.19"
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@nx/nx-darwin-arm64@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.2.1.tgz#8a144a6fd38a2a7179c583c1fc344b2a0de27996"
|
||||
integrity sha512-xK/dL5T2R8zrcD8/13PeaYH/LBcYeaELIZkXGdGbtQ8WeFHjPJLBfuWo/7Se7KSWIXLIJEeYrVZwyxuei1dOTA==
|
||||
|
||||
"@nx/nx-darwin-arm64@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.3.2.tgz#83b6e78b27d2d7da8f7626560f52070c8735d28a"
|
||||
integrity sha512-YfYVNfsJBzBcBnJUU4AcA6A4QMkgnVlETfp4KGL36Otq542mRY1ISGHdox63ocI5AKh5gay5AaGcR4wR9PU9Vg==
|
||||
|
||||
"@nx/nx-darwin-x64@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.2.1.tgz#f878b9257bb5ed939c5095b72f1f37fe01bab950"
|
||||
integrity sha512-J1ZBqy8FtIhvZopcc96JWZY2InZClQ+XHWHnAmX8S1f79hcLUiatpu90FZhvfXmfOfLlpkKsa8aje/kjpnnWhA==
|
||||
"@nx/nx-darwin-arm64@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.4.3.tgz#08e63921c4e4dfc9eb9da612140c62ca8c190059"
|
||||
integrity sha512-iVr3KTHXqGWx34mLxKjdDT1m6px9NME7zqSoKZW9DQuxDt3G7NN4PkK6+n2YqVNNSOmYml/Oo5iVtQ2TUCJDFA==
|
||||
|
||||
"@nx/nx-darwin-x64@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.3.2.tgz#0ae2a64356542c5fb73ca8038ce10ec4512e7fcb"
|
||||
integrity sha512-bJtpozz0zSRVRrcQ76GrlT3TWEGTymLYWrVG51bH5KZ46t6/a4EQBI3uL3vubMmOZ0jR4ywybOcPBBhxmBJ68w==
|
||||
|
||||
"@nx/nx-darwin-x64@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.4.3.tgz#e1e591f38bd103cf110487bd8c35daf17f8636c7"
|
||||
integrity sha512-Km1N7Rek4VZW9rFMpV/gwmW0YHCoeV/5/tbYOYjSPJY6n2GB/vVoqE1DTf69muIk32436aK+qYRpd98bXC8GKg==
|
||||
|
||||
"@nx/nx-freebsd-x64@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.3.2.tgz#202adf4d6070f47ed46450f006ecd50851147c74"
|
||||
integrity sha512-ZvufI0bWqT67nLbBo6ejrIGxypdoedRQTP/tudWbs/4isvxLe1uVku1BfKCTQUsJG367SqNOU1H5kzI/MRr3ow==
|
||||
|
||||
"@nx/nx-linux-arm-gnueabihf@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.2.1.tgz#a0f7d2c1f90d78bf30c7beae7c5481a71fb2652a"
|
||||
integrity sha512-rnujPmWlnkEvzkWARuW85cizVx6uGwQ/gA84tK3cHZQf9ly172WbDtsMtYRS9/CjvysMqDV0zBd7o/YhwpXNZg==
|
||||
"@nx/nx-freebsd-x64@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.4.3.tgz#dc7fd8dbb87d7eb613b3f7302b0e3cba233277fd"
|
||||
integrity sha512-i6gc7oiDekYY2DS20COoeIrUqSQt0A3V+xUbrMGTInbHMux8QlfY5LGPRHGzqRlvnmUbrpgN0TdwBB9KOgaWmw==
|
||||
|
||||
"@nx/nx-linux-arm-gnueabihf@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.3.2.tgz#62314a82566e3647866b9dd4167a2d0e1397f001"
|
||||
integrity sha512-IQL4kxdiZLvifar7+SIum3glRuVsxtE0dL8RvteSDXrxDQnaTUrjILC+VGhalRmk7ngBbGKNrhWOeeL7390CzQ==
|
||||
|
||||
"@nx/nx-linux-arm64-gnu@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.2.1.tgz#30dead7a96437c7cbb041a45e1c0e7292fb2151a"
|
||||
integrity sha512-ZcuQN8eaxEI+93ut6UrDrZMPsk61LGlS6yaWPgrv3blKMfcU2+DYBDQ3ois7o5t0bnVad5QYSNhIvnMF2iU+hQ==
|
||||
"@nx/nx-linux-arm-gnueabihf@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.4.3.tgz#5a2aa53297eff9b3d0cef5b0280d67400e61e80d"
|
||||
integrity sha512-hozcDrzbv3X0oWYYbJfSybVmKviko78wjjxvdwYS2H9eqNN6sNBZ5+LL+duUazCeGGHj1fRipvb9E3rJxiKWEw==
|
||||
|
||||
"@nx/nx-linux-arm64-gnu@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.3.2.tgz#02826400aa55b8f44bac83332dd29647d0e95001"
|
||||
integrity sha512-f6AWgPVu3mfUEoOBa0rY2/7QY0Or9eR0KtLFpcPh7RUpxPw2EXzIbjD/0RGipdpspSrgiMKbZpsUjo6mXBFsQA==
|
||||
|
||||
"@nx/nx-linux-arm64-musl@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.2.1.tgz#31219ecf98f9fe78b5fc06c9e0102d99e335bc5b"
|
||||
integrity sha512-mMOvkYyBLU4j+mSHobtrj/pIDYXFGIX3Q9FMWxZ5Xz15m0DsbypZ/8v6NWpJaBY4VX6rJhCc+D/pZH+QBT8+/g==
|
||||
"@nx/nx-linux-arm64-gnu@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.4.3.tgz#2129426f8258e193f9997adafcda570e23d94435"
|
||||
integrity sha512-LrlSKCZtFl8TiIFuLjkSNN/yzQ8phZ6+0jgsuumrIE8t02y+WLcZ4dSGlCo4nwVX/MDCtTbc9LPI+rIoBvO/pQ==
|
||||
|
||||
"@nx/nx-linux-arm64-musl@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.3.2.tgz#a0a81520e0904aa026a7ab0a8a3bf3facec9f14c"
|
||||
integrity sha512-AvrWcYz7021E3b5P9/0i26p60XMZfw86Epks51L6AhlflarlOH4AcEChc7APMtb1ELAIbDWx2S6oIDRbQ7rtVA==
|
||||
|
||||
"@nx/nx-linux-x64-gnu@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.2.1.tgz#fb89cbbdf852e27093e0296ff7414ccccdf3591a"
|
||||
integrity sha512-Kyn4dxFTj2PCRv+39tKU8BzDRE6/ru5v435uvodx03GS650F7+OMr4DN57jG4MQWhf//OUX8zPkvbKhsmxjndA==
|
||||
"@nx/nx-linux-arm64-musl@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.4.3.tgz#0285f71f94b5a2eb40f15033457f937e0362770d"
|
||||
integrity sha512-3ahS0k330T339FdVBQhr3EGrghAaezqdVpbOwG2pyiZRwvLVgnDkPF/d4EkGd3ZAsOLazcPkPH/fKxPPf8HP2g==
|
||||
|
||||
"@nx/nx-linux-x64-gnu@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.3.2.tgz#e79b5c142ec8d9bfb458ea5803bc4b62abbcf296"
|
||||
integrity sha512-K2pWGAcbCNm6b7UZI9cc8z4Rb540QcuepBXD7akjPjWerzXriT6VCn4i9mVKsCg2mwSfknTJJVJ1PZwJSmTl/Q==
|
||||
|
||||
"@nx/nx-linux-x64-musl@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.2.1.tgz#82b1b5ba04ef6e4d49527841239bf9e0fb1456e3"
|
||||
integrity sha512-q8iFxLosSLiWkRWsbrioXV/qMG8TgsbqcM0VGz2FFLNMJ9DXvav/E/+8YbgEeHOjvA1MDeRaspIpDF7OMgJYGw==
|
||||
"@nx/nx-linux-x64-gnu@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.4.3.tgz#defea39bbd5f494c28369bd403f909d5ec905ac0"
|
||||
integrity sha512-Nbo+FLBYZRhJUB367Eg9f0mH7Q+X67H+QAF+wU2oK3StSGQNQbLnr7Q0yfmX912WdYDe7gWhEpqWTLZ7rv65mg==
|
||||
|
||||
"@nx/nx-linux-x64-musl@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.3.2.tgz#900aee8f171638b9fb44378e2ac0548cb4aa99a7"
|
||||
integrity sha512-sY1QDuQlqyYiRPJZanrtV07tU0DOXiCrWb0pDsGiO0qHuUSmW5Vw17GWEY4z3rt0/5U8fJ+/9WQrneviOmsOKg==
|
||||
|
||||
"@nx/nx-win32-arm64-msvc@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.2.1.tgz#8a19a0c2db565f6d07a2d0b4a8b8fc6c8c86fadd"
|
||||
integrity sha512-PpGiYzrMivDY1i10Zwf5Hmnv6oAQ8ACf6ehDgyQ3tByMMXHgyUZJLykfPaoWjoLh0s8wOvMV74WZO+K1LcIxTA==
|
||||
"@nx/nx-linux-x64-musl@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.4.3.tgz#c78db85f3234d2b899c7acaa7b5e2ef2c8591eb6"
|
||||
integrity sha512-RG31ewe3GRmwSMBgWF0yeJ1zu8s42xywpwK8swgGHpUp+Z6JN8dkUqi7UfHGbjeaOIDg4w45/7OJyrE7dlqHCg==
|
||||
|
||||
"@nx/nx-win32-arm64-msvc@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.3.2.tgz#88db772b3535648e147b1a0206b1a1fe875fa9a5"
|
||||
integrity sha512-wBfohT2hjrLKn9WFHvG0MFVk7uYhgYNiptnTLdTouziHgFyZ08vyl7XYBq55BwHPMQ5iswVoEfjn/5ZBfCPscg==
|
||||
|
||||
"@nx/nx-win32-x64-msvc@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.2.1.tgz#848b4c5b118f6a6f92f59c1643297e938c439242"
|
||||
integrity sha512-m5oHCaSKdyydM1n1W9V0m2oxBL8PiF54dZB0+PlKB2fhf1zxiyq8i1hL2hXbKA90IOYcUt5/b7761/BzN5njAw==
|
||||
"@nx/nx-win32-arm64-msvc@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.4.3.tgz#d131273e8267eb98a7640f79a94049b5f12d572e"
|
||||
integrity sha512-5HXY8S0vGUculndAhWqBrqkrQxY6M3v3Ac/3rr8O238JkdkhRiHilnGbwS2MIQpU7dou3wROO6wKT7+TyFv+cA==
|
||||
|
||||
"@nx/nx-win32-x64-msvc@16.3.2":
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.3.2.tgz#2195faaf1fc465c7a89bfdd62323fdd2a5d91f15"
|
||||
integrity sha512-QC0sWrfQm0/WdvvM//7UAgm+otbak6bznZ0zawTeqmLBh1hLjNeweyzSVKQEtZtlzDMKpzCVuuwkJq+VKBLvmw==
|
||||
|
||||
"@nx/workspace@16.2.1":
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@nx/workspace/-/workspace-16.2.1.tgz#52cc54bf9970fe6769459b1315eb7f6db8ec387f"
|
||||
integrity sha512-gGJNKsH2KFtxlBBL0AqPu0vo322wGfCPDK19OxgwTQMWDruMZ9jjAe3XU4a+FbCGmK1CmZUlbFo4HueD9hVkig==
|
||||
"@nx/nx-win32-x64-msvc@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.4.3.tgz#cc8d87dbada3965b3156440277951b742b6c0de3"
|
||||
integrity sha512-9vdA5t5xuWCQ9JFJZFjzYGz9w5wtZ7zfKcx2HdBvg2nDWUzK5Z3khwsakTSsc7Ff7Hnd0i0l5T3Ls6Hk42Haww==
|
||||
|
||||
"@nx/workspace@16.4.3":
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@nx/workspace/-/workspace-16.4.3.tgz#0466ba261511bdbd41afedfe51ee002e6dee8f86"
|
||||
integrity sha512-vgZo4ywYhRheFA2xUzf6Jt00tJ4B2iYFRqFCw4bNDOrn01wnpDUcMof4M0VE3P0OHMKktygDxuARzO20tGMRQQ==
|
||||
dependencies:
|
||||
"@nrwl/workspace" "16.2.1"
|
||||
"@nx/devkit" "16.2.1"
|
||||
"@nrwl/workspace" "16.4.3"
|
||||
"@nx/devkit" "16.4.3"
|
||||
"@parcel/watcher" "2.0.4"
|
||||
chalk "^4.1.0"
|
||||
chokidar "^3.5.1"
|
||||
|
@ -4901,7 +4915,7 @@
|
|||
ignore "^5.0.4"
|
||||
minimatch "3.0.5"
|
||||
npm-run-path "^4.0.1"
|
||||
nx "16.2.1"
|
||||
nx "16.4.3"
|
||||
open "^8.4.0"
|
||||
rxjs "^7.8.0"
|
||||
tmp "~0.2.1"
|
||||
|
@ -7403,6 +7417,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
|
||||
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
|
||||
|
||||
"@yarnpkg/parsers@3.0.0-rc.46":
|
||||
version "3.0.0-rc.46"
|
||||
resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz#03f8363111efc0ea670e53b0282cd3ef62de4e01"
|
||||
integrity sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==
|
||||
dependencies:
|
||||
js-yaml "^3.10.0"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@yarnpkg/parsers@^3.0.0-rc.18":
|
||||
version "3.0.0-rc.42"
|
||||
resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.42.tgz#3814e90a81bb1f9c06cc83c6a009139c55efe94d"
|
||||
|
@ -7563,6 +7585,11 @@ add-stream@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
|
||||
integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==
|
||||
|
||||
address@^1.0.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e"
|
||||
integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
|
||||
|
||||
after-all-results@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/after-all-results/-/after-all-results-2.0.0.tgz#6ac2fc202b500f88da8f4f5530cfa100f4c6a2d0"
|
||||
|
@ -8166,6 +8193,15 @@ axios@0.24.0:
|
|||
dependencies:
|
||||
follow-redirects "^1.14.4"
|
||||
|
||||
axios@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
|
||||
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axios@^0.21.1, axios@^0.21.4:
|
||||
version "0.21.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
|
||||
|
@ -10782,6 +10818,14 @@ detect-node@^2.0.4:
|
|||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
|
||||
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
||||
|
||||
detect-port@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b"
|
||||
integrity sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==
|
||||
dependencies:
|
||||
address "^1.0.1"
|
||||
debug "4"
|
||||
|
||||
detective-amd@^3.1.0:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-3.1.2.tgz#bf55eb5291c218b76d6224a3d07932ef13a9a357"
|
||||
|
@ -17501,13 +17545,13 @@ leaflet@^1.7.1:
|
|||
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.3.tgz#52ec436954964e2d3d39e0d433da4b2500d74414"
|
||||
integrity sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==
|
||||
|
||||
lerna@7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.0.2.tgz#45e844bfca72d12cc285c9a00f6f2cfb341bed05"
|
||||
integrity sha512-omFpf1pTiaObC2YOC7K+euaDwhQA9CyKN1kXxmlSwaSkh8b8QTs4SC8jp3oNeXfcHpVS1ttuuz98AvQvJD46wA==
|
||||
lerna@7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.1.1.tgz#6703062e6c4ddefdaf41e8890e9200690924fd71"
|
||||
integrity sha512-rjivAl3bYu2+lWOi90vy0tYFgwBYPMiNkR/DuEWZC08wle5dsbOZ/SlXeLk9+kzbF89Bt5P6p+qF78A2tJsWPA==
|
||||
dependencies:
|
||||
"@lerna/child-process" "7.0.2"
|
||||
"@lerna/create" "7.0.2"
|
||||
"@lerna/child-process" "7.1.1"
|
||||
"@lerna/create" "7.1.1"
|
||||
"@npmcli/run-script" "6.0.2"
|
||||
"@nx/devkit" ">=16.1.3 < 17"
|
||||
"@octokit/plugin-enterprise-rest" "6.0.1"
|
||||
|
@ -19348,6 +19392,11 @@ node-int64@^0.4.0:
|
|||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
||||
|
||||
node-machine-id@^1.1.12:
|
||||
version "1.1.12"
|
||||
resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267"
|
||||
integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==
|
||||
|
||||
node-mocks-http@^1.11.0:
|
||||
version "1.12.1"
|
||||
resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.12.1.tgz#838e176019daf177caff6bb8534e3a32646e7531"
|
||||
|
@ -19739,55 +19788,21 @@ nwsapi@^2.2.2:
|
|||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.4.tgz#fd59d5e904e8e1f03c25a7d5a15cfa16c714a1e5"
|
||||
integrity sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==
|
||||
|
||||
nx@16.2.1:
|
||||
version "16.2.1"
|
||||
resolved "https://registry.yarnpkg.com/nx/-/nx-16.2.1.tgz#8571a4663c79dc9d60c98599b19146b58c59b473"
|
||||
integrity sha512-O+yGcYIQtYKYagbIuOQFk1P8ki5PHn0BZjdZpsa4K8UZ4pCaRWzlwWwwUL91FUJe6tdhic5710DwAAakbGKP7Q==
|
||||
nx-cloud@16.0.5:
|
||||
version "16.0.5"
|
||||
resolved "https://registry.yarnpkg.com/nx-cloud/-/nx-cloud-16.0.5.tgz#fa0b0185d254405ec47fcbcdbbd8b12ff1add096"
|
||||
integrity sha512-13P7r0aKikjBtmdZrNorwXzVPeVIV4MLEwqGY+DEG6doLBtI5KqEQk/d5B5l2dCF2BEi/LXEmLYCmf9gwbOJ+Q==
|
||||
dependencies:
|
||||
"@nrwl/tao" "16.2.1"
|
||||
"@parcel/watcher" "2.0.4"
|
||||
"@yarnpkg/lockfile" "^1.1.0"
|
||||
"@yarnpkg/parsers" "^3.0.0-rc.18"
|
||||
"@zkochan/js-yaml" "0.0.6"
|
||||
axios "^1.0.0"
|
||||
"@nrwl/nx-cloud" "16.0.5"
|
||||
axios "1.1.3"
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "3.1.0"
|
||||
cli-spinners "2.6.1"
|
||||
cliui "^7.0.2"
|
||||
dotenv "~10.0.0"
|
||||
enquirer "~2.3.6"
|
||||
fast-glob "3.2.7"
|
||||
figures "3.2.0"
|
||||
flat "^5.0.2"
|
||||
fs-extra "^11.1.0"
|
||||
glob "7.1.4"
|
||||
ignore "^5.0.4"
|
||||
js-yaml "4.1.0"
|
||||
jsonc-parser "3.2.0"
|
||||
lines-and-columns "~2.0.3"
|
||||
minimatch "3.0.5"
|
||||
npm-run-path "^4.0.1"
|
||||
open "^8.4.0"
|
||||
semver "7.3.4"
|
||||
string-width "^4.2.3"
|
||||
strong-log-transformer "^2.1.0"
|
||||
tar-stream "~2.2.0"
|
||||
tmp "~0.2.1"
|
||||
tsconfig-paths "^4.1.2"
|
||||
tslib "^2.3.0"
|
||||
v8-compile-cache "2.3.0"
|
||||
yargs "^17.6.2"
|
||||
yargs-parser "21.1.1"
|
||||
optionalDependencies:
|
||||
"@nx/nx-darwin-arm64" "16.2.1"
|
||||
"@nx/nx-darwin-x64" "16.2.1"
|
||||
"@nx/nx-linux-arm-gnueabihf" "16.2.1"
|
||||
"@nx/nx-linux-arm64-gnu" "16.2.1"
|
||||
"@nx/nx-linux-arm64-musl" "16.2.1"
|
||||
"@nx/nx-linux-x64-gnu" "16.2.1"
|
||||
"@nx/nx-linux-x64-musl" "16.2.1"
|
||||
"@nx/nx-win32-arm64-msvc" "16.2.1"
|
||||
"@nx/nx-win32-x64-msvc" "16.2.1"
|
||||
node-machine-id "^1.1.12"
|
||||
open "~8.4.0"
|
||||
strip-json-comments "^3.1.1"
|
||||
tar "6.1.11"
|
||||
yargs-parser ">=21.1.1"
|
||||
|
||||
nx@16.3.2, "nx@>=16.1.3 < 17":
|
||||
version "16.3.2"
|
||||
|
@ -19840,6 +19855,57 @@ nx@16.3.2, "nx@>=16.1.3 < 17":
|
|||
"@nx/nx-win32-arm64-msvc" "16.3.2"
|
||||
"@nx/nx-win32-x64-msvc" "16.3.2"
|
||||
|
||||
nx@16.4.3:
|
||||
version "16.4.3"
|
||||
resolved "https://registry.yarnpkg.com/nx/-/nx-16.4.3.tgz#0bd8e408eeb9f09f9fca334689bf3d13f361254f"
|
||||
integrity sha512-bq3wc7WI/j/mmz4MbrhDVE+DLJ6ywvmAoUjxNRcVAhPi+rT7bDaztVZceDbxxVFW55wfOIjcYwhS9fGQMSBBpQ==
|
||||
dependencies:
|
||||
"@nrwl/tao" "16.4.3"
|
||||
"@parcel/watcher" "2.0.4"
|
||||
"@yarnpkg/lockfile" "^1.1.0"
|
||||
"@yarnpkg/parsers" "3.0.0-rc.46"
|
||||
"@zkochan/js-yaml" "0.0.6"
|
||||
axios "^1.0.0"
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "3.1.0"
|
||||
cli-spinners "2.6.1"
|
||||
cliui "^7.0.2"
|
||||
dotenv "~10.0.0"
|
||||
enquirer "~2.3.6"
|
||||
fast-glob "3.2.7"
|
||||
figures "3.2.0"
|
||||
flat "^5.0.2"
|
||||
fs-extra "^11.1.0"
|
||||
glob "7.1.4"
|
||||
ignore "^5.0.4"
|
||||
js-yaml "4.1.0"
|
||||
jsonc-parser "3.2.0"
|
||||
lines-and-columns "~2.0.3"
|
||||
minimatch "3.0.5"
|
||||
npm-run-path "^4.0.1"
|
||||
open "^8.4.0"
|
||||
semver "7.5.3"
|
||||
string-width "^4.2.3"
|
||||
strong-log-transformer "^2.1.0"
|
||||
tar-stream "~2.2.0"
|
||||
tmp "~0.2.1"
|
||||
tsconfig-paths "^4.1.2"
|
||||
tslib "^2.3.0"
|
||||
v8-compile-cache "2.3.0"
|
||||
yargs "^17.6.2"
|
||||
yargs-parser "21.1.1"
|
||||
optionalDependencies:
|
||||
"@nx/nx-darwin-arm64" "16.4.3"
|
||||
"@nx/nx-darwin-x64" "16.4.3"
|
||||
"@nx/nx-freebsd-x64" "16.4.3"
|
||||
"@nx/nx-linux-arm-gnueabihf" "16.4.3"
|
||||
"@nx/nx-linux-arm64-gnu" "16.4.3"
|
||||
"@nx/nx-linux-arm64-musl" "16.4.3"
|
||||
"@nx/nx-linux-x64-gnu" "16.4.3"
|
||||
"@nx/nx-linux-x64-musl" "16.4.3"
|
||||
"@nx/nx-win32-arm64-msvc" "16.4.3"
|
||||
"@nx/nx-win32-x64-msvc" "16.4.3"
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
|
@ -20043,7 +20109,7 @@ open@^7.3.1:
|
|||
is-docker "^2.0.0"
|
||||
is-wsl "^2.1.1"
|
||||
|
||||
open@^8.0.0, open@^8.4.0:
|
||||
open@^8.0.0, open@^8.4.0, open@~8.4.0:
|
||||
version "8.4.2"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9"
|
||||
integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==
|
||||
|
@ -23131,6 +23197,11 @@ rollup@^3.18.0:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rotating-file-stream@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rotating-file-stream/-/rotating-file-stream-3.1.0.tgz#6cf50e1671de82a396de6d31d39a6f2445f45fba"
|
||||
integrity sha512-TkMF6cP1/QDcon9D71mjxHoflNuznNOrY5JJQfuxkKklZRmoow/lWBLNxXVjb6KcjAU8BDCV145buLgOx9Px1Q==
|
||||
|
||||
rrweb-cssom@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1"
|
||||
|
@ -23377,6 +23448,13 @@ semver@7.3.7, semver@^7.3.4:
|
|||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@7.5.3, semver@^7.5.3:
|
||||
version "7.5.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
|
||||
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@7.x, semver@^7.3.2, semver@^7.3.7, semver@^7.3.8:
|
||||
version "7.3.8"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
|
||||
|
@ -23403,13 +23481,6 @@ semver@^7.2.1, semver@^7.3.5:
|
|||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.5.3:
|
||||
version "7.5.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
|
||||
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@~2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-2.3.2.tgz#b9848f25d6cf36333073ec9ef8856d42f1233e52"
|
||||
|
@ -26952,7 +27023,7 @@ yargs-parser@20.2.4:
|
|||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
|
||||
integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
|
||||
|
||||
yargs-parser@21.1.1, yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1:
|
||||
yargs-parser@21.1.1, yargs-parser@>=21.1.1, yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1:
|
||||
version "21.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
|
||||
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
|
||||
|
|
Loading…
Reference in New Issue