From f992bb0d7c7b829f77ad2bb7feab1944a85b04f8 Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Mon, 30 Jun 2025 17:25:17 +0200 Subject: [PATCH 01/26] feat: graph --- package.json | 4 +- pnpm-lock.yaml | 421 ++++++++++++++++++++++++ src/app/components/graph.component.html | 24 ++ src/app/components/graph.component.ts | 132 ++++++++ src/app/types/graph.types.ts | 16 + 5 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 src/app/components/graph.component.html create mode 100644 src/app/components/graph.component.ts create mode 100644 src/app/types/graph.types.ts diff --git a/package.json b/package.json index 34d762f7e..50a37b711 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "@ngx-grpc/core": "^3.1.2", "@ngx-grpc/grpc-web-client": "^3.1.2", "@ungap/structured-clone": "^1.3.0", + "d3": "^7.9.0", + "force-graph": "^1.49.6", "jest-junit": "^16.0.0", "luxon": "^3.6.1", "rxjs": "~7.8.2", @@ -52,9 +54,9 @@ "@types/ungap__structured-clone": "^1.2.0", "@typescript-eslint/eslint-plugin": "8.34.0", "@typescript-eslint/parser": "8.34.0", + "angular-eslint": "^19.8.0", "bumpp": "^9.11.1", "eslint": "^9.28.0", - "angular-eslint": "^19.8.0", "eslint-import-resolver-typescript": "^3.10.1", "eslint-plugin-import": "^2.31.0", "jest": "^29.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 363414c3f..1b9fb4c11 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,12 @@ importers: '@ungap/structured-clone': specifier: ^1.3.0 version: 1.3.0 + d3: + specifier: ^7.9.0 + version: 7.9.0 + force-graph: + specifier: ^1.49.6 + version: 1.49.6 jest-junit: specifier: ^16.0.0 version: 16.0.0 @@ -2274,6 +2280,9 @@ packages: resolution: {integrity: sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==} engines: {node: ^16.14.0 || >=18.0.0} + '@tweenjs/tween.js@25.0.0': + resolution: {integrity: sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -2669,6 +2678,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accessor-fn@1.5.3: + resolution: {integrity: sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==} + engines: {node: '>=12'} + acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} @@ -2922,6 +2935,9 @@ packages: batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + bezier-js@6.1.4: + resolution: {integrity: sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -3025,6 +3041,10 @@ packages: caniuse-lite@1.0.30001653: resolution: {integrity: sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==} + canvas-color-tracker@1.3.2: + resolution: {integrity: sha512-ryQkDX26yJ3CXzb3hxUVNlg1NKE4REc5crLBq661Nxzr8TNd236SaEf2ffYLXyI5tSABSeguHLqcVq4vf9L3Zg==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3136,6 +3156,10 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} @@ -3259,6 +3283,143 @@ packages: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-binarytree@1.0.2: + resolution: {integrity: sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force-3d@3.0.6: + resolution: {integrity: sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-octree@1.1.0: + resolution: {integrity: sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -3361,6 +3522,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -3803,6 +3967,10 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + float-tooltip@1.7.5: + resolution: {integrity: sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==} + engines: {node: '>=12'} + follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -3815,6 +3983,10 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + force-graph@1.49.6: + resolution: {integrity: sha512-o3uZ22YMvRwcS4RZ5lMQE5mCsQ5w1AzR4bPlQ1cThqgAxRrzOO4mGOaeNGTAkGGQwL6f7RIBCaxPNtvkbgAykw==} + engines: {node: '>=12'} + foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -4115,6 +4287,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + index-array-by@1.4.2: + resolution: {integrity: sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==} + engines: {node: '>=12'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -4137,6 +4313,10 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ip@2.0.0: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} @@ -4585,6 +4765,10 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} + kapsule@1.16.3: + resolution: {integrity: sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==} + engines: {node: '>=12'} + karma-source-map-support@1.4.0: resolution: {integrity: sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==} @@ -4675,6 +4859,9 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -5281,6 +5468,9 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} + preact@10.26.9: + resolution: {integrity: sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5475,6 +5665,9 @@ packages: engines: {node: '>=14.18'} hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.22.4: resolution: {integrity: sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -5491,6 +5684,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -5878,6 +6074,9 @@ packages: tiny-conventional-commits-parser@0.0.1: resolution: {integrity: sha512-N5+AZWdBeHNSgTIaxvx0+9mFrnW4H1BbjQ84H7i3TuWSkno8Hju886hLaHZhE/hYEKrfrfl/uHurqpZJHDuYGQ==} + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} @@ -8762,6 +8961,8 @@ snapshots: '@tufjs/canonical-json': 2.0.0 minimatch: 9.0.4 + '@tweenjs/tween.js@25.0.0': {} + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 @@ -9221,6 +9422,8 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accessor-fn@1.5.3: {} + acorn-globals@7.0.1: dependencies: acorn: 8.12.1 @@ -9526,6 +9729,8 @@ snapshots: batch@0.6.1: {} + bezier-js@6.1.4: {} + big.js@5.2.2: {} binary-extensions@2.2.0: {} @@ -9671,6 +9876,10 @@ snapshots: caniuse-lite@1.0.30001653: {} + canvas-color-tracker@1.3.2: + dependencies: + tinycolor2: 1.6.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -9773,6 +9982,8 @@ snapshots: commander@2.20.3: {} + commander@7.2.0: {} + common-path-prefix@3.0.0: {} compressible@2.0.18: @@ -9918,6 +10129,170 @@ snapshots: dependencies: cssom: 0.3.8 + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-binarytree@1.0.2: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force-3d@3.0.6: + dependencies: + d3-binarytree: 1.0.2 + d3-dispatch: 3.0.1 + d3-octree: 1.1.0 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-octree@1.1.0: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + data-urls@3.0.2: dependencies: abab: 2.0.6 @@ -9999,6 +10374,10 @@ snapshots: defu@6.1.4: {} + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} depd@1.1.2: {} @@ -10615,6 +10994,12 @@ snapshots: flatted@3.3.1: {} + float-tooltip@1.7.5: + dependencies: + d3-selection: 3.0.0 + kapsule: 1.16.3 + preact: 10.26.9 + follow-redirects@1.15.6(debug@4.4.1): optionalDependencies: debug: 4.4.1 @@ -10623,6 +11008,24 @@ snapshots: dependencies: is-callable: 1.2.7 + force-graph@1.49.6: + dependencies: + '@tweenjs/tween.js': 25.0.0 + accessor-fn: 1.5.3 + bezier-js: 6.1.4 + canvas-color-tracker: 1.3.2 + d3-array: 3.2.4 + d3-drag: 3.0.0 + d3-force-3d: 3.0.6 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + float-tooltip: 1.7.5 + index-array-by: 1.4.2 + kapsule: 1.16.3 + lodash-es: 4.17.21 + foreground-child@3.1.1: dependencies: cross-spawn: 7.0.6 @@ -10940,6 +11343,8 @@ snapshots: indent-string@4.0.0: {} + index-array-by@1.4.2: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -10975,6 +11380,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.4 + internmap@2.0.3: {} + ip@2.0.0: {} ipaddr.js@1.9.1: {} @@ -11607,6 +12014,10 @@ snapshots: jsonparse@1.3.1: {} + kapsule@1.16.3: + dependencies: + lodash-es: 4.17.21 + karma-source-map-support@1.4.0: dependencies: source-map-support: 0.5.21 @@ -11722,6 +12133,8 @@ snapshots: dependencies: p-locate: 6.0.0 + lodash-es@4.17.21: {} + lodash.debounce@4.0.8: {} lodash.memoize@4.1.2: {} @@ -12378,6 +12791,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + preact@10.26.9: {} + prelude-ls@1.2.1: {} pretty-format@29.7.0: @@ -12560,6 +12975,8 @@ snapshots: dependencies: glob: 10.4.1 + robust-predicates@3.0.2: {} + rollup@4.22.4: dependencies: '@types/estree': 1.0.5 @@ -12590,6 +13007,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@7.8.1: dependencies: tslib: 2.8.1 @@ -13011,6 +13430,8 @@ snapshots: tiny-conventional-commits-parser@0.0.1: {} + tinycolor2@1.6.0: {} + tinyexec@0.3.2: {} tinyglobby@0.2.10: diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html new file mode 100644 index 000000000..2fabac8cc --- /dev/null +++ b/src/app/components/graph.component.html @@ -0,0 +1,24 @@ + + + Session: {{ sessionId }} + + +
+ + {{getIcon('back')}} + Back to Sessions List + + +
+
+ + + Display Particles + +
+
+
+
\ No newline at end of file diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts new file mode 100644 index 000000000..788d07d92 --- /dev/null +++ b/src/app/components/graph.component.ts @@ -0,0 +1,132 @@ +import { AfterViewInit, Component, ElementRef, Input, ViewChild, inject } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatIconModule } from '@angular/material/icon'; +import { ArmoniKGraphNode, GraphLink } from '@app/types/graph.types'; +import { IconsService } from '@services/icons.service'; +import { forceLink, forceManyBody } from 'd3'; +import ForceGraph from 'force-graph'; +import { Observable, Subject, switchMap } from 'rxjs'; +import { AutoCompleteComponent } from './auto-complete.component'; + +@Component({ + selector: 'app-graph', + templateUrl: 'graph.component.html', + standalone: true, + imports: [ + MatCardModule, + MatIconModule, + AutoCompleteComponent, + MatCheckboxModule, + ], + providers: [], +}) +export class GraphComponent> implements AfterViewInit { + @Input({ required: true }) grpcObservable: Observable<{nodes: N[], links: L[]}>; + + @ViewChild('graph', { static: false }) readonly graphRef: ElementRef | null = null; + + graph!: ForceGraph; + canvasWidth: number = window.innerWidth; + canvasHeight: number = window.innerHeight; + + @Input() taskToFind: string = ''; + nodesToHighlight: Set = new Set(); + + colorMap: Map = new Map([ + ['taskResultLink', '#f7b657'], + ['parentLink', '#8A427AAA'], + ['dependencyLink', '#878adeDD'], + ]); + + private readonly iconsService = inject(IconsService); + private readonly refreshGraph$ = new Subject(); + + ngAfterViewInit(): void { + if (this.graphRef) { + this.graph = new ForceGraph(this.graphRef.nativeElement); + + this.graph + .d3Force('charge', forceManyBody().strength(-1000)) + .d3Force('link', forceLink().distance(50).iterations(10)) + .dagMode('td') + .dagLevelDistance(100) + .nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => + this.drawNode(node, 'red', ctx) + ) + .linkColor((link: L) => { + return this.getLinkColor(link); + }) + .linkWidth(4) + .nodeLabel('id') + .onNodeClick((node: N) => { + // this.setPanelData(node.id, node.type); + this.graph.centerAt(node.x, node.y); + this.graph.zoom(4, 2000); + }); + + this.refreshGraph$ + .pipe(switchMap(() => this.grpcObservable)) + .subscribe((result) => this.graph.graphData({ nodes: result.nodes, links: result.links })); + } + } + + refresh() { + this.refreshGraph$.next(); + } + + drawNode(node: N, color: string, ctx: CanvasRenderingContext2D) { + if (node.x && node.y) { + ctx.font = '50px Material Icons'; + ctx.fillStyle = color; + ctx.fillText(this.iconsService.getIcon(node.type), node.x, node.y); + } + } + + setParticles(checked: boolean) { + this.graph.linkDirectionalParticles(checked ? 1 : 0); + } + + getLinkColor(link: L): string { + switch (link.type) { + case 'parent': + return this.colorMap.get('parentLink')!; + case 'dependency': + return this.colorMap.get('dependencyLink')!; + default: + return this.colorMap.get('taskResultLink')!; + } + } + + getIcon(name: string) { + return this.iconsService.getIcon(name); + } + + /** + * Hightlight nodes with names included the searched value + * @param searchedValue + */ + highlightNodes(searchedValue: string) { + this.taskToFind = searchedValue; + this.nodesToHighlight.clear(); + this.graphdataService.nodes.forEach((node: TaskResultNode) => { + if ( + searchedValue !== '' && + node.id.includes(searchedValue) + ) { + this.nodesToHighlight.add(node.id); + } + }); + this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => + this.drawNode(node, 'red', ctx) + ); + } + + onResize(event: UIEvent) { + const w = event.target as Window; + this.canvasWidth = w.innerWidth; + this.canvasHeight = w.innerHeight; + this.graph.width(this.canvasWidth); + this.graph.height(this.canvasHeight); + } +} \ No newline at end of file diff --git a/src/app/types/graph.types.ts b/src/app/types/graph.types.ts new file mode 100644 index 000000000..409d01879 --- /dev/null +++ b/src/app/types/graph.types.ts @@ -0,0 +1,16 @@ +import { LinkObject, NodeObject } from 'force-graph'; +import { Status } from '../types/status'; + +export type NodeEventType = 'task' | 'session' | 'result'; +export type LinkType = 'parent' | 'dependency' | 'output'; + +export interface ArmoniKGraphNode extends NodeObject { + id: string; + status: Status; + type: NodeEventType; +} + + +export interface GraphLink extends LinkObject { + type: LinkType; +} \ No newline at end of file From 19f629b00075c82e6a03651ace4654b7ce59a5c5 Mon Sep 17 00:00:00 2001 From: faustin Date: Tue, 1 Jul 2025 17:34:13 +0200 Subject: [PATCH 02/26] chore: update graph component --- package.json | 1 + pnpm-lock.yaml | 218 ++++++++++++++++++++++++ src/app/components/graph.component.html | 11 +- src/app/components/graph.component.ts | 31 ++-- src/app/types/graph.types.ts | 9 +- 5 files changed, 253 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 50a37b711..43809b392 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@ngx-grpc/common": "^3.1.2", "@ngx-grpc/core": "^3.1.2", "@ngx-grpc/grpc-web-client": "^3.1.2", + "@types/d3": "^7.4.3", "@ungap/structured-clone": "^1.3.0", "d3": "^7.9.0", "force-graph": "^1.49.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b9fb4c11..85883bb1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: '@ngx-grpc/grpc-web-client': specifier: ^3.1.2 version: 3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(grpc-web@1.4.2)(rxjs@7.8.2) + '@types/d3': + specifier: ^7.4.3 + version: 7.4.3 '@ungap/structured-clone': specifier: ^1.3.0 version: 1.3.0 @@ -2310,6 +2313,99 @@ packages: '@types/connect@3.4.35': resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/eslint-scope@3.7.4': resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} @@ -2328,6 +2424,9 @@ packages: '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/google-protobuf@3.15.12': resolution: {integrity: sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==} @@ -9007,6 +9106,123 @@ snapshots: dependencies: '@types/node': 22.15.31 + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/eslint-scope@3.7.4': dependencies: '@types/eslint': 8.40.2 @@ -9035,6 +9251,8 @@ snapshots: '@types/qs': 6.9.7 '@types/serve-static': 1.15.7 + '@types/geojson@7946.0.16': {} + '@types/google-protobuf@3.15.12': {} '@types/graceful-fs@4.1.6': diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index 2fabac8cc..10d798bad 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -6,16 +6,19 @@
{{getIcon('back')}} - Back to Sessions List + Back to Sessions List
- - + + + + + Display Particles
diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 788d07d92..60d49481e 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -1,13 +1,13 @@ import { AfterViewInit, Component, ElementRef, Input, ViewChild, inject } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; -import { ArmoniKGraphNode, GraphLink } from '@app/types/graph.types'; +import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; import { IconsService } from '@services/icons.service'; import { forceLink, forceManyBody } from 'd3'; import ForceGraph from 'force-graph'; import { Observable, Subject, switchMap } from 'rxjs'; -import { AutoCompleteComponent } from './auto-complete.component'; @Component({ selector: 'app-graph', @@ -16,13 +16,14 @@ import { AutoCompleteComponent } from './auto-complete.component'; imports: [ MatCardModule, MatIconModule, - AutoCompleteComponent, + MatFormFieldModule, MatCheckboxModule, ], providers: [], }) export class GraphComponent> implements AfterViewInit { - @Input({ required: true }) grpcObservable: Observable<{nodes: N[], links: L[]}>; + @Input({ required: true }) grpcObservable: Observable>; + @Input({ required: true }) readonly sessionId: string; @ViewChild('graph', { static: false }) readonly graphRef: ElementRef | null = null; @@ -42,6 +43,8 @@ export class GraphComponent> private readonly iconsService = inject(IconsService); private readonly refreshGraph$ = new Subject(); + private nodes: N[]; + ngAfterViewInit(): void { if (this.graphRef) { this.graph = new ForceGraph(this.graphRef.nativeElement); @@ -65,12 +68,19 @@ export class GraphComponent> this.graph.zoom(4, 2000); }); + this.grpcObservable.subscribe((result) => this.subscribeToData(result)); + this.refreshGraph$ .pipe(switchMap(() => this.grpcObservable)) - .subscribe((result) => this.graph.graphData({ nodes: result.nodes, links: result.links })); + .subscribe((result) => this.subscribeToData(result)); } } + subscribeToData(result: GraphData) { + this.nodes = result.nodes; + this.graph.graphData({ nodes: result.nodes, links: result.links }); + } + refresh() { this.refreshGraph$.next(); } @@ -106,13 +116,12 @@ export class GraphComponent> * Hightlight nodes with names included the searched value * @param searchedValue */ - highlightNodes(searchedValue: string) { - this.taskToFind = searchedValue; + highlightNodes(searchedValue: Event) { + this.taskToFind = (searchedValue.target as HTMLInputElement).value; this.nodesToHighlight.clear(); - this.graphdataService.nodes.forEach((node: TaskResultNode) => { - if ( - searchedValue !== '' && - node.id.includes(searchedValue) + this.nodes.forEach((node: N) => { + if (this.taskToFind !== '' && + node.id.includes(this.taskToFind) ) { this.nodesToHighlight.add(node.id); } diff --git a/src/app/types/graph.types.ts b/src/app/types/graph.types.ts index 409d01879..5a5b2c558 100644 --- a/src/app/types/graph.types.ts +++ b/src/app/types/graph.types.ts @@ -4,13 +4,18 @@ import { Status } from '../types/status'; export type NodeEventType = 'task' | 'session' | 'result'; export type LinkType = 'parent' | 'dependency' | 'output'; + export interface ArmoniKGraphNode extends NodeObject { id: string; status: Status; type: NodeEventType; } - export interface GraphLink extends LinkObject { type: LinkType; -} \ No newline at end of file +} + +export type GraphData> = { + nodes: N[], + links: L[] +}; \ No newline at end of file From d317b2631c59b067978abc6b4031cf80944639d8 Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Wed, 2 Jul 2025 11:26:54 +0200 Subject: [PATCH 03/26] feat: graph basic components --- src/app/components/graph-legend.component.css | 18 +++++ .../components/graph-legend.component.html | 72 +++++++++++++++++++ src/app/components/graph-legend.component.ts | 60 ++++++++++++++++ src/app/components/graph.component.css | 36 ++++++++++ src/app/components/graph.component.html | 15 ++-- src/app/components/graph.component.ts | 63 +++++++++++++--- src/app/services/icons.service.ts | 6 ++ 7 files changed, 252 insertions(+), 18 deletions(-) create mode 100644 src/app/components/graph-legend.component.css create mode 100644 src/app/components/graph-legend.component.html create mode 100644 src/app/components/graph-legend.component.ts create mode 100644 src/app/components/graph.component.css diff --git a/src/app/components/graph-legend.component.css b/src/app/components/graph-legend.component.css new file mode 100644 index 000000000..515919d80 --- /dev/null +++ b/src/app/components/graph-legend.component.css @@ -0,0 +1,18 @@ +section { + display: grid; + grid-template-rows: repeat(6, 1fr); + grid-auto-flow: column; + gap: 0.25rem 0.25rem; +} + +main { + display: flex; + justify-content: space-evenly; + width: 100%; + gap: 1rem; +} + +.section-header { + display: flex; + flex-direction: row; +} \ No newline at end of file diff --git a/src/app/components/graph-legend.component.html b/src/app/components/graph-legend.component.html new file mode 100644 index 000000000..84bc6e34a --- /dev/null +++ b/src/app/components/graph-legend.component.html @@ -0,0 +1,72 @@ + + + Legend + +
+
+
+ {{ getIcon('session-graph-icon') }} +

Sessions Statuses

+
+
+ @for (status of sessionsStatuses; track status) { + @let statusData = sessionsStatusesService.statusToLabel(status); + + + {{ statusData.label }} + + } +
+
+ + + +
+
+ {{ getIcon('task-graph-icon') }} +

Tasks Statuses

+
+
+ @for (status of tasksStatuses; track status) { + @let statusData = tasksStatusesService.statusToLabel(status); + + + {{ statusData.label }} + + } +
+
+ + + +
+
+ {{ getIcon('result-graph-icon') }} +

Results Statuses

+
+
+ @for (status of resultsStatuses; track status) { + @let statusData = resultsStatusesService.statusToLabel(status); + + + {{ statusData.label }} + + } +
+
+ + + +
+

Links

+
+ @for (link of links; track link.label) { + + + {{ link.label }} + + } +
+
+
+
\ No newline at end of file diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts new file mode 100644 index 000000000..42083ac36 --- /dev/null +++ b/src/app/components/graph-legend.component.ts @@ -0,0 +1,60 @@ +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatIconModule } from '@angular/material/icon'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { IconsService } from '@services/icons.service'; + +@Component({ + selector: 'app-graph-legend', + templateUrl: 'graph-legend.component.html', + styleUrl: 'graph-legend.component.css', + standalone: true, + imports: [ + MatExpansionModule, + MatChipsModule, + MatIconModule, + MatDividerModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class GraphLegendComponent implements OnInit { + private readonly iconsService = inject(IconsService); + readonly sessionsStatusesService = inject(SessionsStatusesService); + readonly tasksStatusesService = inject(TasksStatusesService); + readonly resultsStatusesService = inject(ResultsStatusesService); + + links: { label: string, color: string }[] = [ + { + label: 'Task result', + color: '#f7b657', + }, + { + label: 'Parent', + color: '#8A427AAA', + }, + { + label: 'Dependency', + color: '#878adeDD', + } + ]; + + // TODO: this part will be useless when statuses are merged + sessionsStatuses: SessionStatus[]; + tasksStatuses: TaskStatus[]; + resultsStatuses: ResultStatus[]; + + ngOnInit(): void { + this.sessionsStatuses = Object.keys(this.sessionsStatusesService.statuses).map((key) => Number(key) as SessionStatus); + this.tasksStatuses = Object.keys(this.tasksStatusesService.statuses).map((key) => Number(key) as TaskStatus); + this.resultsStatuses = Object.keys(this.resultsStatusesService.statuses).map((key) => Number(key) as ResultStatus); + } + + getIcon(name: string | undefined) { + return this.iconsService.getIcon(name); + } +} \ No newline at end of file diff --git a/src/app/components/graph.component.css b/src/app/components/graph.component.css new file mode 100644 index 000000000..c18b2e22a --- /dev/null +++ b/src/app/components/graph.component.css @@ -0,0 +1,36 @@ +mat-card { + position: absolute; + z-index: 2; + top: 1rem; + left: 3rem; + width: fit-content; +} + +mat-card-title { + width: fit-content !important; +} + +mat-card-actions { + display: flex; + justify-content: space-between; + gap: 2rem; + align-items: start; +} + +mat-card-actions > section { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +app-graph-legend { + position: absolute; + z-index: 2; + bottom: 0; + left:0; +} + +.graph { + overflow: hidden; + height: 80vh; +} \ No newline at end of file diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index 10d798bad..e6ed48fa1 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -4,9 +4,9 @@
- - {{getIcon('back')}} - Back to Sessions List + + {{ getIcon('back') }} + Back to Sessions List
- - - + + Highlight a task + Display Particles @@ -24,4 +24,5 @@
-
\ No newline at end of file + +
\ No newline at end of file diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 60d49481e..a92746e05 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -1,29 +1,50 @@ -import { AfterViewInit, Component, ElementRef, Input, ViewChild, inject } from '@angular/core'; +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { RouterModule } from '@angular/router'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; +import { StatusLabelColor } from '@app/types/status'; import { IconsService } from '@services/icons.service'; import { forceLink, forceManyBody } from 'd3'; import ForceGraph from 'force-graph'; import { Observable, Subject, switchMap } from 'rxjs'; +import { GraphLegendComponent } from './graph-legend.component'; @Component({ selector: 'app-graph', templateUrl: 'graph.component.html', + styleUrl: 'graph.component.css', standalone: true, imports: [ MatCardModule, MatIconModule, - MatFormFieldModule, MatCheckboxModule, + MatFormFieldModule, + MatButtonModule, + MatInputModule, + RouterModule, + GraphLegendComponent, + MatTooltipModule, ], - providers: [], + providers: [ + SessionsStatusesService, + TasksStatusesService, + ResultsStatusesService, + ], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class GraphComponent> implements AfterViewInit { @Input({ required: true }) grpcObservable: Observable>; - @Input({ required: true }) readonly sessionId: string; + @Input({ required: true }) sessionId: string; @ViewChild('graph', { static: false }) readonly graphRef: ElementRef | null = null; @@ -41,6 +62,10 @@ export class GraphComponent> ]); private readonly iconsService = inject(IconsService); + private readonly sessionsStatusesService = inject(SessionsStatusesService); + private readonly tasksStatusesService = inject(TasksStatusesService); + private readonly resultsStatusesService = inject(ResultsStatusesService); + private readonly refreshGraph$ = new Subject(); private nodes: N[]; @@ -55,7 +80,7 @@ export class GraphComponent> .dagMode('td') .dagLevelDistance(100) .nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => - this.drawNode(node, 'red', ctx) + this.drawNode(node, ctx) ) .linkColor((link: L) => { return this.getLinkColor(link); @@ -63,7 +88,6 @@ export class GraphComponent> .linkWidth(4) .nodeLabel('id') .onNodeClick((node: N) => { - // this.setPanelData(node.id, node.type); this.graph.centerAt(node.x, node.y); this.graph.zoom(4, 2000); }); @@ -85,11 +109,12 @@ export class GraphComponent> this.refreshGraph$.next(); } - drawNode(node: N, color: string, ctx: CanvasRenderingContext2D) { + drawNode(node: N, ctx: CanvasRenderingContext2D) { if (node.x && node.y) { + const label = this.getNodeStatusData(node); ctx.font = '50px Material Icons'; - ctx.fillStyle = color; - ctx.fillText(this.iconsService.getIcon(node.type), node.x, node.y); + ctx.fillStyle = label.color; + ctx.fillText(this.iconsService.getIcon(`${node.type}-graph-icon`), node.x - 25, node.y + 25); } } @@ -97,6 +122,22 @@ export class GraphComponent> this.graph.linkDirectionalParticles(checked ? 1 : 0); } + private getNodeStatusData(node: N): StatusLabelColor { + switch (node.type) { + case 'session': + return this.sessionsStatusesService.statusToLabel(node.status as SessionStatus); + case 'task': + return this.tasksStatusesService.statusToLabel(node.status as TaskStatus); + case 'result': + return this.resultsStatusesService.statusToLabel(node.status as ResultStatus); + default: + return { + label: $localize`Unknown`, + color: 'grey', + }; + } + } + getLinkColor(link: L): string { switch (link.type) { case 'parent': @@ -108,7 +149,7 @@ export class GraphComponent> } } - getIcon(name: string) { + getIcon(name: string | undefined) { return this.iconsService.getIcon(name); } @@ -127,7 +168,7 @@ export class GraphComponent> } }); this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => - this.drawNode(node, 'red', ctx) + this.drawNode(node, ctx) ); } diff --git a/src/app/services/icons.service.ts b/src/app/services/icons.service.ts index 04469f2fa..a58f58b2c 100644 --- a/src/app/services/icons.service.ts +++ b/src/app/services/icons.service.ts @@ -84,6 +84,12 @@ export class IconsService { 'retry': 'repeat_on', 'pending': 'pending', 'creating': 'create', + 'session-graph-icon': 'change_history', + 'task-graph-icon': 'circle', + 'result-graph-icon': 'rectangle', + 'line': 'remove', + 'back': 'arrow_back_ios_new', + 'graph': 'insights', }; getIcon(name: string | null | undefined): string { From 1573d57a473f22fd76aa539ad16bbbde9a80253b Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Wed, 2 Jul 2025 11:27:06 +0200 Subject: [PATCH 04/26] feat: session graph --- src/app/services/graph-data.service.ts | 211 ++++++++++++++++++ src/app/services/grpc-events.service.ts | 19 ++ .../sessions/components/table.component.ts | 8 + src/app/sessions/graph.component.html | 1 + src/app/sessions/graph.component.ts | 43 ++++ src/app/sessions/routes.ts | 2 + 6 files changed, 284 insertions(+) create mode 100644 src/app/services/graph-data.service.ts create mode 100644 src/app/services/grpc-events.service.ts create mode 100644 src/app/sessions/graph.component.html create mode 100644 src/app/sessions/graph.component.ts diff --git a/src/app/services/graph-data.service.ts b/src/app/services/graph-data.service.ts new file mode 100644 index 000000000..5f2e019f1 --- /dev/null +++ b/src/app/services/graph-data.service.ts @@ -0,0 +1,211 @@ +import { EventSubscriptionResponse, ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { Injectable, inject } from '@angular/core'; +import { ArmoniKGraphNode, GraphLink, LinkType, NodeEventType } from '@app/types/graph.types'; +import { GraphData } from 'force-graph'; +import { Observable, Subject, of, switchMap } from 'rxjs'; +import { GrpcEventsService } from './grpc-events.service'; +import { Status } from '../types/status'; + +@Injectable() +export class GraphDataService { + private readonly grpcEventsService = inject(GrpcEventsService); + + sessionId: string = ''; + + readonly nodes: ArmoniKGraphNode[] = []; + readonly links: GraphLink[] = []; + + private missingSources: GraphLink[] = []; + + readonly updateGraphSubject = new Subject(); + + /** + * Add the session node to the nodes array. + * Subscribe to the ArmoniK events associated to the current session. + * Handles : + * - New Task event: create a task node and its links + * - New Result event: create a result node and its links + * - Task status update event: update the status of a task node + * - Result status update event: update the status of a result node + * - Result Owner update event: update the task owner of a result + */ + listenToEvents(): Observable>> { + this.addSession(); + return this.grpcEventsService.getEvents$(this.sessionId) + .pipe( + switchMap((event: EventSubscriptionResponse) => { + switch(event.update) { + case (EventSubscriptionResponse.UpdateCase.newTask): { + this.addTask(event.newTask); + break; + } + case (EventSubscriptionResponse.UpdateCase.newResult): { + this.addResult(event.newResult); + break; + } + case (EventSubscriptionResponse.UpdateCase.taskStatusUpdate): { + this.updateStatus( + event.taskStatusUpdate!.taskId, + event.taskStatusUpdate!.status + ); + break; + } + case (EventSubscriptionResponse.UpdateCase.resultStatusUpdate): { + this.updateStatus( + event.resultStatusUpdate!.resultId, + event.resultStatusUpdate!.status + ); + break; + } + case (EventSubscriptionResponse.UpdateCase.resultOwnerUpdate): { + this.updateTaskOwner( + event.resultOwnerUpdate!.resultId, + event.resultOwnerUpdate!.previousOwnerId, + event.resultOwnerUpdate!.currentOwnerId + ); + break; + } + default: { + console.warn('Unknown Grpc Update Event.'); + } + } + return of({ nodes: this.nodes, links: this.links }); + }) + ); + } + + /** + * Return a node based on its Id. If none is found, return `undefined`. + */ + private getNodeById(id: string): ArmoniKGraphNode | undefined { + return this.nodes.find(node => node.id === id); + } + + /** + * Check if a node with the same Id exists. If none are found, creates the node. + * If a node is found and its status is different, updates the status. + * @param id + * @param status + * @param type + */ + private createNode(id: string, status: Status, type: NodeEventType) { + const node = this.getNodeById(id); + if (!node) { + const node: ArmoniKGraphNode = { id, status, type }; + this.nodes.push(node); + this.checkForMissingSource(node); + } else if (node.status !== status) { + node.status = status; + } + } + + /** + * Create a task node. + * If the node has dependencies, it will create dependencies link. + * If the node has no dependencies, it will create links with parent tasks. + */ + private addTask(newTask: EventSubscriptionResponse.NewTask | undefined) { + if (newTask) { + this.createNode(newTask.taskId, newTask.status, 'task'); + if (newTask.dataDependencies.length === 0) { + this.addParentTask( + newTask.taskId, + newTask.parentTaskIds.at(-1) as string + ); + } else { + newTask.dataDependencies.forEach(dependencyId => { + this.addDependency(newTask.taskId, dependencyId); + }); + } + } + } + + /** + * Creates the session node. + */ + private addSession() { + this.createNode(this.sessionId, SessionStatus.SESSION_STATUS_RUNNING, 'session'); + } + + /** + * Create a result ands its link with the owner task. + */ + private addResult(newResult: EventSubscriptionResponse.NewResult | undefined) { + if (newResult) { + this.createNode(newResult.resultId, newResult.status, 'result'); + this.addTaskOwner(newResult.resultId, newResult.ownerId); + } + } + + /** + * Update the status of a result or task node + */ + private updateStatus(nodeId: string, newStatus: TaskStatus | ResultStatus) { + const node = this.getNodeById(nodeId); + if (node) { + node.status = newStatus; + } + } + + /** + * Check if a link with the same source and target exist in the Link array. + * If none is found, creates the link. + * @param target end of the link + * @param source start of the link + * @param type parent | dependency | output + */ + private addLink(target: string, source: string, type: LinkType) { + if (!this.links.find(link => link.source === source && link.target === target)) { + if (this.getNodeById(source)) { + this.links.push({source, target, type}); + } else { + this.missingSources.push({ target, source, type }); + } + } + } + + /** + * Creates a link between a task (target) and its parent task (source) + */ + private addParentTask(taskId: string, parentTaskId: string) { + this.addLink(taskId, parentTaskId, 'parent'); + } + + /** + * Creates a link between a result (source) and a task (target). + */ + private addDependency(taskId: string, dependencyId: string) { + this.addLink(taskId, dependencyId, 'dependency'); + } + + /** + * Creates a link between a result (target) and its owner task (source) + * @param resultId + * @param taskOwnerId + */ + private addTaskOwner(resultId: string, taskOwnerId: string) { + if (taskOwnerId !== '') { + this.addLink(resultId, taskOwnerId, 'output'); + } + } + + /** + * Update the owner task id of a result. + */ + private updateTaskOwner(resultId: string, previousTaskOwnerId: string, newTaskOwnerId: string) { + const link = this.links.find(link => link.target === resultId && link.source === previousTaskOwnerId); + if (link) { + link.source = newTaskOwnerId; + } else { + this.addTaskOwner(resultId, newTaskOwnerId); + } + } + + private checkForMissingSource(node: ArmoniKGraphNode) { + const result = this.missingSources.find((link) => link.source === node.id); + if (result) { + this.links.push(result); + this.missingSources = this.missingSources.filter((link) => link.source !== node.id); + } + } +} \ No newline at end of file diff --git a/src/app/services/grpc-events.service.ts b/src/app/services/grpc-events.service.ts new file mode 100644 index 000000000..3e25a5c50 --- /dev/null +++ b/src/app/services/grpc-events.service.ts @@ -0,0 +1,19 @@ +import { + EventSubscriptionRequest, + EventSubscriptionResponse, + EventsClient, +} from '@aneoconsultingfr/armonik.api.angular'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; + +@Injectable() +export class GrpcEventsService { + private readonly client = inject(EventsClient); + + getEvents$(sessionId: string): Observable { + const request = new EventSubscriptionRequest({ + sessionId, + }); + return this.client.getEvents(request); + } +} diff --git a/src/app/sessions/components/table.component.ts b/src/app/sessions/components/table.component.ts index b30913cd8..723adfbf1 100644 --- a/src/app/sessions/components/table.component.ts +++ b/src/app/sessions/components/table.component.ts @@ -67,6 +67,9 @@ export class SessionsTableComponent extends AbstractTaskByStatusTableComponent>(); deleteSessionSubscription = this.deleteSession$.subscribe(data => this.onDelete(data.raw.sessionId)); + seeGraph$ = new Subject>(); + seeGraphSubscription = this.seeGraph$.subscribe(data => this.router.navigate(['/sessions', 'graph', data.raw.sessionId])); + actions: ActionTable[] = [ { label: 'Copy session ID', @@ -83,6 +86,11 @@ export class SessionsTableComponent extends AbstractTaskByStatusTableComponent \ No newline at end of file diff --git a/src/app/sessions/graph.component.ts b/src/app/sessions/graph.component.ts new file mode 100644 index 000000000..67cae064e --- /dev/null +++ b/src/app/sessions/graph.component.ts @@ -0,0 +1,43 @@ +import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; +import { GraphComponent } from '@components/graph.component'; +import { GraphDataService } from '@services/graph-data.service'; +import { GrpcEventsService } from '@services/grpc-events.service'; +import { Observable, Subscription, map } from 'rxjs'; + +@Component({ + selector: 'app-session-graph', + templateUrl: 'graph.component.html', + standalone: true, + imports: [ + GraphComponent, + ], + providers: [ + GrpcEventsService, + GraphDataService, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SessionGraphComponent implements OnInit { + id: string; + + grpcObservable: Observable>>; + + private readonly route = inject(ActivatedRoute); + private readonly graphDataService = inject(GraphDataService); + + private readonly subscriptions = new Subscription(); + + ngOnInit(): void { + const routeSubscription = this.route.params.pipe( + map(params => params['id']), + ).subscribe(id => { + this.id = id; + this.graphDataService.sessionId = id; + }); + this.grpcObservable = this.graphDataService.listenToEvents(); + + this.subscriptions.add(routeSubscription); + } +} \ No newline at end of file diff --git a/src/app/sessions/routes.ts b/src/app/sessions/routes.ts index 25f85c49c..d20777c32 100644 --- a/src/app/sessions/routes.ts +++ b/src/app/sessions/routes.ts @@ -1,8 +1,10 @@ import { Route } from '@angular/router'; +import { SessionGraphComponent } from './graph.component'; import { IndexComponent } from './index.component'; import { ShowComponent } from './show.component'; export const SESSIONS_ROUTES: Route[] = [ { path: '', component: IndexComponent }, { path: ':id', component: ShowComponent }, + { path: 'graph/:id', component: SessionGraphComponent }, ]; From 667ce725ed0b957af5a04dc5a3d90150f6bb5483 Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Wed, 2 Jul 2025 14:46:35 +0200 Subject: [PATCH 05/26] test: graph legend component --- .../components/graph-legend.component.spec.ts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/app/components/graph-legend.component.spec.ts diff --git a/src/app/components/graph-legend.component.spec.ts b/src/app/components/graph-legend.component.spec.ts new file mode 100644 index 000000000..2ad37b284 --- /dev/null +++ b/src/app/components/graph-legend.component.spec.ts @@ -0,0 +1,85 @@ +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { IconsService } from '@services/icons.service'; +import { GraphLegendComponent } from './graph-legend.component'; + +describe('GraphLegendComponent', () => { + let component: GraphLegendComponent; + + const mockTasksStatusesService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'cancelled' + }, + [TaskStatus.TASK_STATUS_CREATING]: { + label: 'creating' + }, + }, + }; + + const mockSessionsStatusesService = { + statuses: { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [SessionStatus.SESSION_STATUS_CLOSED]: { + label: 'Closed', + }, + }, + }; + + const mockResultsStatusesService = { + statuses: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed' + }, + }, + }; + + const mockIconsService = { + getIcon: jest.fn(), + }; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + GraphLegendComponent, + { provide: SessionsStatusesService, useValue: mockSessionsStatusesService }, + { provide: TasksStatusesService, useValue: mockTasksStatusesService }, + { provide: ResultsStatusesService, useValue: mockResultsStatusesService }, + { provide: IconsService, useValue: mockIconsService }, + ] + }).inject(GraphLegendComponent); + component.ngOnInit(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('initialisation', () => { + it('should set sessionsStatuses', () => { + expect(component.sessionsStatuses).toEqual([SessionStatus.SESSION_STATUS_CANCELLED, SessionStatus.SESSION_STATUS_CLOSED]); + }); + + it('should set TaskStatuses', () => { + expect(component.tasksStatuses).toEqual([TaskStatus.TASK_STATUS_CANCELLED, TaskStatus.TASK_STATUS_CANCELLING]); + }); + + it('should set resultsStatuses', () => { + expect(component.resultsStatuses).toEqual([ResultStatus.RESULT_STATUS_ABORTED, ResultStatus.RESULT_STATUS_COMPLETED]); + }); + }); + + it('should get icons', () => { + const icon = 'heart'; + component.getIcon(icon); + expect(mockIconsService.getIcon).toHaveBeenCalledWith(icon); + }); +}); \ No newline at end of file From e74172298fe2210ad1eab31e5994186955ecb377 Mon Sep 17 00:00:00 2001 From: faustin Date: Thu, 3 Jul 2025 16:23:03 +0200 Subject: [PATCH 06/26] chore: tests and doc for graph component --- jest.config.ts | 4 +- src/app/components/graph.component.html | 4 +- src/app/components/graph.component.spec.ts | 289 +++++++++++++++++++++ src/app/components/graph.component.ts | 147 +++++++---- test/d3.js | 10 + test/force-graph.js | 52 ++++ 6 files changed, 448 insertions(+), 58 deletions(-) create mode 100644 src/app/components/graph.component.spec.ts create mode 100644 test/d3.js create mode 100644 test/force-graph.js diff --git a/jest.config.ts b/jest.config.ts index f0c6d4279..cac7ee8c6 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -97,7 +97,9 @@ const config: Config = { '@components/(.*)': '/src/app/components/$1', '@services/(.*)': '/src/app/services/$1', '@pipes/(.*)': '/src/app/pipes/$1', - '@app/(.*)': '/src/app/$1' + '@app/(.*)': '/src/app/$1', + '^d3$': '/test/d3.js', + '^force-graph$': '/test/force-graph.js', }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index e6ed48fa1..d171048f2 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -8,9 +8,9 @@ {{ getIcon('back') }} Back to Sessions List -
diff --git a/src/app/components/graph.component.spec.ts b/src/app/components/graph.component.spec.ts new file mode 100644 index 000000000..4d7b8b7a3 --- /dev/null +++ b/src/app/components/graph.component.spec.ts @@ -0,0 +1,289 @@ +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { ElementRef } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; +import { IconsService } from '@services/icons.service'; +import { Subject } from 'rxjs'; +import { GraphComponent } from './graph.component'; + +describe('GraphComponent', () => { + let component: GraphComponent>; + + const grpcObservable = new Subject>>(); + + const mockSessionsStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Running', + color: 'green' + })), + }; + + const mockTasksStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Completed', + color: 'green' + })), + }; + + const mockResultsStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Completed', + color: 'green' + })), + }; + + const mockIconsService = { + getIcon: jest.fn(v => v) + }; + + const mockGraph = { + nativeElement: {} + } as ElementRef; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + GraphComponent, + { provide: IconsService, useValue: mockIconsService }, + { provide: SessionsStatusesService, useValue: mockSessionsStatuses }, + { provide: TasksStatusesService, useValue: mockTasksStatuses }, + { provide: ResultsStatusesService, useValue: mockResultsStatuses }, + ] + }).inject(GraphComponent>); + + component.grpcObservable = grpcObservable; + component['canvasHeight'] = 100; + component['canvasWidth'] = 100; + component['graphRef'] = mockGraph; + component.ngAfterViewInit(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Initialisation', () => { + it('should set the graph', () => { + expect(component['graph']).toBeDefined(); + }); + + it('should subscribe the provided observable', () => { + expect(grpcObservable.observed).toBeTruthy(); + }); + + it('should subscribe the refresh observable', () => { + expect(component['redrawGraph$'].observed).toBeTruthy(); + }); + }); + + it('should redraw properly', () => { + const spy = jest.spyOn(component['redrawGraph$'], 'next'); + component.redraw(); + expect(spy).toHaveBeenCalled(); + }); + + it('should get icons', () => { + const name = 'heart'; + component.getIcon(name); + expect(mockIconsService.getIcon).toHaveBeenCalledWith(name); + }); + + it('should highlight nodes correctly', () => { + component['nodes'] = [ + { + id: 'abc', + }, + { + id: '123abc', + }, + { + id: '123', + }, + ] as ArmoniKGraphNode[]; + + const event = { + target: { + value: 'abc', + }, + } as unknown as Event; + component.highlightNodes(event); + expect(component['nodesToHighlight']).toEqual(new Set(['abc', '123abc'])); + }); + + describe('onResize', () => { + const dimensions = { + innerHeight: 10, + innerWidth: 10, + }; + const event = { + target: dimensions, + } as unknown as UIEvent; + + beforeEach(() => { + component.onResize(event); + }); + + it('should update the canvas width', () => { + expect(component['canvasWidth']).toEqual(dimensions.innerWidth); + }); + + it('should set the canvas width to the graph', () => { + expect(component['graph'].width).toHaveBeenCalledWith(dimensions.innerWidth); + }); + + it('should update the canvas height', () => { + expect(component['canvasHeight']).toEqual(dimensions.innerHeight); + }); + + it('should set the canvas height to the graph', () => { + expect(component['graph'].height).toHaveBeenCalledWith(dimensions.innerHeight); + }); + }); + + describe('setParticles', () => { + it('should display particles', () => { + component.setParticles(true); + expect(component['graph'].linkDirectionalParticles).toHaveBeenCalledWith(1); + }); + + it('should stop displaying particles', () => { + component.setParticles(false); + expect(component['graph'].linkDirectionalParticles).toHaveBeenCalledWith(0); + }); + }); + + it('should draw a node', () => { + const node = { + x: 0, + y: 0, + type: 'session', + } as ArmoniKGraphNode; + + const mockCtx = { + fillText: jest.fn(), + } as unknown as CanvasRenderingContext2D; + + component['drawNode'](node, mockCtx); + + expect(mockCtx.fillText).toHaveBeenCalledWith( + `${node.type}-graph-icon`, + node.x! - 25, + node.y! + 25, + ); + }); + + describe('getNodeStatusData', () => { + it('should return the running session label', () => { + const node = { + type: 'session', + status: SessionStatus.SESSION_STATUS_RUNNING, + } as ArmoniKGraphNode; + expect(component['getNodeStatusData'](node)).toEqual( + mockSessionsStatuses.statusToLabel() + ); + }); + + it('should return the running task label', () => { + const node = { + type: 'task', + status: TaskStatus.TASK_STATUS_COMPLETED, + } as ArmoniKGraphNode; + expect(component['getNodeStatusData'](node)).toEqual( + mockTasksStatuses.statusToLabel() + ); + }); + + it('should return the running result label', () => { + const node = { + type: 'result', + status: ResultStatus.RESULT_STATUS_COMPLETED, + } as ArmoniKGraphNode; + expect(component['getNodeStatusData'](node)).toEqual( + mockResultsStatuses.statusToLabel() + ); + }); + + + it('should get the default color', () => { + const node = { + type: 'unknown', + status: ResultStatus.RESULT_STATUS_COMPLETED, + } as unknown as ArmoniKGraphNode; + + expect(component['getNodeStatusData'](node)).toEqual({ + label: 'Unknown', + color: 'grey' + }); + }); + }); + + describe('getLinkColor', () => { + it('should get the parentlink color', () => { + const link = { + type: 'parent' + } as GraphLink; + expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('parentLink')); + }); + + it('should get the dependencyLink color', () => { + const link = { + type: 'dependency' + } as GraphLink; + expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('dependencyLink')); + }); + + it('should get the taskResultLink color', () => { + const link = { + type: 'output' + } as GraphLink; + expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('taskResultLink')); + }); + }); + + describe('On new node data', () => { + const nodes = [ + { + id: 'abc', + }, + { + id: '123', + }, + ] as ArmoniKGraphNode[]; + + const links = [ + { + source: 'abc', + target: '123', + }, + ] as GraphLink[]; + + beforeEach(() => { + grpcObservable.next({ + nodes: nodes, + links: links, + }); + }); + + it('should update the component nodes', () => { + expect(component['nodes']).toEqual(nodes); + }); + + it('should redraw the graph', () => { + expect(component['graph'].graphData).toHaveBeenCalledWith({ + nodes: nodes, + links: links, + }); + }); + + it('should center the node', () => { + expect(component['graph'].centerAt).toHaveBeenCalled(); + }); + + it('should zoom on the node' ,() => { + expect(component['graph'].zoom).toHaveBeenCalled(); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index a92746e05..505b9ceca 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -16,7 +16,7 @@ import { StatusLabelColor } from '@app/types/status'; import { IconsService } from '@services/icons.service'; import { forceLink, forceManyBody } from 'd3'; import ForceGraph from 'force-graph'; -import { Observable, Subject, switchMap } from 'rxjs'; +import { Observable, Subject, Subscription, switchMap } from 'rxjs'; import { GraphLegendComponent } from './graph-legend.component'; @Component({ @@ -46,16 +46,16 @@ export class GraphComponent> @Input({ required: true }) grpcObservable: Observable>; @Input({ required: true }) sessionId: string; - @ViewChild('graph', { static: false }) readonly graphRef: ElementRef | null = null; + @ViewChild('graph', { static: false }) private graphRef: ElementRef | null = null; - graph!: ForceGraph; - canvasWidth: number = window.innerWidth; - canvasHeight: number = window.innerHeight; + private graph: ForceGraph; + private canvasWidth: number = window.innerWidth; + private canvasHeight: number = window.innerHeight; - @Input() taskToFind: string = ''; - nodesToHighlight: Set = new Set(); + private taskToFind: string = ''; + private readonly nodesToHighlight: Set = new Set(); - colorMap: Map = new Map([ + private readonly colorMap: Map = new Map([ ['taskResultLink', '#f7b657'], ['parentLink', '#8A427AAA'], ['dependencyLink', '#878adeDD'], @@ -66,7 +66,9 @@ export class GraphComponent> private readonly tasksStatusesService = inject(TasksStatusesService); private readonly resultsStatusesService = inject(ResultsStatusesService); - private readonly refreshGraph$ = new Subject(); + private readonly redrawGraph$ = new Subject(); + + private readonly subscription = new Subscription(); private nodes: N[]; @@ -92,25 +94,85 @@ export class GraphComponent> this.graph.zoom(4, 2000); }); - this.grpcObservable.subscribe((result) => this.subscribeToData(result)); + this.subscription.add(this.grpcObservable.subscribe((result) => this.subscribeToData(result))); - this.refreshGraph$ + this.subscription.add(this.redrawGraph$ .pipe(switchMap(() => this.grpcObservable)) - .subscribe((result) => this.subscribeToData(result)); + .subscribe((result) => this.subscribeToData(result))); } } - subscribeToData(result: GraphData) { - this.nodes = result.nodes; - this.graph.graphData({ nodes: result.nodes, links: result.links }); + /** + * Redraw the graph by refreshing the graph data. + */ + redraw(): void { + this.redrawGraph$.next(); } - refresh() { - this.refreshGraph$.next(); + /** + * Returns the associated icon + * @param name string | undefined, icon to search + * @returns string + */ + getIcon(name: string | undefined): string { + return this.iconsService.getIcon(name); } - drawNode(node: N, ctx: CanvasRenderingContext2D) { - if (node.x && node.y) { + /** + * Hightlight nodes with names included the searched value + * @param searchedValue + */ + highlightNodes(searchedValue: Event): void { + this.taskToFind = (searchedValue.target as HTMLInputElement).value; + this.nodesToHighlight.clear(); + this.nodes.forEach((node: N) => { + if (this.taskToFind !== '' && + node.id.includes(this.taskToFind) + ) { + this.nodesToHighlight.add(node.id); + } + }); + this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => + this.drawNode(node, ctx) + ); + } + + /** + * Handles the resize event (zoom in or out) + */ + onResize(event: UIEvent): void { + const newCanvasDimension = event.target as Window; + this.canvasWidth = newCanvasDimension.innerWidth; + this.canvasHeight = newCanvasDimension.innerHeight; + this.graph.width(this.canvasWidth); + this.graph.height(this.canvasHeight); + } + + /** + * Displays particles on the graph + * @param checked boolean + */ + setParticles(checked: boolean): void { + this.graph.linkDirectionalParticles(checked ? 1 : 0); + } + + /** + * Subscription of the data observable. + * Draws the graph and refreshes the nodes array. + * @param result + */ + private subscribeToData(result: GraphData) { + this.nodes = result.nodes; + this.graph.graphData({ nodes: result.nodes, links: result.links }); + } + + /** + * Draws a node in the canvas + * @param node N, must have valid x and y coordinates. + * @param ctx CanvasRenderingContext2D + */ + private drawNode(node: N, ctx: CanvasRenderingContext2D) { + if (node.x !== undefined && node.y !== undefined) { const label = this.getNodeStatusData(node); ctx.font = '50px Material Icons'; ctx.fillStyle = label.color; @@ -118,10 +180,11 @@ export class GraphComponent> } } - setParticles(checked: boolean) { - this.graph.linkDirectionalParticles(checked ? 1 : 0); - } - + /** + * Get the data associated to the node status. + * @param node N + * @returns StatusLabelColor, contains label, color and icon. + */ private getNodeStatusData(node: N): StatusLabelColor { switch (node.type) { case 'session': @@ -138,7 +201,12 @@ export class GraphComponent> } } - getLinkColor(link: L): string { + /** + * Returns the associated link color. + * @param link L + * @returns string + */ + private getLinkColor(link: L): string { switch (link.type) { case 'parent': return this.colorMap.get('parentLink')!; @@ -148,35 +216,4 @@ export class GraphComponent> return this.colorMap.get('taskResultLink')!; } } - - getIcon(name: string | undefined) { - return this.iconsService.getIcon(name); - } - - /** - * Hightlight nodes with names included the searched value - * @param searchedValue - */ - highlightNodes(searchedValue: Event) { - this.taskToFind = (searchedValue.target as HTMLInputElement).value; - this.nodesToHighlight.clear(); - this.nodes.forEach((node: N) => { - if (this.taskToFind !== '' && - node.id.includes(this.taskToFind) - ) { - this.nodesToHighlight.add(node.id); - } - }); - this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => - this.drawNode(node, ctx) - ); - } - - onResize(event: UIEvent) { - const w = event.target as Window; - this.canvasWidth = w.innerWidth; - this.canvasHeight = w.innerHeight; - this.graph.width(this.canvasWidth); - this.graph.height(this.canvasHeight); - } } \ No newline at end of file diff --git a/test/d3.js b/test/d3.js new file mode 100644 index 000000000..8ef80261c --- /dev/null +++ b/test/d3.js @@ -0,0 +1,10 @@ +module.exports = { + forceLink: () =>( { + distance: (value) => ({ + iterations: (value) => {}, + }), + }), + forceManyBody: () => ({ + strength: (value) => {}, + }), +} \ No newline at end of file diff --git a/test/force-graph.js b/test/force-graph.js new file mode 100644 index 000000000..a03deeabc --- /dev/null +++ b/test/force-graph.js @@ -0,0 +1,52 @@ +module.exports = class ForceGraph { + constructor(value) {} + + node = { + x: 0, + y: 0, + type: 'task', + }; + + link = { + type: 'taskResultLink', + }; + + ctx = { + fillText: jest.fn(), + }; + + graphData = jest.fn(() => this); + + d3Force = jest.fn(() => this); + + dagMode = jest.fn(() => this); + + dagLevelDistance = jest.fn(() => this); + + nodeCanvasObject = jest.fn((fn) => { + fn(this.node, this.ctx); + return this; + }); + + linkColor = jest.fn((linkFn) => { + linkFn(this.link); + return this; + }); + + linkWidth = jest.fn(() => this); + + nodeLabel = jest.fn(() => this); + + onNodeClick = jest.fn((fn) => { + fn(this.node); + return this; + }); + + centerAt = jest.fn(() => this); + zoom = jest.fn(() => this); + + width = jest.fn(() => this); + height = jest.fn(() => this); + + linkDirectionalParticles = jest.fn(() => this); +} \ No newline at end of file From 47ff13f2a1e6340c4a1015887a1ed118a263ad7c Mon Sep 17 00:00:00 2001 From: faustin Date: Thu, 3 Jul 2025 17:18:53 +0200 Subject: [PATCH 07/26] chore: added payload link --- src/app/services/graph-data.service.ts | 33 ++++++++++---------------- src/app/types/graph.types.ts | 2 +- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/app/services/graph-data.service.ts b/src/app/services/graph-data.service.ts index 5f2e019f1..898ac5d40 100644 --- a/src/app/services/graph-data.service.ts +++ b/src/app/services/graph-data.service.ts @@ -15,8 +15,6 @@ export class GraphDataService { readonly nodes: ArmoniKGraphNode[] = []; readonly links: GraphLink[] = []; - private missingSources: GraphLink[] = []; - readonly updateGraphSubject = new Subject(); /** @@ -93,7 +91,6 @@ export class GraphDataService { if (!node) { const node: ArmoniKGraphNode = { id, status, type }; this.nodes.push(node); - this.checkForMissingSource(node); } else if (node.status !== status) { node.status = status; } @@ -108,10 +105,7 @@ export class GraphDataService { if (newTask) { this.createNode(newTask.taskId, newTask.status, 'task'); if (newTask.dataDependencies.length === 0) { - this.addParentTask( - newTask.taskId, - newTask.parentTaskIds.at(-1) as string - ); + this.addPayload(newTask); } else { newTask.dataDependencies.forEach(dependencyId => { this.addDependency(newTask.taskId, dependencyId); @@ -120,6 +114,14 @@ export class GraphDataService { } } + private addPayload(task: EventSubscriptionResponse.NewTask) { + if (!this.getNodeById(task.payloadId)) { + this.createNode(task.payloadId, ResultStatus.RESULT_STATUS_UNSPECIFIED, 'result'); + } + this.addLink(task.taskId, task.payloadId, 'payload'); + this.addParentTask(task.payloadId, task.parentTaskIds.at(-1) as string); + } + /** * Creates the session node. */ @@ -156,11 +158,7 @@ export class GraphDataService { */ private addLink(target: string, source: string, type: LinkType) { if (!this.links.find(link => link.source === source && link.target === target)) { - if (this.getNodeById(source)) { - this.links.push({source, target, type}); - } else { - this.missingSources.push({ target, source, type }); - } + this.links.push({source, target, type}); } } @@ -185,6 +183,9 @@ export class GraphDataService { */ private addTaskOwner(resultId: string, taskOwnerId: string) { if (taskOwnerId !== '') { + if (!this.getNodeById(taskOwnerId)) { + this.createNode(taskOwnerId, TaskStatus.TASK_STATUS_UNSPECIFIED, 'task'); + } this.addLink(resultId, taskOwnerId, 'output'); } } @@ -200,12 +201,4 @@ export class GraphDataService { this.addTaskOwner(resultId, newTaskOwnerId); } } - - private checkForMissingSource(node: ArmoniKGraphNode) { - const result = this.missingSources.find((link) => link.source === node.id); - if (result) { - this.links.push(result); - this.missingSources = this.missingSources.filter((link) => link.source !== node.id); - } - } } \ No newline at end of file diff --git a/src/app/types/graph.types.ts b/src/app/types/graph.types.ts index 5a5b2c558..82347cdf9 100644 --- a/src/app/types/graph.types.ts +++ b/src/app/types/graph.types.ts @@ -2,7 +2,7 @@ import { LinkObject, NodeObject } from 'force-graph'; import { Status } from '../types/status'; export type NodeEventType = 'task' | 'session' | 'result'; -export type LinkType = 'parent' | 'dependency' | 'output'; +export type LinkType = 'parent' | 'dependency' | 'output' | 'payload'; export interface ArmoniKGraphNode extends NodeObject { From 3aa9c02c49f4e6e30b3d54395833158b4a04cf8b Mon Sep 17 00:00:00 2001 From: faustin Date: Thu, 3 Jul 2025 17:19:14 +0200 Subject: [PATCH 08/26] chore: added payload link --- src/app/components/graph.component.ts | 3 +++ src/app/types/graph.types.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 505b9ceca..5af41fc80 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -59,6 +59,7 @@ export class GraphComponent> ['taskResultLink', '#f7b657'], ['parentLink', '#8A427AAA'], ['dependencyLink', '#878adeDD'], + ['payloadLink', 'red'], ]); private readonly iconsService = inject(IconsService); @@ -212,6 +213,8 @@ export class GraphComponent> return this.colorMap.get('parentLink')!; case 'dependency': return this.colorMap.get('dependencyLink')!; + case 'payload': + return this.colorMap.get('payloadLink')!; default: return this.colorMap.get('taskResultLink')!; } diff --git a/src/app/types/graph.types.ts b/src/app/types/graph.types.ts index 5a5b2c558..82347cdf9 100644 --- a/src/app/types/graph.types.ts +++ b/src/app/types/graph.types.ts @@ -2,7 +2,7 @@ import { LinkObject, NodeObject } from 'force-graph'; import { Status } from '../types/status'; export type NodeEventType = 'task' | 'session' | 'result'; -export type LinkType = 'parent' | 'dependency' | 'output'; +export type LinkType = 'parent' | 'dependency' | 'output' | 'payload'; export interface ArmoniKGraphNode extends NodeObject { From 639faa3ea959d5a397f6195cd5deb7770becd37b Mon Sep 17 00:00:00 2001 From: faustin Date: Tue, 15 Jul 2025 16:22:48 +0200 Subject: [PATCH 09/26] Merge branch 'main' into feat/graph --- angular.json | 31 +- jest.config.ts | 198 +- package.json | 36 +- pnpm-lock.yaml | 4096 ++++++++++------- setup-jest.ts | 4 +- src/app/app.component.ts | 3 +- src/app/app.config.ts | 16 +- .../components/table.component.ts | 1 - src/app/applications/index.component.spec.ts | 6 + src/app/applications/index.component.ts | 1 - .../actions-toolbar-group.component.ts | 1 - .../components/actions-toolbar.component.ts | 1 - src/app/components/auto-complete.component.ts | 1 - .../auto-refresh-button.component.ts | 4 +- .../auto-refresh-dialog.component.ts | 1 - .../components/columns-button.component.ts | 2 - .../columns-modify-dialog.component.ts | 3 +- .../count-tasks-by-status.component.ts | 9 +- .../filters/filters-chips.component.spec.ts | 2 +- .../filters/filters-chips.component.ts | 5 +- .../filters/filters-dialog-and.component.ts | 3 +- .../filters-dialog-filter-field.component.ts | 3 +- .../filters-dialog-input.component.css | 3 + .../filters-dialog-input.component.html | 19 +- .../filters-dialog-input.component.spec.ts | 27 +- .../filters/filters-dialog-input.component.ts | 28 +- .../filters/filters-dialog-or.component.ts | 3 +- .../filters/filters-dialog.component.ts | 3 +- .../filters/filters-toolbar.component.ts | 3 +- .../icon-picker-dialog.component.ts | 1 - src/app/components/inspect-list.component.ts | 3 +- .../components/inspection-header.component.ts | 1 - .../inspection-toolbar.component.ts | 1 - .../inspection/byte-array.component.ts | 1 - .../inspection/field-content.component.ts | 1 - .../inspection/inspection-card.component.ts | 1 - .../inspection/inspection-json.component.ts | 1 - .../inspection-list-grid.component.ts | 1 - .../inspection/inspection-object.component.ts | 1 - .../inspection/inspection.component.ts | 3 +- .../components/inspection/json.component.ts | 1 - .../inspection/message.component.ts | 1 - .../manage-custom-dialog.component.ts | 1 - .../change-language-button.component.ts | 1 - .../external-services.component.ts | 1 - .../form-external-service.component.ts | 3 +- ...external-services-dialog.component.spec.ts | 14 +- ...nage-external-services-dialog.component.ts | 3 +- .../navigation/navigation.component.spec.ts | 21 +- .../navigation/navigation.component.ts | 1 - .../navigation/theme-selector.component.ts | 6 +- .../repository-version.component.ts | 1 - .../version-menu/versions-menu.component.ts | 1 - src/app/components/page-header.component.ts | 3 +- .../page-section-header.component.ts | 1 - src/app/components/page-section.component.ts | 1 - .../components/refresh-button.component.ts | 1 - .../components/share-url.component.spec.ts | 9 +- src/app/components/share-url.component.ts | 1 - .../components/show-action-area.component.ts | 1 - src/app/components/show-actions.component.ts | 1 - .../components/show-card-content.component.ts | 3 +- src/app/components/show-card.component.ts | 1 - src/app/components/show-page.component.ts | 1 - src/app/components/spinner.component.ts | 4 +- src/app/components/status-chip.component.html | 2 +- src/app/components/status-chip.component.ts | 1 - .../status-color-picker.component.html | 3 + .../status-color-picker.component.spec.ts | 106 + .../status-color-picker.component.ts | 47 + .../status-color-picker.dialog.component.css | 28 + .../status-color-picker.dialog.component.html | 42 + ...atus-color-picker.dialog.component.spec.ts | 159 + .../status-color-picker.dialog.component.ts | 108 + .../add-statuses-group-dialog.component.ts | 4 +- .../edit-status-group-dialog.component.ts | 4 +- .../statuses/form-statuses-group.component.ts | 4 +- .../manage-groups-dialog.component.spec.ts | 30 +- .../manage-groups-dialog.component.ts | 14 +- .../table-actions-toolbar.component.ts | 1 - .../components/table-container.component.ts | 7 +- ...ble-dashboard-actions-toolbar.component.ts | 1 - .../table-index-actions-toolbar.component.ts | 1 - .../table/cells/byte-array-cell.component.ts | 1 - .../table/table-actions.component.ts | 1 - .../table/table-cell.component.spec.ts | 27 +- .../components/table/table-cell.component.ts | 1 - .../table/table-column-header.component.html | 5 +- .../table/table-column-header.component.ts | 3 +- .../table/table-empty-data.component.ts | 3 +- .../table-inspect-message-dialog.component.ts | 1 - .../table/table-inspect-message.component.ts | 1 - .../table-inspect-object-dialog.component.ts | 3 +- .../table/table-inspect-object.component.ts | 8 +- src/app/components/table/table.component.ts | 1 - .../view-tasks-by-status.component.ts | 1 - .../components/add-line-dialog.component.ts | 1 - .../edit-name-line-dialog.component.ts | 4 +- .../lines/applications-line.component.ts | 1 - .../lines/partitions-line.component.ts | 1 - .../lines/results-line.component.ts | 7 +- .../lines/sessions-line.component.ts | 9 +- .../lines/task-by-status-line.component.ts | 7 +- .../components/lines/tasks-line.component.ts | 7 +- .../reorganize-lines-dialog.component.ts | 1 - .../split-lines-dialog.component.ts | 1 - .../statuses-group-card.component.spec.ts | 26 +- .../statuses-group-card.component.ts | 14 +- src/app/dashboard/index.component.ts | 13 - src/app/directives/no-wrap.directive.ts | 2 +- src/app/healthcheck/healthcheck.component.ts | 1 - src/app/initialisation/date-adapter.ts | 28 + .../partitions/components/table.component.ts | 1 - src/app/partitions/index.component.ts | 1 - src/app/partitions/show.component.ts | 1 - src/app/pipes/duration.pipe.ts | 2 +- src/app/pipes/empty-cell.pipe.ts | 2 +- src/app/pipes/pretty.pipe.ts | 2 +- src/app/profile/index.component.ts | 3 +- .../components/table.component.spec.ts | 17 +- src/app/results/components/table.component.ts | 6 +- src/app/results/index.component.ts | 9 +- .../services/results-filters.service.spec.ts | 17 +- .../services/results-filters.service.ts | 3 +- .../services/results-grpc.service.spec.ts | 18 +- .../services/results-status.service.spec.ts | 87 +- .../services/results-statuses.service.ts | 35 +- src/app/results/show.component.spec.ts | 25 +- src/app/results/show.component.ts | 14 +- src/app/services/default-config.service.ts | 146 +- .../components/table.component.spec.ts | 21 +- .../sessions/components/table.component.ts | 4 +- src/app/sessions/index.component.ts | 7 +- .../services/sessions-filters.service.spec.ts | 17 +- .../services/sessions-filters.service.ts | 3 +- .../services/sessions-grpc.service.spec.ts | 19 +- .../sessions-statuses.service.spec.ts | 83 +- .../services/sessions-statuses.service.ts | 41 +- src/app/sessions/show.component.spec.ts | 25 +- src/app/sessions/show.component.ts | 14 +- .../component/clear-all-dialog.component.ts | 1 - src/app/settings/index.component.ts | 1 - .../manage-view-in-logs-dialog.component.ts | 3 +- .../tasks/components/table.component.spec.ts | 23 +- src/app/tasks/components/table.component.ts | 4 +- src/app/tasks/index.component.ts | 7 +- .../services/tasks-filters.service.spec.ts | 17 +- .../tasks/services/tasks-filters.service.ts | 3 +- .../tasks/services/tasks-grpc.service.spec.ts | 18 +- .../services/tasks-statuses.service.spec.ts | 83 +- .../tasks/services/tasks-statuses.service.ts | 76 +- src/app/tasks/show.component.spec.ts | 25 +- src/app/tasks/show.component.ts | 13 +- .../types/components/dashboard-line-table.ts | 6 +- src/app/types/components/table.ts | 2 + src/app/types/config.ts | 6 +- src/app/types/dialog.ts | 7 + src/app/types/status.ts | 40 +- src/styles.css | 16 +- tsconfig.json | 6 +- 160 files changed, 3981 insertions(+), 2350 deletions(-) create mode 100644 src/app/components/filters/filters-dialog-input.component.css create mode 100644 src/app/components/status-color-picker.component.html create mode 100644 src/app/components/status-color-picker.component.spec.ts create mode 100644 src/app/components/status-color-picker.component.ts create mode 100644 src/app/components/status-color-picker.dialog.component.css create mode 100644 src/app/components/status-color-picker.dialog.component.html create mode 100644 src/app/components/status-color-picker.dialog.component.spec.ts create mode 100644 src/app/components/status-color-picker.dialog.component.ts create mode 100644 src/app/initialisation/date-adapter.ts diff --git a/angular.json b/angular.json index 4327f181a..23c9a6873 100644 --- a/angular.json +++ b/angular.json @@ -70,7 +70,10 @@ "src/themes.css" ], "scripts": [], - "browser": "src/main.ts" + "browser": "src/main.ts", + "polyfills": [ + "@angular/localize/init" + ] }, "configurations": { "en": { @@ -148,5 +151,31 @@ } } } + }, + "schematics": { + "@schematics/angular:component": { + "type": "component" + }, + "@schematics/angular:directive": { + "type": "directive" + }, + "@schematics/angular:service": { + "type": "service" + }, + "@schematics/angular:guard": { + "typeSeparator": "." + }, + "@schematics/angular:interceptor": { + "typeSeparator": "." + }, + "@schematics/angular:module": { + "typeSeparator": "." + }, + "@schematics/angular:pipe": { + "typeSeparator": "." + }, + "@schematics/angular:resolver": { + "typeSeparator": "." + } } } diff --git a/jest.config.ts b/jest.config.ts index cac7ee8c6..beaaf3445 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -4,95 +4,15 @@ */ import structuredClone from '@ungap/structured-clone'; +import { createCjsPreset } from 'jest-preset-angular/presets'; import type {Config} from 'jest'; -const config: Config = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/tmp/jest_rs", - - // Automatically clear mock calls, instances, contexts and results before every test +export default { + ...createCjsPreset(), clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - // coverageDirectory: 'coverage', - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - // coverageProvider: 'v8', - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: 'jest-preset-angular/global-setup', - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - globals: { + globals: { structuredClone, }, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "mjs", - // "cjs", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module moduleNameMapper: { '@components/(.*)': '/src/app/components/$1', '@services/(.*)': '/src/app/services/$1', @@ -101,113 +21,11 @@ const config: Config = { '^d3$': '/test/d3.js', '^force-graph$': '/test/force-graph.js', }, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - preset: 'jest-preset-angular', - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state before every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state and implementation before every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: [ - '/setup-jest.ts' - ], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing testEnvironment: './JSDOMEnvironmentPatch.ts', - - // Options that will be passed to the testEnvironment testEnvironmentOptions: { customExportConditions: ['named'] }, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // A map from regular expressions to paths to transformers - // transform: undefined, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; - -export default config; + setupFilesAfterEnv: [ + '/setup-jest.ts' + ], +} satisfies Config; diff --git a/package.json b/package.json index 43809b392..a25bf1850 100644 --- a/package.json +++ b/package.json @@ -19,22 +19,23 @@ "private": true, "dependencies": { "@aneoconsultingfr/armonik.api.angular": "^3.26.0", - "@angular-material-components/datetime-picker": "^16.0.1", - "@angular/animations": "^18.2.13", - "@angular/cdk": "18.2.14", - "@angular/common": "^18.2.13", - "@angular/compiler": "^18.2.13", - "@angular/core": "^18.2.13", - "@angular/forms": "^18.2.13", - "@angular/material": "18.2.14", - "@angular/material-luxon-adapter": "^18.2.14", - "@angular/platform-browser": "^18.2.13", - "@angular/platform-browser-dynamic": "^18.2.13", - "@angular/router": "^18.2.13", + "@angular/animations": "^20.0.3", + "@angular/cdk": "20.0.3", + "@angular/common": "^20.0.3", + "@angular/compiler": "^20.0.3", + "@angular/core": "^20.0.3", + "@angular/forms": "^20.0.3", + "@angular/material": "20.0.3", + "@angular/material-luxon-adapter": "^20.0.3", + "@angular/material-moment-adapter": "^20.0.3", + "@angular/platform-browser": "^20.0.3", + "@angular/platform-browser-dynamic": "^20.0.3", + "@angular/router": "^20.0.3", "@ngx-grpc/common": "^3.1.2", "@ngx-grpc/core": "^3.1.2", "@ngx-grpc/grpc-web-client": "^3.1.2", "@types/d3": "^7.4.3", + "@ngxmc/datetime-picker": "20.0.0", "@ungap/structured-clone": "^1.3.0", "d3": "^7.9.0", "force-graph": "^1.49.6", @@ -44,10 +45,10 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^18.2.20", - "@angular/cli": "~18.2.20", - "@angular/compiler-cli": "^18.2.13", - "@angular/localize": "18.2.13", + "@angular/build": "^20.0.2", + "@angular/cli": "~20.0.2", + "@angular/compiler-cli": "^20.0.3", + "@angular/localize": "20.0.3", "@types/google-protobuf": "^3.15.12", "@types/jest": "^29.5.14", "@types/luxon": "^3.6.2", @@ -63,10 +64,11 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jest-preset-angular": "^14.6.0", + "moment": "^2.30.1", "ng-extract-i18n-merge": "2.15.1", "ts-jest": "^29.4.0", "ts-node": "^10.9.2", - "typescript": "~5.4.5", + "typescript": "~5.8.3", "typescript-eslint": "^8.34.0" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85883bb1f..f24e22ec4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,52 +10,55 @@ importers: dependencies: '@aneoconsultingfr/armonik.api.angular': specifier: ^3.26.0 - version: 3.26.0(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(@ngx-grpc/well-known-types@3.1.2(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(google-protobuf@3.21.2))(google-protobuf@3.21.2)(rxjs@7.8.2) - '@angular-material-components/datetime-picker': - specifier: ^16.0.1 - version: 16.0.1(ff83a336257a45c41a1881b7e044d9d1) + version: 3.26.0(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(@ngx-grpc/well-known-types@3.1.2(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(google-protobuf@3.21.2))(google-protobuf@3.21.2)(rxjs@7.8.2) '@angular/animations': - specifier: ^18.2.13 - version: 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + specifier: ^20.0.3 + version: 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) '@angular/cdk': - specifier: 18.2.14 - version: 18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) + specifier: 20.0.3 + version: 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) '@angular/common': - specifier: ^18.2.13 - version: 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) + specifier: ^20.0.3 + version: 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) '@angular/compiler': - specifier: ^18.2.13 - version: 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + specifier: ^20.0.3 + version: 20.0.3 '@angular/core': - specifier: ^18.2.13 - version: 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + specifier: ^20.0.3 + version: 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) '@angular/forms': - specifier: ^18.2.13 - version: 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2) + specifier: ^20.0.3 + version: 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/material': - specifier: 18.2.14 - version: 18.2.14(ca82722567ed33cf1ad02ca7b207a5bc) + specifier: 20.0.3 + version: 20.0.3(85090e25850fd1deeb320c9388cbdb0b) '@angular/material-luxon-adapter': - specifier: ^18.2.14 - version: 18.2.14(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/material@18.2.14(ca82722567ed33cf1ad02ca7b207a5bc))(luxon@3.6.1) + specifier: ^20.0.3 + version: 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/material@20.0.3(85090e25850fd1deeb320c9388cbdb0b))(luxon@3.6.1) + '@angular/material-moment-adapter': + specifier: ^20.0.3 + version: 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/material@20.0.3(85090e25850fd1deeb320c9388cbdb0b))(moment@2.30.1) '@angular/platform-browser': - specifier: ^18.2.13 - version: 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + specifier: ^20.0.3 + version: 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) '@angular/platform-browser-dynamic': - specifier: ^18.2.13 - version: 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + specifier: ^20.0.3 + version: 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))) '@angular/router': - specifier: ^18.2.13 - version: 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2) + specifier: ^20.0.3 + version: 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2) '@ngx-grpc/common': specifier: ^3.1.2 version: 3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2) '@ngx-grpc/core': specifier: ^3.1.2 - version: 3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) '@ngx-grpc/grpc-web-client': specifier: ^3.1.2 - version: 3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(grpc-web@1.4.2)(rxjs@7.8.2) + version: 3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(grpc-web@1.4.2)(rxjs@7.8.2) + '@ngxmc/datetime-picker': + specifier: 20.0.0 + version: 20.0.0(ba9d63375f4f35e59440e81497e9b0b2) '@types/d3': specifier: ^7.4.3 version: 7.4.3 @@ -82,17 +85,17 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^18.2.20 - version: 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.4.5) + specifier: ^20.0.2 + version: 20.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(tslib@2.8.1)(typescript@5.8.3) '@angular/cli': - specifier: ~18.2.20 - version: 18.2.20(chokidar@3.6.0) + specifier: ~20.0.2 + version: 20.0.2(@types/node@22.15.31) '@angular/compiler-cli': - specifier: ^18.2.13 - version: 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) + specifier: ^20.0.3 + version: 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) '@angular/localize': - specifier: 18.2.13 - version: 18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + specifier: 20.0.3 + version: 20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3) '@types/google-protobuf': specifier: ^3.15.12 version: 3.15.12 @@ -110,13 +113,13 @@ importers: version: 1.2.0 '@typescript-eslint/eslint-plugin': specifier: 8.34.0 - version: 8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + version: 8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/parser': specifier: 8.34.0 - version: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + version: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) angular-eslint: specifier: ^19.8.0 - version: 19.8.0(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(typescript@5.4.5) + version: 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3) bumpp: specifier: ^9.11.1 version: 9.11.1 @@ -128,31 +131,34 @@ importers: version: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.28.0(jiti@2.4.2)) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) + version: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + version: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 jest-preset-angular: specifier: ^14.6.0 - version: 14.6.0(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser-dynamic@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(jsdom@20.0.3)(typescript@5.4.5) + version: 14.6.0(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser-dynamic@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))))(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3) + moment: + specifier: ^2.30.1 + version: 2.30.1 ng-extract-i18n-merge: specifier: 2.15.1 - version: 2.15.1(@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5))(chokidar@3.6.0) + version: 2.15.1(@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3)) ts-jest: specifier: ^29.4.0 - version: 29.4.0(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5) + version: 29.4.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.15.31)(typescript@5.4.5) + version: 10.9.2(@types/node@22.15.31)(typescript@5.8.3) typescript: - specifier: ~5.4.5 - version: 5.4.5 + specifier: ~5.8.3 + version: 5.8.3 typescript-eslint: specifier: ^8.34.0 - version: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + version: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) packages: @@ -179,14 +185,14 @@ packages: resolution: {integrity: sha512-PX7lCTAqWe9C40+fie+DAc8vhpGA+JgZKWWrMHUTV/iZx8RXx2X4xGQsqYu36p4i3MSfQdbn+0xLWGmjScPVOQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/architect@0.1802.20': - resolution: {integrity: sha512-nNUv2541/X4V0vtT2F6wCT+/GAY8v+J8MRMh8kGBVdyV9EdtSTWxHAvE1WhX5uE7VUCNegDfElxvAR9Vq8qSig==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/architect@0.1900.2': resolution: {integrity: sha512-rGUgOgN/jb3Pyx3E1JsUbwQQZp4C0M/t0lwyWIFjUpndl27aBDjO2y5hzeG0B1+FgOuSNg8BPOYaEIO5vSCspw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular-devkit/architect@0.2000.2': + resolution: {integrity: sha512-adJYWJWuyXFtCOg2lZTV/7CImf4ifxd6c//VXuq5kx7AiSGTIH5Nf2xTQe8ZAZqytUmDgnoNMDhGRQ9b3C5TnA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular-devkit/build-angular@18.0.2': resolution: {integrity: sha512-cQkTx7XaIPj6+DXo6wZmO4iY0hOOfPDnSN/+m84XpBW0tuPGxH7Z9B6wV+Uwcpm9HGPqzRA7VZyPsqbK860b0Q==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -253,18 +259,18 @@ packages: chokidar: optional: true - '@angular-devkit/core@18.2.20': - resolution: {integrity: sha512-VNxI2e9EZQNqKYtUJ4u43QRJ9kObeyG9f69caxnj28cg4qim3H1vX/sglnodP8EsTIRbzwBKc884ebHWFdQJkQ==} + '@angular-devkit/core@19.0.2': + resolution: {integrity: sha512-p5pTx9rAtJUfoa7BP6R5U7dGFWHrrgpYpVyF3jwqYIu0h1C0rJIyY8q/HlkvzFxgfWag1qRf15oANq3G9fqdwg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: - chokidar: ^3.5.2 + chokidar: ^4.0.0 peerDependenciesMeta: chokidar: optional: true - '@angular-devkit/core@19.0.2': - resolution: {integrity: sha512-p5pTx9rAtJUfoa7BP6R5U7dGFWHrrgpYpVyF3jwqYIu0h1C0rJIyY8q/HlkvzFxgfWag1qRf15oANq3G9fqdwg==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular-devkit/core@20.0.2': + resolution: {integrity: sha512-qqTSpcIw+TqJ6u/tkQzqgpwVelHsHr8Jhws1Vlx6E0L6E+cRILBK48i9ttE+oYkQlcopQ3VZAmzcZodXJ1SQ9Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 peerDependenciesMeta: @@ -275,14 +281,14 @@ packages: resolution: {integrity: sha512-mMea9txHbnCX5lXLHlo0RAgfhFHDio45/jMsREM2PA8UtVf2S8ltXz7ZwUrUyMQRv8vaSfn4ijDstF4hDMnRgQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/schematics@18.2.20': - resolution: {integrity: sha512-eKoFeWOxwheaGK+aguyTs9utxxmFsrI/aHQttiyhBy+HzmgX/E0grzx6ZpuipUpBA8lYMtxfTJ7AC12fGJMvFA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/schematics@19.0.2': resolution: {integrity: sha512-bwq8ReC92gGFTd2BeNBWCnOqIKu2YKNvwMVc7dl+D154WO2gzCaK2J5nL97qm5EjoUoXgvFRs84ysSAnLFzBxQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular-devkit/schematics@20.0.2': + resolution: {integrity: sha512-r1aSZhcadLtUMhzUUfy+pkJdZW93z8WQtpGR24y88yFpPgDL5kY85VSlOzjGgo1vEs8Dd7ADcOcsVsUW8MxQ3A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular-eslint/builder@19.8.0': resolution: {integrity: sha512-+sDe92BpzlxNZWFuBbKD1L8xsW/dyOU+acPn4V84Vn55XMdhrBWOwDX7oxmBCOwuVTrS3mgHz7d22J1sdNwySw==} peerDependencies: @@ -324,21 +330,12 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular-material-components/datetime-picker@16.0.1': - resolution: {integrity: sha512-dbkwWiC8qL7NVlMclb1hvuZvuP2l1nvfnnmijEc/zGsoWeoLNDXn/+z/UQtMcbUphcwCzFt9CfHhhpGUGgQLgw==} - peerDependencies: - '@angular/cdk': ^16.0.0 - '@angular/common': ^16.0.0 - '@angular/core': ^16.0.0 - '@angular/forms': ^16.0.0 - '@angular/material': ^16.0.0 - '@angular/platform-browser': ^16.0.0 - - '@angular/animations@18.2.13': - resolution: {integrity: sha512-rG5J5Ek5Hg+Tz2NjkNOaG6PupiNK/lPfophXpsR1t/nWujqnMWX2krahD/i6kgD+jNWNKCJCYSOVvCx/BHOtKA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/animations@20.0.3': + resolution: {integrity: sha512-R6yv2RmrH49nW1ybgoOMw5pWzqaRYo8Kn3VtvrUDBty4TXjwc0addaw/t89n0smO3/lmBB4vnlRScePAEQZ/3w==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 18.2.13 + '@angular/common': 20.0.3 + '@angular/core': 20.0.3 '@angular/build@18.0.2': resolution: {integrity: sha512-iPPHdAJ3LiR8t/+39xjvrqMWcTmRrfphzKxXoIVDcswQjVQIk00EYuxinC6EVa7dSKDl1thk1MeCNZ9DIjaAvQ==} @@ -366,153 +363,195 @@ packages: tailwindcss: optional: true - '@angular/build@18.2.20': - resolution: {integrity: sha512-9VW/zSQoSwc9e5OBjtnroj9feacD2HgkSYx7TsfmDyefIlOCeNxbhkm83Px/4B8VG6kzZUBzLBJ4QULl2E1Y/Q==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - peerDependencies: - '@angular/compiler-cli': ^18.0.0 - '@angular/localize': ^18.0.0 - '@angular/platform-server': ^18.0.0 - '@angular/service-worker': ^18.0.0 + '@angular/build@20.0.2': + resolution: {integrity: sha512-nxha/dncAwEbY0nkgDWeiWSi+MSCJBuQbFf5bjTZ+pu0fS+5SOQllZKzZE9H+dms/JsLHm2YmPiScIYVvUenDw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + '@angular/compiler': ^20.0.0 + '@angular/compiler-cli': ^20.0.0 + '@angular/core': ^20.0.0 + '@angular/localize': ^20.0.0 + '@angular/platform-browser': ^20.0.0 + '@angular/platform-server': ^20.0.0 + '@angular/service-worker': ^20.0.0 + '@angular/ssr': ^20.0.2 + karma: ^6.4.0 less: ^4.2.0 + ng-packagr: ^20.0.0 postcss: ^8.4.0 - tailwindcss: ^2.0.0 || ^3.0.0 - typescript: '>=5.4 <5.6' + tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 + tslib: ^2.3.0 + typescript: '>=5.8 <5.9' + vitest: ^3.1.1 peerDependenciesMeta: + '@angular/core': + optional: true '@angular/localize': optional: true + '@angular/platform-browser': + optional: true '@angular/platform-server': optional: true '@angular/service-worker': optional: true + '@angular/ssr': + optional: true + karma: + optional: true less: optional: true + ng-packagr: + optional: true postcss: optional: true tailwindcss: optional: true + vitest: + optional: true - '@angular/cdk@18.2.14': - resolution: {integrity: sha512-vDyOh1lwjfVk9OqoroZAP8pf3xxKUvyl+TVR8nJxL4c5fOfUFkD7l94HaanqKSRwJcI2xiztuu92IVoHn8T33Q==} + '@angular/cdk@20.0.3': + resolution: {integrity: sha512-70KG8GpK4aV9j5hUkpDZJQ6oMgCuaCRY6JX1axPxkNtQaiK6PAmTfQLiGqF2cYhbQneeq3uGvTorAjRfvp8NPQ==} peerDependencies: - '@angular/common': ^18.0.0 || ^19.0.0 - '@angular/core': ^18.0.0 || ^19.0.0 + '@angular/common': ^20.0.0 || ^21.0.0 + '@angular/core': ^20.0.0 || ^21.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/cli@18.2.20': - resolution: {integrity: sha512-uu8XM+vvVQxTgCJAAQtCu6aLErbdCh/xqYpawgTaoOjiDkyWonTC+iGUUy0AEk5no/pbg2TCoZZx0AXWM1yLVA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@angular/cli@20.0.2': + resolution: {integrity: sha512-LzBONPETA1uCZuylgZRYe+vImf8i+rRrwAgOBHWbW2wxut9ZQ8ZFwQgNkjvDhE7DLmsFV+GskfAs5+Td/5LZwA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular/common@18.2.13': - resolution: {integrity: sha512-4ZqrNp1PoZo7VNvW+sbSc2CB2axP1sCH2wXl8B0wdjsj8JY1hF1OhuugwhpAHtGxqewed2kCXayE+ZJqSTV4jw==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/common@20.0.3': + resolution: {integrity: sha512-HqqVqaj+xzByWJOIrONVRkpvM6mRuGmC+m9wKixhc9f+xXsymVTBR6xg+G/RwyYP2NuC5chxIZbaJTz2Hj+6+g==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 18.2.13 + '@angular/core': 20.0.3 rxjs: ^6.5.3 || ^7.4.0 - '@angular/compiler-cli@18.2.13': - resolution: {integrity: sha512-DBSh4AQwkiJDSiVvJATRmjxf6wyUs9pwQLgaFdSlfuTRO+sdb0J2z1r3BYm8t0IqdoyXzdZq2YCH43EmyvD71g==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/compiler-cli@20.0.3': + resolution: {integrity: sha512-u+fYnx1sRrwL0fd8kaAD2LqJjfe/Zj7zyOv0A3Ue7r8jzdNsPU8MWr/QyBaWlqSpPEpR+kD3xmDvRT9ra9RTBA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 18.2.13 - typescript: '>=5.4 <5.6' - - '@angular/compiler@18.2.13': - resolution: {integrity: sha512-TzWcrkopyjFF+WeDr2cRe8CcHjU72KfYV3Sm2TkBkcXrkYX5sDjGWrBGrG3hRB4e4okqchrOCvm1MiTdy2vKMA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} - peerDependencies: - '@angular/core': 18.2.13 + '@angular/compiler': 20.0.3 + typescript: '>=5.8 <5.9' peerDependenciesMeta: - '@angular/core': + typescript: optional: true - '@angular/core@18.2.13': - resolution: {integrity: sha512-8mbWHMgO95OuFV1Ejy4oKmbe9NOJ3WazQf/f7wks8Bck7pcihd0IKhlPBNjFllbF5o+04EYSwFhEtvEgjMDClA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/compiler@20.0.3': + resolution: {integrity: sha512-CShPNvqqV5Cleyho8CKtcFlt7l2thHPUdXZPtKHH3Zf43KojvJbJksZLBz6ZbyoQdgxNMYSfbh4h0UbSGtPOzQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@angular/core@20.0.3': + resolution: {integrity: sha512-kB6w1bQgClfmkTbWJeD3vSLqX0e3uSaJD6KJ7XXT1IEaqUs4J+mKRKHQyxpJlpdUb7R+jDaHSM/vrVF15/L2rA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: + '@angular/compiler': 20.0.3 rxjs: ^6.5.3 || ^7.4.0 - zone.js: ~0.14.10 + zone.js: ~0.15.0 + peerDependenciesMeta: + '@angular/compiler': + optional: true + zone.js: + optional: true - '@angular/forms@18.2.13': - resolution: {integrity: sha512-A67D867fu3DSBhdLWWZl/F5pr7v2+dRM2u3U7ZJ0ewh4a+sv+0yqWdJW+a8xIoiHxS+btGEJL2qAKJiH+MCFfg==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/forms@20.0.3': + resolution: {integrity: sha512-tb4M+c+/JnmPmtTb3+Si/DWGttnCEW5rvi4u55q+EFxYGQO0GeHa53yQTl1e2ngQLT9/kgmDAsJ2mt1Ql9N6xg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 18.2.13 - '@angular/core': 18.2.13 - '@angular/platform-browser': 18.2.13 + '@angular/common': 20.0.3 + '@angular/core': 20.0.3 + '@angular/platform-browser': 20.0.3 rxjs: ^6.5.3 || ^7.4.0 - '@angular/localize@18.2.13': - resolution: {integrity: sha512-qQaIYdDS/l1w6tr/wpOoimjpmoJU0WmB8AGbNeKLoM36K+ix6hkvn67+UgkpZtaDHZylm8GsGW1NjzpM2tr3pA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/localize@20.0.3': + resolution: {integrity: sha512-1vcIvXQqrWGFyLcLlmANdfv66DrJ44ZHxGITZYfGoy062Ffa8nvGSyEMe41LLU729Ygy+caLYzr5G5GAOqs/yg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 18.2.13 - '@angular/compiler-cli': 18.2.13 + '@angular/compiler': 20.0.3 + '@angular/compiler-cli': 20.0.3 - '@angular/material-luxon-adapter@18.2.14': - resolution: {integrity: sha512-XOvOKOS5zqW+kin/YkVzNHX9p3A7TQIBc9pMJINq/8MerMnh8f2DaI0TD1sIsY5xuP3/nImk1qkTsUYX06c1fQ==} + '@angular/material-luxon-adapter@20.0.3': + resolution: {integrity: sha512-CvV7SPovMgYzQDIkf2mHI2uyIGPwGE/Hm3fddT3uwnh8kMztiMwrdxczEmI13oNP/Ekv1QSB65p8fWlLIvMenA==} peerDependencies: - '@angular/core': ^18.0.0 || ^19.0.0 - '@angular/material': 18.2.14 + '@angular/core': ^20.0.0 || ^21.0.0 + '@angular/material': 20.0.3 luxon: ^3.0.0 - '@angular/material@18.2.14': - resolution: {integrity: sha512-28pxzJP49Mymt664WnCtPkKeg7kXUsQKTKGf/Kl95rNTEdTJLbnlcc8wV0rT0yQNR7kXgpfBnG7h0ETLv/iu5Q==} + '@angular/material-moment-adapter@20.0.3': + resolution: {integrity: sha512-+dECu9bJExfR/KMsQI/5sw1f4UbVstSabe0+0N6cwkms+UPXWkH6MPRbjPOWyOc1SzOjGNAcMQsG7LhhrUghbg==} + peerDependencies: + '@angular/core': ^20.0.0 || ^21.0.0 + '@angular/material': 20.0.3 + moment: ^2.18.1 + + '@angular/material@20.0.3': + resolution: {integrity: sha512-kd5Mi6gVxcjDs1nfm8GG2rId59SXWQjkiBMqrYuhy2Trpb+zG0vrLClrpoe3JdWqoX4GJagxGwl3VRDBIoP/cw==} peerDependencies: - '@angular/animations': ^18.0.0 || ^19.0.0 - '@angular/cdk': 18.2.14 - '@angular/common': ^18.0.0 || ^19.0.0 - '@angular/core': ^18.0.0 || ^19.0.0 - '@angular/forms': ^18.0.0 || ^19.0.0 - '@angular/platform-browser': ^18.0.0 || ^19.0.0 + '@angular/cdk': 20.0.3 + '@angular/common': ^20.0.0 || ^21.0.0 + '@angular/core': ^20.0.0 || ^21.0.0 + '@angular/forms': ^20.0.0 || ^21.0.0 + '@angular/platform-browser': ^20.0.0 || ^21.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/platform-browser-dynamic@18.2.13': - resolution: {integrity: sha512-kbQCf9+8EpuJC7buBxhSiwBtXvjAwAKh6MznD6zd2pyCYqfY6gfRCZQRtK59IfgVtKmEONWI9grEyNIRoTmqJg==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/platform-browser-dynamic@20.0.3': + resolution: {integrity: sha512-EUC0q9/L7nBQOJkOi7aKz0cKXym7XIZtZJjZ+K7hCZaE92wb+Uk5YdBfBaq6hJ3aEp896GUs3FVFI6Rxklrm2A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 18.2.13 - '@angular/compiler': 18.2.13 - '@angular/core': 18.2.13 - '@angular/platform-browser': 18.2.13 + '@angular/common': 20.0.3 + '@angular/compiler': 20.0.3 + '@angular/core': 20.0.3 + '@angular/platform-browser': 20.0.3 - '@angular/platform-browser@18.2.13': - resolution: {integrity: sha512-tu7ZzY6qD3ATdWFzcTcsAKe7M6cJeWbT/4/bF9unyGO3XBPcNYDKoiz10+7ap2PUd0fmPwvuvTvSNJiFEBnB8Q==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/platform-browser@20.0.3': + resolution: {integrity: sha512-cba0bibw9dJ8b+a2a8mwkiq5/HPiakY9P5OiJEVefN+2V/K9CND/pW+KIbW0/P6KhSSDQ29xgcGRseVtkjYLmg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/animations': 18.2.13 - '@angular/common': 18.2.13 - '@angular/core': 18.2.13 + '@angular/animations': 20.0.3 + '@angular/common': 20.0.3 + '@angular/core': 20.0.3 peerDependenciesMeta: '@angular/animations': optional: true - '@angular/router@18.2.13': - resolution: {integrity: sha512-VKmfgi/r/CkyBq9nChQ/ptmfu0JT/8ONnLVJ5H+SkFLRYJcIRyHLKjRihMCyVm6xM5yktOdCaW73NTQrFz7+bg==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} + '@angular/router@20.0.3': + resolution: {integrity: sha512-FY2kMZjLh7NUKjSaZ1K26azl67T4aVnOD8PE/w1Ih3eQmSIlHniNP1NmCGMUy6t1O/ZV6sCSKkA5AZFv18wzIQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 18.2.13 - '@angular/core': 18.2.13 - '@angular/platform-browser': 18.2.13 + '@angular/common': 20.0.3 + '@angular/core': 20.0.3 + '@angular/platform-browser': 20.0.3 rxjs: ^6.5.3 || ^7.4.0 '@babel/code-frame@7.24.7': resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.25.4': - resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.27.5': + resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==} engines: {node: '>=6.9.0'} '@babel/core@7.24.5': resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} engines: {node: '>=6.9.0'} - '@babel/core@7.25.2': - resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} + '@babel/core@7.26.10': + resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.1': + resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} engines: {node: '>=6.9.0'} '@babel/generator@7.24.5': @@ -523,20 +562,24 @@ packages: resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.27.5': + resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.22.5': resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.24.7': - resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} + '@babel/helper-annotate-as-pure@7.27.1': + resolution: {integrity: sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==} engines: {node: '>=6.9.0'} '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': resolution: {integrity: sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.2': - resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} '@babel/helper-create-class-features-plugin@7.24.6': @@ -572,12 +615,12 @@ packages: resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.24.7': - resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.25.2': - resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -590,6 +633,10 @@ packages: resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + '@babel/helper-remap-async-to-generator@7.24.6': resolution: {integrity: sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==} engines: {node: '>=6.9.0'} @@ -622,28 +669,36 @@ packages: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.24.7': resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.24.8': - resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} '@babel/helper-wrap-function@7.24.6': resolution: {integrity: sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.25.6': - resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} engines: {node: '>=6.9.0'} '@babel/highlight@7.24.7': resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.25.6': - resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} + '@babel/parser@7.27.5': + resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} engines: {node: '>=6.0.0'} hasBin: true @@ -714,8 +769,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.24.7': - resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1102,18 +1157,22 @@ packages: resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} engines: {node: '>=6.9.0'} - '@babel/template@7.25.0': - resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.25.6': - resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} + '@babel/traverse@7.27.4': + resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} engines: {node: '>=6.9.0'} '@babel/types@7.25.6': resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} + '@babel/types@7.27.6': + resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -1146,14 +1205,14 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.23.0': + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.0': - resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + '@esbuild/aix-ppc64@0.25.5': + resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1170,14 +1229,14 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.23.0': + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.0': - resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + '@esbuild/android-arm64@0.25.5': + resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1194,14 +1253,14 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.23.0': + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.0': - resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + '@esbuild/android-arm@0.25.5': + resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1218,14 +1277,14 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.23.0': + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.0': - resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + '@esbuild/android-x64@0.25.5': + resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1242,14 +1301,14 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.23.0': + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.0': - resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + '@esbuild/darwin-arm64@0.25.5': + resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1266,14 +1325,14 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.23.0': + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.0': - resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + '@esbuild/darwin-x64@0.25.5': + resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1290,14 +1349,14 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.23.0': + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.0': - resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + '@esbuild/freebsd-arm64@0.25.5': + resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1314,14 +1373,14 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.23.0': + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.0': - resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + '@esbuild/freebsd-x64@0.25.5': + resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1338,14 +1397,14 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.23.0': + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.0': - resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + '@esbuild/linux-arm64@0.25.5': + resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1362,14 +1421,14 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.23.0': + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.0': - resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + '@esbuild/linux-arm@0.25.5': + resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1386,14 +1445,14 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.23.0': + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.0': - resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + '@esbuild/linux-ia32@0.25.5': + resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1410,14 +1469,14 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.23.0': + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.0': - resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + '@esbuild/linux-loong64@0.25.5': + resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1434,14 +1493,14 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.23.0': + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.0': - resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + '@esbuild/linux-mips64el@0.25.5': + resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1458,14 +1517,14 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.23.0': + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.0': - resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + '@esbuild/linux-ppc64@0.25.5': + resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1482,14 +1541,14 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.23.0': + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.0': - resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + '@esbuild/linux-riscv64@0.25.5': + resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1506,14 +1565,14 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.23.0': + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.0': - resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + '@esbuild/linux-s390x@0.25.5': + resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1530,18 +1589,24 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.23.0': + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.0': - resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + '@esbuild/linux-x64@0.25.5': + resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.5': + resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.20.1': resolution: {integrity: sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==} engines: {node: '>=12'} @@ -1554,14 +1619,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.23.0': + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.0': - resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + '@esbuild/netbsd-x64@0.25.5': + resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1572,6 +1637,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.25.5': + resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.20.1': resolution: {integrity: sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==} engines: {node: '>=12'} @@ -1584,14 +1655,14 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.23.0': + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.0': - resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + '@esbuild/openbsd-x64@0.25.5': + resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1608,14 +1679,14 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.23.0': + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.0': - resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + '@esbuild/sunos-x64@0.25.5': + resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1632,14 +1703,14 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.23.0': + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.0': - resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + '@esbuild/win32-arm64@0.25.5': + resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1656,14 +1727,14 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.23.0': + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.0': - resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + '@esbuild/win32-ia32@0.25.5': + resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1680,14 +1751,14 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.23.0': + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.0': - resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + '@esbuild/win32-x64@0.25.5': + resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1760,66 +1831,148 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inquirer/checkbox@2.4.7': - resolution: {integrity: sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw==} + '@inquirer/checkbox@4.1.8': + resolution: {integrity: sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/confirm@3.1.22': - resolution: {integrity: sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==} + '@inquirer/confirm@5.1.10': + resolution: {integrity: sha512-FxbQ9giWxUWKUk2O5XZ6PduVnH2CZ/fmMKMBkH71MHJvWr7WL5AHKevhzF1L5uYWB2P548o1RzVxrNd3dpmk6g==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/core@9.0.10': - resolution: {integrity: sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==} + '@inquirer/confirm@5.1.12': + resolution: {integrity: sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/editor@2.1.22': - resolution: {integrity: sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w==} + '@inquirer/core@10.1.13': + resolution: {integrity: sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/expand@2.1.22': - resolution: {integrity: sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA==} + '@inquirer/editor@4.2.13': + resolution: {integrity: sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/figures@1.0.5': - resolution: {integrity: sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==} + '@inquirer/expand@4.0.15': + resolution: {integrity: sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/input@2.2.9': - resolution: {integrity: sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g==} + '@inquirer/figures@1.0.12': + resolution: {integrity: sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==} engines: {node: '>=18'} - '@inquirer/number@1.0.10': - resolution: {integrity: sha512-kWTxRF8zHjQOn2TJs+XttLioBih6bdc5CcosXIzZsrTY383PXI35DuhIllZKu7CdXFi2rz2BWPN9l0dPsvrQOA==} + '@inquirer/input@4.1.12': + resolution: {integrity: sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/password@2.1.22': - resolution: {integrity: sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw==} + '@inquirer/number@3.0.15': + resolution: {integrity: sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/prompts@5.3.8': - resolution: {integrity: sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==} + '@inquirer/password@4.0.15': + resolution: {integrity: sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/rawlist@2.2.4': - resolution: {integrity: sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q==} + '@inquirer/prompts@7.5.1': + resolution: {integrity: sha512-5AOrZPf2/GxZ+SDRZ5WFplCA2TAQgK3OYrXCYmJL5NaTu4ECcoWFlfUZuw7Es++6Njv7iu/8vpYJhuzxUH76Vg==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/search@1.0.7': - resolution: {integrity: sha512-p1wpV+3gd1eST/o5N3yQpYEdFNCzSP0Klrl+5bfD3cTTz8BGG6nf4Z07aBW0xjlKIj1Rp0y3x/X4cZYi6TfcLw==} + '@inquirer/rawlist@4.1.3': + resolution: {integrity: sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/select@2.4.7': - resolution: {integrity: sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ==} + '@inquirer/search@3.0.15': + resolution: {integrity: sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/type@1.5.2': - resolution: {integrity: sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==} + '@inquirer/select@4.2.3': + resolution: {integrity: sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg==} engines: {node: '>=18'} - - '@isaacs/cliui@8.0.2': + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@1.5.5': + resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.7': + resolution: {integrity: sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -1939,29 +2092,24 @@ packages: '@leichtgewicht/ip-codec@2.0.4': resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} - '@listr2/prompt-adapter-inquirer@2.0.15': - resolution: {integrity: sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==} + '@listr2/prompt-adapter-inquirer@2.0.22': + resolution: {integrity: sha512-hV36ZoY+xKL6pYOt1nPNnkciFkn89KZwqLhAFzJvYysAvL5uBQdiADZx/8bIDXIukzzwG0QlPYolgMzQUtKgpQ==} engines: {node: '>=18.0.0'} peerDependencies: - '@inquirer/prompts': '>= 3 < 6' + '@inquirer/prompts': '>= 3 < 8' '@ljharb/through@2.3.13': resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==} engines: {node: '>= 0.4'} - '@lmdb/lmdb-darwin-arm64@3.0.13': - resolution: {integrity: sha512-uiKPB0Fv6WEEOZjruu9a6wnW/8jrjzlZbxXscMB8kuCJ1k6kHpcBnuvaAWcqhbI7rqX5GKziwWEdD+wi2gNLfA==} - cpu: [arm64] - os: [darwin] - '@lmdb/lmdb-darwin-arm64@3.0.8': resolution: {integrity: sha512-+lFwFvU+zQ9zVIFETNtmW++syh3Ps5JS8MPQ8zOYtQZoU+dTR8ivWHTaE2QVk1JG2payGDLUAvpndLAjGMdeeA==} cpu: [arm64] os: [darwin] - '@lmdb/lmdb-darwin-x64@3.0.13': - resolution: {integrity: sha512-bEVIIfK5mSQoG1R19qA+fJOvCB+0wVGGnXHT3smchBVahYBdlPn2OsZZKzlHWfb1E+PhLBmYfqB5zQXFP7hJig==} - cpu: [x64] + '@lmdb/lmdb-darwin-arm64@3.3.0': + resolution: {integrity: sha512-LipbQobyEfQtu8WixasaFUZZ+JCGlho4OWwWIQ5ol0rB1RKkcZvypu7sS1CBvofBGVAa3vbOh8IOGQMrbmL5dg==} + cpu: [arm64] os: [darwin] '@lmdb/lmdb-darwin-x64@3.0.8': @@ -1969,19 +2117,19 @@ packages: cpu: [x64] os: [darwin] - '@lmdb/lmdb-linux-arm64@3.0.13': - resolution: {integrity: sha512-afbVrsMgZ9dUTNUchFpj5VkmJRxvht/u335jUJ7o23YTbNbnpmXif3VKQGCtnjSh+CZaqm6N3CPG8KO3zwyZ1Q==} - cpu: [arm64] - os: [linux] + '@lmdb/lmdb-darwin-x64@3.3.0': + resolution: {integrity: sha512-yA+9P+ZeA3vg76BLXWeUomIAjxfmSmR2eg8fueHXDg5Xe1Xmkl9JCKuHXUhtJ+mMVcH12d5k4kJBLbyXTadfGQ==} + cpu: [x64] + os: [darwin] '@lmdb/lmdb-linux-arm64@3.0.8': resolution: {integrity: sha512-uEBGCQIChsixpykL0pjCxfF64btv64vzsb1NoM5u0qvabKvKEvErhXGoqovyldDu9u1T/fswD8Kf6ih0vJEvDQ==} cpu: [arm64] os: [linux] - '@lmdb/lmdb-linux-arm@3.0.13': - resolution: {integrity: sha512-Yml1KlMzOnXj/tnW7yX8U78iAzTk39aILYvCPbqeewAq1kSzl+w59k/fiVkTBfvDi/oW/5YRxL+Fq+Y1Fr1r2Q==} - cpu: [arm] + '@lmdb/lmdb-linux-arm64@3.3.0': + resolution: {integrity: sha512-OeWvSgjXXZ/zmtLqqL78I3910F6UYpUubmsUU+iBHo6nTtjkpXms95rJtGrjkWQqwswKBD7xSMplbYC4LEsiPA==} + cpu: [arm64] os: [linux] '@lmdb/lmdb-linux-arm@3.0.8': @@ -1989,9 +2137,9 @@ packages: cpu: [arm] os: [linux] - '@lmdb/lmdb-linux-x64@3.0.13': - resolution: {integrity: sha512-vOtxu0xC0SLdQ2WRXg8Qgd8T32ak4SPqk5zjItRszrJk2BdeXqfGxBJbP7o4aOvSPSmSSv46Lr1EP4HXU8v7Kg==} - cpu: [x64] + '@lmdb/lmdb-linux-arm@3.3.0': + resolution: {integrity: sha512-EDYrW9kle+8wI19JCj/PhRnGoCN9bked5cdOPdo1wdgH/HzjgoLPFTn9DHlZccgTEVhp3O+bpWXdN/rWySVvjw==} + cpu: [arm] os: [linux] '@lmdb/lmdb-linux-x64@3.0.8': @@ -1999,9 +2147,14 @@ packages: cpu: [x64] os: [linux] - '@lmdb/lmdb-win32-x64@3.0.13': - resolution: {integrity: sha512-UCrMJQY/gJnOl3XgbWRZZUvGGBuKy6i0YNSptgMzHBjs+QYDYR1Mt/RLTOPy4fzzves65O1EDmlL//OzEqoLlA==} + '@lmdb/lmdb-linux-x64@3.3.0': + resolution: {integrity: sha512-wDd02mt5ScX4+xd6g78zKBr6ojpgCJCTrllCAabjgap5FzuETqOqaQfKhO+tJuGWv/J5q+GIds6uY7rNFueOxg==} cpu: [x64] + os: [linux] + + '@lmdb/lmdb-win32-arm64@3.3.0': + resolution: {integrity: sha512-COotWhHJgzXULLiEjOgWQwqig6PoA+6ji6W+sDl6M1HhMXWIymEVHGs0edsVSNtsNSCAWMxJgR3asv6FNX/2EA==} + cpu: [arm64] os: [win32] '@lmdb/lmdb-win32-x64@3.0.8': @@ -2009,6 +2162,11 @@ packages: cpu: [x64] os: [win32] + '@lmdb/lmdb-win32-x64@3.3.0': + resolution: {integrity: sha512-kqUgQH+l8HDbkAapx+aoko7Ez4X4DqkIraOqY/k0QY5EN/iialVlFpBUXh4wFXzirdmEVjbIUMrceUh0Kh8LeA==} + cpu: [x64] + os: [win32] + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} cpu: [arm64] @@ -2039,6 +2197,106 @@ packages: cpu: [x64] os: [win32] + '@napi-rs/nice-android-arm-eabi@1.0.1': + resolution: {integrity: sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@napi-rs/nice-android-arm64@1.0.1': + resolution: {integrity: sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/nice-darwin-arm64@1.0.1': + resolution: {integrity: sha512-91k3HEqUl2fsrz/sKkuEkscj6EAj3/eZNCLqzD2AA0TtVbkQi8nqxZCZDMkfklULmxLkMxuUdKe7RvG/T6s2AA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/nice-darwin-x64@1.0.1': + resolution: {integrity: sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/nice-freebsd-x64@1.0.1': + resolution: {integrity: sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/nice-linux-arm-gnueabihf@1.0.1': + resolution: {integrity: sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/nice-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/nice-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/nice-linux-ppc64-gnu@1.0.1': + resolution: {integrity: sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q==} + engines: {node: '>= 10'} + cpu: [ppc64] + os: [linux] + + '@napi-rs/nice-linux-riscv64-gnu@1.0.1': + resolution: {integrity: sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@napi-rs/nice-linux-s390x-gnu@1.0.1': + resolution: {integrity: sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg==} + engines: {node: '>= 10'} + cpu: [s390x] + os: [linux] + + '@napi-rs/nice-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/nice-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/nice-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/nice-win32-ia32-msvc@1.0.1': + resolution: {integrity: sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/nice-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/nice@1.0.1': + resolution: {integrity: sha512-zM0mVWSXE0a0h9aKACLwKmD6nHcRiKrPpCfvaKqG1CqDEyjEawId0ocXxVzPMCAm6kkWr2P025msfxXEnt8UGQ==} + engines: {node: '>= 10'} + '@napi-rs/wasm-runtime@0.2.11': resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==} @@ -2078,6 +2336,16 @@ packages: '@ngx-grpc/common': 3.1.2 google-protobuf: ^3.10.0 + '@ngxmc/datetime-picker@20.0.0': + resolution: {integrity: sha512-qTksRc/RBHQikxFo3PjZJb2rgnwJuFcmpJ6+6leqV6E4MayzouBWX1uYWOjOZs35xWKYx4zS1n7wlvC9aFtwPQ==} + peerDependencies: + '@angular/cdk': ^20.0.0 + '@angular/common': ^20.0.0 + '@angular/core': ^20.0.0 + '@angular/forms': ^20.0.0 + '@angular/material': ^20.0.0 + '@angular/platform-browser': ^20.0.0 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2094,124 +2362,226 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@npmcli/agent@2.2.2': - resolution: {integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/agent@3.0.0': + resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/fs@3.1.0': - resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@npmcli/fs@4.0.0': + resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/git@5.0.7': - resolution: {integrity: sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/git@6.0.3': + resolution: {integrity: sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/installed-package-contents@2.0.2': - resolution: {integrity: sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@npmcli/installed-package-contents@3.0.0': + resolution: {integrity: sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - '@npmcli/node-gyp@3.0.0': - resolution: {integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@npmcli/node-gyp@4.0.0': + resolution: {integrity: sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/package-json@5.1.1': - resolution: {integrity: sha512-uTq5j/UqUzbOaOxVy+osfOhpqOiLfUZ0Ut33UbcyyAPJbZcJsf4Mrsyb8r58FoIFlofw0iOFsuCA/oDK14VDJQ==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/package-json@6.2.0': + resolution: {integrity: sha512-rCNLSB/JzNvot0SEyXqWZ7tX2B5dD2a1br2Dp0vSYVo5jh8Z0EZ7lS9TsZ1UtziddB1UfNUaMCc538/HztnJGA==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/promise-spawn@7.0.2': - resolution: {integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/promise-spawn@8.0.2': + resolution: {integrity: sha512-/bNJhjc+o6qL+Dwz/bqfTQClkEO5nTQ1ZEcdCkAQjhkZMHIh22LPG7fNh1enJP1NKWDqYiiABnjFCY7E0zHYtQ==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/redact@2.0.0': - resolution: {integrity: sha512-SEjCPAVHWYUIQR+Yn03kJmrJjZDtJLYpj300m3HV9OTRZNpC5YpbMsM3eTkECyT4aWj8lDr9WeY6TWefpubtYQ==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/redact@3.2.2': + resolution: {integrity: sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==} + engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/run-script@8.1.0': - resolution: {integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==} - engines: {node: ^16.14.0 || >=18.0.0} + '@npmcli/run-script@9.1.0': + resolution: {integrity: sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg==} + engines: {node: ^18.17.0 || >=20.5.0} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.22.4': - resolution: {integrity: sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==} + '@rollup/rollup-android-arm-eabi@4.40.2': + resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.22.4': - resolution: {integrity: sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==} + '@rollup/rollup-android-arm64@4.40.2': + resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.22.4': - resolution: {integrity: sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==} + '@rollup/rollup-darwin-arm64@4.40.2': + resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.22.4': - resolution: {integrity: sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==} + '@rollup/rollup-darwin-x64@4.40.2': + resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.22.4': - resolution: {integrity: sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==} + '@rollup/rollup-freebsd-arm64@4.40.2': + resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.40.2': + resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': + resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.22.4': - resolution: {integrity: sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==} + '@rollup/rollup-linux-arm-musleabihf@4.40.2': + resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.22.4': - resolution: {integrity: sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==} + '@rollup/rollup-linux-arm64-gnu@4.40.2': + resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.22.4': - resolution: {integrity: sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==} + '@rollup/rollup-linux-arm64-musl@4.40.2': + resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': - resolution: {integrity: sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==} + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': + resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': + resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.22.4': - resolution: {integrity: sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==} + '@rollup/rollup-linux-riscv64-gnu@4.40.2': + resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.40.2': + resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.22.4': - resolution: {integrity: sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==} + '@rollup/rollup-linux-s390x-gnu@4.40.2': + resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.22.4': - resolution: {integrity: sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==} + '@rollup/rollup-linux-x64-gnu@4.40.2': + resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.22.4': - resolution: {integrity: sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==} + '@rollup/rollup-linux-x64-musl@4.40.2': + resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.22.4': - resolution: {integrity: sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==} + '@rollup/rollup-win32-arm64-msvc@4.40.2': + resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.22.4': - resolution: {integrity: sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==} + '@rollup/rollup-win32-ia32-msvc@4.40.2': + resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.22.4': - resolution: {integrity: sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==} + '@rollup/rollup-win32-x64-msvc@4.40.2': + resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==} cpu: [x64] os: [win32] @@ -2222,33 +2592,33 @@ packages: resolution: {integrity: sha512-sIoeipsisK5eTLW3XuNZYcal83AfslBbgI7LnV+3VrXwpasKPGHwo2ZdwhCd2IXAkuJ02Iyu7MyV0aQRM9i/3g==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@schematics/angular@18.2.20': - resolution: {integrity: sha512-32bJycGtePm8X994hGl9PChBVgw9bbc+ehDpxeeaIZzcFHWlM06+cJu8Jr2FA8SASg3TwdnEybxFiYS14884OQ==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@schematics/angular@20.0.2': + resolution: {integrity: sha512-TyF+/hV+8flAa/Vu8xOQF241Syg9rdbZD1dARdm6edbLo8nwxmHdRsIulRektb7oD5CpTnxpvrcNJjX77nhv6A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@sigstore/bundle@2.3.2': - resolution: {integrity: sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/bundle@3.1.0': + resolution: {integrity: sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/core@1.1.0': - resolution: {integrity: sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/core@2.0.0': + resolution: {integrity: sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/protobuf-specs@0.3.2': - resolution: {integrity: sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/protobuf-specs@0.4.3': + resolution: {integrity: sha512-fk2zjD9117RL9BjqEwF7fwv7Q/P9yGsMV4MUJZ/DocaQJ6+3pKr+syBq1owU5Q5qGw5CUbXzm+4yJ2JVRDQeSA==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/sign@2.3.2': - resolution: {integrity: sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/sign@3.1.0': + resolution: {integrity: sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/tuf@2.3.4': - resolution: {integrity: sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/tuf@3.1.1': + resolution: {integrity: sha512-eFFvlcBIoGwVkkwmTi/vEQFSva3xs5Ot3WmBcjgjVdiaoelBLQaQ/ZBfhlG0MnG0cmTYScPpk7eDdGDWUcFUmg==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/verify@1.2.1': - resolution: {integrity: sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==} - engines: {node: ^16.14.0 || >=18.0.0} + '@sigstore/verify@2.1.1': + resolution: {integrity: sha512-hVJD77oT67aowHxwT4+M6PGOp+E2LtLdTK3+FC0lBO9T7sYwItDMXZ7Z07IDCvR1M717a4axbIWckrW67KMP/w==} + engines: {node: ^18.17.0 || >=20.5.0} '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -2279,9 +2649,9 @@ packages: resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} engines: {node: ^16.14.0 || >=18.0.0} - '@tufjs/models@2.0.1': - resolution: {integrity: sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==} - engines: {node: ^16.14.0 || >=18.0.0} + '@tufjs/models@3.0.1': + resolution: {integrity: sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA==} + engines: {node: ^18.17.0 || >=20.5.0} '@tweenjs/tween.js@25.0.0': resolution: {integrity: sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==} @@ -2412,12 +2782,12 @@ packages: '@types/eslint@8.40.2': resolution: {integrity: sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/express-serve-static-core@4.17.35': resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} @@ -2466,9 +2836,6 @@ packages: '@types/mime@1.3.2': resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} - '@types/mute-stream@0.0.4': - resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} - '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -2505,9 +2872,6 @@ packages: '@types/ungap__structured-clone@1.2.0': resolution: {integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==} - '@types/wrap-ansi@3.0.0': - resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} - '@types/ws@8.5.10': resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} @@ -2711,6 +3075,12 @@ packages: peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + '@vitejs/plugin-basic-ssl@2.0.0': + resolution: {integrity: sha512-gc9Tjg8bUxBVSTzeWT3Njc0Cl3PakHFKdNfABnZWiUgbxqmHDEn7uECv3fHVylxoYgNzAcmU7ZrILz+BwSo3sA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + peerDependencies: + vite: ^6.0.0 + '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -2769,9 +3139,9 @@ packages: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -2822,14 +3192,10 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -3034,6 +3400,10 @@ packages: batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + beasties@0.3.4: + resolution: {integrity: sha512-NmzN1zN1cvGccXFyZ73335+ASXwBlVWcUPssiUDIlFdfyatHPRRufjCd5w8oPaQPvVnf9ELklaCGb1gi9FBwIw==} + engines: {node: '>=14.0.0'} + bezier-js@6.1.4: resolution: {integrity: sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==} @@ -3067,8 +3437,12 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} - browserslist@4.23.3: - resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -3085,9 +3459,6 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - builtins@5.0.1: - resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} - bumpp@9.11.1: resolution: {integrity: sha512-jBHlab9NnRwrpHsockb5E+MBo0os2yS6S7i3cnN8hB6EkTardKQotmd0CFdOc8pubLz2fxj2AD6RGtrySVG6Mw==} engines: {node: '>=10'} @@ -3117,9 +3488,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - cacache@18.0.3: - resolution: {integrity: sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==} - engines: {node: ^16.14.0 || >=18.0.0} + cacache@19.0.1: + resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} + engines: {node: ^18.17.0 || >=20.5.0} call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} @@ -3137,8 +3508,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001653: - resolution: {integrity: sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==} + caniuse-lite@1.0.30001723: + resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==} canvas-color-tracker@1.3.2: resolution: {integrity: sha512-ryQkDX26yJ3CXzb3hxUVNlg1NKE4REc5crLBq661Nxzr8TNd236SaEf2ffYLXyI5tSABSeguHLqcVq4vf9L3Zg==} @@ -3175,6 +3546,10 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + chrome-trace-event@1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} engines: {node: '>=6.0'} @@ -3189,10 +3564,6 @@ packages: cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -3217,6 +3588,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -3340,10 +3715,6 @@ packages: critters@0.0.22: resolution: {integrity: sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==} - critters@0.0.24: - resolution: {integrity: sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==} - deprecated: Ownership of Critters has moved to the Nuxt team, who will be maintaining the project going forward. If you'd like to keep using Critters, please switch to the actively-maintained fork at https://github.com/danielroe/beasties - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -3643,6 +4014,11 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -3689,8 +4065,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dotenv@16.5.0: resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} @@ -3707,8 +4083,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.13: - resolution: {integrity: sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==} + electron-to-chromium@1.5.167: + resolution: {integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -3742,6 +4118,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -3805,16 +4185,16 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.23.0: resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} engines: {node: '>=18'} hasBin: true + esbuild@0.25.5: + resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3989,6 +4369,10 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -4035,6 +4419,10 @@ packages: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + finalhandler@1.2.0: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} @@ -4250,9 +4638,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} + hosted-git-info@8.1.0: + resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==} + engines: {node: ^18.17.0 || >=20.5.0} hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} @@ -4267,6 +4655,9 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -4320,8 +4711,8 @@ packages: resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} - https-proxy-agent@7.0.5: - resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} human-signals@2.1.0: @@ -4349,9 +4740,9 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore-walk@6.0.5: - resolution: {integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ignore-walk@7.0.0: + resolution: {integrity: sha512-T4gbf83A4NH95zvhVYZc+qWocBBGlpzUXLPGurJggw/WIOwicfXJChLDP/iBZnN5WqROSu5Bm3hhle4z8a8YGQ==} + engines: {node: ^18.17.0 || >=20.5.0} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} @@ -4369,6 +4760,9 @@ packages: immutable@4.3.0: resolution: {integrity: sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==} + immutable@5.1.3: + resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -4382,10 +4776,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - index-array-by@1.4.2: resolution: {integrity: sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==} engines: {node: '>=12'} @@ -4400,9 +4790,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@4.1.3: - resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@5.0.0: + resolution: {integrity: sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==} + engines: {node: ^18.17.0 || >=20.5.0} inquirer@9.2.22: resolution: {integrity: sha512-SqLLa/Oe5rZUagTR9z+Zd6izyatHglbmbvVofo1KzuVB54YHleWzeHNLoR7FOICGOeQSqeLh1cordb3MzhGcEw==} @@ -4456,6 +4846,10 @@ packages: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} @@ -4507,8 +4901,9 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} @@ -4565,6 +4960,14 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} @@ -4604,8 +5007,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} - istanbul-lib-instrument@6.0.0: - resolution: {integrity: sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==} + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} istanbul-lib-report@3.0.0: @@ -4826,15 +5229,20 @@ packages: engines: {node: '>=4'} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-even-better-errors@3.0.0: - resolution: {integrity: sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + json-parse-even-better-errors@4.0.0: + resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} + engines: {node: ^18.17.0 || >=20.5.0} json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -4922,18 +5330,18 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - listr2@8.2.4: - resolution: {integrity: sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==} + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} - lmdb@3.0.13: - resolution: {integrity: sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==} - hasBin: true - lmdb@3.0.8: resolution: {integrity: sha512-9rp8JT4jPhCRJUL7vRARa2N06OLSYzLwQsEkhC6Qu5XbcLyM/XBLMzDlgS/K7l7c5CdURLdDk9uE+hPFIogHTQ==} hasBin: true + lmdb@3.3.0: + resolution: {integrity: sha512-MgJocUI6QEiSXQBFWLeyo1R7eQj8Rke5dlPxX0KFwli8/bsCxpM/KbXO5y0qmV/5llQ3wpneDWcTYxa+4vn8iQ==} + hasBin: true + loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -4977,6 +5385,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -5001,6 +5413,9 @@ packages: magic-string@0.30.12: resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -5012,9 +5427,9 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - make-fetch-happen@13.0.1: - resolution: {integrity: sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==} - engines: {node: ^16.14.0 || >=18.0.0} + make-fetch-happen@14.0.3: + resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} + engines: {node: ^18.17.0 || >=20.5.0} makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -5045,6 +5460,10 @@ packages: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -5086,6 +5505,10 @@ packages: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -5093,17 +5516,14 @@ packages: resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} engines: {node: '>=16 || 14 >=14.17'} - minipass-fetch@3.0.3: - resolution: {integrity: sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + minipass-fetch@4.0.1: + resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} + engines: {node: ^18.17.0 || >=20.5.0} minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} engines: {node: '>= 8'} - minipass-json-stream@1.0.1: - resolution: {integrity: sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==} - minipass-pipeline@1.2.4: resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} engines: {node: '>=8'} @@ -5128,18 +5548,34 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -5150,8 +5586,8 @@ packages: resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==} hasBin: true - msgpackr@1.10.2: - resolution: {integrity: sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==} + msgpackr@1.11.4: + resolution: {integrity: sha512-uaff7RG9VIC4jacFW9xzL3jc0iM32DNHe4jYVycBcjUePT/Klnfj7pqtWJt9khvDFizmjN2TlYniYmSS2LIaZg==} multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} @@ -5161,8 +5597,12 @@ packages: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -5183,6 +5623,10 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -5202,6 +5646,9 @@ packages: node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-fetch-native@1.6.6: resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} @@ -5225,26 +5672,22 @@ packages: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true - node-gyp@10.1.0: - resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==} - engines: {node: ^16.14.0 || >=18.0.0} + node-gyp@11.2.0: + resolution: {integrity: sha512-T0S1zqskVUSxcsSTkAsLc7xCycrRYmtDHadDinzocrThjyQCn5kMlEBSj6H4qDbgsIOSLmmlRIeb0lZXj+UArA==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - nopt@7.2.1: - resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - normalize-package-data@6.0.1: - resolution: {integrity: sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==} - engines: {node: ^16.14.0 || >=18.0.0} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5253,33 +5696,33 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - npm-bundled@3.0.0: - resolution: {integrity: sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-bundled@4.0.0: + resolution: {integrity: sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==} + engines: {node: ^18.17.0 || >=20.5.0} - npm-install-checks@6.1.1: - resolution: {integrity: sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-install-checks@7.1.1: + resolution: {integrity: sha512-u6DCwbow5ynAX5BdiHQ9qvexme4U3qHW3MWe5NqH+NeBm0LbiH6zvGjNNew1fY+AZZUtVHbOPF3j7mJxbUzpXg==} + engines: {node: ^18.17.0 || >=20.5.0} - npm-normalize-package-bin@3.0.1: - resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-normalize-package-bin@4.0.0: + resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} + engines: {node: ^18.17.0 || >=20.5.0} - npm-package-arg@11.0.3: - resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} - engines: {node: ^16.14.0 || >=18.0.0} + npm-package-arg@12.0.2: + resolution: {integrity: sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==} + engines: {node: ^18.17.0 || >=20.5.0} - npm-packlist@8.0.2: - resolution: {integrity: sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-packlist@10.0.0: + resolution: {integrity: sha512-rht9U6nS8WOBDc53eipZNPo5qkAV4X2rhKE2Oj1DYUQ3DieXfj0mKkVmjnf3iuNdtMd8WfLdi2L6ASkD/8a+Kg==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-pick-manifest@9.1.0: - resolution: {integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==} - engines: {node: ^16.14.0 || >=18.0.0} + npm-pick-manifest@10.0.0: + resolution: {integrity: sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==} + engines: {node: ^18.17.0 || >=20.5.0} - npm-registry-fetch@17.0.1: - resolution: {integrity: sha512-fLu9MTdZTlJAHUek/VLklE6EpIiP3VZpTiuN7OOMCt2Sd67NCpSEetMaxHHEZiZxllp8ZLsUpvbEszqTFEc+wA==} - engines: {node: ^16.14.0 || >=18.0.0} + npm-registry-fetch@18.0.2: + resolution: {integrity: sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==} + engines: {node: ^18.17.0 || >=20.5.0} npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -5360,8 +5803,12 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - ordered-binary@1.5.1: - resolution: {integrity: sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + + ordered-binary@1.5.3: + resolution: {integrity: sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==} os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} @@ -5391,9 +5838,9 @@ packages: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} + p-map@7.0.3: + resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + engines: {node: '>=18'} p-retry@6.2.0: resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==} @@ -5406,9 +5853,9 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - pacote@18.0.6: - resolution: {integrity: sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==} - engines: {node: ^16.14.0 || >=18.0.0} + pacote@21.0.0: + resolution: {integrity: sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true parent-module@1.0.1: @@ -5426,6 +5873,9 @@ packages: parse5-html-rewriting-stream@7.0.0: resolution: {integrity: sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==} + parse5-html-rewriting-stream@7.1.0: + resolution: {integrity: sha512-2ifK6Jb+ONoqOy5f+cYHsqvx1obHQdvIk13Jmt/5ezxP0U9p+fqd+R6O73KblGswyuzBYfetmsfK9ThMgnuPPg==} + parse5-sax-parser@7.0.0: resolution: {integrity: sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==} @@ -5494,8 +5944,9 @@ packages: piscina@4.5.0: resolution: {integrity: sha512-iBaLWI56PFP81cfBSomWTmhOo9W2/yhIOL+Tk8O1vBCpK39cM0tGxB+wgYjG31qq4ohGvysfXSdnj8h7g4rZxA==} - piscina@4.6.1: - resolution: {integrity: sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==} + piscina@5.0.0: + resolution: {integrity: sha512-R+arufwL7sZvGjAhSMK3TfH55YdGOqhpKXkcwQJr432AAnJX/xxX19PA4QisrmJ+BTTfZVggaz6HexbkQq1l1Q==} + engines: {node: '>=18.x'} pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -5563,8 +6014,8 @@ packages: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + postcss@8.5.5: + resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==} engines: {node: ^10 || ^12 || >=14} preact@10.26.9: @@ -5578,25 +6029,13 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - proc-log@3.0.0: - resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - proc-log@4.2.0: - resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + proc-log@5.0.0: + resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} + engines: {node: ^18.17.0 || >=20.5.0} process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} @@ -5732,6 +6171,11 @@ packages: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -5767,8 +6211,8 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - rollup@4.22.4: - resolution: {integrity: sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==} + rollup@4.40.2: + resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -5835,8 +6279,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - sass@1.77.6: - resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} + sass@1.88.0: + resolution: {integrity: sha512-sF6TWQqjFvr4JILXzG4ucGOLELkESHL+I5QJhh7CNaE+Yge0SI+ehCatsXhJ7ymU1hAFcIS3/PBpjdIbXoyVbg==} engines: {node: '>=14.0.0'} hasBin: true @@ -5939,9 +6383,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - sigstore@2.3.1: - resolution: {integrity: sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==} - engines: {node: ^16.14.0 || >=18.0.0} + sigstore@3.1.0: + resolution: {integrity: sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q==} + engines: {node: ^18.17.0 || >=20.5.0} sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -6029,9 +6473,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - ssri@10.0.4: - resolution: {integrity: sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ssri@12.0.0: + resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} + engines: {node: ^18.17.0 || >=20.5.0} stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} @@ -6048,6 +6492,10 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -6121,10 +6569,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - symbol-observable@4.0.0: - resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} - engines: {node: '>=0.10'} - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -6136,6 +6580,10 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -6183,6 +6631,10 @@ packages: resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -6286,9 +6738,9 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tuf-js@2.2.1: - resolution: {integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==} - engines: {node: ^16.14.0 || >=18.0.0} + tuf-js@3.0.1: + resolution: {integrity: sha512-+68OP1ZzSF84rTckf3FA95vJ1Zlx/uaXyiiKyPd1pA4rZNkpEvDAKmsu1xUSmbF/chCRYgZ6UZkDwC7PmzmAyA==} + engines: {node: ^18.17.0 || >=20.5.0} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -6336,8 +6788,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true @@ -6370,13 +6822,13 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} - unique-filename@3.0.0: - resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + unique-filename@4.0.0: + resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} + engines: {node: ^18.17.0 || >=20.5.0} - unique-slug@4.0.0: - resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + unique-slug@5.0.0: + resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} + engines: {node: ^18.17.0 || >=20.5.0} universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} @@ -6389,8 +6841,8 @@ packages: unrs-resolver@1.9.0: resolution: {integrity: sha512-wqaRu4UnzBD2ABTC1kLfBjAqIDZ5YUTr/MLGa7By47JV1bJDSW7jq/ZSLigB7enLe7ubNaJhtnBXgrc/50cEhg==} - update-browserslist-db@1.1.0: - resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -6422,9 +6874,9 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validate-npm-package-name@5.0.0: - resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + validate-npm-package-name@6.0.1: + resolution: {integrity: sha512-OaI//3H0J7ZkR1OqlhGA8cA+Cbk/2xFOQpJOt5+s27/ta9eZwpeervh4Mxh4w0im/kdgktowaqVNR7QOrUd7Yg==} + engines: {node: ^18.17.0 || >=20.5.0} vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} @@ -6458,22 +6910,27 @@ packages: terser: optional: true - vite@5.4.19: - resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} - engines: {node: ^18.0.0 || >=20.0.0} + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' less: '*' lightningcss: ^1.21.0 sass: '*' sass-embedded: '*' stylus: '*' sugarss: '*' - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + jiti: + optional: true less: optional: true lightningcss: @@ -6488,6 +6945,10 @@ packages: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true w3c-xmlserializer@4.0.0: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} @@ -6500,6 +6961,10 @@ packages: resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} engines: {node: '>=10.13.0'} + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + wbuf@1.7.3: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} @@ -6595,9 +7060,9 @@ packages: engines: {node: '>= 8'} hasBin: true - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} hasBin: true wildcard@2.0.1: @@ -6673,14 +7138,26 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -6697,9 +7174,6 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} - zone.js@0.14.4: - resolution: {integrity: sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==} - snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} @@ -6709,46 +7183,46 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@aneoconsultingfr/armonik.api.angular@3.26.0(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(@ngx-grpc/well-known-types@3.1.2(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(google-protobuf@3.21.2))(google-protobuf@3.21.2)(rxjs@7.8.2)': + '@aneoconsultingfr/armonik.api.angular@3.26.0(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(@ngx-grpc/well-known-types@3.1.2(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(google-protobuf@3.21.2))(google-protobuf@3.21.2)(rxjs@7.8.2)': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) '@ngx-grpc/common': 3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2) - '@ngx-grpc/core': 3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) + '@ngx-grpc/core': 3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) '@ngx-grpc/well-known-types': 3.1.2(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(google-protobuf@3.21.2) google-protobuf: 3.21.2 rxjs: 7.8.2 tslib: 2.8.1 - '@angular-devkit/architect@0.1800.2(chokidar@3.6.0)': + '@angular-devkit/architect@0.1800.2': dependencies: - '@angular-devkit/core': 18.0.2(chokidar@3.6.0) + '@angular-devkit/core': 18.0.2 rxjs: 7.8.1 transitivePeerDependencies: - chokidar - '@angular-devkit/architect@0.1802.20(chokidar@3.6.0)': + '@angular-devkit/architect@0.1900.2': dependencies: - '@angular-devkit/core': 18.2.20(chokidar@3.6.0) + '@angular-devkit/core': 19.0.2 rxjs: 7.8.1 transitivePeerDependencies: - chokidar - '@angular-devkit/architect@0.1900.2(chokidar@3.6.0)': + '@angular-devkit/architect@0.2000.2': dependencies: - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) - rxjs: 7.8.1 + '@angular-devkit/core': 20.0.2 + rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5)': + '@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.1800.2(chokidar@3.6.0) - '@angular-devkit/build-webpack': 0.1800.2(chokidar@3.6.0)(webpack-dev-server@5.0.4(webpack@5.91.0(esbuild@0.21.3)))(webpack@5.91.0(esbuild@0.21.3)) - '@angular-devkit/core': 18.0.2(chokidar@3.6.0) - '@angular/build': 18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.4.5) - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) + '@angular-devkit/architect': 0.1800.2 + '@angular-devkit/build-webpack': 0.1800.2(webpack-dev-server@5.0.4(webpack@5.91.0(esbuild@0.21.3)))(webpack@5.91.0(esbuild@0.21.3)) + '@angular-devkit/core': 18.0.2 + '@angular/build': 18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.8.3) + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) '@babel/core': 7.24.5 '@babel/generator': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 @@ -6759,13 +7233,13 @@ snapshots: '@babel/preset-env': 7.24.5(@babel/core@7.24.5) '@babel/runtime': 7.24.5 '@discoveryjs/json-ext': 0.5.7 - '@ngtools/webpack': 18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.91.0(esbuild@0.21.3)) + '@ngtools/webpack': 18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.91.0(esbuild@0.21.3)) '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0)) ansi-colors: 4.1.3 autoprefixer: 10.4.19(postcss@8.4.38) babel-loader: 9.1.3(@babel/core@7.24.5)(webpack@5.91.0(esbuild@0.21.3)) babel-plugin-istanbul: 6.1.1 - browserslist: 4.23.3 + browserslist: 4.25.0 copy-webpack-plugin: 11.0.0(webpack@5.91.0(esbuild@0.21.3)) critters: 0.0.22 css-loader: 7.1.1(webpack@5.91.0(esbuild@0.21.3)) @@ -6789,7 +7263,7 @@ snapshots: picomatch: 4.0.2 piscina: 4.5.0 postcss: 8.4.38 - postcss-loader: 8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.91.0(esbuild@0.21.3)) + postcss-loader: 8.1.1(postcss@8.4.38)(typescript@5.8.3)(webpack@5.91.0(esbuild@0.21.3)) resolve-url-loader: 5.0.0 rxjs: 7.8.1 sass: 1.77.2 @@ -6800,7 +7274,7 @@ snapshots: terser: 5.31.0 tree-kill: 1.2.2 tslib: 2.6.2 - typescript: 5.4.5 + typescript: 5.8.3 undici: 6.18.0 vite: 5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0) watchpack: 2.4.1 @@ -6810,9 +7284,9 @@ snapshots: webpack-merge: 5.10.0 webpack-subresource-integrity: 5.1.0(webpack@5.91.0(esbuild@0.21.3)) optionalDependencies: - '@angular/localize': 18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + '@angular/localize': 20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3) esbuild: 0.21.3 - jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-environment-jsdom: 29.7.0 transitivePeerDependencies: - '@rspack/core' @@ -6832,16 +7306,16 @@ snapshots: - utf-8-validate - webpack-cli - '@angular-devkit/build-webpack@0.1800.2(chokidar@3.6.0)(webpack-dev-server@5.0.4(webpack@5.91.0(esbuild@0.21.3)))(webpack@5.91.0(esbuild@0.21.3))': + '@angular-devkit/build-webpack@0.1800.2(webpack-dev-server@5.0.4(webpack@5.91.0(esbuild@0.21.3)))(webpack@5.91.0(esbuild@0.21.3))': dependencies: - '@angular-devkit/architect': 0.1800.2(chokidar@3.6.0) + '@angular-devkit/architect': 0.1800.2 rxjs: 7.8.1 webpack: 5.91.0(esbuild@0.21.3) webpack-dev-server: 5.0.4(webpack@5.91.0(esbuild@0.21.3)) transitivePeerDependencies: - chokidar - '@angular-devkit/core@18.0.2(chokidar@3.6.0)': + '@angular-devkit/core@18.0.2': dependencies: ajv: 8.13.0 ajv-formats: 3.0.1(ajv@8.13.0) @@ -6849,10 +7323,8 @@ snapshots: picomatch: 4.0.2 rxjs: 7.8.1 source-map: 0.7.4 - optionalDependencies: - chokidar: 3.6.0 - '@angular-devkit/core@18.2.12(chokidar@3.6.0)': + '@angular-devkit/core@18.2.12': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) @@ -6860,10 +7332,8 @@ snapshots: picomatch: 4.0.2 rxjs: 7.8.1 source-map: 0.7.4 - optionalDependencies: - chokidar: 3.6.0 - '@angular-devkit/core@18.2.20(chokidar@3.6.0)': + '@angular-devkit/core@19.0.2': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) @@ -6871,23 +7341,19 @@ snapshots: picomatch: 4.0.2 rxjs: 7.8.1 source-map: 0.7.4 - optionalDependencies: - chokidar: 3.6.0 - '@angular-devkit/core@19.0.2(chokidar@3.6.0)': + '@angular-devkit/core@20.0.2': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) jsonc-parser: 3.3.1 picomatch: 4.0.2 - rxjs: 7.8.1 + rxjs: 7.8.2 source-map: 0.7.4 - optionalDependencies: - chokidar: 3.6.0 - '@angular-devkit/schematics@18.2.12(chokidar@3.6.0)': + '@angular-devkit/schematics@18.2.12': dependencies: - '@angular-devkit/core': 18.2.12(chokidar@3.6.0) + '@angular-devkit/core': 18.2.12 jsonc-parser: 3.3.1 magic-string: 0.30.11 ora: 5.4.1 @@ -6895,63 +7361,63 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/schematics@18.2.20(chokidar@3.6.0)': + '@angular-devkit/schematics@19.0.2': dependencies: - '@angular-devkit/core': 18.2.20(chokidar@3.6.0) + '@angular-devkit/core': 19.0.2 jsonc-parser: 3.3.1 - magic-string: 0.30.11 + magic-string: 0.30.12 ora: 5.4.1 rxjs: 7.8.1 transitivePeerDependencies: - chokidar - '@angular-devkit/schematics@19.0.2(chokidar@3.6.0)': + '@angular-devkit/schematics@20.0.2': dependencies: - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) + '@angular-devkit/core': 20.0.2 jsonc-parser: 3.3.1 - magic-string: 0.30.12 - ora: 5.4.1 - rxjs: 7.8.1 + magic-string: 0.30.17 + ora: 8.2.0 + rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-eslint/builder@19.8.0(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/builder@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@angular-devkit/architect': 0.1900.2(chokidar@3.6.0) - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) + '@angular-devkit/architect': 0.1900.2 + '@angular-devkit/core': 19.0.2 eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - chokidar '@angular-eslint/bundled-angular-compiler@19.8.0': {} - '@angular-eslint/eslint-plugin-template@19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/eslint-plugin-template@19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 19.8.0 - '@angular-eslint/template-parser': 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/utils': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@angular-eslint/template-parser': 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/utils': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) aria-query: 5.3.2 axobject-query: 4.1.0 eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 - '@angular-eslint/eslint-plugin@19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/eslint-plugin@19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 19.8.0 - '@angular-eslint/utils': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@angular-eslint/utils': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 - '@angular-eslint/schematics@19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/schematics@19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) - '@angular-devkit/schematics': 19.0.2(chokidar@3.6.0) - '@angular-eslint/eslint-plugin': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/eslint-plugin-template': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@angular-devkit/core': 19.0.2 + '@angular-devkit/schematics': 19.0.2 + '@angular-eslint/eslint-plugin': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/eslint-plugin-template': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) ignore: 7.0.5 semver: 7.7.2 strip-json-comments: 3.1.1 @@ -6963,46 +7429,37 @@ snapshots: - eslint - typescript - '@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 19.8.0 eslint: 9.28.0(jiti@2.4.2) eslint-scope: 8.2.0 - typescript: 5.4.5 + typescript: 5.8.3 - '@angular-eslint/utils@19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@angular-eslint/utils@19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@angular-eslint/bundled-angular-compiler': 19.8.0 - '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 - - '@angular-material-components/datetime-picker@16.0.1(ff83a336257a45c41a1881b7e044d9d1)': - dependencies: - '@angular/cdk': 18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/forms': 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2) - '@angular/material': 18.2.14(ca82722567ed33cf1ad02ca7b207a5bc) - '@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) - tslib: 2.8.1 + typescript: 5.8.3 - '@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))': + '@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))': dependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) tslib: 2.8.1 - '@angular/build@18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.4.5)': + '@angular/build@18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.8.3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.1800.2(chokidar@3.6.0) - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) + '@angular-devkit/architect': 0.1800.2 + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-split-export-declaration': 7.24.5 '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0)) ansi-colors: 4.1.3 - browserslist: 4.23.3 + browserslist: 4.25.0 critters: 0.0.22 esbuild: 0.21.3 fast-glob: 3.3.2 @@ -7017,12 +7474,12 @@ snapshots: piscina: 4.5.0 sass: 1.77.2 semver: 7.6.2 - typescript: 5.4.5 + typescript: 5.8.3 undici: 6.18.0 vite: 5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0) watchpack: 2.4.1 optionalDependencies: - '@angular/localize': 18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + '@angular/localize': 20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3) less: 4.2.0 postcss: 8.4.38 transitivePeerDependencies: @@ -7034,173 +7491,186 @@ snapshots: - supports-color - terser - '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(typescript@5.4.5)': + '@angular/build@20.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(postcss@8.4.38)(terser@5.31.0)(tslib@2.8.1)(typescript@5.8.3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0) - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.24.7 + '@angular-devkit/architect': 0.2000.2 + '@angular/compiler': 20.0.3 + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) + '@babel/core': 7.27.1 + '@babel/helper-annotate-as-pure': 7.27.1 '@babel/helper-split-export-declaration': 7.24.7 - '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.25.2) - '@inquirer/confirm': 3.1.22 - '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.4.19(@types/node@22.15.31)(less@4.2.0)(sass@1.77.6)(terser@5.31.0)) - browserslist: 4.23.3 - critters: 0.0.24 - esbuild: 0.23.0 - fast-glob: 3.3.2 - https-proxy-agent: 7.0.5 - listr2: 8.2.4 - lmdb: 3.0.13 - magic-string: 0.30.11 - mrmime: 2.0.0 - parse5-html-rewriting-stream: 7.0.0 + '@inquirer/confirm': 5.1.10(@types/node@22.15.31) + '@vitejs/plugin-basic-ssl': 2.0.0(vite@6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(sass@1.88.0)(terser@5.31.0)) + beasties: 0.3.4 + browserslist: 4.25.0 + esbuild: 0.25.5 + https-proxy-agent: 7.0.6 + istanbul-lib-instrument: 6.0.3 + jsonc-parser: 3.3.1 + listr2: 8.3.3 + magic-string: 0.30.17 + mrmime: 2.0.1 + parse5-html-rewriting-stream: 7.1.0 picomatch: 4.0.2 - piscina: 4.6.1 - rollup: 4.22.4 - sass: 1.77.6 - semver: 7.6.3 - typescript: 5.4.5 - vite: 5.4.19(@types/node@22.15.31)(less@4.2.0)(sass@1.77.6)(terser@5.31.0) - watchpack: 2.4.1 + piscina: 5.0.0 + rollup: 4.40.2 + sass: 1.88.0 + semver: 7.7.2 + source-map-support: 0.5.21 + tinyglobby: 0.2.13 + tslib: 2.8.1 + typescript: 5.8.3 + vite: 6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(sass@1.88.0)(terser@5.31.0) + watchpack: 2.4.2 optionalDependencies: - '@angular/localize': 18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/localize': 20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) less: 4.2.0 + lmdb: 3.3.0 postcss: 8.4.38 transitivePeerDependencies: - '@types/node' - chokidar + - jiti - lightningcss - sass-embedded - stylus - sugarss - supports-color - terser + - tsx + - yaml - '@angular/cdk@18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2)': + '@angular/cdk@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + parse5: 7.1.2 rxjs: 7.8.2 tslib: 2.8.1 - optionalDependencies: - parse5: 7.1.2 - '@angular/cli@18.2.20(chokidar@3.6.0)': + '@angular/cli@20.0.2(@types/node@22.15.31)': dependencies: - '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0) - '@angular-devkit/core': 18.2.20(chokidar@3.6.0) - '@angular-devkit/schematics': 18.2.20(chokidar@3.6.0) - '@inquirer/prompts': 5.3.8 - '@listr2/prompt-adapter-inquirer': 2.0.15(@inquirer/prompts@5.3.8) - '@schematics/angular': 18.2.20(chokidar@3.6.0) + '@angular-devkit/architect': 0.2000.2 + '@angular-devkit/core': 20.0.2 + '@angular-devkit/schematics': 20.0.2 + '@inquirer/prompts': 7.5.1(@types/node@22.15.31) + '@listr2/prompt-adapter-inquirer': 2.0.22(@inquirer/prompts@7.5.1(@types/node@22.15.31)) + '@schematics/angular': 20.0.2 '@yarnpkg/lockfile': 1.1.0 - ini: 4.1.3 + ini: 5.0.0 jsonc-parser: 3.3.1 - listr2: 8.2.4 - npm-package-arg: 11.0.3 - npm-pick-manifest: 9.1.0 - pacote: 18.0.6 - resolve: 1.22.8 - semver: 7.6.3 - symbol-observable: 4.0.0 + listr2: 8.3.3 + npm-package-arg: 12.0.2 + npm-pick-manifest: 10.0.0 + pacote: 21.0.0 + resolve: 1.22.10 + semver: 7.7.2 yargs: 17.7.2 transitivePeerDependencies: - - bluebird + - '@types/node' - chokidar - supports-color - '@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2)': + '@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5)': + '@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3)': dependencies: - '@angular/compiler': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) - '@babel/core': 7.25.2 + '@angular/compiler': 20.0.3 + '@babel/core': 7.27.4 '@jridgewell/sourcemap-codec': 1.5.0 chokidar: 4.0.3 convert-source-map: 1.9.0 reflect-metadata: 0.2.2 semver: 7.7.2 tslib: 2.8.1 - typescript: 5.4.5 - yargs: 17.7.2 + yargs: 18.0.0 + optionalDependencies: + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))': + '@angular/compiler@20.0.3': dependencies: tslib: 2.8.1 - optionalDependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)': + '@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)': dependencies: rxjs: 7.8.2 tslib: 2.8.1 - zone.js: 0.14.4 + optionalDependencies: + '@angular/compiler': 20.0.3 - '@angular/forms@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2)': + '@angular/forms@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2)': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))': + '@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3)': dependencies: - '@angular/compiler': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) - '@babel/core': 7.25.2 + '@angular/compiler': 20.0.3 + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) + '@babel/core': 7.27.4 '@types/babel__core': 7.20.5 - fast-glob: 3.3.2 - yargs: 17.7.2 + tinyglobby: 0.2.14 + yargs: 18.0.0 transitivePeerDependencies: - supports-color - '@angular/material-luxon-adapter@18.2.14(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/material@18.2.14(ca82722567ed33cf1ad02ca7b207a5bc))(luxon@3.6.1)': + '@angular/material-luxon-adapter@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/material@20.0.3(85090e25850fd1deeb320c9388cbdb0b))(luxon@3.6.1)': dependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/material': 18.2.14(ca82722567ed33cf1ad02ca7b207a5bc) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/material': 20.0.3(85090e25850fd1deeb320c9388cbdb0b) luxon: 3.6.1 tslib: 2.8.1 - '@angular/material@18.2.14(ca82722567ed33cf1ad02ca7b207a5bc)': + '@angular/material-moment-adapter@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/material@20.0.3(85090e25850fd1deeb320c9388cbdb0b))(moment@2.30.1)': + dependencies: + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/material': 20.0.3(85090e25850fd1deeb320c9388cbdb0b) + moment: 2.30.1 + tslib: 2.8.1 + + '@angular/material@20.0.3(85090e25850fd1deeb320c9388cbdb0b)': dependencies: - '@angular/animations': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) - '@angular/cdk': 18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/forms': 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2) - '@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + '@angular/cdk': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/forms': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/platform-browser-dynamic@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))': + '@angular/platform-browser-dynamic@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/compiler': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/compiler': 20.0.3 + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) tslib: 2.8.1 - '@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))': + '@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@angular/animations': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + '@angular/animations': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) - '@angular/router@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(rxjs@7.8.2)': + '@angular/router@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2)': dependencies: - '@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) rxjs: 7.8.2 tslib: 2.8.1 @@ -7209,20 +7679,26 @@ snapshots: '@babel/highlight': 7.24.7 picocolors: 1.1.1 - '@babel/compat-data@7.25.4': {} + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.27.5': {} '@babel/core@7.24.5': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.6 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.24.5) - '@babel/helpers': 7.25.6 - '@babel/parser': 7.25.6 - '@babel/template': 7.25.0 - '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.24.5) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 convert-source-map: 2.0.0 debug: 4.4.1 gensync: 1.0.0-beta.2 @@ -7231,18 +7707,58 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/core@7.25.2': + '@babel/core@7.26.10': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.6 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) - '@babel/helpers': 7.25.6 - '@babel/parser': 7.25.6 - '@babel/template': 7.25.0 - '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.26.10) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.27.1': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.1) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 convert-source-map: 2.0.0 debug: 4.4.1 gensync: 1.0.0-beta.2 @@ -7253,42 +7769,50 @@ snapshots: '@babel/generator@7.24.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 '@babel/generator@7.25.6': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 + '@babel/generator@7.27.5': + dependencies: + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.22.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 - '@babel/helper-annotate-as-pure@7.24.7': + '@babel/helper-annotate-as-pure@7.27.1': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-builder-binary-assignment-operator-visitor@7.24.6': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 - '@babel/helper-compilation-targets@7.25.2': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.25.4 - '@babel/helper-validator-option': 7.24.8 - browserslist: 4.23.3 + '@babel/compat-data': 7.27.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.0 lru-cache: 5.1.1 semver: 6.3.1 '@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-annotate-as-pure': 7.27.1 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 '@babel/helper-member-expression-to-functions': 7.24.6 @@ -7301,75 +7825,93 @@ snapshots: '@babel/helper-create-regexp-features-plugin@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-annotate-as-pure': 7.27.1 regexpu-core: 5.3.2 semver: 6.3.1 '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.1 lodash.debounce: 4.0.8 - resolve: 1.22.8 + resolve: 1.22.10 transitivePeerDependencies: - supports-color '@babel/helper-environment-visitor@7.24.7': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-function-name@7.24.7': dependencies: - '@babel/template': 7.25.0 - '@babel/types': 7.25.6 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 '@babel/helper-hoist-variables@7.24.7': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-member-expression-to-functions@7.24.6': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 - '@babel/helper-module-imports@7.24.7': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.25.2(@babel/core@7.24.5)': + '@babel/helper-module-transforms@7.27.3(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.6 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': + '@babel/helper-module-transforms@7.27.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.6 + '@babel/core': 7.26.10 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.1)': + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.24.6': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-plugin-utils@7.24.7': {} + '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-remap-async-to-generator@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-annotate-as-pure': 7.27.1 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-wrap-function': 7.24.6 @@ -7382,39 +7924,43 @@ snapshots: '@babel/helper-simple-access@7.24.7': dependencies: - '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.24.6': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-split-export-declaration@7.24.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/helper-string-parser@7.24.8': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.24.7': {} - '@babel/helper-validator-option@7.24.8': {} + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.24.6': dependencies: '@babel/helper-function-name': 7.24.7 - '@babel/template': 7.25.0 - '@babel/types': 7.25.6 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 - '@babel/helpers@7.25.6': + '@babel/helpers@7.27.6': dependencies: - '@babel/template': 7.25.0 - '@babel/types': 7.25.6 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 '@babel/highlight@7.24.7': dependencies: @@ -7423,25 +7969,25 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/parser@7.25.6': + '@babel/parser@7.27.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.5) @@ -7449,7 +7995,7 @@ snapshots: dependencies: '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.5)': dependencies: @@ -7460,14 +8006,14 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.5)': @@ -7475,49 +8021,44 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-assertions@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.5)': + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 - - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.5)': @@ -7525,14 +8066,14 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.25.2)': + '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.5)': @@ -7540,9 +8081,9 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.5)': @@ -7550,9 +8091,9 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.5)': @@ -7560,9 +8101,9 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.5)': @@ -7570,9 +8111,9 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.5)': @@ -7580,9 +8121,9 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.5)': @@ -7590,55 +8131,55 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.25.2)': + '@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.5) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.5) transitivePeerDependencies: - supports-color @@ -7646,34 +8187,34 @@ snapshots: '@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-class-properties@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-class-static-block@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.5) '@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-annotate-as-pure': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.5) '@babel/helper-split-export-declaration': 7.24.7 globals: 11.12.0 @@ -7681,91 +8222,91 @@ snapshots: '@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/template': 7.25.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 '@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dotall-regex@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-duplicate-keys@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dynamic-import@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-exponentiation-operator@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-export-namespace-from@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 '@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-function-name': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-json-strings@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-logical-assignment-operators@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) '@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-modules-amd@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color '@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-simple-access': 7.24.7 transitivePeerDependencies: - supports-color @@ -7774,17 +8315,17 @@ snapshots: dependencies: '@babel/core': 7.24.5 '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 transitivePeerDependencies: - supports-color '@babel/plugin-transform-modules-umd@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -7792,92 +8333,92 @@ snapshots: dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-new-target@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-nullish-coalescing-operator@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-numeric-separator@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) '@babel/plugin-transform-object-rest-spread@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.5) '@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.5) '@babel/plugin-transform-optional-catch-binding@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-optional-chaining@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) '@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-private-methods@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-private-property-in-object@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-annotate-as-pure': 7.27.1 '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.5) '@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-regenerator@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 regenerator-transform: 0.15.2 '@babel/plugin-transform-reserved-words@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-runtime@7.24.3(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.5) babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.5) babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.5) @@ -7888,59 +8429,59 @@ snapshots: '@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 '@babel/plugin-transform-sticky-regex@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-typeof-symbol@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-escapes@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-property-regex@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-regex@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-sets-regex@7.24.6(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/preset-env@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/compat-data': 7.25.4 + '@babel/compat-data': 7.27.5 '@babel/core': 7.24.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-validator-option': 7.24.8 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.6(@babel/core@7.24.5) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.6(@babel/core@7.24.5) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.6(@babel/core@7.24.5) @@ -7952,7 +8493,7 @@ snapshots: '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) '@babel/plugin-syntax-import-assertions': 7.24.6(@babel/core@7.24.5) - '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.5) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.24.5) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) @@ -8024,8 +8565,8 @@ snapshots: '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/types': 7.25.6 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.27.6 esutils: 2.0.3 '@babel/regjsgen@0.8.0': {} @@ -8034,19 +8575,19 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.25.0': + '@babel/template@7.27.2': dependencies: - '@babel/code-frame': 7.24.7 - '@babel/parser': 7.25.6 - '@babel/types': 7.25.6 + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 - '@babel/traverse@7.25.6': + '@babel/traverse@7.27.4': dependencies: - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.6 - '@babel/parser': 7.25.6 - '@babel/template': 7.25.0 - '@babel/types': 7.25.6 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 debug: 4.4.1 globals: 11.12.0 transitivePeerDependencies: @@ -8058,6 +8599,11 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@babel/types@7.27.6': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@bcoe/v8-coverage@0.2.3': {} '@cspotcode/source-map-support@0.8.1': @@ -8088,10 +8634,10 @@ snapshots: '@esbuild/aix-ppc64@0.21.3': optional: true - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/aix-ppc64@0.23.0': optional: true - '@esbuild/aix-ppc64@0.23.0': + '@esbuild/aix-ppc64@0.25.5': optional: true '@esbuild/android-arm64@0.20.1': @@ -8100,10 +8646,10 @@ snapshots: '@esbuild/android-arm64@0.21.3': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm64@0.23.0': optional: true - '@esbuild/android-arm64@0.23.0': + '@esbuild/android-arm64@0.25.5': optional: true '@esbuild/android-arm@0.20.1': @@ -8112,10 +8658,10 @@ snapshots: '@esbuild/android-arm@0.21.3': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm@0.23.0': optional: true - '@esbuild/android-arm@0.23.0': + '@esbuild/android-arm@0.25.5': optional: true '@esbuild/android-x64@0.20.1': @@ -8124,10 +8670,10 @@ snapshots: '@esbuild/android-x64@0.21.3': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-x64@0.23.0': optional: true - '@esbuild/android-x64@0.23.0': + '@esbuild/android-x64@0.25.5': optional: true '@esbuild/darwin-arm64@0.20.1': @@ -8136,10 +8682,10 @@ snapshots: '@esbuild/darwin-arm64@0.21.3': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-arm64@0.23.0': optional: true - '@esbuild/darwin-arm64@0.23.0': + '@esbuild/darwin-arm64@0.25.5': optional: true '@esbuild/darwin-x64@0.20.1': @@ -8148,10 +8694,10 @@ snapshots: '@esbuild/darwin-x64@0.21.3': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-x64@0.23.0': optional: true - '@esbuild/darwin-x64@0.23.0': + '@esbuild/darwin-x64@0.25.5': optional: true '@esbuild/freebsd-arm64@0.20.1': @@ -8160,10 +8706,10 @@ snapshots: '@esbuild/freebsd-arm64@0.21.3': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-arm64@0.23.0': optional: true - '@esbuild/freebsd-arm64@0.23.0': + '@esbuild/freebsd-arm64@0.25.5': optional: true '@esbuild/freebsd-x64@0.20.1': @@ -8172,10 +8718,10 @@ snapshots: '@esbuild/freebsd-x64@0.21.3': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-x64@0.23.0': optional: true - '@esbuild/freebsd-x64@0.23.0': + '@esbuild/freebsd-x64@0.25.5': optional: true '@esbuild/linux-arm64@0.20.1': @@ -8184,10 +8730,10 @@ snapshots: '@esbuild/linux-arm64@0.21.3': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm64@0.23.0': optional: true - '@esbuild/linux-arm64@0.23.0': + '@esbuild/linux-arm64@0.25.5': optional: true '@esbuild/linux-arm@0.20.1': @@ -8196,10 +8742,10 @@ snapshots: '@esbuild/linux-arm@0.21.3': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm@0.23.0': optional: true - '@esbuild/linux-arm@0.23.0': + '@esbuild/linux-arm@0.25.5': optional: true '@esbuild/linux-ia32@0.20.1': @@ -8208,10 +8754,10 @@ snapshots: '@esbuild/linux-ia32@0.21.3': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-ia32@0.23.0': optional: true - '@esbuild/linux-ia32@0.23.0': + '@esbuild/linux-ia32@0.25.5': optional: true '@esbuild/linux-loong64@0.20.1': @@ -8220,10 +8766,10 @@ snapshots: '@esbuild/linux-loong64@0.21.3': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-loong64@0.23.0': optional: true - '@esbuild/linux-loong64@0.23.0': + '@esbuild/linux-loong64@0.25.5': optional: true '@esbuild/linux-mips64el@0.20.1': @@ -8232,10 +8778,10 @@ snapshots: '@esbuild/linux-mips64el@0.21.3': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-mips64el@0.23.0': optional: true - '@esbuild/linux-mips64el@0.23.0': + '@esbuild/linux-mips64el@0.25.5': optional: true '@esbuild/linux-ppc64@0.20.1': @@ -8244,10 +8790,10 @@ snapshots: '@esbuild/linux-ppc64@0.21.3': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-ppc64@0.23.0': optional: true - '@esbuild/linux-ppc64@0.23.0': + '@esbuild/linux-ppc64@0.25.5': optional: true '@esbuild/linux-riscv64@0.20.1': @@ -8256,10 +8802,10 @@ snapshots: '@esbuild/linux-riscv64@0.21.3': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-riscv64@0.23.0': optional: true - '@esbuild/linux-riscv64@0.23.0': + '@esbuild/linux-riscv64@0.25.5': optional: true '@esbuild/linux-s390x@0.20.1': @@ -8268,10 +8814,10 @@ snapshots: '@esbuild/linux-s390x@0.21.3': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-s390x@0.23.0': optional: true - '@esbuild/linux-s390x@0.23.0': + '@esbuild/linux-s390x@0.25.5': optional: true '@esbuild/linux-x64@0.20.1': @@ -8280,10 +8826,13 @@ snapshots: '@esbuild/linux-x64@0.21.3': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-x64@0.23.0': + optional: true + + '@esbuild/linux-x64@0.25.5': optional: true - '@esbuild/linux-x64@0.23.0': + '@esbuild/netbsd-arm64@0.25.5': optional: true '@esbuild/netbsd-x64@0.20.1': @@ -8292,25 +8841,28 @@ snapshots: '@esbuild/netbsd-x64@0.21.3': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/netbsd-x64@0.23.0': optional: true - '@esbuild/netbsd-x64@0.23.0': + '@esbuild/netbsd-x64@0.25.5': optional: true '@esbuild/openbsd-arm64@0.23.0': optional: true + '@esbuild/openbsd-arm64@0.25.5': + optional: true + '@esbuild/openbsd-x64@0.20.1': optional: true '@esbuild/openbsd-x64@0.21.3': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.23.0': optional: true - '@esbuild/openbsd-x64@0.23.0': + '@esbuild/openbsd-x64@0.25.5': optional: true '@esbuild/sunos-x64@0.20.1': @@ -8319,10 +8871,10 @@ snapshots: '@esbuild/sunos-x64@0.21.3': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.23.0': optional: true - '@esbuild/sunos-x64@0.23.0': + '@esbuild/sunos-x64@0.25.5': optional: true '@esbuild/win32-arm64@0.20.1': @@ -8331,10 +8883,10 @@ snapshots: '@esbuild/win32-arm64@0.21.3': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.23.0': optional: true - '@esbuild/win32-arm64@0.23.0': + '@esbuild/win32-arm64@0.25.5': optional: true '@esbuild/win32-ia32@0.20.1': @@ -8343,10 +8895,10 @@ snapshots: '@esbuild/win32-ia32@0.21.3': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.23.0': optional: true - '@esbuild/win32-ia32@0.23.0': + '@esbuild/win32-ia32@0.25.5': optional: true '@esbuild/win32-x64@0.20.1': @@ -8355,10 +8907,10 @@ snapshots: '@esbuild/win32-x64@0.21.3': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.23.0': optional: true - '@esbuild/win32-x64@0.23.0': + '@esbuild/win32-x64@0.25.5': optional: true '@eslint-community/eslint-utils@4.4.0(eslint@9.28.0(jiti@2.4.2))': @@ -8427,103 +8979,133 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/checkbox@2.4.7': + '@inquirer/checkbox@4.1.8(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/figures': 1.0.5 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7(@types/node@22.15.31) ansi-escapes: 4.3.2 yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/confirm@3.1.22': + '@inquirer/confirm@5.1.10(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/core@9.0.10': + '@inquirer/confirm@5.1.12(@types/node@22.15.31)': dependencies: - '@inquirer/figures': 1.0.5 - '@inquirer/type': 1.5.2 - '@types/mute-stream': 0.0.4 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) + optionalDependencies: '@types/node': 22.15.31 - '@types/wrap-ansi': 3.0.0 + + '@inquirer/core@10.1.13(@types/node@22.15.31)': + dependencies: + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7(@types/node@22.15.31) ansi-escapes: 4.3.2 - cli-spinners: 2.9.2 cli-width: 4.1.0 - mute-stream: 1.0.0 + mute-stream: 2.0.0 signal-exit: 4.1.0 - strip-ansi: 6.0.1 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/editor@2.1.22': + '@inquirer/editor@4.2.13(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) external-editor: 3.1.0 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/expand@2.1.22': + '@inquirer/expand@4.0.15(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/figures@1.0.5': {} + '@inquirer/figures@1.0.12': {} - '@inquirer/input@2.2.9': + '@inquirer/input@4.1.12(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/number@1.0.10': + '@inquirer/number@3.0.15(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/password@2.1.22': + '@inquirer/password@4.0.15(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) ansi-escapes: 4.3.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/prompts@5.3.8': - dependencies: - '@inquirer/checkbox': 2.4.7 - '@inquirer/confirm': 3.1.22 - '@inquirer/editor': 2.1.22 - '@inquirer/expand': 2.1.22 - '@inquirer/input': 2.2.9 - '@inquirer/number': 1.0.10 - '@inquirer/password': 2.1.22 - '@inquirer/rawlist': 2.2.4 - '@inquirer/search': 1.0.7 - '@inquirer/select': 2.4.7 + '@inquirer/prompts@7.5.1(@types/node@22.15.31)': + dependencies: + '@inquirer/checkbox': 4.1.8(@types/node@22.15.31) + '@inquirer/confirm': 5.1.12(@types/node@22.15.31) + '@inquirer/editor': 4.2.13(@types/node@22.15.31) + '@inquirer/expand': 4.0.15(@types/node@22.15.31) + '@inquirer/input': 4.1.12(@types/node@22.15.31) + '@inquirer/number': 3.0.15(@types/node@22.15.31) + '@inquirer/password': 4.0.15(@types/node@22.15.31) + '@inquirer/rawlist': 4.1.3(@types/node@22.15.31) + '@inquirer/search': 3.0.15(@types/node@22.15.31) + '@inquirer/select': 4.2.3(@types/node@22.15.31) + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/rawlist@2.2.4': + '@inquirer/rawlist@4.1.3(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/type': 3.0.7(@types/node@22.15.31) yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/search@1.0.7': + '@inquirer/search@3.0.15(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/figures': 1.0.5 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7(@types/node@22.15.31) yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/select@2.4.7': + '@inquirer/select@4.2.3(@types/node@22.15.31)': dependencies: - '@inquirer/core': 9.0.10 - '@inquirer/figures': 1.0.5 - '@inquirer/type': 1.5.2 + '@inquirer/core': 10.1.13(@types/node@22.15.31) + '@inquirer/figures': 1.0.12 + '@inquirer/type': 3.0.7(@types/node@22.15.31) ansi-escapes: 4.3.2 yoctocolors-cjs: 2.1.2 + optionalDependencies: + '@types/node': 22.15.31 - '@inquirer/type@1.5.2': + '@inquirer/type@1.5.5': dependencies: mute-stream: 1.0.0 + '@inquirer/type@3.0.7(@types/node@22.15.31)': + optionalDependencies: + '@types/node': 22.15.31 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -8533,6 +9115,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -8552,7 +9138,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -8566,7 +9152,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -8638,7 +9224,7 @@ snapshots: glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 6.0.0 + istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.0 istanbul-lib-source-maps: 4.0.1 istanbul-reports: 3.1.5 @@ -8678,7 +9264,7 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 babel-plugin-istanbul: 6.1.1 @@ -8750,67 +9336,138 @@ snapshots: '@leichtgewicht/ip-codec@2.0.4': {} - '@listr2/prompt-adapter-inquirer@2.0.15(@inquirer/prompts@5.3.8)': + '@listr2/prompt-adapter-inquirer@2.0.22(@inquirer/prompts@7.5.1(@types/node@22.15.31))': dependencies: - '@inquirer/prompts': 5.3.8 - '@inquirer/type': 1.5.2 + '@inquirer/prompts': 7.5.1(@types/node@22.15.31) + '@inquirer/type': 1.5.5 '@ljharb/through@2.3.13': dependencies: call-bind: 1.0.7 - '@lmdb/lmdb-darwin-arm64@3.0.13': + '@lmdb/lmdb-darwin-arm64@3.0.8': + optional: true + + '@lmdb/lmdb-darwin-arm64@3.3.0': + optional: true + + '@lmdb/lmdb-darwin-x64@3.0.8': + optional: true + + '@lmdb/lmdb-darwin-x64@3.3.0': + optional: true + + '@lmdb/lmdb-linux-arm64@3.0.8': + optional: true + + '@lmdb/lmdb-linux-arm64@3.3.0': + optional: true + + '@lmdb/lmdb-linux-arm@3.0.8': + optional: true + + '@lmdb/lmdb-linux-arm@3.3.0': + optional: true + + '@lmdb/lmdb-linux-x64@3.0.8': + optional: true + + '@lmdb/lmdb-linux-x64@3.3.0': + optional: true + + '@lmdb/lmdb-win32-arm64@3.3.0': + optional: true + + '@lmdb/lmdb-win32-x64@3.0.8': + optional: true + + '@lmdb/lmdb-win32-x64@3.3.0': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2': optional: true - '@lmdb/lmdb-darwin-arm64@3.0.8': + '@napi-rs/nice-android-arm-eabi@1.0.1': optional: true - '@lmdb/lmdb-darwin-x64@3.0.13': + '@napi-rs/nice-android-arm64@1.0.1': optional: true - '@lmdb/lmdb-darwin-x64@3.0.8': + '@napi-rs/nice-darwin-arm64@1.0.1': optional: true - '@lmdb/lmdb-linux-arm64@3.0.13': + '@napi-rs/nice-darwin-x64@1.0.1': optional: true - '@lmdb/lmdb-linux-arm64@3.0.8': + '@napi-rs/nice-freebsd-x64@1.0.1': optional: true - '@lmdb/lmdb-linux-arm@3.0.13': + '@napi-rs/nice-linux-arm-gnueabihf@1.0.1': optional: true - '@lmdb/lmdb-linux-arm@3.0.8': + '@napi-rs/nice-linux-arm64-gnu@1.0.1': optional: true - '@lmdb/lmdb-linux-x64@3.0.13': + '@napi-rs/nice-linux-arm64-musl@1.0.1': optional: true - '@lmdb/lmdb-linux-x64@3.0.8': + '@napi-rs/nice-linux-ppc64-gnu@1.0.1': optional: true - '@lmdb/lmdb-win32-x64@3.0.13': + '@napi-rs/nice-linux-riscv64-gnu@1.0.1': optional: true - '@lmdb/lmdb-win32-x64@3.0.8': + '@napi-rs/nice-linux-s390x-gnu@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': + '@napi-rs/nice-linux-x64-gnu@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2': + '@napi-rs/nice-linux-x64-musl@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2': + '@napi-rs/nice-win32-arm64-msvc@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2': + '@napi-rs/nice-win32-ia32-msvc@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2': + '@napi-rs/nice-win32-x64-msvc@1.0.1': optional: true - '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2': + '@napi-rs/nice@1.0.1': + optionalDependencies: + '@napi-rs/nice-android-arm-eabi': 1.0.1 + '@napi-rs/nice-android-arm64': 1.0.1 + '@napi-rs/nice-darwin-arm64': 1.0.1 + '@napi-rs/nice-darwin-x64': 1.0.1 + '@napi-rs/nice-freebsd-x64': 1.0.1 + '@napi-rs/nice-linux-arm-gnueabihf': 1.0.1 + '@napi-rs/nice-linux-arm64-gnu': 1.0.1 + '@napi-rs/nice-linux-arm64-musl': 1.0.1 + '@napi-rs/nice-linux-ppc64-gnu': 1.0.1 + '@napi-rs/nice-linux-riscv64-gnu': 1.0.1 + '@napi-rs/nice-linux-s390x-gnu': 1.0.1 + '@napi-rs/nice-linux-x64-gnu': 1.0.1 + '@napi-rs/nice-linux-x64-musl': 1.0.1 + '@napi-rs/nice-win32-arm64-msvc': 1.0.1 + '@napi-rs/nice-win32-ia32-msvc': 1.0.1 + '@napi-rs/nice-win32-x64-msvc': 1.0.1 optional: true '@napi-rs/wasm-runtime@0.2.11': @@ -8820,10 +9477,10 @@ snapshots: '@tybys/wasm-util': 0.9.0 optional: true - '@ngtools/webpack@18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.91.0(esbuild@0.21.3))': + '@ngtools/webpack@18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.91.0(esbuild@0.21.3))': dependencies: - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) - typescript: 5.4.5 + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) + typescript: 5.8.3 webpack: 5.91.0(esbuild@0.21.3) '@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2)': @@ -8832,18 +9489,18 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@ngx-grpc/core@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) '@ngx-grpc/common': 3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2) rxjs: 7.8.2 tslib: 2.8.1 - '@ngx-grpc/grpc-web-client@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(grpc-web@1.4.2)(rxjs@7.8.2)': + '@ngx-grpc/grpc-web-client@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(@ngx-grpc/core@3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2))(grpc-web@1.4.2)(rxjs@7.8.2)': dependencies: - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) '@ngx-grpc/common': 3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2) - '@ngx-grpc/core': 3.1.2(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) + '@ngx-grpc/core': 3.1.2(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@ngx-grpc/common@3.1.2(google-protobuf@3.21.2)(rxjs@7.8.2))(rxjs@7.8.2) grpc-web: 1.4.2 rxjs: 7.8.2 tslib: 2.8.1 @@ -8854,6 +9511,16 @@ snapshots: google-protobuf: 3.21.2 tslib: 2.8.1 + '@ngxmc/datetime-picker@20.0.0(ba9d63375f4f35e59440e81497e9b0b2)': + dependencies: + '@angular/cdk': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/common': 20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/forms': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(rxjs@7.8.2) + '@angular/material': 20.0.3(85090e25850fd1deeb320c9388cbdb0b) + '@angular/platform-browser': 20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)) + tslib: 2.8.1 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -8868,170 +9535,238 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@npmcli/agent@2.2.2': + '@npmcli/agent@3.0.0': dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 lru-cache: 10.2.2 socks-proxy-agent: 8.0.3 transitivePeerDependencies: - supports-color - '@npmcli/fs@3.1.0': + '@npmcli/fs@4.0.0': dependencies: semver: 7.7.2 - '@npmcli/git@5.0.7': + '@npmcli/git@6.0.3': dependencies: - '@npmcli/promise-spawn': 7.0.2 + '@npmcli/promise-spawn': 8.0.2 + ini: 5.0.0 lru-cache: 10.2.2 - npm-pick-manifest: 9.1.0 - proc-log: 4.2.0 - promise-inflight: 1.0.1 + npm-pick-manifest: 10.0.0 + proc-log: 5.0.0 promise-retry: 2.0.1 semver: 7.7.2 - which: 4.0.0 - transitivePeerDependencies: - - bluebird + which: 5.0.0 - '@npmcli/installed-package-contents@2.0.2': + '@npmcli/installed-package-contents@3.0.0': dependencies: - npm-bundled: 3.0.0 - npm-normalize-package-bin: 3.0.1 + npm-bundled: 4.0.0 + npm-normalize-package-bin: 4.0.0 - '@npmcli/node-gyp@3.0.0': {} + '@npmcli/node-gyp@4.0.0': {} - '@npmcli/package-json@5.1.1': + '@npmcli/package-json@6.2.0': dependencies: - '@npmcli/git': 5.0.7 + '@npmcli/git': 6.0.3 glob: 10.4.1 - hosted-git-info: 7.0.2 - json-parse-even-better-errors: 3.0.0 - normalize-package-data: 6.0.1 - proc-log: 4.2.0 + hosted-git-info: 8.1.0 + json-parse-even-better-errors: 4.0.0 + proc-log: 5.0.0 semver: 7.7.2 - transitivePeerDependencies: - - bluebird + validate-npm-package-license: 3.0.4 - '@npmcli/promise-spawn@7.0.2': + '@npmcli/promise-spawn@8.0.2': dependencies: - which: 4.0.0 + which: 5.0.0 - '@npmcli/redact@2.0.0': {} + '@npmcli/redact@3.2.2': {} - '@npmcli/run-script@8.1.0': + '@npmcli/run-script@9.1.0': dependencies: - '@npmcli/node-gyp': 3.0.0 - '@npmcli/package-json': 5.1.1 - '@npmcli/promise-spawn': 7.0.2 - node-gyp: 10.1.0 - proc-log: 4.2.0 - which: 4.0.0 + '@npmcli/node-gyp': 4.0.0 + '@npmcli/package-json': 6.2.0 + '@npmcli/promise-spawn': 8.0.2 + node-gyp: 11.2.0 + proc-log: 5.0.0 + which: 5.0.0 transitivePeerDependencies: - - bluebird - supports-color + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.22.4': + '@rollup/rollup-android-arm-eabi@4.40.2': + optional: true + + '@rollup/rollup-android-arm64@4.40.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.40.2': + optional: true + + '@rollup/rollup-darwin-x64@4.40.2': optional: true - '@rollup/rollup-android-arm64@4.22.4': + '@rollup/rollup-freebsd-arm64@4.40.2': optional: true - '@rollup/rollup-darwin-arm64@4.22.4': + '@rollup/rollup-freebsd-x64@4.40.2': optional: true - '@rollup/rollup-darwin-x64@4.22.4': + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.22.4': + '@rollup/rollup-linux-arm-musleabihf@4.40.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.22.4': + '@rollup/rollup-linux-arm64-gnu@4.40.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.22.4': + '@rollup/rollup-linux-arm64-musl@4.40.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.22.4': + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.22.4': + '@rollup/rollup-linux-riscv64-gnu@4.40.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.22.4': + '@rollup/rollup-linux-riscv64-musl@4.40.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.22.4': + '@rollup/rollup-linux-s390x-gnu@4.40.2': optional: true - '@rollup/rollup-linux-x64-musl@4.22.4': + '@rollup/rollup-linux-x64-gnu@4.40.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.22.4': + '@rollup/rollup-linux-x64-musl@4.40.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.22.4': + '@rollup/rollup-win32-arm64-msvc@4.40.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.22.4': + '@rollup/rollup-win32-ia32-msvc@4.40.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true '@rtsao/scc@1.1.0': {} - '@schematics/angular@18.2.12(chokidar@3.6.0)': + '@schematics/angular@18.2.12': dependencies: - '@angular-devkit/core': 18.2.12(chokidar@3.6.0) - '@angular-devkit/schematics': 18.2.12(chokidar@3.6.0) + '@angular-devkit/core': 18.2.12 + '@angular-devkit/schematics': 18.2.12 jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar - '@schematics/angular@18.2.20(chokidar@3.6.0)': + '@schematics/angular@20.0.2': dependencies: - '@angular-devkit/core': 18.2.20(chokidar@3.6.0) - '@angular-devkit/schematics': 18.2.20(chokidar@3.6.0) + '@angular-devkit/core': 20.0.2 + '@angular-devkit/schematics': 20.0.2 jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar - '@sigstore/bundle@2.3.2': + '@sigstore/bundle@3.1.0': dependencies: - '@sigstore/protobuf-specs': 0.3.2 + '@sigstore/protobuf-specs': 0.4.3 - '@sigstore/core@1.1.0': {} + '@sigstore/core@2.0.0': {} - '@sigstore/protobuf-specs@0.3.2': {} + '@sigstore/protobuf-specs@0.4.3': {} - '@sigstore/sign@2.3.2': + '@sigstore/sign@3.1.0': dependencies: - '@sigstore/bundle': 2.3.2 - '@sigstore/core': 1.1.0 - '@sigstore/protobuf-specs': 0.3.2 - make-fetch-happen: 13.0.1 - proc-log: 4.2.0 + '@sigstore/bundle': 3.1.0 + '@sigstore/core': 2.0.0 + '@sigstore/protobuf-specs': 0.4.3 + make-fetch-happen: 14.0.3 + proc-log: 5.0.0 promise-retry: 2.0.1 transitivePeerDependencies: - supports-color - '@sigstore/tuf@2.3.4': + '@sigstore/tuf@3.1.1': dependencies: - '@sigstore/protobuf-specs': 0.3.2 - tuf-js: 2.2.1 + '@sigstore/protobuf-specs': 0.4.3 + tuf-js: 3.0.1 transitivePeerDependencies: - supports-color - '@sigstore/verify@1.2.1': + '@sigstore/verify@2.1.1': dependencies: - '@sigstore/bundle': 2.3.2 - '@sigstore/core': 1.1.0 - '@sigstore/protobuf-specs': 0.3.2 + '@sigstore/bundle': 3.1.0 + '@sigstore/core': 2.0.0 + '@sigstore/protobuf-specs': 0.4.3 '@sinclair/typebox@0.27.8': {} @@ -9055,10 +9790,10 @@ snapshots: '@tufjs/canonical-json@2.0.0': {} - '@tufjs/models@2.0.1': + '@tufjs/models@3.0.1': dependencies: '@tufjs/canonical-json': 2.0.0 - minimatch: 9.0.4 + minimatch: 9.0.5 '@tweenjs/tween.js@25.0.0': {} @@ -9069,24 +9804,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.25.6 - '@babel/types': 7.25.6 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.20.1 '@types/babel__generator@7.6.4': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@types/babel__template@7.4.1': dependencies: - '@babel/parser': 7.25.6 - '@babel/types': 7.25.6 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 '@types/babel__traverse@7.20.1': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.27.6 '@types/body-parser@1.19.2': dependencies: @@ -9226,17 +9961,17 @@ snapshots: '@types/eslint-scope@3.7.4': dependencies: '@types/eslint': 8.40.2 - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 '@types/eslint@8.40.2': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 '@types/json-schema': 7.0.15 - '@types/estree@1.0.5': {} - '@types/estree@1.0.6': {} + '@types/estree@1.0.7': {} + '@types/express-serve-static-core@4.17.35': dependencies: '@types/node': 22.15.31 @@ -9294,10 +10029,6 @@ snapshots: '@types/mime@1.3.2': {} - '@types/mute-stream@0.0.4': - dependencies: - '@types/node': 22.15.31 - '@types/node-forge@1.3.11': dependencies: '@types/node': 22.15.31 @@ -9337,8 +10068,6 @@ snapshots: '@types/ungap__structured-clone@1.2.0': {} - '@types/wrap-ansi@3.0.0': {} - '@types/ws@8.5.10': dependencies: '@types/node': 22.15.31 @@ -9349,41 +10078,41 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.0 - '@typescript-eslint/eslint-plugin@8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.34.0 - '@typescript-eslint/type-utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/type-utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.34.0 eslint: 9.28.0(jiti@2.4.2) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.4.5) - typescript: 5.4.5 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.34.0 '@typescript-eslint/types': 8.34.0 - '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.34.0 debug: 4.3.7 eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.34.0(typescript@5.4.5)': + '@typescript-eslint/project-service@8.34.0(typescript@5.8.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.4.5) + '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.8.3) '@typescript-eslint/types': 8.34.0 debug: 4.4.1 - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -9397,18 +10126,18 @@ snapshots: '@typescript-eslint/types': 8.34.0 '@typescript-eslint/visitor-keys': 8.34.0 - '@typescript-eslint/tsconfig-utils@8.34.0(typescript@5.4.5)': + '@typescript-eslint/tsconfig-utils@8.34.0(typescript@5.8.3)': dependencies: - typescript: 5.4.5 + typescript: 5.8.3 - '@typescript-eslint/type-utils@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@typescript-eslint/type-utils@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.4.5) - '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) debug: 4.3.7 eslint: 9.28.0(jiti@2.4.2) - ts-api-utils: 2.1.0(typescript@5.4.5) - typescript: 5.4.5 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -9416,7 +10145,7 @@ snapshots: '@typescript-eslint/types@8.34.0': {} - '@typescript-eslint/typescript-estree@8.15.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@8.15.0(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.15.0 '@typescript-eslint/visitor-keys': 8.15.0 @@ -9425,16 +10154,16 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.7.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.8.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.34.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@8.34.0(typescript@5.8.3)': dependencies: - '@typescript-eslint/project-service': 8.34.0(typescript@5.4.5) - '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.4.5) + '@typescript-eslint/project-service': 8.34.0(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.8.3) '@typescript-eslint/types': 8.34.0 '@typescript-eslint/visitor-keys': 8.34.0 debug: 4.4.1 @@ -9442,31 +10171,31 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.4.5) - typescript: 5.4.5 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.28.0(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.15.0 '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5)': + '@typescript-eslint/utils@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.34.0 '@typescript-eslint/types': 8.34.0 - '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -9545,9 +10274,9 @@ snapshots: dependencies: vite: 5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.19(@types/node@22.15.31)(less@4.2.0)(sass@1.77.6)(terser@5.31.0))': + '@vitejs/plugin-basic-ssl@2.0.0(vite@6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(sass@1.88.0)(terser@5.31.0))': dependencies: - vite: 5.4.19(@types/node@22.15.31)(less@4.2.0)(sass@1.77.6)(terser@5.31.0) + vite: 6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(sass@1.88.0)(terser@5.31.0) '@webassemblyjs/ast@1.12.1': dependencies: @@ -9633,7 +10362,7 @@ snapshots: abab@2.0.6: {} - abbrev@2.0.0: {} + abbrev@3.0.1: {} accepts@1.3.8: dependencies: @@ -9674,16 +10403,7 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.1: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 + agent-base@7.1.3: {} ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: @@ -9727,20 +10447,20 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - angular-eslint@19.8.0(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(typescript@5.4.5): + angular-eslint@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(typescript@5.8.3): dependencies: - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) - '@angular-devkit/schematics': 19.0.2(chokidar@3.6.0) - '@angular-eslint/builder': 19.8.0(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/eslint-plugin': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/eslint-plugin-template': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/schematics': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(chokidar@3.6.0)(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@angular-eslint/template-parser': 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@angular-devkit/core': 19.0.2 + '@angular-devkit/schematics': 19.0.2 + '@angular-eslint/builder': 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/eslint-plugin': 19.8.0(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/eslint-plugin-template': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/schematics': 19.8.0(@angular-eslint/template-parser@19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(@typescript-eslint/types@8.15.0)(@typescript-eslint/utils@8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@angular-eslint/template-parser': 19.8.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/utils': 8.15.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 - typescript-eslint: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + typescript: 5.8.3 + typescript-eslint: 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) transitivePeerDependencies: - chokidar - supports-color @@ -9844,8 +10564,8 @@ snapshots: autoprefixer@10.4.19(postcss@8.4.38): dependencies: - browserslist: 4.23.3 - caniuse-lite: 1.0.30001653 + browserslist: 4.25.0 + caniuse-lite: 1.0.30001723 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -9858,13 +10578,13 @@ snapshots: axobject-query@4.1.0: {} - babel-jest@29.7.0(@babel/core@7.25.2): + babel-jest@29.7.0(@babel/core@7.26.10): dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.25.2) + babel-preset-jest: 29.6.3(@babel/core@7.26.10) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -9890,14 +10610,14 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: - '@babel/template': 7.25.0 - '@babel/types': 7.25.6 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.1 babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.5): dependencies: - '@babel/compat-data': 7.25.4 + '@babel/compat-data': 7.27.5 '@babel/core': 7.24.5 '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) semver: 6.3.1 @@ -9919,27 +10639,27 @@ snapshots: transitivePeerDependencies: - supports-color - babel-preset-current-node-syntax@1.0.1(@babel/core@7.25.2): - dependencies: - '@babel/core': 7.25.2 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2) - - babel-preset-jest@29.6.3(@babel/core@7.25.2): - dependencies: - '@babel/core': 7.25.2 + babel-preset-current-node-syntax@1.0.1(@babel/core@7.26.10): + dependencies: + '@babel/core': 7.26.10 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.10) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.10) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.10) + + babel-preset-jest@29.6.3(@babel/core@7.26.10): + dependencies: + '@babel/core': 7.26.10 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.25.2) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.10) balanced-match@1.0.2: {} @@ -9947,6 +10667,17 @@ snapshots: batch@0.6.1: {} + beasties@0.3.4: + dependencies: + css-select: 5.1.0 + css-what: 6.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + htmlparser2: 10.0.0 + picocolors: 1.1.1 + postcss: 8.5.5 + postcss-media-query-parser: 0.2.3 + bezier-js@6.1.4: {} big.js@5.2.2: {} @@ -9996,12 +10727,16 @@ snapshots: dependencies: fill-range: 7.0.1 - browserslist@4.23.3: + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.0: dependencies: - caniuse-lite: 1.0.30001653 - electron-to-chromium: 1.5.13 - node-releases: 2.0.18 - update-browserslist-db: 1.1.0(browserslist@4.23.3) + caniuse-lite: 1.0.30001723 + electron-to-chromium: 1.5.167 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.0) bs-logger@0.2.6: dependencies: @@ -10018,10 +10753,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - builtins@5.0.1: - dependencies: - semver: 7.7.2 - bumpp@9.11.1: dependencies: c12: 2.0.4 @@ -10063,9 +10794,9 @@ snapshots: cac@6.7.14: {} - cacache@18.0.3: + cacache@19.0.1: dependencies: - '@npmcli/fs': 3.1.0 + '@npmcli/fs': 4.0.0 fs-minipass: 3.0.2 glob: 10.4.1 lru-cache: 10.2.2 @@ -10073,10 +10804,10 @@ snapshots: minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - p-map: 4.0.0 - ssri: 10.0.4 - tar: 6.2.1 - unique-filename: 3.0.0 + p-map: 7.0.3 + ssri: 12.0.0 + tar: 7.4.3 + unique-filename: 4.0.0 call-bind@1.0.7: dependencies: @@ -10092,7 +10823,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001653: {} + caniuse-lite@1.0.30001723: {} canvas-color-tracker@1.3.2: dependencies: @@ -10118,7 +10849,7 @@ snapshots: chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -10133,6 +10864,8 @@ snapshots: chownr@2.0.0: {} + chownr@3.0.0: {} + chrome-trace-event@1.0.3: {} ci-info@3.8.0: {} @@ -10143,8 +10876,6 @@ snapshots: cjs-module-lexer@1.2.3: {} - clean-stack@2.2.0: {} - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -10168,6 +10899,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + clone-deep@4.0.1: dependencies: is-plain-object: 2.0.4 @@ -10248,7 +10985,7 @@ snapshots: copy-webpack-plugin@11.0.0(webpack@5.91.0(esbuild@0.21.3)): dependencies: - fast-glob: 3.3.2 + fast-glob: 3.3.3 glob-parent: 6.0.2 globby: 13.2.0 normalize-path: 3.0.0 @@ -10258,26 +10995,26 @@ snapshots: core-js-compat@3.37.1: dependencies: - browserslist: 4.23.3 + browserslist: 4.25.0 core-util-is@1.0.3: {} - cosmiconfig@9.0.0(typescript@5.4.5): + cosmiconfig@9.0.0(typescript@5.8.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.8.3 - create-jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -10295,17 +11032,7 @@ snapshots: dom-serializer: 2.0.0 domhandler: 5.0.3 htmlparser2: 8.0.2 - postcss: 8.4.49 - postcss-media-query-parser: 0.2.3 - - critters@0.0.24: - dependencies: - chalk: 4.1.2 - css-select: 5.1.0 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - htmlparser2: 8.0.2 - postcss: 8.4.49 + postcss: 8.5.5 postcss-media-query-parser: 0.2.3 cross-spawn@7.0.6: @@ -10316,12 +11043,12 @@ snapshots: css-loader@7.1.1(webpack@5.91.0(esbuild@0.21.3)): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) - postcss-modules-local-by-default: 4.0.5(postcss@8.4.49) - postcss-modules-scope: 3.2.0(postcss@8.4.49) - postcss-modules-values: 4.0.0(postcss@8.4.49) + icss-utils: 5.1.0(postcss@8.5.5) + postcss: 8.5.5 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.5) + postcss-modules-local-by-default: 4.0.5(postcss@8.5.5) + postcss-modules-scope: 3.2.0(postcss@8.5.5) + postcss-modules-values: 4.0.0(postcss@8.5.5) postcss-value-parser: 4.2.0 semver: 7.7.2 optionalDependencies: @@ -10332,7 +11059,7 @@ snapshots: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 css-what@6.1.0: {} @@ -10606,6 +11333,9 @@ snapshots: destroy@1.2.0: {} + detect-libc@1.0.3: + optional: true + detect-libc@2.0.3: {} detect-newline@3.1.0: {} @@ -10644,7 +11374,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - domutils@3.1.0: + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 @@ -10660,7 +11390,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.13: {} + electron-to-chromium@1.5.167: {} emittery@0.13.1: {} @@ -10686,6 +11416,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + env-paths@2.2.1: {} environment@1.1.0: {} @@ -10832,32 +11564,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.3 '@esbuild/win32-x64': 0.21.3 - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.0: optionalDependencies: '@esbuild/aix-ppc64': 0.23.0 @@ -10884,6 +11590,35 @@ snapshots: '@esbuild/win32-arm64': 0.23.0 '@esbuild/win32-ia32': 0.23.0 '@esbuild/win32-x64': 0.23.0 + optional: true + + esbuild@0.25.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.5 + '@esbuild/android-arm': 0.25.5 + '@esbuild/android-arm64': 0.25.5 + '@esbuild/android-x64': 0.25.5 + '@esbuild/darwin-arm64': 0.25.5 + '@esbuild/darwin-x64': 0.25.5 + '@esbuild/freebsd-arm64': 0.25.5 + '@esbuild/freebsd-x64': 0.25.5 + '@esbuild/linux-arm': 0.25.5 + '@esbuild/linux-arm64': 0.25.5 + '@esbuild/linux-ia32': 0.25.5 + '@esbuild/linux-loong64': 0.25.5 + '@esbuild/linux-mips64el': 0.25.5 + '@esbuild/linux-ppc64': 0.25.5 + '@esbuild/linux-riscv64': 0.25.5 + '@esbuild/linux-s390x': 0.25.5 + '@esbuild/linux-x64': 0.25.5 + '@esbuild/netbsd-arm64': 0.25.5 + '@esbuild/netbsd-x64': 0.25.5 + '@esbuild/openbsd-arm64': 0.25.5 + '@esbuild/openbsd-x64': 0.25.5 + '@esbuild/sunos-x64': 0.25.5 + '@esbuild/win32-arm64': 0.25.5 + '@esbuild/win32-ia32': 0.25.5 + '@esbuild/win32-x64': 0.25.5 escalade@3.2.0: {} @@ -10922,22 +11657,22 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.9.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.28.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -10948,7 +11683,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.28.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.28.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -10960,7 +11695,7 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -11133,6 +11868,14 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.5 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -11171,6 +11914,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + finalhandler@1.2.0: dependencies: debug: 2.6.9 @@ -11337,7 +12084,7 @@ snapshots: dependencies: foreground-child: 3.1.1 jackspeak: 3.1.2 - minimatch: 9.0.4 + minimatch: 9.0.5 minipass: 7.1.2 path-scurry: 1.11.1 @@ -11361,7 +12108,7 @@ snapshots: globby@13.2.0: dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 @@ -11402,7 +12149,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hosted-git-info@7.0.2: + hosted-git-info@8.1.0: dependencies: lru-cache: 10.2.2 @@ -11421,11 +12168,18 @@ snapshots: html-escaper@2.0.2: {} + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 entities: 4.5.0 http-cache-semantics@4.1.1: {} @@ -11459,7 +12213,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -11470,7 +12224,7 @@ snapshots: http-proxy: 1.18.1(debug@4.4.1) is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.5 + micromatch: 4.0.8 optionalDependencies: '@types/express': 4.17.21 transitivePeerDependencies: @@ -11483,7 +12237,7 @@ snapshots: http-proxy: 1.18.1(debug@4.4.1) is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.5 + micromatch: 4.0.8 transitivePeerDependencies: - supports-color @@ -11504,14 +12258,14 @@ snapshots: https-proxy-agent@7.0.4: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.1 transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.5: + https-proxy-agent@7.0.6: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -11528,15 +12282,15 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.4.49): + icss-utils@5.1.0(postcss@8.5.5): dependencies: - postcss: 8.4.49 + postcss: 8.5.5 ieee754@1.2.1: {} - ignore-walk@6.0.5: + ignore-walk@7.0.0: dependencies: - minimatch: 9.0.4 + minimatch: 9.0.5 ignore@5.3.2: {} @@ -11547,6 +12301,8 @@ snapshots: immutable@4.3.0: {} + immutable@5.1.3: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -11559,8 +12315,6 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - index-array-by@1.4.2: {} inflight@1.0.6: @@ -11572,11 +12326,11 @@ snapshots: inherits@2.0.4: {} - ini@4.1.3: {} + ini@5.0.0: {} inquirer@9.2.22: dependencies: - '@inquirer/figures': 1.0.5 + '@inquirer/figures': 1.0.12 '@ljharb/through': 2.3.13 ansi-escapes: 4.3.2 chalk: 5.3.0 @@ -11636,6 +12390,10 @@ snapshots: dependencies: hasown: 2.0.2 + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-data-view@1.0.1: dependencies: is-typed-array: 1.1.13 @@ -11670,7 +12428,7 @@ snapshots: is-interactive@1.0.0: {} - is-lambda@1.0.1: {} + is-interactive@2.0.0: {} is-negative-zero@2.0.3: {} @@ -11715,6 +12473,10 @@ snapshots: is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-weakref@1.0.2: dependencies: call-bind: 1.0.7 @@ -11743,18 +12505,18 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.25.2 - '@babel/parser': 7.25.6 + '@babel/core': 7.26.10 + '@babel/parser': 7.27.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - istanbul-lib-instrument@6.0.0: + istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.25.2 - '@babel/parser': 7.25.6 + '@babel/core': 7.27.1 + '@babel/parser': 7.27.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 7.7.2 @@ -11825,16 +12587,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -11844,12 +12606,12 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)): dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.25.2) + babel-jest: 29.7.0(@babel/core@7.26.10) chalk: 4.1.2 ci-info: 3.8.0 deepmerge: 4.3.1 @@ -11870,7 +12632,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.15.31 - ts-node: 10.9.2(@types/node@22.15.31)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@22.15.31)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -11977,19 +12739,19 @@ snapshots: optionalDependencies: jest-resolve: 29.7.0 - jest-preset-angular@14.6.0(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser-dynamic@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(jsdom@20.0.3)(typescript@5.4.5): + jest-preset-angular@14.6.0(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser-dynamic@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))))(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3): dependencies: - '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5) - '@angular/core': 18.2.13(rxjs@7.8.2)(zone.js@0.14.4) - '@angular/platform-browser-dynamic': 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))(rxjs@7.8.2))(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))) + '@angular/compiler-cli': 20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3) + '@angular/core': 20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2) + '@angular/platform-browser-dynamic': 20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@20.0.3)(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(@angular/platform-browser@20.0.3(@angular/animations@20.0.3(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2)))(@angular/common@20.0.3(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@20.0.3(@angular/compiler@20.0.3)(rxjs@7.8.2))) bs-logger: 0.2.6 esbuild-wasm: 0.21.3 - jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) jest-environment-jsdom: 29.7.0 jest-util: 29.7.0 pretty-format: 29.7.0 - ts-jest: 29.4.0(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5) - typescript: 5.4.5 + ts-jest: 29.4.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3) + typescript: 5.8.3 optionalDependencies: esbuild: 0.23.0 jsdom: 20.0.3 @@ -12020,7 +12782,7 @@ snapshots: jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) jest-util: 29.7.0 jest-validate: 29.7.0 - resolve: 1.22.8 + resolve: 1.22.10 resolve.exports: 2.0.2 slash: 3.0.0 @@ -12079,15 +12841,15 @@ snapshots: jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/generator': 7.25.6 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.25.2) - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.25.2) + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.26.10) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.26.10) '@babel/types': 7.25.6 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.25.2) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.10) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -12144,12 +12906,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)): + jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -12208,11 +12970,13 @@ snapshots: jsesc@2.5.2: {} + jsesc@3.1.0: {} + json-buffer@3.0.1: {} json-parse-even-better-errors@2.3.1: {} - json-parse-even-better-errors@3.0.0: {} + json-parse-even-better-errors@4.0.0: {} json-schema-traverse@0.4.1: {} @@ -12290,7 +13054,7 @@ snapshots: lines-and-columns@1.2.4: {} - listr2@8.2.4: + listr2@8.3.3: dependencies: cli-truncate: 4.0.0 colorette: 2.0.20 @@ -12299,27 +13063,12 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.0 - lmdb@3.0.13: - dependencies: - msgpackr: 1.10.2 - node-addon-api: 6.1.0 - node-gyp-build-optional-packages: 5.2.2 - ordered-binary: 1.5.1 - weak-lru-cache: 1.2.2 - optionalDependencies: - '@lmdb/lmdb-darwin-arm64': 3.0.13 - '@lmdb/lmdb-darwin-x64': 3.0.13 - '@lmdb/lmdb-linux-arm': 3.0.13 - '@lmdb/lmdb-linux-arm64': 3.0.13 - '@lmdb/lmdb-linux-x64': 3.0.13 - '@lmdb/lmdb-win32-x64': 3.0.13 - lmdb@3.0.8: dependencies: - msgpackr: 1.10.2 + msgpackr: 1.11.4 node-addon-api: 6.1.0 node-gyp-build-optional-packages: 5.1.1 - ordered-binary: 1.5.1 + ordered-binary: 1.5.3 weak-lru-cache: 1.2.2 optionalDependencies: '@lmdb/lmdb-darwin-arm64': 3.0.8 @@ -12329,6 +13078,23 @@ snapshots: '@lmdb/lmdb-linux-x64': 3.0.8 '@lmdb/lmdb-win32-x64': 3.0.8 + lmdb@3.3.0: + dependencies: + msgpackr: 1.11.4 + node-addon-api: 6.1.0 + node-gyp-build-optional-packages: 5.2.2 + ordered-binary: 1.5.3 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 3.3.0 + '@lmdb/lmdb-darwin-x64': 3.3.0 + '@lmdb/lmdb-linux-arm': 3.3.0 + '@lmdb/lmdb-linux-arm64': 3.3.0 + '@lmdb/lmdb-linux-x64': 3.3.0 + '@lmdb/lmdb-win32-arm64': 3.3.0 + '@lmdb/lmdb-win32-x64': 3.3.0 + optional: true + loader-runner@4.3.0: {} loader-utils@2.0.4: @@ -12366,6 +13132,11 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-symbols@6.0.0: + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + log-update@6.1.0: dependencies: ansi-escapes: 7.0.0 @@ -12394,6 +13165,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -12406,20 +13181,19 @@ snapshots: make-error@1.3.6: {} - make-fetch-happen@13.0.1: + make-fetch-happen@14.0.3: dependencies: - '@npmcli/agent': 2.2.2 - cacache: 18.0.3 + '@npmcli/agent': 3.0.0 + cacache: 19.0.1 http-cache-semantics: 4.1.1 - is-lambda: 1.0.1 minipass: 7.1.2 - minipass-fetch: 3.0.3 + minipass-fetch: 4.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - negotiator: 0.6.3 - proc-log: 4.2.0 + negotiator: 1.0.0 + proc-log: 5.0.0 promise-retry: 2.0.1 - ssri: 10.0.4 + ssri: 12.0.0 transitivePeerDependencies: - supports-color @@ -12449,6 +13223,11 @@ snapshots: braces: 3.0.2 picomatch: 2.3.1 + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + mime-db@1.52.0: {} mime-types@2.1.35: @@ -12481,17 +13260,21 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + minimist@1.2.8: {} minipass-collect@2.0.1: dependencies: minipass: 7.1.2 - minipass-fetch@3.0.3: + minipass-fetch@4.0.1: dependencies: - minipass: 5.0.0 + minipass: 7.1.2 minipass-sized: 1.0.3 - minizlib: 2.1.2 + minizlib: 3.0.2 optionalDependencies: encoding: 0.1.13 @@ -12499,11 +13282,6 @@ snapshots: dependencies: minipass: 3.3.6 - minipass-json-stream@1.0.1: - dependencies: - jsonparse: 1.3.1 - minipass: 3.3.6 - minipass-pipeline@1.2.4: dependencies: minipass: 3.3.6 @@ -12525,8 +13303,14 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + mkdirp@1.0.4: {} + mkdirp@3.0.1: {} + mlly@1.7.4: dependencies: acorn: 8.14.0 @@ -12534,8 +13318,12 @@ snapshots: pkg-types: 1.3.1 ufo: 1.5.4 + moment@2.30.1: {} + mrmime@2.0.0: {} + mrmime@2.0.1: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -12552,7 +13340,7 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.2 optional: true - msgpackr@1.10.2: + msgpackr@1.11.4: optionalDependencies: msgpackr-extract: 3.0.2 @@ -12563,7 +13351,9 @@ snapshots: mute-stream@1.0.0: {} - nanoid@3.3.7: {} + mute-stream@2.0.0: {} + + nanoid@3.3.11: {} napi-postinstall@0.2.4: {} @@ -12580,15 +13370,17 @@ snapshots: negotiator@0.6.3: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} - ng-extract-i18n-merge@2.15.1(@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5))(chokidar@3.6.0): + ng-extract-i18n-merge@2.15.1(@angular-devkit/build-angular@18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3)): dependencies: - '@angular-devkit/architect': 0.1900.2(chokidar@3.6.0) - '@angular-devkit/build-angular': 18.0.2(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/localize@18.2.13(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.2)(zone.js@0.14.4))))(@types/node@22.15.31)(chokidar@3.6.0)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5) - '@angular-devkit/core': 19.0.2(chokidar@3.6.0) - '@angular-devkit/schematics': 19.0.2(chokidar@3.6.0) - '@schematics/angular': 18.2.12(chokidar@3.6.0) + '@angular-devkit/architect': 0.1900.2 + '@angular-devkit/build-angular': 18.0.2(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/localize@20.0.3(@angular/compiler-cli@20.0.3(@angular/compiler@20.0.3)(typescript@5.8.3))(@angular/compiler@20.0.3))(@types/node@22.15.31)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3) + '@angular-devkit/core': 19.0.2 + '@angular-devkit/schematics': 19.0.2 + '@schematics/angular': 18.2.12 xmldoc: 1.1.4 transitivePeerDependencies: - chokidar @@ -12604,6 +13396,9 @@ snapshots: node-addon-api@6.1.0: {} + node-addon-api@7.1.1: + optional: true + node-fetch-native@1.6.6: {} node-forge@1.3.1: {} @@ -12618,82 +13413,76 @@ snapshots: node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.0.3 + optional: true node-gyp-build@4.6.0: optional: true - node-gyp@10.1.0: + node-gyp@11.2.0: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.1 - glob: 10.4.1 graceful-fs: 4.2.11 - make-fetch-happen: 13.0.1 - nopt: 7.2.1 - proc-log: 3.0.0 + make-fetch-happen: 14.0.3 + nopt: 8.1.0 + proc-log: 5.0.0 semver: 7.7.2 - tar: 6.2.1 - which: 4.0.0 + tar: 7.4.3 + tinyglobby: 0.2.14 + which: 5.0.0 transitivePeerDependencies: - supports-color node-int64@0.4.0: {} - node-releases@2.0.18: {} + node-releases@2.0.19: {} - nopt@7.2.1: + nopt@8.1.0: dependencies: - abbrev: 2.0.0 - - normalize-package-data@6.0.1: - dependencies: - hosted-git-info: 7.0.2 - is-core-module: 2.15.1 - semver: 7.7.2 - validate-npm-package-license: 3.0.4 + abbrev: 3.0.1 normalize-path@3.0.0: {} normalize-range@0.1.2: {} - npm-bundled@3.0.0: + npm-bundled@4.0.0: dependencies: - npm-normalize-package-bin: 3.0.1 + npm-normalize-package-bin: 4.0.0 - npm-install-checks@6.1.1: + npm-install-checks@7.1.1: dependencies: semver: 7.7.2 - npm-normalize-package-bin@3.0.1: {} + npm-normalize-package-bin@4.0.0: {} - npm-package-arg@11.0.3: + npm-package-arg@12.0.2: dependencies: - hosted-git-info: 7.0.2 - proc-log: 4.2.0 + hosted-git-info: 8.1.0 + proc-log: 5.0.0 semver: 7.7.2 - validate-npm-package-name: 5.0.0 + validate-npm-package-name: 6.0.1 - npm-packlist@8.0.2: + npm-packlist@10.0.0: dependencies: - ignore-walk: 6.0.5 + ignore-walk: 7.0.0 - npm-pick-manifest@9.1.0: + npm-pick-manifest@10.0.0: dependencies: - npm-install-checks: 6.1.1 - npm-normalize-package-bin: 3.0.1 - npm-package-arg: 11.0.3 + npm-install-checks: 7.1.1 + npm-normalize-package-bin: 4.0.0 + npm-package-arg: 12.0.2 semver: 7.7.2 - npm-registry-fetch@17.0.1: + npm-registry-fetch@18.0.2: dependencies: - '@npmcli/redact': 2.0.0 - make-fetch-happen: 13.0.1 + '@npmcli/redact': 3.2.2 + jsonparse: 1.3.1 + make-fetch-happen: 14.0.3 minipass: 7.1.2 - minipass-fetch: 3.0.3 - minipass-json-stream: 1.0.1 - minizlib: 2.1.2 - npm-package-arg: 11.0.3 - proc-log: 4.2.0 + minipass-fetch: 4.0.1 + minizlib: 3.0.2 + npm-package-arg: 12.0.2 + proc-log: 5.0.0 transitivePeerDependencies: - supports-color @@ -12802,7 +13591,19 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - ordered-binary@1.5.1: {} + ora@8.2.0: + dependencies: + chalk: 5.3.0 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + ordered-binary@1.5.3: {} os-tmpdir@1.0.2: {} @@ -12830,9 +13631,7 @@ snapshots: dependencies: p-limit: 4.0.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 + p-map@7.0.3: {} p-retry@6.2.0: dependencies: @@ -12846,27 +13645,26 @@ snapshots: dependencies: quansync: 0.2.10 - pacote@18.0.6: + pacote@21.0.0: dependencies: - '@npmcli/git': 5.0.7 - '@npmcli/installed-package-contents': 2.0.2 - '@npmcli/package-json': 5.1.1 - '@npmcli/promise-spawn': 7.0.2 - '@npmcli/run-script': 8.1.0 - cacache: 18.0.3 + '@npmcli/git': 6.0.3 + '@npmcli/installed-package-contents': 3.0.0 + '@npmcli/package-json': 6.2.0 + '@npmcli/promise-spawn': 8.0.2 + '@npmcli/run-script': 9.1.0 + cacache: 19.0.1 fs-minipass: 3.0.2 minipass: 7.1.2 - npm-package-arg: 11.0.3 - npm-packlist: 8.0.2 - npm-pick-manifest: 9.1.0 - npm-registry-fetch: 17.0.1 - proc-log: 4.2.0 + npm-package-arg: 12.0.2 + npm-packlist: 10.0.0 + npm-pick-manifest: 10.0.0 + npm-registry-fetch: 18.0.2 + proc-log: 5.0.0 promise-retry: 2.0.1 - sigstore: 2.3.1 - ssri: 10.0.4 + sigstore: 3.1.0 + ssri: 12.0.0 tar: 6.2.1 transitivePeerDependencies: - - bluebird - supports-color parent-module@1.0.1: @@ -12888,6 +13686,12 @@ snapshots: parse5: 7.1.2 parse5-sax-parser: 7.0.0 + parse5-html-rewriting-stream@7.1.0: + dependencies: + entities: 6.0.1 + parse5: 7.1.2 + parse5-sax-parser: 7.0.0 + parse5-sax-parser@7.0.0: dependencies: parse5: 7.1.2 @@ -12936,9 +13740,9 @@ snapshots: optionalDependencies: nice-napi: 1.0.2 - piscina@4.6.1: + piscina@5.0.0: optionalDependencies: - nice-napi: 1.0.2 + '@napi-rs/nice': 1.0.1 pkg-dir@4.2.0: dependencies: @@ -12956,9 +13760,9 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.91.0(esbuild@0.21.3)): + postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.8.3)(webpack@5.91.0(esbuild@0.21.3)): dependencies: - cosmiconfig: 9.0.0(typescript@5.4.5) + cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 1.21.6 postcss: 8.4.38 semver: 7.7.2 @@ -12969,26 +13773,26 @@ snapshots: postcss-media-query-parser@0.2.3: {} - postcss-modules-extract-imports@3.1.0(postcss@8.4.49): + postcss-modules-extract-imports@3.1.0(postcss@8.5.5): dependencies: - postcss: 8.4.49 + postcss: 8.5.5 - postcss-modules-local-by-default@4.0.5(postcss@8.4.49): + postcss-modules-local-by-default@4.0.5(postcss@8.5.5): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 + icss-utils: 5.1.0(postcss@8.5.5) + postcss: 8.5.5 postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.0(postcss@8.4.49): + postcss-modules-scope@3.2.0(postcss@8.5.5): dependencies: - postcss: 8.4.49 + postcss: 8.5.5 postcss-selector-parser: 6.0.13 - postcss-modules-values@4.0.0(postcss@8.4.49): + postcss-modules-values@4.0.0(postcss@8.5.5): dependencies: - icss-utils: 5.1.0(postcss@8.4.49) - postcss: 8.4.49 + icss-utils: 5.1.0(postcss@8.5.5) + postcss: 8.5.5 postcss-selector-parser@6.0.13: dependencies: @@ -12999,13 +13803,13 @@ snapshots: postcss@8.4.38: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.4.49: + postcss@8.5.5: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -13019,14 +13823,10 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.2.0 - proc-log@3.0.0: {} - - proc-log@4.2.0: {} + proc-log@5.0.0: {} process-nextick-args@2.0.1: {} - promise-inflight@1.0.1: {} - promise-retry@2.0.1: dependencies: err-code: 2.0.3 @@ -13160,14 +13960,20 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.4.49 + postcss: 8.5.5 source-map: 0.6.1 resolve.exports@2.0.2: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: dependencies: - is-core-module: 2.15.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -13195,26 +14001,30 @@ snapshots: robust-predicates@3.0.2: {} - rollup@4.22.4: + rollup@4.40.2: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.22.4 - '@rollup/rollup-android-arm64': 4.22.4 - '@rollup/rollup-darwin-arm64': 4.22.4 - '@rollup/rollup-darwin-x64': 4.22.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.22.4 - '@rollup/rollup-linux-arm-musleabihf': 4.22.4 - '@rollup/rollup-linux-arm64-gnu': 4.22.4 - '@rollup/rollup-linux-arm64-musl': 4.22.4 - '@rollup/rollup-linux-powerpc64le-gnu': 4.22.4 - '@rollup/rollup-linux-riscv64-gnu': 4.22.4 - '@rollup/rollup-linux-s390x-gnu': 4.22.4 - '@rollup/rollup-linux-x64-gnu': 4.22.4 - '@rollup/rollup-linux-x64-musl': 4.22.4 - '@rollup/rollup-win32-arm64-msvc': 4.22.4 - '@rollup/rollup-win32-ia32-msvc': 4.22.4 - '@rollup/rollup-win32-x64-msvc': 4.22.4 + '@rollup/rollup-android-arm-eabi': 4.40.2 + '@rollup/rollup-android-arm64': 4.40.2 + '@rollup/rollup-darwin-arm64': 4.40.2 + '@rollup/rollup-darwin-x64': 4.40.2 + '@rollup/rollup-freebsd-arm64': 4.40.2 + '@rollup/rollup-freebsd-x64': 4.40.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.2 + '@rollup/rollup-linux-arm-musleabihf': 4.40.2 + '@rollup/rollup-linux-arm64-gnu': 4.40.2 + '@rollup/rollup-linux-arm64-musl': 4.40.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-musl': 4.40.2 + '@rollup/rollup-linux-s390x-gnu': 4.40.2 + '@rollup/rollup-linux-x64-gnu': 4.40.2 + '@rollup/rollup-linux-x64-musl': 4.40.2 + '@rollup/rollup-win32-arm64-msvc': 4.40.2 + '@rollup/rollup-win32-ia32-msvc': 4.40.2 + '@rollup/rollup-win32-x64-msvc': 4.40.2 fsevents: 2.3.3 run-applescript@7.0.0: {} @@ -13267,11 +14077,13 @@ snapshots: immutable: 4.3.0 source-map-js: 1.2.1 - sass@1.77.6: + sass@1.88.0: dependencies: - chokidar: 3.6.0 - immutable: 4.3.0 + chokidar: 4.0.3 + immutable: 5.1.3 source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 sax@1.2.4: {} @@ -13395,14 +14207,14 @@ snapshots: signal-exit@4.1.0: {} - sigstore@2.3.1: + sigstore@3.1.0: dependencies: - '@sigstore/bundle': 2.3.2 - '@sigstore/core': 1.1.0 - '@sigstore/protobuf-specs': 0.3.2 - '@sigstore/sign': 2.3.2 - '@sigstore/tuf': 2.3.4 - '@sigstore/verify': 1.2.1 + '@sigstore/bundle': 3.1.0 + '@sigstore/core': 2.0.0 + '@sigstore/protobuf-specs': 0.4.3 + '@sigstore/sign': 3.1.0 + '@sigstore/tuf': 3.1.1 + '@sigstore/verify': 2.1.1 transitivePeerDependencies: - supports-color @@ -13432,7 +14244,7 @@ snapshots: socks-proxy-agent@8.0.3: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.1 socks: 2.7.1 transitivePeerDependencies: @@ -13507,9 +14319,9 @@ snapshots: sprintf-js@1.0.3: {} - ssri@10.0.4: + ssri@12.0.0: dependencies: - minipass: 5.0.0 + minipass: 7.1.2 stable-hash@0.0.5: {} @@ -13521,6 +14333,8 @@ snapshots: statuses@2.0.1: {} + stdin-discarder@0.2.2: {} + string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -13601,8 +14415,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - symbol-observable@4.0.0: {} - symbol-tree@3.2.4: {} tapable@2.2.1: {} @@ -13616,6 +14428,15 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + terser-webpack-plugin@5.3.10(esbuild@0.21.3)(webpack@5.91.0(esbuild@0.21.3)): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -13657,6 +14478,11 @@ snapshots: fdir: 6.4.2(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 + tinyglobby@0.2.14: dependencies: fdir: 6.4.6(picomatch@4.0.2) @@ -13693,36 +14519,36 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.8.3): dependencies: - typescript: 5.4.5 + typescript: 5.8.3 - ts-api-utils@2.1.0(typescript@5.4.5): + ts-api-utils@2.1.0(typescript@5.8.3): dependencies: - typescript: 5.4.5 + typescript: 5.8.3 - ts-jest@29.4.0(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)))(typescript@5.4.5): + ts-jest@29.4.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.23.0)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5)) + jest: 29.7.0(@types/node@22.15.31)(ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.7.2 type-fest: 4.41.0 - typescript: 5.4.5 + typescript: 5.8.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.25.2) + babel-jest: 29.7.0(@babel/core@7.26.10) esbuild: 0.23.0 jest-util: 29.7.0 - ts-node@10.9.2(@types/node@22.15.31)(typescript@5.4.5): + ts-node@10.9.2(@types/node@22.15.31)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 @@ -13736,7 +14562,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.4.5 + typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -13751,11 +14577,11 @@ snapshots: tslib@2.8.1: {} - tuf-js@2.2.1: + tuf-js@3.0.1: dependencies: - '@tufjs/models': 2.0.1 + '@tufjs/models': 3.0.1 debug: 4.4.1 - make-fetch-happen: 13.0.1 + make-fetch-happen: 14.0.3 transitivePeerDependencies: - supports-color @@ -13808,17 +14634,17 @@ snapshots: typed-assert@1.0.9: {} - typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5): + typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5))(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) - '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3) eslint: 9.28.0(jiti@2.4.2) - typescript: 5.4.5 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - typescript@5.4.5: {} + typescript@5.8.3: {} ufo@1.5.4: {} @@ -13844,11 +14670,11 @@ snapshots: unicode-property-aliases-ecmascript@2.1.0: {} - unique-filename@3.0.0: + unique-filename@4.0.0: dependencies: - unique-slug: 4.0.0 + unique-slug: 5.0.0 - unique-slug@4.0.0: + unique-slug@5.0.0: dependencies: imurmurhash: 0.1.4 @@ -13880,9 +14706,9 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.9.0 '@unrs/resolver-binding-win32-x64-msvc': 1.9.0 - update-browserslist-db@1.1.0(browserslist@4.23.3): + update-browserslist-db@1.1.3(browserslist@4.25.0): dependencies: - browserslist: 4.23.3 + browserslist: 4.25.0 escalade: 3.2.0 picocolors: 1.1.1 @@ -13914,17 +14740,15 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - validate-npm-package-name@5.0.0: - dependencies: - builtins: 5.0.1 + validate-npm-package-name@6.0.1: {} vary@1.1.2: {} vite@5.2.11(@types/node@22.15.31)(less@4.2.0)(sass@1.77.2)(terser@5.31.0): dependencies: esbuild: 0.20.1 - postcss: 8.4.49 - rollup: 4.22.4 + postcss: 8.5.5 + rollup: 4.40.2 optionalDependencies: '@types/node': 22.15.31 fsevents: 2.3.3 @@ -13932,16 +14756,20 @@ snapshots: sass: 1.77.2 terser: 5.31.0 - vite@5.4.19(@types/node@22.15.31)(less@4.2.0)(sass@1.77.6)(terser@5.31.0): + vite@6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.2.0)(sass@1.88.0)(terser@5.31.0): dependencies: - esbuild: 0.21.5 - postcss: 8.4.49 - rollup: 4.22.4 + esbuild: 0.25.5 + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.5 + rollup: 4.40.2 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 22.15.31 fsevents: 2.3.3 + jiti: 2.4.2 less: 4.2.0 - sass: 1.77.6 + sass: 1.88.0 terser: 5.31.0 w3c-xmlserializer@4.0.0: @@ -13957,6 +14785,11 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + watchpack@2.4.2: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wbuf@1.7.3: dependencies: minimalistic-assert: 1.0.1 @@ -14036,13 +14869,13 @@ snapshots: webpack@5.91.0(esbuild@0.21.3): dependencies: '@types/eslint-scope': 3.7.4 - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.14.0 acorn-import-assertions: 1.9.0(acorn@8.14.0) - browserslist: 4.23.3 + browserslist: 4.25.0 chrome-trace-event: 1.0.3 enhanced-resolve: 5.16.1 es-module-lexer: 1.3.0 @@ -14057,7 +14890,7 @@ snapshots: schema-utils: 3.3.0 tapable: 2.2.1 terser-webpack-plugin: 5.3.10(esbuild@0.21.3)(webpack@5.91.0(esbuild@0.21.3)) - watchpack: 2.4.1 + watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' @@ -14103,7 +14936,7 @@ snapshots: dependencies: isexe: 2.0.0 - which@4.0.0: + which@5.0.0: dependencies: isexe: 3.1.1 @@ -14160,8 +14993,12 @@ snapshots: yallist@4.0.0: {} + yallist@5.0.0: {} + yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -14172,6 +15009,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -14179,7 +15025,3 @@ snapshots: yocto-queue@1.0.0: {} yoctocolors-cjs@2.1.2: {} - - zone.js@0.14.4: - dependencies: - tslib: 2.8.1 diff --git a/setup-jest.ts b/setup-jest.ts index eb8c17423..2faee1da4 100644 --- a/setup-jest.ts +++ b/setup-jest.ts @@ -1,6 +1,6 @@ -import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; +import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless'; import '@angular/localize/init'; import { TextEncoder } from 'util'; -setupZoneTestEnv(); +setupZonelessTestEnv(); global.TextEncoder = TextEncoder; \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 8f3376329..1ccf1931a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -12,8 +12,7 @@ import { NavigationComponent } from '@components/navigation/navigation.component - `, - standalone: true + ` }) export class AppComponent { } diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 980b4bf1e..4a2f61e72 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,5 +1,5 @@ import { HttpClient, provideHttpClient } from '@angular/common/http'; -import { APP_INITIALIZER, ApplicationConfig, importProvidersFrom, provideExperimentalZonelessChangeDetection } from '@angular/core'; +import { ApplicationConfig, importProvidersFrom, inject, provideAppInitializer, provideZonelessChangeDetection } from '@angular/core'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { provideRouter } from '@angular/router'; import { GrpcCoreModule } from '@ngx-grpc/core'; @@ -17,6 +17,7 @@ import { VersionsGrpcService } from '@services/versions-grpc.service'; import { VersionsService } from '@services/versions.service'; import { catchError, merge, of, tap } from 'rxjs'; import { routes } from './app.routes'; +import { provideArmonikDateAdapter } from './initialisation/date-adapter'; import { ExportedDefaultConfig } from './types/config'; function initializeAppFactory(userGrpcService: UserGrpcService, userService: UserService, versionsGrpcService: VersionsGrpcService, versionsService: VersionsService, httpClient: HttpClient, environmentService: EnvironmentService, storageService: StorageService) { @@ -96,13 +97,12 @@ export const appConfig: ApplicationConfig = { provide: Storage, useValue: localStorage }, - { - provide: APP_INITIALIZER, - useFactory: initializeAppFactory, - deps: [UserGrpcService, UserService, VersionsGrpcService, VersionsService, HttpClient, EnvironmentService, StorageService], - multi: true - }, - provideExperimentalZonelessChangeDetection(), + provideAppInitializer(() => { + const initializerFn = (initializeAppFactory)(inject(UserGrpcService), inject(UserService), inject(VersionsGrpcService), inject(VersionsService), inject(HttpClient), inject(EnvironmentService), inject(StorageService)); + return initializerFn(); + }), + provideArmonikDateAdapter(), + provideZonelessChangeDetection(), provideRouter(routes), importProvidersFrom(BrowserAnimationsModule), provideHttpClient(), diff --git a/src/app/applications/components/table.component.ts b/src/app/applications/components/table.component.ts index 10b36cb9b..b4d31425b 100644 --- a/src/app/applications/components/table.component.ts +++ b/src/app/applications/components/table.component.ts @@ -15,7 +15,6 @@ import { ApplicationRaw } from '../types'; @Component({ selector: 'app-application-table', - standalone: true, templateUrl: './table.component.html', providers: [ TasksByStatusService, diff --git a/src/app/applications/index.component.spec.ts b/src/app/applications/index.component.spec.ts index 7b9ca97e9..22dd85be3 100644 --- a/src/app/applications/index.component.spec.ts +++ b/src/app/applications/index.component.spec.ts @@ -1,6 +1,7 @@ import { ApplicationRawEnumField, FilterStringOperator } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { MatDialog } from '@angular/material/dialog'; +import { Router } from '@angular/router'; import { DashboardIndexService } from '@app/dashboard/services/dashboard-index.service'; import { TableColumn } from '@app/types/column.type'; import { ColumnKey } from '@app/types/data'; @@ -154,6 +155,10 @@ describe('Application component', () => { }, }; + const mockRouter = { + navigate: jest.fn() + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ @@ -176,6 +181,7 @@ describe('Application component', () => { } }, { provide: DashboardIndexService, useValue: mockDashboardIndexService }, + { provide: Router, useValue: mockRouter }, DefaultConfigService, ] }).inject(IndexComponent); diff --git a/src/app/applications/index.component.ts b/src/app/applications/index.component.ts index ca33c66a1..e115bc00d 100644 --- a/src/app/applications/index.component.ts +++ b/src/app/applications/index.component.ts @@ -37,7 +37,6 @@ import { ApplicationRaw } from './types'; @Component({ selector: 'app-applications-index', templateUrl: './index.component.html', - standalone: true, providers: [ IconsService, ShareUrlService, diff --git a/src/app/components/actions-toolbar-group.component.ts b/src/app/components/actions-toolbar-group.component.ts index a5ae3e2e4..748df169c 100644 --- a/src/app/components/actions-toolbar-group.component.ts +++ b/src/app/components/actions-toolbar-group.component.ts @@ -18,7 +18,6 @@ import { Component } from '@angular/core'; margin-left: 1rem; } `], - standalone: true, providers: [], imports: [] }) diff --git a/src/app/components/actions-toolbar.component.ts b/src/app/components/actions-toolbar.component.ts index 84f591826..88d214605 100644 --- a/src/app/components/actions-toolbar.component.ts +++ b/src/app/components/actions-toolbar.component.ts @@ -15,7 +15,6 @@ import { Component } from '@angular/core'; justify-content: space-between; } `], - standalone: true, providers: [], imports: [] }) diff --git a/src/app/components/auto-complete.component.ts b/src/app/components/auto-complete.component.ts index cb5a5fe3f..6fbf635e3 100644 --- a/src/app/components/auto-complete.component.ts +++ b/src/app/components/auto-complete.component.ts @@ -6,7 +6,6 @@ import { MatInputModule } from '@angular/material/input'; @Component({ selector: 'app-autocomplete', - standalone: true, templateUrl: 'auto-complete.component.html', imports: [ MatFormFieldModule, diff --git a/src/app/components/auto-refresh-button.component.ts b/src/app/components/auto-refresh-button.component.ts index 7118ddb60..22c0c2077 100644 --- a/src/app/components/auto-refresh-button.component.ts +++ b/src/app/components/auto-refresh-button.component.ts @@ -7,7 +7,7 @@ import { IconsService } from '@services/icons.service'; @Component({ selector: 'app-auto-refresh-button', - templateUrl:'./auto-refresh-button.component.html', + templateUrl: './auto-refresh-button.component.html', styles: [` .auto-refresh-disabled { border: 0px; @@ -15,9 +15,7 @@ import { IconsService } from '@services/icons.service'; background-color: #D7D7D7; } `], - standalone: true, imports: [ - AutoRefreshButtonComponent, MatDialogModule, MatButtonModule, MatIconModule, diff --git a/src/app/components/auto-refresh-dialog.component.ts b/src/app/components/auto-refresh-dialog.component.ts index 20bd3004e..780525221 100644 --- a/src/app/components/auto-refresh-dialog.component.ts +++ b/src/app/components/auto-refresh-dialog.component.ts @@ -8,7 +8,6 @@ import { AutoCompleteComponent } from './auto-complete.component'; selector: 'app-auto-refresh-dialog', templateUrl: './auto-refresh-dialog.component.html', styles: [''], - standalone: true, imports: [ MatDialogModule, MatButtonModule, diff --git a/src/app/components/columns-button.component.ts b/src/app/components/columns-button.component.ts index 62f1c13ed..72f16c153 100644 --- a/src/app/components/columns-button.component.ts +++ b/src/app/components/columns-button.component.ts @@ -18,9 +18,7 @@ import { ColumnsModifyDialogComponent } from './columns-modify-dialog.component' `, styles: [` `], - standalone: true, imports: [ - ColumnsModifyDialogComponent, MatDialogModule, MatButtonModule, MatIconModule diff --git a/src/app/components/columns-modify-dialog.component.ts b/src/app/components/columns-modify-dialog.component.ts index f313587b0..c837b6ad3 100644 --- a/src/app/components/columns-modify-dialog.component.ts +++ b/src/app/components/columns-modify-dialog.component.ts @@ -9,7 +9,7 @@ import { ColumnsModifyDialogData } from '@app/types/dialog'; @Component({ selector: 'app-add-columns-dialog', - templateUrl:'./columns-modify-dialog.component.html', + templateUrl: './columns-modify-dialog.component.html', styles: [` .columns { display: grid; @@ -20,7 +20,6 @@ import { ColumnsModifyDialogData } from '@app/types/dialog'; margin-top: 1rem; } `], - standalone: true, imports: [ MatGridListModule, MatDialogModule, diff --git a/src/app/components/count-tasks-by-status.component.ts b/src/app/components/count-tasks-by-status.component.ts index 68a2cc8c4..daa87ae4e 100644 --- a/src/app/components/count-tasks-by-status.component.ts +++ b/src/app/components/count-tasks-by-status.component.ts @@ -2,7 +2,9 @@ import { Component, Input, OnInit, WritableSignal, inject, signal } from '@angul import { TasksStatusesGroup } from '@app/dashboard/types'; import { TasksFiltersService } from '@app/tasks/services/tasks-filters.service'; import { TasksGrpcService } from '@app/tasks/services/tasks-grpc.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { StatusCount, TaskSummaryFilters } from '@app/tasks/types'; +import { StatusService } from '@app/types/status'; import { ViewTasksByStatusComponent } from '@components/view-tasks-by-status.component'; import { Subject, switchMap } from 'rxjs'; @@ -19,10 +21,13 @@ import { Subject, switchMap } from 'rxjs'; `, styles: [` `], - standalone: true, providers: [ TasksGrpcService, - TasksFiltersService + TasksFiltersService, + { + provide: StatusService, + useClass: TasksStatusesService, + } ], imports: [ ViewTasksByStatusComponent, diff --git a/src/app/components/filters/filters-chips.component.spec.ts b/src/app/components/filters/filters-chips.component.spec.ts index 3ef03eb3f..3401ce11e 100644 --- a/src/app/components/filters/filters-chips.component.spec.ts +++ b/src/app/components/filters/filters-chips.component.spec.ts @@ -100,7 +100,7 @@ describe('FiltersChipsComponent', () => { operator: FilterDateOperator.FILTER_DATE_OPERATOR_AFTER_OR_EQUAL, value: '0', }]; - expect(component.filters()).toEqual(['CreatedAt After or Equal Thu, 01 Jan 1970 00:00:00 GMT']); + expect(component.filters()).toEqual([`CreatedAt After or Equal ${(new Date(0)).toLocaleString()}`]); }); it('should create the label of a duration filter', () => { diff --git a/src/app/components/filters/filters-chips.component.ts b/src/app/components/filters/filters-chips.component.ts index a61f54190..a107a72d0 100644 --- a/src/app/components/filters/filters-chips.component.ts +++ b/src/app/components/filters/filters-chips.component.ts @@ -19,13 +19,12 @@ import { UtilsService } from '@services/utils.service'; margin-left: 8px; } `], - standalone: true, imports: [ MatChipsModule, ], providers: [ FiltersService, - ], + ] }) export class FiltersChipsComponent { private readonly filtersService = inject(FiltersService); @@ -59,7 +58,7 @@ export class FiltersChipsComponent { @Input({ required: true }) first: boolean; diff --git a/src/app/components/filters/filters-dialog-filter-field.component.ts b/src/app/components/filters/filters-dialog-filter-field.component.ts index 1ca24b69e..02aec9d69 100644 --- a/src/app/components/filters/filters-dialog-filter-field.component.ts +++ b/src/app/components/filters/filters-dialog-filter-field.component.ts @@ -27,7 +27,6 @@ span { text-align: end; } `], - standalone: true, imports: [ MatFormFieldModule, MatSelectModule, @@ -39,7 +38,7 @@ span { ], providers: [ FiltersService, - ], + ] }) export class FiltersDialogFilterFieldComponent { @Input({ required: true }) first: boolean; diff --git a/src/app/components/filters/filters-dialog-input.component.css b/src/app/components/filters/filters-dialog-input.component.css new file mode 100644 index 000000000..53a4bc5e4 --- /dev/null +++ b/src/app/components/filters/filters-dialog-input.component.css @@ -0,0 +1,3 @@ +mat-form-field { + width: 100%; +} \ No newline at end of file diff --git a/src/app/components/filters/filters-dialog-input.component.html b/src/app/components/filters/filters-dialog-input.component.html index e39e894f0..66ca370ac 100644 --- a/src/app/components/filters/filters-dialog-input.component.html +++ b/src/app/components/filters/filters-dialog-input.component.html @@ -13,16 +13,15 @@ } @case ('date') { - Choose a date - - - - - - - + Choose a date + + + + + + + + } @case ('status') { diff --git a/src/app/components/filters/filters-dialog-input.component.spec.ts b/src/app/components/filters/filters-dialog-input.component.spec.ts index ab662182a..7241e8c5f 100644 --- a/src/app/components/filters/filters-dialog-input.component.spec.ts +++ b/src/app/components/filters/filters-dialog-input.component.spec.ts @@ -1,19 +1,32 @@ -// eslint-disable-next-line import/no-unresolved -import { NgxMatDatepickerInputEvent } from '@angular-material-components/datetime-picker/lib/datepicker-input-base'; +import { FilterInput } from '@app/types/filters'; +import { NgxMatDatepickerInputEvent } from '@ngxmc/datetime-picker'; +import { Moment } from 'moment'; import { FiltersDialogInputComponent } from './filters-dialog-input.component'; describe('FiltersDialogInputComponent', () => { const component = new FiltersDialogInputComponent(); - component.input = { + const input: FilterInput = { type: 'string', value: 'someValue' }; const valueChangeSpy = jest.spyOn(component.valueChange, 'emit'); + const dateTimeOffsetSpy = jest.spyOn(Date.prototype, 'getTimezoneOffset'); + + beforeEach(() => { + component.input = input; + dateTimeOffsetSpy.mockReturnValue(0); + }); it('should run', () => { expect(component).toBeTruthy(); }); + describe('On initialisation', () => { + it('should set the filter object', () => { + expect(component.input).toBe(input); + }); + }); + it('should emit on string change', () => { const eventValue = 'stringValue'; const event = { @@ -30,8 +43,10 @@ describe('FiltersDialogInputComponent', () => { it('should emit the value', () => { const milliseconds = 19043234000; const event = { - value: new Date(milliseconds) // Date takes milliseconds, not seconds. - } as unknown as NgxMatDatepickerInputEvent; + value: { + toDate: jest.fn(() => new Date(milliseconds)) // Date takes milliseconds, not seconds. + } + } as unknown as NgxMatDatepickerInputEvent; component.onDateChange(event); expect(valueChangeSpy).toHaveBeenCalledWith(`${milliseconds / 1000}`); @@ -40,7 +55,7 @@ describe('FiltersDialogInputComponent', () => { it('should emit null if there is no value', () => { const event = { value: null - } as unknown as NgxMatDatepickerInputEvent; + } as unknown as NgxMatDatepickerInputEvent; component.onDateChange(event); expect(valueChangeSpy).toHaveBeenCalledWith(''); diff --git a/src/app/components/filters/filters-dialog-input.component.ts b/src/app/components/filters/filters-dialog-input.component.ts index 179ffe62d..ba11bff17 100644 --- a/src/app/components/filters/filters-dialog-input.component.ts +++ b/src/app/components/filters/filters-dialog-input.component.ts @@ -3,30 +3,27 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { NgxMatDatetimePickerModule, NgxMatNativeDateModule, NgxMatTimepickerModule } from '@angular-material-components/datetime-picker'; -// eslint-disable-next-line import/no-unresolved -import { NgxMatDatepickerInputEvent } from '@angular-material-components/datetime-picker/lib/datepicker-input-base'; import { FilterInput } from '@app/types/filters'; import { AutoCompleteComponent } from '@components/auto-complete.component'; +import { NgxMatDatepickerActions, NgxMatDatepickerApply, NgxMatDatepickerCancel, NgxMatDatepickerInput, NgxMatDatepickerInputEvent, NgxMatDatepickerToggle, NgxMatDatetimepicker } from '@ngxmc/datetime-picker'; +import { Moment } from 'moment'; @Component({ selector: 'app-filters-dialog-input', templateUrl: './filters-dialog-input.component.html', - styles: [` -mat-form-field { - width: 100%; -} -`], - standalone: true, + styleUrl: 'filters-dialog-input.component.css', imports: [ MatFormFieldModule, MatInputModule, - NgxMatTimepickerModule, - NgxMatDatetimePickerModule, - NgxMatNativeDateModule, MatAutocompleteModule, MatButtonModule, - AutoCompleteComponent + AutoCompleteComponent, + NgxMatDatepickerActions, + NgxMatDatepickerApply, + NgxMatDatepickerCancel, + NgxMatDatepickerInput, + NgxMatDatetimepicker, + NgxMatDatepickerToggle, ], }) export class FiltersDialogInputComponent { @@ -35,7 +32,6 @@ export class FiltersDialogInputComponent { @Output() valueChange: EventEmitter = new EventEmitter(); booleans = ['true', 'false']; - actualDate = new Date(); duration: {[key: number]: string} = {}; private emit(value: string) { @@ -46,9 +42,9 @@ export class FiltersDialogInputComponent { this.emit((event.target as HTMLInputElement).value); } - onDateChange(event: NgxMatDatepickerInputEvent): void { + onDateChange(event: NgxMatDatepickerInputEvent): void { if (event.value) { - this.emit(`${event.value.getTime() / 1000}`); + this.emit(`${event.value.toDate().getTime() / 1000}`); } else { this.emit(''); } diff --git a/src/app/components/filters/filters-dialog-or.component.ts b/src/app/components/filters/filters-dialog-or.component.ts index a3ddac6b8..624d4ee92 100644 --- a/src/app/components/filters/filters-dialog-or.component.ts +++ b/src/app/components/filters/filters-dialog-or.component.ts @@ -36,7 +36,6 @@ span { gap: 1rem; } `], - standalone: true, imports: [ FiltersDialogAndComponent, MatButtonModule, @@ -45,7 +44,7 @@ span { ], providers: [ IconsService - ], + ] }) export class FiltersDialogOrComponent { @Input({ required: true }) first: boolean; diff --git a/src/app/components/filters/filters-dialog.component.ts b/src/app/components/filters/filters-dialog.component.ts index d4fd00c2e..b523f9bd2 100644 --- a/src/app/components/filters/filters-dialog.component.ts +++ b/src/app/components/filters/filters-dialog.component.ts @@ -24,7 +24,6 @@ import { FiltersDialogOrComponent } from './filters-dialog-or.component'; gap: 1rem; } `], - standalone: true, imports: [ FiltersDialogOrComponent, MatDialogModule, @@ -38,7 +37,7 @@ import { FiltersDialogOrComponent } from './filters-dialog-or.component'; ], providers: [ FiltersService, - ], + ] }) export class FiltersDialogComponent implements OnInit { private readonly iconsService = inject(IconsService); diff --git a/src/app/components/filters/filters-toolbar.component.ts b/src/app/components/filters/filters-toolbar.component.ts index d8a12520c..271a6aa72 100644 --- a/src/app/components/filters/filters-toolbar.component.ts +++ b/src/app/components/filters/filters-toolbar.component.ts @@ -56,14 +56,13 @@ button { transform: scale(1.5); } `], - standalone: true, imports: [ FiltersChipsComponent, MatButtonModule, MatIconModule, MatDialogModule, MatTooltipModule, - ], + ] }) export class FiltersToolbarComponent { private readonly iconsService = inject(IconsService); diff --git a/src/app/components/icon-picker-dialog.component.ts b/src/app/components/icon-picker-dialog.component.ts index 952e5385e..dc9de58a4 100644 --- a/src/app/components/icon-picker-dialog.component.ts +++ b/src/app/components/icon-picker-dialog.component.ts @@ -18,7 +18,6 @@ article { display: grid; } `], - standalone: true, providers: [ IconsService ], diff --git a/src/app/components/inspect-list.component.ts b/src/app/components/inspect-list.component.ts index 2b136f57c..2d6aa7192 100644 --- a/src/app/components/inspect-list.component.ts +++ b/src/app/components/inspect-list.component.ts @@ -20,7 +20,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-inspect-list', templateUrl: 'inspect-list.component.html', - standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ MatToolbarModule, @@ -30,7 +29,7 @@ import { NotificationService } from '@services/notification.service'; MatDivider, MatIconModule, ], - styleUrl: 'inspect-list.component.css', + styleUrl: 'inspect-list.component.css' }) export class InspectListComponent { private _list: string[] = []; diff --git a/src/app/components/inspection-header.component.ts b/src/app/components/inspection-header.component.ts index da05e40ca..ca733c6d4 100644 --- a/src/app/components/inspection-header.component.ts +++ b/src/app/components/inspection-header.component.ts @@ -14,7 +14,6 @@ import { StatusChipComponent } from './status-chip.component'; @Component({ selector: 'app-inspection-header', templateUrl: 'inspection-header.component.html', - standalone: true, imports: [ MatToolbarModule, PageHeaderComponent, diff --git a/src/app/components/inspection-toolbar.component.ts b/src/app/components/inspection-toolbar.component.ts index 6f3e030d6..57a0fdf9d 100644 --- a/src/app/components/inspection-toolbar.component.ts +++ b/src/app/components/inspection-toolbar.component.ts @@ -7,7 +7,6 @@ import { IconsService } from '@services/icons.service'; @Component({ selector: 'app-inspection-toolbar', templateUrl: 'inspection-toolbar.component.html', - standalone: true, imports: [ MatToolbarModule, MatIconModule, diff --git a/src/app/components/inspection/byte-array.component.ts b/src/app/components/inspection/byte-array.component.ts index 63058ec2c..104903c7c 100644 --- a/src/app/components/inspection/byte-array.component.ts +++ b/src/app/components/inspection/byte-array.component.ts @@ -16,7 +16,6 @@ import { NotificationService } from '@services/notification.service'; selector: 'app-byte-array-inspection', templateUrl: 'byte-array.component.html', styleUrl: 'byte-array.component.css', - standalone: true, imports: [ MatIconModule, MatCardModule, diff --git a/src/app/components/inspection/field-content.component.ts b/src/app/components/inspection/field-content.component.ts index 50aa7f94f..a67b7a977 100644 --- a/src/app/components/inspection/field-content.component.ts +++ b/src/app/components/inspection/field-content.component.ts @@ -20,7 +20,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-field-content', templateUrl: 'field-content.component.html', - standalone: true, imports: [ MatChipsModule, DatePipe, diff --git a/src/app/components/inspection/inspection-card.component.ts b/src/app/components/inspection/inspection-card.component.ts index 8fdefefa8..acd9eb256 100644 --- a/src/app/components/inspection/inspection-card.component.ts +++ b/src/app/components/inspection/inspection-card.component.ts @@ -9,7 +9,6 @@ import { InspectionComponent } from './inspection.component'; @Component({ selector: 'app-inspection-card', templateUrl: 'inspection-card.component.html', - standalone: true, imports: [ MatCardModule, InspectionComponent, diff --git a/src/app/components/inspection/inspection-json.component.ts b/src/app/components/inspection/inspection-json.component.ts index bb7d06fee..99f5db171 100644 --- a/src/app/components/inspection/inspection-json.component.ts +++ b/src/app/components/inspection/inspection-json.component.ts @@ -12,7 +12,6 @@ import { JsonComponent } from './json.component'; @Component({ selector: 'app-json-inspection', templateUrl: 'inspection-json.component.html', - standalone: true, providers: [ IconsService, ], diff --git a/src/app/components/inspection/inspection-list-grid.component.ts b/src/app/components/inspection/inspection-list-grid.component.ts index f79dc52da..bf29e73db 100644 --- a/src/app/components/inspection/inspection-list-grid.component.ts +++ b/src/app/components/inspection/inspection-list-grid.component.ts @@ -7,7 +7,6 @@ import { PrettyPipe } from '@pipes/pretty.pipe'; @Component({ selector: 'app-inspection-list-grid', templateUrl: 'inspection-list-grid.component.html', - standalone: true, styleUrl: '../../../inspections.css', imports: [ InspectListComponent, diff --git a/src/app/components/inspection/inspection-object.component.ts b/src/app/components/inspection/inspection-object.component.ts index 64fec4540..d0e1eeb7b 100644 --- a/src/app/components/inspection/inspection-object.component.ts +++ b/src/app/components/inspection/inspection-object.component.ts @@ -12,7 +12,6 @@ import { MessageComponent } from './message.component'; @Component({ selector: 'app-inspection-object', templateUrl: 'inspection-object.component.html', - standalone: true, imports: [ MatExpansionModule, PrettyPipe, diff --git a/src/app/components/inspection/inspection.component.ts b/src/app/components/inspection/inspection.component.ts index 3a9a89049..14b667ad7 100644 --- a/src/app/components/inspection/inspection.component.ts +++ b/src/app/components/inspection/inspection.component.ts @@ -9,14 +9,13 @@ import { InspectionObjectComponent } from './inspection-object.component'; @Component({ selector: 'app-inspection', templateUrl: 'inspection.component.html', - standalone: true, imports: [ InspectionObjectComponent, MatExpansionModule, MatToolbarModule, ], changeDetection: ChangeDetectionStrategy.OnPush, - styleUrl: '../../../inspections.css', + styleUrl: '../../../inspections.css' }) export class InspectionComponent { private _data: T = {} as T; diff --git a/src/app/components/inspection/json.component.ts b/src/app/components/inspection/json.component.ts index 260e7583c..7c6f0ccde 100644 --- a/src/app/components/inspection/json.component.ts +++ b/src/app/components/inspection/json.component.ts @@ -4,7 +4,6 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'app-json', templateUrl: 'json.component.html', - standalone: true, imports: [ JsonPipe ], diff --git a/src/app/components/inspection/message.component.ts b/src/app/components/inspection/message.component.ts index 47e60a5b1..730c5f9e6 100644 --- a/src/app/components/inspection/message.component.ts +++ b/src/app/components/inspection/message.component.ts @@ -10,7 +10,6 @@ import { NotificationService } from '@services/notification.service'; selector: 'app-message', templateUrl: 'message.component.html', styleUrl: 'message.component.css', - standalone: true, imports: [ MatCardModule, MatButtonModule, diff --git a/src/app/components/manage-custom-dialog.component.ts b/src/app/components/manage-custom-dialog.component.ts index 1fe4d34f8..481ea6dc4 100644 --- a/src/app/components/manage-custom-dialog.component.ts +++ b/src/app/components/manage-custom-dialog.component.ts @@ -10,7 +10,6 @@ import { CustomColumn } from '@app/types/data'; @Component({ selector: 'app-add-custom-col-dialog', - standalone: true, templateUrl: './manage-custom-dialog.component.html', styles: [` mat-form-field { diff --git a/src/app/components/navigation/change-language-button.component.ts b/src/app/components/navigation/change-language-button.component.ts index 35e9fda24..ba154e108 100644 --- a/src/app/components/navigation/change-language-button.component.ts +++ b/src/app/components/navigation/change-language-button.component.ts @@ -10,7 +10,6 @@ import { StorageService } from '@services/storage.service'; @Component({ selector: 'app-change-language-button', - standalone: true, templateUrl: './change-language-button.component.html', imports: [ RouterModule, diff --git a/src/app/components/navigation/external-services/external-services.component.ts b/src/app/components/navigation/external-services/external-services.component.ts index cade4dfad..ff1364a47 100644 --- a/src/app/components/navigation/external-services/external-services.component.ts +++ b/src/app/components/navigation/external-services/external-services.component.ts @@ -24,7 +24,6 @@ import { ManageExternalServicesDialogComponent } from './manage-external-service IconsService, NavigationService ], - standalone: true, styleUrl: 'external-services.css', changeDetection: ChangeDetectionStrategy.OnPush }) diff --git a/src/app/components/navigation/external-services/form-external-service.component.ts b/src/app/components/navigation/external-services/form-external-service.component.ts index 8a7e1f823..f163ab600 100644 --- a/src/app/components/navigation/external-services/form-external-service.component.ts +++ b/src/app/components/navigation/external-services/form-external-service.component.ts @@ -14,7 +14,6 @@ import { IconsService } from '@services/icons.service'; selector: 'app-form-external-service', templateUrl: './form-external-service.component.html', styleUrl: 'external-services.css', - standalone: true, imports: [ ReactiveFormsModule, MatIconModule, @@ -24,7 +23,7 @@ import { IconsService } from '@services/icons.service'; MatInputModule, IconPickerDialogComponent, MatTooltipModule, - ], + ] }) export class FormExternalServiceComponent implements OnInit { private readonly iconsService = inject(IconsService); diff --git a/src/app/components/navigation/external-services/manage-external-services-dialog.component.spec.ts b/src/app/components/navigation/external-services/manage-external-services-dialog.component.spec.ts index bcca13218..9f06d8e57 100644 --- a/src/app/components/navigation/external-services/manage-external-services-dialog.component.spec.ts +++ b/src/app/components/navigation/external-services/manage-external-services-dialog.component.spec.ts @@ -1,24 +1,13 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ExternalService } from '@app/types/external-service'; import { IconsService } from '@services/icons.service'; -import { BehaviorSubject } from 'rxjs'; import { ManageExternalServicesDialogComponent } from './manage-external-services-dialog.component'; describe('ManageExternalServicesDialogComponent', () => { let component: ManageExternalServicesDialogComponent; - let dialogRefSubject: BehaviorSubject; - const mockMatDialog = { - open: jest.fn(() => { - return { - afterClosed() { - return dialogRefSubject; - } - }; - }) - }; const externalService = { name: 'service', url: 'url', @@ -35,7 +24,6 @@ describe('ManageExternalServicesDialogComponent', () => { component = TestBed.configureTestingModule({ providers: [ ManageExternalServicesDialogComponent, - { provide: MatDialog, useValue: mockMatDialog }, { provide: MatDialogRef, useValue: mockMatDialogRef }, { provide: MAT_DIALOG_DATA, useValue: mockMatDialogData }, IconsService diff --git a/src/app/components/navigation/external-services/manage-external-services-dialog.component.ts b/src/app/components/navigation/external-services/manage-external-services-dialog.component.ts index 28fe6ba3b..f03a84cb7 100644 --- a/src/app/components/navigation/external-services/manage-external-services-dialog.component.ts +++ b/src/app/components/navigation/external-services/manage-external-services-dialog.component.ts @@ -12,7 +12,6 @@ import { FormExternalServiceComponent } from './form-external-service.component' selector: 'app-manage-external-services', templateUrl: './manage-external-services-dialog.component.html', styleUrl: 'external-services.css', - standalone: true, providers: [], imports: [ DragDropModule, @@ -21,7 +20,7 @@ import { FormExternalServiceComponent } from './form-external-service.component' MatIconModule, MatTooltipModule, FormExternalServiceComponent, - ], + ] }) export class ManageExternalServicesDialogComponent implements OnInit { readonly iconsService = inject(IconsService); diff --git a/src/app/components/navigation/navigation.component.spec.ts b/src/app/components/navigation/navigation.component.spec.ts index 03a9aff9f..282b44ff5 100644 --- a/src/app/components/navigation/navigation.component.spec.ts +++ b/src/app/components/navigation/navigation.component.spec.ts @@ -1,7 +1,5 @@ import { BreakpointObserver } from '@angular/cdk/layout'; -import { TestBed, fakeAsync } from '@angular/core/testing'; -import { MatDialog } from '@angular/material/dialog'; -import { ExternalService } from '@app/types/external-service'; +import { TestBed } from '@angular/core/testing'; import { DefaultConfigService } from '@services/default-config.service'; import { EnvironmentService } from '@services/environment.service'; import { IconsService } from '@services/icons.service'; @@ -9,7 +7,7 @@ import { NavigationService } from '@services/navigation.service'; import { StorageService } from '@services/storage.service'; import { UserService } from '@services/user.service'; import { VersionsService } from '@services/versions.service'; -import { BehaviorSubject, Subject, lastValueFrom, of } from 'rxjs'; +import { Subject, lastValueFrom, of } from 'rxjs'; import { NavigationComponent } from './navigation.component'; @@ -23,17 +21,7 @@ jest.mock('rxjs', () => ({ describe('NavigationComponent', () => { let component: NavigationComponent; - let dialogRefSubject: BehaviorSubject; const currentSidebar = ['item-1', 'item-2']; - const mockMatDialog = { - open: jest.fn(() => { - return { - afterClosed() { - return dialogRefSubject; - } - }; - }) - }; const mockNavigationService = { currentSidebar: currentSidebar, restoreSideBarOpened: jest.fn(), @@ -58,7 +46,6 @@ describe('NavigationComponent', () => { NavigationComponent, { provide: BreakpointObserver, useValue: mockBreakpointObserver }, { provide: NavigationService, useValue: mockNavigationService }, - { provide: MatDialog, useValue: mockMatDialog }, IconsService, { provide: UserService, useValue: mockUserService }, VersionsService, @@ -106,7 +93,7 @@ describe('NavigationComponent', () => { expect(component.sidebar).toEqual(currentSidebar); }); - it('should greet correctly', fakeAsync(() => { + it('should greet correctly', () => { jest.useFakeTimers().setSystemTime(new Date('2020-01-01T10:00:00')); fakeIntervalSubject.next(); expect(component.greetings).toEqual('Good morning'); @@ -132,7 +119,7 @@ describe('NavigationComponent', () => { jest.useFakeTimers().setSystemTime(new Date('2020-01-01T13:00:00')); fakeIntervalSubject.next(); expect(component.greetings).toEqual('Good afternoon, user'); - })); + }); describe('toggle sidebar', () => { it('should toggle sidebar', () => { diff --git a/src/app/components/navigation/navigation.component.ts b/src/app/components/navigation/navigation.component.ts index 8049bdd10..1a02a2350 100644 --- a/src/app/components/navigation/navigation.component.ts +++ b/src/app/components/navigation/navigation.component.ts @@ -67,7 +67,6 @@ main { padding: 20px 50px; } `], - standalone: true, providers: [ StorageService, IconsService, diff --git a/src/app/components/navigation/theme-selector.component.ts b/src/app/components/navigation/theme-selector.component.ts index 9444f9f99..31021173c 100644 --- a/src/app/components/navigation/theme-selector.component.ts +++ b/src/app/components/navigation/theme-selector.component.ts @@ -14,15 +14,13 @@ import { StorageService } from '@services/storage.service'; styles: [` `], - standalone: true, - providers: [ - ], + providers: [], imports: [ MatButtonModule, MatMenuModule, MatIconModule, MatTooltipModule, - ], + ] }) export class ThemeSelectorComponent implements OnInit { private readonly defaultConfigService = inject(DefaultConfigService); diff --git a/src/app/components/navigation/version-menu/repository-version.component.ts b/src/app/components/navigation/version-menu/repository-version.component.ts index 25424a210..1bd230e00 100644 --- a/src/app/components/navigation/version-menu/repository-version.component.ts +++ b/src/app/components/navigation/version-menu/repository-version.component.ts @@ -5,7 +5,6 @@ import { IconsService } from '@services/icons.service'; @Component({ selector: 'app-repository-version', - standalone: true, templateUrl: 'repository-version.component.html', imports: [ MatMenuModule, diff --git a/src/app/components/navigation/version-menu/versions-menu.component.ts b/src/app/components/navigation/version-menu/versions-menu.component.ts index 90fc432ca..9ffdf35db 100644 --- a/src/app/components/navigation/version-menu/versions-menu.component.ts +++ b/src/app/components/navigation/version-menu/versions-menu.component.ts @@ -10,7 +10,6 @@ import pkg from '../../../../../package.json'; @Component({ selector: 'app-versions-menu', templateUrl: 'versions-menu.component.html', - standalone: true, imports: [ MatMenuModule, MatIconModule, diff --git a/src/app/components/page-header.component.ts b/src/app/components/page-header.component.ts index 46883f6c5..079f40018 100644 --- a/src/app/components/page-header.component.ts +++ b/src/app/components/page-header.component.ts @@ -3,7 +3,7 @@ import { ShareUrlComponent } from './share-url.component'; @Component({ selector: 'app-page-header', - templateUrl:'./page-header.component.html', + templateUrl: './page-header.component.html', styles: [` .page-header { display: flex; @@ -26,7 +26,6 @@ import { ShareUrlComponent } from './share-url.component'; align-items: center; } `], - standalone: true, providers: [], imports: [ ShareUrlComponent diff --git a/src/app/components/page-section-header.component.ts b/src/app/components/page-section-header.component.ts index 67b84f3e5..9a2ce9474 100644 --- a/src/app/components/page-section-header.component.ts +++ b/src/app/components/page-section-header.component.ts @@ -21,7 +21,6 @@ h2 { gap: 1rem; } `], - standalone: true, providers: [], imports: [ MatIconModule diff --git a/src/app/components/page-section.component.ts b/src/app/components/page-section.component.ts index c07e8aadb..852930110 100644 --- a/src/app/components/page-section.component.ts +++ b/src/app/components/page-section.component.ts @@ -9,7 +9,6 @@ import { Component } from '@angular/core'; `, styles: [` `], - standalone: true, providers: [], imports: [] }) diff --git a/src/app/components/refresh-button.component.ts b/src/app/components/refresh-button.component.ts index 48708180c..701e16982 100644 --- a/src/app/components/refresh-button.component.ts +++ b/src/app/components/refresh-button.component.ts @@ -14,7 +14,6 @@ import { IconsService } from '@services/icons.service'; `, styles: [` `], - standalone: true, imports: [ MatButtonModule, MatTooltipModule, diff --git a/src/app/components/share-url.component.spec.ts b/src/app/components/share-url.component.spec.ts index 25a1973c0..323ba81c0 100644 --- a/src/app/components/share-url.component.spec.ts +++ b/src/app/components/share-url.component.spec.ts @@ -1,4 +1,4 @@ -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { IconsService } from '@services/icons.service'; import { ShareUrlComponent } from './share-url.component'; @@ -34,9 +34,10 @@ describe('ShareUrlComponent', () => { expect(component.copied).toBeTruthy(); }); - it('Should not be copied one second after', fakeAsync(() => { + it('Should not be copied one second after', () => { + jest.useFakeTimers(); component.onCopied(); - tick(1250); + jest.runAllTimers(); expect(component.copied).toBeFalsy(); - })); + }); }); \ No newline at end of file diff --git a/src/app/components/share-url.component.ts b/src/app/components/share-url.component.ts index f42a00535..6946491c7 100644 --- a/src/app/components/share-url.component.ts +++ b/src/app/components/share-url.component.ts @@ -18,7 +18,6 @@ import { IconsService } from '@services/icons.service'; `, styles: [` `], - standalone: true, imports: [ ClipboardModule, MatIconModule, diff --git a/src/app/components/show-action-area.component.ts b/src/app/components/show-action-area.component.ts index 2fb2efaeb..73998c5b4 100644 --- a/src/app/components/show-action-area.component.ts +++ b/src/app/components/show-action-area.component.ts @@ -12,7 +12,6 @@ import { ShowActionButton } from '@app/types/components/show'; margin-right: 3px; } `], - standalone: true, imports: [ RouterModule, MatButtonModule, diff --git a/src/app/components/show-actions.component.ts b/src/app/components/show-actions.component.ts index 3c18a5786..2dc8ae55d 100644 --- a/src/app/components/show-actions.component.ts +++ b/src/app/components/show-actions.component.ts @@ -20,7 +20,6 @@ import { ShowActionAreaComponent } from './show-action-area.component'; margin-right: 5px; } `], - standalone: true, imports: [ CommonModule, MatIconModule, diff --git a/src/app/components/show-card-content.component.ts b/src/app/components/show-card-content.component.ts index 5fe5ad8b4..0e82b89cc 100644 --- a/src/app/components/show-card-content.component.ts +++ b/src/app/components/show-card-content.component.ts @@ -30,8 +30,7 @@ app-show-card-content { DatePipe, EmptyCellPipe, PrettyPipe, - ], - standalone: true + ] }) export class ShowCardContentComponent { @Input({ required: true }) set data(entry: T | T[] | null) { diff --git a/src/app/components/show-card.component.ts b/src/app/components/show-card.component.ts index 51ea6e1c2..af8c16e82 100644 --- a/src/app/components/show-card.component.ts +++ b/src/app/components/show-card.component.ts @@ -12,7 +12,6 @@ pre { margin-top: 0; } `], - standalone: true, imports: [ ShowCardContentComponent, MatCardModule, diff --git a/src/app/components/show-page.component.ts b/src/app/components/show-page.component.ts index 2b8fe7af6..2a08b2bb9 100644 --- a/src/app/components/show-page.component.ts +++ b/src/app/components/show-page.component.ts @@ -14,7 +14,6 @@ import { InspectionToolbarComponent } from './inspection-toolbar.component'; selector: 'app-show-page', templateUrl: './show-page.component.html', styleUrl: 'show-page.component.css', - standalone: true, imports: [ InspectionCardComponent, InspectionHeaderComponent, diff --git a/src/app/components/spinner.component.ts b/src/app/components/spinner.component.ts index 47391b31e..82f017c20 100644 --- a/src/app/components/spinner.component.ts +++ b/src/app/components/spinner.component.ts @@ -8,9 +8,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; `, styles: [` `], - standalone: true, - providers: [ - ], + providers: [], imports: [ MatProgressSpinnerModule ] diff --git a/src/app/components/status-chip.component.html b/src/app/components/status-chip.component.html index a5686a529..d78d601ac 100644 --- a/src/app/components/status-chip.component.html +++ b/src/app/components/status-chip.component.html @@ -1,4 +1,4 @@ - + @if (icon !== undefined) { } diff --git a/src/app/components/status-chip.component.ts b/src/app/components/status-chip.component.ts index ad15721be..045cb3ee9 100644 --- a/src/app/components/status-chip.component.ts +++ b/src/app/components/status-chip.component.ts @@ -9,7 +9,6 @@ import { IconsService } from '../services/icons.service'; selector: 'app-status-chip', templateUrl: 'status-chip.component.html', styleUrl: 'status-chip.component.css', - standalone: true, imports: [ MatChipsModule, MatIconModule, diff --git a/src/app/components/status-color-picker.component.html b/src/app/components/status-color-picker.component.html new file mode 100644 index 000000000..7bec7c762 --- /dev/null +++ b/src/app/components/status-color-picker.component.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/app/components/status-color-picker.component.spec.ts b/src/app/components/status-color-picker.component.spec.ts new file mode 100644 index 000000000..e3d1d2694 --- /dev/null +++ b/src/app/components/status-color-picker.component.spec.ts @@ -0,0 +1,106 @@ +import { ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { MatDialog } from '@angular/material/dialog'; +import { StatusLabelColor, StatusService } from '@app/types/status'; +import { IconsService } from '@services/icons.service'; +import { BehaviorSubject } from 'rxjs'; +import { StatusColorPickerComponent } from './status-color-picker.component'; +import { StatusColorPickerDialogComponent } from './status-color-picker.dialog.component'; + +describe('StatusColorPickerComponent', () => { + let component: StatusColorPickerComponent; + + const mockStatusService = { + statuses: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: 'red' + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed', + color: 'green' + }, + }, + getDefault: jest.fn(() => { + return { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: 'blue' + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed', + color: 'purple' + }, + }; + }), + keys: [ResultStatus.RESULT_STATUS_ABORTED, ResultStatus.RESULT_STATUS_COMPLETED], + updateStatuses: jest.fn(), + }; + + const mockIconsService = { + getIcon: jest.fn() + }; + + const mockDialogReturnData = { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: 'orange' + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed', + color: 'yellow' + }, + } as Record; + + const mockDialog = { + open: jest.fn(() => { + return { + afterClosed: jest.fn(() => new BehaviorSubject>(mockDialogReturnData)) + }; + }), + }; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + StatusColorPickerComponent, + { provide: IconsService, useValue: mockIconsService }, + { provide: MatDialog, useValue: mockDialog }, + { provide: StatusService, useValue: mockStatusService }, + ] + }).inject(StatusColorPickerComponent); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should retrieve icons', () => { + const icon = 'heart'; + component.getIcon(icon); + expect(mockIconsService.getIcon).toHaveBeenCalledWith(icon); + }); + + describe('openDialog', () => { + beforeEach(() => { + component.openDialog(); + }); + + it('should open the dialog', () => { + expect(mockDialog.open).toHaveBeenCalledWith( + StatusColorPickerDialogComponent, + { + data: { + current: mockStatusService.statuses, + default: mockStatusService.getDefault(), + keys: mockStatusService.keys, + } + } + ); + }); + + it('should update the result after the close', () => { + expect(mockStatusService.updateStatuses).toHaveBeenCalledWith(mockDialogReturnData); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/status-color-picker.component.ts b/src/app/components/status-color-picker.component.ts new file mode 100644 index 000000000..389d01980 --- /dev/null +++ b/src/app/components/status-color-picker.component.ts @@ -0,0 +1,47 @@ +import { Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { StatusColorPickerDialogData } from '@app/types/dialog'; +import { Status, StatusLabelColor, StatusService } from '@app/types/status'; +import { IconsService } from '@services/icons.service'; +import { StatusColorPickerDialogComponent } from './status-color-picker.dialog.component'; + +@Component({ + selector: 'app-status-color-picker', + templateUrl: 'status-color-picker.component.html', + imports: [ + MatIconModule, + MatButtonModule, + MatTooltipModule, + ], +}) +export class StatusColorPickerComponent { + private readonly iconsService = inject(IconsService); + private readonly dialog = inject(MatDialog); + private readonly statusService = inject(StatusService); + + getIcon(name: string) { + return this.iconsService.getIcon(name); + } + + openDialog() { + const dialogRef = this.dialog.open, StatusColorPickerDialogData, Record>( + StatusColorPickerDialogComponent, + { + data: { + current: this.statusService.statuses, + default: this.statusService.getDefault(), + keys: this.statusService.keys, + }, + } + ); + + dialogRef.afterClosed().subscribe((result) => { + if (result) { + this.statusService.updateStatuses(result); + } + }); + } +} \ No newline at end of file diff --git a/src/app/components/status-color-picker.dialog.component.css b/src/app/components/status-color-picker.dialog.component.css new file mode 100644 index 000000000..3821ae18e --- /dev/null +++ b/src/app/components/status-color-picker.dialog.component.css @@ -0,0 +1,28 @@ +form { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-gap: 0.5rem 1.25rem; +} + +section { + display: flex; + align-items: center; + margin-bottom: 0.5rem; +} + +p, h3 { + margin: 0px; +} + +input, .header > mat-icon { + margin-right: 1rem; +} + +input[type=color] { + padding: 0px; + height: 3rem; + width: 3rem; + border-radius: 0.3rem; + border: 0px; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/components/status-color-picker.dialog.component.html b/src/app/components/status-color-picker.dialog.component.html new file mode 100644 index 000000000..76a5d32b2 --- /dev/null +++ b/src/app/components/status-color-picker.dialog.component.html @@ -0,0 +1,42 @@ +

Statuses Colors

+ +
+ @for(status of statuses; track status) { + @let control = getControl(status); + @if (control) { +
+
+ @let icon = statusesDefault[status].icon; + @if(icon) { + + } +

{{ statusesDefault[status].label }}

+
+
+ + + Color + + + + @if (control.dirty) { + + } @else { + + } +
+
+ } +} +
+ + + + + \ No newline at end of file diff --git a/src/app/components/status-color-picker.dialog.component.spec.ts b/src/app/components/status-color-picker.dialog.component.spec.ts new file mode 100644 index 000000000..24b47b44a --- /dev/null +++ b/src/app/components/status-color-picker.dialog.component.spec.ts @@ -0,0 +1,159 @@ +import { ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { Clipboard } from '@angular/cdk/clipboard'; +import { TestBed } from '@angular/core/testing'; +import { FormControl } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { IconsService } from '@services/icons.service'; +import { NotificationService } from '@services/notification.service'; +import { StatusColorPickerDialogComponent } from './status-color-picker.dialog.component'; + +describe('StatusColorPickerDialogComponent', () => { + let component: StatusColorPickerDialogComponent; + + const mockIconsService = { + getIcon: jest.fn(), + }; + + const mockClipboard = { + copy: jest.fn() + }; + + const mockNotificationService = { + success: jest.fn(), + error: jest.fn(), + }; + + const mockDialogRef = { + close: jest.fn() + }; + + const mockDialogData = { + current: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: '#00FF00' + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed', + color: '#FF0000' + }, + }, + default: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: '#0000FF' + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed', + color: '#F0000F' + }, + }, + keys: [ResultStatus.RESULT_STATUS_ABORTED, ResultStatus.RESULT_STATUS_COMPLETED], + }; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + StatusColorPickerDialogComponent, + { provide: IconsService, useValue: mockIconsService }, + { provide: Clipboard, useValue: mockClipboard }, + { provide: NotificationService, useValue: mockNotificationService }, + { provide: MatDialogRef, useValue: mockDialogRef }, + { provide: MAT_DIALOG_DATA, useValue: mockDialogData } + ] + }).inject(StatusColorPickerDialogComponent); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('initialisation', () => { + it('should set the statuses', () => { + expect(component.statuses).toEqual([ResultStatus.RESULT_STATUS_ABORTED, ResultStatus.RESULT_STATUS_COMPLETED]); + }); + + it('should set the statusForm', () => { + expect(component.statusesForm.value).toEqual({ + [ResultStatus.RESULT_STATUS_ABORTED]: '#00FF00', + [ResultStatus.RESULT_STATUS_COMPLETED]: '#FF0000', + }); + }); + + it('should set the default statuses', () => { + expect(component.statusesDefault).toEqual(mockDialogData.default); + }); + }); + + it('should return the control of a specific status', () => { + expect(component.getControl(ResultStatus.RESULT_STATUS_COMPLETED)).toBeInstanceOf(FormControl); + }); + + describe('copy', () => { + it('should copy the color of the status', () => { + component.copy(ResultStatus.RESULT_STATUS_ABORTED); + expect(mockClipboard.copy).toHaveBeenCalledWith(mockDialogData.current[ResultStatus.RESULT_STATUS_ABORTED].color.replace('#', '')); + }); + + it('should notify on successfull copy', () => { + component.copy(ResultStatus.RESULT_STATUS_ABORTED); + expect(mockNotificationService.success).toHaveBeenCalled(); + }); + + it('should notify on error', () => { + component.copy(ResultStatus.RESULT_STATUS_DELETED); + expect(mockNotificationService.error).toHaveBeenCalled(); + }); + }); + + describe('reset', () => { + const status = ResultStatus.RESULT_STATUS_ABORTED; + let control: FormControl | null; + beforeEach(() => { + control = component.getControl(status); + control?.setValue('red'); + component.reset(status); + }); + + it('should reset the form to its initial value', () => { + expect(control?.value).toEqual(mockDialogData.current[status].color); + }); + + it('should not be dirty', () => { + expect(control?.dirty).toBeFalsy(); + }); + }); + + describe('resetDefault', () => { + const status = ResultStatus.RESULT_STATUS_ABORTED; + let control: FormControl | null; + beforeEach(() => { + control = component.getControl(status); + component.resetDefault(status); + }); + + it('should reset the form to its default value', () => { + expect(control?.value).toEqual(mockDialogData.default[status].color); + }); + + it('should mark the form as dirty', () => { + expect(control?.dirty).toBeTruthy(); + }); + }); + + it('should get icon', () => { + const icon = 'heart'; + component.getIcon(icon); + expect(mockIconsService.getIcon).toHaveBeenCalledWith(icon); + }); + + it('should close without any data', () => { + component.close(); + expect(mockDialogRef.close).toHaveBeenCalledWith(); + }); + + it('should close with data on submit', () => { + component.submit(); + expect(mockDialogRef.close).toHaveBeenCalledWith(mockDialogData.current); // We havent changed anything, so we should get what we gived to the component + }); +}); \ No newline at end of file diff --git a/src/app/components/status-color-picker.dialog.component.ts b/src/app/components/status-color-picker.dialog.component.ts new file mode 100644 index 000000000..2f4ad3c11 --- /dev/null +++ b/src/app/components/status-color-picker.dialog.component.ts @@ -0,0 +1,108 @@ +import { Clipboard } from '@angular/cdk/clipboard'; +import { ChangeDetectionStrategy, Component, Inject, inject } from '@angular/core'; +import { FormControl, FormRecord, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { StatusColorPickerDialogData } from '@app/types/dialog'; +import { Status, StatusLabelColor } from '@app/types/status'; +import { IconsService } from '@services/icons.service'; +import { NotificationService } from '@services/notification.service'; + +@Component({ + selector: 'app-status-picker-dialog', + templateUrl: 'status-color-picker.dialog.component.html', + styleUrl: 'status-color-picker.dialog.component.css', + imports: [ + MatIconModule, + MatButtonModule, + MatDialogModule, + MatInputModule, + MatFormFieldModule, + ReactiveFormsModule, + MatTooltipModule, + ], + providers: [ + Clipboard, + NotificationService, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class StatusColorPickerDialogComponent { + private readonly iconsService = inject(IconsService); + private readonly clipboard = inject(Clipboard); + private readonly notificationService = inject(NotificationService); + + readonly statuses: S[]; + readonly statusesForm: FormRecord>; + + readonly statusesDefault: Record; + + constructor( + private readonly dialogRef: MatDialogRef, Record>, + @Inject(MAT_DIALOG_DATA) data: StatusColorPickerDialogData + ) { + this.statuses = data.keys; + this.statusesForm = new FormRecord( + this.statuses.reduce((acc, status) => { + acc[status] = new FormControl(data.current[status].color, { nonNullable: true }); + return acc; + }, + {} as Record>) + ); + this.statusesDefault = data.default; + } + + getControl(status: S): FormControl | null { + return this.statusesForm.get(`${status}`) as unknown as FormControl | null; + } + + copy(status: S) { + const value = this.getControl(status)?.value; + if (value) { + this.clipboard.copy(value.replace('#', '')); + this.notificationService.success($localize`Color copied !`); + } else { + this.notificationService.error($localize`An error occured`); + } + } + + reset(status: S) { + const control = this.getControl(status); + if (control) { + control.reset(); + } + } + + resetDefault(status: S) { + const control = this.getControl(status); + const defaultColor = this.statusesDefault[status].color; + if (control && defaultColor) { + control.patchValue(defaultColor); + control.markAsDirty(); + } + } + + getIcon(name: string) { + return this.iconsService.getIcon(name); + } + + close() { + this.dialogRef.close(); + } + + submit() { + const record = this.statusesForm.getRawValue(); + const result = this.statuses.reduce((acc, status) => { + acc[status] = { + ...this.statusesDefault[status], + color: record[status.toString()], + }; + return acc; + }, {} as Record); + this.dialogRef.close(result); + } +} \ No newline at end of file diff --git a/src/app/components/statuses/add-statuses-group-dialog.component.ts b/src/app/components/statuses/add-statuses-group-dialog.component.ts index 09da825a9..14d0319c5 100644 --- a/src/app/components/statuses/add-statuses-group-dialog.component.ts +++ b/src/app/components/statuses/add-statuses-group-dialog.component.ts @@ -17,9 +17,7 @@ import { AddStatusGroupDialogData, TasksStatusesGroup } from '../../dashboard/ty `, styles: [` `], - standalone: true, - providers: [ - ], + providers: [], imports: [ FormStatusesGroupComponent, MatDialogModule, diff --git a/src/app/components/statuses/edit-status-group-dialog.component.ts b/src/app/components/statuses/edit-status-group-dialog.component.ts index 2745cee0f..4b5935e89 100644 --- a/src/app/components/statuses/edit-status-group-dialog.component.ts +++ b/src/app/components/statuses/edit-status-group-dialog.component.ts @@ -17,9 +17,7 @@ import { EditStatusGroupDialogData, TasksStatusesGroup } from '../../dashboard/t `, styles: [` `], - standalone: true, - providers: [ - ], + providers: [], imports: [ FormStatusesGroupComponent, MatDialogModule, diff --git a/src/app/components/statuses/form-statuses-group.component.ts b/src/app/components/statuses/form-statuses-group.component.ts index 86e57babc..bbe6e0abe 100644 --- a/src/app/components/statuses/form-statuses-group.component.ts +++ b/src/app/components/statuses/form-statuses-group.component.ts @@ -32,9 +32,7 @@ mat-dialog-content { gap: 1rem; } `], - standalone: true, - providers: [ - ], + providers: [], imports: [ MatDialogModule, MatButtonModule, diff --git a/src/app/components/statuses/manage-groups-dialog.component.spec.ts b/src/app/components/statuses/manage-groups-dialog.component.spec.ts index d6ed47cbe..5e0292396 100644 --- a/src/app/components/statuses/manage-groups-dialog.component.spec.ts +++ b/src/app/components/statuses/manage-groups-dialog.component.spec.ts @@ -2,7 +2,7 @@ import { TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { TestBed } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { StatusService } from '@app/types/status'; import { IconsService } from '@services/icons.service'; import { Observable, of } from 'rxjs'; import { ManageGroupsDialogComponent } from './manage-groups-dialog.component'; @@ -31,6 +31,26 @@ describe('ManageGroupsDialogComponent', () => { close: jest.fn() }; + const mockStatusService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + color: 'red' + }, + [TaskStatus.TASK_STATUS_PROCESSING]: { + label: 'Processing', + color: 'green' + }, + [TaskStatus.TASK_STATUS_COMPLETED]: { + label: 'Completed', + color: 'yellow' + } + }, + statusToLabel: jest.fn((s: TaskStatus) => { + return (mockStatusService.statuses[s]); + }), + } as unknown as StatusService; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ @@ -38,7 +58,7 @@ describe('ManageGroupsDialogComponent', () => { { provide: MatDialog, useValue: mockMatDialog }, IconsService, { provide: DashboardIndexService, useValue: mockDashboardIndexService }, - TasksStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: MatDialogRef, useValue: mockMatDialogRef }, { provide: MAT_DIALOG_DATA, useValue: { groups: [ @@ -68,11 +88,7 @@ describe('ManageGroupsDialogComponent', () => { }); it('should get statuses labels', () => { - expect(component.statusToLabel(TaskStatus.TASK_STATUS_COMPLETED)).toEqual({ - color: '#006400', - icon: 'success', - label: 'Completed' - }); + expect(component.statusToLabel(TaskStatus.TASK_STATUS_COMPLETED)).toEqual(mockStatusService.statuses[TaskStatus.TASK_STATUS_COMPLETED]); }); it('should change array on drop', () => { diff --git a/src/app/components/statuses/manage-groups-dialog.component.ts b/src/app/components/statuses/manage-groups-dialog.component.ts index 1f21d8d48..f5418e65a 100644 --- a/src/app/components/statuses/manage-groups-dialog.component.ts +++ b/src/app/components/statuses/manage-groups-dialog.component.ts @@ -8,8 +8,10 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { ManageGroupsDialogData, ManageGroupsDialogResult, TasksStatusesGroup } from '@app/dashboard/types'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; -import { StatusLabelColor } from '@app/types/status'; +import { StatusLabelColor, StatusService } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; import { IconsService } from '@services/icons.service'; +import { StorageService } from '@services/storage.service'; import { AddStatusesGroupDialogComponent } from './add-statuses-group-dialog.component'; import { EditStatusesGroupDialogComponent } from './edit-status-group-dialog.component'; @@ -112,9 +114,13 @@ ul { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } `], - standalone: true, providers: [ - TasksStatusesService, + DefaultConfigService, + StorageService, + { + provide: StatusService, + useClass: TasksStatusesService + }, ], imports: [ MatButtonModule, @@ -135,7 +141,7 @@ export class ManageGroupsDialogComponent { private readonly dialog = inject(MatDialog); private readonly iconsServices = inject(IconsService); - private readonly tasksStatusesService = inject(TasksStatusesService); + private readonly tasksStatusesService = inject(StatusService) as TasksStatusesService; constructor( public _dialogRef: MatDialogRef, diff --git a/src/app/components/table-actions-toolbar.component.ts b/src/app/components/table-actions-toolbar.component.ts index b88883472..292405456 100644 --- a/src/app/components/table-actions-toolbar.component.ts +++ b/src/app/components/table-actions-toolbar.component.ts @@ -18,7 +18,6 @@ import { SpinnerComponent } from './spinner.component'; templateUrl: './table-actions-toolbar.component.html', styles: [` `], - standalone: true, providers: [], imports: [ RefreshButtonComponent, diff --git a/src/app/components/table-container.component.ts b/src/app/components/table-container.component.ts index 7ed69dfb7..c873011fc 100644 --- a/src/app/components/table-container.component.ts +++ b/src/app/components/table-container.component.ts @@ -20,10 +20,7 @@ import { Component } from '@angular/core'; overflow: auto; } `], - standalone: true, - providers: [ - ], - imports: [ - ] + providers: [], + imports: [] }) export class TableContainerComponent {} \ No newline at end of file diff --git a/src/app/components/table-dashboard-actions-toolbar.component.ts b/src/app/components/table-dashboard-actions-toolbar.component.ts index 2004f76f0..50288c8b6 100644 --- a/src/app/components/table-dashboard-actions-toolbar.component.ts +++ b/src/app/components/table-dashboard-actions-toolbar.component.ts @@ -9,7 +9,6 @@ import { TableActionsToolbarComponent } from './table-actions-toolbar.component' @Component({ selector: 'app-table-dashboard-actions-toolbar', templateUrl: './table-dashboard-actions-toolbar.component.html', - standalone: true, imports: [ TableActionsToolbarComponent, MatIconModule, diff --git a/src/app/components/table-index-actions-toolbar.component.ts b/src/app/components/table-index-actions-toolbar.component.ts index 37a7a1b5c..7eb97c0ec 100644 --- a/src/app/components/table-index-actions-toolbar.component.ts +++ b/src/app/components/table-index-actions-toolbar.component.ts @@ -9,7 +9,6 @@ import { TableActionsToolbarComponent } from './table-actions-toolbar.component' @Component({ selector: 'app-table-index-actions-toolbar', templateUrl: './table-index-actions-toolbar.component.html', - standalone: true, imports: [ TableActionsToolbarComponent, MatMenuModule, diff --git a/src/app/components/table/cells/byte-array-cell.component.ts b/src/app/components/table/cells/byte-array-cell.component.ts index 7147c4bdd..aa2ef0f5f 100644 --- a/src/app/components/table/cells/byte-array-cell.component.ts +++ b/src/app/components/table/cells/byte-array-cell.component.ts @@ -19,7 +19,6 @@ import { NotificationService } from '@services/notification.service'; selector: 'app-byte-array-cell', templateUrl: 'byte-array-cell.component.html', styleUrl: 'byte-array-cell.component.css', - standalone: true, imports: [ MatButtonModule, MatIconModule, diff --git a/src/app/components/table/table-actions.component.ts b/src/app/components/table/table-actions.component.ts index fecbf2c67..81c0d2cd5 100644 --- a/src/app/components/table/table-actions.component.ts +++ b/src/app/components/table/table-actions.component.ts @@ -10,7 +10,6 @@ import { IconsService } from '@services/icons.service'; @Component({ selector: 'app-table-actions', - standalone: true, templateUrl: './table-actions.component.html', styles: [` p { diff --git a/src/app/components/table/table-cell.component.spec.ts b/src/app/components/table/table-cell.component.spec.ts index aaac021f9..90499e238 100644 --- a/src/app/components/table/table-cell.component.spec.ts +++ b/src/app/components/table/table-cell.component.spec.ts @@ -1,11 +1,11 @@ import { SessionStatus } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; -import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { SessionRaw, SessionRawColumnKey } from '@app/sessions/types'; import { TaskOptions, TaskSummaryFilters } from '@app/tasks/types'; import { TableColumn } from '@app/types/column.type'; import { ApplicationData, ArmonikData, DataRaw, PartitionData, SessionData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { Timestamp } from '@ngx-grpc/well-known-types'; import { TableCellComponent } from './table-cell.component'; @@ -68,6 +68,23 @@ describe('TableCellComponent', () => { navigate: jest.fn() }; + const mockStatusService = { + statuses: { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [SessionStatus.SESSION_STATUS_CLOSED]: { + label: 'Closed' + }, + [SessionStatus.SESSION_STATUS_RUNNING]: { + label: 'Running', + } + }, + statusToLabel: jest.fn((s: SessionStatus) => { + return (mockStatusService.statuses[s]); + }), + } as unknown as StatusService; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ @@ -76,7 +93,7 @@ describe('TableCellComponent', () => { ] }).inject(TableCellComponent); - component.statusesService = new SessionsStatusesService(); + component.statusesService = mockStatusService; component.column = column; component.element = element; }); @@ -189,11 +206,7 @@ describe('TableCellComponent', () => { }); it('should get status label', () => { - expect(component.statusLabel()).toEqual({ - color: '#008000', - icon: 'play', - label: 'Running' - }); + expect(component.statusLabel()).toEqual(mockStatusService.statuses[SessionStatus.SESSION_STATUS_RUNNING]); }); }); diff --git a/src/app/components/table/table-cell.component.ts b/src/app/components/table/table-cell.component.ts index 13d803fa3..aedb52e02 100644 --- a/src/app/components/table/table-cell.component.ts +++ b/src/app/components/table/table-cell.component.ts @@ -20,7 +20,6 @@ import { TableInspectObjectComponent } from './table-inspect-object.component'; @Component({ selector: 'app-table-cell', - standalone: true, templateUrl: './table-cell.component.html', imports: [ EmptyCellPipe, diff --git a/src/app/components/table/table-column-header.component.html b/src/app/components/table/table-column-header.component.html index ca32b1651..2b0cd4817 100644 --- a/src/app/components/table/table-column-header.component.html +++ b/src/app/components/table/table-column-header.component.html @@ -1,5 +1,8 @@ -@if (type !== 'count' && type !== 'select') { +@if (type !== 'count' && type !== 'select' && type !== 'status') { {{ name }} +} @else if (type === 'status') { + {{ name }} + } @else if(type === 'count') { {{ name }} diff --git a/src/app/components/table/table-column-header.component.ts b/src/app/components/table/table-column-header.component.ts index 7337ae1be..638a22697 100644 --- a/src/app/components/table/table-column-header.component.ts +++ b/src/app/components/table/table-column-header.component.ts @@ -6,15 +6,16 @@ import { TaskOptions } from '@app/tasks/types'; import { ColumnType, TableColumn } from '@app/types/column.type'; import { DataRaw } from '@app/types/data'; import { IconsService } from '@services/icons.service'; +import { StatusColorPickerComponent } from '../status-color-picker.component'; @Component({ selector: 'app-table-column-header', templateUrl: './table-column-header.component.html', - standalone: true, imports: [ MatCheckboxModule, MatIconModule, MatButtonModule, + StatusColorPickerComponent ] }) export class TableColumnHeaderComponent { diff --git a/src/app/components/table/table-empty-data.component.ts b/src/app/components/table/table-empty-data.component.ts index 866bee3b7..0d5fe4917 100644 --- a/src/app/components/table/table-empty-data.component.ts +++ b/src/app/components/table/table-empty-data.component.ts @@ -17,8 +17,7 @@ em { text-align: center; } `], - standalone: true, imports: [], - providers: [], + providers: [] }) export class TableEmptyDataComponent {} diff --git a/src/app/components/table/table-inspect-message-dialog.component.ts b/src/app/components/table/table-inspect-message-dialog.component.ts index b0b0a0a90..466ed9172 100644 --- a/src/app/components/table/table-inspect-message-dialog.component.ts +++ b/src/app/components/table/table-inspect-message-dialog.component.ts @@ -16,7 +16,6 @@ export interface TableInspectMessageDialogData { selector: 'app-inspect-message-dialog', templateUrl: 'table-inspect-message-dialog.component.html', styleUrl: 'table-inspect-message-dialog.component.css', - standalone: true, imports: [ MatCardModule, MatButtonModule, diff --git a/src/app/components/table/table-inspect-message.component.ts b/src/app/components/table/table-inspect-message.component.ts index cfeb14630..69e2a04a6 100644 --- a/src/app/components/table/table-inspect-message.component.ts +++ b/src/app/components/table/table-inspect-message.component.ts @@ -13,7 +13,6 @@ import { TableInspectMessageDialogComponent, TableInspectMessageDialogData } fro selector: 'app-table-inspect-message', templateUrl: 'table-inspect-message.component.html', styleUrl: 'table-inspect-message.component.css', - standalone: true, imports: [ MatDialogModule, MatButtonModule, diff --git a/src/app/components/table/table-inspect-object-dialog.component.ts b/src/app/components/table/table-inspect-object-dialog.component.ts index 8f4c83683..be275b890 100644 --- a/src/app/components/table/table-inspect-object-dialog.component.ts +++ b/src/app/components/table/table-inspect-object-dialog.component.ts @@ -13,13 +13,12 @@ export interface TableInspectObjectDialogData { templateUrl: './table-inspect-object-dialog.component.html', styles: [` `], - standalone: true, imports: [ ShowCardContentComponent, MatDialogModule, MatButtonModule ], - providers: [], + providers: [] }) export class TableInspectObjectDialogComponent implements OnInit { diff --git a/src/app/components/table/table-inspect-object.component.ts b/src/app/components/table/table-inspect-object.component.ts index 9a707c87e..234afdf48 100644 --- a/src/app/components/table/table-inspect-object.component.ts +++ b/src/app/components/table/table-inspect-object.component.ts @@ -1,4 +1,4 @@ -import { CommonModule } from '@angular/common'; + import { Component, Input, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; @@ -12,15 +12,13 @@ import { TableInspectObjectDialogComponent, TableInspectObjectDialogData } from templateUrl: './table-inspect-object.component.html', styles: [` `], - standalone: true, imports: [ MatTooltipModule, MatDialogModule, MatButtonModule, - MatIconModule, - CommonModule + MatIconModule ], - providers: [], + providers: [] }) export class TableInspectObjectComponent { diff --git a/src/app/components/table/table.component.ts b/src/app/components/table/table.component.ts index aa930eb71..ffa1c4621 100644 --- a/src/app/components/table/table.component.ts +++ b/src/app/components/table/table.component.ts @@ -20,7 +20,6 @@ import { TableEmptyDataComponent } from './table-empty-data.component'; @Component({ selector: 'app-table', templateUrl: './table.component.html', - standalone: true, imports: [ TableColumnHeaderComponent, TableCellComponent, diff --git a/src/app/components/view-tasks-by-status.component.ts b/src/app/components/view-tasks-by-status.component.ts index 2bc872d41..8e6956d85 100644 --- a/src/app/components/view-tasks-by-status.component.ts +++ b/src/app/components/view-tasks-by-status.component.ts @@ -34,7 +34,6 @@ import { SpinnerComponent } from './spinner.component'; min-width: 0; } `], - standalone: true, imports: [ RouterModule, SpinnerComponent, diff --git a/src/app/dashboard/components/add-line-dialog.component.ts b/src/app/dashboard/components/add-line-dialog.component.ts index a88426174..2789e6e90 100644 --- a/src/app/dashboard/components/add-line-dialog.component.ts +++ b/src/app/dashboard/components/add-line-dialog.component.ts @@ -21,7 +21,6 @@ mat-dialog-content { gap: 1rem; } `], - standalone: true, providers: [], imports: [ MatDialogModule, diff --git a/src/app/dashboard/components/edit-name-line-dialog.component.ts b/src/app/dashboard/components/edit-name-line-dialog.component.ts index 1e0dda0e2..bc1ad6491 100644 --- a/src/app/dashboard/components/edit-name-line-dialog.component.ts +++ b/src/app/dashboard/components/edit-name-line-dialog.component.ts @@ -8,9 +8,7 @@ import { EditNameLineData } from '@app/types/dialog'; @Component({ selector: 'app-edit-name-line-dialog', templateUrl: 'edit-name-line-dialog.component.html', - standalone: true, - providers: [ - ], + providers: [], imports: [ MatDialogModule, MatInputModule, diff --git a/src/app/dashboard/components/lines/applications-line.component.ts b/src/app/dashboard/components/lines/applications-line.component.ts index e4de80d3a..4755f2743 100644 --- a/src/app/dashboard/components/lines/applications-line.component.ts +++ b/src/app/dashboard/components/lines/applications-line.component.ts @@ -24,7 +24,6 @@ import { ShareUrlService } from '@services/share-url.service'; @Component({ selector: 'app-dashboard-applications-line', templateUrl: './applications-line.component.html', - standalone: true, providers: [ ShareUrlService, AutoRefreshService, diff --git a/src/app/dashboard/components/lines/partitions-line.component.ts b/src/app/dashboard/components/lines/partitions-line.component.ts index 8d4f8cc35..7d08342b6 100644 --- a/src/app/dashboard/components/lines/partitions-line.component.ts +++ b/src/app/dashboard/components/lines/partitions-line.component.ts @@ -20,7 +20,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-dashboard-partitions-line', templateUrl: './partitions-line.component.html', - standalone: true, providers: [ PartitionsIndexService, NotificationService, diff --git a/src/app/dashboard/components/lines/results-line.component.ts b/src/app/dashboard/components/lines/results-line.component.ts index e0d793d28..1f2c54283 100644 --- a/src/app/dashboard/components/lines/results-line.component.ts +++ b/src/app/dashboard/components/lines/results-line.component.ts @@ -13,6 +13,7 @@ import { ResultsStatusesService } from '@app/results/services/results-statuses.s import { ResultRaw } from '@app/results/types'; import { DashboardLineTableComponent } from '@app/types/components/dashboard-line-table'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { TableDashboardActionsToolbarComponent } from '@components/table-dashboard-actions-toolbar.component'; import { FiltersService } from '@services/filters.service'; @@ -22,7 +23,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-dashboard-results-line', templateUrl: './results-line.component.html', - standalone: true, providers: [ MatSnackBar, ResultsIndexService, @@ -33,7 +33,10 @@ import { NotificationService } from '@services/notification.service'; }, ResultsDataService, ResultsGrpcService, - ResultsStatusesService, + { + provide: StatusService, + useClass: ResultsStatusesService, + }, GrpcSortFieldService, FiltersService, NotificationService, diff --git a/src/app/dashboard/components/lines/sessions-line.component.ts b/src/app/dashboard/components/lines/sessions-line.component.ts index 055436ae0..dffd7077b 100644 --- a/src/app/dashboard/components/lines/sessions-line.component.ts +++ b/src/app/dashboard/components/lines/sessions-line.component.ts @@ -17,6 +17,7 @@ import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service import { TaskOptions } from '@app/tasks/types'; import { DashboardLineCustomColumnsComponent } from '@app/types/components/dashboard-line-table'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { TableDashboardActionsToolbarComponent } from '@components/table-dashboard-actions-toolbar.component'; import { FiltersService } from '@services/filters.service'; @@ -26,7 +27,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-dashboard-sessions-line', templateUrl: './sessions-line.component.html', - standalone: true, providers: [ MatSnackBar, NotificationService, @@ -36,7 +36,10 @@ import { NotificationService } from '@services/notification.service'; useExisting: SessionsFiltersService }, SessionsIndexService, - SessionsStatusesService, + { + provide: StatusService, + useClass: SessionsStatusesService, + }, TasksStatusesService, TasksFiltersService, SessionsGrpcService, @@ -52,7 +55,7 @@ import { NotificationService } from '@services/notification.service'; SessionsTableComponent, MatIconModule, MatMenuModule, - ], + ] }) export class SessionsLineComponent extends DashboardLineCustomColumnsComponent implements OnInit, AfterViewInit, OnDestroy { readonly indexService = inject(SessionsIndexService); diff --git a/src/app/dashboard/components/lines/task-by-status-line.component.ts b/src/app/dashboard/components/lines/task-by-status-line.component.ts index 9f2b155b8..d78ab7cf7 100644 --- a/src/app/dashboard/components/lines/task-by-status-line.component.ts +++ b/src/app/dashboard/components/lines/task-by-status-line.component.ts @@ -11,6 +11,7 @@ import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service import { StatusCount, TaskSummaryFilters } from '@app/tasks/types'; import { EditNameLineData } from '@app/types/dialog'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { ActionsToolbarGroupComponent } from '@components/actions-toolbar-group.component'; import { ActionsToolbarComponent } from '@components/actions-toolbar.component'; import { AutoRefreshButtonComponent } from '@components/auto-refresh-button.component'; @@ -48,9 +49,7 @@ app-actions-toolbar { grid-gap: 1rem; } `], - standalone: true, providers: [ - TasksStatusesService, ShareUrlService, QueryParamsService, TasksGrpcService, @@ -66,6 +65,10 @@ app-actions-toolbar { }, GrpcSortFieldService, NotificationService, + { + provide: StatusService, + useClass: TasksStatusesService, + } ], imports: [ ActionsToolbarComponent, diff --git a/src/app/dashboard/components/lines/tasks-line.component.ts b/src/app/dashboard/components/lines/tasks-line.component.ts index 5435eb0af..7b084b858 100644 --- a/src/app/dashboard/components/lines/tasks-line.component.ts +++ b/src/app/dashboard/components/lines/tasks-line.component.ts @@ -11,10 +11,12 @@ import TasksDataService from '@app/tasks/services/tasks-data.service'; import { TasksFiltersService } from '@app/tasks/services/tasks-filters.service'; import { TasksGrpcService } from '@app/tasks/services/tasks-grpc.service'; import { TasksIndexService } from '@app/tasks/services/tasks-index.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { TaskOptions, TaskSummary } from '@app/tasks/types'; import { DashboardLineCustomColumnsComponent } from '@app/types/components/dashboard-line-table'; import { ManageViewInLogsDialogData, ManageViewInLogsDialogResult } from '@app/types/dialog'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { TableDashboardActionsToolbarComponent } from '@components/table-dashboard-actions-toolbar.component'; import { FiltersService } from '@services/filters.service'; @@ -24,7 +26,6 @@ import { NotificationService } from '@services/notification.service'; @Component({ selector: 'app-dashboard-tasks-line', templateUrl: './tasks-line.component.html', - standalone: true, providers: [ MatSnackBar, TasksIndexService, @@ -38,6 +39,10 @@ import { NotificationService } from '@services/notification.service'; GrpcSortFieldService, TasksDataService, FiltersService, + { + provide: StatusService, + useClass: TasksStatusesService, + } ], imports: [ MatToolbarModule, diff --git a/src/app/dashboard/components/reorganize-lines-dialog.component.ts b/src/app/dashboard/components/reorganize-lines-dialog.component.ts index 13832e790..1a5a10ff2 100644 --- a/src/app/dashboard/components/reorganize-lines-dialog.component.ts +++ b/src/app/dashboard/components/reorganize-lines-dialog.component.ts @@ -56,7 +56,6 @@ import { Line } from '../types'; transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } `], - standalone: true, providers: [ IconsService, ], diff --git a/src/app/dashboard/components/split-lines-dialog.component.ts b/src/app/dashboard/components/split-lines-dialog.component.ts index 8fb8863b8..655a4025a 100644 --- a/src/app/dashboard/components/split-lines-dialog.component.ts +++ b/src/app/dashboard/components/split-lines-dialog.component.ts @@ -29,7 +29,6 @@ mat-form-field { width: 100%; } `], - standalone: true, providers: [], imports: [ MatInputModule, diff --git a/src/app/dashboard/components/statuses-group-card.component.spec.ts b/src/app/dashboard/components/statuses-group-card.component.spec.ts index e7251fd35..615601ae9 100644 --- a/src/app/dashboard/components/statuses-group-card.component.spec.ts +++ b/src/app/dashboard/components/statuses-group-card.component.spec.ts @@ -1,13 +1,29 @@ import { FilterDateOperator, FilterStringOperator, TaskStatus, TaskSummaryEnumField } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; -import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { TaskSummaryFilters } from '@app/tasks/types'; +import { StatusService } from '@app/types/status'; import { FiltersService } from '@services/filters.service'; import { StatusesGroupCardComponent } from './statuses-group-card.component'; describe('StatusesGroupCardComponent', () => { let component: StatusesGroupCardComponent; + const mockStatusService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + color: 'red' + }, + [TaskStatus.TASK_STATUS_PROCESSING]: { + label: 'Processing', + color: 'green' + } + }, + statusToLabel: jest.fn((s: TaskStatus) => { + return (mockStatusService.statuses[s]); + }), + } as unknown as StatusService; + const filters: TaskSummaryFilters = [ [ { @@ -43,7 +59,7 @@ describe('StatusesGroupCardComponent', () => { component = TestBed.configureTestingModule({ providers: [ StatusesGroupCardComponent, - TasksStatusesService, + { provide: StatusService, useValue: mockStatusService }, FiltersService ] }).inject(StatusesGroupCardComponent); @@ -58,11 +74,7 @@ describe('StatusesGroupCardComponent', () => { }); it('should get labels', () => { - expect(component.statusToLabel(TaskStatus.TASK_STATUS_COMPLETED)).toEqual({ - label: 'Completed', - color: '#006400', - icon: 'success', - }); + expect(component.statusToLabel(TaskStatus.TASK_STATUS_PROCESSING)).toEqual(mockStatusService.statuses[TaskStatus.TASK_STATUS_PROCESSING]); }); it('should update counter', () => { diff --git a/src/app/dashboard/components/statuses-group-card.component.ts b/src/app/dashboard/components/statuses-group-card.component.ts index d7daa19ac..0044e2050 100644 --- a/src/app/dashboard/components/statuses-group-card.component.ts +++ b/src/app/dashboard/components/statuses-group-card.component.ts @@ -5,8 +5,10 @@ import { RouterModule } from '@angular/router'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { StatusCount, TaskSummaryFilters } from '@app/tasks/types'; import { Filter } from '@app/types/filters'; -import { StatusLabelColor } from '@app/types/status'; +import { StatusLabelColor, StatusService } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; import { FiltersService } from '@services/filters.service'; +import { StorageService } from '@services/storage.service'; import { TasksStatusesGroup } from '../types'; @Component({ @@ -40,9 +42,13 @@ ul li a { text-decoration: none; } `], - standalone: true, providers: [ - TasksStatusesService, + DefaultConfigService, + StorageService, + { + provide: StatusService, + useClass: TasksStatusesService + }, FiltersService, ], imports: [ @@ -57,7 +63,7 @@ export class StatusesGroupCardComponent { @Input({ required: true }) data: StatusCount[] = []; @Input({ required: true }) filters: TaskSummaryFilters; - private readonly tasksStatusesService = inject(TasksStatusesService); + private readonly tasksStatusesService = inject(StatusService) as TasksStatusesService; private readonly filtersService = inject(FiltersService); statusToLabel(status: TaskStatus): StatusLabelColor { diff --git a/src/app/dashboard/index.component.ts b/src/app/dashboard/index.component.ts index f3ca934ae..dadcaec74 100644 --- a/src/app/dashboard/index.component.ts +++ b/src/app/dashboard/index.component.ts @@ -10,15 +10,9 @@ import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { AddLineDialogData, AddLineDialogResult, ReorganizeLinesDialogData, ReorganizeLinesDialogResult, SplitLinesDialogData, SplitLinesDialogResult } from '@app/types/dialog'; -import { ActionsToolbarGroupComponent } from '@components/actions-toolbar-group.component'; -import { ActionsToolbarComponent } from '@components/actions-toolbar.component'; -import { AutoRefreshButtonComponent } from '@components/auto-refresh-button.component'; -import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { PageHeaderComponent } from '@components/page-header.component'; import { PageSectionHeaderComponent } from '@components/page-section-header.component'; import { PageSectionComponent } from '@components/page-section.component'; -import { RefreshButtonComponent } from '@components/refresh-button.component'; -import { SpinnerComponent } from '@components/spinner.component'; import { AutoRefreshService } from '@services/auto-refresh.service'; import { FiltersService } from '@services/filters.service'; import { IconsService } from '@services/icons.service'; @@ -86,7 +80,6 @@ import { Line, LineType } from './types'; margin-bottom: 2rem } `], - standalone: true, providers: [ ShareUrlService, QueryParamsService, @@ -106,12 +99,7 @@ import { Line, LineType } from './types'; imports: [ PageHeaderComponent, PageSectionComponent, - SpinnerComponent, PageSectionHeaderComponent, - ActionsToolbarComponent, - ActionsToolbarGroupComponent, - RefreshButtonComponent, - AutoRefreshButtonComponent, MatIconModule, MatToolbarModule, MatButtonModule, @@ -120,7 +108,6 @@ import { Line, LineType } from './types'; MatCardModule, MatTooltipModule, MatProgressSpinnerModule, - FiltersToolbarComponent, TaskByStatusLineComponent, ApplicationsLineComponent, ResultsLineComponent, diff --git a/src/app/directives/no-wrap.directive.ts b/src/app/directives/no-wrap.directive.ts index 6a6e7a787..1c3647806 100644 --- a/src/app/directives/no-wrap.directive.ts +++ b/src/app/directives/no-wrap.directive.ts @@ -1,6 +1,6 @@ import { Directive, ElementRef } from '@angular/core'; -@Directive({ selector: '[appNoWrap]', standalone: true }) +@Directive({ selector: '[appNoWrap]' }) export class NoWrapDirective { constructor(private readonly el: ElementRef) { this.el.nativeElement.style.whiteSpace = 'nowrap'; diff --git a/src/app/healthcheck/healthcheck.component.ts b/src/app/healthcheck/healthcheck.component.ts index e84f91c7d..ff4c0e55b 100644 --- a/src/app/healthcheck/healthcheck.component.ts +++ b/src/app/healthcheck/healthcheck.component.ts @@ -16,7 +16,6 @@ import { Observable, Subject, catchError, of, startWith, switchMap } from 'rxjs' @Component({ selector: 'app-healthcheck', - standalone: true, templateUrl: './healthcheck.component.html', styles: [` .health-color { diff --git a/src/app/initialisation/date-adapter.ts b/src/app/initialisation/date-adapter.ts new file mode 100644 index 000000000..4b0cf7f73 --- /dev/null +++ b/src/app/initialisation/date-adapter.ts @@ -0,0 +1,28 @@ +import { makeEnvironmentProviders } from '@angular/core'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core'; +import { MomentDateAdapter } from '@angular/material-moment-adapter'; + +/** + * All formats used by the MomentDateAdapter + */ +const ARMONIK_DATE_FORMAT: MatDateFormats = { + parse: { + dateInput: 'DD/MM/YYYY HH:mm:ss', + }, + display: { + dateInput: 'DD/MM/YYYY HH:mm:ss', + monthYearLabel: 'MMMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY' + } +}; + +/** + * Provides services and date format to display for the DateTime picker component. + */ +export function provideArmonikDateAdapter() { + return makeEnvironmentProviders([ + { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, + { provide: MAT_DATE_FORMATS, useValue: ARMONIK_DATE_FORMAT } + ]); +} \ No newline at end of file diff --git a/src/app/partitions/components/table.component.ts b/src/app/partitions/components/table.component.ts index a39e62491..a75533d8b 100644 --- a/src/app/partitions/components/table.component.ts +++ b/src/app/partitions/components/table.component.ts @@ -10,7 +10,6 @@ import { PartitionRaw } from '../types'; @Component({ selector: 'app-partitions-table', - standalone: true, templateUrl: './table.component.html', providers: [ TasksByStatusService, diff --git a/src/app/partitions/index.component.ts b/src/app/partitions/index.component.ts index 6b617c490..9dffbc988 100644 --- a/src/app/partitions/index.component.ts +++ b/src/app/partitions/index.component.ts @@ -36,7 +36,6 @@ import { PartitionRaw } from './types'; @Component({ selector: 'app-partitions-index', templateUrl: './index.component.html', - standalone: true, providers: [ ShareUrlService, QueryParamsService, diff --git a/src/app/partitions/show.component.ts b/src/app/partitions/show.component.ts index 5cd13758e..a4985e842 100644 --- a/src/app/partitions/show.component.ts +++ b/src/app/partitions/show.component.ts @@ -24,7 +24,6 @@ import { PartitionRaw } from './types'; selector: 'app-partitions-show', templateUrl: 'show.component.html', styleUrl: '../../inspections.css', - standalone: true, providers: [ UtilsService, ShareUrlService, diff --git a/src/app/pipes/duration.pipe.ts b/src/app/pipes/duration.pipe.ts index cdd997992..be8c7a496 100644 --- a/src/app/pipes/duration.pipe.ts +++ b/src/app/pipes/duration.pipe.ts @@ -1,7 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Duration } from '@ngx-grpc/well-known-types'; -@Pipe({ name: 'duration', standalone: true }) +@Pipe({ name: 'duration' }) export class DurationPipe implements PipeTransform { transform(value: Duration | null | undefined) { if (!value) { diff --git a/src/app/pipes/empty-cell.pipe.ts b/src/app/pipes/empty-cell.pipe.ts index 7e52d24da..07c8a597e 100644 --- a/src/app/pipes/empty-cell.pipe.ts +++ b/src/app/pipes/empty-cell.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ name: 'emptyCell', standalone: true }) +@Pipe({ name: 'emptyCell' }) export class EmptyCellPipe implements PipeTransform { transform(value: unknown) { if (value === undefined || value === null || value === '') { diff --git a/src/app/pipes/pretty.pipe.ts b/src/app/pipes/pretty.pipe.ts index f9573bd92..d0b0f8809 100644 --- a/src/app/pipes/pretty.pipe.ts +++ b/src/app/pipes/pretty.pipe.ts @@ -7,7 +7,7 @@ import { Pipe, PipeTransform } from '@angular/core'; * @param key string to format * @returns formatted string */ -@Pipe({ name: 'pretty', standalone: true }) +@Pipe({ name: 'pretty' }) export class PrettyPipe implements PipeTransform { transform(key: string | number | symbol) { return key.toString().replaceAll('_', '').replace(/(? str.toUpperCase()); diff --git a/src/app/profile/index.component.ts b/src/app/profile/index.component.ts index 599073d48..7119911dc 100644 --- a/src/app/profile/index.component.ts +++ b/src/app/profile/index.component.ts @@ -10,7 +10,7 @@ import { Group, PermissionGroup, isGroup } from './types'; @Component({ selector: 'app-profile-index', - templateUrl: './index.component.html', + templateUrl: './index.component.html', styles: [` .permissions { display: grid; @@ -39,7 +39,6 @@ import { Group, PermissionGroup, isGroup } from './types'; margin: 0; } `], - standalone: true, providers: [ QueryParamsService, ], diff --git a/src/app/results/components/table.component.spec.ts b/src/app/results/components/table.component.spec.ts index 6a01d8d67..6b64c5412 100644 --- a/src/app/results/components/table.component.spec.ts +++ b/src/app/results/components/table.component.spec.ts @@ -1,11 +1,12 @@ +import { ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; import { Clipboard } from '@angular/cdk/clipboard'; import { TestBed } from '@angular/core/testing'; import { TableColumn } from '@app/types/column.type'; import { ColumnKey, ResultData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { NotificationService } from '@services/notification.service'; import { ResultsTableComponent } from './table.component'; import ResultsDataService from '../services/results-data.service'; -import { ResultsStatusesService } from '../services/results-statuses.service'; import { ResultRaw } from '../types'; describe('ResultsTableComponent', () => { @@ -59,11 +60,23 @@ describe('ResultsTableComponent', () => { }, }; + const mockStatusService = { + statuses: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed' + }, + }, + }; + + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ ResultsTableComponent, - ResultsStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: NotificationService, useValue: mockNotificationService }, { provide: Clipboard, useValue: mockClipBoard }, { provide: ResultsDataService, useValue: mockResultsDataService } diff --git a/src/app/results/components/table.component.ts b/src/app/results/components/table.component.ts index 46fec411e..48b30e481 100644 --- a/src/app/results/components/table.component.ts +++ b/src/app/results/components/table.component.ts @@ -2,6 +2,7 @@ import { ResultRawEnumField } from '@aneoconsultingfr/armonik.api.angular'; import { Component, OnInit, inject } from '@angular/core'; import { AbstractTableComponent } from '@app/types/components/table'; import { ArmonikData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { TableComponent } from '@components/table/table.component'; import { NotificationService } from '@services/notification.service'; import ResultsDataService from '../services/results-data.service'; @@ -10,8 +11,7 @@ import { ResultRaw } from '../types'; @Component({ selector: 'app-results-table', - standalone: true, - templateUrl: './table.component.html', + templateUrl: './table.component.html', providers: [ ResultsStatusesService, NotificationService, @@ -22,7 +22,7 @@ import { ResultRaw } from '../types'; }) export class ResultsTableComponent extends AbstractTableComponent implements OnInit { readonly tableDataService = inject(ResultsDataService); - readonly statusesService = inject(ResultsStatusesService); + readonly statusesService: ResultsStatusesService = inject(StatusService); ngOnInit(): void { this.initTableDataService(); diff --git a/src/app/results/index.component.ts b/src/app/results/index.component.ts index ebb4b5368..9c9a0ecc6 100644 --- a/src/app/results/index.component.ts +++ b/src/app/results/index.component.ts @@ -7,9 +7,9 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatToolbarModule } from '@angular/material/toolbar'; import { DashboardIndexService } from '@app/dashboard/services/dashboard-index.service'; import { DashboardStorageService } from '@app/dashboard/services/dashboard-storage.service'; -import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; import { TableHandler } from '@app/types/components'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { TableType } from '@app/types/table'; import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { PageHeaderComponent } from '@components/page-header.component'; @@ -36,7 +36,6 @@ import { ResultRaw } from './types'; @Component({ selector: 'app-results-index', templateUrl: './index.component.html', - standalone: true, providers: [ ShareUrlService, QueryParamsService, @@ -51,12 +50,14 @@ import { ResultRaw } from './types'; provide: DataFilterService, useExisting: ResultsFiltersService, }, - ResultsStatusesService, + { + provide: StatusService, + useClass: ResultsStatusesService + }, TableStorageService, NotificationService, DashboardIndexService, DashboardStorageService, - TasksStatusesService, ResultsDataService, ResultsGrpcService, GrpcSortFieldService, diff --git a/src/app/results/services/results-filters.service.spec.ts b/src/app/results/services/results-filters.service.spec.ts index ec5b2e598..644a85adf 100644 --- a/src/app/results/services/results-filters.service.spec.ts +++ b/src/app/results/services/results-filters.service.spec.ts @@ -1,11 +1,11 @@ -import { FilterDateOperator, FilterStringOperator, ResultRawEnumField } from '@aneoconsultingfr/armonik.api.angular'; +import { FilterDateOperator, FilterStringOperator, ResultRawEnumField, ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { FiltersOr } from '@app/types/filters'; +import { StatusService } from '@app/types/status'; import { DefaultConfigService } from '@services/default-config.service'; import { FiltersCacheService } from '@services/filters-cache.service'; import { TableService } from '@services/table.service'; import { ResultsFiltersService } from './results-filters.service'; -import { ResultsStatusesService } from './results-statuses.service'; import { ResultRawFilters } from '../types'; describe('ResultsFilterService', () => { @@ -41,12 +41,23 @@ describe('ResultsFilterService', () => { get: jest.fn(() => cachedFilters), }; + const mockStatusService = { + statuses: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: 'Completed' + }, + }, + }; + beforeEach(() => { service = TestBed.configureTestingModule({ providers: [ ResultsFiltersService, - ResultsStatusesService, DefaultConfigService, + { provide: StatusService, useValue: mockStatusService }, { provide: TableService, useValue: mockTableService }, { provide: FiltersCacheService, useValue: mockFiltersCacheService } ] diff --git a/src/app/results/services/results-filters.service.ts b/src/app/results/services/results-filters.service.ts index 88111f1a4..1061eb602 100644 --- a/src/app/results/services/results-filters.service.ts +++ b/src/app/results/services/results-filters.service.ts @@ -3,6 +3,7 @@ import { Injectable, inject } from '@angular/core'; import { Scope } from '@app/types/config'; import { FilterFor } from '@app/types/filter-definition'; import { DataFilterService, FiltersServiceStatusesInterface } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { ResultsStatusesService } from './results-statuses.service'; import { ResultFilterField, ResultRawFilters, ResultsFiltersDefinition } from '../types'; @@ -11,7 +12,7 @@ import { ResultFilterField, ResultRawFilters, ResultsFiltersDefinition } from '. }) export class ResultsFiltersService extends DataFilterService implements FiltersServiceStatusesInterface { protected readonly scope: Scope = 'results'; - readonly statusService = inject(ResultsStatusesService); + readonly statusService: ResultsStatusesService = inject(StatusService); readonly rootField: Record = { [ResultRawEnumField.RESULT_RAW_ENUM_FIELD_COMPLETED_AT]: $localize`Completed at`, diff --git a/src/app/results/services/results-grpc.service.spec.ts b/src/app/results/services/results-grpc.service.spec.ts index 9f8ea4a79..ade812ef1 100644 --- a/src/app/results/services/results-grpc.service.spec.ts +++ b/src/app/results/services/results-grpc.service.spec.ts @@ -4,7 +4,6 @@ import { ListOptionsSort } from '@app/types/options'; import { UtilsService } from '@services/utils.service'; import { ResultsFiltersService } from './results-filters.service'; import { ResultsGrpcService } from './results-grpc.service'; -import { ResultsStatusesService } from './results-statuses.service'; import { ResultRaw, ResultRawFilters, ResultRawListOptions } from '../types'; describe('ResultsGrpcService', () => { @@ -56,7 +55,6 @@ describe('ResultsGrpcService', () => { } }; - const resultStatusesService = new ResultsStatusesService(); const mockResultsFiltersService = { filtersDefinitions: [ { @@ -68,12 +66,16 @@ describe('ResultsGrpcService', () => { for: 'root', field: ResultRawEnumField.RESULT_RAW_ENUM_FIELD_STATUS, type: 'status', - statuses: Object.keys(resultStatusesService.statuses).map(status => { - return { - key: status, - value: resultStatusesService.statuses[Number(status) as ResultStatus], - }; - }), + statuses: [ + { + key: ResultStatus.RESULT_STATUS_COMPLETED, + value: 'Completed', + }, + { + key: ResultStatus.RESULT_STATUS_CREATED, + value: 'Created', + } + ] }, { for: 'root', diff --git a/src/app/results/services/results-status.service.spec.ts b/src/app/results/services/results-status.service.spec.ts index 81cc13948..58b68599e 100644 --- a/src/app/results/services/results-status.service.spec.ts +++ b/src/app/results/services/results-status.service.spec.ts @@ -1,10 +1,93 @@ import { ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { StatusLabelColor } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; +import { StorageService } from '@services/storage.service'; import { ResultsStatusesService } from './results-statuses.service'; describe('ResultsStatusService', () => { - const service = new ResultsStatusesService(); + let service: ResultsStatusesService; + + const mockDefaultStatuses = { + [ResultStatus.RESULT_STATUS_ABORTED]: { + color: 'red', + label: 'Aborted' + } + }; + + const mockDefaultConfigService = { + exportedDefaultConfig: { + 'results-statuses': mockDefaultStatuses, + }, + }; + + const mockStoredStatuses = { + [ResultStatus.RESULT_STATUS_ABORTED]: { + color: 'blue', + label: 'Aborted' + } + }; + + const mockStorageService = { + getItem: jest.fn((): unknown => mockStoredStatuses), + setItem: jest.fn(), + }; + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + ResultsStatusesService, + { provide: DefaultConfigService, useValue: mockDefaultConfigService }, + { provide: StorageService, useValue: mockStorageService }, + ] + }).inject(ResultsStatusesService); + }); + + it('should create', () => { + expect(service).toBeTruthy(); + }); + + describe('initialisation', () => { + beforeEach(() => { + mockStorageService.getItem.mockReturnValueOnce(null); + }); + + it('should init the statuses with stored config', () => { + expect(service.statuses).toEqual(mockStoredStatuses); + }); + + it('should init the statuses with default config', () => { + const serviceWithDefault = TestBed.inject(ResultsStatusesService); + expect(serviceWithDefault.statuses).toEqual(mockDefaultStatuses); + }); + }); + + describe('updateStatuses', () => { + const newStatuses = { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Aborted', + color: 'green', + } + } as Record; + + beforeEach(() => { + service.updateStatuses(newStatuses); + }); + + it('should update the statuses', () => { + expect(service.statuses[ResultStatus.RESULT_STATUS_ABORTED]).toEqual(newStatuses[ResultStatus.RESULT_STATUS_ABORTED]); + }); + + it('should store the new statuses', () => { + expect(mockStorageService.setItem).toHaveBeenCalledWith('results-statuses', service.statuses); + }); + }); + + it('should retrieve the default statuses config', () => { + expect(service.getDefault()).toEqual(mockDefaultConfigService.exportedDefaultConfig['results-statuses']); + }); it('should return the correct status label', () => { - expect(service.statusToLabel(ResultStatus.RESULT_STATUS_COMPLETED)).toBeDefined(); + expect(service.statusToLabel(ResultStatus.RESULT_STATUS_ABORTED)).toBeDefined(); }); }); \ No newline at end of file diff --git a/src/app/results/services/results-statuses.service.ts b/src/app/results/services/results-statuses.service.ts index 5443c84a4..a9a9171c7 100644 --- a/src/app/results/services/results-statuses.service.ts +++ b/src/app/results/services/results-statuses.service.ts @@ -1,37 +1,10 @@ import { ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; import { Injectable } from '@angular/core'; -import { StatusLabelColor, StatusService } from '@app/types/status'; +import { StatusService } from '@app/types/status'; @Injectable() export class ResultsStatusesService extends StatusService { - readonly statuses: Record = { - [ResultStatus.RESULT_STATUS_UNSPECIFIED]: { - label: $localize`Unspecified`, - color: '#696969', - }, - [ResultStatus.RESULT_STATUS_CREATED]: { - label: $localize`Created`, - color: '#008B8B', - icon: 'add', - }, - [ResultStatus.RESULT_STATUS_COMPLETED]: { - label: $localize`Completed`, - color: '#006400', - icon: 'success', - }, - [ResultStatus.RESULT_STATUS_ABORTED]: { - label: $localize`Aborted`, - color: '#800080', - icon: 'cancel' - }, - [ResultStatus.RESULT_STATUS_DELETED]: { - label: $localize`Deleted`, - color: '#000000', - icon: 'delete', - }, - [ResultStatus.RESULT_STATUS_NOTFOUND]: { - label: $localize`Not found`, - color: '#696969' - }, - }; + constructor() { + super('results'); + } } diff --git a/src/app/results/show.component.spec.ts b/src/app/results/show.component.spec.ts index 333ebfa6b..583ae98c1 100644 --- a/src/app/results/show.component.spec.ts +++ b/src/app/results/show.component.spec.ts @@ -1,6 +1,7 @@ import { GetResultResponse, ResultStatus } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; +import { StatusService } from '@app/types/status'; import { GrpcStatusEvent } from '@ngx-grpc/common'; import { FiltersService } from '@services/filters.service'; import { IconsService } from '@services/icons.service'; @@ -9,7 +10,6 @@ import { ShareUrlService } from '@services/share-url.service'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { ResultsGrpcService } from './services/results-grpc.service'; import { ResultsInspectionService } from './services/results-inspection.service'; -import { ResultsStatusesService } from './services/results-statuses.service'; import { ShowComponent } from './show.component'; import { ResultRaw } from './types'; @@ -43,13 +43,26 @@ describe('ShowComponent', () => { get$: jest.fn((): Observable => of({result: returnedResult} as GetResultResponse)), }; + const mockStatusService = { + statuses: { + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: 'Cancelled', + color: 'red', + }, + [ResultStatus.RESULT_STATUS_CREATED]: { + label: 'Created', + color: 'green', + }, + } + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ ShowComponent, IconsService, FiltersService, - ResultsStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: NotificationService, useValue: mockNotificationService }, { provide: ShareUrlService, useValue: mockShareUrlService }, { provide: ActivatedRoute, useValue: mockActivatedRoute }, @@ -81,11 +94,7 @@ describe('ShowComponent', () => { describe('get status', () => { it('should return the status label if there is data', () => { component.refresh.next(); - expect(component.status).toEqual({ - label: 'Created', - color: '#008B8B', - icon: 'add', - }); + expect(component.status).toEqual(mockStatusService.statuses[ResultStatus.RESULT_STATUS_CREATED]); }); it('should return undefined if there is no data', () => { @@ -161,6 +170,6 @@ describe('ShowComponent', () => { }); it('should get statuses', () => { - expect(component.statuses).toEqual((new ResultsStatusesService).statuses); + expect(component.statuses).toEqual(mockStatusService.statuses); }); }); \ No newline at end of file diff --git a/src/app/results/show.component.ts b/src/app/results/show.component.ts index 132f6d850..0c855414e 100644 --- a/src/app/results/show.component.ts +++ b/src/app/results/show.component.ts @@ -5,11 +5,13 @@ import { MatIconModule } from '@angular/material/icon'; import { MatSnackBar } from '@angular/material/snack-bar'; import { RouterModule } from '@angular/router'; import { AppShowComponent } from '@app/types/components/show'; -import { StatusLabelColor } from '@app/types/status'; +import { StatusLabelColor, StatusService } from '@app/types/status'; import { ShowPageComponent } from '@components/show-page.component'; +import { DefaultConfigService } from '@services/default-config.service'; import { NotificationService } from '@services/notification.service'; import { QueryParamsService } from '@services/query-params.service'; import { ShareUrlService } from '@services/share-url.service'; +import { StorageService } from '@services/storage.service'; import { TableStorageService } from '@services/table-storage.service'; import { TableURLService } from '@services/table-url.service'; import { TableService } from '@services/table.service'; @@ -24,13 +26,11 @@ import { ResultRaw } from './types'; selector: 'app-result-show', templateUrl: 'show.component.html', styleUrl: '../../inspections.css', - standalone: true, providers: [ UtilsService, ShareUrlService, QueryParamsService, ResultsGrpcService, - ResultsStatusesService, TableService, TableStorageService, TableURLService, @@ -38,6 +38,12 @@ import { ResultRaw } from './types'; NotificationService, MatSnackBar, ResultsInspectionService, + DefaultConfigService, + StorageService, + { + provide: StatusService, + useClass: ResultsStatusesService + } ], imports: [ ShowPageComponent, @@ -51,7 +57,7 @@ export class ShowComponent extends AppShowComponent = { + [SessionStatus.SESSION_STATUS_UNSPECIFIED]: { + label: $localize`Unspecified`, + color: '#696969', + }, + [SessionStatus.SESSION_STATUS_RUNNING]: { + label: $localize`Running`, + color: '#339220', + icon: 'play', + }, + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: $localize`Cancelled`, + color: '#0E4D92', + icon: 'cancel', + }, + [SessionStatus.SESSION_STATUS_CLOSED]: { + label: $localize`Closed`, + color: '#F20707', + icon: 'close', + }, + [SessionStatus.SESSION_STATUS_DELETED]: { + label: $localize`Deleted`, + color: '#000000', + icon: 'delete', + }, + [SessionStatus.SESSION_STATUS_PURGED]: { + label: $localize`Purged`, + color: '#800080', + icon: 'purge', + }, + [SessionStatus.SESSION_STATUS_PAUSED]: { + label: $localize`Paused`, + color: '#FF8C00', + icon: 'pause', + }, + }; + readonly #defaultResults: ScopeConfig = { interval: 10, lockColumns: false, @@ -176,6 +214,37 @@ export class DefaultConfigService { showFilters: true, }; + readonly #defaultResultsStatuses: Record = { + [ResultStatus.RESULT_STATUS_UNSPECIFIED]: { + label: $localize`Unspecified`, + color: '#696969', + }, + [ResultStatus.RESULT_STATUS_CREATED]: { + label: $localize`Created`, + color: '#008B8B', + icon: 'add', + }, + [ResultStatus.RESULT_STATUS_COMPLETED]: { + label: $localize`Completed`, + color: '#339220', + icon: 'success', + }, + [ResultStatus.RESULT_STATUS_ABORTED]: { + label: $localize`Aborted`, + color: '#800080', + icon: 'cancel' + }, + [ResultStatus.RESULT_STATUS_DELETED]: { + label: $localize`Deleted`, + color: '#000000', + icon: 'delete', + }, + [ResultStatus.RESULT_STATUS_NOTFOUND]: { + label: $localize`Not found`, + color: '#696969' + }, + }; + readonly #defaultTasks: ScopeConfig = { interval: 10, lockColumns: false, @@ -206,6 +275,78 @@ export class DefaultConfigService { urlTemplate: null, }; + readonly #defaultTaskStatuses: Record = { + [TaskStatus.TASK_STATUS_COMPLETED]: { + label: 'Completed', + color: '#339220', + icon: 'success' + }, + [TaskStatus.TASK_STATUS_CREATING]: { + label: 'Creating', + color: '#008B8B', + icon: 'creating', + }, + [TaskStatus.TASK_STATUS_PROCESSING]: { + label: 'Processing', + color: '#320DE7', + icon: 'play' + }, + [TaskStatus.TASK_STATUS_PROCESSED]: { + label: 'Processed', + color: '#008B8B', + icon: 'processed' + }, + [TaskStatus.TASK_STATUS_PENDING]: { + label: $localize`Pending`, + color: '#696969', + icon: 'pending' + }, + [TaskStatus.TASK_STATUS_SUBMITTED]: { + label: 'Submitted', + color: '#00008B', + icon: 'submitting', + }, + [TaskStatus.TASK_STATUS_DISPATCHED]: { + label: 'Dispatched', + color: '#6495ED', + icon: 'dispatched', + }, + [TaskStatus.TASK_STATUS_CANCELLING]: { + label: 'Cancelling', + color: '#696969', + icon: 'cancelling', + }, + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + color: '#000000', + icon: 'cancel', + }, + [TaskStatus.TASK_STATUS_PAUSED]: { + label: $localize`Paused`, + color: '#FF8C00', + icon: 'pause', + }, + [TaskStatus.TASK_STATUS_ERROR]: { + label: 'Error', + color: '#F20707', + icon: 'error', + }, + [TaskStatus.TASK_STATUS_TIMEOUT]: { + label: 'Timeout', + color: '#F20707', + icon: 'timeout', + }, + [TaskStatus.TASK_STATUS_RETRIED]: { + label: 'Retried', + color: '#F6AB09', + icon: 'retry', + }, + [TaskStatus.TASK_STATUS_UNSPECIFIED]: { + label: 'Unspecified', + color: '#A9A9A9' + } + }; + // We use getters to be able to deep copy the default config and to access the default config from the outside get defaultTheme(): Theme { @@ -297,12 +438,14 @@ export class DefaultConfigService { 'sessions-interval': this.#defaultSessions.interval, 'sessions-lock-columns': this.#defaultSessions.lockColumns, 'sessions-show-filters': this.#defaultSessions.showFilters, + 'sessions-statuses': this.#defaultSessionsStatuses, 'results-columns': this.#defaultResults.columns, 'results-options': this.#defaultResults.options, 'results-filters': this.#defaultResults.filters, 'results-interval': this.#defaultResults.interval, 'results-lock-columns': this.#defaultResults.lockColumns, 'results-show-filters': this.#defaultResults.showFilters, + 'results-statuses': this.#defaultResultsStatuses, 'tasks-columns': this.#defaultTasks.columns, 'tasks-options': this.#defaultTasks.options, 'tasks-filters': this.#defaultTasks.filters, @@ -310,6 +453,7 @@ export class DefaultConfigService { 'tasks-view-in-logs': this.#defaultTasksViewInLogs, 'tasks-lock-columns': this.#defaultTasks.lockColumns, 'tasks-show-filters': this.#defaultTasks.showFilters, + 'tasks-statuses': this.#defaultTaskStatuses, 'tasks-custom-columns': [], 'sessions-custom-columns': [], }; diff --git a/src/app/sessions/components/table.component.spec.ts b/src/app/sessions/components/table.component.spec.ts index 97ccc900f..a1c57c5f3 100644 --- a/src/app/sessions/components/table.component.spec.ts +++ b/src/app/sessions/components/table.component.spec.ts @@ -7,6 +7,7 @@ import { ManageGroupsDialogResult, TasksStatusesGroup } from '@app/dashboard/typ import { TaskOptions } from '@app/tasks/types'; import { TableColumn } from '@app/types/column.type'; import { ColumnKey, SessionData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { ActionTable } from '@app/types/table'; import { CacheService } from '@services/cache.service'; import { FiltersService } from '@services/filters.service'; @@ -15,7 +16,6 @@ import { TasksByStatusService } from '@services/tasks-by-status.service'; import { of } from 'rxjs'; import { SessionsTableComponent } from './table.component'; import { SessionsDataService } from '../services/sessions-data.service'; -import { SessionsStatusesService } from '../services/sessions-statuses.service'; import { SessionRaw } from '../types'; function getAction(actions: ActionTable[], label: string) { @@ -130,13 +130,30 @@ describe('SessionsTableComponent', () => { save: jest.fn() }; + const mockStatusService = { + statuses: { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [SessionStatus.SESSION_STATUS_CLOSED]: { + label: 'Closed' + }, + }, + canPause: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_PAUSED), + canResume: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_RUNNING), + canCancel: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_CANCELLED), + canPurge: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_RUNNING), + canClose: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_CLOSED), + canDelete: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_DELETED), + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ SessionsTableComponent, { provide: SessionsDataService, useValue: mockSessionsDataService }, { provide: NotificationService, useValue: mockNotificationService }, - SessionsStatusesService, + { provide: StatusService, useValue: mockStatusService }, FiltersService, { provide: CacheService, useValue: mockCacheService }, { provide: Clipboard, useValue: mockClipBoard }, diff --git a/src/app/sessions/components/table.component.ts b/src/app/sessions/components/table.component.ts index b30913cd8..e43578c37 100644 --- a/src/app/sessions/components/table.component.ts +++ b/src/app/sessions/components/table.component.ts @@ -6,6 +6,7 @@ import { Router, RouterModule } from '@angular/router'; import { TaskOptions } from '@app/tasks/types'; import { AbstractTaskByStatusTableComponent } from '@app/types/components/table'; import { ArmonikData, SessionData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { ActionTable } from '@app/types/table'; import { TableComponent } from '@components/table/table.component'; import { TableTasksByStatus, TasksByStatusService } from '@services/tasks-by-status.service'; @@ -16,7 +17,6 @@ import { SessionRaw } from '../types'; @Component({ selector: 'app-sessions-table', - standalone: true, templateUrl: './table.component.html', providers: [ TasksByStatusService, @@ -30,7 +30,7 @@ import { SessionRaw } from '../types'; }) export class SessionsTableComponent extends AbstractTaskByStatusTableComponent implements OnInit { - readonly statusesService = inject(SessionsStatusesService); + readonly statusesService = inject(StatusService) as SessionsStatusesService; readonly router = inject(Router); readonly copyService = inject(Clipboard); diff --git a/src/app/sessions/index.component.ts b/src/app/sessions/index.component.ts index a31a11cb7..d7cdc9496 100644 --- a/src/app/sessions/index.component.ts +++ b/src/app/sessions/index.component.ts @@ -16,6 +16,7 @@ import { TaskOptions } from '@app/tasks/types'; import { TableHandlerCustomValues } from '@app/types/components'; import { ColumnKey } from '@app/types/data'; import { DataFilterService } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { TableType } from '@app/types/table'; import { FiltersToolbarComponent } from '@components/filters/filters-toolbar.component'; import { PageHeaderComponent } from '@components/page-header.component'; @@ -42,7 +43,6 @@ import { SessionRaw } from './types'; @Component({ selector: 'app-sessions-index', templateUrl: './index.component.html', - standalone: true, providers: [ ShareUrlService, QueryParamsService, @@ -62,7 +62,10 @@ import { SessionRaw } from './types'; provide: DataFilterService, useExisting: SessionsFiltersService }, - SessionsStatusesService, + { + provide: StatusService, + useClass: SessionsStatusesService, + }, MatDialog, DashboardIndexService, DashboardStorageService, diff --git a/src/app/sessions/services/sessions-filters.service.spec.ts b/src/app/sessions/services/sessions-filters.service.spec.ts index 4bfccc025..cae4657a7 100644 --- a/src/app/sessions/services/sessions-filters.service.spec.ts +++ b/src/app/sessions/services/sessions-filters.service.spec.ts @@ -1,11 +1,11 @@ -import { FilterDateOperator, SessionRawEnumField, SessionTaskOptionEnumField } from '@aneoconsultingfr/armonik.api.angular'; +import { FilterDateOperator, SessionRawEnumField, SessionStatus, SessionTaskOptionEnumField } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { FiltersOr } from '@app/types/filters'; +import { StatusService } from '@app/types/status'; import { DefaultConfigService } from '@services/default-config.service'; import { FiltersCacheService } from '@services/filters-cache.service'; import { TableService } from '@services/table.service'; import { SessionsFiltersService } from './sessions-filters.service'; -import { SessionsStatusesService } from './sessions-statuses.service'; import { SessionFilterDefinition, SessionFilterField, SessionRawFilters } from '../types'; describe('SessionsFilterService', () => { @@ -39,12 +39,23 @@ describe('SessionsFilterService', () => { get: jest.fn(() => cachedFilters), }; + const mockStatusService = { + statuses: { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [SessionStatus.SESSION_STATUS_CLOSED]: { + label: 'Closed' + }, + }, + }; + beforeEach(() => { service = TestBed.configureTestingModule({ providers: [ SessionsFiltersService, DefaultConfigService, - SessionsStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: TableService, useValue: mockTableService }, { provide: FiltersCacheService, useValue: mockFiltersCacheService }, ] diff --git a/src/app/sessions/services/sessions-filters.service.ts b/src/app/sessions/services/sessions-filters.service.ts index 2525fcc18..0d5942fbc 100644 --- a/src/app/sessions/services/sessions-filters.service.ts +++ b/src/app/sessions/services/sessions-filters.service.ts @@ -2,6 +2,7 @@ import { SessionRawEnumField, SessionStatus, SessionTaskOptionEnumField, TaskOpt import { Injectable, inject } from '@angular/core'; import { Scope } from '@app/types/config'; import { DataFilterService, FiltersServiceOptionsInterface, FiltersServiceStatusesInterface } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { SessionsStatusesService } from './sessions-statuses.service'; import { SessionFilterDefinition, SessionFilterField, SessionFilterFor, SessionRawFilters } from '../types'; @@ -11,7 +12,7 @@ import { SessionFilterDefinition, SessionFilterField, SessionFilterFor, SessionR export class SessionsFiltersService extends DataFilterService implements FiltersServiceOptionsInterface, FiltersServiceStatusesInterface { protected readonly scope: Scope = 'sessions'; - readonly statusService = inject(SessionsStatusesService); + readonly statusService = inject(StatusService) as SessionsStatusesService; readonly rootField: Record = { [SessionRawEnumField.SESSION_RAW_ENUM_FIELD_SESSION_ID]: $localize`Session ID`, diff --git a/src/app/sessions/services/sessions-grpc.service.spec.ts b/src/app/sessions/services/sessions-grpc.service.spec.ts index 81ad6057e..b062ffabe 100644 --- a/src/app/sessions/services/sessions-grpc.service.spec.ts +++ b/src/app/sessions/services/sessions-grpc.service.spec.ts @@ -10,14 +10,11 @@ import { UtilsService } from '@services/utils.service'; import { lastValueFrom, of } from 'rxjs'; import { SessionsFiltersService } from './sessions-filters.service'; import { SessionsGrpcService } from './sessions-grpc.service'; -import { SessionsStatusesService } from './sessions-statuses.service'; import { SessionFilterDefinition, SessionRaw } from '../types'; describe('SessionsGrpcService', () => { let service: SessionsGrpcService; - const statusesService = new SessionsStatusesService(); - const mocksessionsFilterService = { filtersDefinitions: [ { @@ -29,12 +26,16 @@ describe('SessionsGrpcService', () => { for: 'root', field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_STATUS, type: 'status', - statuses: Object.keys(statusesService.statuses).map(status => { - return { - key: status, - value: statusesService.statusToLabel(Number(status)), - }; - }), + statuses: [ + { + key: SessionStatus.SESSION_STATUS_RUNNING, + value: 'Running', + }, + { + key: SessionStatus.SESSION_STATUS_PURGED, + value: 'Purged', + }, + ], }, { for: 'root', diff --git a/src/app/sessions/services/sessions-statuses.service.spec.ts b/src/app/sessions/services/sessions-statuses.service.spec.ts index 4b388de1a..7feefa984 100644 --- a/src/app/sessions/services/sessions-statuses.service.spec.ts +++ b/src/app/sessions/services/sessions-statuses.service.spec.ts @@ -1,15 +1,94 @@ import { SessionStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { StatusLabelColor } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; +import { StorageService } from '@services/storage.service'; import { SessionsStatusesService } from './sessions-statuses.service'; describe('SessionsStatusesService', () => { - const service = new SessionsStatusesService(); + let service: SessionsStatusesService; + + const mockDefaultStatuses = { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + color: 'red', + label: 'Cancelled' + } + }; + + const mockDefaultConfigService = { + exportedDefaultConfig: { + 'sessions-statuses': mockDefaultStatuses, + }, + }; + + const mockStoredStatuses = { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + color: 'blue', + label: 'Cancelled' + } + }; + + const mockStorageService = { + getItem: jest.fn((): unknown => mockStoredStatuses), + setItem: jest.fn(), + }; + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + SessionsStatusesService, + { provide: DefaultConfigService, useValue: mockDefaultConfigService }, + { provide: StorageService, useValue: mockStorageService }, + ] + }).inject(SessionsStatusesService); + }); it('should be created', () => { expect(service).toBeTruthy(); }); + describe('initialisation', () => { + beforeEach(() => { + mockStorageService.getItem.mockReturnValueOnce(null); + }); + + it('should init the statuses with stored config', () => { + expect(service.statuses).toEqual(mockStoredStatuses); + }); + + it('should init the statuses with default config', () => { + const serviceWithDefault = TestBed.inject(SessionsStatusesService); + expect(serviceWithDefault.statuses).toEqual(mockDefaultStatuses); + }); + }); + + describe('updateStatuses', () => { + const newStatuses = { + [SessionStatus.SESSION_STATUS_CANCELLED]: { + label: 'Cancelled', + color: 'green', + } + } as Record; + + beforeEach(() => { + service.updateStatuses(newStatuses); + }); + + it('should update the statuses', () => { + expect(service.statuses[SessionStatus.SESSION_STATUS_CANCELLED]).toEqual(newStatuses[SessionStatus.SESSION_STATUS_CANCELLED]); + }); + + it('should store the new statuses', () => { + expect(mockStorageService.setItem).toHaveBeenCalledWith('sessions-statuses', service.statuses); + }); + }); + + it('should retrieve the default statuses config', () => { + expect(service.getDefault()).toEqual(mockDefaultConfigService.exportedDefaultConfig['sessions-statuses']); + }); + it('should return the correct label', () => { - expect(service.statusToLabel(SessionStatus.SESSION_STATUS_RUNNING)).toBeDefined(); + expect(service.statusToLabel(SessionStatus.SESSION_STATUS_CANCELLED)).toBeDefined(); }); describe('canCancel', () => { diff --git a/src/app/sessions/services/sessions-statuses.service.ts b/src/app/sessions/services/sessions-statuses.service.ts index 1a3463fe0..1f5b3566c 100644 --- a/src/app/sessions/services/sessions-statuses.service.ts +++ b/src/app/sessions/services/sessions-statuses.service.ts @@ -1,45 +1,12 @@ import { SessionStatus } from '@aneoconsultingfr/armonik.api.angular'; import { Injectable } from '@angular/core'; -import { StatusLabelColor, StatusService } from '@app/types/status'; +import { StatusService } from '@app/types/status'; @Injectable() export class SessionsStatusesService extends StatusService { - readonly statuses: Record = { - [SessionStatus.SESSION_STATUS_UNSPECIFIED]: { - label: $localize`Unspecified`, - color: '#696969', - }, - [SessionStatus.SESSION_STATUS_RUNNING]: { - label: $localize`Running`, - color: '#008000', - icon: 'play', - }, - [SessionStatus.SESSION_STATUS_CANCELLED]: { - label: $localize`Cancelled`, - color: '#0E4D92', - icon: 'cancel', - }, - [SessionStatus.SESSION_STATUS_CLOSED]: { - label: $localize`Closed`, - color: '#FF0000', - icon: 'close', - }, - [SessionStatus.SESSION_STATUS_DELETED]: { - label: $localize`Deleted`, - color: '#000000', - icon: 'delete', - }, - [SessionStatus.SESSION_STATUS_PURGED]: { - label: $localize`Purged`, - color: '#800080', - icon: 'purge', - }, - [SessionStatus.SESSION_STATUS_PAUSED]: { - label: $localize`Paused`, - color: '#FF8C00', - icon: 'pause', - }, - }; + constructor() { + super('sessions'); + } canCancel(status: SessionStatus): boolean { return status === SessionStatus.SESSION_STATUS_RUNNING || status === SessionStatus.SESSION_STATUS_PAUSED; diff --git a/src/app/sessions/show.component.spec.ts b/src/app/sessions/show.component.spec.ts index 42a04df48..b2d3b1f94 100644 --- a/src/app/sessions/show.component.spec.ts +++ b/src/app/sessions/show.component.spec.ts @@ -2,6 +2,7 @@ import { GetSessionResponse, SessionStatus } from '@aneoconsultingfr/armonik.api import { TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { TasksInspectionService } from '@app/tasks/services/tasks-inspection.service'; +import { StatusService } from '@app/types/status'; import { GrpcStatusEvent } from '@ngx-grpc/common'; import { Duration, Timestamp } from '@ngx-grpc/well-known-types'; import { FiltersService } from '@services/filters.service'; @@ -11,7 +12,6 @@ import { ShareUrlService } from '@services/share-url.service'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { SessionsGrpcService } from './services/sessions-grpc.service'; import { SessionsInspectionService } from './services/sessions-inspection.service'; -import { SessionsStatusesService } from './services/sessions-statuses.service'; import { ShowComponent } from './show.component'; import { SessionRaw } from './types'; @@ -72,13 +72,28 @@ describe('AppShowComponent', () => { navigate: jest.fn(), }; + const mockStatusService = { + statuses: { + [SessionStatus.SESSION_STATUS_RUNNING]: { + label: 'Running', + color: 'green' + }, + }, + canPause: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_PAUSED), + canResume: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_RUNNING), + canCancel: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_CANCELLED), + canPurge: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_RUNNING), + canClose: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_CLOSED), + canDelete: jest.fn((s: SessionStatus) => s !== SessionStatus.SESSION_STATUS_DELETED), + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ ShowComponent, IconsService, FiltersService, - SessionsStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: NotificationService, useValue: mockNotificationService }, { provide: ShareUrlService, useValue: mockShareUrlService }, { provide: ActivatedRoute, useValue: mockActivatedRoute }, @@ -229,11 +244,7 @@ describe('AppShowComponent', () => { describe('get status', () => { it('should return the status label if there is data', () => { component.refresh.next(); - expect(component.status).toEqual({ - color: '#008000', - icon: 'play', - label: 'Running' - }); + expect(component.status).toEqual(mockStatusService.statuses[SessionStatus.SESSION_STATUS_RUNNING]); }); it('should return undefined if there is no data', () => { diff --git a/src/app/sessions/show.component.ts b/src/app/sessions/show.component.ts index 7a1bfdab1..53eb894e9 100644 --- a/src/app/sessions/show.component.ts +++ b/src/app/sessions/show.component.ts @@ -10,14 +10,16 @@ import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service import { TaskOptions } from '@app/tasks/types'; import { Field } from '@app/types/column.type'; import { AppShowComponent } from '@app/types/components/show'; -import { StatusLabelColor } from '@app/types/status'; +import { StatusLabelColor, StatusService } from '@app/types/status'; import { ShowPageComponent } from '@components/show-page.component'; import { Duration, Timestamp } from '@ngx-grpc/well-known-types'; +import { DefaultConfigService } from '@services/default-config.service'; import { FiltersService } from '@services/filters.service'; import { GrpcSortFieldService } from '@services/grpc-sort-field.service'; import { NotificationService } from '@services/notification.service'; import { QueryParamsService } from '@services/query-params.service'; import { ShareUrlService } from '@services/share-url.service'; +import { StorageService } from '@services/storage.service'; import { TableStorageService } from '@services/table-storage.service'; import { TableURLService } from '@services/table-url.service'; import { TableService } from '@services/table.service'; @@ -34,13 +36,11 @@ import { SessionRaw } from './types'; selector: 'app-sessions-show', templateUrl: 'show.component.html', styleUrl: '../../inspections.css', - standalone: true, providers: [ UtilsService, ShareUrlService, QueryParamsService, SessionsGrpcService, - SessionsStatusesService, SessionsIndexService, SessionsFiltersService, TableService, @@ -54,6 +54,12 @@ import { SessionRaw } from './types'; GrpcSortFieldService, SessionsInspectionService, TasksInspectionService, + DefaultConfigService, + StorageService, + { + provide: StatusService, + useClass: SessionsStatusesService, + } ], imports: [ ShowPageComponent, @@ -74,7 +80,7 @@ export class ShowComponent extends AppShowComponent); diff --git a/src/app/tasks/components/table.component.spec.ts b/src/app/tasks/components/table.component.spec.ts index 55072bc2c..6620a66f3 100644 --- a/src/app/tasks/components/table.component.spec.ts +++ b/src/app/tasks/components/table.component.spec.ts @@ -1,12 +1,13 @@ import { TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; import { Clipboard } from '@angular/cdk/clipboard'; import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; import { TableColumn } from '@app/types/column.type'; import { ArmonikData, ColumnKey, TaskData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { NotificationService } from '@services/notification.service'; import { TasksTableComponent } from './table.component'; import TasksDataService from '../services/tasks-data.service'; -import { TasksStatusesService } from '../services/tasks-statuses.service'; import { TaskOptions, TaskSummary } from '../types'; describe('TasksTableComponent', () => { @@ -61,13 +62,31 @@ describe('TasksTableComponent', () => { cancelTask: jest.fn(), }; + const mockRouter = { + navigate: jest.fn(), + }; + + const mockStatusService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [TaskStatus.TASK_STATUS_COMPLETED]: { + label: 'Completed' + }, + }, + isRetried: jest.fn((s: TaskStatus) => s === TaskStatus.TASK_STATUS_RETRIED), + taskNotEnded: jest.fn((s: TaskStatus) => s !== TaskStatus.TASK_STATUS_COMPLETED) + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ TasksTableComponent, - TasksStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: NotificationService, useValue: mockNotificationService }, { provide: Clipboard, useValue: mockClipBoard }, + { provide: Router, useValue: mockRouter }, { provide: TasksDataService, useValue: mockTasksDataService } ] }).inject(TasksTableComponent); diff --git a/src/app/tasks/components/table.component.ts b/src/app/tasks/components/table.component.ts index 0af17419a..1b93ac0fa 100644 --- a/src/app/tasks/components/table.component.ts +++ b/src/app/tasks/components/table.component.ts @@ -5,6 +5,7 @@ import { Router} from '@angular/router'; import { AbstractTableComponent } from '@app/types/components/table'; import { Scope } from '@app/types/config'; import { ArmonikData, TaskData } from '@app/types/data'; +import { StatusService } from '@app/types/status'; import { ActionTable } from '@app/types/table'; import { TableComponent } from '@components/table/table.component'; import { Subject } from 'rxjs'; @@ -14,7 +15,6 @@ import { TaskOptions, TaskSummary } from '../types'; @Component({ selector: 'app-tasks-table', - standalone: true, templateUrl: './table.component.html', providers: [ Clipboard, @@ -52,7 +52,7 @@ export class TasksTableComponent extends AbstractTableComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/tasks/services/tasks-filters.service.spec.ts b/src/app/tasks/services/tasks-filters.service.spec.ts index 7aadb35e0..2b7a56ca4 100644 --- a/src/app/tasks/services/tasks-filters.service.spec.ts +++ b/src/app/tasks/services/tasks-filters.service.spec.ts @@ -1,11 +1,11 @@ -import { FilterDateOperator, TaskOptionEnumField, TaskSummaryEnumField } from '@aneoconsultingfr/armonik.api.angular'; +import { FilterDateOperator, TaskOptionEnumField, TaskStatus, TaskSummaryEnumField } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { FiltersAnd, FiltersOr } from '@app/types/filters'; +import { StatusService } from '@app/types/status'; import { DefaultConfigService } from '@services/default-config.service'; import { FiltersCacheService } from '@services/filters-cache.service'; import { TableService } from '@services/table.service'; import { TasksFiltersService } from './tasks-filters.service'; -import { TasksStatusesService } from './tasks-statuses.service'; import { TaskFilterField, TaskSummaryFilters } from '../types'; @@ -42,12 +42,23 @@ describe('TasksFilterService', () => { get: jest.fn(() => cachedFilters), }; + const mockStatusService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + }, + [TaskStatus.TASK_STATUS_COMPLETED]: { + label: 'Completed' + }, + }, + }; + beforeEach(() => { service = TestBed.configureTestingModule({ providers: [ TasksFiltersService, DefaultConfigService, - TasksStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: TableService, useValue: mockTableService }, { provide: FiltersCacheService, useValue: mockFiltersCacheService }, ] diff --git a/src/app/tasks/services/tasks-filters.service.ts b/src/app/tasks/services/tasks-filters.service.ts index d32bc5bd5..6327d6be4 100644 --- a/src/app/tasks/services/tasks-filters.service.ts +++ b/src/app/tasks/services/tasks-filters.service.ts @@ -2,6 +2,7 @@ import { TaskOptionEnumField, TaskStatus, TaskSummaryEnumField } from '@aneocons import { Injectable, inject } from '@angular/core'; import { Scope } from '@app/types/config'; import { DataFilterService, FiltersServiceOptionsInterface, FiltersServiceStatusesInterface } from '@app/types/services/data-filter.service'; +import { StatusService } from '@app/types/status'; import { TasksStatusesService } from './tasks-statuses.service'; import { TaskFilterDefinition, TaskFilterField, TaskFilterFor, TaskSummaryFilters } from '../types'; @@ -11,7 +12,7 @@ import { TaskFilterDefinition, TaskFilterField, TaskFilterFor, TaskSummaryFilter export class TasksFiltersService extends DataFilterService implements FiltersServiceOptionsInterface, FiltersServiceStatusesInterface { protected readonly scope: Scope = 'tasks'; - readonly statusService = inject(TasksStatusesService); + readonly statusService = inject(StatusService) as TasksStatusesService; readonly rootField: Record = { [TaskSummaryEnumField.TASK_SUMMARY_ENUM_FIELD_TASK_ID]: $localize`Task ID`, diff --git a/src/app/tasks/services/tasks-grpc.service.spec.ts b/src/app/tasks/services/tasks-grpc.service.spec.ts index 00070d4b9..bb98e271b 100644 --- a/src/app/tasks/services/tasks-grpc.service.spec.ts +++ b/src/app/tasks/services/tasks-grpc.service.spec.ts @@ -5,13 +5,11 @@ import { GrpcSortFieldService } from '@services/grpc-sort-field.service'; import { UtilsService } from '@services/utils.service'; import { TasksFiltersService } from './tasks-filters.service'; import { TasksGrpcService } from './tasks-grpc.service'; -import { TasksStatusesService } from './tasks-statuses.service'; import { TaskFilterDefinition, TaskOptions, TaskSummary, TaskSummaryFilters, TaskSummaryListOptions } from '../types'; describe('TasksGrpcService', () => { let service: TasksGrpcService; - const statusesService = new TasksStatusesService(); const mocktasksFilterService = { filtersDefinitions: [ @@ -24,12 +22,16 @@ describe('TasksGrpcService', () => { for: 'root', field: TaskSummaryEnumField.TASK_SUMMARY_ENUM_FIELD_STATUS, type: 'status', - statuses: Object.keys(statusesService.statuses).map(status => { - return { - key: status, - value: statusesService.statuses[Number(status) as TaskStatus], - }; - }), + statuses: [ + { + key: TaskStatus.TASK_STATUS_PROCESSING, + value: 'Processing', + }, + { + key: TaskStatus.TASK_STATUS_COMPLETED, + value: 'Completed' + } + ] }, { for: 'root', diff --git a/src/app/tasks/services/tasks-statuses.service.spec.ts b/src/app/tasks/services/tasks-statuses.service.spec.ts index 5a319d00b..4300257c7 100644 --- a/src/app/tasks/services/tasks-statuses.service.spec.ts +++ b/src/app/tasks/services/tasks-statuses.service.spec.ts @@ -1,15 +1,94 @@ import { TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { StatusLabelColor } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; +import { StorageService } from '@services/storage.service'; import { TasksStatusesService } from './tasks-statuses.service'; describe('tasksStatusesService', () => { - const service: TasksStatusesService = new TasksStatusesService(); + let service: TasksStatusesService; + + const mockDefaultStatuses = { + [TaskStatus.TASK_STATUS_CANCELLED]: { + color: 'red', + label: 'Cancelled' + } + }; + + const mockDefaultConfigService = { + exportedDefaultConfig: { + 'tasks-statuses': mockDefaultStatuses, + }, + }; + + const mockStoredStatuses = { + [TaskStatus.TASK_STATUS_CANCELLED]: { + color: 'blue', + label: 'Cancelled' + } + }; + + const mockStorageService = { + getItem: jest.fn((): unknown => mockStoredStatuses), + setItem: jest.fn(), + }; + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + TasksStatusesService, + { provide: DefaultConfigService, useValue: mockDefaultConfigService }, + { provide: StorageService, useValue: mockStorageService }, + ] + }).inject(TasksStatusesService); + }); it('should create TasksStatusesService', () => { expect(service).toBeTruthy(); }); + describe('initialisation', () => { + beforeEach(() => { + mockStorageService.getItem.mockReturnValueOnce(null); + }); + + it('should init the statuses with stored config', () => { + expect(service.statuses).toEqual(mockStoredStatuses); + }); + + it('should init the statuses with default config', () => { + const serviceWithDefault = TestBed.inject(TasksStatusesService); + expect(serviceWithDefault.statuses).toEqual(mockDefaultStatuses); + }); + }); + + describe('updateStatuses', () => { + const newStatuses = { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + color: 'green', + } + } as Record; + + beforeEach(() => { + service.updateStatuses(newStatuses); + }); + + it('should update the statuses', () => { + expect(service.statuses[TaskStatus.TASK_STATUS_CANCELLED]).toEqual(newStatuses[TaskStatus.TASK_STATUS_CANCELLED]); + }); + + it('should store the new statuses', () => { + expect(mockStorageService.setItem).toHaveBeenCalledWith('tasks-statuses', service.statuses); + }); + }); + + it('should retrieve the default statuses config', () => { + expect(service.getDefault()).toEqual(mockDefaultConfigService.exportedDefaultConfig['tasks-statuses']); + }); + it('should return the right task status', () => { - expect(service.statusToLabel(TaskStatus.TASK_STATUS_PROCESSED)).toBeDefined(); + expect(service.statusToLabel(TaskStatus.TASK_STATUS_CANCELLED)).toBeDefined(); }); describe('isRetried', () => { diff --git a/src/app/tasks/services/tasks-statuses.service.ts b/src/app/tasks/services/tasks-statuses.service.ts index 3d9ba4259..0e0f906ab 100644 --- a/src/app/tasks/services/tasks-statuses.service.ts +++ b/src/app/tasks/services/tasks-statuses.service.ts @@ -1,81 +1,13 @@ import { TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; import { Injectable } from '@angular/core'; -import { StatusLabelColor, StatusService } from '@app/types/status'; +import { StatusService } from '@app/types/status'; @Injectable() export class TasksStatusesService extends StatusService { - readonly statuses: Record = { - [TaskStatus.TASK_STATUS_UNSPECIFIED]: { - label: 'Unspecified', - color: '#A9A9A9' - }, - [TaskStatus.TASK_STATUS_CREATING]: { - label: 'Creating', - color: '#008B8B', - icon: 'creating', - }, - [TaskStatus.TASK_STATUS_SUBMITTED]: { - label: 'Submitted', - color: '#00008B', - icon: 'submitting', - }, - [TaskStatus.TASK_STATUS_DISPATCHED]: { - label: 'Dispatched', - color: '#6495ED', - icon: 'dispatched', - }, - [TaskStatus.TASK_STATUS_COMPLETED]: { - label: 'Completed', - color: '#006400', - icon: 'success' - }, - [TaskStatus.TASK_STATUS_ERROR]: { - label: 'Error', - color: '#FF0000', - icon: 'error', - }, - [TaskStatus.TASK_STATUS_TIMEOUT]: { - label: 'Timeout', - color: '#FF0000', - icon: 'timeout', - }, - [TaskStatus.TASK_STATUS_CANCELLING]: { - label: 'Cancelling', - color: '#696969', - icon: 'cancelling', - }, - [TaskStatus.TASK_STATUS_CANCELLED]: { - label: 'Cancelled', - color: '#000000', - icon: 'cancel', - }, - [TaskStatus.TASK_STATUS_PROCESSING]: { - label: 'Processing', - color: '#008000', - icon: 'play' - }, - [TaskStatus.TASK_STATUS_PROCESSED]: { - label: 'Processed', - color: '#008B8B', - icon: 'processed' - }, - [TaskStatus.TASK_STATUS_RETRIED]: { - label: 'Retried', - color: '#FF0000', - icon: 'retry', - }, - [TaskStatus.TASK_STATUS_PENDING]: { - label: $localize`Pending`, - color: '#696969', - icon: 'pending' - }, - [TaskStatus.TASK_STATUS_PAUSED]: { - label: $localize`Paused`, - color: '#FF8C00', - icon: 'pause', - }, - }; + constructor() { + super('tasks'); + } /** * @param status Number standing for a task status diff --git a/src/app/tasks/show.component.spec.ts b/src/app/tasks/show.component.spec.ts index 036f780fc..743e95172 100644 --- a/src/app/tasks/show.component.spec.ts +++ b/src/app/tasks/show.component.spec.ts @@ -1,6 +1,7 @@ import { GetTaskResponse, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; +import { StatusService } from '@app/types/status'; import { GrpcStatusEvent } from '@ngx-grpc/common'; import { FiltersService } from '@services/filters.service'; import { IconsService } from '@services/icons.service'; @@ -9,7 +10,6 @@ import { ShareUrlService } from '@services/share-url.service'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { TasksGrpcService } from './services/tasks-grpc.service'; import { TasksInspectionService } from './services/tasks-inspection.service'; -import { TasksStatusesService } from './services/tasks-statuses.service'; import { ShowComponent } from './show.component'; import { TaskRaw } from './types'; @@ -50,13 +50,26 @@ describe('AppShowComponent', () => { cancel$: jest.fn(() => of({})) }; + const mockStatusService = { + statuses: { + [TaskStatus.TASK_STATUS_CANCELLED]: { + label: 'Cancelled', + color: 'red' + }, + [TaskStatus.TASK_STATUS_PROCESSING]: { + label: 'Processing', + color: 'green' + } + }, + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ ShowComponent, IconsService, FiltersService, - TasksStatusesService, + { provide: StatusService, useValue: mockStatusService }, { provide: NotificationService, useValue: mockNotificationService }, { provide: ShareUrlService, useValue: mockShareUrlService }, { provide: ActivatedRoute, useValue: mockActivatedRoute }, @@ -118,11 +131,7 @@ describe('AppShowComponent', () => { it('should return the status label if there is data', () => { component.status = undefined; component.refresh.next(); - expect(component.status).toEqual({ - color: '#008000', - icon: 'play', - label: 'Processing' - }); + expect(component.status).toEqual(mockStatusService.statuses[TaskStatus.TASK_STATUS_PROCESSING]); }); }); @@ -189,7 +198,7 @@ describe('AppShowComponent', () => { }); it('should get statuses', () => { - expect(component.statuses).toEqual((new TasksStatusesService).statuses); + expect(component.statuses).toEqual(mockStatusService.statuses); }); describe('cancelling', () => { diff --git a/src/app/tasks/show.component.ts b/src/app/tasks/show.component.ts index 5eca44095..0bbc88e1d 100644 --- a/src/app/tasks/show.component.ts +++ b/src/app/tasks/show.component.ts @@ -6,14 +6,16 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { Params, RouterModule } from '@angular/router'; import { Field } from '@app/types/column.type'; import { AppShowComponent } from '@app/types/components/show'; -import { StatusLabelColor } from '@app/types/status'; +import { StatusLabelColor, StatusService } from '@app/types/status'; import { ShowPageComponent } from '@components/show-page.component'; +import { DefaultConfigService } from '@services/default-config.service'; import { FiltersService } from '@services/filters.service'; import { GrpcSortFieldService } from '@services/grpc-sort-field.service'; import { IconsService } from '@services/icons.service'; import { NotificationService } from '@services/notification.service'; import { QueryParamsService } from '@services/query-params.service'; import { ShareUrlService } from '@services/share-url.service'; +import { StorageService } from '@services/storage.service'; import { TableStorageService } from '@services/table-storage.service'; import { TableURLService } from '@services/table-url.service'; import { TableService } from '@services/table.service'; @@ -28,7 +30,6 @@ import { TaskOptions, TaskRaw } from './types'; selector: 'app-tasks-show', templateUrl: 'show.component.html', styleUrl: '../../inspections.css', - standalone: true, providers: [ IconsService, UtilsService, @@ -45,6 +46,12 @@ import { TaskOptions, TaskRaw } from './types'; FiltersService, GrpcSortFieldService, TasksInspectionService, + DefaultConfigService, + StorageService, + { + provide: StatusService, + useClass: TasksStatusesService, + }, ], imports: [ ShowPageComponent, @@ -59,7 +66,7 @@ export class ShowComponent extends AppShowComponent im readonly grpcService = inject(TasksGrpcService); readonly inspectionService = inject(TasksInspectionService); - private readonly tasksStatusesService = inject(TasksStatusesService); + private readonly tasksStatusesService = inject(StatusService) as TasksStatusesService; private readonly filtersService = inject(FiltersService); private _status: StatusLabelColor | undefined; diff --git a/src/app/types/components/dashboard-line-table.ts b/src/app/types/components/dashboard-line-table.ts index 4ea85a281..d7fbdfde4 100644 --- a/src/app/types/components/dashboard-line-table.ts +++ b/src/app/types/components/dashboard-line-table.ts @@ -19,7 +19,8 @@ import { AbstractTableDataService } from '../services/table-data.service'; @Component({ selector: 'app-dashboard-line-table', - template: '' + template: '', + }) export abstract class DashboardLineTableComponent { readonly autoRefreshService = inject(AutoRefreshService); @@ -214,7 +215,8 @@ export abstract class DashboardLineTableComponent extends DashboardLineTableComponent { abstract override readonly indexService: IndexServiceCustomInterface; diff --git a/src/app/types/components/table.ts b/src/app/types/components/table.ts index 12959502b..2780027a5 100644 --- a/src/app/types/components/table.ts +++ b/src/app/types/components/table.ts @@ -22,6 +22,7 @@ export interface SelectableTable { @Component({ selector: 'app-abstract-table', template: '', + }) export abstract class AbstractTableComponent { @Input({ required: true }) set displayedColumns(columns: TableColumn[]) { @@ -68,6 +69,7 @@ export abstract class AbstractTableComponent extends AbstractTableComponent { diff --git a/src/app/types/config.ts b/src/app/types/config.ts index 07175c06b..4bae055a8 100644 --- a/src/app/types/config.ts +++ b/src/app/types/config.ts @@ -13,7 +13,8 @@ export type ScopeConfig { currentColumns: ColumnKey[] @@ -77,3 +78,9 @@ export type ManageViewInLogsDialogResult = { serviceName: string; urlTemplate: string; }; + +export type StatusColorPickerDialogData = { + current: Record, + default: Record, + keys: S[], +} \ No newline at end of file diff --git a/src/app/types/status.ts b/src/app/types/status.ts index 617ea247b..3624e5f88 100644 --- a/src/app/types/status.ts +++ b/src/app/types/status.ts @@ -1,4 +1,8 @@ import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { inject } from '@angular/core'; +import { DefaultConfigService } from '@services/default-config.service'; +import { StorageService } from '@services/storage.service'; +import { StatusScope } from './config'; export type Status = TaskStatus | SessionStatus | ResultStatus; @@ -9,7 +13,23 @@ export type StatusLabelColor = { } export abstract class StatusService { - abstract readonly statuses: Record; + private readonly defaultConfigService = inject(DefaultConfigService); + private readonly storageService = inject(StorageService); + + private readonly scope: StatusScope; + + readonly keys: S[]; + readonly statuses: Record; + + constructor(scope: StatusScope) { + this.scope = scope; + let statuses = this.storageService.getItem>(`${scope}-statuses`, true) as Record; + if (!statuses) { + statuses = structuredClone(this.getDefault()); + } + this.statuses = statuses; + this.keys = Object.keys(statuses).map((status) => Number(status) as S); + } /** * @param status Status to get the label of @@ -18,4 +38,22 @@ export abstract class StatusService { statusToLabel(status: S): StatusLabelColor { return this.statuses[status]; } + + /** + * Replace the stored configuration of the statuses + * @param statuses Record of a status and its color/label/icon + */ + updateStatuses(statuses: Record) { + this.keys.forEach((status) => { + this.statuses[status] = statuses[status]; + }); + this.storageService.setItem(`${this.scope}-statuses`, this.statuses); + } + + /** + * @returns the default configuration of the statuses + */ + getDefault() { + return this.defaultConfigService.exportedDefaultConfig[`${this.scope}-statuses`] as Record; + } } \ No newline at end of file diff --git a/src/styles.css b/src/styles.css index 8a1f1464e..2448bc7dc 100644 --- a/src/styles.css +++ b/src/styles.css @@ -14,27 +14,27 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } } .mat-mdc-snack-bar-container.success { - --mdc-snackbar-container-color: #4caf50; + --mat-snackbar-container-color: #4caf50; --mat-mdc-snack-bar-button-color: #000; - --mdc-snackbar-supporting-text-color: #000; + --mat-snackbar-supporting-text-color: #000; } .mat-mdc-snack-bar-container.error { - --mdc-snackbar-container-color: #f44336; + --mat-snackbar-container-color: #f44336; --mat-mdc-snack-bar-button-color: #000; - --mdc-snackbar-supporting-text-color: #000; + --mat-snackbar-supporting-text-color: #000; } .mat-mdc-snack-bar-container.warning { - --mdc-snackbar-container-color: #ff9800; + --mat-snackbar-container-color: #ff9800; --mat-mdc-snack-bar-button-color: #000; - --mdc-snackbar-supporting-text-color: #000; + --mat-snackbar-supporting-text-color: #000; } .mat-mdc-snack-bar-container.info { - --mdc-snackbar-container-color: #2196f3; + --mat-snackbar-container-color: #2196f3; --mat-mdc-snack-bar-button-color: #000; - --mdc-snackbar-supporting-text-color: #000; + --mat-snackbar-supporting-text-color: #000; } .mat-mdc-card-header-text { diff --git a/tsconfig.json b/tsconfig.json index 3ed0cd3ef..57b9d7932 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ ], "@app/*": [ "src/app/*" - ], + ] }, "rootDir": "./", "outDir": "./dist/out-tsc", @@ -30,7 +30,7 @@ "declaration": false, "experimentalDecorators": true, "strictPropertyInitialization": false, - "moduleResolution": "node", + "moduleResolution": "bundler", "importHelpers": true, "target": "ES2022", "module": "ES2022", @@ -38,7 +38,7 @@ "useDefineForClassFields": false, "lib": [ "ES2023", - "dom", + "dom" ] }, "angularCompilerOptions": { From 89ec3cb1daa35e036780f7b9563602623223fb7d Mon Sep 17 00:00:00 2001 From: faustin Date: Tue, 15 Jul 2025 17:36:31 +0200 Subject: [PATCH 10/26] chore: updated code --- .../components/graph-legend.component.html | 4 +- src/app/components/graph-legend.component.ts | 26 +++++------- src/app/components/graph.component.css | 23 +++++++++-- src/app/components/graph.component.html | 41 +++++++++++-------- src/app/components/graph.component.ts | 23 ++++++----- 5 files changed, 67 insertions(+), 50 deletions(-) diff --git a/src/app/components/graph-legend.component.html b/src/app/components/graph-legend.component.html index 84bc6e34a..5aa8b315d 100644 --- a/src/app/components/graph-legend.component.html +++ b/src/app/components/graph-legend.component.html @@ -60,10 +60,10 @@

Results Statuses

Links

- @for (link of links; track link.label) { + @for (link of linksDescription; track link.label) { - {{ link.label }} + {{ link.label | pretty }} }
diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index 42083ac36..9a0364d7f 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -1,5 +1,5 @@ import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; -import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnInit, inject } from '@angular/core'; import { MatChipsModule } from '@angular/material/chips'; import { MatDividerModule } from '@angular/material/divider'; import { MatExpansionModule } from '@angular/material/expansion'; @@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon'; import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { PrettyPipe } from '@pipes/pretty.pipe'; import { IconsService } from '@services/icons.service'; @Component({ @@ -19,6 +20,7 @@ import { IconsService } from '@services/icons.service'; MatChipsModule, MatIconModule, MatDividerModule, + PrettyPipe, ], changeDetection: ChangeDetectionStrategy.OnPush, }) @@ -28,20 +30,14 @@ export class GraphLegendComponent implements OnInit { readonly tasksStatusesService = inject(TasksStatusesService); readonly resultsStatusesService = inject(ResultsStatusesService); - links: { label: string, color: string }[] = [ - { - label: 'Task result', - color: '#f7b657', - }, - { - label: 'Parent', - color: '#8A427AAA', - }, - { - label: 'Dependency', - color: '#878adeDD', - } - ]; + @Input({ required: true }) set links(entry: Map) { + this.linksDescription = [...entry.keys()].map(key => ({ + label: key.replace('Link', ''), + color: entry.get(key) as string, + })); + } + + linksDescription: { label: string, color: string }[]; // TODO: this part will be useless when statuses are merged sessionsStatuses: SessionStatus[]; diff --git a/src/app/components/graph.component.css b/src/app/components/graph.component.css index c18b2e22a..f5977a712 100644 --- a/src/app/components/graph.component.css +++ b/src/app/components/graph.component.css @@ -6,15 +6,30 @@ mat-card { width: fit-content; } -mat-card-title { +mat-card-content { + min-width: 60vw; + padding: 0.5rem !important; + display: flex; + align-items: center; + justify-content: space-between; +} + +section { width: fit-content !important; + display: flex; + align-items: center; + gap: 0.5rem; +} + +h2 { + padding: 0px; + margin: 0px; } mat-card-actions { display: flex; - justify-content: space-between; - gap: 2rem; - align-items: start; + gap: 1rem; + align-items: center; } mat-card-actions > section { diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index d171048f2..ba7e8c1d8 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -1,28 +1,33 @@ - - Session: {{ sessionId }} - - + +
+

+ Session: + {{ sessionId }} +

+ +
- {{ getIcon('back') }} - Back to Sessions List + Back to Sessions List -
-
- - Highlight a task - - - - Display Particles - -
+
+ + + + Display Particles +
- +
\ No newline at end of file diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 5af41fc80..b01b113f1 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -17,6 +17,7 @@ import { IconsService } from '@services/icons.service'; import { forceLink, forceManyBody } from 'd3'; import ForceGraph from 'force-graph'; import { Observable, Subject, Subscription, switchMap } from 'rxjs'; +import { AutoCompleteComponent } from './auto-complete.component'; import { GraphLegendComponent } from './graph-legend.component'; @Component({ @@ -34,6 +35,7 @@ import { GraphLegendComponent } from './graph-legend.component'; RouterModule, GraphLegendComponent, MatTooltipModule, + AutoCompleteComponent ], providers: [ SessionsStatusesService, @@ -52,10 +54,9 @@ export class GraphComponent> private canvasWidth: number = window.innerWidth; private canvasHeight: number = window.innerHeight; - private taskToFind: string = ''; private readonly nodesToHighlight: Set = new Set(); - private readonly colorMap: Map = new Map([ + readonly colorMap: Map = new Map([ ['taskResultLink', '#f7b657'], ['parentLink', '#8A427AAA'], ['dependencyLink', '#878adeDD'], @@ -71,7 +72,9 @@ export class GraphComponent> private readonly subscription = new Subscription(); - private nodes: N[]; + private nodes: N[] = []; + nodesIds: string[] = []; + readonly highlightLabel = $localize`Highlight a task`; ngAfterViewInit(): void { if (this.graphRef) { @@ -123,19 +126,16 @@ export class GraphComponent> * Hightlight nodes with names included the searched value * @param searchedValue */ - highlightNodes(searchedValue: Event): void { - this.taskToFind = (searchedValue.target as HTMLInputElement).value; + highlightNodes(searchedValue: string) { this.nodesToHighlight.clear(); - this.nodes.forEach((node: N) => { - if (this.taskToFind !== '' && - node.id.includes(this.taskToFind) + this.nodes.forEach((node: ArmoniKGraphNode) => { + if ( + searchedValue !== '' && + node.id.includes(searchedValue) ) { this.nodesToHighlight.add(node.id); } }); - this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => - this.drawNode(node, ctx) - ); } /** @@ -164,6 +164,7 @@ export class GraphComponent> */ private subscribeToData(result: GraphData) { this.nodes = result.nodes; + this.nodesIds = result.nodes.map((node) => node.id); this.graph.graphData({ nodes: result.nodes, links: result.links }); } From 2aab2dfde0bc4fc2ff4d5b6c3656a1a785979f2d Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Thu, 17 Jul 2025 10:27:31 +0200 Subject: [PATCH 11/26] chore: stored links colors --- src/app/components/graph-legend.component.ts | 7 +++-- src/app/components/graph.component.ts | 33 +++++++++----------- src/app/services/default-config.service.ts | 13 ++++++++ src/app/types/config.ts | 1 + 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index 9a0364d7f..205536550 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon'; import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { LinkType } from '@app/types/graph.types'; import { PrettyPipe } from '@pipes/pretty.pipe'; import { IconsService } from '@services/icons.service'; @@ -30,10 +31,10 @@ export class GraphLegendComponent implements OnInit { readonly tasksStatusesService = inject(TasksStatusesService); readonly resultsStatusesService = inject(ResultsStatusesService); - @Input({ required: true }) set links(entry: Map) { - this.linksDescription = [...entry.keys()].map(key => ({ + @Input({ required: true }) set links(entry: Record) { + this.linksDescription = Object.keys(entry).map(key => ({ label: key.replace('Link', ''), - color: entry.get(key) as string, + color: entry[key as LinkType] as string, })); } diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index b01b113f1..970ed2067 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -1,5 +1,5 @@ import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; -import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, inject } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, ViewChild, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -11,9 +11,11 @@ import { RouterModule } from '@angular/router'; import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; -import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; +import { ArmoniKGraphNode, GraphData, GraphLink, LinkType } from '@app/types/graph.types'; import { StatusLabelColor } from '@app/types/status'; +import { DefaultConfigService } from '@services/default-config.service'; import { IconsService } from '@services/icons.service'; +import { StorageService } from '@services/storage.service'; import { forceLink, forceManyBody } from 'd3'; import ForceGraph from 'force-graph'; import { Observable, Subject, Subscription, switchMap } from 'rxjs'; @@ -44,7 +46,7 @@ import { GraphLegendComponent } from './graph-legend.component'; ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class GraphComponent> implements AfterViewInit { +export class GraphComponent> implements OnInit, AfterViewInit { @Input({ required: true }) grpcObservable: Observable>; @Input({ required: true }) sessionId: string; @@ -56,17 +58,14 @@ export class GraphComponent> private readonly nodesToHighlight: Set = new Set(); - readonly colorMap: Map = new Map([ - ['taskResultLink', '#f7b657'], - ['parentLink', '#8A427AAA'], - ['dependencyLink', '#878adeDD'], - ['payloadLink', 'red'], - ]); + colorMap: Record; private readonly iconsService = inject(IconsService); private readonly sessionsStatusesService = inject(SessionsStatusesService); private readonly tasksStatusesService = inject(TasksStatusesService); private readonly resultsStatusesService = inject(ResultsStatusesService); + private readonly storageService = inject(StorageService); + private readonly defaultConfigService = inject(DefaultConfigService); private readonly redrawGraph$ = new Subject(); @@ -76,6 +75,11 @@ export class GraphComponent> nodesIds: string[] = []; readonly highlightLabel = $localize`Highlight a task`; + ngOnInit(): void { + const storedColorMap = this.storageService.getItem>('graph-links-colors', true) as Record | null; + this.colorMap = storedColorMap ?? this.defaultConfigService.defaultGraphLinksColors; + } + ngAfterViewInit(): void { if (this.graphRef) { this.graph = new ForceGraph(this.graphRef.nativeElement); @@ -209,15 +213,6 @@ export class GraphComponent> * @returns string */ private getLinkColor(link: L): string { - switch (link.type) { - case 'parent': - return this.colorMap.get('parentLink')!; - case 'dependency': - return this.colorMap.get('dependencyLink')!; - case 'payload': - return this.colorMap.get('payloadLink')!; - default: - return this.colorMap.get('taskResultLink')!; - } + return this.colorMap[link.type]; } } \ No newline at end of file diff --git a/src/app/services/default-config.service.ts b/src/app/services/default-config.service.ts index 63c278d24..3ef4f15e6 100644 --- a/src/app/services/default-config.service.ts +++ b/src/app/services/default-config.service.ts @@ -8,6 +8,7 @@ import { SessionRaw } from '@app/sessions/types'; import { TaskOptions, TaskSummary } from '@app/tasks/types'; import { ExportedDefaultConfig, ScopeConfig } from '@app/types/config'; import { ExternalService } from '@app/types/external-service'; +import { LinkType } from '@app/types/graph.types'; import { Sidebar } from '@app/types/navigation'; import { StatusLabelColor } from '@app/types/status'; import { Theme } from '@app/types/themes'; @@ -347,6 +348,13 @@ export class DefaultConfigService { } }; + readonly #defaultGraphLinksColors: Record = { + 'parent': '#8A427AAA', + 'dependency': '#878adeDD', + 'payload': '#00a700ff', + 'output': '#f7b657', + }; + // We use getters to be able to deep copy the default config and to access the default config from the outside get defaultTheme(): Theme { @@ -409,6 +417,10 @@ export class DefaultConfigService { return structuredClone(this.#availableLanguages); } + get defaultGraphLinksColors() { + return structuredClone(this.#defaultGraphLinksColors); + } + readonly #exportedDefaultConfig: ExportedDefaultConfig = { 'language': this.#defaultLanguage, 'navigation-sidebar': this.#defaultSidebar, @@ -456,6 +468,7 @@ export class DefaultConfigService { 'tasks-statuses': this.#defaultTaskStatuses, 'tasks-custom-columns': [], 'sessions-custom-columns': [], + 'graph-links-colors': this.#defaultGraphLinksColors, }; get exportedDefaultConfig(): ExportedDefaultConfig { diff --git a/src/app/types/config.ts b/src/app/types/config.ts index 4bae055a8..3e2c068ea 100644 --- a/src/app/types/config.ts +++ b/src/app/types/config.ts @@ -29,6 +29,7 @@ export type Key = 'sessions-tasks-by-status' | 'partitions-tasks-by-status' | 'tasks-view-in-logs' | + 'graph-links-colors' | `${CustomScope}-custom-columns` | `${Scope}-${Element}` | `${Scope}-show-filters` | From ee5eba26dc5be30281b319a3aefad0f154b1158e Mon Sep 17 00:00:00 2001 From: faustin Date: Thu, 17 Jul 2025 14:26:19 +0200 Subject: [PATCH 12/26] chore: updated highlight code --- src/app/components/graph-legend.component.ts | 2 +- src/app/components/graph.component.spec.ts | 80 ++++++++++---------- src/app/components/graph.component.ts | 69 ++++++++++++++++- test/force-graph.js | 1 + 4 files changed, 111 insertions(+), 41 deletions(-) diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index 205536550..da3176878 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -33,7 +33,7 @@ export class GraphLegendComponent implements OnInit { @Input({ required: true }) set links(entry: Record) { this.linksDescription = Object.keys(entry).map(key => ({ - label: key.replace('Link', ''), + label: key, color: entry[key as LinkType] as string, })); } diff --git a/src/app/components/graph.component.spec.ts b/src/app/components/graph.component.spec.ts index 4d7b8b7a3..5b83a0b33 100644 --- a/src/app/components/graph.component.spec.ts +++ b/src/app/components/graph.component.spec.ts @@ -4,8 +4,10 @@ import { TestBed } from '@angular/core/testing'; import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; -import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; +import { ArmoniKGraphNode, GraphData, GraphLink, LinkType } from '@app/types/graph.types'; +import { DefaultConfigService } from '@services/default-config.service'; import { IconsService } from '@services/icons.service'; +import { StorageService } from '@services/storage.service'; import { Subject } from 'rxjs'; import { GraphComponent } from './graph.component'; @@ -14,6 +16,10 @@ describe('GraphComponent', () => { const grpcObservable = new Subject>>(); + const mockStorageService = { + getItem: jest.fn(), + }; + const mockSessionsStatuses = { statusToLabel: jest.fn(() => ({ label: 'Running', @@ -47,6 +53,8 @@ describe('GraphComponent', () => { component = TestBed.configureTestingModule({ providers: [ GraphComponent, + DefaultConfigService, + { provide: StorageService, useValue: mockStorageService }, { provide: IconsService, useValue: mockIconsService }, { provide: SessionsStatusesService, useValue: mockSessionsStatuses }, { provide: TasksStatusesService, useValue: mockTasksStatuses }, @@ -58,6 +66,7 @@ describe('GraphComponent', () => { component['canvasHeight'] = 100; component['canvasWidth'] = 100; component['graphRef'] = mockGraph; + component.ngOnInit(); component.ngAfterViewInit(); }); @@ -91,26 +100,30 @@ describe('GraphComponent', () => { expect(mockIconsService.getIcon).toHaveBeenCalledWith(name); }); - it('should highlight nodes correctly', () => { - component['nodes'] = [ - { - id: 'abc', - }, - { - id: '123abc', - }, - { - id: '123', - }, - ] as ArmoniKGraphNode[]; + describe('highlightNodes', () => { + beforeEach(() => { + component['nodes'] = [ + { + id: 'abc', + }, + { + id: '123abc', + }, + { + id: '123', + }, + ] as ArmoniKGraphNode[]; + }); - const event = { - target: { - value: 'abc', - }, - } as unknown as Event; - component.highlightNodes(event); - expect(component['nodesToHighlight']).toEqual(new Set(['abc', '123abc'])); + it('should highlight nodes correctly', () => { + const event = 'abc'; + component.highlightNodes(event); + expect(component['nodesToHighlight']).toEqual(new Set(['abc', '123abc'])); + }); + + it('should highlight all parents and children nodes if there is only one matching node', () => { + + }); }); describe('onResize', () => { @@ -221,25 +234,14 @@ describe('GraphComponent', () => { }); describe('getLinkColor', () => { - it('should get the parentlink color', () => { - const link = { - type: 'parent' - } as GraphLink; - expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('parentLink')); - }); - - it('should get the dependencyLink color', () => { - const link = { - type: 'dependency' - } as GraphLink; - expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('dependencyLink')); - }); - - it('should get the taskResultLink color', () => { - const link = { - type: 'output' - } as GraphLink; - expect(component['getLinkColor'](link)).toEqual(component['colorMap'].get('taskResultLink')); + it('should get all kind of link colors', () => { + const types: LinkType[] = ['dependency', 'output', 'parent', 'payload']; + types.forEach(type => { + const link = { + type: type + } as GraphLink; + expect(component['getLinkColor'](link)).toEqual(component.colorMap[type]); + }); }); }); diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 970ed2067..b94128aff 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -72,6 +72,8 @@ export class GraphComponent> private readonly subscription = new Subscription(); private nodes: N[] = []; + private links: L[] = []; + nodesIds: string[] = []; readonly highlightLabel = $localize`Highlight a task`; @@ -95,6 +97,7 @@ export class GraphComponent> .linkColor((link: L) => { return this.getLinkColor(link); }) + .linkDirectionalParticleWidth(15) .linkWidth(4) .nodeLabel('id') .onNodeClick((node: N) => { @@ -127,7 +130,8 @@ export class GraphComponent> } /** - * Hightlight nodes with names included the searched value + * Hightlight nodes with names included the searched value. + * If there is only one node, will display all its parents and children * @param searchedValue */ highlightNodes(searchedValue: string) { @@ -140,6 +144,63 @@ export class GraphComponent> this.nodesToHighlight.add(node.id); } }); + if (this.nodesToHighlight.size === 1) { + const parentsIds = this.getParentNodes([...(this.nodesToHighlight).values()][0]); + const childrenIds = this.getChildrenNodes([...(this.nodesToHighlight).values()][0]); + [...parentsIds, ...childrenIds].forEach(id => this.nodesToHighlight.add(id)); + } + + this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => + this.drawNode(node, ctx) + ); + } + + /** + * Retrieves all parent nodes of the provided node. + * @param nodeId string + * @returns string[] + */ + private getParentNodes(nodeId: string): string[] { + const parentIds: string[] = []; + const links = this.getLinksBySourceId(nodeId); + links.forEach(link => { + const parentId = (link.target as N)?.id ?? link.target; + parentIds.push(parentId, ...this.getParentNodes(parentId)); + }); + return parentIds; + } + + /** + * Retrieves all children nodes of the provided node. + * @param nodeId string + * @returns string[] + */ + private getChildrenNodes(nodeId: string): string[] { + const childrenIds: string[] = []; + const links = this.getLinksByTargetId(nodeId); + links.forEach(link => { + const childrenId = (link.source as N)?.id ?? link.source; + childrenIds.push(childrenId, ...this.getChildrenNodes(childrenId)); + }); + return childrenIds; + } + + /** + * Retrieves the source link from the provided nodeId. + * @param nodeId string + * @returns L[] + */ + private getLinksBySourceId(nodeId: string): L[] { + return this.links.filter(link => link.source === nodeId || (link.source as N).id === nodeId); + } + + /** + * Retrieves the target link from the provided nodeId + * @param nodeId string + * @returns L[] + */ + private getLinksByTargetId(nodeId: string): L[] { + return this.links.filter(link => link.target === nodeId || (link.target as N).id === nodeId); } /** @@ -168,6 +229,7 @@ export class GraphComponent> */ private subscribeToData(result: GraphData) { this.nodes = result.nodes; + this.links = result.links; this.nodesIds = result.nodes.map((node) => node.id); this.graph.graphData({ nodes: result.nodes, links: result.links }); } @@ -179,6 +241,11 @@ export class GraphComponent> */ private drawNode(node: N, ctx: CanvasRenderingContext2D) { if (node.x !== undefined && node.y !== undefined) { + if (this.nodesToHighlight.has(node.id)) { + ctx.font = '70px Material Icons'; + ctx.fillStyle = 'black'; + ctx.fillText(this.iconsService.getIcon(`${node.type}-graph-icon`), node.x - 35, node.y + 35); + } const label = this.getNodeStatusData(node); ctx.font = '50px Material Icons'; ctx.fillStyle = label.color; diff --git a/test/force-graph.js b/test/force-graph.js index a03deeabc..30e353b87 100644 --- a/test/force-graph.js +++ b/test/force-graph.js @@ -49,4 +49,5 @@ module.exports = class ForceGraph { height = jest.fn(() => this); linkDirectionalParticles = jest.fn(() => this); + linkDirectionalParticleWidth = jest.fn(() => this); } \ No newline at end of file From fc6d386d405d6627b184cfb37cbfaee13205bcb0 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 14:16:48 +0200 Subject: [PATCH 13/26] test: graph component --- src/app/components/graph.component.spec.ts | 77 +++++++++++++++------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/src/app/components/graph.component.spec.ts b/src/app/components/graph.component.spec.ts index 5b83a0b33..cc05a84a6 100644 --- a/src/app/components/graph.component.spec.ts +++ b/src/app/components/graph.component.spec.ts @@ -101,18 +101,35 @@ describe('GraphComponent', () => { }); describe('highlightNodes', () => { + const nodes = [ + { + id: 'abc', + }, + { + id: '123abc', + }, + { + id: '123', + }, + { + id: '1234', + }, + ] as ArmoniKGraphNode[]; + + const links = [ + { + source: '123', + target: '123abc', + }, + { + source: '123abc', + target: '1234', + } + ] as GraphLink[]; + beforeEach(() => { - component['nodes'] = [ - { - id: 'abc', - }, - { - id: '123abc', - }, - { - id: '123', - }, - ] as ArmoniKGraphNode[]; + component['nodes'] = nodes; + component['links'] = links; }); it('should highlight nodes correctly', () => { @@ -122,7 +139,9 @@ describe('GraphComponent', () => { }); it('should highlight all parents and children nodes if there is only one matching node', () => { - + const event = '123abc'; + component.highlightNodes(event); + expect(component['nodesToHighlight']).toEqual(new Set(['123', '123abc', '1234'])); }); }); @@ -168,24 +187,38 @@ describe('GraphComponent', () => { }); }); - it('should draw a node', () => { + describe('drawNode', () => { + let mockCtx: CanvasRenderingContext2D; + const node = { + id: '1', x: 0, y: 0, type: 'session', } as ArmoniKGraphNode; - const mockCtx = { - fillText: jest.fn(), - } as unknown as CanvasRenderingContext2D; + beforeEach(() => { + mockCtx = { + fillText: jest.fn(), + } as unknown as CanvasRenderingContext2D; + }); - component['drawNode'](node, mockCtx); + it('should draw a node', () => { + component['drawNode'](node, mockCtx); - expect(mockCtx.fillText).toHaveBeenCalledWith( - `${node.type}-graph-icon`, - node.x! - 25, - node.y! + 25, - ); + expect(mockCtx.fillText).toHaveBeenCalledWith( + `${node.type}-graph-icon`, + node.x! - 25, + node.y! + 25, + ); + }); + + it('should highlight a node if its id is in the nodesToHighlight', () => { + component['nodesToHighlight'].add('1'); + component['drawNode'](node, mockCtx); + + expect(mockCtx.fillText).toHaveBeenCalledTimes(2); + }); }); describe('getNodeStatusData', () => { From 0bb350f8d05d634c4530c8f5b7cc5737588b5000 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 14:27:06 +0200 Subject: [PATCH 14/26] chore: tests and rework for graph legend component --- .../components/graph-legend.component.html | 6 +- .../components/graph-legend.component.spec.ts | 69 +++++++++---------- src/app/components/graph-legend.component.ts | 16 +---- src/app/services/default-config.service.ts | 8 +-- 4 files changed, 40 insertions(+), 59 deletions(-) diff --git a/src/app/components/graph-legend.component.html b/src/app/components/graph-legend.component.html index 5aa8b315d..6161f4894 100644 --- a/src/app/components/graph-legend.component.html +++ b/src/app/components/graph-legend.component.html @@ -9,7 +9,7 @@

Sessions Statuses

- @for (status of sessionsStatuses; track status) { + @for (status of sessionsStatusesService.keys; track status) { @let statusData = sessionsStatusesService.statusToLabel(status); @@ -27,7 +27,7 @@

Sessions Statuses

Tasks Statuses

- @for (status of tasksStatuses; track status) { + @for (status of tasksStatusesService.keys; track status) { @let statusData = tasksStatusesService.statusToLabel(status); @@ -45,7 +45,7 @@

Tasks Statuses

Results Statuses

- @for (status of resultsStatuses; track status) { + @for (status of resultsStatusesService.keys; track status) { @let statusData = resultsStatusesService.statusToLabel(status); diff --git a/src/app/components/graph-legend.component.spec.ts b/src/app/components/graph-legend.component.spec.ts index 2ad37b284..bad709ae7 100644 --- a/src/app/components/graph-legend.component.spec.ts +++ b/src/app/components/graph-legend.component.spec.ts @@ -1,8 +1,8 @@ -import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; import { TestBed } from '@angular/core/testing'; import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { LinkType } from '@app/types/graph.types'; import { IconsService } from '@services/icons.service'; import { GraphLegendComponent } from './graph-legend.component'; @@ -10,42 +10,28 @@ describe('GraphLegendComponent', () => { let component: GraphLegendComponent; const mockTasksStatusesService = { - statuses: { - [TaskStatus.TASK_STATUS_CANCELLED]: { - label: 'cancelled' - }, - [TaskStatus.TASK_STATUS_CREATING]: { - label: 'creating' - }, - }, + keys: ['Cancelled', 'Creating'], }; const mockSessionsStatusesService = { - statuses: { - [SessionStatus.SESSION_STATUS_CANCELLED]: { - label: 'Cancelled', - }, - [SessionStatus.SESSION_STATUS_CLOSED]: { - label: 'Closed', - }, - }, + keys: ['Cancelled', 'Closed'], }; const mockResultsStatusesService = { - statuses: { - [ResultStatus.RESULT_STATUS_ABORTED]: { - label: 'Aborted', - }, - [ResultStatus.RESULT_STATUS_COMPLETED]: { - label: 'Completed' - }, - }, + keys: ['Aborted', 'Completed'], }; const mockIconsService = { getIcon: jest.fn(), }; + const links: Record = { + dependency: 'blue', + output: 'red', + parent: 'yellow', + payload: 'green' + }; + beforeEach(() => { component = TestBed.configureTestingModule({ providers: [ @@ -56,25 +42,32 @@ describe('GraphLegendComponent', () => { { provide: IconsService, useValue: mockIconsService }, ] }).inject(GraphLegendComponent); - component.ngOnInit(); + component.links = links; }); it('should create', () => { expect(component).toBeTruthy(); }); - describe('initialisation', () => { - it('should set sessionsStatuses', () => { - expect(component.sessionsStatuses).toEqual([SessionStatus.SESSION_STATUS_CANCELLED, SessionStatus.SESSION_STATUS_CLOSED]); - }); - - it('should set TaskStatuses', () => { - expect(component.tasksStatuses).toEqual([TaskStatus.TASK_STATUS_CANCELLED, TaskStatus.TASK_STATUS_CANCELLING]); - }); - - it('should set resultsStatuses', () => { - expect(component.resultsStatuses).toEqual([ResultStatus.RESULT_STATUS_ABORTED, ResultStatus.RESULT_STATUS_COMPLETED]); - }); + it('should initialize linksDescription', () => { + expect(component.linksDescription).toEqual([ + { + label: 'dependency', + color: 'blue', + }, + { + label: 'output', + color: 'red', + }, + { + label: 'parent', + color: 'yellow', + }, + { + label: 'payload', + color: 'green', + }, + ]); }); it('should get icons', () => { diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index da3176878..6ef0c0bd9 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -1,5 +1,4 @@ -import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; -import { ChangeDetectionStrategy, Component, Input, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, inject } from '@angular/core'; import { MatChipsModule } from '@angular/material/chips'; import { MatDividerModule } from '@angular/material/divider'; import { MatExpansionModule } from '@angular/material/expansion'; @@ -25,7 +24,7 @@ import { IconsService } from '@services/icons.service'; ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class GraphLegendComponent implements OnInit { +export class GraphLegendComponent { private readonly iconsService = inject(IconsService); readonly sessionsStatusesService = inject(SessionsStatusesService); readonly tasksStatusesService = inject(TasksStatusesService); @@ -40,17 +39,6 @@ export class GraphLegendComponent implements OnInit { linksDescription: { label: string, color: string }[]; - // TODO: this part will be useless when statuses are merged - sessionsStatuses: SessionStatus[]; - tasksStatuses: TaskStatus[]; - resultsStatuses: ResultStatus[]; - - ngOnInit(): void { - this.sessionsStatuses = Object.keys(this.sessionsStatusesService.statuses).map((key) => Number(key) as SessionStatus); - this.tasksStatuses = Object.keys(this.tasksStatusesService.statuses).map((key) => Number(key) as TaskStatus); - this.resultsStatuses = Object.keys(this.resultsStatusesService.statuses).map((key) => Number(key) as ResultStatus); - } - getIcon(name: string | undefined) { return this.iconsService.getIcon(name); } diff --git a/src/app/services/default-config.service.ts b/src/app/services/default-config.service.ts index 3ef4f15e6..878507bb5 100644 --- a/src/app/services/default-config.service.ts +++ b/src/app/services/default-config.service.ts @@ -349,10 +349,10 @@ export class DefaultConfigService { }; readonly #defaultGraphLinksColors: Record = { - 'parent': '#8A427AAA', - 'dependency': '#878adeDD', - 'payload': '#00a700ff', - 'output': '#f7b657', + parent: '#8A427AAA', + dependency: '#878adeDD', + payload: '#00a700ff', + output: '#f7b657', }; // We use getters to be able to deep copy the default config and to access the default config from the outside From 0860c54b40f72439a98f7806cc9ed6d572b9bcf5 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 16:29:50 +0200 Subject: [PATCH 15/26] test: graph data service, grpc event and graph session component --- src/app/services/graph-data.service.spec.ts | 397 +++++++++++++++++++ src/app/services/grpc-events.service.spec.ts | 32 ++ src/app/sessions/graph.component.spec.ts | 65 +++ 3 files changed, 494 insertions(+) create mode 100644 src/app/services/graph-data.service.spec.ts create mode 100644 src/app/services/grpc-events.service.spec.ts create mode 100644 src/app/sessions/graph.component.spec.ts diff --git a/src/app/services/graph-data.service.spec.ts b/src/app/services/graph-data.service.spec.ts new file mode 100644 index 000000000..5901139cc --- /dev/null +++ b/src/app/services/graph-data.service.spec.ts @@ -0,0 +1,397 @@ +import { EventSubscriptionResponse, ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { ArmoniKGraphNode, GraphLink } from '@app/types/graph.types'; +import { Subject, Subscription } from 'rxjs'; +import { GraphDataService } from './graph-data.service'; +import { GrpcEventsService } from './grpc-events.service'; + +describe('GraphDataService', () => { + let service: GraphDataService; + + let subscription: Subscription; + + const events = new Subject(); + const mockGrpcEventsService = { + getEvents$: jest.fn(() => events), + }; + + const sessionId = 'session'; + + const sessionNode: ArmoniKGraphNode = { + id: sessionId, + status: SessionStatus.SESSION_STATUS_RUNNING, + type: 'session', + }; + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + GraphDataService, + { provide: GrpcEventsService, useValue: mockGrpcEventsService }, + ], + }).inject(GraphDataService); + service.sessionId = sessionId; + subscription = service.listenToEvents().subscribe(); + }); + + afterEach(() => { + subscription.unsubscribe(); + }); + + it('should create', () => { + expect(service).toBeTruthy(); + }); + + describe('new Task', () => { + const startingNodes = [ + { + id: 'task-parent', + status: TaskStatus.TASK_STATUS_COMPLETED, + type: 'task' + }, + { + id: 'result-1', + status: ResultStatus.RESULT_STATUS_COMPLETED, + type: 'result', + }, + ] as ArmoniKGraphNode[]; + + const event: EventSubscriptionResponse = { + update: EventSubscriptionResponse.UpdateCase.newTask, + newTask: { + taskId: 'task', + status: TaskStatus.TASK_STATUS_CREATING, + payloadId: 'result-payload', + parentTaskIds: ['task-parent'], + dataDependencies: [ + 'result-1', 'result-2', + ], + } as EventSubscriptionResponse.NewTask + } as EventSubscriptionResponse; + + beforeEach(() => { + service.nodes.push( + ...startingNodes, + ); + }); + + it('should add a task to the nodes', () => { + events.next(event); + expect(service.nodes).toEqual([ + sessionNode, + ...startingNodes, + { + id: event.newTask!.taskId, + status: event.newTask!.status, + type: 'task' + } + ]); + }); + + it('should add task dependencies to links', () => { + events.next(event); + expect(service.links).toEqual[]>( + event.newTask!.dataDependencies.map((dependency) => ({ + type: 'dependency', + source: dependency, + target: event.newTask!.taskId + })), + ); + }); + + describe('with payloadId and no dataDependency', () => { + beforeEach(() => { + event.newTask!.dataDependencies = []; + events.next(event); + }); + + it('should add a payload link if there is no data dependency', () => { + expect(service.links).toEqual[]>( + [ + { + type: 'payload', + source: event.newTask!.payloadId, + target: event.newTask!.taskId, + }, + { + type: 'parent', + source: event.newTask!.parentTaskIds.at(-1), + target: event.newTask!.payloadId, + } + ] + ); + }); + + it('should add the payload to the nodes', () => { + expect(service.nodes).toEqual([ + sessionNode, + ...startingNodes, + { + id: event.newTask!.taskId, + status: event.newTask!.status, + type: 'task' + }, + { + id: event.newTask!.payloadId, + status: ResultStatus.RESULT_STATUS_UNSPECIFIED, + type: 'result' + }, + ]); + }); + }); + }); + + describe('new Result', () => { + const event: EventSubscriptionResponse = { + update: EventSubscriptionResponse.UpdateCase.newResult, + newResult: { + resultId: 'result', + status: ResultStatus.RESULT_STATUS_CREATED, + ownerId: 'task' + } as EventSubscriptionResponse.NewResult, + } as EventSubscriptionResponse; + + beforeEach(() => { + events.next(event); + }); + + it('should add the result node and its owner if it does not exists', () => { + expect(service.nodes).toEqual([ + sessionNode, + { + id: event.newResult!.resultId, + status: event.newResult!.status, + type: 'result', + }, + { + id: event.newResult!.ownerId, + status: TaskStatus.TASK_STATUS_UNSPECIFIED, + type: 'task', + }, + ]); + }); + + it('should add the link between the result node and its owner', () => { + expect(service.links).toEqual[]>([ + { + type: 'output', + source: event.newResult!.ownerId, + target: event.newResult!.resultId, + } + ]); + }); + }); + + describe('taskStatusUpdate', () => { + const startingNodes: ArmoniKGraphNode[] = [ + { + id: 'task', + status: TaskStatus.TASK_STATUS_PROCESSING, + type: 'task', + }, + ]; + + const event: EventSubscriptionResponse = { + update: EventSubscriptionResponse.UpdateCase.taskStatusUpdate, + taskStatusUpdate: { + taskId: 'task', + status: TaskStatus.TASK_STATUS_PAUSED, + } as EventSubscriptionResponse.TaskStatusUpdate + } as EventSubscriptionResponse; + + beforeEach(() => { + service.nodes.push(...startingNodes); + events.next(event); + }); + + it('should change the status of the specified node', () => { + expect(service.nodes).toEqual([ + sessionNode, + { + id: event.taskStatusUpdate!.taskId, + status: event.taskStatusUpdate!.status, + type: 'task', + }, + ]); + }); + }); + + describe('resultStatusUpdate', () => { + const startingNodes: ArmoniKGraphNode[] = [ + { + id: 'result', + status: ResultStatus.RESULT_STATUS_CREATED, + type: 'result', + }, + ]; + + const event: EventSubscriptionResponse = { + update: EventSubscriptionResponse.UpdateCase.resultStatusUpdate, + resultStatusUpdate: { + resultId: 'result', + status: ResultStatus.RESULT_STATUS_DELETED, + } as EventSubscriptionResponse.ResultStatusUpdate, + } as EventSubscriptionResponse; + + beforeEach(() => { + service.nodes.push(...startingNodes); + events.next(event); + }); + + it('should change the status of the specified node', () => { + expect(service.nodes).toEqual([ + sessionNode, + { + id: event.resultStatusUpdate!.resultId, + status: event.resultStatusUpdate!.status, + type: 'result', + }, + ]); + }); + }); + + describe('resultOwnerUpdate', () => { + const startingLinks: GraphLink[] = [ + { + type: 'output', + source: 'task-1', + target: 'result', + }, + ]; + + const event: EventSubscriptionResponse = { + update: EventSubscriptionResponse.UpdateCase.resultOwnerUpdate, + resultOwnerUpdate: { + resultId: 'result', + previousOwnerId: 'task-1', + currentOwnerId: 'task-2' + } as EventSubscriptionResponse.ResultOwnerUpdate, + } as EventSubscriptionResponse; + + it('should change the owner of the specified link', () => { + service.links.push(...startingLinks); + events.next(event); + expect(service.links).toEqual[]>([ + { + type: 'output', + source: event.resultOwnerUpdate!.currentOwnerId, + target: event.resultOwnerUpdate!.resultId, + }, + ]); + }); + + it('should create the link if it does not exists', () => { + events.next(event); + expect(service.links).toEqual[]>([ + { + type: 'output', + source: event.resultOwnerUpdate!.currentOwnerId, + target: event.resultOwnerUpdate!.resultId, + }, + ]); + }); + }); + + it('should catch an unknown event', () => { + const spy = jest.spyOn(console, 'warn'); + spy.mockImplementationOnce(() => {}); + const event: EventSubscriptionResponse = { + update: 'some random unknown event' as unknown as EventSubscriptionResponse.UpdateCase, + } as EventSubscriptionResponse; + events.next(event); + expect(spy).toHaveBeenCalledWith('Unknown Grpc Update Event.'); + }); + + describe('createNode', () => { + it('should create a node if it does not exists', () => { + service['createNode']('task', TaskStatus.TASK_STATUS_PROCESSED, 'task'); + expect(service.nodes).toEqual([ + sessionNode, + { + id: 'task', + status: TaskStatus.TASK_STATUS_PROCESSED, + type: 'task' + } + ]); + }); + + it('should update a node status if it already exists', () => { + service.nodes.push({ + id: 'task', + status: TaskStatus.TASK_STATUS_UNSPECIFIED, + type: 'task', + }); + service['createNode']('task', TaskStatus.TASK_STATUS_PROCESSED, 'task'); + expect(service.nodes).toEqual([ + sessionNode, + { + id: 'task', + status: TaskStatus.TASK_STATUS_PROCESSED, + type: 'task' + } + ]); + }); + }); + + describe('addLink', () => { + it('should add a link that does not exists', () => { + service['addLink']('result', 'task-parent', 'output'); + expect(service.links).toEqual[]>([ + { + target: 'result', + source: 'task-parent', + type: 'output', + } + ]); + }); + + it('should not add or update a link that already exists', () => { + const startingLink = { + target: 'result', + source: 'task-parent', + type: 'output', + } as GraphLink; + service.links.push(startingLink); + service['addLink']('result', 'task-parent', 'dependency'); + expect(service.links).toEqual[]>([ + startingLink + ]); + }); + + it('should add a link with a target already in the links array', () => { + const startingLink = { + target: 'result', + source: 'task-parent', + type: 'output', + } as GraphLink; + service.links.push(startingLink); + service['addLink']('result', 'task-parent-2', 'output'); + expect(service.links).toEqual[]>([ + startingLink, + { + target: 'result', + source: 'task-parent-2', + type: 'output', + } + ]); + }); + + it('should add a link with a source already in the links array', () => { + const startingLink = { + target: 'result', + source: 'task-parent', + type: 'output', + } as GraphLink; + service.links.push(startingLink); + service['addLink']('result-2', 'task-parent', 'output'); + expect(service.links).toEqual[]>([ + startingLink, + { + target: 'result-2', + source: 'task-parent', + type: 'output', + } + ]); + }); + }); +}); \ No newline at end of file diff --git a/src/app/services/grpc-events.service.spec.ts b/src/app/services/grpc-events.service.spec.ts new file mode 100644 index 000000000..b45bb4bdb --- /dev/null +++ b/src/app/services/grpc-events.service.spec.ts @@ -0,0 +1,32 @@ +import { EventsClient, EventSubscriptionRequest } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { GrpcEventsService } from './grpc-events.service'; + +describe('GrpcEventsService', () => { + let service: GrpcEventsService; + + const mockEventsClient = { + getEvents: jest.fn(), + }; + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + GrpcEventsService, + { provide: EventsClient, useValue: mockEventsClient }, + ], + }).inject(GrpcEventsService); + }); + + it('should create', () => { + expect(service).toBeTruthy(); + }); + + it('should get events', () => { + const sessionId = 'session'; + service.getEvents$(sessionId); + expect(mockEventsClient.getEvents).toHaveBeenCalledWith(new EventSubscriptionRequest({ + sessionId: sessionId, + })); + }); +}); \ No newline at end of file diff --git a/src/app/sessions/graph.component.spec.ts b/src/app/sessions/graph.component.spec.ts new file mode 100644 index 000000000..565eb5406 --- /dev/null +++ b/src/app/sessions/graph.component.spec.ts @@ -0,0 +1,65 @@ +import { TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { GraphDataService } from '@services/graph-data.service'; +import { Observable, Subject } from 'rxjs'; +import { SessionGraphComponent } from './graph.component'; + +describe('SessionGraphComponent', () => { + let component: SessionGraphComponent; + + const mockGrpcEvent = new Observable(); + const mockGraphDataService = { + listenToEvents: jest.fn(() => mockGrpcEvent), + sessionId: null, + }; + + const mockParams = new Subject>(); + const mockRoute = { + params: mockParams + }; + + const sessionId = 'sessionId'; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + SessionGraphComponent, + { provide: GraphDataService, useValue: mockGraphDataService }, + { provide: ActivatedRoute, useValue: mockRoute }, + ] + }).inject(SessionGraphComponent); + component.ngOnInit(); + mockParams.next({ 'id': sessionId }); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('initialisation', () => { + it('should set the component id', () => { + expect(component.id).toEqual(sessionId); + }); + + it('should set the graphService sessionId', () => { + expect(mockGraphDataService.sessionId).toEqual(sessionId); + }); + + it('should set the grpcObservable', () => { + expect(component.grpcObservable).toBe(mockGrpcEvent); + }); + }); + + describe('destruction', () => { + let spy: jest.SpyInstance; + + beforeEach(() => { + spy = jest.spyOn(component['subscriptions'], 'unsubscribe'); + component.ngOnDestroy(); + }); + + it('should unsubscribe', () => { + expect(spy).toHaveBeenCalled(); + }); + }); +}); \ No newline at end of file From b6812f1270e16a4542cb8f3fb00b33095facc961 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 16:30:05 +0200 Subject: [PATCH 16/26] chore: add on destroy method to session graph component --- src/app/sessions/graph.component.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/sessions/graph.component.ts b/src/app/sessions/graph.component.ts index 67cae064e..76d0d3b58 100644 --- a/src/app/sessions/graph.component.ts +++ b/src/app/sessions/graph.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, inject } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ArmoniKGraphNode, GraphData, GraphLink } from '@app/types/graph.types'; import { GraphComponent } from '@components/graph.component'; @@ -19,7 +19,7 @@ import { Observable, Subscription, map } from 'rxjs'; ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class SessionGraphComponent implements OnInit { +export class SessionGraphComponent implements OnInit, OnDestroy { id: string; grpcObservable: Observable>>; @@ -40,4 +40,8 @@ export class SessionGraphComponent implements OnInit { this.subscriptions.add(routeSubscription); } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } } \ No newline at end of file From 2aefb17d90c99b574b00521f47dc1c194b2bb5f1 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 17:11:29 +0200 Subject: [PATCH 17/26] chore: address sonarqube comments --- src/app/components/graph-legend.component.ts | 2 +- test/force-graph.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index 6ef0c0bd9..6f3befcce 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -33,7 +33,7 @@ export class GraphLegendComponent { @Input({ required: true }) set links(entry: Record) { this.linksDescription = Object.keys(entry).map(key => ({ label: key, - color: entry[key as LinkType] as string, + color: entry[key as LinkType], })); } diff --git a/test/force-graph.js b/test/force-graph.js index 30e353b87..d07567ae6 100644 --- a/test/force-graph.js +++ b/test/force-graph.js @@ -1,6 +1,4 @@ module.exports = class ForceGraph { - constructor(value) {} - node = { x: 0, y: 0, From 6baf1c3afd3899ec1916266d84ea958b00e81e75 Mon Sep 17 00:00:00 2001 From: faustin Date: Wed, 23 Jul 2025 17:12:01 +0200 Subject: [PATCH 18/26] chore: address sonarqube comments --- src/app/components/graph-legend.component.ts | 2 +- test/force-graph.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/components/graph-legend.component.ts b/src/app/components/graph-legend.component.ts index 6ef0c0bd9..6f3befcce 100644 --- a/src/app/components/graph-legend.component.ts +++ b/src/app/components/graph-legend.component.ts @@ -33,7 +33,7 @@ export class GraphLegendComponent { @Input({ required: true }) set links(entry: Record) { this.linksDescription = Object.keys(entry).map(key => ({ label: key, - color: entry[key as LinkType] as string, + color: entry[key as LinkType], })); } diff --git a/test/force-graph.js b/test/force-graph.js index 30e353b87..d07567ae6 100644 --- a/test/force-graph.js +++ b/test/force-graph.js @@ -1,6 +1,4 @@ module.exports = class ForceGraph { - constructor(value) {} - node = { x: 0, y: 0, From 41eab89cd0ff08c219f57b3cb8df67beef26dcca Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Mon, 28 Jul 2025 14:07:34 +0200 Subject: [PATCH 19/26] fix: "flying" results in the graph --- src/app/services/graph-data.service.spec.ts | 68 +++++++-------------- src/app/services/graph-data.service.ts | 5 +- 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/src/app/services/graph-data.service.spec.ts b/src/app/services/graph-data.service.spec.ts index 5901139cc..b9af17c47 100644 --- a/src/app/services/graph-data.service.spec.ts +++ b/src/app/services/graph-data.service.spec.ts @@ -75,7 +75,7 @@ describe('GraphDataService', () => { ); }); - it('should add a task to the nodes', () => { + it('should add a task to the nodes, as well as its dependencies and payload', () => { events.next(event); expect(service.nodes).toEqual([ sessionNode, @@ -84,60 +84,36 @@ describe('GraphDataService', () => { id: event.newTask!.taskId, status: event.newTask!.status, type: 'task' - } + }, + { + id: event.newTask!.payloadId, + status: ResultStatus.RESULT_STATUS_UNSPECIFIED, + type: 'result' + }, ]); }); - it('should add task dependencies to links', () => { + it('should add task dependencies and payload to links', () => { events.next(event); expect(service.links).toEqual[]>( - event.newTask!.dataDependencies.map((dependency) => ({ - type: 'dependency', - source: dependency, - target: event.newTask!.taskId - })), - ); - }); - - describe('with payloadId and no dataDependency', () => { - beforeEach(() => { - event.newTask!.dataDependencies = []; - events.next(event); - }); - - it('should add a payload link if there is no data dependency', () => { - expect(service.links).toEqual[]>( - [ - { - type: 'payload', - source: event.newTask!.payloadId, - target: event.newTask!.taskId, - }, - { - type: 'parent', - source: event.newTask!.parentTaskIds.at(-1), - target: event.newTask!.payloadId, - } - ] - ); - }); - - it('should add the payload to the nodes', () => { - expect(service.nodes).toEqual([ - sessionNode, - ...startingNodes, + [ { - id: event.newTask!.taskId, - status: event.newTask!.status, - type: 'task' + type: 'payload', + source: event.newTask!.payloadId, + target: event.newTask!.taskId, }, { - id: event.newTask!.payloadId, - status: ResultStatus.RESULT_STATUS_UNSPECIFIED, - type: 'result' + type: 'parent', + source: event.newTask!.parentTaskIds.at(-1), + target: event.newTask!.payloadId, }, - ]); - }); + ...event.newTask!.dataDependencies.map((dependency) => ({ + type: 'dependency', + source: dependency, + target: event.newTask!.taskId + } as GraphLink)), + ] + ); }); }); diff --git a/src/app/services/graph-data.service.ts b/src/app/services/graph-data.service.ts index 898ac5d40..487344857 100644 --- a/src/app/services/graph-data.service.ts +++ b/src/app/services/graph-data.service.ts @@ -104,9 +104,10 @@ export class GraphDataService { private addTask(newTask: EventSubscriptionResponse.NewTask | undefined) { if (newTask) { this.createNode(newTask.taskId, newTask.status, 'task'); - if (newTask.dataDependencies.length === 0) { + if (newTask.payloadId?.length !== 0) { this.addPayload(newTask); - } else { + } + if (newTask.dataDependencies.length !== 0) { newTask.dataDependencies.forEach(dependencyId => { this.addDependency(newTask.taskId, dependencyId); }); From 4625c6caf5cfefd40af4bbab52390544201274ea Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Mon, 28 Jul 2025 16:53:53 +0200 Subject: [PATCH 20/26] chore: add highlight detail --- src/app/components/graph.component.css | 2 +- src/app/components/graph.component.html | 10 ++- src/app/components/graph.component.spec.ts | 73 +++++++++++++++++++- src/app/components/graph.component.ts | 78 +++++++++++++++++++--- src/app/services/default-config.service.ts | 13 ++++ src/app/types/config.ts | 2 + 6 files changed, 164 insertions(+), 14 deletions(-) diff --git a/src/app/components/graph.component.css b/src/app/components/graph.component.css index f5977a712..cb198a71f 100644 --- a/src/app/components/graph.component.css +++ b/src/app/components/graph.component.css @@ -47,5 +47,5 @@ app-graph-legend { .graph { overflow: hidden; - height: 80vh; + height: 90vh; } \ No newline at end of file diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index ba7e8c1d8..d58e3c2e5 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -5,7 +5,7 @@

Session: {{ sessionId }}

-
@@ -18,12 +18,18 @@

+ + Highlight parent nodes + + + Highlight children nodes + Display Particles diff --git a/src/app/components/graph.component.spec.ts b/src/app/components/graph.component.spec.ts index cc05a84a6..a493c82ca 100644 --- a/src/app/components/graph.component.spec.ts +++ b/src/app/components/graph.component.spec.ts @@ -18,6 +18,7 @@ describe('GraphComponent', () => { const mockStorageService = { getItem: jest.fn(), + setItem: jest.fn(), }; const mockSessionsStatuses = { @@ -138,8 +139,24 @@ describe('GraphComponent', () => { expect(component['nodesToHighlight']).toEqual(new Set(['abc', '123abc'])); }); - it('should highlight all parents and children nodes if there is only one matching node', () => { + it('should highlight all parents nodes if there is only one matching node and highlightParentNodes is true', () => { const event = '123abc'; + component.highlightParentNodes = true; + component.highlightNodes(event); + expect(component['nodesToHighlight']).toEqual(new Set(['123', '123abc'])); + }); + + it('should highlight all parents nodes if there is only one matching node and highlightChildrenNodes is true', () => { + const event = '123abc'; + component.highlightChildrenNodes = true; + component.highlightNodes(event); + expect(component['nodesToHighlight']).toEqual(new Set(['123abc', '1234'])); + }); + + it('should highlight both parents and children nodes if there is only one matching node and highlightChildrenNodes and highlightParentNodes are true', () => { + const event = '123abc'; + component.highlightChildrenNodes = true; + component.highlightParentNodes = true; component.highlightNodes(event); expect(component['nodesToHighlight']).toEqual(new Set(['123', '123abc', '1234'])); }); @@ -321,4 +338,58 @@ describe('GraphComponent', () => { expect(component['graph'].zoom).toHaveBeenCalled(); }); }); + + describe('toggleHighlightChildrenNodes', () => { + const checked = true; + let spy: jest.SpyInstance; + + beforeEach(() => { + spy = jest.spyOn(component, 'highlightNodes'); + component['highlightChildrenNodes'] = !checked; + component['nodeToHighlight'] = null; + }); + + it('should set the provided value as highlightChildrenNodes', () => { + component.toggleHighlightChildrenNodes(checked); + expect(component['highlightChildrenNodes']).toEqual(checked); + }); + + it('should not highlight the nodes if there is no nodes to hightlight', () => { + component.toggleHighlightChildrenNodes(checked); + expect(spy).not.toHaveBeenCalled(); + }); + + it('should hightlight the nodes if there is a node to highlight', () => { + component['nodeToHighlight'] = 'some node'; + component.toggleHighlightChildrenNodes(checked); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('toggleHighlightChildrenNodes', () => { + const checked = true; + let spy: jest.SpyInstance; + + beforeEach(() => { + spy = jest.spyOn(component, 'highlightNodes'); + component['highlightParentNodes'] = !checked; + component['nodeToHighlight'] = null; + }); + + it('should set the provided value as highlightChildrenNodes', () => { + component.toggleHighlightChildrenNodes(checked); + expect(component['highlightChildrenNodes']).toEqual(checked); + }); + + it('should not highlight the nodes if there is no nodes to hightlight', () => { + component.toggleHighlightParentNodes(checked); + expect(spy).not.toHaveBeenCalled(); + }); + + it('should hightlight the nodes if there is a node to highlight', () => { + component['nodeToHighlight'] = 'some node'; + component.toggleHighlightParentNodes(checked); + expect(spy).toHaveBeenCalled(); + }); + }); }); \ No newline at end of file diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index b94128aff..081a72c35 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -57,6 +57,9 @@ export class GraphComponent> private canvasHeight: number = window.innerHeight; private readonly nodesToHighlight: Set = new Set(); + highlightParentNodes = false; + highlightChildrenNodes = false; + private nodeToHighlight: string | null; colorMap: Record; @@ -79,7 +82,13 @@ export class GraphComponent> ngOnInit(): void { const storedColorMap = this.storageService.getItem>('graph-links-colors', true) as Record | null; - this.colorMap = storedColorMap ?? this.defaultConfigService.defaultGraphLinksColors; + this.colorMap = storedColorMap ?? this.defaultConfigService.defaultGraphLinksColors; + + const storedHighlightParents = this.storageService.getItem('graph-highlight-parents', true) as boolean; + this.highlightParentNodes = storedHighlightParents ?? this.defaultConfigService.defaultGraphHighlightParents; + + const storedHighlightChildren = this.storageService.getItem('graph-highlight-children', true) as boolean; + this.highlightChildrenNodes = storedHighlightChildren ?? this.defaultConfigService.defaultGraphHighlightChildren; } ngAfterViewInit(): void { @@ -129,6 +138,46 @@ export class GraphComponent> return this.iconsService.getIcon(name); } + /** + * Updates and stores highlightParentNodes. + * @param checked boolean + */ + toggleHighlightParentNodes(checked: boolean) { + this.highlightParentNodes = checked; + this.storageService.setItem('graph-highlight-parents', checked); + if (this.nodeToHighlight !== null) { + this.highlightNodes(this.nodeToHighlight); + } + } + + /** + * Updates and stores highlightChildrenNodes. + * @param checked boolean + */ + toggleHighlightChildrenNodes(checked: boolean) { + this.highlightChildrenNodes = checked; + this.storageService.setItem('graph-highlight-children', checked); + if (this.nodeToHighlight !== null) { + this.highlightNodes(this.nodeToHighlight); + } + } + + /** + * Returns the complementary color of the provided color + * @param color hexadecimal color + * @returns hexadecimal color + */ + getComplementaryColor(color: string) { + const colorHex = color.replace('#', ''); + const colorDec = parseInt(colorHex, 16); + let complementaryHex = ((1 << 4 * colorHex.length) - 1 - colorDec).toString(16); + + while (complementaryHex.length < colorHex.length) { + complementaryHex = '0' + complementaryHex; + } + return '#' + complementaryHex; + } + /** * Hightlight nodes with names included the searched value. * If there is only one node, will display all its parents and children @@ -136,6 +185,7 @@ export class GraphComponent> */ highlightNodes(searchedValue: string) { this.nodesToHighlight.clear(); + this.nodeToHighlight = searchedValue; this.nodes.forEach((node: ArmoniKGraphNode) => { if ( searchedValue !== '' && @@ -145,9 +195,15 @@ export class GraphComponent> } }); if (this.nodesToHighlight.size === 1) { - const parentsIds = this.getParentNodes([...(this.nodesToHighlight).values()][0]); - const childrenIds = this.getChildrenNodes([...(this.nodesToHighlight).values()][0]); - [...parentsIds, ...childrenIds].forEach(id => this.nodesToHighlight.add(id)); + const nodeId = [...(this.nodesToHighlight).values()][0]; + const node = this.nodes.find(node => node.id === nodeId) as ArmoniKGraphNode; + this.graph.centerAt(node.x, node.y, 500); + if (this.highlightParentNodes) { + this.getParentNodes(nodeId).forEach(id => this.nodesToHighlight.add(id)); + } + if (this.highlightChildrenNodes) { + this.getChildrenNodes(nodeId).forEach(id => this.nodesToHighlight.add(id)); + } } this.graph.nodeCanvasObject((node: N, ctx: CanvasRenderingContext2D) => @@ -162,9 +218,9 @@ export class GraphComponent> */ private getParentNodes(nodeId: string): string[] { const parentIds: string[] = []; - const links = this.getLinksBySourceId(nodeId); + const links = this.getLinksByTargetId(nodeId); links.forEach(link => { - const parentId = (link.target as N)?.id ?? link.target; + const parentId = (link.source as N)?.id ?? link.source; parentIds.push(parentId, ...this.getParentNodes(parentId)); }); return parentIds; @@ -177,9 +233,10 @@ export class GraphComponent> */ private getChildrenNodes(nodeId: string): string[] { const childrenIds: string[] = []; - const links = this.getLinksByTargetId(nodeId); + const links = this.getLinksBySourceId(nodeId); links.forEach(link => { - const childrenId = (link.source as N)?.id ?? link.source; + const childrenId = (link.target as N)?.id ?? link.target; + console.log(childrenId); childrenIds.push(childrenId, ...this.getChildrenNodes(childrenId)); }); return childrenIds; @@ -241,12 +298,13 @@ export class GraphComponent> */ private drawNode(node: N, ctx: CanvasRenderingContext2D) { if (node.x !== undefined && node.y !== undefined) { + const label = this.getNodeStatusData(node); if (this.nodesToHighlight.has(node.id)) { ctx.font = '70px Material Icons'; - ctx.fillStyle = 'black'; + const complementary = this.getComplementaryColor(label.color); + ctx.fillStyle = complementary; ctx.fillText(this.iconsService.getIcon(`${node.type}-graph-icon`), node.x - 35, node.y + 35); } - const label = this.getNodeStatusData(node); ctx.font = '50px Material Icons'; ctx.fillStyle = label.color; ctx.fillText(this.iconsService.getIcon(`${node.type}-graph-icon`), node.x - 25, node.y + 25); diff --git a/src/app/services/default-config.service.ts b/src/app/services/default-config.service.ts index 878507bb5..cd824ae8c 100644 --- a/src/app/services/default-config.service.ts +++ b/src/app/services/default-config.service.ts @@ -355,6 +355,9 @@ export class DefaultConfigService { output: '#f7b657', }; + readonly #defaultGraphHighlightParents: boolean = false; + readonly #defaultGraphHighlightChildren: boolean = false; + // We use getters to be able to deep copy the default config and to access the default config from the outside get defaultTheme(): Theme { @@ -421,6 +424,14 @@ export class DefaultConfigService { return structuredClone(this.#defaultGraphLinksColors); } + get defaultGraphHighlightParents() { + return structuredClone(this.#defaultGraphHighlightParents); + } + + get defaultGraphHighlightChildren() { + return structuredClone(this.#defaultGraphHighlightChildren); + } + readonly #exportedDefaultConfig: ExportedDefaultConfig = { 'language': this.#defaultLanguage, 'navigation-sidebar': this.#defaultSidebar, @@ -469,6 +480,8 @@ export class DefaultConfigService { 'tasks-custom-columns': [], 'sessions-custom-columns': [], 'graph-links-colors': this.#defaultGraphLinksColors, + 'graph-highlight-parents': this.#defaultGraphHighlightParents, + 'graph-highlight-children': this.#defaultGraphHighlightChildren, }; get exportedDefaultConfig(): ExportedDefaultConfig { diff --git a/src/app/types/config.ts b/src/app/types/config.ts index 3e2c068ea..a354b4578 100644 --- a/src/app/types/config.ts +++ b/src/app/types/config.ts @@ -30,6 +30,8 @@ export type Key = 'partitions-tasks-by-status' | 'tasks-view-in-logs' | 'graph-links-colors' | + 'graph-highlight-parents' | + 'graph-highlight-children' | `${CustomScope}-custom-columns` | `${Scope}-${Element}` | `${Scope}-show-filters` | From 9bda88129b3e8363787a3fa100d0d60093882be0 Mon Sep 17 00:00:00 2001 From: faustin Date: Thu, 31 Jul 2025 15:50:38 +0200 Subject: [PATCH 21/26] fix: huge lags when loading children and parents nodes --- src/app/components/graph.component.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/app/components/graph.component.ts b/src/app/components/graph.component.ts index 081a72c35..9fea2913d 100644 --- a/src/app/components/graph.component.ts +++ b/src/app/components/graph.component.ts @@ -219,10 +219,15 @@ export class GraphComponent> private getParentNodes(nodeId: string): string[] { const parentIds: string[] = []; const links = this.getLinksByTargetId(nodeId); - links.forEach(link => { - const parentId = (link.source as N)?.id ?? link.source; - parentIds.push(parentId, ...this.getParentNodes(parentId)); - }); + const idBuffer: L[] = [...links]; + while (idBuffer.length !== 0) { + const link = idBuffer.pop(); + if (link) { + const parentId = (link.source as N)?.id ?? link.source; + parentIds.push(parentId); + idBuffer.push(...this.getLinksByTargetId(parentId)); + } + } return parentIds; } @@ -234,11 +239,15 @@ export class GraphComponent> private getChildrenNodes(nodeId: string): string[] { const childrenIds: string[] = []; const links = this.getLinksBySourceId(nodeId); - links.forEach(link => { - const childrenId = (link.target as N)?.id ?? link.target; - console.log(childrenId); - childrenIds.push(childrenId, ...this.getChildrenNodes(childrenId)); - }); + const idBuffer: L[] = [...links]; + while (idBuffer.length !== 0) { + const link = idBuffer.pop(); + if (link) { + const childrenId = (link.target as N)?.id ?? link.target; + childrenIds.push(childrenId); + idBuffer.push(...this.getLinksBySourceId(childrenId)); + } + } return childrenIds; } From 56713cfa006efa1185d9ee786a350bed2a3b1f02 Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Mon, 1 Sep 2025 17:03:45 +0200 Subject: [PATCH 22/26] chore: address comments --- src/app/components/graph.component.html | 4 ++-- src/app/components/graph.component.spec.ts | 11 +++++++++++ src/app/components/graph.component.ts | 9 +++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/app/components/graph.component.html b/src/app/components/graph.component.html index d58e3c2e5..bdcfe0a1b 100644 --- a/src/app/components/graph.component.html +++ b/src/app/components/graph.component.html @@ -5,7 +5,7 @@

Session: {{ sessionId }}

-
@@ -13,7 +13,7 @@

Back to Sessions List - + See Session +

+ + + + + @switch (node.type) { + @case ('task') { + + } + @case ('result') { + + } + } + \ No newline at end of file diff --git a/src/app/components/graph/inspect-node.component.spec.ts b/src/app/components/graph/inspect-node.component.spec.ts new file mode 100644 index 000000000..a1ef7e248 --- /dev/null +++ b/src/app/components/graph/inspect-node.component.spec.ts @@ -0,0 +1,94 @@ +import { Clipboard } from '@angular/cdk/clipboard'; +import { TestBed } from '@angular/core/testing'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { IconsService } from '@services/icons.service'; +import { InspectNodeComponent } from './inspect-node.component'; +import { NodeStatusService } from './services/node-status.service'; + +describe('InspectNodeComponent', () => { + let component: InspectNodeComponent; + + const mockIconsService = { + getIcon: jest.fn(), + }; + + const mockClipboard = { + copy: jest.fn(), + }; + + const mockNodeStatusService = { + getNodeStatusData: jest.fn(), + }; + + const node = { + id: 'id' + } as ArmoniKGraphNode; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + InspectNodeComponent, + { provide: IconsService, useValue: mockIconsService }, + { provide: Clipboard, useValue: mockClipboard }, + { provide: NodeStatusService, useValue: mockNodeStatusService }, + ], + }).inject(InspectNodeComponent); + component.ngOnInit(); + component.node = node; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('init', () => { + it('should subscribe to copySubject', () => { + expect(component['copySubject'].observed).toBeTruthy(); + }); + + it('should set "copy" as the default copy icon', () => { + expect(component.copyIcon()).toEqual('copy'); + }); + }); + + it('should get icon', () => { + const icon = 'icon'; + component.getIcon(icon); + expect(mockIconsService.getIcon).toHaveBeenCalledWith(icon); + }); + + describe('copy', () => { + beforeEach(() => { + jest.useFakeTimers(); + component.copy(); + }); + it('should copy the node id', () => { + expect(mockClipboard.copy).toHaveBeenCalledWith(node.id); + }); + + it('should update the copy icon to "success"', () => { + expect(component.copyIcon()).toEqual('success'); + }); + + it('should update the copy icon back to "copy" after 2 seconds', () => { + jest.advanceTimersByTime(2000); + expect(component.copyIcon()).toEqual('copy'); + }); + }); + + it('should emit on close', () => { + const spy = jest.spyOn(component.closePanel, 'emit'); + component.onClose(); + expect(spy).toHaveBeenCalled(); + }); + + describe('On destroy', () => { + beforeEach(() => { + component.ngOnDestroy(); + }); + + it('should unsubscribe', () => { + expect(component['subscriptions'].closed).toBeTruthy(); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/graph/inspect-node.component.ts b/src/app/components/graph/inspect-node.component.ts new file mode 100644 index 000000000..182dce6e8 --- /dev/null +++ b/src/app/components/graph/inspect-node.component.ts @@ -0,0 +1,67 @@ +import { Clipboard } from '@angular/cdk/clipboard'; +import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, OnDestroy, OnInit, Output, signal } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { StatusChipComponent } from '@components/status-chip.component'; +import { IconsService } from '@services/icons.service'; +import { delay, Subject, Subscription } from 'rxjs'; +import { InspectResultActionsComponent } from './inspect-result-actions.component'; +import { InspectTaskActionsComponent } from './inspect-task-actions.component'; +import { NodeStatusService } from './services/node-status.service'; + +@Component({ + selector: 'app-graph-inspect-node', + templateUrl: 'inspect-node.component.html', + styleUrl: 'inspect-node.component.css', + imports: [ + MatCardModule, + MatButtonModule, + MatIconModule, + StatusChipComponent, + InspectTaskActionsComponent, + InspectResultActionsComponent, + MatTooltipModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class InspectNodeComponent implements OnInit, OnDestroy { + readonly nodeStatusService = inject(NodeStatusService); + private readonly iconsService = inject(IconsService); + private readonly clipboard = inject(Clipboard); + + @Input({ required: true }) node: N; + + @Output() readonly closePanel = new EventEmitter(); + + copyIcon = signal('copy'); + private readonly copySubject = new Subject(); + private readonly subscriptions = new Subscription(); + + ngOnInit(): void { + const copySubscription = this.copySubject + .pipe(delay(2000)) + .subscribe(() => (this.copyIcon.set('copy'))); + this.subscriptions.add(copySubscription); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + + getIcon(name: string) { + return this.iconsService.getIcon(name); + } + + copy() { + this.clipboard.copy(this.node.id); + this.copyIcon.set('success'); + this.copySubject.next(); + } + + onClose() { + this.closePanel.emit(); + } +} \ No newline at end of file diff --git a/src/app/components/graph/inspect-result-actions.component.html b/src/app/components/graph/inspect-result-actions.component.html new file mode 100644 index 000000000..6241d085b --- /dev/null +++ b/src/app/components/graph/inspect-result-actions.component.html @@ -0,0 +1,16 @@ + + @let resultData = result(); + @if (resultData) { + + + @if (resultData.ownerTaskId) { + + } +} + \ No newline at end of file diff --git a/src/app/components/graph/inspect-result-actions.component.spec.ts b/src/app/components/graph/inspect-result-actions.component.spec.ts new file mode 100644 index 000000000..80f72452d --- /dev/null +++ b/src/app/components/graph/inspect-result-actions.component.spec.ts @@ -0,0 +1,81 @@ +import { GetResultResponse, ResultRaw } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { ResultsGrpcService } from '@app/results/services/results-grpc.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { Subject } from 'rxjs'; +import { InspectResultActionsComponent } from './inspect-result-actions.component'; + +describe('InspectResultActionsComponent', () => { + let component: InspectResultActionsComponent; + + const getSubject = new Subject(); + const mockResultsGrpcService = { + get$: jest.fn(() => getSubject), + }; + + const mockRouter = { + navigate: jest.fn(), + }; + + const node = { + id: 'resultId', + } as ArmoniKGraphNode; + + const mockResult = { + resultId: 'resultId', + sessionId: 'sessionId', + ownerTaskId: 'ownerTaskId', + } as ResultRaw; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + InspectResultActionsComponent, + { provide: ResultsGrpcService, useValue: mockResultsGrpcService }, + { provide: Router, useValue: mockRouter }, + ] + }).inject(InspectResultActionsComponent); + component.node = node; + getSubject.next({result: mockResult} as GetResultResponse); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Initialisation', () => { + it('should subscribe to the grpc get event', () => { + expect(getSubject.observed).toBeTruthy(); + }); + + it('should retrieve result information', () => { + expect(component.result()).toBe(mockResult); + }); + }); + + it('should redirect to the result page', () => { + component.seeResult(mockResult); + expect(mockRouter.navigate).toHaveBeenCalledWith(['/results', mockResult.resultId]); + }); + + it('should redirect to the result session', () => { + component.seeSession(mockResult); + expect(mockRouter.navigate).toHaveBeenCalledWith(['/sessions', mockResult.sessionId]); + }); + + it('should redirect to the owner task page', () => { + component.seeOwnerTask(mockResult); + expect(mockRouter.navigate).toHaveBeenCalledWith(['/tasks', mockResult.ownerTaskId]); + }); + + describe('On destroy', () => { + beforeEach(() => { + component.ngOnDestroy(); + }); + + it('should unsubscribe', () => { + expect(component['subscriptions'].closed).toBeTruthy(); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/graph/inspect-result-actions.component.ts b/src/app/components/graph/inspect-result-actions.component.ts new file mode 100644 index 000000000..c1032101f --- /dev/null +++ b/src/app/components/graph/inspect-result-actions.component.ts @@ -0,0 +1,56 @@ +import { ResultRaw } from '@aneoconsultingfr/armonik.api.angular'; +import { ChangeDetectionStrategy, Component, inject, Input, OnDestroy, signal } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardActions } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { Router } from '@angular/router'; +import { ResultsGrpcService } from '@app/results/services/results-grpc.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'app-graph-inspect-result-actions', + templateUrl: 'inspect-result-actions.component.html', + styleUrl: 'inspect-node.component.css', + imports: [ + MatButtonModule, + MatIconModule, + MatCardActions + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class InspectResultActionsComponent implements OnDestroy { + private readonly grpcService = inject(ResultsGrpcService); + private readonly router = inject(Router); + + private readonly subscriptions = new Subscription(); + + result = signal(null); + + @Input({ required: true }) set node(entry: N) { + const getSubscription = this.grpcService.get$(entry.id) + .subscribe(result => { + if (result.result) { + this.result.set(result.result); + } + }); + + this.subscriptions.add(getSubscription); + }; + + seeResult(result: ResultRaw) { + this.router.navigate(['/results', result.resultId]); + } + + seeSession(result: ResultRaw) { + this.router.navigate(['/sessions', result.sessionId]); + } + + seeOwnerTask(result: ResultRaw) { + this.router.navigate(['/tasks', result.ownerTaskId]); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } +} \ No newline at end of file diff --git a/src/app/components/graph/inspect-task-actions.component.html b/src/app/components/graph/inspect-task-actions.component.html new file mode 100644 index 000000000..c90403c8f --- /dev/null +++ b/src/app/components/graph/inspect-task-actions.component.html @@ -0,0 +1,19 @@ + + @let taskData = task(); + @if (taskData) { + + + + @if (taskData.parentTaskIds.length !== 0) { + + } + } + \ No newline at end of file diff --git a/src/app/components/graph/inspect-task-actions.component.spec.ts b/src/app/components/graph/inspect-task-actions.component.spec.ts new file mode 100644 index 000000000..fc4273a62 --- /dev/null +++ b/src/app/components/graph/inspect-task-actions.component.spec.ts @@ -0,0 +1,113 @@ +import { GetTaskResponse, TaskDetailed } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { TasksGrpcService } from '@app/tasks/services/tasks-grpc.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { FiltersService } from '@services/filters.service'; +import { Subject } from 'rxjs'; +import { InspectTaskActionsComponent } from './inspect-task-actions.component'; + +describe('InspectTaskActionsComponent', () => { + let component: InspectTaskActionsComponent; + + const getSubject = new Subject(); + const mockTasksGrpcService = { + get$: jest.fn(() => getSubject), + }; + + const mockRouter = { + navigate: jest.fn(), + }; + + const node = { + id: 'taskId', + } as ArmoniKGraphNode; + + const mockTask = { + id: 'taskId', + options: { + paritionId: 'partitionId', + }, + parentTaskIds: [ + 'task-1', 'task-2', 'task-3' + ], + expectedOutputIds: [ + 'result-1', 'result-2' + ] + } as unknown as TaskDetailed; + + beforeEach(() => { + component = TestBed.configureTestingModule({ + providers: [ + InspectTaskActionsComponent, + FiltersService, + { provide: TasksGrpcService, useValue: mockTasksGrpcService }, + { provide: Router, useValue: mockRouter }, + ] + }).inject(InspectTaskActionsComponent); + component.node = node; + getSubject.next({task: mockTask} as GetTaskResponse); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Initialisation', () => { + it('should subscribe to the grpc get event', () => { + expect(getSubject.observed).toBeTruthy(); + }); + + it('should retrieve task information', () => { + expect(component.task()).toBe(mockTask); + }); + }); + + it('should redirect to the task page', () => { + component.seeTask(mockTask); + expect(mockRouter.navigate).toHaveBeenCalledWith(['/tasks', mockTask.id]); + }); + + it('should redirect to the task partition', () => { + component.seePartition(mockTask); + expect(mockRouter.navigate).toHaveBeenCalledWith(['/partitions', mockTask.options?.partitionId]); + }); + + it('should redirect to the filtered task table', () => { + component.listParentTasks(mockTask); + expect(mockRouter.navigate).toHaveBeenCalledWith( + ['/tasks'], + { + queryParams: { + '0-root-16-0': 'task-1', + '1-root-16-0': 'task-2', + '2-root-16-0': 'task-3', + } + } + ); + }); + + it('should redirect to the filtered result table', () => { + component.listResults(mockTask); + expect(mockRouter.navigate).toHaveBeenCalledWith( + ['/results'], + { + queryParams: { + '0-root-7-0': 'result-1', + '1-root-7-0': 'result-2', + } + } + ); + }); + + + describe('On destroy', () => { + beforeEach(() => { + component.ngOnDestroy(); + }); + + it('should unsubscribe', () => { + expect(component['subscriptions'].closed).toBeTruthy(); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/graph/inspect-task-actions.component.ts b/src/app/components/graph/inspect-task-actions.component.ts new file mode 100644 index 000000000..66865b4c8 --- /dev/null +++ b/src/app/components/graph/inspect-task-actions.component.ts @@ -0,0 +1,89 @@ +import { FilterStringOperator, ResultRawEnumField, TaskDetailed, TaskSummaryEnumField } from '@aneoconsultingfr/armonik.api.angular'; +import { ChangeDetectionStrategy, Component, inject, Input, OnDestroy, signal } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardActions } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { Params, Router } from '@angular/router'; +import { TasksGrpcService } from '@app/tasks/services/tasks-grpc.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { FiltersService } from '@services/filters.service'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'app-graph-inspect-task-actions', + templateUrl: 'inspect-task-actions.component.html', + styleUrl: 'inspect-node.component.css', + imports: [ + MatButtonModule, + MatIconModule, + MatCardActions + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class InspectTaskActionsComponent implements OnDestroy { + private readonly grpcService = inject(TasksGrpcService); + private readonly filtersService = inject(FiltersService); + private readonly router = inject(Router); + + private readonly subscriptions = new Subscription(); + + task = signal(null); + + @Input({ required: true }) set node(entry: N) { + const getSubscription = this.grpcService.get$(entry.id) + .subscribe(result => { + if (result.task) { + this.task.set(result.task); + } + }); + + this.subscriptions.add(getSubscription); + }; + + seeTask(task: TaskDetailed) { + this.router.navigate(['/tasks', task.id]); + } + + seePartition(task: TaskDetailed) { + if (task.options) { + this.router.navigate(['/partitions', task.options.partitionId]); + } + } + + listParentTasks(task: TaskDetailed) { + const queryParams = task.parentTaskIds + .filter(parent => parent !== task.sessionId) + .map((parent, index) => { + const key = this.filtersService.createQueryParamsKey(index, 'root', FilterStringOperator.FILTER_STRING_OPERATOR_EQUAL, TaskSummaryEnumField.TASK_SUMMARY_ENUM_FIELD_TASK_ID); + return [key, parent]; + }) + .reduce((record: Params, [key, parent]) => { + record[key] = parent; + return record; + }, {}); + + this.router.navigate(['/tasks'], { + queryParams: queryParams, + }); + } + + listResults(task: TaskDetailed) { + const queryParams = task.expectedOutputIds + .map((parent, index) => { + const key = this.filtersService.createQueryParamsKey(index, 'root', FilterStringOperator.FILTER_STRING_OPERATOR_EQUAL, ResultRawEnumField.RESULT_RAW_ENUM_FIELD_RESULT_ID); + return [key, parent]; + }) + .reduce((record: Params, [key, parent]) => { + record[key] = parent; + return record; + }, {}); + + this.router.navigate(['/results'], { + queryParams: queryParams, + }); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } +} \ No newline at end of file diff --git a/src/app/components/graph/services/node-status.service.spec.ts b/src/app/components/graph/services/node-status.service.spec.ts new file mode 100644 index 000000000..4e9573ab9 --- /dev/null +++ b/src/app/components/graph/services/node-status.service.spec.ts @@ -0,0 +1,89 @@ +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { TestBed } from '@angular/core/testing'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { NodeStatusService } from './node-status.service'; + +describe('NodeStatusService', () => { + let service: NodeStatusService; + + const mockSessionsStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Running', + color: 'green' + })), + }; + + const mockTasksStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Completed', + color: 'green' + })), + }; + + const mockResultsStatuses = { + statusToLabel: jest.fn(() => ({ + label: 'Completed', + color: 'green' + })), + }; + + + beforeEach(() => { + service = TestBed.configureTestingModule({ + providers: [ + NodeStatusService, + { provide: SessionsStatusesService, useValue: mockSessionsStatuses }, + { provide: TasksStatusesService, useValue: mockTasksStatuses }, + { provide: ResultsStatusesService, useValue: mockResultsStatuses }, + ], + }).inject(NodeStatusService); + }); + + describe('getNodeStatusData', () => { + it('should return the running session label', () => { + const node = { + type: 'session', + status: SessionStatus.SESSION_STATUS_RUNNING, + } as ArmoniKGraphNode; + expect(service.getNodeStatusData(node)).toEqual( + mockSessionsStatuses.statusToLabel() + ); + }); + + it('should return the running task label', () => { + const node = { + type: 'task', + status: TaskStatus.TASK_STATUS_COMPLETED, + } as ArmoniKGraphNode; + expect(service.getNodeStatusData(node)).toEqual( + mockTasksStatuses.statusToLabel() + ); + }); + + it('should return the running result label', () => { + const node = { + type: 'result', + status: ResultStatus.RESULT_STATUS_COMPLETED, + } as ArmoniKGraphNode; + expect(service.getNodeStatusData(node)).toEqual( + mockResultsStatuses.statusToLabel() + ); + }); + + + it('should get the default color', () => { + const node = { + type: 'unknown', + status: ResultStatus.RESULT_STATUS_COMPLETED, + } as unknown as ArmoniKGraphNode; + + expect(service.getNodeStatusData(node)).toEqual({ + label: 'Unknown', + color: 'grey' + }); + }); + }); +}); \ No newline at end of file diff --git a/src/app/components/graph/services/node-status.service.ts b/src/app/components/graph/services/node-status.service.ts new file mode 100644 index 000000000..ff3f1c9c8 --- /dev/null +++ b/src/app/components/graph/services/node-status.service.ts @@ -0,0 +1,35 @@ +import { ResultStatus, SessionStatus, TaskStatus } from '@aneoconsultingfr/armonik.api.angular'; +import { inject, Injectable } from '@angular/core'; +import { ResultsStatusesService } from '@app/results/services/results-statuses.service'; +import { SessionsStatusesService } from '@app/sessions/services/sessions-statuses.service'; +import { TasksStatusesService } from '@app/tasks/services/tasks-statuses.service'; +import { ArmoniKGraphNode } from '@app/types/graph.types'; +import { StatusLabelColor } from '@app/types/status'; + +@Injectable() +export class NodeStatusService { + private readonly sessionsStatusesService = inject(SessionsStatusesService); + private readonly tasksStatusesService = inject(TasksStatusesService); + private readonly resultsStatusesService = inject(ResultsStatusesService); + + /** + * Get the data associated to the node status. + * @param node N + * @returns StatusLabelColor, contains label, color and icon. + */ + getNodeStatusData(node: N): StatusLabelColor { + switch (node.type) { + case 'session': + return this.sessionsStatusesService.statusToLabel(node.status as SessionStatus); + case 'task': + return this.tasksStatusesService.statusToLabel(node.status as TaskStatus); + case 'result': + return this.resultsStatusesService.statusToLabel(node.status as ResultStatus); + default: + return { + label: $localize`Unknown`, + color: 'grey', + }; + } + } +} \ No newline at end of file From 098a8d32ac7c152c57af377e8b64c29f4d4770b2 Mon Sep 17 00:00:00 2001 From: fdewas-aneo Date: Mon, 8 Sep 2025 10:02:00 +0200 Subject: [PATCH 24/26] docs: inspect components --- .../graph/inspect-node.component.ts | 4 ++++ .../inspect-result-actions.component.html | 3 --- .../inspect-result-actions.component.spec.ts | 5 ----- .../graph/inspect-result-actions.component.ts | 15 +++++++++++---- .../graph/inspect-task-actions.component.ts | 19 +++++++++++++++++++ .../graph/services/node-status.service.ts | 3 +++ 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/app/components/graph/inspect-node.component.ts b/src/app/components/graph/inspect-node.component.ts index 182dce6e8..17c50d603 100644 --- a/src/app/components/graph/inspect-node.component.ts +++ b/src/app/components/graph/inspect-node.component.ts @@ -12,6 +12,10 @@ import { InspectResultActionsComponent } from './inspect-result-actions.componen import { InspectTaskActionsComponent } from './inspect-task-actions.component'; import { NodeStatusService } from './services/node-status.service'; +/** + * Component displayed when a node (task, result) is clicked on the graph. + * Display its Id, status and some actions. + */ @Component({ selector: 'app-graph-inspect-node', templateUrl: 'inspect-node.component.html', diff --git a/src/app/components/graph/inspect-result-actions.component.html b/src/app/components/graph/inspect-result-actions.component.html index 6241d085b..b00f98391 100644 --- a/src/app/components/graph/inspect-result-actions.component.html +++ b/src/app/components/graph/inspect-result-actions.component.html @@ -4,9 +4,6 @@ - @if (resultData.ownerTaskId) {