From ac6b028d4e582b50699c81fc05b5215e1963dbe8 Mon Sep 17 00:00:00 2001 From: Hubert Date: Wed, 29 Oct 2025 11:28:10 +0100 Subject: [PATCH 1/6] workspace tests for creation and deletion --- package-lock.json | 152 ++++++++++------ .../ControlPlaneListWorkspaceGridTile.tsx | 22 ++- .../CreateWorkspaceDialogContainer.cy.tsx | 164 ++++++++++++++++++ .../CreateWorkspaceDialogContainer.tsx | 58 +++---- src/hooks/useCreateWorkspace.spec.tsx | 114 ++++++++++++ src/hooks/useCreateWorkspace.tsx | 63 +++++++ src/hooks/useDeleteWorkspace.spec.tsx | 103 +++++++++++ src/hooks/useDeleteWorkspace.tsx | 33 ++++ 8 files changed, 606 insertions(+), 103 deletions(-) create mode 100644 src/components/Dialogs/CreateWorkspaceDialogContainer.cy.tsx create mode 100644 src/hooks/useCreateWorkspace.spec.tsx create mode 100644 src/hooks/useCreateWorkspace.tsx create mode 100644 src/hooks/useDeleteWorkspace.spec.tsx create mode 100644 src/hooks/useDeleteWorkspace.tsx diff --git a/package-lock.json b/package-lock.json index c5dacdf3..c3329500 100644 --- a/package-lock.json +++ b/package-lock.json @@ -261,7 +261,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -613,7 +612,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -660,7 +658,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1226,6 +1223,7 @@ "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", @@ -1241,6 +1239,7 @@ "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1251,6 +1250,7 @@ "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1314,6 +1314,7 @@ "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1324,6 +1325,7 @@ "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" @@ -2643,6 +2645,7 @@ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18.0" } @@ -2653,6 +2656,7 @@ "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -2667,6 +2671,7 @@ "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18" }, @@ -2681,6 +2686,7 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=12.22" }, @@ -2695,6 +2701,7 @@ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18" }, @@ -3232,6 +3239,7 @@ "integrity": "sha512-rmOWVRUbUJD7iSvJugjUbFZshTAuJ48MXoZ80Osx1GM0K/H1w7rSEvmw8m6vdWxNASgtaHIhAgre4H/E9GJiYQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", @@ -3265,6 +3273,7 @@ "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", "dev": true, "license": "ISC", + "peer": true, "peerDependencies": { "zod": "^3.24.1" } @@ -3345,7 +3354,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -3367,7 +3375,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.1.0.tgz", "integrity": "sha512-zOyetmZppnwTyPrt4S7jMfXiSX9yyfF0hxlA8B5oo2TtKl+/RGCy7fi4DrBfIf3lCPrkKsRBWZZD7RFojK7FDg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": "^18.19.0 || >=20.6.0" }, @@ -3380,7 +3387,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -4450,7 +4456,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.1.0", "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4467,7 +4472,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.1.0", "@opentelemetry/resources": "2.1.0", @@ -4485,7 +4489,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.37.0.tgz", "integrity": "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=14" } @@ -5473,6 +5476,7 @@ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -5521,7 +5525,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -5725,7 +5730,8 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -5794,7 +5800,6 @@ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -5805,7 +5810,6 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5917,7 +5921,6 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -6161,7 +6164,6 @@ "resolved": "https://registry.npmjs.org/@ui5/webcomponents/-/webcomponents-2.15.1.tgz", "integrity": "sha512-8dJd9o0PEMwBBkG2K86XnyZYVQmtMz/9PNUJWeqPJLU/JST2ty7M7lE+JRdwvac58/OcboNWZidHpAbJs/pmPw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@ui5/webcomponents-base": "2.15.1", "@ui5/webcomponents-icons": "2.15.1", @@ -6207,7 +6209,6 @@ "resolved": "https://registry.npmjs.org/@ui5/webcomponents-fiori/-/webcomponents-fiori-2.15.1.tgz", "integrity": "sha512-Sptnb0vcpO1xRgCZly3NKKBiisJZXAMSIyEMnCs+wsra1eyoL4CZBNvc4MJvSqu0BU4xazJhE8X3pNwpadbJNw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@ui5/webcomponents": "2.15.1", "@ui5/webcomponents-base": "2.15.1", @@ -6297,7 +6298,6 @@ "resolved": "https://registry.npmjs.org/@ui5/webcomponents-react-base/-/webcomponents-react-base-2.15.3.tgz", "integrity": "sha512-anD0B4k9DfZr4kEqISfBSCBytE+aUnubXCZE3Y/xcutKbJwZnzbIBtsqk0X1NXSRo4vNdxFWEjiH5I4aq2bcWw==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@types/react": "*", "@ui5/webcomponents-base": "~2.15.0", @@ -6918,6 +6918,7 @@ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" @@ -6932,6 +6933,7 @@ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -6942,6 +6944,7 @@ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -6954,7 +6957,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7565,7 +7567,6 @@ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.1.6.tgz", "integrity": "sha512-FgjDeR+/yDH34By4I0qB5NxAoWv7dOTYcOXwn73kr+c93HyC2lU6tnjifqUe33LKMJcDyCYPQjEAqgOQiXkE2Q==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bare-path": "^3.0.0" } @@ -7643,6 +7644,7 @@ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", @@ -7664,6 +7666,7 @@ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -7674,6 +7677,7 @@ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -7684,6 +7688,7 @@ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -7697,6 +7702,7 @@ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -7748,7 +7754,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001716", "electron-to-chromium": "^1.5.149", @@ -7813,6 +7818,7 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -8517,6 +8523,7 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -8542,6 +8549,7 @@ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.6.0" } @@ -8559,6 +8567,7 @@ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "object-assign": "^4", "vary": "^1" @@ -8671,7 +8680,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@cypress/request": "^3.0.9", "@cypress/xvfb": "^1.2.4", @@ -8918,7 +8926,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -9217,7 +9224,8 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/define-data-property": { "version": "1.1.4", @@ -9342,7 +9350,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -9438,7 +9447,8 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron-to-chromium": { "version": "1.5.155", @@ -9458,6 +9468,7 @@ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -9477,7 +9488,6 @@ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -9831,6 +9841,7 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -9908,7 +9919,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -10069,7 +10079,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -10264,6 +10273,7 @@ "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -10294,6 +10304,7 @@ "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -10304,6 +10315,7 @@ "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -10317,6 +10329,7 @@ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -10358,6 +10371,7 @@ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -10371,6 +10385,7 @@ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -10414,6 +10429,7 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -10437,6 +10453,7 @@ "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "eventsource-parser": "^3.0.1" }, @@ -10450,6 +10467,7 @@ "integrity": "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" } @@ -10507,6 +10525,7 @@ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -10550,6 +10569,7 @@ "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 16" }, @@ -10566,6 +10586,7 @@ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "5.2.1" }, @@ -10579,6 +10600,7 @@ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -10589,6 +10611,7 @@ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -10599,6 +10622,7 @@ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -10609,6 +10633,7 @@ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -10622,6 +10647,7 @@ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -10799,7 +10825,8 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-querystring": { "version": "1.1.2", @@ -10850,7 +10877,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@fastify/ajv-compiler": "^4.0.0", "@fastify/error": "^4.0.0", @@ -11024,6 +11050,7 @@ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flat-cache": "^4.0.0" }, @@ -11049,6 +11076,7 @@ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -11125,6 +11153,7 @@ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -11138,7 +11167,8 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/for-each": { "version": "0.3.5", @@ -11244,6 +11274,7 @@ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -11478,6 +11509,7 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -11615,7 +11647,6 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -11695,7 +11726,6 @@ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.5.tgz", "integrity": "sha512-HzYw057ch0hx2gZjkbgk1pur4kAtgljlWRP+Gccudqm3BRrTpExjWCQ9OHdIsq47Y6lHL++1lTvuQHhgRRcevw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" }, @@ -11986,7 +12016,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.27.6" }, @@ -12108,6 +12137,7 @@ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.19" } @@ -12536,7 +12566,8 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/is-regex": { "version": "1.2.1", @@ -12829,7 +12860,6 @@ "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.12.tgz", "integrity": "sha512-s8PPq2HQ3HIbSU0SjhNvTitf5VoXbQWof9q6k3gIX7F2il0ptjD5lONTDccpuKt/2U7RjbCp/TCHPK7eDwO7zQ==", "license": "MIT", - "peer": true, "dependencies": { "relative-time-format": "^1.1.7" } @@ -12995,7 +13025,8 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -13041,7 +13072,8 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -13132,6 +13164,7 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -13171,6 +13204,7 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -13551,7 +13585,8 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.once": { "version": "4.1.1", @@ -13674,6 +13709,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -13748,6 +13784,7 @@ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -13900,7 +13937,6 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.54.0.tgz", "integrity": "sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==", "license": "MIT", - "peer": true, "dependencies": { "dompurify": "3.1.7", "marked": "14.0.0" @@ -14031,6 +14067,7 @@ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -14268,6 +14305,7 @@ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -14318,6 +14356,7 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -14506,6 +14545,7 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -14766,6 +14806,7 @@ "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=16.20.0" } @@ -14896,7 +14937,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -14951,6 +14991,7 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -14960,7 +15001,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -15003,6 +15043,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -15018,6 +15059,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -15030,7 +15072,8 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/process": { "version": "0.11.10", @@ -15094,6 +15137,7 @@ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -15108,6 +15152,7 @@ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.10" } @@ -15197,6 +15242,7 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -15207,6 +15253,7 @@ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -15222,7 +15269,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -15244,7 +15290,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -15269,7 +15314,6 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.65.0.tgz", "integrity": "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==", "license": "MIT", - "peer": true, "engines": { "node": ">=18.0.0" }, @@ -15765,6 +15809,7 @@ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -15976,6 +16021,7 @@ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", @@ -15999,6 +16045,7 @@ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -16009,6 +16056,7 @@ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -16034,6 +16082,7 @@ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -16865,7 +16914,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17061,7 +17109,6 @@ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -17102,6 +17149,7 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -17219,7 +17267,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17350,6 +17397,7 @@ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -17373,7 +17421,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.2.2" }, @@ -17546,7 +17593,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -17670,7 +17716,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17684,7 +17729,6 @@ "integrity": "sha512-SXrA2ZzOPulX479d8W13RqKSmvHb9Bfg71eW7Fbs6ZjUFcCCXyt/OzFCkNyiUE8mFlPHa4ZVUGw0ky+5ndKnrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.2", "@vitest/mocker": "4.0.2", @@ -18024,6 +18068,7 @@ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -18072,7 +18117,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index cf97ef31..5f87cc42 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -7,12 +7,10 @@ import { ControlPlaneCard } from '../ControlPlaneCard/ControlPlaneCard.tsx'; import { ListWorkspacesType, isWorkspaceReady } from '../../../lib/api/types/crate/listWorkspaces.ts'; import { useMemo, useState } from 'react'; import { MembersAvatarView } from './MembersAvatarView.tsx'; -import { DeleteWorkspaceResource, DeleteWorkspaceType } from '../../../lib/api/types/crate/deleteWorkspace.ts'; -import { useApiResourceMutation, useApiResource } from '../../../lib/api/useApiResource.ts'; +import { useApiResource } from '../../../lib/api/useApiResource.ts'; import { DISPLAY_NAME_ANNOTATION } from '../../../lib/api/types/shared/keyNames.ts'; import { DeleteConfirmationDialog } from '../../Dialogs/DeleteConfirmationDialog.tsx'; import { KubectlDeleteWorkspace } from '../../Dialogs/KubectlCommandInfo/Controllers/KubectlDeleteWorkspace.tsx'; -import { useToast } from '../../../context/ToastContext.tsx'; import { ListControlPlanes } from '../../../lib/api/types/crate/controlPlanes.ts'; import IllustratedError from '../../Shared/IllustratedError.tsx'; import { APIError } from '../../../lib/api/error.ts'; @@ -24,13 +22,19 @@ import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/Illustr import styles from './WorkspacesList.module.css'; import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx'; import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx'; +import { useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.tsx'; interface Props { projectName: string; workspace: ListWorkspacesType; + useDeleteWorkspace?: typeof useDeleteWorkspace; } -export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Props) { +export function ControlPlaneListWorkspaceGridTile({ + projectName, + workspace, + useDeleteWorkspace: useDeleteWorkspaceHook = useDeleteWorkspace, +}: Props) { const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false); const [initialTemplateName, setInitialTemplateName] = useState(undefined); const workspaceName = workspace.metadata.name; @@ -40,13 +44,10 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr const { t } = useTranslation(); - const toast = useToast(); const [dialogDeleteWsIsOpen, setDialogDeleteWsIsOpen] = useState(false); const { data: controlplanes, error: cpsError } = useApiResource(ListControlPlanes(projectName, workspaceName)); - const { trigger } = useApiResourceMutation( - DeleteWorkspaceResource(projectNamespace, workspaceName), - ); + const { deleteWorkspace } = useDeleteWorkspaceHook(projectName, projectNamespace, workspaceName); const { mcpCreationGuide } = useLink(); const errorView = createErrorView(cpsError); @@ -181,10 +182,7 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr kubectl={} isOpen={dialogDeleteWsIsOpen} setIsOpen={setDialogDeleteWsIsOpen} - onDeletionConfirmed={async () => { - await trigger(); - toast.show(t('ControlPlaneListWorkspaceGridTile.deleteConfirmationDialog')); - }} + onDeletionConfirmed={deleteWorkspace} /> {isCreateManagedControlPlaneWizardOpen ? ( { + let createWorkspacePayload: Omit | null = null; + + const fakeUseCreateWorkspace: typeof useCreateWorkspace = () => ({ + createWorkspace: async (data: Omit): Promise => { + createWorkspacePayload = data; + return true; + }, + isLoading: false, + errorDialogRef: { current: null }, + }); + + const fakeUseAuthOnboarding = (() => ({ + user: { + email: 'name@domain.com', + }, + })) as typeof useAuthOnboarding; + + beforeEach(() => { + createWorkspacePayload = null; + }); + + it('creates a workspace with valid data', () => { + const setIsOpen = cy.stub(); + + cy.mount( + , + ); + + const expectedPayload = { + name: 'test-workspace', + displayName: 'Test Workspace Display Name', + chargingTarget: '12345678-1234-1234-1234-123456789abc', + members: [ + { + name: 'name@domain.com', + roles: ['admin'], + kind: 'User', + }, + ], + }; + + // Fill in the form (using Shadow DOM selectors) + cy.get('#name').find('input[id*="inner"]').type('test-workspace'); + cy.get('#displayName').find('input[id*="inner"]').type('Test Workspace Display Name'); + + // Select charging target type + cy.get('#chargingTargetType').click(); + cy.contains('BTP').click(); + + // Fill charging target + cy.get('#chargingTarget').find('input[id*="inner"]').type('12345678-1234-1234-1234-123456789abc'); + + // Submit the form + cy.get('ui5-button').contains('Create').click(); + + // Verify the hook was called with correct data + cy.then(() => cy.wrap(createWorkspacePayload).deepEqualJson(expectedPayload)); + + // Dialog should close on success + cy.wrap(setIsOpen).should('have.been.calledWith', false); + }); + + it('validates required fields', () => { + const setIsOpen = cy.stub(); + + cy.mount( + , + ); + + // Try to submit without filling required fields + cy.get('ui5-button').contains('Create').click(); + + // Should show validation errors - check for value-state="Negative" attribute + cy.get('#name').should('have.attr', 'value-state', 'Negative'); + + // Or check if error message exists in DOM (even if hidden by CSS) + cy.contains('This field is required').should('exist'); + + // Dialog should not close + cy.wrap(setIsOpen).should('not.have.been.called'); + }); + + it('validates charging target format for BTP', () => { + const setIsOpen = cy.stub(); + + cy.mount( + , + ); + + cy.get('#name').find('input[id*="inner"]').type('test-workspace'); + cy.get('#chargingTargetType').click(); + cy.contains('BTP').click(); + + // Invalid format + cy.get('#chargingTarget').find('input[id*="inner"]').type('invalid-format'); + cy.get('ui5-button').contains('Create').click(); + + // Should show validation error - check for value-state="Negative" attribute + cy.get('#chargingTarget').should('have.attr', 'value-state', 'Negative'); + + // Dialog should not close + cy.wrap(setIsOpen).should('not.have.been.called'); + }); + + it('should not close dialog when creation fails', () => { + const failingUseCreateWorkspace: typeof useCreateWorkspace = () => ({ + createWorkspace: async (): Promise => { + return false; // Simulate failure + }, + isLoading: false, + errorDialogRef: { current: null }, + }); + + const setIsOpen = cy.stub(); + + cy.mount( + , + ); + + // Fill in the form + cy.get('#name').find('input[id*="inner"]').type('test-workspace'); + cy.get('#chargingTargetType').click(); + cy.contains('BTP').click(); + cy.get('#chargingTarget').find('input[id*="inner"]').type('12345678-1234-1234-1234-123456789abc'); + + // Submit the form + cy.get('ui5-button').contains('Create').click(); + + // Dialog should NOT close on failure + cy.wrap(setIsOpen).should('not.have.been.called'); + + // Dialog should still be visible + cy.contains('Create').should('be.visible'); + }); +}); diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index bca3b319..2c149bf2 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -1,16 +1,6 @@ -import { useCallback, useEffect, useMemo, useRef } from 'react'; -import { useApiResourceMutation, useRevalidateApiResource } from '../../lib/api/useApiResource'; -import { ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx'; -import { APIError } from '../../lib/api/error'; +import { useCallback, useEffect, useMemo } from 'react'; import { CreateProjectWorkspaceDialog, OnCreatePayload } from './CreateProjectWorkspaceDialog.tsx'; -import { - CreateWorkspace, - CreateWorkspaceResource, - CreateWorkspaceType, -} from '../../lib/api/types/crate/createWorkspace'; import { projectnameToNamespace } from '../../utils'; -import { ListWorkspaces } from '../../lib/api/types/crate/listWorkspaces'; -import { useToast } from '../../context/ToastContext.tsx'; import { useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding.tsx'; import { Member, MemberRoles } from '../../lib/api/types/shared/members.ts'; import { useTranslation } from 'react-i18next'; @@ -18,6 +8,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { createProjectWorkspaceSchema } from '../../lib/api/validations/schemas.ts'; import { ComponentsListItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; +import { useCreateWorkspace } from '../../hooks/useCreateWorkspace.tsx'; export type CreateDialogProps = { name: string; @@ -32,10 +23,14 @@ export function CreateWorkspaceDialogContainer({ isOpen, setIsOpen, project = '', + useCreateWorkspace: useCreateWorkspaceHook = useCreateWorkspace, + useAuthOnboarding: useAuthOnboardingHook = useAuthOnboarding, }: { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; project?: string; + useCreateWorkspace?: typeof useCreateWorkspace; + useAuthOnboarding?: typeof useAuthOnboarding; }) { const { t } = useTranslation(); const validationSchemaProjectWorkspace = useMemo(() => createProjectWorkspaceSchema(t), [t]); @@ -56,9 +51,13 @@ export function CreateWorkspaceDialogContainer({ chargingTargetType: '', }, }); - const { user } = useAuthOnboarding(); + const { user } = useAuthOnboardingHook(); const username = user?.email; + const namespace = projectnameToNamespace(project); + + const { createWorkspace, errorDialogRef } = useCreateWorkspaceHook(project, namespace); + const clearForm = useCallback(() => { resetField('name'); resetField('chargingTarget'); @@ -74,12 +73,6 @@ export function CreateWorkspaceDialogContainer({ clearForm(); } }, [resetField, setValue, username, isOpen, clearForm]); - const namespace = projectnameToNamespace(project); - const toast = useToast(); - - const { trigger } = useApiResourceMutation(CreateWorkspaceResource(namespace)); - const revalidate = useRevalidateApiResource(ListWorkspaces(project)); - const errorDialogRef = useRef(null); const handleWorkspaceCreate = async ({ name, @@ -87,27 +80,18 @@ export function CreateWorkspaceDialogContainer({ chargingTarget, members, }: OnCreatePayload): Promise => { - try { - await trigger( - CreateWorkspace(name, namespace, { - displayName: displayName, - chargingTarget: chargingTarget, - members: members, - }), - ); - await revalidate(); + const success = await createWorkspace({ + name, + displayName, + chargingTarget, + members, + }); + + if (success) { setIsOpen(false); - toast.show(t('CreateWorkspaceDialog.toastMessage')); - return true; - } catch (e) { - console.error(e); - if (e instanceof APIError) { - if (errorDialogRef.current) { - errorDialogRef.current.showErrorDialog(`${e.message}: ${JSON.stringify(e.info)}`); - } - } - return false; } + + return success; }; return ( diff --git a/src/hooks/useCreateWorkspace.spec.tsx b/src/hooks/useCreateWorkspace.spec.tsx new file mode 100644 index 00000000..759d0c92 --- /dev/null +++ b/src/hooks/useCreateWorkspace.spec.tsx @@ -0,0 +1,114 @@ +import { act, renderHook } from '@testing-library/react'; +import { useCreateWorkspace } from './useCreateWorkspace'; +import { describe, it, expect, vi, afterEach, Mock, beforeEach } from 'vitest'; +import { assertNonNullish, assertString } from '../utils/test/vitest-utils'; +import { MemberRoles } from '../lib/api/types/shared/members'; + +// Mock toast and translation +vi.mock('../context/ToastContext', () => ({ + useToast: () => ({ + show: vi.fn(), + }), +})); + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +describe('useCreateWorkspace', () => { + let fetchMock: Mock; + + beforeEach(() => { + fetchMock = vi.fn(); + global.fetch = fetchMock; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should perform a valid create workspace request', async () => { + // ARRANGE + const mockWorkspaceData = { + name: 'test-workspace', + displayName: 'Test Workspace', + chargingTarget: '12345678-1234-1234-1234-123456789abc', + members: [ + { + name: 'user@domain.com', + roles: [MemberRoles.admin], + kind: 'User' as const, + }, + ], + }; + + fetchMock.mockResolvedValue({ + ok: true, + status: 200, + json: vi.fn().mockResolvedValue({}), + } as unknown as Response); + + // ACT + const renderHookResult = renderHook(() => useCreateWorkspace('test-project', 'test-project--ns')); + const { createWorkspace } = renderHookResult.result.current; + + let result: boolean = false; + await act(async () => { + result = await createWorkspace(mockWorkspaceData); + }); + + // ASSERT + expect(result).toBe(true); + expect(fetchMock).toHaveBeenCalledTimes(1); + + const call = fetchMock.mock.calls[0]; + const [url, init] = call; + assertNonNullish(init); + const { method, headers, body } = init; + + expect(url).toContain('/api/onboarding/apis/core.openmcp.cloud/v1alpha1/namespaces/test-project--ns/workspaces'); + expect(method).toBe('POST'); + expect(headers).toEqual( + expect.objectContaining({ + 'Content-Type': 'application/json', + 'X-use-crate': 'true', + }), + ); + + assertString(body); + const parsedBody = JSON.parse(body); + expect(parsedBody.metadata.name).toBe('test-workspace'); + expect(parsedBody.metadata.annotations?.['openmcp.cloud/display-name']).toBe('Test Workspace'); + expect(parsedBody.metadata.labels?.['openmcp.cloud.sap/charging-target']).toBe( + '12345678-1234-1234-1234-123456789abc', + ); + expect(parsedBody.spec.members).toHaveLength(1); + expect(parsedBody.spec.members[0].name).toBe('user@domain.com'); + }); + + it('should return false on API error', async () => { + // ARRANGE + fetchMock.mockRejectedValue(new Error('API Error')); + + const mockWorkspaceData = { + name: 'test-workspace', + displayName: 'Test Workspace', + chargingTarget: '12345678-1234-1234-1234-123456789abc', + members: [], + }; + + // ACT + const renderHookResult = renderHook(() => useCreateWorkspace('test-project', 'test-project--ns')); + const { createWorkspace } = renderHookResult.result.current; + + let result: boolean = true; + await act(async () => { + result = await createWorkspace(mockWorkspaceData); + }); + + // ASSERT + expect(result).toBe(false); + }); +}); diff --git a/src/hooks/useCreateWorkspace.tsx b/src/hooks/useCreateWorkspace.tsx new file mode 100644 index 00000000..9696a4e9 --- /dev/null +++ b/src/hooks/useCreateWorkspace.tsx @@ -0,0 +1,63 @@ +import { useCallback, useRef } from 'react'; +import { useApiResourceMutation, useRevalidateApiResource } from '../lib/api/useApiResource'; +import { CreateWorkspace, CreateWorkspaceResource, CreateWorkspaceType } from '../lib/api/types/crate/createWorkspace'; +import { ListWorkspaces } from '../lib/api/types/crate/listWorkspaces'; +import { useToast } from '../context/ToastContext'; +import { APIError } from '../lib/api/error'; +import { ErrorDialogHandle } from '../components/Shared/ErrorMessageBox'; +import { Member } from '../lib/api/types/shared/members'; +import { useTranslation } from 'react-i18next'; + +export interface CreateWorkspaceParams { + name: string; + namespace: string; + displayName?: string; + chargingTarget?: string; + members: Member[]; +} + +export function useCreateWorkspace(projectName: string, namespace: string) { + const { t } = useTranslation(); + const toast = useToast(); + const errorDialogRef = useRef(null); + + const { trigger, isMutating } = useApiResourceMutation(CreateWorkspaceResource(namespace)); + const revalidate = useRevalidateApiResource(ListWorkspaces(projectName)); + + const createWorkspace = useCallback( + async ({ + name, + displayName, + chargingTarget, + members, + }: Omit): Promise => { + try { + await trigger( + CreateWorkspace(name, namespace, { + displayName, + chargingTarget, + members, + }), + ); + await revalidate(); + toast.show(t('CreateWorkspaceDialog.toastMessage')); + return true; + } catch (e) { + console.error(e); + if (e instanceof APIError) { + if (errorDialogRef.current) { + errorDialogRef.current.showErrorDialog(`${e.message}: ${JSON.stringify(e.info)}`); + } + } + return false; + } + }, + [trigger, revalidate, toast, t, namespace], + ); + + return { + createWorkspace, + isLoading: isMutating, + errorDialogRef, + }; +} diff --git a/src/hooks/useDeleteWorkspace.spec.tsx b/src/hooks/useDeleteWorkspace.spec.tsx new file mode 100644 index 00000000..3802c1b2 --- /dev/null +++ b/src/hooks/useDeleteWorkspace.spec.tsx @@ -0,0 +1,103 @@ +import { act, renderHook } from '@testing-library/react'; +import { useDeleteWorkspace } from './useDeleteWorkspace'; +import { describe, it, expect, vi, afterEach, Mock, beforeEach } from 'vitest'; +import { assertNonNullish } from '../utils/test/vitest-utils'; + +// Mock toast and translation +vi.mock('../context/ToastContext', () => ({ + useToast: () => ({ + show: vi.fn(), + }), +})); + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +describe('useDeleteWorkspace', () => { + let fetchMock: Mock; + + beforeEach(() => { + fetchMock = vi.fn(); + global.fetch = fetchMock; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should perform a valid delete workspace request', async () => { + // ARRANGE + fetchMock.mockResolvedValue({ + ok: true, + status: 200, + json: vi.fn().mockResolvedValue({}), + } as unknown as Response); + + // ACT + const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); + const { deleteWorkspace } = renderHookResult.result.current; + + let result: boolean = false; + await act(async () => { + result = await deleteWorkspace(); + }); + + // ASSERT + expect(result).toBe(true); + expect(fetchMock).toHaveBeenCalledTimes(1); + + const call = fetchMock.mock.calls[0]; + const [url, init] = call; + assertNonNullish(init); + const { method, headers } = init; + + expect(url).toContain( + '/api/onboarding/apis/core.openmcp.cloud/v1alpha1/namespaces/test-project--ns/workspaces/test-workspace', + ); + expect(method).toBe('DELETE'); + expect(headers).toEqual( + expect.objectContaining({ + 'Content-Type': 'application/json', + 'X-use-crate': 'true', + }), + ); + }); + + it('should return false on API error', async () => { + // ARRANGE + fetchMock.mockRejectedValue(new Error('API Error')); + + // ACT + const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); + const { deleteWorkspace } = renderHookResult.result.current; + + let result: boolean = true; + await act(async () => { + result = await deleteWorkspace(); + }); + + // ASSERT + expect(result).toBe(false); + }); + + it('should return false on network error', async () => { + // ARRANGE + fetchMock.mockRejectedValue(new TypeError('Network error')); + + // ACT + const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); + const { deleteWorkspace } = renderHookResult.result.current; + + let result: boolean = true; + await act(async () => { + result = await deleteWorkspace(); + }); + + // ASSERT + expect(result).toBe(false); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/hooks/useDeleteWorkspace.tsx b/src/hooks/useDeleteWorkspace.tsx new file mode 100644 index 00000000..8d4c8c77 --- /dev/null +++ b/src/hooks/useDeleteWorkspace.tsx @@ -0,0 +1,33 @@ +import { useCallback } from 'react'; +import { useApiResourceMutation, useRevalidateApiResource } from '../lib/api/useApiResource'; +import { DeleteWorkspaceResource, DeleteWorkspaceType } from '../lib/api/types/crate/deleteWorkspace'; +import { ListWorkspaces } from '../lib/api/types/crate/listWorkspaces'; +import { useToast } from '../context/ToastContext'; +import { useTranslation } from 'react-i18next'; + +export function useDeleteWorkspace(projectName: string, projectNamespace: string, workspaceName: string) { + const { t } = useTranslation(); + const toast = useToast(); + + const { trigger, isMutating } = useApiResourceMutation( + DeleteWorkspaceResource(projectNamespace, workspaceName), + ); + const revalidate = useRevalidateApiResource(ListWorkspaces(projectName)); + + const deleteWorkspace = useCallback(async (): Promise => { + try { + await trigger(); + await revalidate(); + toast.show(t('ControlPlaneListWorkspaceGridTile.deleteConfirmationDialog')); + return true; + } catch (e) { + console.error('Failed to delete workspace:', e); + return false; + } + }, [trigger, revalidate, toast, t]); + + return { + deleteWorkspace, + isDeleting: isMutating, + }; +} From 731671100ad705ec1d6ebafda5aa02a2d66cc8a5 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 30 Oct 2025 10:02:18 +0100 Subject: [PATCH 2/6] PR changes --- .../ControlPlaneListWorkspaceGridTile.tsx | 2 +- .../CreateWorkspaceDialogContainer.cy.tsx | 12 ++-- .../CreateWorkspaceDialogContainer.tsx | 47 ++++++++------ ...ce.spec.tsx => useCreateWorkspace.spec.ts} | 13 ++-- src/hooks/useCreateWorkspace.ts | 49 +++++++++++++++ src/hooks/useCreateWorkspace.tsx | 63 ------------------- ...ce.spec.tsx => useDeleteWorkspace.spec.ts} | 0 ...eteWorkspace.tsx => useDeleteWorkspace.ts} | 0 8 files changed, 88 insertions(+), 98 deletions(-) rename src/hooks/{useCreateWorkspace.spec.tsx => useCreateWorkspace.spec.ts} (91%) create mode 100644 src/hooks/useCreateWorkspace.ts delete mode 100644 src/hooks/useCreateWorkspace.tsx rename src/hooks/{useDeleteWorkspace.spec.tsx => useDeleteWorkspace.spec.ts} (100%) rename src/hooks/{useDeleteWorkspace.tsx => useDeleteWorkspace.ts} (100%) diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 5f87cc42..5356a602 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -22,7 +22,7 @@ import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/Illustr import styles from './WorkspacesList.module.css'; import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx'; import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx'; -import { useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.tsx'; +import { useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.ts'; interface Props { projectName: string; diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.cy.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.cy.tsx index c8bc4620..22fe9edb 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.cy.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.cy.tsx @@ -3,15 +3,13 @@ import { useCreateWorkspace, CreateWorkspaceParams } from '../../hooks/useCreate import { useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding'; describe('CreateWorkspaceDialogContainer', () => { - let createWorkspacePayload: Omit | null = null; + let createWorkspacePayload: CreateWorkspaceParams | null = null; const fakeUseCreateWorkspace: typeof useCreateWorkspace = () => ({ - createWorkspace: async (data: Omit): Promise => { + createWorkspace: async (data: CreateWorkspaceParams): Promise => { createWorkspacePayload = data; - return true; }, isLoading: false, - errorDialogRef: { current: null }, }); const fakeUseAuthOnboarding = (() => ({ @@ -41,6 +39,7 @@ describe('CreateWorkspaceDialogContainer', () => { name: 'test-workspace', displayName: 'Test Workspace Display Name', chargingTarget: '12345678-1234-1234-1234-123456789abc', + chargingTargetType: 'btp', members: [ { name: 'name@domain.com', @@ -127,11 +126,10 @@ describe('CreateWorkspaceDialogContainer', () => { it('should not close dialog when creation fails', () => { const failingUseCreateWorkspace: typeof useCreateWorkspace = () => ({ - createWorkspace: async (): Promise => { - return false; // Simulate failure + createWorkspace: async (): Promise => { + throw new Error('Creation failed'); // Simulate failure by throwing error }, isLoading: false, - errorDialogRef: { current: null }, }); const setIsOpen = cy.stub(); diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index 2c149bf2..96448ea7 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -1,14 +1,16 @@ -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; import { CreateProjectWorkspaceDialog, OnCreatePayload } from './CreateProjectWorkspaceDialog.tsx'; import { projectnameToNamespace } from '../../utils'; -import { useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding.tsx'; +import { useAuthOnboarding as _useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding.tsx'; import { Member, MemberRoles } from '../../lib/api/types/shared/members.ts'; import { useTranslation } from 'react-i18next'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { createProjectWorkspaceSchema } from '../../lib/api/validations/schemas.ts'; import { ComponentsListItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; -import { useCreateWorkspace } from '../../hooks/useCreateWorkspace.tsx'; +import { useCreateWorkspace as _useCreateWorkspace } from '../../hooks/useCreateWorkspace.ts'; +import { APIError } from '../../lib/api/error.ts'; +import { ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx'; export type CreateDialogProps = { name: string; @@ -23,14 +25,14 @@ export function CreateWorkspaceDialogContainer({ isOpen, setIsOpen, project = '', - useCreateWorkspace: useCreateWorkspaceHook = useCreateWorkspace, - useAuthOnboarding: useAuthOnboardingHook = useAuthOnboarding, + useCreateWorkspace: useCreateWorkspaceHook = _useCreateWorkspace, + useAuthOnboarding: useAuthOnboardingHook = _useAuthOnboarding, }: { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; project?: string; - useCreateWorkspace?: typeof useCreateWorkspace; - useAuthOnboarding?: typeof useAuthOnboarding; + useCreateWorkspace?: typeof _useCreateWorkspace; + useAuthOnboarding?: typeof _useAuthOnboarding; }) { const { t } = useTranslation(); const validationSchemaProjectWorkspace = useMemo(() => createProjectWorkspaceSchema(t), [t]); @@ -56,7 +58,8 @@ export function CreateWorkspaceDialogContainer({ const username = user?.email; const namespace = projectnameToNamespace(project); - const { createWorkspace, errorDialogRef } = useCreateWorkspaceHook(project, namespace); + const { createWorkspace } = useCreateWorkspaceHook(project, namespace); + const errorDialogRef = useRef(null); const clearForm = useCallback(() => { resetField('name'); @@ -78,20 +81,28 @@ export function CreateWorkspaceDialogContainer({ name, displayName, chargingTarget, + chargingTargetType, members, }: OnCreatePayload): Promise => { - const success = await createWorkspace({ - name, - displayName, - chargingTarget, - members, - }); - - if (success) { + try { + await createWorkspace({ + name, + displayName, + chargingTarget, + chargingTargetType, + members, + }); setIsOpen(false); + return true; + } catch (e) { + console.error(e); + if (e instanceof APIError) { + if (errorDialogRef.current) { + errorDialogRef.current.showErrorDialog(`${e.message}: ${JSON.stringify(e.info)}`); + } + } + return false; } - - return success; }; return ( diff --git a/src/hooks/useCreateWorkspace.spec.tsx b/src/hooks/useCreateWorkspace.spec.ts similarity index 91% rename from src/hooks/useCreateWorkspace.spec.tsx rename to src/hooks/useCreateWorkspace.spec.ts index 759d0c92..8bf83e66 100644 --- a/src/hooks/useCreateWorkspace.spec.tsx +++ b/src/hooks/useCreateWorkspace.spec.ts @@ -54,13 +54,11 @@ describe('useCreateWorkspace', () => { const renderHookResult = renderHook(() => useCreateWorkspace('test-project', 'test-project--ns')); const { createWorkspace } = renderHookResult.result.current; - let result: boolean = false; await act(async () => { - result = await createWorkspace(mockWorkspaceData); + await createWorkspace(mockWorkspaceData); }); // ASSERT - expect(result).toBe(true); expect(fetchMock).toHaveBeenCalledTimes(1); const call = fetchMock.mock.calls[0]; @@ -88,7 +86,7 @@ describe('useCreateWorkspace', () => { expect(parsedBody.spec.members[0].name).toBe('user@domain.com'); }); - it('should return false on API error', async () => { + it('should throw error on API failure', async () => { // ARRANGE fetchMock.mockRejectedValue(new Error('API Error')); @@ -103,12 +101,9 @@ describe('useCreateWorkspace', () => { const renderHookResult = renderHook(() => useCreateWorkspace('test-project', 'test-project--ns')); const { createWorkspace } = renderHookResult.result.current; - let result: boolean = true; + // ASSERT await act(async () => { - result = await createWorkspace(mockWorkspaceData); + await expect(createWorkspace(mockWorkspaceData)).rejects.toThrow('API Error'); }); - - // ASSERT - expect(result).toBe(false); }); }); diff --git a/src/hooks/useCreateWorkspace.ts b/src/hooks/useCreateWorkspace.ts new file mode 100644 index 00000000..64528509 --- /dev/null +++ b/src/hooks/useCreateWorkspace.ts @@ -0,0 +1,49 @@ +import { useCallback } from 'react'; +import { useApiResourceMutation, useRevalidateApiResource } from '../lib/api/useApiResource'; +import { CreateWorkspace, CreateWorkspaceResource, CreateWorkspaceType } from '../lib/api/types/crate/createWorkspace'; +import { ListWorkspaces } from '../lib/api/types/crate/listWorkspaces'; +import { useToast } from '../context/ToastContext'; +import { Member } from '../lib/api/types/shared/members'; +import { useTranslation } from 'react-i18next'; + +export interface CreateWorkspaceParams { + name: string; + displayName?: string; + chargingTarget?: string; + chargingTargetType?: string; + members: Member[]; +} + +export function useCreateWorkspace(projectName: string, namespace: string) { + const { t } = useTranslation(); + const toast = useToast(); + + const { trigger } = useApiResourceMutation(CreateWorkspaceResource(namespace)); + const revalidate = useRevalidateApiResource(ListWorkspaces(projectName)); + + const createWorkspace = useCallback( + async ({ + name, + displayName, + chargingTarget, + chargingTargetType, + members, + }: CreateWorkspaceParams): Promise => { + await trigger( + CreateWorkspace(name, namespace, { + displayName, + chargingTarget, + chargingTargetType, + members, + }), + ); + await revalidate(); + toast.show(t('CreateWorkspaceDialog.toastMessage')); + }, + [trigger, revalidate, toast, t, namespace], + ); + + return { + createWorkspace, + }; +} diff --git a/src/hooks/useCreateWorkspace.tsx b/src/hooks/useCreateWorkspace.tsx deleted file mode 100644 index 9696a4e9..00000000 --- a/src/hooks/useCreateWorkspace.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useCallback, useRef } from 'react'; -import { useApiResourceMutation, useRevalidateApiResource } from '../lib/api/useApiResource'; -import { CreateWorkspace, CreateWorkspaceResource, CreateWorkspaceType } from '../lib/api/types/crate/createWorkspace'; -import { ListWorkspaces } from '../lib/api/types/crate/listWorkspaces'; -import { useToast } from '../context/ToastContext'; -import { APIError } from '../lib/api/error'; -import { ErrorDialogHandle } from '../components/Shared/ErrorMessageBox'; -import { Member } from '../lib/api/types/shared/members'; -import { useTranslation } from 'react-i18next'; - -export interface CreateWorkspaceParams { - name: string; - namespace: string; - displayName?: string; - chargingTarget?: string; - members: Member[]; -} - -export function useCreateWorkspace(projectName: string, namespace: string) { - const { t } = useTranslation(); - const toast = useToast(); - const errorDialogRef = useRef(null); - - const { trigger, isMutating } = useApiResourceMutation(CreateWorkspaceResource(namespace)); - const revalidate = useRevalidateApiResource(ListWorkspaces(projectName)); - - const createWorkspace = useCallback( - async ({ - name, - displayName, - chargingTarget, - members, - }: Omit): Promise => { - try { - await trigger( - CreateWorkspace(name, namespace, { - displayName, - chargingTarget, - members, - }), - ); - await revalidate(); - toast.show(t('CreateWorkspaceDialog.toastMessage')); - return true; - } catch (e) { - console.error(e); - if (e instanceof APIError) { - if (errorDialogRef.current) { - errorDialogRef.current.showErrorDialog(`${e.message}: ${JSON.stringify(e.info)}`); - } - } - return false; - } - }, - [trigger, revalidate, toast, t, namespace], - ); - - return { - createWorkspace, - isLoading: isMutating, - errorDialogRef, - }; -} diff --git a/src/hooks/useDeleteWorkspace.spec.tsx b/src/hooks/useDeleteWorkspace.spec.ts similarity index 100% rename from src/hooks/useDeleteWorkspace.spec.tsx rename to src/hooks/useDeleteWorkspace.spec.ts diff --git a/src/hooks/useDeleteWorkspace.tsx b/src/hooks/useDeleteWorkspace.ts similarity index 100% rename from src/hooks/useDeleteWorkspace.tsx rename to src/hooks/useDeleteWorkspace.ts From 00159f2fc0c500dc471745ff8bde7366d788c7a2 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 30 Oct 2025 10:11:16 +0100 Subject: [PATCH 3/6] PR changes --- src/hooks/useDeleteWorkspace.spec.ts | 22 +++++++--------------- src/hooks/useDeleteWorkspace.ts | 14 ++++---------- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/hooks/useDeleteWorkspace.spec.ts b/src/hooks/useDeleteWorkspace.spec.ts index 3802c1b2..0b406ef7 100644 --- a/src/hooks/useDeleteWorkspace.spec.ts +++ b/src/hooks/useDeleteWorkspace.spec.ts @@ -40,13 +40,11 @@ describe('useDeleteWorkspace', () => { const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); const { deleteWorkspace } = renderHookResult.result.current; - let result: boolean = false; await act(async () => { - result = await deleteWorkspace(); + await deleteWorkspace(); }); // ASSERT - expect(result).toBe(true); expect(fetchMock).toHaveBeenCalledTimes(1); const call = fetchMock.mock.calls[0]; @@ -66,7 +64,7 @@ describe('useDeleteWorkspace', () => { ); }); - it('should return false on API error', async () => { + it('should throw error on API failure', async () => { // ARRANGE fetchMock.mockRejectedValue(new Error('API Error')); @@ -74,16 +72,13 @@ describe('useDeleteWorkspace', () => { const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); const { deleteWorkspace } = renderHookResult.result.current; - let result: boolean = true; + // ASSERT await act(async () => { - result = await deleteWorkspace(); + await expect(deleteWorkspace()).rejects.toThrow('API Error'); }); - - // ASSERT - expect(result).toBe(false); }); - it('should return false on network error', async () => { + it('should throw error on network failure', async () => { // ARRANGE fetchMock.mockRejectedValue(new TypeError('Network error')); @@ -91,13 +86,10 @@ describe('useDeleteWorkspace', () => { const renderHookResult = renderHook(() => useDeleteWorkspace('test-project', 'test-project--ns', 'test-workspace')); const { deleteWorkspace } = renderHookResult.result.current; - let result: boolean = true; + // ASSERT await act(async () => { - result = await deleteWorkspace(); + await expect(deleteWorkspace()).rejects.toThrow('Network error'); }); - - // ASSERT - expect(result).toBe(false); expect(fetchMock).toHaveBeenCalledTimes(1); }); }); diff --git a/src/hooks/useDeleteWorkspace.ts b/src/hooks/useDeleteWorkspace.ts index 8d4c8c77..8e4f417a 100644 --- a/src/hooks/useDeleteWorkspace.ts +++ b/src/hooks/useDeleteWorkspace.ts @@ -14,16 +14,10 @@ export function useDeleteWorkspace(projectName: string, projectNamespace: string ); const revalidate = useRevalidateApiResource(ListWorkspaces(projectName)); - const deleteWorkspace = useCallback(async (): Promise => { - try { - await trigger(); - await revalidate(); - toast.show(t('ControlPlaneListWorkspaceGridTile.deleteConfirmationDialog')); - return true; - } catch (e) { - console.error('Failed to delete workspace:', e); - return false; - } + const deleteWorkspace = useCallback(async (): Promise => { + await trigger(); + await revalidate(); + toast.show(t('ControlPlaneListWorkspaceGridTile.deleteConfirmationDialog')); }, [trigger, revalidate, toast, t]); return { From c472b45c9f4219f420c0f9a1312baa2ffcb044d5 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 30 Oct 2025 11:06:51 +0100 Subject: [PATCH 4/6] PR changes --- .../List/ControlPlaneListWorkspaceGridTile.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 5356a602..4ab86a2f 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -22,18 +22,18 @@ import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/Illustr import styles from './WorkspacesList.module.css'; import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx'; import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx'; -import { useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.ts'; +import { useDeleteWorkspace as _useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.ts'; interface Props { projectName: string; workspace: ListWorkspacesType; - useDeleteWorkspace?: typeof useDeleteWorkspace; + useDeleteWorkspace?: typeof _useDeleteWorkspace; } export function ControlPlaneListWorkspaceGridTile({ projectName, workspace, - useDeleteWorkspace: useDeleteWorkspaceHook = useDeleteWorkspace, + useDeleteWorkspace: useDeleteWorkspaceHook = _useDeleteWorkspace, }: Props) { const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false); const [initialTemplateName, setInitialTemplateName] = useState(undefined); From 6996751c4b64a817a2687f20c7f9713726461a52 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 30 Oct 2025 11:19:47 +0100 Subject: [PATCH 5/6] PR changes --- .../List/ControlPlaneListWorkspaceGridTile.tsx | 4 ++-- src/components/Dialogs/CreateWorkspaceDialogContainer.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 4ab86a2f..f9bb7d59 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -33,7 +33,7 @@ interface Props { export function ControlPlaneListWorkspaceGridTile({ projectName, workspace, - useDeleteWorkspace: useDeleteWorkspaceHook = _useDeleteWorkspace, + useDeleteWorkspace: useDeleteWorkspace = _useDeleteWorkspace, }: Props) { const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false); const [initialTemplateName, setInitialTemplateName] = useState(undefined); @@ -47,7 +47,7 @@ export function ControlPlaneListWorkspaceGridTile({ const [dialogDeleteWsIsOpen, setDialogDeleteWsIsOpen] = useState(false); const { data: controlplanes, error: cpsError } = useApiResource(ListControlPlanes(projectName, workspaceName)); - const { deleteWorkspace } = useDeleteWorkspaceHook(projectName, projectNamespace, workspaceName); + const { deleteWorkspace } = useDeleteWorkspace(projectName, projectNamespace, workspaceName); const { mcpCreationGuide } = useLink(); const errorView = createErrorView(cpsError); diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index 96448ea7..1d38ec58 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -25,8 +25,8 @@ export function CreateWorkspaceDialogContainer({ isOpen, setIsOpen, project = '', - useCreateWorkspace: useCreateWorkspaceHook = _useCreateWorkspace, - useAuthOnboarding: useAuthOnboardingHook = _useAuthOnboarding, + useCreateWorkspace: useCreateWorkspace = _useCreateWorkspace, + useAuthOnboarding: useAuthOnboarding = _useAuthOnboarding, }: { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; @@ -53,12 +53,12 @@ export function CreateWorkspaceDialogContainer({ chargingTargetType: '', }, }); - const { user } = useAuthOnboardingHook(); + const { user } = useAuthOnboarding(); const username = user?.email; const namespace = projectnameToNamespace(project); - const { createWorkspace } = useCreateWorkspaceHook(project, namespace); + const { createWorkspace } = useCreateWorkspace(project, namespace); const errorDialogRef = useRef(null); const clearForm = useCallback(() => { From 3da4741b02a87ef05f227003aa4ba25e5afd36e8 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 30 Oct 2025 11:24:46 +0100 Subject: [PATCH 6/6] PR changes --- .../ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx | 2 +- src/components/Dialogs/CreateWorkspaceDialogContainer.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index f9bb7d59..ae85eaff 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -33,7 +33,7 @@ interface Props { export function ControlPlaneListWorkspaceGridTile({ projectName, workspace, - useDeleteWorkspace: useDeleteWorkspace = _useDeleteWorkspace, + useDeleteWorkspace = _useDeleteWorkspace, }: Props) { const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false); const [initialTemplateName, setInitialTemplateName] = useState(undefined); diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index 1d38ec58..96dcf7a9 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -25,8 +25,8 @@ export function CreateWorkspaceDialogContainer({ isOpen, setIsOpen, project = '', - useCreateWorkspace: useCreateWorkspace = _useCreateWorkspace, - useAuthOnboarding: useAuthOnboarding = _useAuthOnboarding, + useCreateWorkspace = _useCreateWorkspace, + useAuthOnboarding = _useAuthOnboarding, }: { isOpen: boolean; setIsOpen: (isOpen: boolean) => void;