From ce28197cba54f258652e53c6cfcf509fe08bc572 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Fri, 5 Apr 2024 14:55:29 -0700 Subject: [PATCH] Parse and persist UI metadata on editor page (#125) Signed-off-by: Tyler Ohlsen --- .github/workflows/build-and-test.yml | 4 - codecov.yml | 17 +++ package.json | 8 +- public/component_types/indexer/indexer.ts | 6 +- public/component_types/indexer/knn_indexer.ts | 2 +- public/component_types/interfaces.ts | 2 +- .../transformer/text_embedding_transformer.ts | 6 +- .../input_fields/select_field.tsx | 4 +- .../input_fields/text_field.tsx | 6 +- public/pages/workflow_detail/utils/index.ts | 6 - public/pages/workflow_detail/utils/utils.ts | 27 ---- .../workspace/resizable_workspace.tsx | 54 ++++--- public/utils/utils.ts | 42 ++++- server/routes/helpers.ts | 1 + yarn.lock | 143 ------------------ 15 files changed, 97 insertions(+), 231 deletions(-) create mode 100644 codecov.yml delete mode 100644 public/pages/workflow_detail/utils/index.ts delete mode 100644 public/pages/workflow_detail/utils/utils.ts diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dc4b8230..aba2c515 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -45,8 +45,6 @@ jobs: su `id -un 1000` -c "source $NVM_DIR/nvm.sh && nvm use && node -v && yarn -v && cd ./plugins/dashboards-flow-framework && whoami && yarn osd bootstrap && yarn build && yarn run test:jest --coverage" - - name: Uploads coverage - uses: codecov/codecov-action@v1 # TODO: once github actions supports windows and macos docker containers, we can # merge these in to the above step's matrix, including adding windows support @@ -98,6 +96,4 @@ jobs: run: | cd OpenSearch-Dashboards/plugins/dashboards-flow-framework yarn run test:jest --coverage - - name: Uploads coverage - uses: codecov/codecov-action@v1 diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..44df4e8e --- /dev/null +++ b/codecov.yml @@ -0,0 +1,17 @@ +# disable tracking status entirely until UT is added. +# tracking issue: https://github.com/opensearch-project/dashboards-flow-framework/issues/95 +coverage: + # displays different colors depending on below, between, or above the range + range: 50..90 + status: + project: + enabled: no + default: + target: auto + # allows 5% coverage reduction without failing + threshold: 5% + patch: no + changes: no + +# disable comments in PRs +comment: no \ No newline at end of file diff --git a/package.json b/package.json index 2b098fe8..eec6cfc9 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "osd": "../../scripts/use_node ../../scripts/osd", "opensearch": "../../scripts/use_node ../../scripts/opensearch", "lint:es": "../../scripts/use_node ../../scripts/eslint -c eslintrc.json", - "lint:es:precommit": "yarn lint:es common/* public/* server/*", "test:jest": "../../node_modules/.bin/jest --config ./test/jest.config.js", "build": "yarn plugin-helpers build && echo Renaming artifact to $npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip && mv ./build/$npm_package_config_plugin_name*.zip ./build/$npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip" }, @@ -21,9 +20,6 @@ "type": "git", "url": "https://github.com/opensearch-project/dashboards-flow-framework.git" }, - "pre-commit": [ - "lint:es:precommit" - ], "lint-staged": { "*.{ts,tsx,js,jsx,json,css,md}": [ "prettier --write", @@ -35,8 +31,6 @@ "reactflow": "^11.8.3", "yup": "^1.3.2" }, - "devDependencies": { - "pre-commit": "^1.2.2" - }, + "devDependencies": {}, "resolutions": {} } \ No newline at end of file diff --git a/public/component_types/indexer/indexer.ts b/public/component_types/indexer/indexer.ts index 781b1f27..019151fc 100644 --- a/public/component_types/indexer/indexer.ts +++ b/public/component_types/indexer/indexer.ts @@ -31,19 +31,19 @@ export class Indexer extends BaseComponent { this.fields = [ { label: 'Index Name', - name: 'indexName', + id: 'indexName', type: 'select', }, ]; this.createFields = [ { label: 'Index Name', - name: 'indexName', + id: 'indexName', type: 'string', }, // { // label: 'Mappings', - // name: 'indexMappings', + // id: 'indexMappings', // type: 'json', // placeholder: 'Enter an index mappings JSON blob...', // }, diff --git a/public/component_types/indexer/knn_indexer.ts b/public/component_types/indexer/knn_indexer.ts index 65023604..faf7b766 100644 --- a/public/component_types/indexer/knn_indexer.ts +++ b/public/component_types/indexer/knn_indexer.ts @@ -19,7 +19,7 @@ export class KnnIndexer extends Indexer { // TODO: finalize what to expose / what to have for defaults here // { // label: 'K-NN Settings', - // name: 'knnSettings', + // id: 'knnSettings', // type: 'json', // placeholder: 'Enter K-NN settings JSON blob...', // }, diff --git a/public/component_types/interfaces.ts b/public/component_types/interfaces.ts index 94e12952..527015bf 100644 --- a/public/component_types/interfaces.ts +++ b/public/component_types/interfaces.ts @@ -42,7 +42,7 @@ export interface IComponentInput { export interface IComponentField { label: string; type: FieldType; - name: string; + id: string; value?: FieldValue; placeholder?: string; helpText?: string; diff --git a/public/component_types/transformer/text_embedding_transformer.ts b/public/component_types/transformer/text_embedding_transformer.ts index 28e07582..eee236ab 100644 --- a/public/component_types/transformer/text_embedding_transformer.ts +++ b/public/component_types/transformer/text_embedding_transformer.ts @@ -17,7 +17,7 @@ export class TextEmbeddingTransformer extends MLTransformer { this.createFields = [ { label: 'Model ID', - name: 'modelId', + id: 'modelId', type: 'select', selectType: 'model', helpText: 'The deployed text embedding model to use for embedding.', @@ -26,7 +26,7 @@ export class TextEmbeddingTransformer extends MLTransformer { }, { label: 'Input Field', - name: 'inputField', + id: 'inputField', type: 'string', helpText: 'The name of the field from which to obtain text for generating text embeddings.', @@ -36,7 +36,7 @@ export class TextEmbeddingTransformer extends MLTransformer { { label: 'Vector Field', - name: 'vectorField', + id: 'vectorField', type: 'string', helpText: ' The name of the vector field in which to store the generated text embeddings.', diff --git a/public/pages/workflow_detail/component_details/input_fields/select_field.tsx b/public/pages/workflow_detail/component_details/input_fields/select_field.tsx index 008ece7f..709fe18c 100644 --- a/public/pages/workflow_detail/component_details/input_fields/select_field.tsx +++ b/public/pages/workflow_detail/component_details/input_fields/select_field.tsx @@ -48,7 +48,7 @@ export function SelectField(props: SelectFieldProps) { } }, [models]); - const formField = `${props.componentId}.${props.field.name}`; + const formField = `${props.componentId}.${props.field.id}`; const { errors, touched } = useFormikContext(); return ( @@ -84,7 +84,7 @@ export function SelectField(props: SelectFieldProps) { }} isInvalid={isFieldInvalid( props.componentId, - props.field.name, + props.field.id, errors, touched )} diff --git a/public/pages/workflow_detail/component_details/input_fields/text_field.tsx b/public/pages/workflow_detail/component_details/input_fields/text_field.tsx index 78ea27ec..2bcb51a7 100644 --- a/public/pages/workflow_detail/component_details/input_fields/text_field.tsx +++ b/public/pages/workflow_detail/component_details/input_fields/text_field.tsx @@ -24,7 +24,7 @@ interface TextFieldProps { * An input field for a component where users input plaintext */ export function TextField(props: TextFieldProps) { - const formField = `${props.componentId}.${props.field.name}`; + const formField = `${props.componentId}.${props.field.id}`; const { errors, touched } = useFormikContext(); return ( @@ -44,10 +44,10 @@ export function TextField(props: TextFieldProps) { ) : undefined } helpText={props.field.helpText || undefined} - error={getFieldError(props.componentId, props.field.name, errors)} + error={getFieldError(props.componentId, props.field.id, errors)} isInvalid={isFieldInvalid( props.componentId, - props.field.name, + props.field.id, errors, touched )} diff --git a/public/pages/workflow_detail/utils/index.ts b/public/pages/workflow_detail/utils/index.ts deleted file mode 100644 index 079132ce..00000000 --- a/public/pages/workflow_detail/utils/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './utils'; diff --git a/public/pages/workflow_detail/utils/utils.ts b/public/pages/workflow_detail/utils/utils.ts deleted file mode 100644 index 5108c519..00000000 --- a/public/pages/workflow_detail/utils/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReactFlowComponent } from '../../../../common'; - -// Process the raw ReactFlow nodes to only persist the fields we need -export function processNodes( - nodes: ReactFlowComponent[] -): ReactFlowComponent[] { - return nodes - .map((node: ReactFlowComponent) => { - return Object.fromEntries( - ['id', 'data', 'type', 'width', 'height'].map((key: string) => [ - key, - node[key], - ]) - ) as ReactFlowComponent; - }) - .map((node: ReactFlowComponent) => { - return { - ...node, - selected: false, - }; - }); -} diff --git a/public/pages/workflow_detail/workspace/resizable_workspace.tsx b/public/pages/workflow_detail/workspace/resizable_workspace.tsx index d82b8f33..041ebf01 100644 --- a/public/pages/workflow_detail/workspace/resizable_workspace.tsx +++ b/public/pages/workflow_detail/workspace/resizable_workspace.tsx @@ -34,6 +34,7 @@ import { DEFAULT_NEW_WORKFLOW_DESCRIPTION, USE_CASE, WORKFLOW_STATE, + processNodes, } from '../../../../common'; import { AppState, @@ -47,7 +48,6 @@ import { } from '../../../store'; import { Workspace } from './workspace'; import { ComponentDetails } from '../component_details'; -import { processNodes } from '../utils'; // styling import './workspace-styles.scss'; @@ -147,30 +147,36 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) { // Metadata fields (name/description/use_case/etc.) may not exist if the user // cold reloads the page on a new, unsaved workflow. useEffect(() => { - let workflowCopy = { ...props.workflow } as Workflow; - if (!workflowCopy.ui_metadata || !workflowCopy.ui_metadata.workspaceFlow) { - workflowCopy.ui_metadata = { - ...(workflowCopy.ui_metadata || {}), - workspaceFlow: toWorkspaceFlow(workflowCopy.workflows), - }; - console.debug( - `There is no saved UI flow for workflow: ${workflowCopy.name}. Generating a default one.` - ); - } + if (props.workflow) { + let workflowCopy = { ...props.workflow } as Workflow; + if ( + !workflowCopy.ui_metadata || + !workflowCopy.ui_metadata.workspaceFlow + ) { + workflowCopy.ui_metadata = { + ...(workflowCopy.ui_metadata || {}), + workspaceFlow: toWorkspaceFlow(workflowCopy.workflows), + }; + console.debug( + `There is no saved UI flow for workflow: ${workflowCopy.name}. Generating a default one.` + ); + } - // TODO: tune some of the defaults, like use_case and version as these will change - workflowCopy = { - ...workflowCopy, - name: workflowCopy.name || DEFAULT_NEW_WORKFLOW_NAME, - description: workflowCopy.description || DEFAULT_NEW_WORKFLOW_DESCRIPTION, - use_case: workflowCopy.use_case || USE_CASE.PROVISION, - version: workflowCopy.version || { - template: '1.0.0', - compatibility: ['2.12.0', '3.0.0'], - }, - }; + // TODO: tune some of the defaults, like use_case and version as these will change + workflowCopy = { + ...workflowCopy, + name: workflowCopy.name || DEFAULT_NEW_WORKFLOW_NAME, + description: + workflowCopy.description || DEFAULT_NEW_WORKFLOW_DESCRIPTION, + use_case: workflowCopy.use_case || USE_CASE.PROVISION, + version: workflowCopy.version || { + template: '1.0.0', + compatibility: ['2.12.0', '3.0.0'], + }, + }; - setWorkflow(workflowCopy); + setWorkflow(workflowCopy); + } }, [props.workflow]); // Hook to updated the selected ReactFlow component @@ -260,7 +266,7 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) { let curFlowState = reactFlowInstance.toObject() as WorkspaceFlowState; curFlowState = { ...curFlowState, - nodes: processNodes(curFlowState.nodes), + nodes: processNodes(curFlowState.nodes, formikProps.values), }; if (validateWorkspaceFlow(curFlowState)) { setFlowValidOnSubmit(true); diff --git a/public/utils/utils.ts b/public/utils/utils.ts index 1a24f6ea..75ea61a3 100644 --- a/public/utils/utils.ts +++ b/public/utils/utils.ts @@ -15,6 +15,7 @@ import { IComponentField, WorkspaceFormValues, WORKFLOW_STATE, + ReactFlowComponent, } from '../../common'; // Append 16 random characters @@ -48,18 +49,27 @@ export function initComponentData( export function componentDataToFormik(data: IComponentData): FormikValues { const formikValues = {} as FormikValues; data.createFields?.forEach((field) => { - formikValues[field.name] = field.value || getInitialValue(field.type); + formikValues[field.id] = field.value || getInitialValue(field.type); }); return formikValues; } +// TODO: below, we are hardcoding to only persisting and validating create fields. +// If we support both, we will need to dynamically update. +// Injecting the current form values into the component data export function formikToComponentData( - data: IComponentData, - values: FormikValues + origData: IComponentData, + formValues: FormikValues ): IComponentData { - // TODO: populate data.fields with updated values based on the formik values - // We will need this when submitting to the backend. - return data; + return { + ...origData, + createFields: origData.createFields?.map( + (createField: IComponentField) => ({ + ...createField, + value: formValues[createField.id], + }) + ), + } as IComponentData; } // Helper fn to get an initial value based on the field type @@ -97,6 +107,24 @@ export function getFieldError( return errors[componentId]?.[fieldName] as string | undefined; } +// Process the raw ReactFlow nodes. +// De-select them all, and propagate the form data to the internal node data +export function processNodes( + nodes: ReactFlowComponent[], + formValues: WorkspaceFormValues +): ReactFlowComponent[] { + return nodes.map((node: ReactFlowComponent) => { + return { + ...node, + selected: false, + data: formikToComponentData( + { ...node.data, selected: false }, + formValues[node.id] + ), + }; + }); +} + /* **************** Yup (validation) utils ********************** */ @@ -106,7 +134,7 @@ export function getFieldError( export function getComponentSchema(data: IComponentData): ObjectSchema { const schemaObj = {} as { [key: string]: Schema }; data.createFields?.forEach((field) => { - schemaObj[field.name] = getFieldSchema(field); + schemaObj[field.id] = getFieldSchema(field); }); return yup.object(schemaObj); } diff --git a/server/routes/helpers.ts b/server/routes/helpers.ts index c3c671be..531d1bd1 100644 --- a/server/routes/helpers.ts +++ b/server/routes/helpers.ts @@ -37,6 +37,7 @@ function toWorkflowObj(workflowHit: any): Workflow { description: hitSource.description || '', version: hitSource.version, workflows: hitSource.workflows, + ui_metadata: hitSource.ui_metadata, lastUpdated: hitSource.last_updated_time, lastLaunched: hitSource.last_provisioned_time, } as Workflow; diff --git a/yarn.lock b/yarn.lock index 32e25582..f7ff8bac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -283,40 +283,11 @@ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.11.tgz#012c17cb2256ad8de78560da851ab914a7b9b40e" integrity sha512-L7A0AINMXQpVwxHJ4jxD6/XjZ4NDufaRlUJHjNIFKYUFBH1SvOW+neaqb0VTRSLW5suSrSu19ObFEFnfNcr+qg== -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - classcat@^5.0.3, classcat@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.4.tgz#e12d1dfe6df6427f260f03b80dc63571a5107ba6" integrity sha512-sbpkOw6z413p+HDGcBENe498WM9woqWHiJxCq7nvmxe9WmrUmqfAcxpIwAiMtM5Q3AhYkzXcNQHqsWq0mND51g== -concat-stream@^1.4.7: - version "1.6.2" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz" - integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A== - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - "d3-color@1 - 3": version "3.1.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" @@ -404,21 +375,6 @@ hoist-non-react-statics@^3.3.0: dependencies: react-is "^16.7.0" -inherits@^2.0.3, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -429,43 +385,11 @@ lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz" - integrity sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A== - -pre-commit@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" - integrity sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA== - dependencies: - cross-spawn "^5.0.1" - spawn-sync "^1.0.15" - which "1.2.x" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - property-expr@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - react-fast-compare@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" @@ -488,51 +412,6 @@ reactflow@^11.8.3: "@reactflow/node-resizer" "2.1.5" "@reactflow/node-toolbar" "1.2.7" -readable-stream@^2.2.2: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz" - integrity sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw== - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - tiny-case@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" @@ -558,33 +437,11 @@ type-fest@^2.19.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== - use-sync-external-store@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -which@1.2.x, which@^1.2.9: - version "1.2.14" - resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz" - integrity sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw== - dependencies: - isexe "^2.0.0" - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== - yup@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/yup/-/yup-1.3.2.tgz#afffc458f1513ed386e6aaf4bcaa4e67a9e270dc"