From 424455661039e38184746613e6df57eb5f3f52c4 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 26 Mar 2023 19:38:03 -0500 Subject: [PATCH 001/118] Install and configure Redux Toolkit. --- client/middleware.js | 5 + client/modules/App/App.jsx | 6 +- client/modules/IDE/selectors/collections.js | 2 +- client/modules/IDE/selectors/projects.js | 2 +- client/modules/IDE/selectors/users.js | 2 +- client/store.js | 42 +- package-lock.json | 966 +++++++++++--------- package.json | 8 +- 8 files changed, 555 insertions(+), 478 deletions(-) create mode 100644 client/middleware.js diff --git a/client/middleware.js b/client/middleware.js new file mode 100644 index 0000000000..0b4230ec9d --- /dev/null +++ b/client/middleware.js @@ -0,0 +1,5 @@ +import { createListenerMiddleware } from '@reduxjs/toolkit'; + +const listenerMiddleware = createListenerMiddleware(); + +export default listenerMiddleware; diff --git a/client/modules/App/App.jsx b/client/modules/App/App.jsx index 1f41446a79..10286ac09a 100644 --- a/client/modules/App/App.jsx +++ b/client/modules/App/App.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { connect } from 'react-redux'; -import getConfig from '../../utils/getConfig'; +import { showReduxDevTools } from '../../store'; import DevTools from './components/DevTools'; import { setPreviousPath } from '../IDE/actions/ide'; import { setLanguage } from '../IDE/actions/preferences'; @@ -51,9 +51,7 @@ class App extends React.Component { return (
- {this.state.isMounted && - !window.devToolsExtension && - getConfig('NODE_ENV') === 'development' && } + {this.state.isMounted && showReduxDevTools() && } {this.props.children}
); diff --git a/client/modules/IDE/selectors/collections.js b/client/modules/IDE/selectors/collections.js index 207dce39a9..136a0a7920 100644 --- a/client/modules/IDE/selectors/collections.js +++ b/client/modules/IDE/selectors/collections.js @@ -1,4 +1,4 @@ -import { createSelector } from 'reselect'; +import { createSelector } from '@reduxjs/toolkit'; import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'; import find from 'lodash/find'; import orderBy from 'lodash/orderBy'; diff --git a/client/modules/IDE/selectors/projects.js b/client/modules/IDE/selectors/projects.js index 08701d211c..d5ba29a268 100644 --- a/client/modules/IDE/selectors/projects.js +++ b/client/modules/IDE/selectors/projects.js @@ -1,4 +1,4 @@ -import { createSelector } from 'reselect'; +import { createSelector } from '@reduxjs/toolkit'; import differenceInMilliseconds from 'date-fns/differenceInMilliseconds'; import orderBy from 'lodash/orderBy'; import { DIRECTION } from '../actions/sorting'; diff --git a/client/modules/IDE/selectors/users.js b/client/modules/IDE/selectors/users.js index 4086348041..15f1f141bb 100644 --- a/client/modules/IDE/selectors/users.js +++ b/client/modules/IDE/selectors/users.js @@ -1,4 +1,4 @@ -import { createSelector } from 'reselect'; +import { createSelector } from '@reduxjs/toolkit'; import getConfig from '../../../utils/getConfig'; const getAuthenticated = (state) => state.user.authenticated; diff --git a/client/store.js b/client/store.js index 4cec9419b7..12beed2e12 100644 --- a/client/store.js +++ b/client/store.js @@ -1,30 +1,36 @@ -import { createStore, applyMiddleware, compose } from 'redux'; -import thunk from 'redux-thunk'; +import { configureStore } from '@reduxjs/toolkit'; +import listenerMiddleware from './middleware'; import DevTools from './modules/App/components/DevTools'; import rootReducer from './reducers'; import { clearState, loadState } from './persistState'; import getConfig from './utils/getConfig'; -export default function configureStore(initialState) { - const enhancers = [applyMiddleware(thunk)]; - - if (getConfig('CLIENT') && getConfig('NODE_ENV') === 'development') { - // Enable DevTools only when rendering on client and during development. - enhancers.push( - window.devToolsExtension - ? window.devToolsExtension() - : DevTools.instrument() - ); - } +// Enable DevTools only when rendering on client and during development. +// Display the dock monitor only if no browser extension is found. +export function showReduxDevTools() { + return ( + getConfig('CLIENT') && + getConfig('NODE_ENV') === 'development' && + !window.__REDUX_DEVTOOLS_EXTENSION__ + ); +} +export default function setupStore(initialState) { const savedState = loadState(); clearState(); - const store = createStore( - rootReducer, - savedState != null ? savedState : initialState, - compose(...enhancers) - ); + const store = configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + thunk: true, + serializableCheck: true, + // TODO: enable immutableCheck once the mutations are fixed. + immutableCheck: false + }).concat(listenerMiddleware.middleware), + preloadedState: savedState || initialState, + enhancers: showReduxDevTools() ? [DevTools.instrument()] : [] + }); if (module.hot) { // Enable Webpack hot module replacement for reducers diff --git a/package-lock.json b/package-lock.json index c6a5dee419..1677762d97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,9 @@ "@babel/register": "^7.14.5", "@emmetio/codemirror-plugin": "^1.2.4", "@redux-devtools/core": "^3.11.0", - "@redux-devtools/dock-monitor": "^2.1.0", - "@redux-devtools/log-monitor": "^3.1.0", + "@redux-devtools/dock-monitor": "^3.0.1", + "@redux-devtools/log-monitor": "^4.0.2", + "@reduxjs/toolkit": "^1.9.3", "async": "^3.2.3", "axios": "^0.21.2", "babel-plugin-styled-components": "^1.13.2", @@ -88,12 +89,11 @@ "react-split-pane": "^0.1.92", "react-tabs": "^2.3.1", "react-transition-group": "^4.4.2", - "redux": "^3.7.2", + "redux": "^4.2.1", "redux-auth-wrapper": "^2.1.0", "redux-thunk": "^2.3.0", "regenerator-runtime": "^0.13.9", "remark-slug": "^6.1.0", - "reselect": "^4.0.0", "s3-policy-v4": "0.0.3", "shortid": "^2.2.16", "sinon": "^7.5.0", @@ -2282,11 +2282,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" @@ -2670,6 +2670,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.1.1", @@ -2689,6 +2690,7 @@ "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -2703,6 +2705,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, "engines": { "node": ">= 4" } @@ -2711,6 +2714,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2726,6 +2730,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -2734,6 +2739,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "engines": { "node": ">=8" }, @@ -2745,6 +2751,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "engines": { "node": ">=10" }, @@ -2762,6 +2769,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", @@ -2774,7 +2782,8 @@ "node_modules/@humanwhocodes/object-schema": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true }, "node_modules/@hypnosphi/create-react-context": { "version": "0.3.1", @@ -5814,39 +5823,23 @@ } }, "node_modules/@redux-devtools/dock-monitor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/dock-monitor/-/dock-monitor-2.1.0.tgz", - "integrity": "sha512-DFVLgrFCjiuCGeHxZNaRUGVgACeZmkmm7I/grBU72Slx+KW7C5QCm0dS5UEZr3siTcRBLTDKhUzQLXkAT+6PJg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@redux-devtools/dock-monitor/-/dock-monitor-3.0.1.tgz", + "integrity": "sha512-ajIa3NRy89B7mw0/4SCNipXIV+B1eOqvprQXdGJPA66F6Gpzf3TKJ2Mupmj4yZNL1NL2GBIAbApNnWE9u+DU5w==", "dependencies": { - "@babel/runtime": "^7.16.7", - "@types/prop-types": "^15.7.4", + "@babel/runtime": "^7.18.3", + "@types/prop-types": "^15.7.5", "parse-key": "^0.2.1", "prop-types": "^15.8.1", - "react-dock": "^0.5.1" + "react-dock": "^0.6.0" }, "peerDependencies": { - "@redux-devtools/core": "^3.7.0", - "@types/react": "^16.3.0 || ^17.0.0", - "react": "^16.3.0 || ^17.0.0", + "@redux-devtools/core": "^3.13.1", + "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react": "^16.3.0 || ^17.0.0 || ^18.0.0", "redux": "^3.4.0 || ^4.0.0" } }, - "node_modules/@redux-devtools/dock-monitor/node_modules/react-dock": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.5.1.tgz", - "integrity": "sha512-mRY6xQDreHlUQPPgx1PHICUMQpY0Ywo8idS9rDdWhN+1ERWgl85w6en9ad017ERbaodP50f9D9CHg5DrRU9bhg==", - "dependencies": { - "@babel/runtime": "^7.16.7", - "@types/lodash": "^4.14.178", - "@types/prop-types": "^15.7.4", - "lodash.debounce": "^4.0.8", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "@types/react": "^16.3.0 || ^17.0.0", - "react": "^16.3.0 || ^17.0.0" - } - }, "node_modules/@redux-devtools/instrument": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@redux-devtools/instrument/-/instrument-2.1.0.tgz", @@ -5860,58 +5853,64 @@ } }, "node_modules/@redux-devtools/log-monitor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/log-monitor/-/log-monitor-3.1.0.tgz", - "integrity": "sha512-T5NXzasj7250tJmQPiXzFkxlY0Rg0W7feR1eZj8VrdePvVkeXTP5k9VjxkVqtba5EmZR8swGec+Z1eD71ZgUsA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@redux-devtools/log-monitor/-/log-monitor-4.0.2.tgz", + "integrity": "sha512-BaTAwadm/XzRfnN2+8t4mwdbOILWfwsvMfVPn5OuE+NFaUG9pDKGoHRPCdMBaRdggDqqb5nlMgRCVdHzYftgVw==", "dependencies": { - "@babel/runtime": "^7.16.7", - "@types/lodash.debounce": "^4.0.6", - "@types/prop-types": "^15.7.4", + "@babel/runtime": "^7.20.6", + "@types/lodash.debounce": "^4.0.7", + "@types/prop-types": "^15.7.5", "@types/redux-devtools-themes": "^1.0.0", "lodash.debounce": "^4.0.8", "prop-types": "^15.8.1", - "react-json-tree": "^0.16.1", + "react-json-tree": "^0.18.0", "redux-devtools-themes": "^1.0.0" }, "peerDependencies": { - "@redux-devtools/core": "^3.7.0", - "@types/react": "^16.3.0 || ^17.0.0", - "react": "^16.3.0 || ^17.0.0", + "@redux-devtools/core": "^3.13.1", + "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react": "^16.3.0 || ^17.0.0 || ^18.0.0", "redux": "^3.4.0 || ^4.0.0" } }, - "node_modules/@redux-devtools/log-monitor/node_modules/csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" - }, - "node_modules/@redux-devtools/log-monitor/node_modules/react-base16-styling": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz", - "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", + "node_modules/@reduxjs/toolkit": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", + "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", "dependencies": { - "@babel/runtime": "^7.16.7", - "@types/base16": "^1.0.2", - "@types/lodash": "^4.14.178", - "base16": "^1.0.0", - "color": "^3.2.1", - "csstype": "^3.0.10", - "lodash.curry": "^4.1.1" + "immer": "^9.0.16", + "redux": "^4.2.0", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.7" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } } }, - "node_modules/@redux-devtools/log-monitor/node_modules/react-json-tree": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.16.2.tgz", - "integrity": "sha512-80F7ZTqeOl1YaS/sDce4tYBcSe69/d0mlUmcIhyXezPFctWrtvyN56EMExX9jWsq3XMdvsUKKPUeNo8QCBy2jg==", - "dependencies": { - "@babel/runtime": "^7.17.8", - "@types/prop-types": "^15.7.4", - "prop-types": "^15.8.1", - "react-base16-styling": "^0.9.1" - }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@reduxjs/toolkit/node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", "peerDependencies": { - "@types/react": "^16.3.0 || ^17.0.0", - "react": "^16.3.0 || ^17.0.0" + "redux": "^4" } }, "node_modules/@sindresorhus/is": { @@ -10477,14 +10476,14 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "node_modules/@types/lodash": { - "version": "4.14.181", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.181.tgz", - "integrity": "sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==" + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==" }, "node_modules/@types/lodash.debounce": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", - "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz", + "integrity": "sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==", "dependencies": { "@types/lodash": "*" } @@ -10569,9 +10568,9 @@ "dev": true }, "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/q": { "version": "1.5.2", @@ -10619,14 +10618,6 @@ "redux": "^4.0.0" } }, - "node_modules/@types/react-redux/node_modules/redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "node_modules/@types/react-syntax-highlighter": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz", @@ -10938,39 +10929,6 @@ "@vue/shared": "3.1.5" } }, - "node_modules/@vue/reactivity": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", - "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/shared": "3.1.5" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.5.tgz", - "integrity": "sha512-YQbG5cBktN1RowQDKA22itmvQ+b40f0WgQ6CXK4VYoYICAiAfu6Cc14777ve8zp1rJRGtk5oIeS149TOculrTg==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/reactivity": "3.1.5", - "@vue/shared": "3.1.5" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.5.tgz", - "integrity": "sha512-tNcf3JhVR0RfW0kw1p8xZgv30nvX8Y9rsz7eiQ0dHe273sfoCngAG0y4GvMaY4Xd8FsjUwFedd4suQ8Lu8meXg==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/runtime-core": "3.1.5", - "@vue/shared": "3.1.5", - "csstype": "^2.6.8" - } - }, "node_modules/@vue/shared": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", @@ -11343,6 +11301,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -11671,6 +11630,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -12224,6 +12184,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, "engines": { "node": ">=8" } @@ -15356,9 +15317,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -18799,6 +18760,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -19200,6 +19162,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, "dependencies": { "ansi-colors": "^4.1.1" }, @@ -19211,6 +19174,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, "engines": { "node": ">=6" } @@ -19437,6 +19401,7 @@ "version": "7.31.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -20088,6 +20053,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -20102,6 +20068,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, "engines": { "node": ">=4" } @@ -20246,6 +20213,7 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, "dependencies": { "@babel/highlight": "^7.10.4" } @@ -20254,6 +20222,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -20262,6 +20231,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -20277,6 +20247,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -20291,6 +20262,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -20302,6 +20274,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -20312,12 +20285,14 @@ "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/eslint/node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -20331,6 +20306,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { "node": ">=10" }, @@ -20342,6 +20318,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, "engines": { "node": ">=10" } @@ -20349,12 +20326,14 @@ "node_modules/eslint/node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/eslint/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -20366,6 +20345,7 @@ "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -20380,6 +20360,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -20388,6 +20369,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, "engines": { "node": ">= 4" } @@ -20396,6 +20378,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -20411,6 +20394,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -20419,6 +20403,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -20430,6 +20415,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -20442,6 +20428,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -20453,6 +20440,7 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -20469,6 +20457,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -20477,6 +20466,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "engines": { "node": ">= 0.8.0" } @@ -20485,6 +20475,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -20493,6 +20484,7 @@ "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -20507,6 +20499,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -20518,6 +20511,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -20526,6 +20520,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.0" }, @@ -20537,6 +20532,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "engines": { "node": ">=8" }, @@ -20548,6 +20544,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -20559,6 +20556,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "engines": { "node": ">=10" }, @@ -20570,6 +20568,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -20583,12 +20582,14 @@ "node_modules/eslint/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, "dependencies": { "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", @@ -20602,6 +20603,7 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -20613,6 +20615,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, "engines": { "node": ">=4" } @@ -20633,6 +20636,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -20644,6 +20648,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, "engines": { "node": ">=4.0" } @@ -21846,6 +21851,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -22082,6 +22088,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -22094,6 +22101,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -22107,7 +22115,8 @@ "node_modules/flatted": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", - "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==" + "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", + "dev": true }, "node_modules/flatten": { "version": "1.0.2", @@ -23610,7 +23619,8 @@ "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true }, "node_modules/functions-have-names": { "version": "1.2.2", @@ -25463,6 +25473,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, "engines": { "node": ">=0.8.19" } @@ -33458,6 +33469,7 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -34168,7 +34180,8 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -34982,7 +34995,8 @@ "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true }, "node_modules/lodash._reinterpolate": { "version": "3.0.0", @@ -35009,12 +35023,13 @@ "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true }, "node_modules/lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -35122,7 +35137,8 @@ "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true }, "node_modules/lodash.unescape": { "version": "4.0.1", @@ -38155,7 +38171,8 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true }, "node_modules/negotiator": { "version": "0.6.2", @@ -42200,6 +42217,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -42958,6 +42976,25 @@ "node": ">=0.10.0" } }, + "node_modules/react-base16-styling": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz", + "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", + "dependencies": { + "@babel/runtime": "^7.16.7", + "@types/base16": "^1.0.2", + "@types/lodash": "^4.14.178", + "base16": "^1.0.0", + "color": "^3.2.1", + "csstype": "^3.0.10", + "lodash.curry": "^4.1.1" + } + }, + "node_modules/react-base16-styling/node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, "node_modules/react-clientside-effect": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz", @@ -43263,6 +43300,22 @@ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", "dev": true }, + "node_modules/react-dock": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.6.0.tgz", + "integrity": "sha512-jEOhv1s+pqRQ4JxgUw4XUotnprOehZ23mqchf3whxYXnvNgTQOXCxh6bpcqW8P6OybIk2bYO18r3qimZ3ypCbg==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@types/lodash": "^4.14.182", + "@types/prop-types": "^15.7.5", + "lodash.debounce": "^4.0.8", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", @@ -43500,6 +43553,20 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-json-tree": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.18.0.tgz", + "integrity": "sha512-Qe6HKSXrr++n9Y31nkRJ3XvQMATISpqigH1vEKhLwB56+nk5thTP0ITThpjxY6ZG/ubpVq/aEHIcyLP/OPHxeA==", + "dependencies": { + "@babel/runtime": "^7.20.6", + "@types/lodash": "^4.14.191", + "react-base16-styling": "^0.9.1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -44282,14 +44349,11 @@ } }, "node_modules/redux": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { - "lodash": "^4.2.1", - "lodash-es": "^4.2.1", - "loose-envify": "^1.1.0", - "symbol-observable": "^1.0.3" + "@babel/runtime": "^7.9.2" } }, "node_modules/redux-auth-wrapper": { @@ -44394,9 +44458,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -44455,6 +44519,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, "engines": { "node": ">=8" }, @@ -45021,9 +45086,9 @@ "dev": true }, "node_modules/reselect": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", - "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", @@ -46176,7 +46241,7 @@ "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "dependencies": { "is-arrayish": "^0.3.1" } @@ -46255,6 +46320,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -46271,6 +46337,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -46285,6 +46352,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -46295,12 +46363,14 @@ "node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -46684,7 +46754,8 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "node_modules/sshpk": { "version": "1.16.1", @@ -47577,14 +47648,6 @@ "domelementtype": "1" } }, - "node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -47704,6 +47767,7 @@ "version": "6.7.1", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, "dependencies": { "ajv": "^8.0.1", "lodash.clonedeep": "^4.5.0", @@ -47720,6 +47784,7 @@ "version": "8.6.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -47735,6 +47800,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -47742,17 +47808,20 @@ "node_modules/table/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/table/node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -47760,12 +47829,14 @@ "node_modules/table/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true }, "node_modules/table/node_modules/string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -47779,6 +47850,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.0" }, @@ -48104,7 +48176,8 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "node_modules/thenify": { "version": "3.3.0", @@ -49169,7 +49242,8 @@ "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true }, "node_modules/v8-to-istanbul": { "version": "8.1.0", @@ -49307,18 +49381,6 @@ "node": ">=0.10.0" } }, - "node_modules/vue": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.1.5.tgz", - "integrity": "sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.1.5", - "@vue/runtime-dom": "3.1.5", - "@vue/shared": "3.1.5" - } - }, "node_modules/vue-docgen-api": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/vue-docgen-api/-/vue-docgen-api-4.40.0.tgz", @@ -50750,6 +50812,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -52543,11 +52606,11 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "requires": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" } }, "@babel/runtime-corejs3": { @@ -52634,8 +52697,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@egoist/vue-to-react/-/vue-to-react-1.2.0.tgz", "integrity": "sha512-uUtkzw+jtB1t++XjgwmzD/cgPVs7ZWyypw/IjciwZHNWODb/Ij19KJIkwxxKqokzopxmgbJKK4a5Zj9d9+WrPA==", - "dev": true, - "requires": {} + "dev": true }, "@emmetio/codemirror-plugin": { "version": "1.2.4", @@ -52900,6 +52962,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", @@ -52916,6 +52979,7 @@ "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, "requires": { "type-fest": "^0.20.2" } @@ -52923,12 +52987,14 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -52937,17 +53003,20 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, @@ -52961,6 +53030,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", @@ -52970,7 +53040,8 @@ "@humanwhocodes/object-schema": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true }, "@hypnosphi/create-react-context": { "version": "0.3.1", @@ -52997,8 +53068,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", - "dev": true, - "requires": {} + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -55190,8 +55260,7 @@ "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", - "dev": true, - "requires": {} + "dev": true }, "@mdx-js/util": { "version": "1.6.22", @@ -55358,29 +55427,15 @@ } }, "@redux-devtools/dock-monitor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/dock-monitor/-/dock-monitor-2.1.0.tgz", - "integrity": "sha512-DFVLgrFCjiuCGeHxZNaRUGVgACeZmkmm7I/grBU72Slx+KW7C5QCm0dS5UEZr3siTcRBLTDKhUzQLXkAT+6PJg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@redux-devtools/dock-monitor/-/dock-monitor-3.0.1.tgz", + "integrity": "sha512-ajIa3NRy89B7mw0/4SCNipXIV+B1eOqvprQXdGJPA66F6Gpzf3TKJ2Mupmj4yZNL1NL2GBIAbApNnWE9u+DU5w==", "requires": { - "@babel/runtime": "^7.16.7", - "@types/prop-types": "^15.7.4", + "@babel/runtime": "^7.18.3", + "@types/prop-types": "^15.7.5", "parse-key": "^0.2.1", "prop-types": "^15.8.1", - "react-dock": "^0.5.1" - }, - "dependencies": { - "react-dock": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.5.1.tgz", - "integrity": "sha512-mRY6xQDreHlUQPPgx1PHICUMQpY0Ywo8idS9rDdWhN+1ERWgl85w6en9ad017ERbaodP50f9D9CHg5DrRU9bhg==", - "requires": { - "@babel/runtime": "^7.16.7", - "@types/lodash": "^4.14.178", - "@types/prop-types": "^15.7.4", - "lodash.debounce": "^4.0.8", - "prop-types": "^15.8.1" - } - } + "react-dock": "^0.6.0" } }, "@redux-devtools/instrument": { @@ -55393,49 +55448,40 @@ } }, "@redux-devtools/log-monitor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/log-monitor/-/log-monitor-3.1.0.tgz", - "integrity": "sha512-T5NXzasj7250tJmQPiXzFkxlY0Rg0W7feR1eZj8VrdePvVkeXTP5k9VjxkVqtba5EmZR8swGec+Z1eD71ZgUsA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@redux-devtools/log-monitor/-/log-monitor-4.0.2.tgz", + "integrity": "sha512-BaTAwadm/XzRfnN2+8t4mwdbOILWfwsvMfVPn5OuE+NFaUG9pDKGoHRPCdMBaRdggDqqb5nlMgRCVdHzYftgVw==", "requires": { - "@babel/runtime": "^7.16.7", - "@types/lodash.debounce": "^4.0.6", - "@types/prop-types": "^15.7.4", + "@babel/runtime": "^7.20.6", + "@types/lodash.debounce": "^4.0.7", + "@types/prop-types": "^15.7.5", "@types/redux-devtools-themes": "^1.0.0", "lodash.debounce": "^4.0.8", "prop-types": "^15.8.1", - "react-json-tree": "^0.16.1", + "react-json-tree": "^0.18.0", "redux-devtools-themes": "^1.0.0" + } + }, + "@reduxjs/toolkit": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", + "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", + "requires": { + "immer": "^9.0.16", + "redux": "^4.2.0", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.7" }, "dependencies": { - "csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + "immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==" }, - "react-base16-styling": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz", - "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", - "requires": { - "@babel/runtime": "^7.16.7", - "@types/base16": "^1.0.2", - "@types/lodash": "^4.14.178", - "base16": "^1.0.0", - "color": "^3.2.1", - "csstype": "^3.0.10", - "lodash.curry": "^4.1.1" - } - }, - "react-json-tree": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.16.2.tgz", - "integrity": "sha512-80F7ZTqeOl1YaS/sDce4tYBcSe69/d0mlUmcIhyXezPFctWrtvyN56EMExX9jWsq3XMdvsUKKPUeNo8QCBy2jg==", - "requires": { - "@babel/runtime": "^7.17.8", - "@types/prop-types": "^15.7.4", - "prop-types": "^15.8.1", - "react-base16-styling": "^0.9.1" - } + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==" } } }, @@ -58267,57 +58313,49 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz", "integrity": "sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-remove-jsx-attribute": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.0.0.tgz", "integrity": "sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-remove-jsx-empty-expression": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.0.0.tgz", "integrity": "sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-replace-jsx-attribute-value": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.0.0.tgz", "integrity": "sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-svg-dynamic-title": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.0.0.tgz", "integrity": "sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-svg-em-dimensions": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.0.0.tgz", "integrity": "sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-transform-react-native-svg": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.0.0.tgz", "integrity": "sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-plugin-transform-svg-component": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.2.0.tgz", "integrity": "sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg==", - "dev": true, - "requires": {} + "dev": true }, "@svgr/babel-preset": { "version": "6.2.0", @@ -59034,14 +59072,14 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "@types/lodash": { - "version": "4.14.181", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.181.tgz", - "integrity": "sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==" + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==" }, "@types/lodash.debounce": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", - "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz", + "integrity": "sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==", "requires": { "@types/lodash": "*" } @@ -59125,9 +59163,9 @@ "dev": true }, "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/q": { "version": "1.5.2", @@ -59180,16 +59218,6 @@ "@types/react": "*", "hoist-non-react-statics": "^3.3.0", "redux": "^4.0.0" - }, - "dependencies": { - "redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "requires": { - "@babel/runtime": "^7.9.2" - } - } } }, "@types/react-syntax-highlighter": { @@ -59481,39 +59509,6 @@ "@vue/shared": "3.1.5" } }, - "@vue/reactivity": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", - "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", - "dev": true, - "peer": true, - "requires": { - "@vue/shared": "3.1.5" - } - }, - "@vue/runtime-core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.5.tgz", - "integrity": "sha512-YQbG5cBktN1RowQDKA22itmvQ+b40f0WgQ6CXK4VYoYICAiAfu6Cc14777ve8zp1rJRGtk5oIeS149TOculrTg==", - "dev": true, - "peer": true, - "requires": { - "@vue/reactivity": "3.1.5", - "@vue/shared": "3.1.5" - } - }, - "@vue/runtime-dom": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.5.tgz", - "integrity": "sha512-tNcf3JhVR0RfW0kw1p8xZgv30nvX8Y9rsz7eiQ0dHe273sfoCngAG0y4GvMaY4Xd8FsjUwFedd4suQ8Lu8meXg==", - "dev": true, - "peer": true, - "requires": { - "@vue/runtime-core": "3.1.5", - "@vue/shared": "3.1.5", - "csstype": "^2.6.8" - } - }, "@vue/shared": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", @@ -59773,8 +59768,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "requires": {} + "dev": true }, "@webpack-cli/info": { "version": "1.4.1", @@ -59789,8 +59783,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "requires": {} + "dev": true }, "@xmldom/xmldom": { "version": "0.7.5", @@ -59860,7 +59853,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -59949,8 +59942,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true, - "requires": {} + "dev": true }, "ajv-formats": { "version": "2.1.1", @@ -59986,8 +59978,7 @@ "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" }, "ansi-align": { "version": "3.0.0", @@ -60117,6 +60108,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -60531,7 +60523,8 @@ "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true }, "async": { "version": "3.2.3", @@ -60737,8 +60730,7 @@ "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true, - "requires": {} + "dev": true }, "babel-helper-evaluate-path": { "version": "0.5.0", @@ -61458,8 +61450,7 @@ "version": "0.3.7", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==", - "dev": true, - "requires": {} + "dev": true }, "babel-plugin-polyfill-corejs2": { "version": "0.3.1", @@ -62986,8 +62977,7 @@ "codemirror-colorpicker": { "version": "1.9.80", "resolved": "https://registry.npmjs.org/codemirror-colorpicker/-/codemirror-colorpicker-1.9.80.tgz", - "integrity": "sha512-7lGqNxf5haBJXLnVR1ynPiPkN2d1Whm0jdy8Z9QsSOhRWVyK2C2ihgm1dX4DCks57ht/jKMdpL9lYv+zAphxWQ==", - "requires": {} + "integrity": "sha512-7lGqNxf5haBJXLnVR1ynPiPkN2d1Whm0jdy8Z9QsSOhRWVyK2C2ihgm1dX4DCks57ht/jKMdpL9lYv+zAphxWQ==" }, "collapse-white-space": { "version": "1.0.6", @@ -63033,9 +63023,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -64585,8 +64575,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz", "integrity": "sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg==", - "dev": true, - "requires": {} + "dev": true }, "css-select": { "version": "4.3.0", @@ -64787,29 +64776,25 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz", "integrity": "sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-duplicates": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-empty": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-overridden": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-merge-longhand": { "version": "5.1.4", @@ -64877,8 +64862,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "dev": true, - "requires": {} + "dev": true }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -65174,8 +65158,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", - "dev": true, - "requires": {} + "dev": true }, "csso": { "version": "4.2.0", @@ -65638,6 +65621,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, "requires": { "esutils": "^2.0.2" } @@ -66006,6 +65990,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, "requires": { "ansi-colors": "^4.1.1" }, @@ -66013,7 +65998,8 @@ "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true } } }, @@ -66192,6 +66178,7 @@ "version": "7.31.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, "requires": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -66239,6 +66226,7 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -66246,12 +66234,14 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -66261,6 +66251,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -66269,6 +66260,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -66279,6 +66271,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -66286,12 +66279,14 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -66301,22 +66296,26 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true }, "eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -66325,6 +66324,7 @@ "version": "13.10.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, "requires": { "type-fest": "^0.20.2" } @@ -66332,17 +66332,20 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -66351,12 +66354,14 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -66365,6 +66370,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "requires": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -66374,6 +66380,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -66382,6 +66389,7 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, "requires": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -66394,22 +66402,26 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -66418,6 +66430,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -66425,12 +66438,14 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -66438,12 +66453,14 @@ "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "requires": { "prelude-ls": "^1.2.1" } @@ -66451,12 +66468,14 @@ "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -66464,7 +66483,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -66490,8 +66510,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.4", @@ -66915,6 +66934,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" }, @@ -66922,7 +66942,8 @@ "eslint-visitor-keys": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true } } }, @@ -67020,6 +67041,7 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, "requires": { "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", @@ -67029,12 +67051,14 @@ "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true }, "eslint-visitor-keys": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true } } }, @@ -67047,6 +67071,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, "requires": { "estraverse": "^5.1.0" }, @@ -67054,7 +67079,8 @@ "estraverse": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true } } }, @@ -68024,6 +68050,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, "requires": { "flat-cache": "^3.0.4" } @@ -68206,6 +68233,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -68215,6 +68243,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -68224,7 +68253,8 @@ "flatted": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", - "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==" + "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", + "dev": true }, "flatten": { "version": "1.0.2", @@ -69390,7 +69420,8 @@ "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true }, "functions-have-names": { "version": "1.2.2", @@ -70662,8 +70693,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} + "dev": true }, "ieee754": { "version": "1.1.13", @@ -70817,7 +70847,8 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indent-string": { "version": "4.0.0", @@ -74625,8 +74656,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "24.9.0", @@ -77006,6 +77036,7 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -77474,8 +77505,7 @@ "ws": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "requires": {} + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==" } } }, @@ -77573,7 +77603,8 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", @@ -78188,7 +78219,8 @@ "lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true }, "lodash._reinterpolate": { "version": "3.0.0", @@ -78215,12 +78247,13 @@ "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true }, "lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" }, "lodash.debounce": { "version": "4.0.8", @@ -78328,7 +78361,8 @@ "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true }, "lodash.unescape": { "version": "4.0.1", @@ -80196,8 +80230,7 @@ "mockingoose": { "version": "2.15.2", "resolved": "https://registry.npmjs.org/mockingoose/-/mockingoose-2.15.2.tgz", - "integrity": "sha512-50mtbAk29Go5hdhzqTmjmE67Z/cB0yPz45u2jrHoGm4nkYnnBq224viWgyKwnxzWw8birnqn98viM2cRBTnJvw==", - "requires": {} + "integrity": "sha512-50mtbAk29Go5hdhzqTmjmE67Z/cB0yPz45u2jrHoGm4nkYnnBq224viWgyKwnxzWw8birnqn98viM2cRBTnJvw==" }, "mongodb": { "version": "2.2.36", @@ -80320,8 +80353,7 @@ "mongoose-legacy-pluralize": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==", - "requires": {} + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" }, "move-concurrently": { "version": "1.0.1", @@ -80797,7 +80829,8 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true }, "negotiator": { "version": "0.6.2", @@ -82880,8 +82913,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-focus/-/postcss-focus-5.0.1.tgz", "integrity": "sha512-iVP+4VLenlI0tHHJD+7HyE+7pQ6Hlg3+Zm/xTwNE1LT7OgmYC4r1ale6AnEkABGNKKE3j1LkF/BNcv89lDoICw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-focus-visible": { "version": "4.0.0", @@ -83244,8 +83276,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -83880,7 +83911,8 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, "promise": { "version": "7.3.1", @@ -84483,6 +84515,27 @@ "prop-types": "^15.6.2" } }, + "react-base16-styling": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz", + "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", + "requires": { + "@babel/runtime": "^7.16.7", + "@types/base16": "^1.0.2", + "@types/lodash": "^4.14.178", + "base16": "^1.0.0", + "color": "^3.2.1", + "csstype": "^3.0.10", + "lodash.curry": "^4.1.1" + }, + "dependencies": { + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + } + } + }, "react-clientside-effect": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz", @@ -84734,6 +84787,18 @@ } } }, + "react-dock": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.6.0.tgz", + "integrity": "sha512-jEOhv1s+pqRQ4JxgUw4XUotnprOehZ23mqchf3whxYXnvNgTQOXCxh6bpcqW8P6OybIk2bYO18r3qimZ3ypCbg==", + "requires": { + "@babel/runtime": "^7.18.3", + "@types/lodash": "^4.14.182", + "@types/prop-types": "^15.7.5", + "lodash.debounce": "^4.0.8", + "prop-types": "^15.8.1" + } + }, "react-dom": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", @@ -84820,8 +84885,7 @@ "react-ga": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz", - "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==", - "requires": {} + "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==" }, "react-helmet": { "version": "5.2.1", @@ -84919,6 +84983,16 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-json-tree": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.18.0.tgz", + "integrity": "sha512-Qe6HKSXrr++n9Y31nkRJ3XvQMATISpqigH1vEKhLwB56+nk5thTP0ITThpjxY6ZG/ubpVq/aEHIcyLP/OPHxeA==", + "requires": { + "@babel/runtime": "^7.20.6", + "@types/lodash": "^4.14.191", + "react-base16-styling": "^0.9.1" + } + }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -85542,14 +85616,11 @@ } }, "redux": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "requires": { - "lodash": "^4.2.1", - "lodash-es": "^4.2.1", - "loose-envify": "^1.1.0", - "symbol-observable": "^1.0.3" + "@babel/runtime": "^7.9.2" } }, "redux-auth-wrapper": { @@ -85648,9 +85719,9 @@ } }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { "version": "0.15.0", @@ -85696,7 +85767,8 @@ "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true }, "regexpu-core": { "version": "5.0.1", @@ -86145,9 +86217,9 @@ "dev": true }, "reselect": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", - "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" }, "resize-observer-polyfill": { "version": "1.5.1", @@ -87073,7 +87145,7 @@ "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "requires": { "is-arrayish": "^0.3.1" }, @@ -87126,8 +87198,7 @@ "sinon-mongoose": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/sinon-mongoose/-/sinon-mongoose-2.3.0.tgz", - "integrity": "sha512-d0rrL53wuDDs91GMCFAvQam64IpdVfkaxA4cGLTZfw1d5tTg6+F/D7F080d1n3d1gSHJBZLUf9pGpijC/x7xKQ==", - "requires": {} + "integrity": "sha512-d0rrL53wuDDs91GMCFAvQam64IpdVfkaxA4cGLTZfw1d5tTg6+F/D7F080d1n3d1gSHJBZLUf9pGpijC/x7xKQ==" }, "sisteransi": { "version": "1.0.5", @@ -87145,6 +87216,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, "requires": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -87155,6 +87227,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -87163,6 +87236,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -87170,12 +87244,14 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true } } }, @@ -87491,7 +87567,8 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "sshpk": { "version": "1.16.1", @@ -88041,8 +88118,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "requires": {} + "dev": true }, "style-to-object": { "version": "0.3.0", @@ -88191,11 +88267,6 @@ } } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -88281,6 +88352,7 @@ "version": "6.7.1", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, "requires": { "ajv": "^8.0.1", "lodash.clonedeep": "^4.5.0", @@ -88294,6 +88366,7 @@ "version": "8.6.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -88304,32 +88377,38 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true }, "string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -88340,6 +88419,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -88570,7 +88650,8 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "thenify": { "version": "3.3.0", @@ -89332,8 +89413,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz", "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==", - "dev": true, - "requires": {} + "dev": true }, "use-sidecar": { "version": "1.0.5", @@ -89388,7 +89468,8 @@ "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true }, "v8-to-istanbul": { "version": "8.1.0", @@ -89483,18 +89564,6 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" }, - "vue": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.1.5.tgz", - "integrity": "sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==", - "dev": true, - "peer": true, - "requires": { - "@vue/compiler-dom": "3.1.5", - "@vue/runtime-dom": "3.1.5", - "@vue/shared": "3.1.5" - } - }, "vue-docgen-api": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/vue-docgen-api/-/vue-docgen-api-4.40.0.tgz", @@ -90118,8 +90187,7 @@ "acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "requires": {} + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" }, "glob-to-regexp": { "version": "0.4.1", @@ -90638,7 +90706,8 @@ "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true }, "wordwrap": { "version": "1.0.0", @@ -90758,8 +90827,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true, - "requires": {} + "dev": true }, "xdg-basedir": { "version": "4.0.0", diff --git a/package.json b/package.json index 90c91f5d12..3448f48bab 100644 --- a/package.json +++ b/package.json @@ -148,8 +148,9 @@ "@babel/register": "^7.14.5", "@emmetio/codemirror-plugin": "^1.2.4", "@redux-devtools/core": "^3.11.0", - "@redux-devtools/dock-monitor": "^2.1.0", - "@redux-devtools/log-monitor": "^3.1.0", + "@redux-devtools/dock-monitor": "^3.0.1", + "@redux-devtools/log-monitor": "^4.0.2", + "@reduxjs/toolkit": "^1.9.3", "async": "^3.2.3", "axios": "^0.21.2", "babel-plugin-styled-components": "^1.13.2", @@ -222,12 +223,11 @@ "react-split-pane": "^0.1.92", "react-tabs": "^2.3.1", "react-transition-group": "^4.4.2", - "redux": "^3.7.2", + "redux": "^4.2.1", "redux-auth-wrapper": "^2.1.0", "redux-thunk": "^2.3.0", "regenerator-runtime": "^0.13.9", "remark-slug": "^6.1.0", - "reselect": "^4.0.0", "s3-policy-v4": "0.0.3", "shortid": "^2.2.16", "sinon": "^7.5.0", From 81f11bcc46c22819aa7e8d7be9f60ca7228f000f Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sat, 6 May 2023 21:17:30 -0500 Subject: [PATCH 002/118] Update `createSelector` import. --- client/modules/IDE/selectors/project.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/modules/IDE/selectors/project.js b/client/modules/IDE/selectors/project.js index 26197f3b00..cdf7d61826 100644 --- a/client/modules/IDE/selectors/project.js +++ b/client/modules/IDE/selectors/project.js @@ -1,4 +1,4 @@ -import { createSelector } from 'reselect'; +import { createSelector } from '@reduxjs/toolkit'; export const selectProjectOwner = (state) => state.project.owner; export const selectProjectId = (state) => state.project.id; From 1601e0ff0eab97d30b0da273e2689aa944471447 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Mon, 12 Jun 2023 18:23:18 -0500 Subject: [PATCH 003/118] Adjust the `totalSize` when deleting an asset. --- client/constants.js | 2 -- client/modules/IDE/actions/assets.js | 23 +++++++------------- client/modules/IDE/reducers/assets.js | 31 ++++++++++++++++----------- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/client/constants.js b/client/constants.js index 2678e6950b..fc7ba88914 100644 --- a/client/constants.js +++ b/client/constants.js @@ -131,8 +131,6 @@ export const CLEAR_PERSISTED_STATE = 'CLEAR_PERSISTED_STATE'; export const HIDE_RUNTIME_ERROR_WARNING = 'HIDE_RUNTIME_ERROR_WARNING'; export const SHOW_RUNTIME_ERROR_WARNING = 'SHOW_RUNTIME_ERROR_WARNING'; -export const SET_ASSETS = 'SET_ASSETS'; -export const DELETE_ASSET = 'DELETE_ASSET'; export const TOGGLE_DIRECTION = 'TOGGLE_DIRECTION'; export const SET_SORTING = 'SET_SORTING'; diff --git a/client/modules/IDE/actions/assets.js b/client/modules/IDE/actions/assets.js index 8c7a046121..abeeb22321 100644 --- a/client/modules/IDE/actions/assets.js +++ b/client/modules/IDE/actions/assets.js @@ -1,14 +1,9 @@ import apiClient from '../../../utils/apiClient'; import * as ActionTypes from '../../../constants'; import { startLoader, stopLoader } from './loader'; +import { assetsActions } from '../reducers/assets'; -function setAssets(assets, totalSize) { - return { - type: ActionTypes.SET_ASSETS, - assets, - totalSize - }; -} +const { setAssets, deleteAsset } = assetsActions; export function getAssets() { return (dispatch) => { @@ -16,7 +11,12 @@ export function getAssets() { apiClient .get('/S3/objects') .then((response) => { - dispatch(setAssets(response.data.assets, response.data.totalSize)); + dispatch( + setAssets({ + list: response.data.assets, + totalSize: response.data.totalSize + }) + ); dispatch(stopLoader()); }) .catch(() => { @@ -28,13 +28,6 @@ export function getAssets() { }; } -export function deleteAsset(assetKey) { - return { - type: ActionTypes.DELETE_ASSET, - key: assetKey - }; -} - export function deleteAssetRequest(assetKey) { return (dispatch) => { apiClient diff --git a/client/modules/IDE/reducers/assets.js b/client/modules/IDE/reducers/assets.js index f1dd0f40cb..e2fb58f625 100644 --- a/client/modules/IDE/reducers/assets.js +++ b/client/modules/IDE/reducers/assets.js @@ -1,20 +1,27 @@ -import * as ActionTypes from '../../../constants'; +import { createSlice } from '@reduxjs/toolkit'; -// 1,000,000 bytes in a MB. can't upload if totalSize is bigger than this. const initialState = { list: [], totalSize: 0 }; -const assets = (state = initialState, action) => { - switch (action.type) { - case ActionTypes.SET_ASSETS: - return { list: action.assets, totalSize: action.totalSize }; - case ActionTypes.DELETE_ASSET: - return { list: state.list.filter((asset) => asset.key !== action.key) }; - default: - return state; +const assetsSlice = createSlice({ + name: 'assets', + initialState, + reducers: { + setAssets: (state, action) => action.payload, + deleteAsset: (state, action) => { + const key = action.payload; + const index = state.list.findIndex((asset) => asset.key === key); + if (index !== -1) { + const asset = state.list[index]; + state.totalSize -= asset.size; + state.list.splice(index, 1); + } + } } -}; +}); + +export const assetsActions = assetsSlice.actions; -export default assets; +export default assetsSlice.reducer; From 8f9ddb5f621019db3e41eef9490f96f0318a85d9 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 25 Jun 2023 14:11:20 -0500 Subject: [PATCH 004/118] Support dynamic paths in `loadImage`. --- client/modules/Preview/EmbedFrame.jsx | 8 +++++++ client/utils/previewEntry.js | 32 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/client/modules/Preview/EmbedFrame.jsx b/client/modules/Preview/EmbedFrame.jsx index 43f229fa2d..fbd4847082 100644 --- a/client/modules/Preview/EmbedFrame.jsx +++ b/client/modules/Preview/EmbedFrame.jsx @@ -254,6 +254,14 @@ function injectLocalFiles(files, htmlFile, options) { previewScripts.setAttribute('crossorigin', ''); sketchDoc.head.appendChild(previewScripts); + const fileData = sketchDoc.createElement('script'); + fileData.innerHTML = ` + window.files = ${JSON.stringify( + files.filter((file) => file.url || file.fileType === 'folder') + )}; + `; + sketchDoc.head.prepend(fileData); + const sketchDocString = `\n${sketchDoc.documentElement.outerHTML}`; scriptOffs = getAllScriptOffsets(sketchDocString); const consoleErrorsScript = sketchDoc.createElement('script'); diff --git a/client/utils/previewEntry.js b/client/utils/previewEntry.js index 2dfa2a239b..c19226bf26 100644 --- a/client/utils/previewEntry.js +++ b/client/utils/previewEntry.js @@ -1,6 +1,8 @@ import loopProtect from 'loop-protect'; import { Hook, Decode, Encode } from 'console-feed'; import StackTrace from 'stacktrace-js'; +import { resolvePathToFile } from '../../server/utils/filePath'; +import { EXTERNAL_LINK_REGEX } from '../../server/utils/fileUtils'; import evaluateExpression from './evaluateExpression'; // should postMessage user the dispatcher? does the parent window need to @@ -178,3 +180,33 @@ if (_report) { _report.apply(window.p5, [newMessage, method, color]); }; } + +const __patchedMethods = {}; + +function applyPatching(methodName) { + __patchedMethods[methodName] = window.p5.prototype[methodName]; + if (__patchedMethods[methodName]) { + window.p5.prototype[methodName] = function patched(path, ...args) { + let resolvedPath = path; + if (!EXTERNAL_LINK_REGEX.test(path)) { + const file = resolvePathToFile(path, window.files); + if (file && file.url) { + resolvedPath = file.url; + } + } + return __patchedMethods[methodName].apply(this, [resolvedPath, ...args]); + }; + } +} + +[ + 'loadImage', + 'loadModel', + 'loadJSON', + 'loadStrings', + 'loadTable', + 'loadXML', + 'loadBytes', + 'loadFont', + 'loadShader' +].forEach(applyPatching); From b3750e4fe35b74d4cb56aaccaba95d1d63b7c0c1 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 16 Jul 2023 15:58:12 -0500 Subject: [PATCH 005/118] Convert App to a function component. --- client/modules/App/App.jsx | 98 ++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/client/modules/App/App.jsx b/client/modules/App/App.jsx index 1f41446a79..a2b4d1e7ad 100644 --- a/client/modules/App/App.jsx +++ b/client/modules/App/App.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; -import React from 'react'; -import { connect } from 'react-redux'; +import React, { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import getConfig from '../../utils/getConfig'; import DevTools from './components/DevTools'; import { setPreviousPath } from '../IDE/actions/ide'; @@ -14,51 +14,50 @@ function hideCookieConsent(pathname) { return false; } -class App extends React.Component { - constructor(props, context) { - super(props, context); - this.state = { isMounted: false }; - } +// TODO: get location from `useLocation` after upgrading react-router to v5. +const App = ({ children, location }) => { + const dispatch = useDispatch(); - componentDidMount() { - this.setState({ isMounted: true }); // eslint-disable-line react/no-did-mount-set-state - document.body.className = this.props.theme; - } + const theme = useSelector((state) => state.preferences.theme); + useEffect(() => { + document.body.className = theme; + }, [theme]); - componentWillReceiveProps(nextProps) { - const locationWillChange = nextProps.location !== this.props.location; - const shouldSkipRemembering = - nextProps.location.state && - nextProps.location.state.skipSavingPath === true; + // TODO: this is only needed for the initial load and would be better handled elsewhere - Linda + const language = useSelector((state) => state.preferences.language); + useEffect(() => { + dispatch(setLanguage(language, { persistPreference: false })); + }, [language]); - if (locationWillChange && !shouldSkipRemembering) { - this.props.setPreviousPath(this.props.location.pathname); - } + // TODO: do we actually need this? - Linda + const [isMounted, setIsMounted] = useState(false); + useEffect(() => setIsMounted(true), []); - if (this.props.language !== nextProps.language) { - this.props.setLanguage(nextProps.language, { persistPreference: false }); - } - } + const previousLocationRef = useRef(location); + useEffect(() => { + const prevLocation = previousLocationRef.current; + const locationChanged = + prevLocation && prevLocation.pathname !== location.pathname; + const shouldSkipRemembering = location.state?.skipSavingPath === true; - componentDidUpdate(prevProps) { - if (this.props.theme !== prevProps.theme) { - document.body.className = this.props.theme; + if (locationChanged && !shouldSkipRemembering) { + dispatch(setPreviousPath(location.pathname)); } - } + previousLocationRef.current = location; + }, [location]); - render() { - const hide = hideCookieConsent(this.props.location.pathname); - return ( -
- - {this.state.isMounted && - !window.devToolsExtension && - getConfig('NODE_ENV') === 'development' && } - {this.props.children} -
- ); - } -} + const hide = hideCookieConsent(location.pathname); + + return ( +
+ + {isMounted && + !window.devToolsExtension && + getConfig('NODE_ENV') === 'development' && } + {children} +
+ ); +}; App.propTypes = { children: PropTypes.element, @@ -67,24 +66,11 @@ App.propTypes = { state: PropTypes.shape({ skipSavingPath: PropTypes.bool }) - }).isRequired, - setPreviousPath: PropTypes.func.isRequired, - setLanguage: PropTypes.func.isRequired, - language: PropTypes.string, - theme: PropTypes.string + }).isRequired }; App.defaultProps = { - children: null, - language: null, - theme: 'light' + children: null }; -const mapStateToProps = (state) => ({ - theme: state.preferences.theme, - language: state.preferences.language -}); - -const mapDispatchToProps = { setPreviousPath, setLanguage }; - -export default connect(mapStateToProps, mapDispatchToProps)(App); +export default App; From 5618c283ac2f7c039798b4e672af5ed01d7e85d8 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 16 Jul 2023 17:52:39 -0500 Subject: [PATCH 006/118] Fix previousPath handling. --- client/modules/App/App.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/modules/App/App.jsx b/client/modules/App/App.jsx index a2b4d1e7ad..777ce061ce 100644 --- a/client/modules/App/App.jsx +++ b/client/modules/App/App.jsx @@ -36,12 +36,11 @@ const App = ({ children, location }) => { const previousLocationRef = useRef(location); useEffect(() => { const prevLocation = previousLocationRef.current; - const locationChanged = - prevLocation && prevLocation.pathname !== location.pathname; + const locationChanged = prevLocation && prevLocation !== location; const shouldSkipRemembering = location.state?.skipSavingPath === true; if (locationChanged && !shouldSkipRemembering) { - dispatch(setPreviousPath(location.pathname)); + dispatch(setPreviousPath(prevLocation.pathname)); } previousLocationRef.current = location; }, [location]); From 9da55356bb0fbabd1e20b65b98ccd53a28c464d8 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 16 Jul 2023 18:18:02 -0500 Subject: [PATCH 007/118] Extract common logic from modal component. --- client/common/useModalClose.js | 50 +++++++++++++++++++++++++ client/components/Nav/NavBar.jsx | 42 +++------------------ client/modules/IDE/components/Modal.jsx | 21 ++--------- client/modules/IDE/pages/IDEView.jsx | 10 ----- 4 files changed, 59 insertions(+), 64 deletions(-) create mode 100644 client/common/useModalClose.js diff --git a/client/common/useModalClose.js b/client/common/useModalClose.js new file mode 100644 index 0000000000..b0d36e89ff --- /dev/null +++ b/client/common/useModalClose.js @@ -0,0 +1,50 @@ +import { useEffect, useRef } from 'react'; + +/** + * Common logic for Modal, Overlay, etc. + * + * Pass in the `onClose` handler. + * + * Can optionally pass in a ref, in case the `onClose` function needs to use the ref. + * + * Calls the provided `onClose` function on: + * - Press Escape key. + * - Click outside the element. + * + * Returns a ref to attach to the outermost element of the modal. + * + * @param {() => void} onClose + * @param {React.MutableRefObject} [passedRef] + * @return {React.MutableRefObject} + */ +export default function useModalClose(onClose, passedRef) { + const createdRef = useRef(null); + const modalRef = passedRef || createdRef; + + useEffect(() => { + modalRef.current?.focus(); + + function handleKeyDown(e) { + if (e.key === 'Escape') { + onClose?.(); + } + } + + function handleClick(e) { + // ignore clicks on the component itself + if (modalRef.current && !modalRef.current.contains(e.target)) { + onClose?.(); + } + } + + document.addEventListener('mousedown', handleClick, false); + document.addEventListener('keydown', handleKeyDown, false); + + return () => { + document.removeEventListener('mousedown', handleClick, false); + document.removeEventListener('keydown', handleKeyDown, false); + }; + }, [onClose, modalRef]); + + return modalRef; +} diff --git a/client/components/Nav/NavBar.jsx b/client/components/Nav/NavBar.jsx index d5e33ada23..8452138044 100644 --- a/client/components/Nav/NavBar.jsx +++ b/client/components/Nav/NavBar.jsx @@ -1,11 +1,6 @@ import PropTypes from 'prop-types'; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState -} from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; +import useModalClose from '../../common/useModalClose'; import { MenuOpenContext, NavBarContext } from './contexts'; function NavBar({ children }) { @@ -13,37 +8,12 @@ function NavBar({ children }) { const timerRef = useRef(null); - const nodeRef = useRef(null); - - useEffect(() => { - function handleClick(e) { - if (!nodeRef.current) { - return; - } - if (nodeRef.current.contains(e.target)) { - return; - } - setDropdownOpen('none'); - } - document.addEventListener('mousedown', handleClick, false); - return () => { - document.removeEventListener('mousedown', handleClick, false); - }; - }, [nodeRef, setDropdownOpen]); - - // TODO: replace with `useKeyDownHandlers` after #2052 is merged - useEffect(() => { - function handleKeyDown(e) { - if (e.keyCode === 27) { - setDropdownOpen('none'); - } - } - document.addEventListener('keydown', handleKeyDown, false); - return () => { - document.removeEventListener('keydown', handleKeyDown, false); - }; + const handleClose = useCallback(() => { + setDropdownOpen('none'); }, [setDropdownOpen]); + const nodeRef = useModalClose(handleClose); + const clearHideTimeout = useCallback(() => { if (timerRef.current) { clearTimeout(timerRef.current); diff --git a/client/modules/IDE/components/Modal.jsx b/client/modules/IDE/components/Modal.jsx index 5d1bbc88e0..831527b266 100644 --- a/client/modules/IDE/components/Modal.jsx +++ b/client/modules/IDE/components/Modal.jsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; -import React, { useEffect, useRef } from 'react'; +import React from 'react'; +import useModalClose from '../../../common/useModalClose'; import ExitIcon from '../../../images/exit.svg'; // Common logic from NewFolderModal, NewFileModal, UploadFileModal @@ -12,23 +13,7 @@ const Modal = ({ contentClassName, children }) => { - const modalRef = useRef(null); - - const handleOutsideClick = (e) => { - // ignore clicks on the component itself - if (modalRef.current?.contains?.(e.target)) return; - - onClose(); - }; - - useEffect(() => { - modalRef.current?.focus(); - document.addEventListener('click', handleOutsideClick, false); - - return () => { - document.removeEventListener('click', handleOutsideClick, false); - }; - }, []); + const modalRef = useModalClose(onClose); return (
diff --git a/client/modules/IDE/pages/IDEView.jsx b/client/modules/IDE/pages/IDEView.jsx index 5158e33c44..d10a7f24f6 100644 --- a/client/modules/IDE/pages/IDEView.jsx +++ b/client/modules/IDE/pages/IDEView.jsx @@ -220,14 +220,6 @@ class IDEView extends React.Component { } else { this.props.expandConsole(); } - } else if (e.keyCode === 27) { - if (this.props.ide.newFolderModalVisible) { - this.props.closeNewFolderModal(); - } else if (this.props.ide.uploadFileModalVisible) { - this.props.closeUploadFileModal(); - } else if (this.props.ide.modalIsVisible) { - this.props.closeNewFileModal(); - } } } @@ -556,8 +548,6 @@ IDEView.propTypes = { openProjectOptions: PropTypes.func.isRequired, closeProjectOptions: PropTypes.func.isRequired, newFolder: PropTypes.func.isRequired, - closeNewFolderModal: PropTypes.func.isRequired, - closeNewFileModal: PropTypes.func.isRequired, closeShareModal: PropTypes.func.isRequired, closeKeyboardShortcutModal: PropTypes.func.isRequired, autosaveProject: PropTypes.func.isRequired, From 0854d43a36e43e8170d837a8021dfa1fb78968c3 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 16 Jul 2023 18:19:47 -0500 Subject: [PATCH 008/118] Convert `Overlay` to a function component. --- client/modules/App/components/Overlay.jsx | 143 +++++++++------------- 1 file changed, 56 insertions(+), 87 deletions(-) diff --git a/client/modules/App/components/Overlay.jsx b/client/modules/App/components/Overlay.jsx index 39f492fc6f..6759beb5ab 100644 --- a/client/modules/App/components/Overlay.jsx +++ b/client/modules/App/components/Overlay.jsx @@ -1,101 +1,73 @@ import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useCallback, useRef } from 'react'; +import { useSelector } from 'react-redux'; import { browserHistory } from 'react-router'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; +import useModalClose from '../../../common/useModalClose'; import ExitIcon from '../../../images/exit.svg'; -class Overlay extends React.Component { - constructor(props) { - super(props); - this.close = this.close.bind(this); - this.handleClick = this.handleClick.bind(this); - this.handleClickOutside = this.handleClickOutside.bind(this); - this.keyPressHandle = this.keyPressHandle.bind(this); - } +const Overlay = ({ + actions, + ariaLabel, + children, + closeOverlay, + isFixedHeight, + title +}) => { + const { t } = useTranslation(); - componentWillMount() { - document.addEventListener('mousedown', this.handleClick, false); - document.addEventListener('keydown', this.keyPressHandle); - } + const previousPath = useSelector((state) => state.ide.previousPath); - componentDidMount() { - this.node.focus(); - } + const ref = useRef(null); - componentWillUnmount() { - document.removeEventListener('mousedown', this.handleClick, false); - document.removeEventListener('keydown', this.keyPressHandle); - } - - handleClick(e) { - if (this.node.contains(e.target)) { - return; - } - - this.handleClickOutside(e); - } - - handleClickOutside() { - this.close(); - } - - keyPressHandle(e) { - // escape key code = 27. - // So here we are checking if the key pressed was Escape key. - if (e.keyCode === 27) { - this.close(); - } - } - - close() { + const close = useCallback(() => { + const node = ref.current; + if (!node) return; // Only close if it is the last (and therefore the topmost overlay) const overlays = document.getElementsByClassName('overlay'); - if (this.node.parentElement.parentElement !== overlays[overlays.length - 1]) + if (node.parentElement.parentElement !== overlays[overlays.length - 1]) return; - if (!this.props.closeOverlay) { - browserHistory.push(this.props.previousPath); + if (!closeOverlay) { + browserHistory.push(previousPath); } else { - this.props.closeOverlay(); + closeOverlay(); } - } + }, [previousPath, closeOverlay, ref]); - render() { - const { ariaLabel, title, children, actions, isFixedHeight } = this.props; - return ( -
-
-
{ - this.node = node; - }} - className="overlay__body" - > -
-

{title}

-
- {actions} - -
-
- {children} -
-
+ useModalClose(close, ref); + + return ( +
+
+
+
+

{title}

+
+ {actions} + +
+
+ {children} +
- ); - } -} +
+ ); +}; Overlay.propTypes = { children: PropTypes.element, @@ -103,9 +75,7 @@ Overlay.propTypes = { closeOverlay: PropTypes.func, title: PropTypes.string, ariaLabel: PropTypes.string, - previousPath: PropTypes.string, - isFixedHeight: PropTypes.bool, - t: PropTypes.func.isRequired + isFixedHeight: PropTypes.bool }; Overlay.defaultProps = { @@ -114,8 +84,7 @@ Overlay.defaultProps = { title: 'Modal', closeOverlay: null, ariaLabel: 'modal', - previousPath: '/', isFixedHeight: false }; -export default withTranslation()(Overlay); +export default Overlay; From 65823629e1e1ea81c70b2e26ab728e4bf118a4a8 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 16 Jul 2023 18:32:59 -0500 Subject: [PATCH 009/118] Apply `useModalClose` to collection `ShareURL`. --- client/modules/User/components/Collection.jsx | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/client/modules/User/components/Collection.jsx b/client/modules/User/components/Collection.jsx index 563fd7d6ff..196489c3e8 100644 --- a/client/modules/User/components/Collection.jsx +++ b/client/modules/User/components/Collection.jsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, { useState, useRef, useEffect } from 'react'; +import React, { useState, useCallback } from 'react'; import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; import { Link } from 'react-router'; @@ -9,6 +9,7 @@ import classNames from 'classnames'; import Button from '../../../common/Button'; import { DropdownArrowIcon } from '../../../common/icons'; +import useModalClose from '../../../common/useModalClose'; import * as ProjectActions from '../../IDE/actions/project'; import * as ProjectsActions from '../../IDE/actions/projects'; import * as CollectionsActions from '../../IDE/actions/collections'; @@ -30,30 +31,12 @@ import RemoveIcon from '../../../images/close.svg'; const ShareURL = ({ value }) => { const [showURL, setShowURL] = useState(false); - const node = useRef(); const { t } = useTranslation(); - - const handleClickOutside = (e) => { - if (node.current.contains(e.target)) { - return; - } - setShowURL(false); - }; - - useEffect(() => { - if (showURL) { - document.addEventListener('mousedown', handleClickOutside); - } else { - document.removeEventListener('mousedown', handleClickOutside); - } - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [showURL]); + const close = useCallback(() => setShowURL(false), [setShowURL]); + const ref = useModalClose(close); return ( -
+
+ {isOpen && ( + + {children} + + )} +
+ ); + } +); + +DropdownMenu.propTypes = { + children: PropTypes.node, + 'aria-label': PropTypes.string.isRequired, + align: PropTypes.oneOf(['left', 'right']), + className: PropTypes.string, + classes: PropTypes.shape({ + button: PropTypes.string, + list: PropTypes.string + }) +}; + +DropdownMenu.defaultProps = { + children: null, + align: 'right', + className: '', + classes: {} +}; + +export default DropdownMenu; diff --git a/client/components/Dropdown/MenuItem.jsx b/client/components/Dropdown/MenuItem.jsx new file mode 100644 index 0000000000..8b6f6d7247 --- /dev/null +++ b/client/components/Dropdown/MenuItem.jsx @@ -0,0 +1,35 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ButtonOrLink from '../../common/ButtonOrLink'; + +// TODO: combine with NavMenuItem + +function MenuItem({ hideIf, ...rest }) { + if (hideIf) { + return null; + } + + return ( +
  • + +
  • + ); +} + +MenuItem.propTypes = { + ...ButtonOrLink.propTypes, + onClick: PropTypes.func, + value: PropTypes.string, + /** + * Provides a way to deal with optional items. + */ + hideIf: PropTypes.bool +}; + +MenuItem.defaultProps = { + onClick: null, + value: null, + hideIf: false +}; + +export default MenuItem; diff --git a/client/components/Dropdown/TableDropdown.jsx b/client/components/Dropdown/TableDropdown.jsx new file mode 100644 index 0000000000..da7b6d7342 --- /dev/null +++ b/client/components/Dropdown/TableDropdown.jsx @@ -0,0 +1,20 @@ +import styled from 'styled-components'; +import { prop, remSize } from '../../theme'; +import DropdownMenu from './DropdownMenu'; + +const TableDropdown = styled(DropdownMenu).attrs({ align: 'right' })` + & > button { + width: ${remSize(25)}; + height: ${remSize(25)}; + & polygon, + & path { + fill: ${prop('inactiveTextColor')}; + } + } + & ul { + top: 63%; + right: calc(100% - 26px); + } +`; + +export default TableDropdown; diff --git a/client/modules/IDE/components/AssetList.jsx b/client/modules/IDE/components/AssetList.jsx index 559f60c580..7da5c0e865 100644 --- a/client/modules/IDE/components/AssetList.jsx +++ b/client/modules/IDE/components/AssetList.jsx @@ -1,129 +1,68 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { connect } from 'react-redux'; +import { connect, useDispatch } from 'react-redux'; import { bindActionCreators } from 'redux'; import { Link } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import prettyBytes from 'pretty-bytes'; -import { withTranslation } from 'react-i18next'; +import { useTranslation, withTranslation } from 'react-i18next'; +import MenuItem from '../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../components/Dropdown/TableDropdown'; import Loader from '../../App/components/loader'; +import { deleteAssetRequest } from '../actions/assets'; import * as AssetActions from '../actions/assets'; -import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg'; -class AssetListRowBase extends React.Component { - constructor(props) { - super(props); - this.state = { - isFocused: false, - optionsOpen: false - }; - } - - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeOptions(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; +const AssetMenu = ({ item: asset }) => { + const { t } = useTranslation(); - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; + const dispatch = useDispatch(); - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); + const handleAssetDelete = () => { + const { key, name } = asset; + if (window.confirm(t('Common.DeleteConfirmation', { name }))) { + dispatch(deleteAssetRequest(key)); } }; - handleDropdownOpen = () => { - this.closeOptions(); - this.openOptions(); - }; + return ( + + {t('AssetList.Delete')} + + {t('AssetList.OpenNewTab')} + + + ); +}; - handleAssetDelete = () => { - const { key, name } = this.props.asset; - this.closeOptions(); - if (window.confirm(this.props.t('Common.DeleteConfirmation', { name }))) { - this.props.deleteAssetRequest(key); - } - }; +AssetMenu.propTypes = { + item: PropTypes.shape({ + key: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + name: PropTypes.string.isRequired + }).isRequired +}; - render() { - const { asset, username, t } = this.props; - const { optionsOpen } = this.state; - return ( - - - - {asset.name} - - - {prettyBytes(asset.size)} - - {asset.sketchId && ( - - {asset.sketchName} - - )} - - - - {optionsOpen && ( -
      -
    • - -
    • -
    • - - {t('AssetList.OpenNewTab')} - -
    • -
    - )} - - - ); - } -} +const AssetListRowBase = ({ asset, username }) => ( + + + + {asset.name} + + + {prettyBytes(asset.size)} + + {asset.sketchId && ( + + {asset.sketchName} + + )} + + + + + +); AssetListRowBase.propTypes = { asset: PropTypes.shape({ @@ -134,9 +73,7 @@ AssetListRowBase.propTypes = { name: PropTypes.string.isRequired, size: PropTypes.number.isRequired }).isRequired, - deleteAssetRequest: PropTypes.func.isRequired, - username: PropTypes.string.isRequired, - t: PropTypes.func.isRequired + username: PropTypes.string.isRequired }; function mapStateToPropsAssetListRow(state) { diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index ed109141d7..ffb2d3c3d2 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -4,84 +4,35 @@ import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { bindActionCreators } from 'redux'; import { withTranslation } from 'react-i18next'; +import MenuItem from '../../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../../components/Dropdown/TableDropdown'; import * as ProjectActions from '../../actions/project'; import * as CollectionsActions from '../../actions/collections'; import * as IdeActions from '../../actions/ide'; import * as ToastActions from '../../actions/toast'; import dates from '../../../../utils/formatDate'; -import DownFilledTriangleIcon from '../../../../images/down-filled-triangle.svg'; - class CollectionListRowBase extends React.Component { - static projectInCollection(project, collection) { - return ( - collection.items.find((item) => item.project.id === project.id) != null - ); - } - constructor(props) { super(props); this.state = { - optionsOpen: false, - isFocused: false, renameOpen: false, renameValue: '' }; this.renameInput = React.createRef(); } - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeAll(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; - - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; - - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); - } - }; - closeAll = () => { this.setState({ - optionsOpen: false, renameOpen: false }); }; handleAddSketches = () => { - this.closeAll(); this.props.onAddSketches(); }; - handleDropdownOpen = () => { - this.closeAll(); - this.openOptions(); - }; - handleCollectionDelete = () => { - this.closeAll(); if ( window.confirm( this.props.t('Common.DeleteConfirmation', { @@ -94,7 +45,6 @@ class CollectionListRowBase extends React.Component { }; handleRenameOpen = () => { - this.closeAll(); this.setState( { renameOpen: true, @@ -132,61 +82,24 @@ class CollectionListRowBase extends React.Component { }; renderActions = () => { - const { optionsOpen } = this.state; const userIsOwner = this.props.user.username === this.props.username; return ( - - - {optionsOpen && ( -
      -
    • - -
    • - {userIsOwner && ( -
    • - -
    • - )} - {userIsOwner && ( -
    • - -
    • - )} -
    + + > + + {this.props.t('CollectionListRow.AddSketch')} + + + {this.props.t('CollectionListRow.Delete')} + + + {this.props.t('CollectionListRow.Rename')} + + ); }; diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx index af03453e0d..108e00755e 100644 --- a/client/modules/IDE/components/SketchList.jsx +++ b/client/modules/IDE/components/SketchList.jsx @@ -7,6 +7,8 @@ import { Link } from 'react-router-dom'; import { bindActionCreators } from 'redux'; import classNames from 'classnames'; import slugify from 'slugify'; +import MenuItem from '../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../components/Dropdown/TableDropdown'; import dates from '../../../utils/formatDate'; import * as ProjectActions from '../actions/project'; import * as ProjectsActions from '../actions/projects'; @@ -22,7 +24,6 @@ import getConfig from '../../../utils/getConfig'; import ArrowUpIcon from '../../../images/sort-arrow-up.svg'; import ArrowDownIcon from '../../../images/sort-arrow-down.svg'; -import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg'; const ROOT_URL = getConfig('API_URL'); @@ -33,47 +34,12 @@ class SketchListRowBase extends React.Component { constructor(props) { super(props); this.state = { - optionsOpen: false, renameOpen: false, - renameValue: props.sketch.name, - isFocused: false + renameValue: props.sketch.name }; this.renameInput = React.createRef(); } - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeAll(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; - - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; - - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); - } - }; - openRename = () => { this.setState( { @@ -90,13 +56,6 @@ class SketchListRowBase extends React.Component { }); }; - closeAll = () => { - this.setState({ - renameOpen: false, - optionsOpen: false - }); - }; - handleRenameChange = (e) => { this.setState({ renameValue: e.target.value @@ -106,13 +65,13 @@ class SketchListRowBase extends React.Component { handleRenameEnter = (e) => { if (e.key === 'Enter') { this.updateName(); - this.closeAll(); + this.closeRename(); } }; handleRenameBlur = () => { this.updateName(); - this.closeAll(); + this.closeRename(); }; updateName = () => { @@ -125,23 +84,6 @@ class SketchListRowBase extends React.Component { } }; - resetSketchName = () => { - this.setState({ - renameValue: this.props.sketch.name, - renameOpen: false - }); - }; - - handleDropdownOpen = () => { - this.closeAll(); - this.openOptions(); - }; - - handleRenameOpen = () => { - this.closeAll(); - this.openRename(); - }; - handleSketchDownload = () => { const { sketch } = this.props; const downloadLink = document.createElement('a'); @@ -153,12 +95,10 @@ class SketchListRowBase extends React.Component { }; handleSketchDuplicate = () => { - this.closeAll(); this.props.cloneProject(this.props.sketch); }; handleSketchShare = () => { - this.closeAll(); this.props.showShareModal( this.props.sketch.id, this.props.sketch.name, @@ -167,7 +107,6 @@ class SketchListRowBase extends React.Component { }; handleSketchDelete = () => { - this.closeAll(); if ( window.confirm( this.props.t('Common.DeleteConfirmation', { @@ -179,102 +118,42 @@ class SketchListRowBase extends React.Component { } }; - renderViewButton = (sketchURL) => ( - - {this.props.t('SketchList.View')} - - ); - renderDropdown = () => { - const { optionsOpen } = this.state; const userIsOwner = this.props.user.username === this.props.username; return ( - - {optionsOpen && ( -
      - {userIsOwner && ( -
    • - -
    • - )} -
    • - -
    • - {this.props.user.authenticated && ( -
    • - -
    • - )} - {this.props.user.authenticated && ( -
    • - -
    • - )} - {/*
    • - -
    • */} - {userIsOwner && ( -
    • - -
    • - )} -
    - )} + + + {this.props.t('SketchList.DropdownRename')} + + + {this.props.t('SketchList.DropdownDownload')} + + + {this.props.t('SketchList.DropdownDuplicate')} + + { + this.props.onAddToCollection(); + }} + > + {this.props.t('SketchList.DropdownAddToCollection')} + + + {/* + + Share + + */} + + {this.props.t('SketchList.DropdownDelete')} + + ); }; diff --git a/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap b/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap index bd7475ebf9..63a4542d36 100644 --- a/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap +++ b/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap @@ -85,15 +85,19 @@ exports[` snapshot testing 1`] = ` - + +
    snapshot testing 1`] = ` - + +
    diff --git a/client/styles/components/_asset-list.scss b/client/styles/components/_asset-list.scss index 6f7c035993..7d8f6065e8 100644 --- a/client/styles/components/_asset-list.scss +++ b/client/styles/components/_asset-list.scss @@ -76,24 +76,3 @@ background-color: getThemifyVariable('background-color'); } } - -.asset-table__dropdown-button { - width:#{25 / $base-font-size}rem; - height:#{25 / $base-font-size}rem; - - @include themify() { - & polygon, & path { - fill: getThemifyVariable('inactive-text-color'); - } - } -} - -.asset-table__action-dialogue { - @extend %dropdown-open-right; - top: 63%; - right: calc(100% - 26px); -} - -.asset-table__action-option { - font-size: #{12 / $base-font-size}rem; -} diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss index b03381b091..58e17f109b 100644 --- a/client/styles/components/_sketch-list.scss +++ b/client/styles/components/_sketch-list.scss @@ -100,17 +100,6 @@ font-weight: normal; } - -.sketch-list__dropdown-button { - width:#{25 / $base-font-size}rem; - height:#{25 / $base-font-size}rem; - @include themify() { - & polygon, & path { - fill: getThemifyVariable('inactive-text-color'); - } - } -} - .sketches-table__name { display: flex; align-items: center; @@ -120,12 +109,6 @@ width: #{35 / $base-font-size}rem; } -.sketch-list__action-dialogue { - @extend %dropdown-open-right; - top: 63%; - right: calc(100% - 26px); -} - .sketches-table__empty { text-align: center; font-size: #{16 / $base-font-size}rem; From 3980be0037015dd287452fc7ac3e61a24aaed1d1 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Wed, 16 Aug 2023 12:30:27 -0500 Subject: [PATCH 022/118] add setTimeout to close --- client/components/Dropdown/DropdownMenu.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/components/Dropdown/DropdownMenu.jsx b/client/components/Dropdown/DropdownMenu.jsx index ce7e03837e..0e18207f26 100644 --- a/client/components/Dropdown/DropdownMenu.jsx +++ b/client/components/Dropdown/DropdownMenu.jsx @@ -50,7 +50,9 @@ const DropdownMenu = forwardRef( { + setTimeout(close, 0); + }} onBlur={handleBlur} onFocus={handleFocus} > From d18d6fdd6f3453c7e740a418f341e466bd05d7a8 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Mon, 28 Aug 2023 16:09:40 -0500 Subject: [PATCH 023/118] update showToast action syntax --- client/modules/IDE/components/Toast.test.jsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/client/modules/IDE/components/Toast.test.jsx b/client/modules/IDE/components/Toast.test.jsx index fd92d3633c..f02fa42eae 100644 --- a/client/modules/IDE/components/Toast.test.jsx +++ b/client/modules/IDE/components/Toast.test.jsx @@ -6,11 +6,9 @@ import { fireEvent, waitFor } from '../../../test-utils'; -import { setToastText, showToast } from '../actions/toast'; +import { showToast } from '../actions/toast'; import Toast from './Toast'; -// TODO: update action calls after reducer refactor is merged. - describe(`Toast`, () => { it('is hidden by default', () => { reduxRender(); @@ -20,8 +18,7 @@ describe(`Toast`, () => { it('opens when an action is dispatched', async () => { const { store } = reduxRender(); act(() => { - store.dispatch(showToast(1500)); - store.dispatch(setToastText('Toast.SketchSaved')); + store.dispatch(showToast('Toast.SketchSaved')); }); const toast = screen.queryByRole('status'); @@ -32,8 +29,7 @@ describe(`Toast`, () => { it('closes automatically after time', async () => { const { store } = reduxRender(); act(() => { - store.dispatch(showToast(100)); - store.dispatch(setToastText('Toast.SketchSaved')); + store.dispatch(showToast('Toast.SketchSaved', 100)); }); expect(screen.queryByRole('status')).toBeInTheDocument(); From d2bff5b2b8345fe7404ffc99499ffa2ec40dbf93 Mon Sep 17 00:00:00 2001 From: Aviroop Jana Date: Mon, 11 Sep 2023 18:11:31 +0530 Subject: [PATCH 024/118] Moved CollectionListRow to be a functional component --- .../CollectionList/CollectionListRow.jsx | 566 +++++++++--------- 1 file changed, 267 insertions(+), 299 deletions(-) diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index 16421f7a6b..5e875a8a2e 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -1,299 +1,267 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; -import { bindActionCreators } from 'redux'; -import { withTranslation } from 'react-i18next'; -import * as ProjectActions from '../../actions/project'; -import * as CollectionsActions from '../../actions/collections'; -import * as IdeActions from '../../actions/ide'; -import * as ToastActions from '../../actions/toast'; -import dates from '../../../../utils/formatDate'; - -import DownFilledTriangleIcon from '../../../../images/down-filled-triangle.svg'; -import MoreIconSvg from '../../../../images/more.svg'; - -const formatDateCell = (date, mobile = false) => - dates.format(date, { showTime: !mobile }); - -class CollectionListRowBase extends React.Component { - static projectInCollection(project, collection) { - return ( - collection.items.find((item) => item.project.id === project.id) != null - ); - } - - constructor(props) { - super(props); - this.state = { - optionsOpen: false, - isFocused: false, - renameOpen: false, - renameValue: '' - }; - this.renameInput = React.createRef(); - } - - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeAll(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; - - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; - - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); - } - }; - - closeAll = () => { - this.setState({ - optionsOpen: false, - renameOpen: false - }); - }; - - handleAddSketches = () => { - this.closeAll(); - this.props.onAddSketches(); - }; - - handleDropdownOpen = () => { - this.closeAll(); - this.openOptions(); - }; - - handleCollectionDelete = () => { - this.closeAll(); - if ( - window.confirm( - this.props.t('Common.DeleteConfirmation', { - name: this.props.collection.name - }) - ) - ) { - this.props.deleteCollection(this.props.collection.id); - } - }; - - handleRenameOpen = () => { - this.closeAll(); - this.setState( - { - renameOpen: true, - renameValue: this.props.collection.name - }, - () => this.renameInput.current.focus() - ); - }; - - handleRenameChange = (e) => { - this.setState({ - renameValue: e.target.value - }); - }; - - handleRenameEnter = (e) => { - if (e.key === 'Enter') { - this.updateName(); - this.closeAll(); - } - }; - - handleRenameBlur = () => { - this.updateName(); - this.closeAll(); - }; - - updateName = () => { - const isValid = this.state.renameValue.trim().length !== 0; - if (isValid) { - this.props.editCollection(this.props.collection.id, { - name: this.state.renameValue.trim() - }); - } - }; - - renderActions = () => { - const { optionsOpen } = this.state; - const userIsOwner = this.props.user.username === this.props.username; - - return ( - - - {optionsOpen && ( -
      -
    • - -
    • - {userIsOwner && ( -
    • - -
    • - )} - {userIsOwner && ( -
    • - -
    • - )} -
    - )} -
    - ); - }; - - renderCollectionName = () => { - const { collection, username } = this.props; - const { renameOpen, renameValue } = this.state; - - return ( - - - {renameOpen ? '' : collection.name} - - {renameOpen && ( - e.stopPropagation()} - ref={this.renameInput} - /> - )} - - ); - }; - - render() { - const { collection, mobile } = this.props; - - return ( - - - - {this.renderCollectionName()} - - - {formatDateCell(collection.createdAt, mobile)} - {formatDateCell(collection.updatedAt, mobile)} - - {mobile && 'sketches: '} - {(collection.items || []).length} - - {this.renderActions()} - - ); - } -} - -CollectionListRowBase.propTypes = { - collection: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - owner: PropTypes.shape({ - username: PropTypes.string.isRequired - }).isRequired, - createdAt: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - project: PropTypes.shape({ - id: PropTypes.string.isRequired - }) - }) - ) - }).isRequired, - username: PropTypes.string.isRequired, - user: PropTypes.shape({ - username: PropTypes.string, - authenticated: PropTypes.bool.isRequired - }).isRequired, - deleteCollection: PropTypes.func.isRequired, - editCollection: PropTypes.func.isRequired, - onAddSketches: PropTypes.func.isRequired, - mobile: PropTypes.bool, - t: PropTypes.func.isRequired -}; - -CollectionListRowBase.defaultProps = { - mobile: false -}; - -function mapDispatchToPropsSketchListRow(dispatch) { - return bindActionCreators( - Object.assign( - {}, - CollectionsActions, - ProjectActions, - IdeActions, - ToastActions - ), - dispatch - ); -} - -export default withTranslation()( - connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase) -); +import PropTypes from 'prop-types'; +import React, { useState, useRef } from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; +import { bindActionCreators } from 'redux'; +import { withTranslation } from 'react-i18next'; +import * as ProjectActions from '../../actions/project'; +import * as CollectionsActions from '../../actions/collections'; +import * as IdeActions from '../../actions/ide'; +import * as ToastActions from '../../actions/toast'; +import dates from '../../../../utils/formatDate'; + +import DownFilledTriangleIcon from '../../../../images/down-filled-triangle.svg'; +import MoreIconSvg from '../../../../images/more.svg'; + +const formatDateCell = (date, mobile = false) => + dates.format(date, { showTime: !mobile }); + +const CollectionListRowBase = (props) => { + const [optionsOpen, setOptionsOpen] = useState(false); + const [isFocused, setIsFocused] = useState(false); + const [renameOpen, setRenameOpen] = useState(false); + const [renameValue, setRenameValue] = useState(''); + const renameInput = useRef(null); + + const onFocusComponent = () => { + setIsFocused(true); + }; + + const onBlurComponent = () => { + setIsFocused(false); + setTimeout(() => { + if (!isFocused) { + closeAll(); + } + }, 200); + }; + + const openOptions = () => { + setOptionsOpen(true); + }; + + const closeOptions = () => { + setOptionsOpen(false); + }; + + const toggleOptions = () => { + if (optionsOpen) { + closeOptions(); + } else { + openOptions(); + } + }; + + const closeAll = () => { + setOptionsOpen(false); + setRenameOpen(false); + }; + + const handleAddSketches = () => { + closeAll(); + props.onAddSketches(); + }; + + const handleCollectionDelete = () => { + closeAll(); + if ( + window.confirm( + props.t('Common.DeleteConfirmation', { + name: props.collection.name + }) + ) + ) { + props.deleteCollection(props.collection.id); + } + }; + + const handleRenameOpen = () => { + closeAll(); + setRenameOpen(true); + setRenameValue(props.collection.name); + if (renameInput.current) { + renameInput.current.focus(); + } + }; + + const handleRenameChange = (e) => { + setRenameValue(e.target.value); + }; + + const handleRenameEnter = (e) => { + if (e.key === 'Enter') { + updateName(); + closeAll(); + } + }; + + const handleRenameBlur = () => { + updateName(); + closeAll(); + }; + + const updateName = () => { + const isValid = renameValue.trim().length !== 0; + if (isValid) { + props.editCollection(props.collection.id, { + name: renameValue.trim() + }); + } + }; + + const renderActions = () => { + const { mobile } = props; + const userIsOwner = props.user.username === props.username; + + return ( + <> + + {optionsOpen && ( +
      +
    • + +
    • + {userIsOwner && ( +
    • + +
    • + )} + {userIsOwner && ( +
    • + +
    • + )} +
    + )} + + ); + }; + + const renderCollectionName = () => { + const { collection, username } = props; + + return ( + <> + + {renameOpen ? '' : collection.name} + + {renameOpen && ( + e.stopPropagation()} + ref={renameInput} + /> + )} + + ); + }; + + const { collection, mobile } = props; + + return ( + + + {renderCollectionName()} + + {formatDateCell(collection.createdAt, mobile)} + {formatDateCell(collection.updatedAt, mobile)} + + {mobile && 'sketches: '} + {(collection.items || []).length} + + {renderActions()} + + ); +}; + +CollectionListRowBase.propTypes = { + collection: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + owner: PropTypes.shape({ + username: PropTypes.string.isRequired + }).isRequired, + createdAt: PropTypes.string.isRequired, + updatedAt: PropTypes.string.isRequired, + items: PropTypes.arrayOf( + PropTypes.shape({ + project: PropTypes.shape({ + id: PropTypes.string.isRequired + }) + }) + ) + }).isRequired, + username: PropTypes.string.isRequired, + user: PropTypes.shape({ + username: PropTypes.string, + authenticated: PropTypes.bool.isRequired + }).isRequired, + deleteCollection: PropTypes.func.isRequired, + editCollection: PropTypes.func.isRequired, + onAddSketches: PropTypes.func.isRequired, + mobile: PropTypes.bool, + t: PropTypes.func.isRequired +}; + +CollectionListRowBase.defaultProps = { + mobile: false +}; + +function mapDispatchToPropsSketchListRow(dispatch) { + return bindActionCreators( + Object.assign( + {}, + CollectionsActions, + ProjectActions, + IdeActions, + ToastActions + ), + dispatch + ); +} + +export default withTranslation()( + connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase) +); + From 8999a9cfc01f140681e0aa823628a4b1ba023f3f Mon Sep 17 00:00:00 2001 From: Aviroop Jana Date: Mon, 11 Sep 2023 18:24:52 +0530 Subject: [PATCH 025/118] Moved CollectionListRow to be a functional component --- .../CollectionList/CollectionListRow.jsx | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index 5e875a8a2e..73ac9ba4c8 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -23,6 +23,20 @@ const CollectionListRowBase = (props) => { const [renameValue, setRenameValue] = useState(''); const renameInput = useRef(null); + const closeAll = () => { + setOptionsOpen(false); + setRenameOpen(false); + }; + + const updateName = () => { + const isValid = renameValue.trim().length !== 0; + if (isValid) { + props.editCollection(props.collection.id, { + name: renameValue.trim() + }); + } + }; + const onFocusComponent = () => { setIsFocused(true); }; @@ -52,11 +66,6 @@ const CollectionListRowBase = (props) => { } }; - const closeAll = () => { - setOptionsOpen(false); - setRenameOpen(false); - }; - const handleAddSketches = () => { closeAll(); props.onAddSketches(); @@ -100,15 +109,6 @@ const CollectionListRowBase = (props) => { closeAll(); }; - const updateName = () => { - const isValid = renameValue.trim().length !== 0; - if (isValid) { - props.editCollection(props.collection.id, { - name: renameValue.trim() - }); - } - }; - const renderActions = () => { const { mobile } = props; const userIsOwner = props.user.username === props.username; @@ -264,4 +264,3 @@ function mapDispatchToPropsSketchListRow(dispatch) { export default withTranslation()( connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase) ); - From 2ad0c3a2d2f2f15c38217a7f6f42624c4a649140 Mon Sep 17 00:00:00 2001 From: Ankush263 Date: Fri, 15 Sep 2023 16:04:21 +0530 Subject: [PATCH 026/118] Update the S3/AWS client package --- package.json | 1 + server/controllers/aws.controller.js | 289 ++++++++++++--------------- server/migrations/s3UnderUser.js | 170 ++++++++-------- 3 files changed, 221 insertions(+), 239 deletions(-) diff --git a/package.json b/package.json index 569631aef2..0ba3d24808 100644 --- a/package.json +++ b/package.json @@ -155,6 +155,7 @@ }, "dependencies": { "@auth0/s3": "^1.0.0", + "@aws-sdk/client-s3": "^3.412.0", "@babel/core": "^7.14.6", "@babel/register": "^7.14.5", "@emmetio/codemirror-plugin": "^1.2.4", diff --git a/server/controllers/aws.controller.js b/server/controllers/aws.controller.js index 91d3d487be..0ef0fafa4c 100644 --- a/server/controllers/aws.controller.js +++ b/server/controllers/aws.controller.js @@ -1,23 +1,24 @@ import { v4 as uuidv4 } from 'uuid'; import S3Policy from 's3-policy-v4'; -import s3 from '@auth0/s3'; +import { + S3Client, + HeadObjectCommand, + CopyObjectCommand, + ListObjectsCommand, + DeleteObjectsCommand +} from '@aws-sdk/client-s3'; import mongoose from 'mongoose'; import { getProjectsForUserId } from './project.controller'; import { findUserByUsername } from './user.controller'; const { ObjectId } = mongoose.Types; -const client = s3.createClient({ - maxAsyncS3: 20, - s3RetryCount: 3, - s3RetryDelay: 1000, - multipartUploadThreshold: 20971520, // this is the default (20 MB) - multipartUploadSize: 15728640, // this is the default (15 MB) - s3Options: { - accessKeyId: `${process.env.AWS_ACCESS_KEY}`, - secretAccessKey: `${process.env.AWS_SECRET_KEY}`, - region: `${process.env.AWS_REGION}` - } +const s3Client = new S3Client({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY, + secretAccessKey: process.env.AWS_SECRET_KEY + }, + region: process.env.AWS_REGION }); const s3Bucket = @@ -39,21 +40,26 @@ export function getObjectKey(url) { return objectKey; } -export function deleteObjectsFromS3(keyList, callback) { - const keys = keyList.map((key) => { return { Key: key }; }); // eslint-disable-line - if (keyList.length > 0) { +export async function deleteObjectsFromS3(keyList, callback) { + const objectsToDelete = keyList.map((key) => ({ Key: key })); + + if (objectsToDelete.length > 0) { const params = { - Bucket: `${process.env.S3_BUCKET}`, - Delete: { - Objects: keys - } + Bucket: process.env.S3_BUCKET, + Delete: { Objects: objectsToDelete } }; - const del = client.deleteObjects(params); - del.on('end', () => { + + try { + await s3Client.send(new DeleteObjectsCommand(params)); if (callback) { callback(); } - }); + } catch (error) { + console.error('Error deleting objects from S3: ', error); + if (callback) { + callback(error); + } + } } else if (callback) { callback(); } @@ -61,12 +67,7 @@ export function deleteObjectsFromS3(keyList, callback) { export function deleteObjectFromS3(req, res) { const { objectKey, userId } = req.params; - let fullObjectKey; - if (userId) { - fullObjectKey = `${userId}/${objectKey}`; - } else { - fullObjectKey = objectKey; - } + const fullObjectKey = userId ? `${userId}/${objectKey}` : objectKey; deleteObjectsFromS3([fullObjectKey], () => { res.json({ success: true }); }); @@ -96,151 +97,127 @@ export function signS3(req, res) { res.json(policy); } -export function copyObjectInS3(url, userId) { - return new Promise((resolve, reject) => { - const objectKey = getObjectKey(url); - const fileExtension = getExtension(objectKey); - const newFilename = uuidv4() + fileExtension; - const headParams = { - Bucket: `${process.env.S3_BUCKET}`, - Key: `${objectKey}` - }; - client.s3.headObject(headParams, (headErr) => { - if (headErr) { - reject( - new Error( - `Object with key ${process.env.S3_BUCKET}/${objectKey} does not exist.` - ) - ); - return; - } - const params = { - Bucket: `${process.env.S3_BUCKET}`, - CopySource: `${process.env.S3_BUCKET}/${objectKey}`, - Key: `${userId}/${newFilename}`, - ACL: 'public-read' - }; - const copy = client.copyObject(params); - copy.on('err', (err) => { - reject(err); - }); - copy.on('end', (data) => { - resolve(`${s3Bucket}${userId}/${newFilename}`); - }); - }); - }); +export async function copyObjectInS3(url, userId) { + const objectKey = getObjectKey(url); + const fileExtension = getExtension(objectKey); + const newFilename = uuidv4() + fileExtension; + const headParams = { + Bucket: process.env.S3_BUCKET, + Key: objectKey + }; + + await s3Client.send(new HeadObjectCommand(headParams)); + + const params = { + Bucket: process.env.S3_BUCKET, + CopySource: `${process.env.S3_BUCKET}/${objectKey}`, + Key: `${userId}/${newFilename}`, + ACL: 'public-read' + }; + + try { + await s3Client.send(new CopyObjectCommand(params)); + return `${s3Bucket}${userId}/${newFilename}`; + } catch (error) { + console.error('Error copying object in S3:', error); + throw error; + } } -export function copyObjectInS3RequestHandler(req, res) { +export async function copyObjectInS3RequestHandler(req, res) { const { url } = req.body; - copyObjectInS3(url, req.user.id).then((newUrl) => { - res.json({ url: newUrl }); - }); + const newUrl = await copyObjectInS3(url, req.user.id); + res.json({ url: newUrl }); } -export function moveObjectToUserInS3(url, userId) { - return new Promise((resolve, reject) => { - const objectKey = getObjectKey(url); - const fileExtension = getExtension(objectKey); - const newFilename = uuidv4() + fileExtension; +export async function moveObjectToUserInS3(url, userId) { + const objectKey = getObjectKey(url); + const fileExtension = getExtension(objectKey); + const newFilename = uuidv4() + fileExtension; + + try { const headParams = { - Bucket: `${process.env.S3_BUCKET}`, - Key: `${objectKey}` + Bucket: process.env.S3_BUCKET, + Key: objectKey }; - client.s3.headObject(headParams, (headErr) => { - if (headErr) { - reject( - new Error( - `Object with key ${process.env.S3_BUCKET}/${objectKey} does not exist.` - ) - ); - return; - } - const params = { - Bucket: `${process.env.S3_BUCKET}`, - CopySource: `${process.env.S3_BUCKET}/${objectKey}`, - Key: `${userId}/${newFilename}`, - ACL: 'public-read' - }; - const move = client.moveObject(params); - move.on('err', (err) => { - reject(err); - }); - move.on('end', (data) => { - resolve(`${s3Bucket}${userId}/${newFilename}`); - }); - }); - }); + await s3Client.send(new HeadObjectCommand(headParams)); + } catch (headErr) { + throw new Error( + `Object with key ${process.env.S3_BUCKET}/${objectKey} does not exist.` + ); + } + + const params = { + Bucket: process.env.S3_BUCKET, + CopySource: `${process.env.S3_BUCKET}/${objectKey}`, + Key: `${userId}/${newFilename}`, + ACL: 'public-read' + }; + + await s3Client.send(new CopyObjectCommand(params)); + return `${s3Bucket}${userId}/${newFilename}`; } -export function listObjectsInS3ForUser(userId) { - let assets = []; - return new Promise((resolve) => { +export async function listObjectsInS3ForUser(userId) { + try { + let assets = []; const params = { - s3Params: { - Bucket: `${process.env.S3_BUCKET}`, - Prefix: `${userId}/` - } + Bucket: process.env.S3_BUCKET, + Prefix: `${userId}/` }; - client - .listObjects(params) - .on('data', (data) => { - assets = assets.concat( - data.Contents.map((object) => ({ - key: object.Key, - size: object.Size - })) - ); - }) - .on('end', () => { - resolve(); - }); - }) - .then(() => getProjectsForUserId(userId)) - .then((projects) => { - const projectAssets = []; - let totalSize = 0; - assets.forEach((asset) => { - const name = asset.key.split('/').pop(); - const foundAsset = { - key: asset.key, - name, - size: asset.size, - url: `${process.env.S3_BUCKET_URL_BASE}${asset.key}` - }; - totalSize += asset.size; - projects.some((project) => { - let found = false; - project.files.some((file) => { - if (!file.url) return false; - if (file.url.includes(asset.key)) { - found = true; - foundAsset.name = file.name; - foundAsset.sketchName = project.name; - foundAsset.sketchId = project.id; - foundAsset.url = file.url; - return true; - } - return false; - }); - return found; + + const data = await s3Client.send(new ListObjectsCommand(params)); + + assets = data.Contents.map((object) => ({ + key: object.Key, + size: object.Size + })); + + const projects = await getProjectsForUserId(userId); + const projectAssets = []; + let totalSize = 0; + + assets.forEach((asset) => { + const name = asset.key.split('/').pop(); + const foundAsset = { + key: asset.key, + name, + size: asset.size, + url: `${process.env.S3_BUCKET_URL_BASE}${asset.key}` + }; + totalSize += asset.size; + + projects.some((project) => { + let found = false; + project.files.some((file) => { + if (!file.url) return false; + if (file.url.includes(asset.key)) { + found = true; + foundAsset.name = file.name; + foundAsset.sketchName = project.name; + foundAsset.sketchId = project.id; + foundAsset.url = file.url; + return true; + } + return false; }); - projectAssets.push(foundAsset); + return found; }); - return Promise.resolve({ assets: projectAssets, totalSize }); - }) - .catch((err) => { - console.log('got an error'); - console.log(err); + projectAssets.push(foundAsset); }); + + return { assets: projectAssets, totalSize }; + } catch (error) { + console.log('Got an error:', error); + throw error; + } } -export function listObjectsInS3ForUserRequestHandler(req, res) { +export async function listObjectsInS3ForUserRequestHandler(req, res) { const { username } = req.user; - findUserByUsername(username, (user) => { + findUserByUsername(username, async (user) => { const userId = user.id; - listObjectsInS3ForUser(userId).then((objects) => { - res.json(objects); - }); + const objects = await listObjectsInS3ForUser(userId); + res.json(objects); }); } diff --git a/server/migrations/s3UnderUser.js b/server/migrations/s3UnderUser.js index 33500f75de..0657b0edc3 100644 --- a/server/migrations/s3UnderUser.js +++ b/server/migrations/s3UnderUser.js @@ -1,96 +1,100 @@ /* eslint-disable */ -import s3 from '@auth0/s3'; +import { + S3Client, + CopyObjectCommand, + HeadObjectCommand +} from '@aws-sdk/client-s3'; import path from 'path'; import mongoose from 'mongoose'; import User from '../models/user'; import Project from '../models/project'; import async from 'async'; -require('dotenv').config({path: path.resolve('.env')}); -mongoose.connect('mongodb://localhost:27017/p5js-web-editor'); -mongoose.connection.on('error', () => { - console.error('MongoDB Connection Error. Please make sure that MongoDB is running.'); - process.exit(1); -}); +import dotenv from 'dotenv'; -let client = s3.createClient({ - maxAsyncS3: 20, - s3RetryCount: 3, - s3RetryDelay: 1000, - multipartUploadThreshold: 20971520, // this is the default (20 MB) - multipartUploadSize: 15728640, // this is the default (15 MB) - s3Options: { - accessKeyId: `${process.env.AWS_ACCESS_KEY}`, - secretAccessKey: `${process.env.AWS_SECRET_KEY}`, - region: `${process.env.AWS_REGION}` - }, -}); +dotenv.config({ path: path.resolve('.env') }); -const CHUNK = 100; -Project.count({}).exec().then((numProjects) => { +async function main() { + mongoose.connect('mongodb://localhost:27017/p5js-web-editor'); + mongoose.connection.on('error', () => { + console.error( + 'MongoDB Connection Error. Please make sure that MongoDB is running.' + ); + process.exit(1); + }); + + const s3Client = new S3Client({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY, + secretAccessKey: process.env.AWS_SECRET_KEY + }, + region: process.env.AWS_REGION + }); + + const CHUNK = 100; + const numProjects = await Project.count({}).exec(); console.log(numProjects); let index = 0; - async.whilst( - () => { - return index < numProjects; - }, - (whilstCb) => { - Project.find({}).skip(index).limit(CHUNK).exec((err, projects) => { - async.eachSeries(projects, (project, cb) => { - if (!project.user) { - cb(); + + while (index < numProjects) { + const projects = await Project.find({}).skip(index).limit(CHUNK).exec(); + await async.eachSeries(projects, async (project) => { + if (!project.user) { + return; + } + const userId = project.user.valueOf(); + console.log(project.name); + + await async.eachSeries(project.files, async (file) => { + if ( + file.url && + file.url.includes(process.env.S3_BUCKET) && + !file.url.includes(userId) + ) { + console.log(file.url); + console.log(userId); + const key = file.url.split('/').pop(); + console.log(key); + const sourceKey = `${process.env.S3_BUCKET}/${key}`; + const destinationKey = `${userId}/${key}`; + + const headParams = { + Bucket: process.env.S3_BUCKET, + Key: key + }; + + try { + await s3Client.send(new HeadObjectCommand(headParams)); + } catch (headErr) { + console.log(headErr); return; } - const userId = project.user.valueOf(); - console.log(project.name); - async.eachSeries(project.files, (file, fileCb) => { - if (file.url && file.url.includes(process.env.S3_BUCKET) && !file.url.includes(userId)) { - console.log(file.url); - console.log(userId); - const key = file.url.split('/').pop(); - console.log(key); - const params = { - Bucket: `${process.env.S3_BUCKET}`, - CopySource: `${process.env.S3_BUCKET}/${key}`, - Key: `${userId}/${key}` - }; - try { - client.moveObject(params) - .on('error', (err) => { - console.log(err); - file.url = (process.env.S3_BUCKET_URL_BASE || - `https://s3-${process.env.AWS_REGION}.amazonaws.com/${process.env.S3_BUCKET}`) + `/${userId}/${key}`; - project.save((err, savedProject) => { - console.log(`updated file ${key}`); - fileCb(); - }); - }) - .on('end', () => { - file.url = (process.env.S3_BUCKET_URL_BASE || - `https://s3-${process.env.AWS_REGION}.amazonaws.com/${process.env.S3_BUCKET}`) + `/${userId}/${key}`; - project.save((err, savedProject) => { - console.log(`updated file ${key}`); - fileCb(); - }); - }); - } catch(e) { - console.log(e); - fileCb(); - } - } else { - fileCb(); - } - }, () => { - cb(); - }); - }, () => { - index += CHUNK; - whilstCb(); - }); + + const copyParams = { + Bucket: process.env.S3_BUCKET, + CopySource: sourceKey, + Key: destinationKey + }; + + try { + await s3Client.send(new CopyObjectCommand(copyParams)); + file.url = + (process.env.S3_BUCKET_URL_BASE || + `https://s3-${process.env.AWS_REGION}.amazonaws.com/${process.env.S3_BUCKET}`) + + `/${userId}/${key}`; + project.save((err, savedProject) => { + console.log(`updated file ${key}`); + }); + } catch (e) { + console.log(e); + } + } }); - }, - () => { - console.log('finished processing all documents.'); - process.exit(0); - } - ); -}); + }); + index += CHUNK; + } + + console.log('finished processing all documents.'); + process.exit(0); +} + +main(); From c7bf38ee56acf93b405babd68859a3eab224ffc6 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Mon, 14 Aug 2023 11:59:59 -0500 Subject: [PATCH 027/118] Common dropdown component for table actions. --- client/components/Dropdown.jsx | 3 +- client/components/Dropdown/DropdownMenu.jsx | 83 ++++++++ client/components/Dropdown/MenuItem.jsx | 35 ++++ client/components/Dropdown/TableDropdown.jsx | 20 ++ client/modules/IDE/components/AssetList.jsx | 161 +++++--------- .../CollectionList/CollectionListRow.jsx | 124 ++--------- client/modules/IDE/components/SketchList.jsx | 198 ++++-------------- .../SketchList.unit.test.jsx.snap | 40 ++-- client/styles/components/_asset-list.scss | 21 -- client/styles/components/_sketch-list.scss | 17 -- 10 files changed, 265 insertions(+), 437 deletions(-) create mode 100644 client/components/Dropdown/DropdownMenu.jsx create mode 100644 client/components/Dropdown/MenuItem.jsx create mode 100644 client/components/Dropdown/TableDropdown.jsx diff --git a/client/components/Dropdown.jsx b/client/components/Dropdown.jsx index 9a91d54cd2..369bef51b0 100644 --- a/client/components/Dropdown.jsx +++ b/client/components/Dropdown.jsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { remSize, prop } from '../theme'; import IconButton from './mobile/IconButton'; -const DropdownWrapper = styled.ul` +export const DropdownWrapper = styled.ul` background-color: ${prop('Modal.background')}; border: 1px solid ${prop('Modal.border')}; box-shadow: 0 0 18px 0 ${prop('shadowColor')}; @@ -52,6 +52,7 @@ const DropdownWrapper = styled.ul` & button span, & a { padding: ${remSize(8)} ${remSize(16)}; + font-size: ${remSize(12)}; } * { diff --git a/client/components/Dropdown/DropdownMenu.jsx b/client/components/Dropdown/DropdownMenu.jsx new file mode 100644 index 0000000000..ce7e03837e --- /dev/null +++ b/client/components/Dropdown/DropdownMenu.jsx @@ -0,0 +1,83 @@ +import PropTypes from 'prop-types'; +import React, { forwardRef, useCallback, useRef, useState } from 'react'; +import useModalClose from '../../common/useModalClose'; +import DownArrowIcon from '../../images/down-filled-triangle.svg'; +import { DropdownWrapper } from '../Dropdown'; + +// TODO: enable arrow keys to navigate options from list + +const DropdownMenu = forwardRef( + ({ children, 'aria-label': ariaLabel, align, className, classes }, ref) => { + // Note: need to use a ref instead of a state to avoid stale closures. + const focusedRef = useRef(false); + + const [isOpen, setIsOpen] = useState(false); + + const close = useCallback(() => setIsOpen(false), [setIsOpen]); + + const anchorRef = useModalClose(close, ref); + + const toggle = useCallback(() => { + setIsOpen((prevState) => !prevState); + }, [setIsOpen]); + + const handleFocus = () => { + focusedRef.current = true; + }; + + const handleBlur = () => { + focusedRef.current = false; + setTimeout(() => { + if (!focusedRef.current) { + close(); + } + }, 200); + }; + + return ( +
    + + {isOpen && ( + + {children} + + )} +
    + ); + } +); + +DropdownMenu.propTypes = { + children: PropTypes.node, + 'aria-label': PropTypes.string.isRequired, + align: PropTypes.oneOf(['left', 'right']), + className: PropTypes.string, + classes: PropTypes.shape({ + button: PropTypes.string, + list: PropTypes.string + }) +}; + +DropdownMenu.defaultProps = { + children: null, + align: 'right', + className: '', + classes: {} +}; + +export default DropdownMenu; diff --git a/client/components/Dropdown/MenuItem.jsx b/client/components/Dropdown/MenuItem.jsx new file mode 100644 index 0000000000..8b6f6d7247 --- /dev/null +++ b/client/components/Dropdown/MenuItem.jsx @@ -0,0 +1,35 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ButtonOrLink from '../../common/ButtonOrLink'; + +// TODO: combine with NavMenuItem + +function MenuItem({ hideIf, ...rest }) { + if (hideIf) { + return null; + } + + return ( +
  • + +
  • + ); +} + +MenuItem.propTypes = { + ...ButtonOrLink.propTypes, + onClick: PropTypes.func, + value: PropTypes.string, + /** + * Provides a way to deal with optional items. + */ + hideIf: PropTypes.bool +}; + +MenuItem.defaultProps = { + onClick: null, + value: null, + hideIf: false +}; + +export default MenuItem; diff --git a/client/components/Dropdown/TableDropdown.jsx b/client/components/Dropdown/TableDropdown.jsx new file mode 100644 index 0000000000..da7b6d7342 --- /dev/null +++ b/client/components/Dropdown/TableDropdown.jsx @@ -0,0 +1,20 @@ +import styled from 'styled-components'; +import { prop, remSize } from '../../theme'; +import DropdownMenu from './DropdownMenu'; + +const TableDropdown = styled(DropdownMenu).attrs({ align: 'right' })` + & > button { + width: ${remSize(25)}; + height: ${remSize(25)}; + & polygon, + & path { + fill: ${prop('inactiveTextColor')}; + } + } + & ul { + top: 63%; + right: calc(100% - 26px); + } +`; + +export default TableDropdown; diff --git a/client/modules/IDE/components/AssetList.jsx b/client/modules/IDE/components/AssetList.jsx index 559f60c580..7da5c0e865 100644 --- a/client/modules/IDE/components/AssetList.jsx +++ b/client/modules/IDE/components/AssetList.jsx @@ -1,129 +1,68 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { connect } from 'react-redux'; +import { connect, useDispatch } from 'react-redux'; import { bindActionCreators } from 'redux'; import { Link } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import prettyBytes from 'pretty-bytes'; -import { withTranslation } from 'react-i18next'; +import { useTranslation, withTranslation } from 'react-i18next'; +import MenuItem from '../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../components/Dropdown/TableDropdown'; import Loader from '../../App/components/loader'; +import { deleteAssetRequest } from '../actions/assets'; import * as AssetActions from '../actions/assets'; -import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg'; -class AssetListRowBase extends React.Component { - constructor(props) { - super(props); - this.state = { - isFocused: false, - optionsOpen: false - }; - } - - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeOptions(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; +const AssetMenu = ({ item: asset }) => { + const { t } = useTranslation(); - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; + const dispatch = useDispatch(); - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); + const handleAssetDelete = () => { + const { key, name } = asset; + if (window.confirm(t('Common.DeleteConfirmation', { name }))) { + dispatch(deleteAssetRequest(key)); } }; - handleDropdownOpen = () => { - this.closeOptions(); - this.openOptions(); - }; + return ( + + {t('AssetList.Delete')} + + {t('AssetList.OpenNewTab')} + + + ); +}; - handleAssetDelete = () => { - const { key, name } = this.props.asset; - this.closeOptions(); - if (window.confirm(this.props.t('Common.DeleteConfirmation', { name }))) { - this.props.deleteAssetRequest(key); - } - }; +AssetMenu.propTypes = { + item: PropTypes.shape({ + key: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + name: PropTypes.string.isRequired + }).isRequired +}; - render() { - const { asset, username, t } = this.props; - const { optionsOpen } = this.state; - return ( - - - - {asset.name} - - - {prettyBytes(asset.size)} - - {asset.sketchId && ( - - {asset.sketchName} - - )} - - - - {optionsOpen && ( -
      -
    • - -
    • -
    • - - {t('AssetList.OpenNewTab')} - -
    • -
    - )} - - - ); - } -} +const AssetListRowBase = ({ asset, username }) => ( + + + + {asset.name} + + + {prettyBytes(asset.size)} + + {asset.sketchId && ( + + {asset.sketchName} + + )} + + + + + +); AssetListRowBase.propTypes = { asset: PropTypes.shape({ @@ -134,9 +73,7 @@ AssetListRowBase.propTypes = { name: PropTypes.string.isRequired, size: PropTypes.number.isRequired }).isRequired, - deleteAssetRequest: PropTypes.func.isRequired, - username: PropTypes.string.isRequired, - t: PropTypes.func.isRequired + username: PropTypes.string.isRequired }; function mapStateToPropsAssetListRow(state) { diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index 16421f7a6b..1d52163230 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -4,88 +4,38 @@ import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { bindActionCreators } from 'redux'; import { withTranslation } from 'react-i18next'; +import MenuItem from '../../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../../components/Dropdown/TableDropdown'; import * as ProjectActions from '../../actions/project'; import * as CollectionsActions from '../../actions/collections'; import * as IdeActions from '../../actions/ide'; import * as ToastActions from '../../actions/toast'; import dates from '../../../../utils/formatDate'; -import DownFilledTriangleIcon from '../../../../images/down-filled-triangle.svg'; -import MoreIconSvg from '../../../../images/more.svg'; - const formatDateCell = (date, mobile = false) => dates.format(date, { showTime: !mobile }); class CollectionListRowBase extends React.Component { - static projectInCollection(project, collection) { - return ( - collection.items.find((item) => item.project.id === project.id) != null - ); - } - constructor(props) { super(props); this.state = { - optionsOpen: false, - isFocused: false, renameOpen: false, renameValue: '' }; this.renameInput = React.createRef(); } - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeAll(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; - - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; - - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); - } - }; - closeAll = () => { this.setState({ - optionsOpen: false, renameOpen: false }); }; handleAddSketches = () => { - this.closeAll(); this.props.onAddSketches(); }; - handleDropdownOpen = () => { - this.closeAll(); - this.openOptions(); - }; - handleCollectionDelete = () => { - this.closeAll(); if ( window.confirm( this.props.t('Common.DeleteConfirmation', { @@ -98,7 +48,6 @@ class CollectionListRowBase extends React.Component { }; handleRenameOpen = () => { - this.closeAll(); this.setState( { renameOpen: true, @@ -136,65 +85,24 @@ class CollectionListRowBase extends React.Component { }; renderActions = () => { - const { optionsOpen } = this.state; const userIsOwner = this.props.user.username === this.props.username; return ( - - - {optionsOpen && ( -
      -
    • - -
    • - {userIsOwner && ( -
    • - -
    • - )} - {userIsOwner && ( -
    • - -
    • - )} -
    + + > + + {this.props.t('CollectionListRow.AddSketch')} + + + {this.props.t('CollectionListRow.Delete')} + + + {this.props.t('CollectionListRow.Rename')} + + ); }; diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx index bce30da1dc..85d3030d61 100644 --- a/client/modules/IDE/components/SketchList.jsx +++ b/client/modules/IDE/components/SketchList.jsx @@ -7,6 +7,8 @@ import { Link } from 'react-router-dom'; import { bindActionCreators } from 'redux'; import classNames from 'classnames'; import slugify from 'slugify'; +import MenuItem from '../../../components/Dropdown/MenuItem'; +import TableDropdown from '../../../components/Dropdown/TableDropdown'; import dates from '../../../utils/formatDate'; import * as ProjectActions from '../actions/project'; import * as ProjectsActions from '../actions/projects'; @@ -22,8 +24,6 @@ import getConfig from '../../../utils/getConfig'; import ArrowUpIcon from '../../../images/sort-arrow-up.svg'; import ArrowDownIcon from '../../../images/sort-arrow-down.svg'; -import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg'; -import MoreIconSvg from '../../../images/more.svg'; const ROOT_URL = getConfig('API_URL'); @@ -34,47 +34,12 @@ class SketchListRowBase extends React.Component { constructor(props) { super(props); this.state = { - optionsOpen: false, renameOpen: false, - renameValue: props.sketch.name, - isFocused: false + renameValue: props.sketch.name }; this.renameInput = React.createRef(); } - onFocusComponent = () => { - this.setState({ isFocused: true }); - }; - - onBlurComponent = () => { - this.setState({ isFocused: false }); - setTimeout(() => { - if (!this.state.isFocused) { - this.closeAll(); - } - }, 200); - }; - - openOptions = () => { - this.setState({ - optionsOpen: true - }); - }; - - closeOptions = () => { - this.setState({ - optionsOpen: false - }); - }; - - toggleOptions = () => { - if (this.state.optionsOpen) { - this.closeOptions(); - } else { - this.openOptions(); - } - }; - openRename = () => { this.setState( { @@ -91,13 +56,6 @@ class SketchListRowBase extends React.Component { }); }; - closeAll = () => { - this.setState({ - renameOpen: false, - optionsOpen: false - }); - }; - handleRenameChange = (e) => { this.setState({ renameValue: e.target.value @@ -107,13 +65,13 @@ class SketchListRowBase extends React.Component { handleRenameEnter = (e) => { if (e.key === 'Enter') { this.updateName(); - this.closeAll(); + this.closeRename(); } }; handleRenameBlur = () => { this.updateName(); - this.closeAll(); + this.closeRename(); }; updateName = () => { @@ -126,23 +84,6 @@ class SketchListRowBase extends React.Component { } }; - resetSketchName = () => { - this.setState({ - renameValue: this.props.sketch.name, - renameOpen: false - }); - }; - - handleDropdownOpen = () => { - this.closeAll(); - this.openOptions(); - }; - - handleRenameOpen = () => { - this.closeAll(); - this.openRename(); - }; - handleSketchDownload = () => { const { sketch } = this.props; const downloadLink = document.createElement('a'); @@ -154,12 +95,10 @@ class SketchListRowBase extends React.Component { }; handleSketchDuplicate = () => { - this.closeAll(); this.props.cloneProject(this.props.sketch); }; handleSketchShare = () => { - this.closeAll(); this.props.showShareModal( this.props.sketch.id, this.props.sketch.name, @@ -168,7 +107,6 @@ class SketchListRowBase extends React.Component { }; handleSketchDelete = () => { - this.closeAll(); if ( window.confirm( this.props.t('Common.DeleteConfirmation', { @@ -180,106 +118,42 @@ class SketchListRowBase extends React.Component { } }; - renderViewButton = (sketchURL) => ( - - {this.props.t('SketchList.View')} - - ); - renderDropdown = () => { - const { optionsOpen } = this.state; const userIsOwner = this.props.user.username === this.props.username; return ( - - {optionsOpen && ( -
      - {userIsOwner && ( -
    • - -
    • - )} -
    • - -
    • - {this.props.user.authenticated && ( -
    • - -
    • - )} - {this.props.user.authenticated && ( -
    • - -
    • - )} - {/*
    • - -
    • */} - {userIsOwner && ( -
    • - -
    • - )} -
    - )} + + + {this.props.t('SketchList.DropdownRename')} + + + {this.props.t('SketchList.DropdownDownload')} + + + {this.props.t('SketchList.DropdownDuplicate')} + + { + this.props.onAddToCollection(); + }} + > + {this.props.t('SketchList.DropdownAddToCollection')} + + + {/* + + Share + + */} + + {this.props.t('SketchList.DropdownDelete')} + + ); }; diff --git a/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap b/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap index bd7475ebf9..63a4542d36 100644 --- a/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap +++ b/client/modules/IDE/components/__snapshots__/SketchList.unit.test.jsx.snap @@ -85,15 +85,19 @@ exports[` snapshot testing 1`] = ` - + + snapshot testing 1`] = ` - + + diff --git a/client/styles/components/_asset-list.scss b/client/styles/components/_asset-list.scss index 6f7c035993..7d8f6065e8 100644 --- a/client/styles/components/_asset-list.scss +++ b/client/styles/components/_asset-list.scss @@ -76,24 +76,3 @@ background-color: getThemifyVariable('background-color'); } } - -.asset-table__dropdown-button { - width:#{25 / $base-font-size}rem; - height:#{25 / $base-font-size}rem; - - @include themify() { - & polygon, & path { - fill: getThemifyVariable('inactive-text-color'); - } - } -} - -.asset-table__action-dialogue { - @extend %dropdown-open-right; - top: 63%; - right: calc(100% - 26px); -} - -.asset-table__action-option { - font-size: #{12 / $base-font-size}rem; -} diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss index 69d41bdca4..315b10712f 100644 --- a/client/styles/components/_sketch-list.scss +++ b/client/styles/components/_sketch-list.scss @@ -169,17 +169,6 @@ font-weight: normal; } -.sketch-list__dropdown-button { - width: #{25 / $base-font-size}rem; - height: #{25 / $base-font-size}rem; - @include themify() { - & polygon, - & path { - fill: getThemifyVariable("inactive-text-color"); - } - } -} - .sketches-table__name { display: flex; align-items: center; @@ -189,12 +178,6 @@ width: #{35 / $base-font-size}rem; } -.sketch-list__action-dialogue { - @extend %dropdown-open-right; - top: 63%; - right: calc(100% - 26px); -} - .sketches-table__empty { text-align: center; font-size: #{16 / $base-font-size}rem; From 4ffbb42af973c902638a0bc50eb756fe6489eadf Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Wed, 16 Aug 2023 12:30:27 -0500 Subject: [PATCH 028/118] add setTimeout to close --- client/components/Dropdown/DropdownMenu.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/components/Dropdown/DropdownMenu.jsx b/client/components/Dropdown/DropdownMenu.jsx index ce7e03837e..0e18207f26 100644 --- a/client/components/Dropdown/DropdownMenu.jsx +++ b/client/components/Dropdown/DropdownMenu.jsx @@ -50,7 +50,9 @@ const DropdownMenu = forwardRef( { + setTimeout(close, 0); + }} onBlur={handleBlur} onFocus={handleFocus} > From c9cca4a0182647fd27b58c2ba0b1cc8180043dc7 Mon Sep 17 00:00:00 2001 From: Linda Paiste Date: Sun, 17 Sep 2023 16:58:59 -0500 Subject: [PATCH 029/118] Apply new responsive styles --- client/components/Dropdown/DropdownMenu.jsx | 19 +++++++++--- client/components/Dropdown/TableDropdown.jsx | 30 ++++++++++++++++++- .../SketchList.unit.test.jsx.snap | 27 +++++++++++++++-- client/styles/components/_sketch-list.scss | 7 +---- 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/client/components/Dropdown/DropdownMenu.jsx b/client/components/Dropdown/DropdownMenu.jsx index 0e18207f26..da41b30101 100644 --- a/client/components/Dropdown/DropdownMenu.jsx +++ b/client/components/Dropdown/DropdownMenu.jsx @@ -7,7 +7,10 @@ import { DropdownWrapper } from '../Dropdown'; // TODO: enable arrow keys to navigate options from list const DropdownMenu = forwardRef( - ({ children, 'aria-label': ariaLabel, align, className, classes }, ref) => { + ( + { children, anchor, 'aria-label': ariaLabel, align, className, classes }, + ref + ) => { // Note: need to use a ref instead of a state to avoid stale closures. const focusedRef = useRef(false); @@ -44,7 +47,7 @@ const DropdownMenu = forwardRef( onBlur={handleBlur} onFocus={handleFocus} > -