From adceb29c0ffed23c9e620dfbd48726c839ccf671 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 3 Dec 2024 16:01:39 +0100 Subject: [PATCH 1/5] added blockly editor to script editor --- .../[processId]/blockly-editor-config.ts | 496 ++++++++++++++++++ .../processes/[processId]/blockly-editor.css | 7 + .../processes/[processId]/blockly-editor.tsx | 114 ++++ .../processes/[processId]/script-editor.tsx | 373 +++++++++---- src/management-system-v2/package.json | 1 + yarn.lock | 204 ++++++- 6 files changed, 1088 insertions(+), 107 deletions(-) create mode 100644 src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts create mode 100644 src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css create mode 100644 src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts new file mode 100644 index 000000000..39018a48e --- /dev/null +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts @@ -0,0 +1,496 @@ +import * as BlocklyJavaScript from 'blockly/javascript'; +const { javascriptGenerator } = BlocklyJavaScript; +import * as Blockly from 'blockly/core'; + +export const INITIAL_TOOLBOX_JSON = { + kind: 'categoryToolbox', + contents: [ + { + kind: 'category', + name: 'Logic', + colour: 210, + contents: [ + { + kind: 'block', + type: 'controls_if', + }, + { + kind: 'block', + blockxml: 'EQ', + }, + { + kind: 'block', + blockxml: 'AND', + }, + { + kind: 'block', + type: 'logic_negate', + }, + { + kind: 'block', + blockxml: 'TRUE', + }, + { + kind: 'block', + type: 'logic_null', + }, + { + kind: 'block', + type: 'logic_ternary', + }, + ], + }, + { + kind: 'category', + name: 'Loops', + colour: 120, + contents: [ + { + kind: 'block', + blockxml: + '\n' + + ' \n' + + ' \n' + + ' 10\n' + + ' \n' + + ' \n' + + ' ', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' WHILE\n' + + ' ', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' i\n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 10\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' j\n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' BREAK\n' + + ' \n', + }, + ], + }, + { + kind: 'category', + name: 'Math', + colour: 230, + contents: [ + { + kind: 'block', + blockxml: + ' \n' + + ' ROUND\n' + + ' \n' + + ' \n' + + ' 3.1\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' 0\n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' ROOT\n' + + ' \n' + + ' \n' + + ' 9\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' SIN\n' + + ' \n' + + ' \n' + + ' 45\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' PI\n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' EVEN\n' + + ' \n' + + ' \n' + + ' 0\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' ADD\n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' SUM\n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' 64\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 10\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' 50\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 100\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' 1\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' 100\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + type: 'math_random_float', + }, + ], + }, + { + kind: 'category', + name: 'Text', + colour: 160, + contents: [ + { + kind: 'block', + blockxml: + ' \n' + ' \n' + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' abc\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' UPPERCASE\n' + + ' \n' + + ' \n' + + ' abc\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' BOTH\n' + + ' \n' + + ' \n' + + ' abc\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' \n' + + ' abc\n' + + ' \n' + + ' \n' + + ' \n', + }, + { + kind: 'block', + blockxml: + ' \n' + + ' \n' + + ' TEXT\n' + + ' \n' + + ' \n' + + ' abc\n' + + ' \n' + + ' \n' + + ' \n', + }, + ], + }, + { + kind: 'category', + name: 'Functions', + custom: 'PROCEDURE', + colour: 50, + }, + { kind: 'sep' }, + { + kind: 'category', + name: 'Variables', + colour: 290, + contents: [ + { + kind: 'block', + type: 'variables_get', + }, + { + kind: 'block', + type: 'variables_set', + }, + ], + }, + { + kind: 'category', + name: 'Error', + colour: 290, + contents: [ + { + kind: 'block', + type: 'throw_error', + }, + ], + }, + { + kind: 'category', + name: 'Progress', + colour: 290, + contents: [ + { + kind: 'block', + type: 'progress', + }, + ], + }, + ], +}; + +Blockly.Blocks['variables_get'] = { + init: function () { + this.appendDummyInput() + .appendField('Variable') + .appendField(new Blockly.FieldTextInput('variableName'), 'name'); + this.setOutput(true, null); + this.setTooltip('Returns value for selected variable'); + this.setHelpUrl(''); + this.setColour(75); + }, +}; + +javascriptGenerator.forBlock['variables_get'] = function (block) { + const variableName = block.getFieldValue('name'); + const code = `variable.get("${variableName}");\n`; + return [code, BlocklyJavaScript.Order.ATOMIC]; +}; + +Blockly.Blocks['variables_set'] = { + init: function () { + this.appendValueInput('value') + .appendField('Set variable') + .appendField(new Blockly.FieldTextInput('variableName'), 'name') + .appendField('to'); + this.setInputsInline(true); + this.setTooltip(''); + this.setHelpUrl(''); + this.setColour(75); + this.setPreviousStatement(true); + this.setNextStatement(true); + }, +}; + +javascriptGenerator.forBlock['variables_set'] = function (block) { + const variableName = block.getFieldValue('name'); + const variableValue = javascriptGenerator.valueToCode( + block, + 'value', + BlocklyJavaScript.Order.ATOMIC, + ); + + const code = `variable.set("${variableName}", ${variableValue});\n`; + return code; +}; + +Blockly.Blocks['progress'] = { + init: function () { + this.appendValueInput('value').setCheck('Number').appendField('Set progress to'); + this.setInputsInline(true); + this.setTooltip(''); + this.setHelpUrl(''); + this.setColour(75); + this.setPreviousStatement(true); + this.setNextStatement(true); + }, +}; + +javascriptGenerator.forBlock['progress'] = function (block) { + const progressValue = + javascriptGenerator.valueToCode(block, 'value', BlocklyJavaScript.Order.ATOMIC) || 0; + + // Generierten Code zurückgeben + const code = `setProgress(${progressValue});\n`; + return code; +}; + +Blockly.Blocks['throw_error'] = { + init: function () { + this.appendDummyInput() + .appendField('Throw') + .appendField( + new Blockly.FieldDropdown([ + ['BpmnEscalation', 'BpmnEscalation'], + ['BpmnError', 'BpmnError'], + ]), + 'name', + ); + + this.appendDummyInput() + .appendField('Reference') + .appendField(new Blockly.FieldTextInput(''), 'reference'); + + this.appendDummyInput() + .appendField('Explanation') + .appendField(new Blockly.FieldTextInput(''), 'explanation'); + + this.setInputsInline(false); + this.setTooltip('Throws error with given reference and explanation'); + this.setHelpUrl(''); + this.setColour(75); + this.setPreviousStatement(true); + this.setNextStatement(false); + }, +}; + +javascriptGenerator.forBlock['throw_error'] = function (block) { + const errorType = block.getFieldValue('name'); + const reference = block.getFieldValue('reference'); + const explanation = block.getFieldValue('explanation'); + + const code = `throw new ${errorType}("${reference}", "${explanation}");\n`; + return code; +}; + +export { Blockly, javascriptGenerator }; diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css new file mode 100644 index 000000000..729b00584 --- /dev/null +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css @@ -0,0 +1,7 @@ +.fill-height { + height: 100%; +} + +.ant-tabs-content { + height: 100%; +} diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx new file mode 100644 index 000000000..0f68bf995 --- /dev/null +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx @@ -0,0 +1,114 @@ +'use client'; +import { + forwardRef, + PropsWithChildren, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react'; +import { BlocklyWorkspace, useBlocklyWorkspace } from 'react-blockly'; +import { INITIAL_TOOLBOX_JSON, javascriptGenerator, Blockly } from './blockly-editor-config'; + +import './blockly-editor.css'; + +type BlocklyEditorProps = PropsWithChildren<{ + onChange: (isScriptValid: boolean, code: { xml: string; js: string }) => void; + initialXml: string; +}>; + +export type BlocklyEditorRefType = { getCode: () => { js: string; xml: string } }; + +const ForwardedBlocklyEditor = forwardRef( + function ForwardedBlocklyEditor( + { + onChange, + initialXml, + }: { + onChange: (isScriptValid: boolean, code: { xml: string; js: string }) => void; + initialXml: string; + }, + ref, + ) { + const blocklyEditorRef = useRef(null); + + const validateBlockScript = () => { + if (blocklyEditorRef.current) { + const topBlocks = blocklyEditorRef.current.getTopBlocks(); + + const topBlocksWithoutPreviousBlock = topBlocks.filter( + (block) => + block.type !== 'procedures_defreturn' && + block.type !== 'procedures_defnoreturn' && + block.getPreviousBlock() === null, + ); + const topBlocksWithoutNextBlock = topBlocks.filter( + (block) => + block.type !== 'procedures_defreturn' && + block.type !== 'procedures_defnoreturn' && + block.getNextBlock() === null, + ); + + if (topBlocksWithoutPreviousBlock.length <= 1 && topBlocksWithoutNextBlock.length <= 1) { + return true; + } + } + + return false; + }; + + useEffect(() => { + if (blocklyEditorRef.current && blocklyEditorRef.current.rendered && initialXml) { + const xml = Blockly.utils.xml.textToDom(initialXml); + Blockly.Xml.clearWorkspaceAndLoadFromXml(xml, blocklyEditorRef.current); + } + }, [initialXml]); + + useImperativeHandle(ref, () => ({ + getCode: () => { + if (blocklyEditorRef.current) { + const xmlText = Blockly.Xml.domToText( + Blockly.Xml.workspaceToDom(blocklyEditorRef.current), + ); + const javascriptCode = javascriptGenerator.workspaceToCode(blocklyEditorRef.current); + return { xml: xmlText, js: javascriptCode }; + } + return { xml: '', js: '' }; + }, + })); + + return ( + { + const isBlockScriptValid = validateBlockScript(); + const xmlText = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace)); + const javascriptCode = javascriptGenerator.workspaceToCode(workspace); + + onChange(isBlockScriptValid, { xml: xmlText, js: javascriptCode }); + }} + onInject={(newWorkspace) => { + blocklyEditorRef.current = newWorkspace; + }} + /> + ); + }, +); + +const BlocklyEditor: React.FC<{ editorRef: any } & BlocklyEditorProps> = ({ + editorRef, + ...props +}) => { + return ; +}; + +export default BlocklyEditor; diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx index cf6e3ffad..c5883f14c 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx @@ -1,9 +1,27 @@ 'use client'; import React, { FC, useEffect, useMemo, useRef, useState } from 'react'; -import { Modal, Button, Tooltip, Space, Row, Col, Input, Divider, List } from 'antd'; +import dynamic from 'next/dynamic'; +import { + Modal, + Button, + Tooltip, + Space, + Row, + Col, + Input, + Divider, + List, + Tag, + Popconfirm, +} from 'antd'; import { CopyOutlined } from '@ant-design/icons'; import { FaArrowRight } from 'react-icons/fa'; +import { CheckCircleOutlined, ExclamationCircleOutlined, FormOutlined } from '@ant-design/icons'; + +import { MdOutlineTransform } from 'react-icons/md'; + +import { IoExtensionPuzzleOutline } from 'react-icons/io5'; const { Search } = Input; @@ -11,9 +29,15 @@ import Editor, { Monaco } from '@monaco-editor/react'; import * as monaco from 'monaco-editor'; import languageExtension from './languageExtension.js'; import useModelerStateStore from './use-modeler-state-store'; -import { getProcessScriptTaskData, saveProcessScriptTask } from '@/lib/data/processes'; +import { + getProcessScriptTaskData, + saveProcessScriptTask, + deleteProcessScriptTask, +} from '@/lib/data/processes'; import { useEnvironment } from '@/components/auth-can'; import { generateScriptTaskFileName } from '@proceed/bpmn-helper'; +import { BlocklyEditorRefType } from './blockly-editor'; +const BlocklyEditor = dynamic(() => import('./blockly-editor'), { ssr: false }); type ScriptEditorProps = { processId: string; @@ -23,11 +47,15 @@ type ScriptEditorProps = { }; const ScriptEditor: FC = ({ processId, open, onClose, selectedElement }) => { - const editorRef = useRef(null); + const monacoEditorRef = useRef(null); const monacoRef = useRef(null); - const [script, setScript] = useState(''); + const [initialScript, setInitialScript] = useState(''); + const [isScriptValid, setIsScriptValid] = useState(true); const modeler = useModelerStateStore((state) => state.modeler); const environment = useEnvironment(); + const [selectedEditor, setSelectedEditor] = useState(null); // JS or blockly + + const blocklyRef = useRef(null); const filename = useMemo(() => { if (modeler && selectedElement && selectedElement.type === 'bpmn:ScriptTask') { @@ -41,19 +69,27 @@ const ScriptEditor: FC = ({ processId, open, onClose, selecte }, [modeler, selectedElement]); useEffect(() => { + setInitialScript(''); + setSelectedEditor(null); if (filename && open) { + // Check if script is stored in JS or blockly and set script and selected editor accordingly getProcessScriptTaskData(processId, filename, 'ts', environment.spaceId).then((res) => { if (typeof res === 'string') { - setScript(res); - } else { - setScript(''); + setInitialScript(res); + setSelectedEditor('JS'); + } + }); + getProcessScriptTaskData(processId, filename, 'xml', environment.spaceId).then((res) => { + if (typeof res === 'string') { + setInitialScript(res); + setSelectedEditor('blockly'); } }); } }, [processId, open, filename, environment]); const handleEditorMount = (editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => { - editorRef.current = editor; + monacoEditorRef.current = editor; monacoRef.current = monaco; const defaultOptions = @@ -70,12 +106,26 @@ const ScriptEditor: FC = ({ processId, open, onClose, selecte }; const handleSave = async () => { - if (modeler && editorRef.current && monacoRef.current && selectedElement && filename) { - const typescriptCode = editorRef.current.getValue(); + if (modeler && filename && selectedElement) { + modeler.getModeling().updateProperties(selectedElement, { + fileName: filename, + }); + + if (selectedEditor === 'JS') { + await storeJSScript(); + } else if (selectedEditor === 'blockly') { + await storeBlocklyScript(); + } + } + }; + + const storeJSScript = async () => { + if (filename && monacoEditorRef.current && monacoRef.current) { + const typescriptCode = monacoEditorRef.current.getValue(); // Transpile TS code to JS const typescriptWorker = await monacoRef.current.languages.typescript.getTypeScriptWorker(); - const editorModel = editorRef.current.getModel(); + const editorModel = monacoEditorRef.current.getModel(); if (!editorModel) { throw new Error( 'Could not get model from editor to transpile TypeScript code to JavaScript', @@ -85,28 +135,58 @@ const ScriptEditor: FC = ({ processId, open, onClose, selecte const emitOutput = await client.getEmitOutput(editorModel.uri.toString()); const javascriptCode = emitOutput.outputFiles[0].text; - modeler.getModeling().updateProperties(selectedElement, { - fileName: filename, - }); - - saveProcessScriptTask(processId, filename, 'ts', typescriptCode, environment.spaceId).then( + await deleteProcessScriptTask(processId, filename, 'xml', environment.spaceId).then( (res) => res && console.error(res.error), ); - saveProcessScriptTask(processId, filename, 'js', javascriptCode, environment.spaceId).then( + await saveProcessScriptTask( + processId, + filename, + 'ts', + typescriptCode, + environment.spaceId, + ).then((res) => res && console.error(res.error)); + await saveProcessScriptTask( + processId, + filename, + 'js', + javascriptCode, + environment.spaceId, + ).then((res) => res && console.error(res.error)); + } + }; + + const storeBlocklyScript = async () => { + if (filename && isScriptValid && blocklyRef.current) { + const blocklyCode = blocklyRef.current.getCode(); + await deleteProcessScriptTask(processId, filename, 'ts', environment.spaceId).then( (res) => res && console.error(res.error), ); + await saveProcessScriptTask( + processId, + filename, + 'xml', + blocklyCode.xml, + environment.spaceId, + ).then((res) => res && console.error(res.error)); + await saveProcessScriptTask( + processId, + filename, + 'js', + blocklyCode.js, + environment.spaceId, + ).then((res) => res && console.error(res.error)); } }; const handleCopyToClipboard = () => { - if (editorRef.current) { - navigator.clipboard.writeText(editorRef.current.getValue()); + if (monacoEditorRef.current) { + navigator.clipboard.writeText(monacoEditorRef.current.getValue()); } }; const getEditorPositionRange = () => { - if (editorRef.current && monacoRef.current) { - const position = editorRef.current.getPosition(); + if (monacoEditorRef.current && monacoRef.current) { + const position = monacoEditorRef.current.getPosition(); if (position) { return new monacoRef.current.Range( position.lineNumber, @@ -119,6 +199,14 @@ const ScriptEditor: FC = ({ processId, open, onClose, selecte return null; }; + const transformToCode = async () => { + if (blocklyRef.current) { + const blocklyCode = blocklyRef.current.getCode(); + setInitialScript(blocklyCode.js); + setSelectedEditor('JS'); + } + }; + return ( = ({ processId, open, onClose, selecte width="90vw" styles={{ body: { height: '85vh' }, header: { margin: 0 } }} title={Edit Script Task} - okText="Save" - cancelText="Close" onCancel={onClose} - onOk={handleSave} + footer={ + + + + + } >
- - - - - - - - - + + )} +
+ )} +
+ {selectedEditor === 'JS' ? ( + + + + + + + + + + + + )} + > +
+ + + + + + ) : selectedEditor === 'blockly' ? ( + boolean), code: any) => { + setIsScriptValid(isScriptValid); + }} + > + ) : (
- Variables - } - dataSource={['VariableA', 'VariableB', 'VariableC']} - renderItem={(item) => ( - - {item} - - - - - - )} - > + + + +
- - - - - + )} +
); diff --git a/src/management-system-v2/package.json b/src/management-system-v2/package.json index f3821877f..35472b9a5 100644 --- a/src/management-system-v2/package.json +++ b/src/management-system-v2/package.json @@ -56,6 +56,7 @@ "nodemailer": "6.9.13", "openapi-fetch": "0.8.2", "react": "18.2.0", + "react-blockly": "9.0.0", "react-contenteditable": "^3.3.7", "react-dom": "18.2.0", "react-frame-component": "^5.2.6", diff --git a/yarn.lock b/yarn.lock index 76183a7da..74e4cb088 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4394,6 +4394,13 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + aggregate-error@^3.0.0, aggregate-error@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" @@ -5742,6 +5749,13 @@ blob@0.0.5: resolved "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== +"blockly@>= 11.0.0": + version "11.1.1" + resolved "https://registry.yarnpkg.com/blockly/-/blockly-11.1.1.tgz#01da2e7760032fc6aeccbfadf699fe22fe7491e0" + integrity sha512-PmInYM9zH1HcYMffqnfmeu2O3g0intsowy08S0KDu3q8/95TfGo1tcDYpeWNQDkPOEzN1yy3oocsRO4NPDHtKA== + dependencies: + jsdom "23.0.0" + bluebird-lst@^1.0.9: version "1.0.9" resolved "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz" @@ -7839,6 +7853,13 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" +cssstyle@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-3.0.0.tgz#17ca9c87d26eac764bb8cfd00583cff21ce0277a" + integrity sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg== + dependencies: + rrweb-cssom "^0.6.0" + csstype@^3.0.2, csstype@^3.1.0, csstype@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" @@ -8123,6 +8144,14 @@ data-urls@^1.0.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + data-view-buffer@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz" @@ -8227,6 +8256,11 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz" @@ -9163,7 +9197,7 @@ entities@^2.0.0: resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== -entities@^4.2.0, entities@^4.4.0: +entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -11762,6 +11796,13 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + html-entities@^1.3.1: version "1.4.0" resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz" @@ -11939,6 +11980,14 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz" @@ -11988,6 +12037,14 @@ https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.2: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" @@ -12023,7 +12080,7 @@ iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: +iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -12740,6 +12797,11 @@ is-posix-bracket@^0.1.0: resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz" integrity sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" @@ -14043,6 +14105,33 @@ jsdoc@^3.6.6: taffydb "2.6.2" underscore "~1.13.2" +jsdom@23.0.0: + version "23.0.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-23.0.0.tgz#7c8bac82e32e1ac3eef29096ea59d519c72ce4eb" + integrity sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ== + dependencies: + cssstyle "^3.0.0" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.7" + parse5 "^7.1.2" + rrweb-cssom "^0.6.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.3" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.14.2" + xml-name-validator "^5.0.0" + jsdom@^11.5.1: version "11.12.0" resolved "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz" @@ -16127,6 +16216,11 @@ nwsapi@^2.0.7: resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz" integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== +nwsapi@^2.2.7: + version "2.2.16" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" + integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" @@ -16762,6 +16856,13 @@ parse5@^6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +parse5@^7.1.2: + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + dependencies: + entities "^4.5.0" + parseley@^0.12.0: version "0.12.1" resolved "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz" @@ -17796,6 +17897,13 @@ psl@^1.1.28: resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +psl@^1.1.33: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + pstree.remy@^1.1.8: version "1.1.8" resolved "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz" @@ -17852,7 +17960,7 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -18389,6 +18497,14 @@ rdf-canonize@^1.0.2: node-forge "^0.10.0" semver "^6.3.0" +react-blockly@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/react-blockly/-/react-blockly-9.0.0.tgz#9a9a5a6489eb386e9e87fa98b689f31ed2496c32" + integrity sha512-EzvGpaYYjbTbsenQov7UyrxvnjqitqJ03wBY4Rz0Q/9tfpVTZ4Lx4um0sDG6xY5KsWzyOIuo60KablYCOr8LUQ== + dependencies: + blockly ">= 11.0.0" + prop-types "^15.8.1" + react-contenteditable@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/react-contenteditable/-/react-contenteditable-3.3.7.tgz#18dd1f281841ba2c2b306e2d28278bc31b7929ed" @@ -19063,6 +19179,11 @@ rope-sequence@^1.3.0: resolved "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz" integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== +rrweb-cssom@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" + integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== + rsvp@^3.3.3: version "3.6.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz" @@ -19227,6 +19348,13 @@ saxen@^8.1.0, saxen@^8.1.2: resolved "https://registry.npmjs.org/saxen/-/saxen-8.1.2.tgz" integrity sha512-xUOiiFbc3Ow7p8KMxwsGICPx46ZQvy3+qfNVhrkwfz3Vvq45eGt98Ft5IQaA1R/7Tb5B5MKh9fUR9x3c3nDTxw== +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" @@ -20564,7 +20692,7 @@ swap-case@^1.1.0: lower-case "^1.1.1" upper-case "^1.1.1" -"symbol-tree@>= 3.1.0 < 4.0.0", symbol-tree@^3.2.2: +"symbol-tree@>= 3.1.0 < 4.0.0", symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== @@ -20991,6 +21119,16 @@ tough-cookie@^2.2.0, tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5 psl "^1.1.28" punycode "^2.1.1" +tough-cookie@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + tr46@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz" @@ -20998,6 +21136,13 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" @@ -21442,6 +21587,11 @@ universalify@^0.1.0: resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" @@ -21561,7 +21711,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@^1.5.1, url-parse@^1.5.10: +url-parse@^1.5.1, url-parse@^1.5.10, url-parse@^1.5.3: version "1.5.10" resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -21945,6 +22095,13 @@ w3c-keyname@^2.2.0: resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + walker@^1.0.8, walker@~1.0.5: version "1.0.8" resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" @@ -22015,6 +22172,11 @@ webidl-conversions@^4.0.2: resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-bundle-analyzer@^3.3.0: version "3.9.0" resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz" @@ -22225,11 +22387,31 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.24" +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" + integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-2.0.1.tgz" @@ -22554,7 +22736,7 @@ ws@^7.5.5: resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.17.1: +ws@^8.14.2, ws@^8.17.1: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== @@ -22589,11 +22771,21 @@ xml-name-validator@^3.0.0: resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1: version "15.1.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xmlcreate@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz" From 060ba280b7094bbaf645941d5e19600578412d13 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 21 Jan 2025 12:42:05 +0100 Subject: [PATCH 2/5] remove unnecessary css --- .../[environmentId]/processes/[processId]/blockly-editor.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css index 729b00584..0ceb9d28b 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.css @@ -1,7 +1,3 @@ .fill-height { height: 100%; } - -.ant-tabs-content { - height: 100%; -} From 9ec2daa4e5aa44bfc677168a4ccf8eaa1deab2ae Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 21 Jan 2025 12:46:38 +0100 Subject: [PATCH 3/5] set variable to null if trying to init without value --- .../processes/[processId]/blockly-editor-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts index 39018a48e..c705c3342 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor-config.ts @@ -430,7 +430,7 @@ javascriptGenerator.forBlock['variables_set'] = function (block) { BlocklyJavaScript.Order.ATOMIC, ); - const code = `variable.set("${variableName}", ${variableValue});\n`; + const code = `variable.set("${variableName}", ${variableValue || null});\n`; return code; }; From 36866a70156465a8fb3987924400f04a6f4ce22a Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 21 Jan 2025 13:01:22 +0100 Subject: [PATCH 4/5] use promise.allSettled for async scriptTask storage operations --- .../processes/[processId]/script-editor.tsx | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx index c5883f14c..eacbdb08e 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/script-editor.tsx @@ -158,23 +158,24 @@ const ScriptEditor: FC = ({ processId, open, onClose, selecte const storeBlocklyScript = async () => { if (filename && isScriptValid && blocklyRef.current) { const blocklyCode = blocklyRef.current.getCode(); - await deleteProcessScriptTask(processId, filename, 'ts', environment.spaceId).then( - (res) => res && console.error(res.error), - ); - await saveProcessScriptTask( - processId, - filename, - 'xml', - blocklyCode.xml, - environment.spaceId, - ).then((res) => res && console.error(res.error)); - await saveProcessScriptTask( - processId, - filename, - 'js', - blocklyCode.js, - environment.spaceId, - ).then((res) => res && console.error(res.error)); + + const scriptTaskStoragePromises = [ + deleteProcessScriptTask(processId, filename, 'ts', environment.spaceId), + saveProcessScriptTask(processId, filename, 'xml', blocklyCode.xml, environment.spaceId), + saveProcessScriptTask(processId, filename, 'js', blocklyCode.js, environment.spaceId), + ]; + + return Promise.allSettled(scriptTaskStoragePromises).then((results) => { + results.forEach((res) => { + if (res.status === 'fulfilled' && res.value) { + console.error(res.value.error); + } + + if (res.status === 'rejected') { + console.error(res.reason); + } + }); + }); } }; From 42e283bd939a4e4494b2c6d245198f1975a89927 Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 21 Jan 2025 13:46:42 +0100 Subject: [PATCH 5/5] use editorRef as prop in blockly component --- .../processes/[processId]/blockly-editor.tsx | 147 ++++++++---------- 1 file changed, 64 insertions(+), 83 deletions(-) diff --git a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx index 0f68bf995..607a8146d 100644 --- a/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx +++ b/src/management-system-v2/app/(dashboard)/[environmentId]/processes/[processId]/blockly-editor.tsx @@ -12,103 +12,84 @@ import { INITIAL_TOOLBOX_JSON, javascriptGenerator, Blockly } from './blockly-ed import './blockly-editor.css'; +export type BlocklyEditorRefType = { getCode: () => { js: string; xml: string } }; + type BlocklyEditorProps = PropsWithChildren<{ onChange: (isScriptValid: boolean, code: { xml: string; js: string }) => void; initialXml: string; + editorRef: React.Ref; }>; -export type BlocklyEditorRefType = { getCode: () => { js: string; xml: string } }; - -const ForwardedBlocklyEditor = forwardRef( - function ForwardedBlocklyEditor( - { - onChange, - initialXml, - }: { - onChange: (isScriptValid: boolean, code: { xml: string; js: string }) => void; - initialXml: string; - }, - ref, - ) { - const blocklyEditorRef = useRef(null); +const BlocklyEditor = ({ onChange, initialXml, editorRef }: BlocklyEditorProps) => { + const blocklyEditorRef = useRef(null); - const validateBlockScript = () => { - if (blocklyEditorRef.current) { - const topBlocks = blocklyEditorRef.current.getTopBlocks(); + const validateBlockScript = () => { + if (blocklyEditorRef.current) { + const topBlocks = blocklyEditorRef.current.getTopBlocks(); - const topBlocksWithoutPreviousBlock = topBlocks.filter( - (block) => - block.type !== 'procedures_defreturn' && - block.type !== 'procedures_defnoreturn' && - block.getPreviousBlock() === null, - ); - const topBlocksWithoutNextBlock = topBlocks.filter( - (block) => - block.type !== 'procedures_defreturn' && - block.type !== 'procedures_defnoreturn' && - block.getNextBlock() === null, - ); + const topBlocksWithoutPreviousBlock = topBlocks.filter( + (block) => + block.type !== 'procedures_defreturn' && + block.type !== 'procedures_defnoreturn' && + block.getPreviousBlock() === null, + ); + const topBlocksWithoutNextBlock = topBlocks.filter( + (block) => + block.type !== 'procedures_defreturn' && + block.type !== 'procedures_defnoreturn' && + block.getNextBlock() === null, + ); - if (topBlocksWithoutPreviousBlock.length <= 1 && topBlocksWithoutNextBlock.length <= 1) { - return true; - } + if (topBlocksWithoutPreviousBlock.length <= 1 && topBlocksWithoutNextBlock.length <= 1) { + return true; } + } - return false; - }; + return false; + }; - useEffect(() => { - if (blocklyEditorRef.current && blocklyEditorRef.current.rendered && initialXml) { - const xml = Blockly.utils.xml.textToDom(initialXml); - Blockly.Xml.clearWorkspaceAndLoadFromXml(xml, blocklyEditorRef.current); - } - }, [initialXml]); - - useImperativeHandle(ref, () => ({ - getCode: () => { - if (blocklyEditorRef.current) { - const xmlText = Blockly.Xml.domToText( - Blockly.Xml.workspaceToDom(blocklyEditorRef.current), - ); - const javascriptCode = javascriptGenerator.workspaceToCode(blocklyEditorRef.current); - return { xml: xmlText, js: javascriptCode }; - } - return { xml: '', js: '' }; - }, - })); + useEffect(() => { + if (blocklyEditorRef.current && blocklyEditorRef.current.rendered && initialXml) { + const xml = Blockly.utils.xml.textToDom(initialXml); + Blockly.Xml.clearWorkspaceAndLoadFromXml(xml, blocklyEditorRef.current); + } + }, [initialXml]); - return ( - { - const isBlockScriptValid = validateBlockScript(); - const xmlText = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace)); - const javascriptCode = javascriptGenerator.workspaceToCode(workspace); + useImperativeHandle(editorRef, () => ({ + getCode: () => { + if (blocklyEditorRef.current) { + const xmlText = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(blocklyEditorRef.current)); + const javascriptCode = javascriptGenerator.workspaceToCode(blocklyEditorRef.current); + return { xml: xmlText, js: javascriptCode }; + } + return { xml: '', js: '' }; + }, + })); - onChange(isBlockScriptValid, { xml: xmlText, js: javascriptCode }); - }} - onInject={(newWorkspace) => { - blocklyEditorRef.current = newWorkspace; - }} - /> - ); - }, -); + return ( + { + const isBlockScriptValid = validateBlockScript(); + const xmlText = Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace)); + const javascriptCode = javascriptGenerator.workspaceToCode(workspace); -const BlocklyEditor: React.FC<{ editorRef: any } & BlocklyEditorProps> = ({ - editorRef, - ...props -}) => { - return ; + onChange(isBlockScriptValid, { xml: xmlText, js: javascriptCode }); + }} + onInject={(newWorkspace) => { + blocklyEditorRef.current = newWorkspace; + }} + /> + ); }; export default BlocklyEditor;