diff --git a/front/cypress/e2e/routes/dashboard/Dashboard.cy.js b/front/cypress/e2e/routes/dashboard/Dashboard.cy.js index 6b77ac2ddf..f48c4b0ea9 100644 --- a/front/cypress/e2e/routes/dashboard/Dashboard.cy.js +++ b/front/cypress/e2e/routes/dashboard/Dashboard.cy.js @@ -4,8 +4,10 @@ describe('Dashboard', () => { }); it('Should create new dashboard', () => { cy.visit('/dashboard'); - cy.contains('dashboard.newDashboardButton') - .should('have.class', 'btn-outline-success') + + cy.get('a') + .contains('dashboard.newDashboardButton') + .should('have.class', 'btn-success') .click(); cy.url().should('eq', `${Cypress.config().baseUrl}/dashboard/create/new`); @@ -20,12 +22,9 @@ describe('Dashboard', () => { .should('have.class', 'btn-primary') .click(); - cy.url().should('eq', `${Cypress.config().baseUrl}/dashboard/my-new-dashboard`); + cy.url().should('eq', `${Cypress.config().baseUrl}/dashboard/my-new-dashboard/edit`); }); it('Should add new boxes', () => { - cy.contains('dashboard.editDashboardButton') - .should('have.class', 'btn-outline-primary') - .click(); cy.get('select').then(inputs => { cy.wrap(inputs[0]).select('user-presence'); cy.get('button').then(inputs => { @@ -51,5 +50,9 @@ describe('Dashboard', () => { cy.contains('dashboard.editDashboardDeleteButton') .should('have.class', 'btn-outline-danger') .click(); + cy.contains('dashboard.editDashboardDeleteButton') + .should('have.class', 'btn-outline-danger') + .click(); + cy.url().should('eq', `${Cypress.config().baseUrl}/dashboard`); }); }); diff --git a/front/package-lock.json b/front/package-lock.json index 543a423843..3054c1c03a 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -31,6 +31,9 @@ "react-big-calendar": "^0.40.0", "react-clock": "^3.1.0", "react-datepicker": "^3.8.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dnd-touch-backend": "^16.0.1", "react-select": "^4.3.1", "unistore": "^3.5.2", "useragent-parser-js": "^1.0.3", @@ -3573,11 +3576,14 @@ } }, "node_modules/@babel/runtime": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", - "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dependencies": { - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/template": { @@ -3861,22 +3867,6 @@ } } }, - "node_modules/@emotion/react/node_modules/@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emotion/react/node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, "node_modules/@emotion/serialize": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", @@ -3999,17 +3989,6 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4349,12 +4328,12 @@ } }, "node_modules/@preact/async-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@preact/async-loader/-/async-loader-3.0.1.tgz", - "integrity": "sha512-BoUN24hxEfAQYnWjliAmkZLuliv+ONQi7AWn+/+VOJHTIHmbFiXrvmSxITf7PDkKiK0a5xy4OErZtVVLlk96Tg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@preact/async-loader/-/async-loader-3.0.2.tgz", + "integrity": "sha512-nYIdlAGbZ0+0/u5VJxQdLDgNFgEJmNLzctuqnCBZxW/EpLPMg8lcsnRsoXVl+O28ZZYhVhos3XiWM3KtuN0C3Q==", "dev": true, "dependencies": { - "kleur": "^4.0.2", + "kleur": "^4.1.4", "loader-utils": "^2.0.0" }, "engines": { @@ -4400,6 +4379,21 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, "node_modules/@relative-ci/agent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@relative-ci/agent/-/agent-2.0.0.tgz", @@ -5008,7 +5002,7 @@ "version": "16.3.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.2.tgz", "integrity": "sha512-jJs9ErFLP403I+hMLGnqDRWT0RYKSvArxuBVh2veudHV7ifEC1WAmjJADacZ7mRbA2nWgHtn8xyECMAot0SkAw==", - "dev": true + "devOptional": true }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -7457,18 +7451,6 @@ "npm": ">=6" } }, - "node_modules/babel-plugin-macros/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==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-plugin-macros/node_modules/is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -7487,12 +7469,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/babel-plugin-macros/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==", - "dev": true - }, "node_modules/babel-plugin-macros/node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -8378,9 +8354,45 @@ "dev": true }, "node_modules/builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/node_modules/lru-cache": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "node_modules/bytes": { @@ -11952,6 +11964,16 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -12821,18 +12843,6 @@ "node": ">=4.0" } }, - "node_modules/eslint-config-preact/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-config-preact/node_modules/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -13508,18 +13518,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-plugin-react/node_modules/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -13977,17 +13975,6 @@ "node": ">= 0.8.0" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -19410,9 +19397,9 @@ "dev": true }, "node_modules/kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, "engines": { "node": ">=6" @@ -20652,9 +20639,9 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -20824,9 +20811,9 @@ } }, "node_modules/mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, "engines": { "node": ">=4" @@ -25187,9 +25174,9 @@ } }, "node_modules/preact-cli": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/preact-cli/-/preact-cli-3.3.5.tgz", - "integrity": "sha512-qtIk8WtheEoY192UoKFQD14cw5CoUnYs9A+gIL95H/WT4aw8Z4CvxsB6+eELMZnsruakkq7OQMd0xRrfyoZNgA==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/preact-cli/-/preact-cli-3.4.5.tgz", + "integrity": "sha512-pLTawiXDy4rEct5ul0mDCP92GB6NK/QFhpoR+iHZJqgkeyE25qEXPf1/tJhAiijphDL5kxGvsT4qA6SrpQ5BsQ==", "dev": true, "dependencies": { "@babel/core": "^7.13.16", @@ -25201,22 +25188,23 @@ "@babel/plugin-transform-react-jsx": "^7.13.12", "@babel/preset-env": "^7.13.15", "@babel/preset-typescript": "^7.13.0", - "@preact/async-loader": "^3.0.1", + "@preact/async-loader": "^3.0.2", "@prefresh/babel-plugin": "^0.4.1", "@prefresh/webpack": "^3.2.2", "@types/webpack": "^4.38.0", - "autoprefixer": "^10.2.5", + "autoprefixer": "^10.4.7", "babel-esm-plugin": "^0.9.0", - "babel-loader": "^8.2.2", + "babel-loader": "^8.2.5", "babel-plugin-macros": "^3.1.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "browserslist": "^4.16.4", - "compression-webpack-plugin": "^6.0.4", + "browserslist": "^4.20.3", + "compression-webpack-plugin": "^6.1.1", "console-clear": "^1.0.0", - "copy-webpack-plugin": "^6.2.1", + "copy-webpack-plugin": "^6.4.0", "critters-webpack-plugin": "^2.5.0", "cross-spawn-promise": "^0.10.1", - "css-loader": "^5.2.4", + "css-loader": "^5.2.7", + "dotenv": "^16.0.0", "ejs-loader": "^0.5.0", "envinfo": "^7.8.1", "esm": "^3.2.25", @@ -25224,54 +25212,56 @@ "fork-ts-checker-webpack-plugin": "^4.0.4", "get-port": "^5.0.0", "gittar": "^0.1.0", - "glob": "^7.1.4", + "glob": "^8.0.3", "html-webpack-exclude-assets-plugin": "0.0.7", "html-webpack-plugin": "^3.2.0", - "ip": "^1.1.5", + "ip": "^1.1.8", "isomorphic-unfetch": "^3.1.0", "kleur": "^4.1.4", "loader-utils": "^2.0.0", - "mini-css-extract-plugin": "^1.5.0", + "mini-css-extract-plugin": "^1.6.2", "minimatch": "^3.0.3", "native-url": "0.3.4", - "optimize-css-assets-webpack-plugin": "^6.0.0", - "ora": "^5.4.0", - "pnp-webpack-plugin": "^1.6.4", - "postcss": "^8.2.10", - "postcss-load-config": "^3.0.1", - "postcss-loader": "^4.0.4", + "optimize-css-assets-webpack-plugin": "^6.0.1", + "ora": "^5.4.1", + "pnp-webpack-plugin": "^1.7.0", + "postcss": "^8.4.13", + "postcss-load-config": "^3.1.4", + "postcss-loader": "^4.2.0", "progress-bar-webpack-plugin": "^2.1.0", - "promise-polyfill": "^8.2.0", - "prompts": "^2.4.1", + "promise-polyfill": "^8.2.3", + "prompts": "^2.4.2", "raw-loader": "^4.0.2", "react-refresh": "0.10.0", "rimraf": "^3.0.2", - "sade": "^1.7.4", + "sade": "^1.8.1", "size-plugin": "^3.0.0", "source-map": "^0.7.2", + "source-map-loader": "^1.1.1", "stack-trace": "0.0.10", "style-loader": "^2.0.0", "terser-webpack-plugin": "^4.2.3", - "typescript": "~4.2.4", + "typescript": "~4.6.4", "update-notifier": "^5.1.0", "url-loader": "^4.1.1", - "validate-npm-package-name": "^3.0.0", - "webpack": "^4.38.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-dev-server": "^4.7.3", + "validate-npm-package-name": "^4.0.0", + "webpack": "^4.44.2", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.0", "webpack-fix-style-only-entries": "^0.6.1", - "webpack-merge": "^5.3.0", + "webpack-manifest-plugin": "^4.1.1", + "webpack-merge": "^5.8.0", "webpack-plugin-replace": "^1.2.0", "which": "^2.0.2", - "workbox-cacheable-response": "^6.1.5", - "workbox-core": "^6.1.5", - "workbox-precaching": "^6.1.5", - "workbox-routing": "^6.1.5", - "workbox-strategies": "^6.1.5", - "workbox-webpack-plugin": "^6.1.5" + "workbox-cacheable-response": "^6.5.3", + "workbox-core": "^6.5.3", + "workbox-precaching": "^6.5.3", + "workbox-routing": "^6.5.3", + "workbox-strategies": "^6.5.3", + "workbox-webpack-plugin": "^6.5.3" }, "bin": { - "preact": "lib/index.js" + "preact": "src/index.js" }, "engines": { "node": ">=12" @@ -25295,6 +25285,55 @@ } } }, + "node_modules/preact-cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/preact-cli/node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/preact-cli/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/preact-cli/node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/preact-cli/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -25310,6 +25349,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/preact-cli/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/preact-cli/node_modules/source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -26051,17 +26110,6 @@ "react-dom": "^16.14.0 || ^17" } }, - "node_modules/react-big-calendar/node_modules/@babel/runtime": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", - "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/react-big-calendar/node_modules/csstype": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", @@ -26096,11 +26144,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/react-big-calendar/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==" - }, "node_modules/react-clock": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/react-clock/-/react-clock-3.1.0.tgz", @@ -26135,6 +26178,52 @@ "react-dom": "^16.9.0 || ^17" } }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, + "node_modules/react-dnd-touch-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-touch-backend/-/react-dnd-touch-backend-16.0.1.tgz", + "integrity": "sha512-NonoCABzzjyWGZuDxSG77dbgMZ2Wad7eQiCd/ECtsR2/NBLTjGksPUx9UPezZ1nQ/L7iD130Tz3RUshL/ClKLA==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "dnd-core": "^16.0.1" + } + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -26202,17 +26291,6 @@ "react-dom": ">=16.3.0" } }, - "node_modules/react-overlays/node_modules/@babel/runtime": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", - "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/react-overlays/node_modules/csstype": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", @@ -26227,11 +26305,6 @@ "csstype": "^3.0.2" } }, - "node_modules/react-overlays/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==" - }, "node_modules/react-popper": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", @@ -26276,27 +26349,11 @@ "react-dom": "^16.8.0 || ^17.0.0" } }, - "node_modules/react-select/node_modules/@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/react-select/node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, - "node_modules/react-select/node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, "node_modules/react-transition-group": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", @@ -26390,6 +26447,14 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -26409,9 +26474,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + "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", @@ -26422,24 +26487,6 @@ "@babel/runtime": "^7.8.4" } }, - "node_modules/regenerator-transform/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==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/regenerator-transform/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==", - "dev": true - }, "node_modules/regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", @@ -27067,15 +27114,15 @@ } }, "node_modules/sade": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", - "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "dependencies": { "mri": "^1.1.0" }, "engines": { - "node": ">= 6" + "node": ">=6" } }, "node_modules/safe-buffer": { @@ -28272,6 +28319,106 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-loader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.1.3.tgz", + "integrity": "sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.2", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "source-map": "^0.6.1", + "whatwg-mimetype": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/source-map-loader/node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/source-map-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/source-map-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/source-map-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/source-map-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", @@ -30329,9 +30476,9 @@ } }, "node_modules/typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -31180,12 +31327,15 @@ } }, "node_modules/validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "builtins": "^1.0.3" + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/vary": { @@ -32289,6 +32439,53 @@ "node": ">= 6" } }, + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dev": true, + "dependencies": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webpack-merge": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", @@ -33211,18 +33408,6 @@ "node": ">=10.0.0" } }, - "node_modules/workbox-build/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==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/workbox-build/node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -33247,12 +33432,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/workbox-build/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==", - "dev": true - }, "node_modules/workbox-build/node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -36237,11 +36416,11 @@ } }, "@babel/runtime": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", - "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "requires": { - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.11" } }, "@babel/template": { @@ -36462,21 +36641,6 @@ "@emotion/utils": "^1.0.0", "@emotion/weak-memoize": "^0.2.5", "hoist-non-react-statics": "^3.3.1" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - } } }, "@emotion/serialize": { @@ -36579,14 +36743,6 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -36877,12 +37033,12 @@ "integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==" }, "@preact/async-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@preact/async-loader/-/async-loader-3.0.1.tgz", - "integrity": "sha512-BoUN24hxEfAQYnWjliAmkZLuliv+ONQi7AWn+/+VOJHTIHmbFiXrvmSxITf7PDkKiK0a5xy4OErZtVVLlk96Tg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@preact/async-loader/-/async-loader-3.0.2.tgz", + "integrity": "sha512-nYIdlAGbZ0+0/u5VJxQdLDgNFgEJmNLzctuqnCBZxW/EpLPMg8lcsnRsoXVl+O28ZZYhVhos3XiWM3KtuN0C3Q==", "dev": true, "requires": { - "kleur": "^4.0.2", + "kleur": "^4.1.4", "loader-utils": "^2.0.0" } }, @@ -36915,6 +37071,21 @@ "@prefresh/utils": "^1.1.2" } }, + "@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, "@relative-ci/agent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@relative-ci/agent/-/agent-2.0.0.tgz", @@ -37372,7 +37543,7 @@ "version": "16.3.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.2.tgz", "integrity": "sha512-jJs9ErFLP403I+hMLGnqDRWT0RYKSvArxuBVh2veudHV7ifEC1WAmjJADacZ7mRbA2nWgHtn8xyECMAot0SkAw==", - "dev": true + "devOptional": true }, "@types/parse-json": { "version": "4.0.0", @@ -39323,15 +39494,6 @@ "resolve": "^1.19.0" }, "dependencies": { - "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -39347,12 +39509,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "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==", - "dev": true - }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -40089,10 +40245,39 @@ "dev": true }, "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + }, + "dependencies": { + "lru-cache": { + "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" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } }, "bytes": { "version": "3.0.0", @@ -42907,6 +43092,16 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "requires": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -43581,14 +43776,6 @@ "type-check": "~0.4.0" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -43821,15 +44008,6 @@ "object.assign": "^4.1.2" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -44298,15 +44476,6 @@ "has-tostringtag": "^1.0.0" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -48744,9 +48913,9 @@ } }, "kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true }, "klona": { @@ -49754,9 +49923,9 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } @@ -49898,9 +50067,9 @@ } }, "mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true }, "ms": { @@ -53139,9 +53308,9 @@ "integrity": "sha512-GLjn0I3r6ka+NvxJUppsVFqb4V0qDTEHT/QxHlidPuClGaxF/4AI2Qti4a0cv3XMh5n1+D3hLScW10LRIm5msQ==" }, "preact-cli": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/preact-cli/-/preact-cli-3.3.5.tgz", - "integrity": "sha512-qtIk8WtheEoY192UoKFQD14cw5CoUnYs9A+gIL95H/WT4aw8Z4CvxsB6+eELMZnsruakkq7OQMd0xRrfyoZNgA==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/preact-cli/-/preact-cli-3.4.5.tgz", + "integrity": "sha512-pLTawiXDy4rEct5ul0mDCP92GB6NK/QFhpoR+iHZJqgkeyE25qEXPf1/tJhAiijphDL5kxGvsT4qA6SrpQ5BsQ==", "dev": true, "requires": { "@babel/core": "^7.13.16", @@ -53153,22 +53322,23 @@ "@babel/plugin-transform-react-jsx": "^7.13.12", "@babel/preset-env": "^7.13.15", "@babel/preset-typescript": "^7.13.0", - "@preact/async-loader": "^3.0.1", + "@preact/async-loader": "^3.0.2", "@prefresh/babel-plugin": "^0.4.1", "@prefresh/webpack": "^3.2.2", "@types/webpack": "^4.38.0", - "autoprefixer": "^10.2.5", + "autoprefixer": "^10.4.7", "babel-esm-plugin": "^0.9.0", - "babel-loader": "^8.2.2", + "babel-loader": "^8.2.5", "babel-plugin-macros": "^3.1.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "browserslist": "^4.16.4", - "compression-webpack-plugin": "^6.0.4", + "browserslist": "^4.20.3", + "compression-webpack-plugin": "^6.1.1", "console-clear": "^1.0.0", - "copy-webpack-plugin": "^6.2.1", + "copy-webpack-plugin": "^6.4.0", "critters-webpack-plugin": "^2.5.0", "cross-spawn-promise": "^0.10.1", - "css-loader": "^5.2.4", + "css-loader": "^5.2.7", + "dotenv": "^16.0.0", "ejs-loader": "^0.5.0", "envinfo": "^7.8.1", "esm": "^3.2.25", @@ -53176,53 +53346,94 @@ "fork-ts-checker-webpack-plugin": "^4.0.4", "get-port": "^5.0.0", "gittar": "^0.1.0", - "glob": "^7.1.4", + "glob": "^8.0.3", "html-webpack-exclude-assets-plugin": "0.0.7", "html-webpack-plugin": "^3.2.0", - "ip": "^1.1.5", + "ip": "^1.1.8", "isomorphic-unfetch": "^3.1.0", "kleur": "^4.1.4", "loader-utils": "^2.0.0", - "mini-css-extract-plugin": "^1.5.0", + "mini-css-extract-plugin": "^1.6.2", "minimatch": "^3.0.3", "native-url": "0.3.4", - "optimize-css-assets-webpack-plugin": "^6.0.0", - "ora": "^5.4.0", - "pnp-webpack-plugin": "^1.6.4", - "postcss": "^8.2.10", - "postcss-load-config": "^3.0.1", - "postcss-loader": "^4.0.4", + "optimize-css-assets-webpack-plugin": "^6.0.1", + "ora": "^5.4.1", + "pnp-webpack-plugin": "^1.7.0", + "postcss": "^8.4.13", + "postcss-load-config": "^3.1.4", + "postcss-loader": "^4.2.0", "progress-bar-webpack-plugin": "^2.1.0", - "promise-polyfill": "^8.2.0", - "prompts": "^2.4.1", + "promise-polyfill": "^8.2.3", + "prompts": "^2.4.2", "raw-loader": "^4.0.2", "react-refresh": "0.10.0", "rimraf": "^3.0.2", - "sade": "^1.7.4", + "sade": "^1.8.1", "size-plugin": "^3.0.0", "source-map": "^0.7.2", + "source-map-loader": "^1.1.1", "stack-trace": "0.0.10", "style-loader": "^2.0.0", "terser-webpack-plugin": "^4.2.3", - "typescript": "~4.2.4", + "typescript": "~4.6.4", "update-notifier": "^5.1.0", "url-loader": "^4.1.1", - "validate-npm-package-name": "^3.0.0", - "webpack": "^4.38.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-dev-server": "^4.7.3", + "validate-npm-package-name": "^4.0.0", + "webpack": "^4.44.2", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.0", "webpack-fix-style-only-entries": "^0.6.1", - "webpack-merge": "^5.3.0", + "webpack-manifest-plugin": "^4.1.1", + "webpack-merge": "^5.8.0", "webpack-plugin-replace": "^1.2.0", "which": "^2.0.2", - "workbox-cacheable-response": "^6.1.5", - "workbox-core": "^6.1.5", - "workbox-precaching": "^6.1.5", - "workbox-routing": "^6.1.5", - "workbox-strategies": "^6.1.5", - "workbox-webpack-plugin": "^6.1.5" + "workbox-cacheable-response": "^6.5.3", + "workbox-core": "^6.5.3", + "workbox-precaching": "^6.5.3", + "workbox-routing": "^6.5.3", + "workbox-strategies": "^6.5.3", + "workbox-webpack-plugin": "^6.5.3" }, "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -53230,6 +53441,22 @@ "dev": true, "requires": { "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "source-map": { @@ -53819,14 +54046,6 @@ "uncontrollable": "^7.2.1" }, "dependencies": { - "@babel/runtime": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", - "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "csstype": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", @@ -53860,11 +54079,6 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "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==" } } }, @@ -53891,6 +54105,35 @@ "react-popper": "^1.3.8" } }, + "react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "requires": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + } + }, + "react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "requires": { + "dnd-core": "^16.0.1" + } + }, + "react-dnd-touch-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-touch-backend/-/react-dnd-touch-backend-16.0.1.tgz", + "integrity": "sha512-NonoCABzzjyWGZuDxSG77dbgMZ2Wad7eQiCd/ECtsR2/NBLTjGksPUx9UPezZ1nQ/L7iD130Tz3RUshL/ClKLA==", + "requires": { + "@react-dnd/invariant": "^4.0.1", + "dnd-core": "^16.0.1" + } + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -53941,14 +54184,6 @@ "warning": "^4.0.3" }, "dependencies": { - "@babel/runtime": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", - "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "csstype": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", @@ -53962,11 +54197,6 @@ "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } - }, - "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==" } } }, @@ -54004,23 +54234,10 @@ "react-transition-group": "^4.3.0" }, "dependencies": { - "@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" } } }, @@ -54097,6 +54314,14 @@ "picomatch": "^2.2.1" } }, + "redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -54113,9 +54338,9 @@ } }, "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + "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", @@ -54124,23 +54349,6 @@ "dev": true, "requires": { "@babel/runtime": "^7.8.4" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "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==", - "dev": true - } } }, "regex-cache": { @@ -54630,9 +54838,9 @@ } }, "sade": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", - "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "requires": { "mri": "^1.1.0" @@ -55625,6 +55833,79 @@ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, + "source-map-loader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.1.3.tgz", + "integrity": "sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.2", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "source-map": "^0.6.1", + "whatwg-mimetype": "^2.3.0" + }, + "dependencies": { + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", @@ -57221,9 +57502,9 @@ } }, "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "uglify-js": { @@ -57867,12 +58148,12 @@ } }, "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "requires": { - "builtins": "^1.0.3" + "builtins": "^5.0.0" } }, "vary": { @@ -59255,6 +59536,40 @@ "uuid": "^3.3.2" } }, + "webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dev": true, + "requires": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + } + } + }, "webpack-merge": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", @@ -59519,15 +59834,6 @@ "workbox-window": "6.5.3" }, "dependencies": { - "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -59546,12 +59852,6 @@ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true }, - "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==", - "dev": true - }, "source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", diff --git a/front/package.json b/front/package.json index 11f91ed621..34feb404df 100644 --- a/front/package.json +++ b/front/package.json @@ -69,6 +69,9 @@ "react-big-calendar": "^0.40.0", "react-clock": "^3.1.0", "react-datepicker": "^3.8.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dnd-touch-backend": "^16.0.1", "react-select": "^4.3.1", "unistore": "^3.5.2", "useragent-parser-js": "^1.0.3", diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index 82a6de31ac..69f7f49788 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -36,8 +36,11 @@ import SignupPreferences from '../routes/signup/3-preferences'; import SignupConfigureHouse from '../routes/signup/4-configure-house'; import SignupSuccess from '../routes/signup/5-success'; +// Dashboard import Dashboard from '../routes/dashboard'; import NewDashboard from '../routes/dashboard/new-dashboard'; +import EditDashboard from '../routes/dashboard/edit-dashboard'; + import Device from '../routes/device'; import IntegrationPage from '../routes/integration'; import ChatPage from '../routes/chat'; @@ -184,6 +187,7 @@ const AppRouter = connect( + diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 2c27914095..9d5cf8d0bb 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -196,6 +196,7 @@ "noDashboardSentenceBottom": "Click on the \"New\" button to create a new dashboard", "gatewayInstanceNotFoundError": "Your Gladys instance is not connected to the Gladys Gateway", "editDashboardNameLabel": "Name", + "editDashboardMyDashboards": "My dashboards", "boxTitle": { "weather": "Weather", "temperature-in-room": "Temperature in room", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index d9b41f7b4c..26e9e5a24b 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -196,6 +196,7 @@ "noDashboardSentenceBottom": "Cliquez sur le bouton \"Nouveau\" pour créer un tableau de bord.", "gatewayInstanceNotFoundError": "Votre instance Gladys n'est pas connectée à Gladys Plus.", "editDashboardNameLabel": "Nom", + "editDashboardMyDashboards": "Mes tableaux de bords", "boxTitle": { "weather": "Météo", "temperature-in-room": "Température de la pièce", diff --git a/front/src/routes/dashboard/DashboardPage.jsx b/front/src/routes/dashboard/DashboardPage.jsx index 4e5aab4640..46d6dde074 100644 --- a/front/src/routes/dashboard/DashboardPage.jsx +++ b/front/src/routes/dashboard/DashboardPage.jsx @@ -2,16 +2,10 @@ import { Text } from 'preact-i18n'; import { Link } from 'preact-router/match'; import cx from 'classnames'; import BoxColumns from './BoxColumns'; -import EditBoxColumns from './EditBoxColumns'; import EmptyState from './EmptyState'; -import EditActions from './EditActions'; import style from './style.css'; -const marginBottom = { - marginBottom: '10rem' -}; - const DashboardPage = ({ children, ...props }) => (
@@ -19,92 +13,62 @@ const DashboardPage = ({ children, ...props }) => (
-
- {!props.dashboardEditMode && ( - + )} +
+ +
+ {!props.dashboardNotConfigured && props.browserFullScreenCompatible && false && ( +
+ + )} + {props.currentDashboard && ( + + )}
- )} +
+ {props.gatewayInstanceNotFound && (
)} - {props.dashboardNotConfigured && !props.dashboardEditMode && ( - - )} - {!props.dashboardNotConfigured && !props.dashboardEditMode && ( - - )} - {props.dashboardEditMode && ( - - )} - {props.dashboardEditMode && } + {props.dashboardNotConfigured && } + {!props.dashboardNotConfigured && }
diff --git a/front/src/routes/dashboard/EmptyState.jsx b/front/src/routes/dashboard/EmptyState.jsx index 8df2c0db67..67d6de9182 100644 --- a/front/src/routes/dashboard/EmptyState.jsx +++ b/front/src/routes/dashboard/EmptyState.jsx @@ -1,4 +1,5 @@ import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; import style from './style.css'; const EmptyState = ({ children, ...props }) => ( @@ -9,6 +10,11 @@ const EmptyState = ({ children, ...props }) => (
{!props.dashboardListEmpty && } {props.dashboardListEmpty && }

+ {props.dashboardListEmpty && ( + + + + )} ); diff --git a/front/src/routes/dashboard/EditActions.jsx b/front/src/routes/dashboard/edit-dashboard/EditActions.jsx similarity index 100% rename from front/src/routes/dashboard/EditActions.jsx rename to front/src/routes/dashboard/edit-dashboard/EditActions.jsx diff --git a/front/src/routes/dashboard/EditAddBoxButton.jsx b/front/src/routes/dashboard/edit-dashboard/EditAddBoxButton.jsx similarity index 92% rename from front/src/routes/dashboard/EditAddBoxButton.jsx rename to front/src/routes/dashboard/edit-dashboard/EditAddBoxButton.jsx index f1e37f6fd9..c080744b23 100644 --- a/front/src/routes/dashboard/EditAddBoxButton.jsx +++ b/front/src/routes/dashboard/edit-dashboard/EditAddBoxButton.jsx @@ -1,5 +1,5 @@ import { Text } from 'preact-i18n'; -import { DASHBOARD_BOX_TYPE_LIST } from '../../../../server/utils/constants'; +import { DASHBOARD_BOX_TYPE_LIST } from '../../../../../server/utils/constants'; const addBox = (addBoxFunction, x) => () => { addBoxFunction(x); diff --git a/front/src/routes/dashboard/EditBox.jsx b/front/src/routes/dashboard/edit-dashboard/EditBox.jsx similarity index 53% rename from front/src/routes/dashboard/EditBox.jsx rename to front/src/routes/dashboard/edit-dashboard/EditBox.jsx index a6349c84fa..3d281346eb 100644 --- a/front/src/routes/dashboard/EditBox.jsx +++ b/front/src/routes/dashboard/edit-dashboard/EditBox.jsx @@ -1,12 +1,12 @@ -import EditWeatherBox from '../../components/boxs/weather/EditWeatherBox'; -import EditRoomTemperatureBox from '../../components/boxs/room-temperature/EditRoomTemperatureBox'; -import EditRoomHumidityBox from '../../components/boxs/room-humidity/EditRoomHumidityBox'; -import EditCameraBox from '../../components/boxs/camera/EditCamera'; -import EditAtHomeBox from '../../components/boxs/user-presence/EditUserPresenceBox'; -import EditDevicesInRoom from '../../components/boxs/device-in-room/EditDeviceInRoom'; -import EditChart from '../../components/boxs/chart/EditChart'; -import EditEcowatt from '../../components/boxs/ecowatt/EditEcowatt'; -import EditClock from '../../components/boxs/clock/EditClock'; +import EditWeatherBox from '../../../components/boxs/weather/EditWeatherBox'; +import EditRoomTemperatureBox from '../../../components/boxs/room-temperature/EditRoomTemperatureBox'; +import EditRoomHumidityBox from '../../../components/boxs/room-humidity/EditRoomHumidityBox'; +import EditCameraBox from '../../../components/boxs/camera/EditCamera'; +import EditAtHomeBox from '../../../components/boxs/user-presence/EditUserPresenceBox'; +import EditDevicesInRoom from '../../../components/boxs/device-in-room/EditDeviceInRoom'; +import EditChart from '../../../components/boxs/chart/EditChart'; +import EditEcowatt from '../../../components/boxs/ecowatt/EditEcowatt'; +import EditClock from '../../../components/boxs/clock/EditClock'; const Box = ({ children, ...props }) => { switch (props.box.type) { diff --git a/front/src/routes/dashboard/EditBoxColumns.jsx b/front/src/routes/dashboard/edit-dashboard/EditBoxColumns.jsx similarity index 89% rename from front/src/routes/dashboard/EditBoxColumns.jsx rename to front/src/routes/dashboard/edit-dashboard/EditBoxColumns.jsx index c376ae7b12..0cf31560e2 100644 --- a/front/src/routes/dashboard/EditBoxColumns.jsx +++ b/front/src/routes/dashboard/edit-dashboard/EditBoxColumns.jsx @@ -2,13 +2,13 @@ import { Text, Localizer } from 'preact-i18n'; import cx from 'classnames'; import EditBox from './EditBox'; import EditAddBoxButton from './EditAddBoxButton'; -import style from './style.css'; +import style from '../style.css'; const EditBoxColumns = ({ children, ...props }) => (
-

+

-

+ {props.dashboardAlreadyExistError && (
@@ -24,8 +24,8 @@ const EditBoxColumns = ({ children, ...props }) => (
)} -
-
+
+
{props.homeDashboard && + props.homeDashboard.boxes && props.homeDashboard.boxes.map((column, x) => (
( +
+
+
+
+
+
+
+
+
+
+
+

+ +

+
+ + + + +
+
+ {props.currentDashboard && ( + + )} +
+
+
+
+
+ {props.currentDashboard && ( + + )} +
+
+
+
+ + +
+
+
+
+
+
+); + +export default EditDashboard; diff --git a/front/src/routes/dashboard/edit-dashboard/ReorderDashbordList.jsx b/front/src/routes/dashboard/edit-dashboard/ReorderDashbordList.jsx new file mode 100644 index 0000000000..5dc5d97780 --- /dev/null +++ b/front/src/routes/dashboard/edit-dashboard/ReorderDashbordList.jsx @@ -0,0 +1,95 @@ +import { useRef } from 'preact/hooks'; +import { Component } from 'preact'; +import cx from 'classnames'; +import update from 'immutability-helper'; +import { route } from 'preact-router'; +import { DndProvider, useDrag, useDrop } from 'react-dnd'; +import { TouchBackend } from 'react-dnd-touch-backend'; +import { HTML5Backend } from 'react-dnd-html5-backend'; + +const DASHBOARD_LIST_ITEM_TYPE = 'DASHBOARD_LIST_ITEM'; + +const DashboardListItem = ({ children, ...props }) => { + const { index } = props; + const ref = useRef(null); + const [{ isDragging }, drag, preview] = useDrag(() => ({ + type: DASHBOARD_LIST_ITEM_TYPE, + item: () => { + return { index }; + }, + collect: monitor => ({ + isDragging: !!monitor.isDragging() + }) + })); + const [{ isActive }, drop] = useDrop({ + accept: DASHBOARD_LIST_ITEM_TYPE, + collect: monitor => ({ + isActive: monitor.canDrop() && monitor.isOver() + }), + drop(item) { + if (!ref.current) { + return; + } + props.insertAtPosition(item.index, index); + } + }); + const openEditPage = () => { + route(`/dashboard/${props.selector}/edit`); + }; + preview(drop(ref)); + + return ( +
  • + {props.name} +
  • + ); +}; + +class RedorderDashboardList extends Component { + isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; + + insertAtPosition = (sourceIndex, destinationIndex) => { + const { dashboards } = this.props; + const element = dashboards[sourceIndex]; + const newDashboards = update(dashboards, { + $splice: [ + [sourceIndex, 1], + [destinationIndex, 0, element] + ] + }); + this.props.updateDashboardList(newDashboards); + }; + + render({ dashboards, currentDashboard }, {}) { + return ( + +
      + {dashboards && + dashboards.map((dashboard, index) => ( + + ))} +
    +
    + ); + } +} + +export default RedorderDashboardList; diff --git a/front/src/routes/dashboard/edit-dashboard/index.js b/front/src/routes/dashboard/edit-dashboard/index.js new file mode 100644 index 0000000000..c3fa49adc3 --- /dev/null +++ b/front/src/routes/dashboard/edit-dashboard/index.js @@ -0,0 +1,349 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import { route } from 'preact-router'; +import update from 'immutability-helper'; +import EditDashboardPage from './EditDashboard'; +import get from 'get-value'; + +class EditDashboard extends Component { + getDashboards = async () => { + try { + await this.setState({ + getDashboardsError: false, + loading: true + }); + const dashboards = await this.props.httpClient.get('/api/v1/dashboard'); + let currentDashboardSelector; + if (this.props.dashboardSelector) { + currentDashboardSelector = this.props.dashboardSelector; + } else if (dashboards.length > 0) { + currentDashboardSelector = dashboards[0].selector; + } + await this.setState({ + dashboards, + currentDashboardSelector, + getDashboardsError: false, + loading: false + }); + } catch (e) { + console.error(e); + this.setState({ loading: false }); + const status = get(e, 'response.status'); + const errorMessage = get(e, 'response.error_message'); + // in case we are on the gateway (Gladys Plus) + if (status === 404 && errorMessage === 'NO_INSTANCE_FOUND') { + this.setState({ + gatewayInstanceNotFound: true + }); + } else { + this.setState({ + getDashboardsError: true + }); + } + } + }; + + getCurrentDashboard = async () => { + try { + await this.setState({ loading: true }); + const currentDashboard = await this.props.httpClient.get( + `/api/v1/dashboard/${this.state.currentDashboardSelector}` + ); + this.setState({ + currentDashboard, + loading: false + }); + } catch (e) { + this.setState({ + loading: false + }); + console.error(e); + } + }; + + init = async () => { + await this.getDashboards(); + if (this.state.currentDashboardSelector) { + await this.getCurrentDashboard(); + } + }; + + cancelDashboardEdit = async () => { + route(`/dashboard/${this.state.currentDashboardSelector}`); + }; + + moveCard = async (originalX, originalY, destX, destY) => { + // incorrect coordinates + if (destX < 0 || destY < 0) { + return null; + } + if (destX >= this.state.currentDashboard.boxes.length || destY >= this.state.currentDashboard.boxes[destX].length) { + return null; + } + const element = this.state.currentDashboard.boxes[originalX][originalY]; + const newStateWithoutElement = update(this.state, { + currentDashboard: { + boxes: { + [originalX]: { + $splice: [[originalY, 1]] + } + } + } + }); + const newState = update(newStateWithoutElement, { + currentDashboard: { + boxes: { + [destX]: { + $splice: [[destY, 0, element]] + } + } + } + }); + await this.setState(newState); + }; + + moveBoxDown = (x, y) => { + this.moveCard(x, y, x, y + 1); + }; + + moveBoxUp = (x, y) => { + this.moveCard(x, y, x, y - 1); + }; + + addBox = x => { + if (this.state.newSelectedBoxType && this.state.newSelectedBoxType[x]) { + const newState = update(this.state, { + currentDashboard: { + boxes: { + [x]: { + $push: [ + { + type: this.state.newSelectedBoxType[x] + } + ] + } + } + } + }); + this.setState(newState); + } + }; + + removeBox = (x, y) => { + const newState = update(this.state, { + currentDashboard: { + boxes: { + [x]: { + $splice: [[y, 1]] + } + } + } + }); + this.setState(newState); + }; + + updateCurrentDashboardName = e => { + const newState = update(this.state, { + currentDashboard: { + name: { + $set: e.target.value + } + } + }); + this.setState(newState); + }; + + updateBoxConfig = (x, y, data) => { + const newState = update(this.state, { + currentDashboard: { + boxes: { + [x]: { + [y]: { + $merge: data + } + } + } + } + }); + this.setState(newState); + }; + + updateNewSelectedBox = (x, type) => { + const newSelectedBoxType = Object.assign({}, this.state.newSelectedBoxType, { + [x]: type + }); + this.setState({ + newSelectedBoxType + }); + }; + + saveDashboard = async () => { + this.setState({ + loading: true, + dashboardValidationError: false, + dashboardAlreadyExistError: false, + unknownError: false + }); + try { + const { currentDashboard: selectedDashboard, dashboards } = this.state; + const { selector } = selectedDashboard; + + const currentDashboard = await this.props.httpClient.patch( + `/api/v1/dashboard/${selector}`, + this.state.currentDashboard + ); + + const currentDashboardIndex = dashboards.findIndex(d => d.selector === selector); + const updatedDashboards = update(dashboards, { + [currentDashboardIndex]: { + $set: currentDashboard + } + }); + + await this.setState({ + currentDashboard, + loading: false, + dashboards: updatedDashboards + }); + route(`/dashboard/${currentDashboard.selector}`); + } catch (e) { + if (e.response && e.response.status === 422) { + this.setState({ + dashboardValidationError: true + }); + } else if (e.response && e.response.status === 409) { + this.setState({ + dashboardAlreadyExistError: true + }); + } else { + this.setState({ + unknownError: true + }); + } + } + }; + + askDeleteCurrentDashboard = async () => { + await this.setState({ + askDeleteDashboard: true + }); + }; + + cancelDeleteCurrentDashboard = async () => { + await this.setState({ + askDeleteDashboard: false + }); + }; + + deleteCurrentDashboard = async () => { + try { + await this.props.httpClient.delete(`/api/v1/dashboard/${this.state.currentDashboard.selector}`); + const dashboardIndex = this.state.dashboards.findIndex(d => d.id === this.state.currentDashboard.id); + const dashboards = update(this.state.dashboards, { + $splice: [[dashboardIndex, 1]] + }); + const currentDashboard = dashboards.length > 0 ? dashboards[0] : null; + await this.setState({ + askDeleteDashboard: false + }); + if (currentDashboard === null) { + route('/dashboard'); + } else { + route(`/dashboard/${currentDashboard.selector}/edit`); + } + } catch (e) { + console.error(e); + } + }; + + updateDashboardList = async newDashboards => { + await this.setState({ + savingNewDashboardList: true, + dashboards: newDashboards + }); + try { + const dashboardSelectors = this.state.dashboards.map(d => d.selector); + await this.props.httpClient.post('/api/v1/dashboard/order', dashboardSelectors); + } catch (e) { + console.error(e); + } + this.setState({ + savingNewDashboardList: false + }); + }; + + constructor(props) { + super(props); + this.props = props; + this.state = { + dashboards: [], + newSelectedBoxType: {}, + askDeleteDashboard: false + }; + } + + componentDidMount() { + this.init(); + } + + componentDidUpdate(prevProps) { + if (prevProps.currentUrl !== this.props.currentUrl) { + this.init(); + } + } + + render( + props, + { + dashboards, + currentDashboard, + loading, + dashboardValidationError, + dashboardAlreadyExistError, + unknownError, + askDeleteDashboard, + savingNewDashboardList + } + ) { + const dashboardConfigured = + currentDashboard && + currentDashboard.boxes && + ((currentDashboard.boxes[0] && currentDashboard.boxes[0].length > 0) || + (currentDashboard.boxes[1] && currentDashboard.boxes[1].length > 0) || + (currentDashboard.boxes[2] && currentDashboard.boxes[2].length > 0)); + const dashboardListEmpty = !(dashboards && dashboards.length > 0); + const dashboardNotConfigured = !dashboardConfigured; + return ( + + ); + } +} + +export default connect('user,fullScreen,currentUrl,httpClient,gatewayAccountExpired', {})(EditDashboard); diff --git a/front/src/routes/dashboard/index.js b/front/src/routes/dashboard/index.js index 86ac5e7bd3..9b8bba19ba 100644 --- a/front/src/routes/dashboard/index.js +++ b/front/src/routes/dashboard/index.js @@ -11,7 +11,6 @@ extend('$auto', (value, object) => { return object ? update(object, value) : update({}, value); }); -@connect('user,fullScreen,currentUrl,httpClient,gatewayAccountExpired', actions) class Dashboard extends Component { toggleDashboardDropdown = () => { this.setState(prevState => { @@ -88,7 +87,7 @@ class Dashboard extends Component { }; editDashboard = () => { - this.setState(prevState => ({ ...prevState, dashboardEditMode: !prevState.dashboardEditMode })); + route(`/dashboard/${this.state.currentDashboard.selector}/edit`); }; cancelDashboardEdit = async () => { @@ -319,12 +318,45 @@ class Dashboard extends Component { this.props.setFullScreen(isFullScreen); }; + toggleReorderDashboard = () => { + if (this.state.showReorderDashboard) { + this.saveNewDashboardList(); + } else { + this.setState({ showReorderDashboard: !this.state.showReorderDashboard }); + } + }; + + updateDashboardList = newDashboards => { + this.setState({ + dashboards: newDashboards + }); + }; + + saveNewDashboardList = async () => { + await this.setState({ + savingNewDashboardList: true + }); + try { + const dashboardSelectors = this.state.dashboards.map(d => d.selector); + await this.props.httpClient.post('/api/v1/dashboard/order', dashboardSelectors); + this.setState({ + showReorderDashboard: false + }); + } catch (e) { + console.error(e); + } + this.setState({ + savingNewDashboardList: false + }); + }; + constructor(props) { super(props); this.props = props; this.state = { dashboardDropdownOpened: false, dashboardEditMode: false, + showReorderDashboard: false, browserFullScreenCompatible: this.isBrowserFullScreenCompatible(), dashboards: [], newSelectedBoxType: {}, @@ -364,7 +396,9 @@ class Dashboard extends Component { dashboardValidationError, dashboardAlreadyExistError, unknownError, - askDeleteDashboard + askDeleteDashboard, + showReorderDashboard, + savingNewDashboardList } ) { const dashboardConfigured = @@ -411,9 +445,13 @@ class Dashboard extends Component { deleteCurrentDashboard={this.deleteCurrentDashboard} askDeleteDashboard={askDeleteDashboard} fullScreen={props.fullScreen} + showReorderDashboard={showReorderDashboard} + toggleReorderDashboard={this.toggleReorderDashboard} + updateDashboardList={this.updateDashboardList} + savingNewDashboardList={savingNewDashboardList} /> ); } } -export default Dashboard; +export default connect('user,fullScreen,currentUrl,httpClient,gatewayAccountExpired', actions)(Dashboard); diff --git a/front/src/routes/dashboard/new-dashboard/index.js b/front/src/routes/dashboard/new-dashboard/index.js index 5f2da5ca87..03e0a19ca7 100644 --- a/front/src/routes/dashboard/new-dashboard/index.js +++ b/front/src/routes/dashboard/new-dashboard/index.js @@ -1,17 +1,28 @@ import { Component } from 'preact'; import { Text, Localizer } from 'preact-i18n'; import { connect } from 'unistore/preact'; -import { Link } from 'preact-router/match'; import { route } from 'preact-router'; +import { Link } from 'preact-router/match'; import cx from 'classnames'; import { DASHBOARD_TYPE } from '../../../../../server/utils/constants'; import style from './style.css'; const NewDashboardPage = ({ children, ...props }) => (
    - - - +
    +
    + {props.prev && ( + + + + )} + {!props.prev && ( + + + + )} +
    +
    ); -@connect('user,httpClient', {}) class Dashboard extends Component { updateName = e => { this.setState({ name: e.target.value }); }; + goBack = () => { + this.props.history.go(-1); + }; createDashboard = async e => { e.preventDefault(); await this.setState({ @@ -88,7 +101,7 @@ class Dashboard extends Component { }; const createDashboard = await this.props.httpClient.post('/api/v1/dashboard', newDashboard); this.setState({ loading: false, dashboardAlreadyExistError: false, unknownError: false }); - route(`/dashboard/${createDashboard.selector}`); + route(`/dashboard/${createDashboard.selector}/edit`); } catch (e) { if (e.response && e.response.status === 409) { this.setState({ dashboardAlreadyExistError: true }); @@ -116,9 +129,11 @@ class Dashboard extends Component { unknownError={unknownError} updateName={this.updateName} createDashboard={this.createDashboard} + goBack={this.goBack} + prev={props.prev} /> ); } } -export default Dashboard; +export default connect('user,httpClient', {})(Dashboard); diff --git a/front/src/routes/dashboard/new-dashboard/style.css b/front/src/routes/dashboard/new-dashboard/style.css index f5d0c084cf..67d7c9bea1 100644 --- a/front/src/routes/dashboard/new-dashboard/style.css +++ b/front/src/routes/dashboard/new-dashboard/style.css @@ -1,3 +1,10 @@ .containerWithMargin { margin-top: 3rem; } + +@media (max-width: 768px) { + .backButtonDiv { + margin-bottom: 1rem; + max-width: 24rem; + } +} diff --git a/front/src/routes/dashboard/style.css b/front/src/routes/dashboard/style.css index 61fe47589b..a85d039109 100644 --- a/front/src/routes/dashboard/style.css +++ b/front/src/routes/dashboard/style.css @@ -1,6 +1,5 @@ .emptyStateDivBox { - width: 60%; - max-width: 400px; + max-width: 450px; margin-left: auto; margin-right: auto; margin-top: 80px; @@ -19,6 +18,10 @@ margin-top: 20px; } +.largeContainer { + max-width: 1600px; +} + @media (min-width: 992px) { .removePaddingFirstCol { padding-left: 0; @@ -45,3 +48,25 @@ border-radius: 3px; } } + +.collapse { + max-height: 0; + transition: max-height 0.25s ease-out; + overflow: hidden; +} + +.showCollapse { + max-height: 500px; + overflow: auto; + transition: max-height 0.5s ease-in; +} + +.editDashboardText { + display: inline; +} + +@media (max-width: 992px) { + .editDashboardText { + display: none; + } +} diff --git a/server/api/controllers/dashboard.controller.js b/server/api/controllers/dashboard.controller.js index 14fc3d66dc..fcf2b343cf 100644 --- a/server/api/controllers/dashboard.controller.js +++ b/server/api/controllers/dashboard.controller.js @@ -16,7 +16,7 @@ const asyncMiddleware = require('../middlewares/asyncMiddleware'); * @apiSuccess {Array} [boxes] Array of boxes in the dashboard. */ -module.exports = function HouseController(gladys) { +module.exports = function DashboardController(gladys) { /** * @api {post} /api/v1/dashboard create * @apiName createDashoard @@ -52,6 +52,17 @@ module.exports = function HouseController(gladys) { res.json(dashboard); } + /** + * @api {post} /api/v1/dashboard/order updateOrder + * @apiName updateOrder + * @apiGroup Dashboard + * @apiParam {Array} [selectors] Array of selectors in new order. + */ + async function updateOrder(req, res) { + await gladys.dashboard.updateOrder(req.user.id, req.body); + res.json({ success: true }); + } + /** * @api {get} /api/v1/dashboard/:dashboard_selector getBySelector * @apiName getBySelector @@ -82,5 +93,6 @@ module.exports = function HouseController(gladys) { get: asyncMiddleware(get), getBySelector: asyncMiddleware(getBySelector), update: asyncMiddleware(update), + updateOrder: asyncMiddleware(updateOrder), }); }; diff --git a/server/api/routes.js b/server/api/routes.js index 6e2f162e4b..cb8edcc46a 100644 --- a/server/api/routes.js +++ b/server/api/routes.js @@ -174,6 +174,10 @@ function getRoutes(gladys) { authenticated: true, controller: dashboardController.create, }, + 'post /api/v1/dashboard/order': { + authenticated: true, + controller: dashboardController.updateOrder, + }, 'get /api/v1/dashboard/:dashboard_selector': { authenticated: true, controller: dashboardController.getBySelector, diff --git a/server/lib/dashboard/dashboard.create.js b/server/lib/dashboard/dashboard.create.js index 639972d63b..b8ed6b7732 100644 --- a/server/lib/dashboard/dashboard.create.js +++ b/server/lib/dashboard/dashboard.create.js @@ -13,6 +13,19 @@ const db = require('../../models'); * }); */ async function create(userId, dashboard) { + // We try to find if one dashboard already exist, if yes we use the position of this dashboard + 1 + const dashboardWithTheHighestPosition = await db.Dashboard.findAll({ + attributes: ['position'], + where: { + user_id: userId, + }, + order: [['position', 'desc']], + limit: 1, + raw: true, + }); + if (dashboardWithTheHighestPosition.length > 0) { + dashboard.position = dashboardWithTheHighestPosition[0].position + 1; + } return db.Dashboard.create({ ...dashboard, user_id: userId }); } diff --git a/server/lib/dashboard/dashboard.get.js b/server/lib/dashboard/dashboard.get.js index 00b84509d1..cdb5ed50df 100644 --- a/server/lib/dashboard/dashboard.get.js +++ b/server/lib/dashboard/dashboard.get.js @@ -15,6 +15,7 @@ async function get(userId) { where: { user_id: userId, }, + order: [['position', 'ASC']], raw: true, }); return dashboards; diff --git a/server/lib/dashboard/dashboard.getBySelector.js b/server/lib/dashboard/dashboard.getBySelector.js index 1cdfae66ca..1f0ee7648c 100644 --- a/server/lib/dashboard/dashboard.getBySelector.js +++ b/server/lib/dashboard/dashboard.getBySelector.js @@ -11,6 +11,7 @@ const { NotFoundError } = require('../../utils/coreErrors'); */ async function getBySelector(userId, selector) { const dashboard = await db.Dashboard.findOne({ + attributes: ['id', 'name', 'selector', 'type', 'created_at', 'updated_at', 'boxes'], where: { user_id: userId, selector, diff --git a/server/lib/dashboard/dashboard.updateOrder.js b/server/lib/dashboard/dashboard.updateOrder.js new file mode 100644 index 0000000000..f3861c0146 --- /dev/null +++ b/server/lib/dashboard/dashboard.updateOrder.js @@ -0,0 +1,28 @@ +const Promise = require('bluebird'); +const db = require('../../models'); + +/** + * @description Update a dashboard. + * @param {string} userId - The userId querying. + * @param {Array} dashboards - Dashboard selectors new order. + * @example + * gladys.dashboard.updateOrder('483b68cb-15ef-4ea3-80df-1e1bed5b402d', ['my-dashboard', 'other-dashboard']); + */ +async function updateOrder(userId, dashboards) { + // Foreach dashboard, update its position + await Promise.each(dashboards, async (dashboard, index) => { + await db.Dashboard.update( + { position: index }, + { + where: { + user_id: userId, + selector: dashboard, + }, + }, + ); + }); +} + +module.exports = { + updateOrder, +}; diff --git a/server/lib/dashboard/index.js b/server/lib/dashboard/index.js index 144c0a0390..37ac3ca9b8 100644 --- a/server/lib/dashboard/index.js +++ b/server/lib/dashboard/index.js @@ -3,6 +3,7 @@ const { get } = require('./dashboard.get'); const { destroy } = require('./dashboard.destroy'); const { getBySelector } = require('./dashboard.getBySelector'); const { update } = require('./dashboard.update'); +const { updateOrder } = require('./dashboard.updateOrder'); const Dashboard = function Dashboard() {}; @@ -11,5 +12,6 @@ Dashboard.prototype.destroy = destroy; Dashboard.prototype.get = get; Dashboard.prototype.getBySelector = getBySelector; Dashboard.prototype.update = update; +Dashboard.prototype.updateOrder = updateOrder; module.exports = Dashboard; diff --git a/server/migrations/20230130044921-add-position-dashboard.js b/server/migrations/20230130044921-add-position-dashboard.js new file mode 100644 index 0000000000..c5a866e53f --- /dev/null +++ b/server/migrations/20230130044921-add-position-dashboard.js @@ -0,0 +1,10 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('t_dashboard', 'position', { + type: Sequelize.INTEGER, + allowNull: false, + defaultValue: 0, + }); + }, + down: async (queryInterface, Sequelize) => {}, +}; diff --git a/server/models/dashboard.js b/server/models/dashboard.js index a32a4d648a..7f72ec4de2 100644 --- a/server/models/dashboard.js +++ b/server/models/dashboard.js @@ -55,6 +55,11 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, type: DataTypes.ENUM(DASHBOARD_TYPE_LIST), }, + position: { + allowNull: false, + type: DataTypes.INTEGER, + defaultValue: 0, + }, selector: { allowNull: false, unique: true, diff --git a/server/test/controllers/dashboard/dashboard.controller.test.js b/server/test/controllers/dashboard/dashboard.controller.test.js index 36fc7696fb..baf739500a 100644 --- a/server/test/controllers/dashboard/dashboard.controller.test.js +++ b/server/test/controllers/dashboard/dashboard.controller.test.js @@ -8,6 +8,7 @@ describe('POST /api/v1/dashboard', () => { .send({ name: 'my dashboard', type: 'main', + position: 0, boxes: [ [ { @@ -56,7 +57,6 @@ describe('GET /api/v1/dashboard/:dashboard_selector', () => { id: '854dda11-80c0-4476-843b-65cbc95c6a85', name: 'Test dashboard', selector: 'test-dashboard', - user_id: '0cd30aef-9c4e-4a23-88e3-3547971296e5', type: 'main', boxes: [ [ @@ -86,6 +86,7 @@ describe('PATCH /api/v1/dashboard/:dashboard_selector', () => { id: '854dda11-80c0-4476-843b-65cbc95c6a85', name: 'new name', selector: 'test-dashboard', + position: 0, user_id: '0cd30aef-9c4e-4a23-88e3-3547971296e5', type: 'main', boxes: [ @@ -102,6 +103,16 @@ describe('PATCH /api/v1/dashboard/:dashboard_selector', () => { }); }); +describe('POST /api/v1/dashboard/order', () => { + it('should update order of dashboards', async () => { + await authenticatedRequest + .post('/api/v1/dashboard/order') + .send(['test-dashboard']) + .expect('Content-Type', /json/) + .expect(200); + }); +}); + describe('DELETE /api/v1/dashboard/:dashboard_selector', () => { it('should patch dashboard', async () => { await authenticatedRequest diff --git a/server/test/lib/dashboard/dashboard.test.js b/server/test/lib/dashboard/dashboard.test.js index c4b0624b53..b7ef928167 100644 --- a/server/test/lib/dashboard/dashboard.test.js +++ b/server/test/lib/dashboard/dashboard.test.js @@ -2,6 +2,7 @@ const { expect, assert } = require('chai'); const { DASHBOARD_BOX_TYPE, DASHBOARD_TYPE } = require('../../../utils/constants'); const Dashboard = require('../../../lib/dashboard'); +const db = require('../../../models'); describe('dashboard.create', () => { const dashboard = new Dashboard(); @@ -9,6 +10,7 @@ describe('dashboard.create', () => { const newDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { name: 'My new dashboard', type: DASHBOARD_TYPE.MAIN, + position: 0, boxes: [ [ { @@ -76,6 +78,34 @@ describe('dashboard.update', () => { }); }); +describe('dashboard.updateOrder', () => { + const dashboard = new Dashboard(); + it('should update the order of dashboards', async () => { + const newDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { + name: 'My new dashboard', + type: DASHBOARD_TYPE.MAIN, + position: 0, + boxes: [ + [ + { + type: DASHBOARD_BOX_TYPE.USER_PRESENCE, + }, + ], + ], + }); + await dashboard.updateOrder('0cd30aef-9c4e-4a23-88e3-3547971296e5', [newDashboard.selector, 'test-dashboard']); + const dashboardsInNewOrder = await db.Dashboard.findAll({ + attributes: ['selector', 'position'], + order: [['position', 'asc']], + raw: true, + }); + expect(dashboardsInNewOrder).to.deep.equal([ + { selector: 'my-new-dashboard', position: 0 }, + { selector: 'test-dashboard', position: 1 }, + ]); + }); +}); + describe('dashboard.destroy', () => { const dashboard = new Dashboard(); it('should destroy a dashoard', async () => {