From c15a52959bcf314b232790264eaf0ca81a819074 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 6 Jan 2025 10:05:00 +0100 Subject: [PATCH] Remove unused dependencies and symbols using knip --- .github/workflows/ci.yaml | 26 + frontend/i18next-parser.config.ts | 6 +- frontend/knip.config.ts | 22 + frontend/locales/en.json | 1 - frontend/package-lock.json | 518 ++++++++---------- frontend/package.json | 16 +- frontend/src/components/NotLoggedIn.tsx | 19 - .../PasswordCreationDoubleInput.tsx | 6 +- .../SessionDetail/SessionDetails.tsx | 2 +- frontend/src/components/Typography.tsx | 27 - .../components/UserProfile/UserEmailList.tsx | 2 +- frontend/src/config.ts | 2 +- frontend/src/pagination.ts | 10 +- frontend/src/result.ts | 64 --- 14 files changed, 297 insertions(+), 424 deletions(-) create mode 100644 frontend/knip.config.ts delete mode 100644 frontend/src/components/NotLoggedIn.tsx delete mode 100644 frontend/src/result.ts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 167b91808..3b2a6cbb8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -98,6 +98,31 @@ jobs: run: npm test + frontend-knip: + name: Check the frontend for unused dependencies + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4.2.2 + + - name: Install Node + uses: actions/setup-node@v4.1.0 + with: + node-version: 20 + + - name: Install Node dependencies + working-directory: ./frontend + run: npm ci + + - name: Check for unused dependencies + working-directory: ./frontend + run: npm run knip + + rustfmt: name: Check Rust style runs-on: ubuntu-latest @@ -362,6 +387,7 @@ jobs: - opa-lint - frontend-lint - frontend-test + - frontend-knip - rustfmt - cargo-deny - clippy diff --git a/frontend/i18next-parser.config.ts b/frontend/i18next-parser.config.ts index 2f0170dfe..4b003ccbd 100644 --- a/frontend/i18next-parser.config.ts +++ b/frontend/i18next-parser.config.ts @@ -6,7 +6,7 @@ import type { UserConfig } from "i18next-parser"; -const config: UserConfig = { +export default { keySeparator: ".", pluralSeparator: ":", defaultNamespace: "frontend", @@ -30,6 +30,4 @@ const config: UserConfig = { output: "locales/$LOCALE.json", input: ["src/**/*.{ts,tsx}"], sort: true, -}; - -export default config; +} satisfies UserConfig; diff --git a/frontend/knip.config.ts b/frontend/knip.config.ts new file mode 100644 index 000000000..ad7343eaf --- /dev/null +++ b/frontend/knip.config.ts @@ -0,0 +1,22 @@ +// Copyright 2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. + +import type { KnipConfig } from "knip"; + +export default { + entry: [ + "src/main.tsx", + "src/swagger.tsx", + "src/routes/*", + "i18next-parser.config.ts", + ], + ignore: ["src/gql/*", "src/routeTree.gen.ts", ".storybook/locales.ts"], + ignoreDependencies: [ + // This is used by the tailwind PostCSS plugin, but not detected by knip + "postcss-nesting", + // We're using @storybook/addon-essentials to simplify upgrades, but knip doesn't detect them + "@storybook/addon-*", + ], +} satisfies KnipConfig; diff --git a/frontend/locales/en.json b/frontend/locales/en.json index 15ee71401..cdd48a779 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -96,7 +96,6 @@ "settings": "Settings" }, "not_found_alert_title": "Not found.", - "not_logged_in_alert": "You're not logged in.", "oauth2_client_detail": { "details_title": "Client info", "name": "Name", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f701b60bd..1ceae1a9b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,10 +15,6 @@ "@tanstack/react-query": "^5.62.15", "@tanstack/react-router": "^1.95.1", "@tanstack/router-zod-adapter": "^1.81.5", - "@urql/core": "^5.0.8", - "@urql/devtools": "^2.0.3", - "@urql/exchange-refocus": "^1.1.0", - "@urql/exchange-request-policy": "^1.2.0", "@vector-im/compound-design-tokens": "2.1.3", "@vector-im/compound-web": "^7.3.0", "@zxcvbn-ts/core": "^3.0.4", @@ -39,11 +35,9 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@codecov/vite-plugin": "^1.4.0", - "@graphql-codegen/add": "^5.0.3", "@graphql-codegen/cli": "^5.0.3", "@graphql-codegen/client-preset": "^4.5.1", "@graphql-codegen/typescript-msw": "^3.0.0", - "@graphql-codegen/urql-introspection": "^3.0.0", "@storybook/addon-essentials": "^8.4.7", "@storybook/addon-interactions": "^8.4.7", "@storybook/react": "^8.4.7", @@ -54,10 +48,10 @@ "@tanstack/router-vite-plugin": "^1.95.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@testing-library/user-event": "^14.5.2", "@types/node": "^22.10.5", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", - "@types/react-test-renderer": "^19.0.0", "@types/swagger-ui-react": "^4.18.3", "@vitejs/plugin-react": "^4.3.3", "@vitest/coverage-v8": "^2.1.8", @@ -66,16 +60,17 @@ "graphql": "^16.9.0", "happy-dom": "^15.11.4", "i18next-parser": "^9.1.0", + "knip": "^5.41.1", "msw": "^2.6.5", "msw-storybook-addon": "^2.0.4", "postcss": "^8.4.49", - "postcss-modules": "^6.0.1", + "postcss-import": "^16.1.0", "postcss-nesting": "^13.0.1", "rimraf": "^6.0.1", "storybook": "^8.4.4", "storybook-react-i18next": "^3.1.8", "tailwindcss": "^3.4.17", - "typescript": "5.7.2", + "typescript": "^5.7.2", "vite": "5.4.11", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.3.8", @@ -83,20 +78,6 @@ "vitest": "^2.1.2" } }, - "node_modules/@0no-co/graphql.web": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.11.tgz", - "integrity": "sha512-xuSJ9WXwTmtngWkbdEoopMo6F8NLtjy84UNAMsAr5C3/2SgAL/dEU10TMqTIsipqPQ8HA/7WzeqQ9DEQxSvPPA==", - "license": "MIT", - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" - }, - "peerDependenciesMeta": { - "graphql": { - "optional": true - } - } - }, "node_modules/@actions/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", @@ -2436,63 +2417,6 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@graphql-codegen/urql-introspection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/urql-introspection/-/urql-introspection-3.0.0.tgz", - "integrity": "sha512-DBYfG3CO3G6MTzp+/FaXuxYS6cFSkpDMwxXKoJVqKR0jIGd/ev3Gh1pTgqxndcBu8oV9xjiaBQglKCge0EqLpQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-codegen/plugin-helpers": "^3.0.0", - "@urql/introspection": "^0.3.2", - "tslib": "~2.6.0" - }, - "engines": { - "node": ">= 16.0.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-codegen/plugin-helpers": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", - "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-tools/utils": "^9.0.0", - "change-case-all": "1.0.15", - "common-tags": "1.8.2", - "import-from": "4.0.0", - "lodash": "~4.17.0", - "tslib": "~2.4.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@graphql-codegen/urql-introspection/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/@graphql-codegen/visitor-plugin-common": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.6.0.tgz", @@ -4801,6 +4725,34 @@ "hasInstallScript": true, "license": "Apache-2.0" }, + "node_modules/@snyk/github-codeowners": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz", + "integrity": "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^4.1.1", + "ignore": "^5.1.8", + "p-map": "^4.0.0" + }, + "bin": { + "github-codeowners": "dist/cli.js" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/@snyk/github-codeowners/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/@storybook/addon-actions": { "version": "8.4.7", "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.4.7.tgz", @@ -6323,6 +6275,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } @@ -6364,16 +6317,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-test-renderer": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.0.0.tgz", - "integrity": "sha512-qDVnNybqFm2eZKJ4jD34EvRd6VHD67KjgnWaEMM0Id9L22EpWe3nOSVKHWL1XWRCxUWe3lhXwlEeCKD1BlJCQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/resolve": { "version": "1.20.6", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", @@ -6441,65 +6384,6 @@ "@types/node": "*" } }, - "node_modules/@urql/core": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.0.8.tgz", - "integrity": "sha512-1GOnUw7/a9bzkcM0+U8U5MmxW2A7FE5YquuEmcJzTtW5tIs2EoS4F2ITpuKBjRBbyRjZgO860nWFPo1m4JImGA==", - "license": "MIT", - "dependencies": { - "@0no-co/graphql.web": "^1.0.5", - "wonka": "^6.3.2" - } - }, - "node_modules/@urql/devtools": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@urql/devtools/-/devtools-2.0.3.tgz", - "integrity": "sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==", - "license": "MIT", - "dependencies": { - "wonka": ">= 4.0.9" - }, - "peerDependencies": { - "@urql/core": ">= 1.14.0", - "graphql": ">= 0.11.0" - } - }, - "node_modules/@urql/exchange-refocus": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@urql/exchange-refocus/-/exchange-refocus-1.1.0.tgz", - "integrity": "sha512-tMgIqXUGIuNBeEoXDNOZ48Kut2m85etNIorwBG89tQZHDLxJM52N6A0eLm0Mv9BJFb0U94i3drwlD55He+9Uvw==", - "license": "MIT", - "dependencies": { - "@urql/core": "^5.0.0", - "wonka": "^6.3.2" - }, - "peerDependencies": { - "@urql/core": "^5.0.0" - } - }, - "node_modules/@urql/exchange-request-policy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@urql/exchange-request-policy/-/exchange-request-policy-1.2.0.tgz", - "integrity": "sha512-30CwS5/YzX0YWVATg19rrDhruDCRIu96xUz6HGlhJPUw22M7njRldl44fmoU11ZbIemg01t8ysq6+0rdktYBgg==", - "license": "MIT", - "dependencies": { - "@urql/core": "^5.0.0", - "wonka": "^6.3.2" - }, - "peerDependencies": { - "@urql/core": "^5.0.0" - } - }, - "node_modules/@urql/introspection": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@urql/introspection/-/introspection-0.3.3.tgz", - "integrity": "sha512-tekSLLqWnusfV6V7xaEnLJQSdXOD/lWy7f8JYQwrX+88Md+voGSCSx5WJXI7KLBN3Tat2OV08tAr8UROykls4Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, "node_modules/@vector-im/compound-design-tokens": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@vector-im/compound-design-tokens/-/compound-design-tokens-2.1.3.tgz", @@ -8608,6 +8492,19 @@ "dev": true, "license": "MIT" }, + "node_modules/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.58", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.58.tgz", @@ -8646,6 +8543,20 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", + "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ensure-posix-path": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz", @@ -9249,16 +9160,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/generic-names": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", - "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "loader-utils": "^3.2.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9463,6 +9364,7 @@ "version": "16.9.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "dev": true, "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" @@ -10374,19 +10276,6 @@ "node": ">=0.10.0" } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -11091,6 +10980,79 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/knip": { + "version": "5.41.1", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.41.1.tgz", + "integrity": "sha512-yNpCCe2REU7U3VRvMASnXSEtfEC2HmOoDW9Vp9teQ9FktJYnuagvSZD3xWq8Ru7sPABkmvbC5TVWuMzIaeADNA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/knip" + }, + { + "type": "polar", + "url": "https://polar.sh/webpro-nl" + } + ], + "license": "ISC", + "dependencies": { + "@nodelib/fs.walk": "1.2.8", + "@snyk/github-codeowners": "1.1.0", + "easy-table": "1.2.0", + "enhanced-resolve": "^5.17.1", + "fast-glob": "^3.3.2", + "jiti": "^2.4.0", + "js-yaml": "^4.1.0", + "minimist": "^1.2.8", + "picocolors": "^1.1.0", + "picomatch": "^4.0.1", + "pretty-ms": "^9.0.0", + "smol-toml": "^1.3.1", + "strip-json-comments": "5.0.1", + "summary": "2.1.0", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "bin": { + "knip": "bin/knip.js", + "knip-bun": "bin/knip-bun.js" + }, + "engines": { + "node": ">=18.6.0" + }, + "peerDependencies": { + "@types/node": ">=18", + "typescript": ">=5.0.4" + } + }, + "node_modules/knip/node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/knip/node_modules/strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lead": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", @@ -11166,16 +11128,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/loader-utils": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", - "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -11198,13 +11150,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -12175,6 +12120,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse5": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", @@ -12457,9 +12415,9 @@ } }, "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", + "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", "dev": true, "license": "MIT", "dependencies": { @@ -12468,7 +12426,7 @@ "resolve": "^1.1.7" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "postcss": "^8.0.0" @@ -12530,89 +12488,6 @@ } } }, - "node_modules/postcss-modules": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.1.tgz", - "integrity": "sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "generic-names": "^4.0.0", - "icss-utils": "^5.1.0", - "lodash.camelcase": "^4.3.0", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "string-hash": "^1.1.3" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", - "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", - "dev": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/postcss-nested": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", @@ -12772,6 +12647,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prismjs": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", @@ -14059,6 +13950,19 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz", + "integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -14264,13 +14168,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -14485,6 +14382,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/summary": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz", + "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==", + "dev": true, + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -14674,6 +14578,24 @@ "node": ">=10.13.0" } }, + "node_modules/tailwindcss/node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, "node_modules/tailwindcss/node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -14688,6 +14610,16 @@ "node": ">=4" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -15220,6 +15152,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "devOptional": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16493,12 +16426,6 @@ "node": ">=8" } }, - "node_modules/wonka": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.4.tgz", - "integrity": "sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==", - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -16692,6 +16619,19 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 2daf4e55b..a7546808b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,8 @@ "coverage": "vitest run --coverage", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "i18n": "i18next" + "i18n": "i18next", + "knip": "knip" }, "dependencies": { "@fontsource/inconsolata": "^5.1.1", @@ -24,10 +25,6 @@ "@tanstack/react-query": "^5.62.15", "@tanstack/react-router": "^1.95.1", "@tanstack/router-zod-adapter": "^1.81.5", - "@urql/core": "^5.0.8", - "@urql/devtools": "^2.0.3", - "@urql/exchange-refocus": "^1.1.0", - "@urql/exchange-request-policy": "^1.2.0", "@vector-im/compound-design-tokens": "2.1.3", "@vector-im/compound-web": "^7.3.0", "@zxcvbn-ts/core": "^3.0.4", @@ -48,11 +45,9 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@codecov/vite-plugin": "^1.4.0", - "@graphql-codegen/add": "^5.0.3", "@graphql-codegen/cli": "^5.0.3", "@graphql-codegen/client-preset": "^4.5.1", "@graphql-codegen/typescript-msw": "^3.0.0", - "@graphql-codegen/urql-introspection": "^3.0.0", "@storybook/addon-essentials": "^8.4.7", "@storybook/addon-interactions": "^8.4.7", "@storybook/react": "^8.4.7", @@ -63,10 +58,10 @@ "@tanstack/router-vite-plugin": "^1.95.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@testing-library/user-event": "^14.5.2", "@types/node": "^22.10.5", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", - "@types/react-test-renderer": "^19.0.0", "@types/swagger-ui-react": "^4.18.3", "@vitejs/plugin-react": "^4.3.3", "@vitest/coverage-v8": "^2.1.8", @@ -75,16 +70,17 @@ "graphql": "^16.9.0", "happy-dom": "^15.11.4", "i18next-parser": "^9.1.0", + "knip": "^5.41.1", "msw": "^2.6.5", "msw-storybook-addon": "^2.0.4", "postcss": "^8.4.49", - "postcss-modules": "^6.0.1", + "postcss-import": "^16.1.0", "postcss-nesting": "^13.0.1", "rimraf": "^6.0.1", "storybook": "^8.4.4", "storybook-react-i18next": "^3.1.8", "tailwindcss": "^3.4.17", - "typescript": "5.7.2", + "typescript": "^5.7.2", "vite": "5.4.11", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.3.8", diff --git a/frontend/src/components/NotLoggedIn.tsx b/frontend/src/components/NotLoggedIn.tsx deleted file mode 100644 index 9727c76fc..000000000 --- a/frontend/src/components/NotLoggedIn.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 New Vector Ltd. -// Copyright 2023, 2024 The Matrix.org Foundation C.I.C. -// -// SPDX-License-Identifier: AGPL-3.0-only -// Please see LICENSE in the repository root for full details. - -import { Alert } from "@vector-im/compound-web"; -import type { ReactNode } from "react"; -import { Translation } from "react-i18next"; - -const NotLoggedIn: React.FC = () => ( - - {(t): ReactNode => ( - - )} - -); - -export default NotLoggedIn; diff --git a/frontend/src/components/PasswordCreationDoubleInput.tsx b/frontend/src/components/PasswordCreationDoubleInput.tsx index 6c53ddcab..284cb7001 100644 --- a/frontend/src/components/PasswordCreationDoubleInput.tsx +++ b/frontend/src/components/PasswordCreationDoubleInput.tsx @@ -20,7 +20,9 @@ const CONFIG_FRAGMENT = graphql(/* GraphQL */ ` // This will load the password complexity module lazily, // so that it doesn't block the initial render and can be code-split -const loadPromise = import("../utils/password_complexity"); +const loadPromise = import("../utils/password_complexity").then( + ({ estimatePasswordComplexity }) => estimatePasswordComplexity, +); const usePasswordComplexity = (password: string): PasswordComplexity => { const { t } = useTranslation(); @@ -40,7 +42,7 @@ const usePasswordComplexity = (password: string): PasswordComplexity => { }); } else { loadPromise - .then(({ estimatePasswordComplexity }) => + .then((estimatePasswordComplexity) => estimatePasswordComplexity(deferredPassword, t), ) .then((response) => setResult(response)); diff --git a/frontend/src/components/SessionDetail/SessionDetails.tsx b/frontend/src/components/SessionDetail/SessionDetails.tsx index b5905ecc5..3b1775fd0 100644 --- a/frontend/src/components/SessionDetail/SessionDetails.tsx +++ b/frontend/src/components/SessionDetail/SessionDetails.tsx @@ -21,7 +21,7 @@ import { VisualList, VisualListItem } from "../VisualList/VisualList"; import styles from "./SessionDetails.module.css"; -export type Detail = { label: string; value: ReactNode }; +type Detail = { label: string; value: ReactNode }; type Props = { title: string | ReactNode; lastActive?: Date; diff --git a/frontend/src/components/Typography.tsx b/frontend/src/components/Typography.tsx index 82f27697e..af9dcb423 100644 --- a/frontend/src/components/Typography.tsx +++ b/frontend/src/components/Typography.tsx @@ -48,31 +48,4 @@ const Typography: React.FC = ({ return createElement(element, { className }, ...Children.toArray(children)); }; -type SimpleProps = { children: React.ReactNode }; - -export const Bold: React.FC = ({ children }) => ( - {children} -); - -export const Code: React.FC = ({ children }) => ( - {children} -); - -export const Title: React.FC = ({ children }) => ( - {children} -); - -export const Subtitle: React.FC = ({ children }) => ( - {children} -); - -export const Body: React.FC<{ - children: React.ReactNode; - justified?: boolean; -}> = ({ children, justified }) => ( - - {children} - -); - export default Typography; diff --git a/frontend/src/components/UserProfile/UserEmailList.tsx b/frontend/src/components/UserProfile/UserEmailList.tsx index 9edf7b065..9af5b0fb0 100644 --- a/frontend/src/components/UserProfile/UserEmailList.tsx +++ b/frontend/src/components/UserProfile/UserEmailList.tsx @@ -49,7 +49,7 @@ const QUERY = graphql(/* GraphQL */ ` } `); -export const FRAGMENT = graphql(/* GraphQL */ ` +const FRAGMENT = graphql(/* GraphQL */ ` fragment UserEmailList_user on User { id primaryEmail { diff --git a/frontend/src/config.ts b/frontend/src/config.ts index 1b26c7f55..177817178 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -4,7 +4,7 @@ // SPDX-License-Identifier: AGPL-3.0-only // Please see LICENSE in the repository root for full details. -export type AppConfig = { +type AppConfig = { root: string; graphqlEndpoint: string; }; diff --git a/frontend/src/pagination.ts b/frontend/src/pagination.ts index 0929618b1..14a323e81 100644 --- a/frontend/src/pagination.ts +++ b/frontend/src/pagination.ts @@ -16,7 +16,7 @@ type PageInfo = { }; export const FIRST_PAGE = Symbol("FIRST_PAGE"); -export const LAST_PAGE = Symbol("LAST_PAGE"); +const LAST_PAGE = Symbol("LAST_PAGE"); export const anyPaginationSchema = z.object({ first: z.number().nullish(), @@ -25,7 +25,7 @@ export const anyPaginationSchema = z.object({ before: z.string().nullish(), }); -export const forwardPaginationSchema = z.object({ +const forwardPaginationSchema = z.object({ first: z.number(), after: z.string().nullish(), }); @@ -46,20 +46,20 @@ export type Pagination = z.infer; export type AnyPagination = z.infer; // Check if the pagination is a valid pagination -export const isValidPagination = ( +const isValidPagination = ( pagination: AnyPagination, ): pagination is Pagination => typeof pagination.first === "number" || typeof pagination.last === "number"; // Check if the pagination is forward pagination. -export const isForwardPagination = ( +const isForwardPagination = ( pagination: Pagination, ): pagination is ForwardPagination => { return Object.hasOwn(pagination, "first"); }; // Check if the pagination is backward pagination. -export const isBackwardPagination = ( +const isBackwardPagination = ( pagination: Pagination, ): pagination is BackwardPagination => { return Object.hasOwn(pagination, "last"); diff --git a/frontend/src/result.ts b/frontend/src/result.ts deleted file mode 100644 index 3b3523489..000000000 --- a/frontend/src/result.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2024 New Vector Ltd. -// Copyright 2023, 2024 The Matrix.org Foundation C.I.C. -// -// SPDX-License-Identifier: AGPL-3.0-only -// Please see LICENSE in the repository root for full details. - -const RESULT = Symbol("Result"); -const ERR = Symbol("Err"); -const OK = Symbol("Ok"); - -/** - * An `Ok` is a type that represents a successful result. - */ -export type Ok = { - [RESULT]: typeof OK; - [OK]: T; -}; - -/** - * An `Err` is a type that represents an error. - */ -export type Err = { - [RESULT]: typeof ERR; - [ERR]: E; -}; - -/** - * A `Result` is a type that represents either an `Ok` or an `Err`. - */ -export type Result = Ok | Err; - -// Construct an `Ok` -export const ok = (data: T): Ok => ({ [RESULT]: OK, [OK]: data }); - -// Construct an `Err` -export const err = (error: E): Err => ({ - [RESULT]: ERR, - [ERR]: error, -}); - -// Check if a `Result` is an `Ok` -export const isOk = (result: Result): result is Ok => - result[RESULT] === OK; - -// Check if a `Result` is an `Err` -export const isErr = (result: Result): result is Err => - result[RESULT] === ERR; - -// Extract the data from an `Ok` -export const unwrapOk = (result: Ok): T => result[OK]; - -// Extract the error from an `Err` -export const unwrapErr = (result: Err): E => result[ERR]; - -/** - * Check result for error and throw unwrapped error - * Otherwise return unwrapped Ok result - */ -export const unwrap = (result: Result): T => { - if (isErr(result)) { - throw unwrapErr(result); - } - return unwrapOk(result); -};