From 8ba73e64cdbebd2bae002696b1cef18fb40560f4 Mon Sep 17 00:00:00 2001 From: Roland Date: Thu, 30 Jul 2026 14:50:47 -0600 Subject: [PATCH] build: uninstall Semantic UI `semantic-ui-react`, `react-semantic-toasts-2` and `semantic-ui-offline` are gone from package.json, the lockfile and node_modules -- 19 MB of dependencies that nothing had imported since the migration finished. Four things still referenced them and would have broken on uninstall. None was caught by a build or by jest: Four test files still ran `jest.mock('react-semantic-toasts-2', ...)` for components that no longer use it. A jest.mock of a module that does not exist throws, so the packages could not have come out without this. `src/components/Download.cy.js` and `cypress/support/component.js` both imported semantic.min.css. The support file now loads what the app loads -- index.css, the font and token stylesheets, and Mantine's. The ratchet changes job rather than being deleted. An import of a missing module fails loudly now, but three quieter mistakes would not: a `className="ui button"` that styles nothing, a file reaching back through Theme.tsx, and someone reinstalling a package to "just use one Semantic component". It asserts all three, plus that package.json names nothing matching /semantic/i. Two pre-existing problems in the cypress component harness surfaced while checking the uninstall had not broken it, both fixed because that file had to be edited anyway: It imported `react-router-dom`, which is not installed -- this app is on react-router v7. Dates to 5621d473, so the component suite has been un-runnable since well before this migration. Its mount helper supplied no MantineProvider, so every library component threw -- the same gap test-utils.js had for jest. The component specs now load and four pass; eleven assertions are still written against markup from before they stopped running. Repairing those is its own piece of work, deliberately not bundled in here. The e2e suite is unaffected: 43/43. --- app/cypress/support/component.js | 18 +- app/package-lock.json | 287 ------------------ app/package.json | 3 - app/src/components/Download.cy.js | 1 - .../collections/BatchReorganizeModal.test.js | 4 - .../CollectionReorganizeModal.test.js | 4 - .../ConflictResolutionModal.test.js | 4 - app/src/hooks/useSubsystemToggle.test.js | 1 - app/src/semantic-baseline.test.js | 48 ++- 9 files changed, 48 insertions(+), 322 deletions(-) diff --git a/app/cypress/support/component.js b/app/cypress/support/component.js index 03b30c0a..9be6f32d 100644 --- a/app/cypress/support/component.js +++ b/app/cypress/support/component.js @@ -14,10 +14,17 @@ // *********************************************************** import './commands' -import 'semantic-ui-offline/semantic.min.css'; -import {MemoryRouter, Route, Routes} from "react-router-dom"; +// Component tests mount real components, so they need the same styles the app loads. +import '../../src/index.css'; +import '../../src/themes/fonts.css'; +import '../../src/themes/tokens.css'; +import '@mantine/core/styles.css'; +// react-router v7 ships these directly; `react-router-dom` is not installed. +import {MemoryRouter, Route, Routes} from "react-router"; import {QueryProvider} from "../../src/hooks/customHooks"; import {TagsProvider} from "../../src/Tags"; +import {MantineProvider} from "@mantine/core"; +import {cssVariablesResolver, mantineTheme} from "../../src/themes/mantine"; import React from "react"; Cypress.on('uncaught:exception', (err, runnable) => { @@ -31,8 +38,14 @@ Cypress.on('uncaught:exception', (err, runnable) => { Cypress.Commands.add('mountWithRouter', (component, options) => { options = options || {}; const initialEntries = options?.initialEntries || ['/']; + /* + * MantineProvider, configured exactly as ThemeProvider configures it. Every component + * in src/components/ui renders Mantine internals and throws without it -- the same + * thing that had to be added to test-utils.js for jest. + */ return cy.mount( + @@ -41,6 +54,7 @@ Cypress.Commands.add('mountWithRouter', (component, options) => { + , options ); diff --git a/app/package-lock.json b/app/package-lock.json index 541073c2..40aafcc6 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -33,10 +33,7 @@ "react-qr-code": "^2.2.0", "react-router": "^7.18.2", "react-scripts": "5.0.1", - "react-semantic-toasts-2": "^0.6.7", "react-stl-viewer": "^2.5.0", - "semantic-ui-offline": "^2.5.1", - "semantic-ui-react": "^2.1.5", "three": "^0.185", "web-vitals": "^5.3.0" }, @@ -3799,36 +3796,6 @@ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", "license": "MIT" }, - "node_modules/@fluentui/react-component-event-listener": { - "version": "0.63.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz", - "integrity": "sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==", - "dependencies": { - "@babel/runtime": "^7.10.4" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18", - "react-dom": "^16.8.0 || ^17 || ^18" - } - }, - "node_modules/@fluentui/react-component-ref": { - "version": "0.63.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-component-ref/-/react-component-ref-0.63.1.tgz", - "integrity": "sha512-8MkXX4+R3i80msdbD4rFpEB4WWq2UDvGwG386g3ckIWbekdvN9z2kWAd9OXhRGqB7QeOsoAGWocp6gAMCivRlw==", - "dependencies": { - "@babel/runtime": "^7.10.4", - "react-is": "^16.6.3" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18", - "react-dom": "^16.8.0 || ^17 || ^18" - } - }, - "node_modules/@fluentui/react-component-ref/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -4905,16 +4872,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/@popperjs/core": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@react-three/fiber": { "version": "8.16.5", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.5.tgz", @@ -5153,19 +5110,6 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, - "node_modules/@semantic-ui-react/event-stack": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz", - "integrity": "sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==", - "dependencies": { - "exenv": "^1.2.2", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", @@ -7937,14 +7881,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "engines": { - "node": ">=6" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -10453,11 +10389,6 @@ "node": ">=4" } }, - "node_modules/exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" - }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -14520,11 +14451,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" - }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -14706,11 +14632,6 @@ "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", "license": "ISC" }, - "node_modules/keyboard-key": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", - "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -14934,11 +14855,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, - "node_modules/lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -17592,7 +17508,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -18016,11 +17931,6 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, - "node_modules/react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, "node_modules/react-hotkeys-hook": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-5.3.3.tgz", @@ -18045,20 +17955,6 @@ "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/react-popper": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", - "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", - "dependencies": { - "react-fast-compare": "^3.0.1", - "warning": "^4.0.2" - }, - "peerDependencies": { - "@popperjs/core": "^2.0.0", - "react": "^16.8.0 || ^17 || ^18", - "react-dom": "^16.8.0 || ^17 || ^18" - } - }, "node_modules/react-qr-code": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.2.0.tgz", @@ -18252,16 +18148,6 @@ } } }, - "node_modules/react-semantic-toasts-2": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/react-semantic-toasts-2/-/react-semantic-toasts-2-0.6.7.tgz", - "integrity": "sha512-Mwcwu6DbozO8XOteOOXmicNywLwskX7XV98sG2cSZ02G/RIM2uRUZvx65nqIFp67CSe+tBU1wKVWvNascZQR/w==", - "peerDependencies": { - "prop-types": "^15.7.2", - "react": "16.x.x || 17.x.x || 18.x.x", - "semantic-ui-react": "*" - } - }, "node_modules/react-stl-viewer": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/react-stl-viewer/-/react-stl-viewer-2.5.0.tgz", @@ -18978,39 +18864,6 @@ "node": ">=10" } }, - "node_modules/semantic-ui-offline": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/semantic-ui-offline/-/semantic-ui-offline-2.5.1.tgz", - "integrity": "sha512-uwykZ0AF8rbKSsm6GIbQtAwLCKUexqKVX4qbbB1hvYNvOqhYdWqWMbTfrb3JLHYb19g9m6CEV6n+077AoVTUNg==", - "dependencies": { - "jquery": "^3.7.1" - } - }, - "node_modules/semantic-ui-react": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-2.1.5.tgz", - "integrity": "sha512-nIqmmUNpFHfovEb+RI2w3E2/maZQutd8UIWyRjf1SLse+XF51hI559xbz/sLN3O6RpLjr/echLOOXwKCirPy3Q==", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.10.5", - "@fluentui/react-component-event-listener": "~0.63.0", - "@fluentui/react-component-ref": "~0.63.0", - "@popperjs/core": "^2.6.0", - "@semantic-ui-react/event-stack": "^3.1.3", - "clsx": "^1.1.1", - "keyboard-key": "^1.1.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "prop-types": "^15.7.2", - "react-is": "^16.8.6 || ^17.0.0 || ^18.0.0", - "react-popper": "^2.3.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -19210,11 +19063,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -20872,14 +20720,6 @@ "makeerror": "1.0.12" } }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", @@ -24434,30 +24274,6 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==" }, - "@fluentui/react-component-event-listener": { - "version": "0.63.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz", - "integrity": "sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==", - "requires": { - "@babel/runtime": "^7.10.4" - } - }, - "@fluentui/react-component-ref": { - "version": "0.63.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-component-ref/-/react-component-ref-0.63.1.tgz", - "integrity": "sha512-8MkXX4+R3i80msdbD4rFpEB4WWq2UDvGwG386g3ckIWbekdvN9z2kWAd9OXhRGqB7QeOsoAGWocp6gAMCivRlw==", - "requires": { - "@babel/runtime": "^7.10.4", - "react-is": "^16.6.3" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -25238,12 +25054,6 @@ } } }, - "@popperjs/core": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", - "peer": true - }, "@react-three/fiber": { "version": "8.16.5", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.5.tgz", @@ -25394,15 +25204,6 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" }, - "@semantic-ui-react/event-stack": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz", - "integrity": "sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==", - "requires": { - "exenv": "^1.2.2", - "prop-types": "^15.6.2" - } - }, "@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", @@ -27424,11 +27225,6 @@ "wrap-ansi": "^7.0.0" } }, - "clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -29229,11 +29025,6 @@ "pify": "^2.2.0" } }, - "exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" - }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -32124,11 +31915,6 @@ } } }, - "jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" - }, "js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -32266,11 +32052,6 @@ "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" }, - "keyboard-key": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", - "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -32428,11 +32209,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, - "lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==" - }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -34132,7 +33908,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "peer": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -34443,11 +34218,6 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, - "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, "react-hotkeys-hook": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-5.3.3.tgz", @@ -34465,15 +34235,6 @@ "integrity": "sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==", "requires": {} }, - "react-popper": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", - "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", - "requires": { - "react-fast-compare": "^3.0.1", - "warning": "^4.0.2" - } - }, "react-qr-code": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.2.0.tgz", @@ -34600,12 +34361,6 @@ "workbox-webpack-plugin": "^6.4.1" } }, - "react-semantic-toasts-2": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/react-semantic-toasts-2/-/react-semantic-toasts-2-0.6.7.tgz", - "integrity": "sha512-Mwcwu6DbozO8XOteOOXmicNywLwskX7XV98sG2cSZ02G/RIM2uRUZvx65nqIFp67CSe+tBU1wKVWvNascZQR/w==", - "requires": {} - }, "react-stl-viewer": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/react-stl-viewer/-/react-stl-viewer-2.5.0.tgz", @@ -35081,35 +34836,6 @@ "node-forge": "^1" } }, - "semantic-ui-offline": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/semantic-ui-offline/-/semantic-ui-offline-2.5.1.tgz", - "integrity": "sha512-uwykZ0AF8rbKSsm6GIbQtAwLCKUexqKVX4qbbB1hvYNvOqhYdWqWMbTfrb3JLHYb19g9m6CEV6n+077AoVTUNg==", - "requires": { - "jquery": "^3.7.1" - } - }, - "semantic-ui-react": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-2.1.5.tgz", - "integrity": "sha512-nIqmmUNpFHfovEb+RI2w3E2/maZQutd8UIWyRjf1SLse+XF51hI559xbz/sLN3O6RpLjr/echLOOXwKCirPy3Q==", - "peer": true, - "requires": { - "@babel/runtime": "^7.10.5", - "@fluentui/react-component-event-listener": "~0.63.0", - "@fluentui/react-component-ref": "~0.63.0", - "@popperjs/core": "^2.6.0", - "@semantic-ui-react/event-stack": "^3.1.3", - "clsx": "^1.1.1", - "keyboard-key": "^1.1.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "prop-types": "^15.7.2", - "react-is": "^16.8.6 || ^17.0.0 || ^18.0.0", - "react-popper": "^2.3.0", - "shallowequal": "^1.1.0" - } - }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -35282,11 +35008,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -36437,14 +36158,6 @@ "makeerror": "1.0.12" } }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - }, "watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", diff --git a/app/package.json b/app/package.json index 2ed3275e..13b0fa90 100644 --- a/app/package.json +++ b/app/package.json @@ -28,10 +28,7 @@ "react-qr-code": "^2.2.0", "react-router": "^7.18.2", "react-scripts": "5.0.1", - "react-semantic-toasts-2": "^0.6.7", "react-stl-viewer": "^2.5.0", - "semantic-ui-offline": "^2.5.1", - "semantic-ui-react": "^2.1.5", "three": "^0.185", "web-vitals": "^5.3.0" }, diff --git a/app/src/components/Download.cy.js b/app/src/components/Download.cy.js index 39195b35..cb03ca71 100644 --- a/app/src/components/Download.cy.js +++ b/app/src/components/Download.cy.js @@ -1,6 +1,5 @@ import React from 'react'; import {ArchiveDownloadForm, ChannelDownloadForm, EditRSSDownloadForm} from './Download'; -import 'semantic-ui-offline/semantic.min.css'; describe('', () => { beforeEach(() => { diff --git a/app/src/components/collections/BatchReorganizeModal.test.js b/app/src/components/collections/BatchReorganizeModal.test.js index f434eae4..0945e77f 100644 --- a/app/src/components/collections/BatchReorganizeModal.test.js +++ b/app/src/components/collections/BatchReorganizeModal.test.js @@ -11,10 +11,6 @@ jest.mock('../../api', () => ({ getBatchReorganizationStatus: jest.fn(), })); -// Mock react-semantic-toasts-2 -jest.mock('react-semantic-toasts-2', () => ({ - toast: jest.fn(), -})); // Mock the FileWorkerStatusContext jest.mock('../../contexts/FileWorkerStatusContext', () => ({ diff --git a/app/src/components/collections/CollectionReorganizeModal.test.js b/app/src/components/collections/CollectionReorganizeModal.test.js index 1e5aab9e..b34ab6f7 100644 --- a/app/src/components/collections/CollectionReorganizeModal.test.js +++ b/app/src/components/collections/CollectionReorganizeModal.test.js @@ -11,10 +11,6 @@ jest.mock('../../api', () => ({ getReorganizationStatus: jest.fn(), })); -// Mock react-semantic-toasts-2 -jest.mock('react-semantic-toasts-2', () => ({ - toast: jest.fn(), -})); // Mock the FileWorkerStatusContext - default mock returns inactive state jest.mock('../../contexts/FileWorkerStatusContext', () => ({ diff --git a/app/src/components/collections/ConflictResolutionModal.test.js b/app/src/components/collections/ConflictResolutionModal.test.js index 27a90054..2ecd200a 100644 --- a/app/src/components/collections/ConflictResolutionModal.test.js +++ b/app/src/components/collections/ConflictResolutionModal.test.js @@ -9,10 +9,6 @@ jest.mock('../../api', () => ({ deleteFileGroups: jest.fn(), })); -// Mock react-semantic-toasts-2 -jest.mock('react-semantic-toasts-2', () => ({ - toast: jest.fn(), -})); describe('ConflictResolutionModal', () => { const mockConflicts = [ diff --git a/app/src/hooks/useSubsystemToggle.test.js b/app/src/hooks/useSubsystemToggle.test.js index d08c241f..ec8c9be6 100644 --- a/app/src/hooks/useSubsystemToggle.test.js +++ b/app/src/hooks/useSubsystemToggle.test.js @@ -17,7 +17,6 @@ jest.mock('../api/controller', () => ({ getControllerStats: jest.fn().mockResolvedValue({}), })); -jest.mock('react-semantic-toasts-2', () => ({toast: jest.fn()})); const controllerApi = require('../api/controller'); diff --git a/app/src/semantic-baseline.test.js b/app/src/semantic-baseline.test.js index 92c20ab1..a55d7c3c 100644 --- a/app/src/semantic-baseline.test.js +++ b/app/src/semantic-baseline.test.js @@ -3,20 +3,20 @@ import path from 'path'; import baseline from './semantic-baseline.json'; /* - * A ratchet for the Semantic UI removal. + * Semantic UI is gone, and this keeps it gone. * - * semantic-baseline.json lists every file that still imports Semantic UI (or the - * Semantic-based toast library). This test fails if a file not on that list - * starts importing them, and asks for the list to shrink when a file stops. + * It began as a ratchet: semantic-baseline.json listed the 75 files still importing + * Semantic UI, the list only shrank, and adding a file to it failed the build. The list + * reached zero, the three packages are uninstalled, and the baseline is now an empty + * array kept only so a reintroduction has to delete a file rather than edit one. * - * It replaces an ESLint rule deliberately: `no-restricted-imports` would either - * print 75 warnings on every dev rebuild, or fail the build outright, and CI - * already unsets CI= for the build step so warnings there guard nothing. + * The assertions below are cheap and each one caught something real during the migration, + * so they stay: an import would now fail to resolve, but a `className="ui button"` or a + * reach back through Theme.tsx would not, and neither would reinstalling a package. * - * The list has reached zero. The test stays as a guard rather than being deleted: it now - * asserts that nothing imports Semantic UI, nothing calls its toast library, nothing leans - * on its stylesheet, and no migrated file reaches back through Theme.tsx. It can go when - * the packages themselves are uninstalled. + * It is a test rather than an ESLint rule deliberately: `no-restricted-imports` would + * either print dozens of warnings on every dev rebuild or fail the build outright, and CI + * unsets CI= for its build step, so warnings there guard nothing. */ const SRC = path.join(__dirname); @@ -109,10 +109,26 @@ describe('Semantic UI removal', () => { expect(leaks).toEqual([]); }); - it('reports how much of the migration is left', () => { - // Not an assertion so much as a progress readout in the test output. - const remaining = importers().length; - expect(remaining).toBeLessThanOrEqual(baseline.length); - console.log(`Semantic UI: ${remaining} files remaining to migrate.`); + it('has no Semantic package installed', () => { + /* + * The three packages are uninstalled. An import of a missing module fails loudly, + * so this guards the quieter mistake: someone reinstalling one -- to "just use a + * Semantic component for this one thing" -- which would drag the whole library and + * its 300kB stylesheet back into the bundle. + */ + const pkg = JSON.parse( + fs.readFileSync(path.join(SRC, '..', 'package.json'), 'utf8')); + const named = [...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.devDependencies || {})] + .filter(name => /semantic/i.test(name)); + + expect(named).toEqual([]); + }); + + it('keeps the baseline empty', () => { + // The migration is finished; the file stays as an empty list so that putting a + // name back requires a deliberate edit. + expect(baseline).toEqual([]); + expect(importers()).toEqual([]); }); });