From ae2bb005b07ee3e2062501caa4d75eccebcd2a26 Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:13:34 +0530 Subject: [PATCH] Upgrade to react 19, add titles, add duplicate files util (#1154) * Upgrade to react 19, add titles * Add duplicate files util --- package.json | 10 +- pnpm-lock.yaml | 612 +++++++++--------- src/components/Collection/constants.ts | 2 + src/components/Layout/TopNav.tsx | 4 +- .../Utilities/ReleaseManagement/Episode.tsx | 175 +++++ .../MultiplesUtilEpisode.tsx | 101 --- .../{MultiplesUtilList.tsx => SeriesList.tsx} | 142 ++-- .../Utilities/ReleaseManagement/Title.tsx | 4 +- src/components/Utilities/constants.tsx | 6 +- src/core/react-query/file/mutations.ts | 6 + src/core/react-query/file/types.ts | 6 + .../react-query/release-management/queries.ts | 26 +- .../react-query/release-management/types.ts | 4 +- src/core/router/index.tsx | 5 +- src/core/types/api/file.ts | 2 + src/core/types/api/series.ts | 2 +- src/pages/collection/Collection.tsx | 99 +-- src/pages/collection/Series.tsx | 2 +- src/pages/collection/series/SeriesCredits.tsx | 83 +-- .../collection/series/SeriesEpisodes.tsx | 215 +++--- .../collection/series/SeriesFileSummary.tsx | 54 +- src/pages/collection/series/SeriesImages.tsx | 159 ++--- .../collection/series/SeriesOverview.tsx | 27 +- src/pages/collection/series/SeriesTags.tsx | 73 +-- src/pages/dashboard/DashboardPage.tsx | 1 + src/pages/logs/LogsPage.tsx | 129 ++-- src/pages/settings/SettingsPage.tsx | 2 +- src/pages/settings/tabs/AniDBSettings.tsx | 1 + src/pages/settings/tabs/ApiKeys.tsx | 1 + .../settings/tabs/CollectionSettings.tsx | 1 + src/pages/settings/tabs/GeneralSettings.tsx | 1 + src/pages/settings/tabs/ImportSettings.tsx | 1 + .../settings/tabs/IntegrationsSettings.tsx | 1 + .../settings/tabs/MetadataSitesSettings.tsx | 1 + .../settings/tabs/UserManagementSettings.tsx | 1 + src/pages/utilities/FileSearch.tsx | 137 ++-- src/pages/utilities/ReleaseManagement.tsx | 210 ++++++ .../MultiplesUtil.tsx | 180 ------ src/pages/utilities/Renamer.tsx | 347 +++++----- .../utilities/SeriesWithoutFilesUtility.tsx | 93 +-- .../IgnoredFilesTab.tsx | 93 +-- .../ManuallyLinkedTab.tsx | 171 ++--- .../UnrecognizedTab.tsx | 1 + 43 files changed, 1690 insertions(+), 1501 deletions(-) create mode 100644 src/components/Utilities/ReleaseManagement/Episode.tsx delete mode 100644 src/components/Utilities/ReleaseManagement/MultiplesUtilEpisode.tsx rename src/components/Utilities/ReleaseManagement/{MultiplesUtilList.tsx => SeriesList.tsx} (63%) create mode 100644 src/pages/utilities/ReleaseManagement.tsx delete mode 100644 src/pages/utilities/ReleaseManagementUtilityTabs/MultiplesUtil.tsx diff --git a/package.json b/package.json index 536127864..ed04d3174 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,10 @@ "lodash": "^4.17.21", "monaco-editor": "^0.52.0", "pretty-bytes": "^6.1.1", - "react": "^18.3.1", + "react": "^19.0.0", "react-animate-height": "^3.2.3", "react-avatar-editor": "^13.0.2", - "react-dom": "^18.3.1", + "react-dom": "^19.0.0", "react-grid-layout": "^1.5.0", "react-modal": "^3.16.1", "react-redux": "^9.1.2", @@ -60,9 +60,9 @@ "@types/format-thousands": "^2.0.3", "@types/lodash": "^4.17.13", "@types/node": "^22.10.1", - "@types/react": "^18.3.14", + "@types/react": "^19.0.1", "@types/react-avatar-editor": "^13.0.3", - "@types/react-dom": "^18.3.2", + "@types/react-dom": "^19.0.1", "@types/react-grid-layout": "^1.3.5", "@types/react-modal": "^3.16.3", "@types/react-redux": "^7.1.34", @@ -95,7 +95,7 @@ "tailwindcss": "^3.4.16", "tailwindcss-text-fill-stroke": "2.0.0-beta.1", "typescript": "5.6.3", - "vite": "^5.4.11", + "vite": "^6.0.3", "vite-plugin-webpackchunkname": "^1.0.3" }, "scripts": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e33d13b17..d1f58aebd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,13 +13,13 @@ importers: version: 5.1.0 '@headlessui/react': specifier: ^2.2.0 - version: 2.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@headlessui/tailwindcss': specifier: ^0.2.1 version: 0.2.1(tailwindcss@3.4.16) '@hello-pangea/dnd': specifier: ^17.0.0 - version: 17.0.0(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 17.0.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mdi/js': specifier: ^7.4.47 version: 7.4.47 @@ -31,25 +31,25 @@ importers: version: 8.0.7 '@monaco-editor/react': specifier: ^4.6.0 - version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@reduxjs/toolkit': specifier: ^2.4.0 - version: 2.4.0(react-redux@9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1))(react@18.3.1) + version: 2.4.0(react-redux@9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1))(react@19.0.0) '@sentry/browser': specifier: ^8.42.0 version: 8.42.0 '@sentry/react': specifier: ^8.42.0 - version: 8.42.0(react@18.3.1) + version: 8.42.0(react@19.0.0) '@tanstack/react-query': specifier: ^5.62.3 - version: 5.62.3(react@18.3.1) + version: 5.62.3(react@19.0.0) '@tanstack/react-query-devtools': specifier: ^5.62.3 - version: 5.62.3(@tanstack/react-query@5.62.3(react@18.3.1))(react@18.3.1) + version: 5.62.3(@tanstack/react-query@5.62.3(react@19.0.0))(react@19.0.0) '@tanstack/react-virtual': specifier: ^3.11.0 - version: 3.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.11.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) axios: specifier: ^1.7.9 version: 1.7.9 @@ -81,47 +81,47 @@ importers: specifier: ^6.1.1 version: 6.1.1 react: - specifier: ^18.3.1 - version: 18.3.1 + specifier: ^19.0.0 + version: 19.0.0 react-animate-height: specifier: ^3.2.3 - version: 3.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-avatar-editor: specifier: ^13.0.2 - version: 13.0.2(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 13.0.2(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-dom: - specifier: ^18.3.1 - version: 18.3.1(react@18.3.1) + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) react-grid-layout: specifier: ^1.5.0 - version: 1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-modal: specifier: ^3.16.1 - version: 3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-redux: specifier: ^9.1.2 - version: 9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1) + version: 9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1) react-resizable: specifier: ^3.0.5 - version: 3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.0.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-responsive: specifier: ^10.0.0 - version: 10.0.0(react@18.3.1) + version: 10.0.0(react@19.0.0) react-router: specifier: ^6.28.0 - version: 6.28.0(react@18.3.1) + version: 6.28.0(react@19.0.0) react-router-dom: specifier: ^6.28.0 - version: 6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 6.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-toastify: specifier: ^10.0.6 - version: 10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 10.0.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-tooltip: specifier: ^5.28.0 - version: 5.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-use-measure: specifier: ^2.1.1 - version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) redux: specifier: ^5.0.1 version: 5.0.1 @@ -133,10 +133,10 @@ importers: version: 13.20.0 use-immer: specifier: ^0.10.0 - version: 0.10.0(immer@10.1.1)(react@18.3.1) + version: 0.10.0(immer@10.1.1)(react@19.0.0) usehooks-ts: specifier: ^3.1.0 - version: 3.1.0(react@18.3.1) + version: 3.1.0(react@19.0.0) devDependencies: '@sentry/vite-plugin': specifier: ^2.22.7 @@ -160,14 +160,14 @@ importers: specifier: ^22.10.1 version: 22.10.1 '@types/react': - specifier: ^18.3.14 - version: 18.3.14 + specifier: ^19.0.1 + version: 19.0.1 '@types/react-avatar-editor': specifier: ^13.0.3 version: 13.0.3 '@types/react-dom': - specifier: ^18.3.2 - version: 18.3.2 + specifier: ^19.0.1 + version: 19.0.1 '@types/react-grid-layout': specifier: ^1.3.5 version: 1.3.5 @@ -188,7 +188,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.6.3) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.11(@types/node@22.10.1)) + version: 4.3.4(vite@6.0.3(@types/node@22.10.1)(jiti@1.21.6)(yaml@2.6.1)) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -265,8 +265,8 @@ importers: specifier: 5.6.3 version: 5.6.3 vite: - specifier: ^5.4.11 - version: 5.4.11(@types/node@22.10.1) + specifier: ^6.0.3 + version: 6.0.3(@types/node@22.10.1)(jiti@1.21.6)(yaml@2.6.1) vite-plugin-webpackchunkname: specifier: ^1.0.3 version: 1.0.3(rollup@4.28.1) @@ -682,141 +682,147 @@ packages: '@dual-bundle/import-meta-resolve@4.1.0': resolution: {integrity: sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==} - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1283,14 +1289,11 @@ packages: '@types/node@22.10.1': resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} - '@types/prop-types@15.7.14': - resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} - '@types/react-avatar-editor@13.0.3': resolution: {integrity: sha512-icRAOKLKjkIsExFAiFSquztByJwpyTKEgnBRYSuLG2V81bM3LtQZi7hRS+Hr+4AXreq0yNRjVZiMOVeEeh6DLg==} - '@types/react-dom@18.3.2': - resolution: {integrity: sha512-Fqp+rcvem9wEnGr3RY8dYNvSQ8PoLqjZ9HLgaPUOjJJD120uDyOxOjc/39M4Kddp9JQCxpGQbnhVQF0C0ncYVg==} + '@types/react-dom@19.0.1': + resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} '@types/react-grid-layout@1.3.5': resolution: {integrity: sha512-WH/po1gcEcoR6y857yAnPGug+ZhkF4PaTUxgAbwfeSH/QOgVSakKHBXoPGad/sEznmkiaK3pqHk+etdWisoeBQ==} @@ -1301,8 +1304,8 @@ packages: '@types/react-redux@7.1.34': resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==} - '@types/react@18.3.14': - resolution: {integrity: sha512-NzahNKvjNhVjuPBQ+2G7WlxstQ+47kXZNHlUvFakDViuIEfGY926GqhMueQFZ7woG+sPiQKlF36XfrIUVSUfFg==} + '@types/react@19.0.1': + resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -1904,9 +1907,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} hasBin: true escalade@3.2.0: @@ -3160,10 +3163,10 @@ packages: react: ^0.14.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^0.14.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + react-dom@19.0.0: + resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: - react: ^18.3.1 + react: ^19.0.0 react-draggable@4.4.6: resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} @@ -3248,8 +3251,8 @@ packages: react: '>=16.13' react-dom: '>=16.13' - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + react@19.0.0: + resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -3345,8 +3348,8 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} @@ -3671,22 +3674,27 @@ packages: vite-plugin-webpackchunkname@1.0.3: resolution: {integrity: sha512-88lt6IrgCumnf4Up8eyaSJbmo4V0ZIaR4M94fbZvGGmK2aWMmPGVsiFBszYE7Kq04I9tGjLFnyremn+KEgEGyw==} - vite@5.4.11: - resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} - engines: {node: ^18.0.0 || >=20.0.0} + vite@6.0.3: + resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + 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: @@ -3701,6 +3709,10 @@ packages: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} @@ -4235,73 +4247,76 @@ snapshots: '@dual-bundle/import-meta-resolve@4.1.0': {} - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/aix-ppc64@0.24.0': + optional: true + + '@esbuild/android-arm64@0.24.0': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm@0.24.0': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-x64@0.24.0': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/darwin-arm64@0.24.0': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-x64@0.24.0': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/freebsd-arm64@0.24.0': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-x64@0.24.0': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/linux-arm64@0.24.0': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm@0.24.0': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-ia32@0.24.0': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-loong64@0.24.0': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-mips64el@0.24.0': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-ppc64@0.24.0': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-riscv64@0.24.0': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-s390x@0.24.0': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-x64@0.24.0': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/netbsd-x64@0.24.0': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/openbsd-arm64@0.24.0': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.24.0': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.24.0': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.24.0': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.24.0': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.24.0': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': @@ -4336,48 +4351,48 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@floating-ui/dom': 1.6.12 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - '@floating-ui/react@0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react@0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@floating-ui/utils': 0.2.8 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) tabbable: 6.2.0 '@floating-ui/utils@0.2.8': {} '@fontsource/sora@5.1.0': {} - '@headlessui/react@2.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@headlessui/react@2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react': 0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-aria/focus': 3.19.0(react@18.3.1) - '@react-aria/interactions': 3.22.5(react@18.3.1) - '@tanstack/react-virtual': 3.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@react-aria/focus': 3.19.0(react@19.0.0) + '@react-aria/interactions': 3.22.5(react@19.0.0) + '@tanstack/react-virtual': 3.11.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) '@headlessui/tailwindcss@0.2.1(tailwindcss@3.4.16)': dependencies: tailwindcss: 3.4.16 - '@hello-pangea/dnd@17.0.0(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@hello-pangea/dnd@17.0.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@babel/runtime': 7.26.0 css-box-model: 1.2.1 memoize-one: 6.0.0 raf-schd: 4.0.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-redux: 9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-redux: 9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1) redux: 5.0.1 - use-memo-one: 1.1.3(react@18.3.1) + use-memo-one: 1.1.3(react@19.0.0) transitivePeerDependencies: - '@types/react' @@ -4442,12 +4457,12 @@ snapshots: monaco-editor: 0.52.0 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) monaco-editor: 0.52.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -4466,55 +4481,55 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@react-aria/focus@3.19.0(react@18.3.1)': + '@react-aria/focus@3.19.0(react@19.0.0)': dependencies: - '@react-aria/interactions': 3.22.5(react@18.3.1) - '@react-aria/utils': 3.26.0(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/interactions': 3.22.5(react@19.0.0) + '@react-aria/utils': 3.26.0(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 clsx: 2.1.1 - react: 18.3.1 + react: 19.0.0 - '@react-aria/interactions@3.22.5(react@18.3.1)': + '@react-aria/interactions@3.22.5(react@19.0.0)': dependencies: - '@react-aria/ssr': 3.9.7(react@18.3.1) - '@react-aria/utils': 3.26.0(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/ssr': 3.9.7(react@19.0.0) + '@react-aria/utils': 3.26.0(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-aria/ssr@3.9.7(react@18.3.1)': + '@react-aria/ssr@3.9.7(react@19.0.0)': dependencies: '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-aria/utils@3.26.0(react@18.3.1)': + '@react-aria/utils@3.26.0(react@19.0.0)': dependencies: - '@react-aria/ssr': 3.9.7(react@18.3.1) - '@react-stately/utils': 3.10.5(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/ssr': 3.9.7(react@19.0.0) + '@react-stately/utils': 3.10.5(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 clsx: 2.1.1 - react: 18.3.1 + react: 19.0.0 - '@react-stately/utils@3.10.5(react@18.3.1)': + '@react-stately/utils@3.10.5(react@19.0.0)': dependencies: '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-types/shared@3.26.0(react@18.3.1)': + '@react-types/shared@3.26.0(react@19.0.0)': dependencies: - react: 18.3.1 + react: 19.0.0 - '@reduxjs/toolkit@2.4.0(react-redux@9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': + '@reduxjs/toolkit@2.4.0(react-redux@9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1))(react@19.0.0)': dependencies: immer: 10.1.1 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 optionalDependencies: - react: 18.3.1 - react-redux: 9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1) + react: 19.0.0 + react-redux: 9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1) '@remix-run/router@1.21.0': {} @@ -4673,12 +4688,12 @@ snapshots: '@sentry/core@8.42.0': {} - '@sentry/react@8.42.0(react@18.3.1)': + '@sentry/react@8.42.0(react@19.0.0)': dependencies: '@sentry/browser': 8.42.0 '@sentry/core': 8.42.0 hoist-non-react-statics: 3.3.2 - react: 18.3.1 + react: 19.0.0 '@sentry/vite-plugin@2.22.7': dependencies: @@ -4720,22 +4735,22 @@ snapshots: '@tanstack/query-devtools@5.61.4': {} - '@tanstack/react-query-devtools@5.62.3(@tanstack/react-query@5.62.3(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-devtools@5.62.3(@tanstack/react-query@5.62.3(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/query-devtools': 5.61.4 - '@tanstack/react-query': 5.62.3(react@18.3.1) - react: 18.3.1 + '@tanstack/react-query': 5.62.3(react@19.0.0) + react: 19.0.0 - '@tanstack/react-query@5.62.3(react@18.3.1)': + '@tanstack/react-query@5.62.3(react@19.0.0)': dependencies: '@tanstack/query-core': 5.62.3 - react: 18.3.1 + react: 19.0.0 - '@tanstack/react-virtual@3.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-virtual@3.11.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/virtual-core': 3.10.9 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) '@tanstack/virtual-core@3.10.9': {} @@ -4766,7 +4781,7 @@ snapshots: '@types/hoist-non-react-statics@3.3.6': dependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 hoist-non-react-statics: 3.3.2 '@types/json5@0.0.29': {} @@ -4777,34 +4792,31 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/prop-types@15.7.14': {} - '@types/react-avatar-editor@13.0.3': dependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 - '@types/react-dom@18.3.2': + '@types/react-dom@19.0.1': dependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 '@types/react-grid-layout@1.3.5': dependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 '@types/react-modal@3.16.3': dependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 '@types/react-redux@7.1.34': dependencies: '@types/hoist-non-react-statics': 3.3.6 - '@types/react': 18.3.14 + '@types/react': 19.0.1 hoist-non-react-statics: 3.3.2 redux: 4.2.1 - '@types/react@18.3.14': + '@types/react@19.0.1': dependencies: - '@types/prop-types': 15.7.14 csstype: 3.1.3 '@types/semver@7.5.8': {} @@ -4933,14 +4945,14 @@ snapshots: '@ungap/structured-clone@1.2.1': {} - '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@22.10.1))': + '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.1)(jiti@1.21.6)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.11(@types/node@22.10.1) + vite: 6.0.3(@types/node@22.10.1)(jiti@1.21.6)(yaml@2.6.1) transitivePeerDependencies: - supports-color @@ -5510,31 +5522,32 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.1.0 - esbuild@0.21.5: + esbuild@0.24.0: 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/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 escalade@3.2.0: {} @@ -6824,120 +6837,117 @@ snapshots: raf-schd@4.0.3: {} - react-animate-height@3.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-animate-height@3.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - react-avatar-editor@13.0.2(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-avatar-editor@13.0.2(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) '@babel/runtime': 7.26.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) transitivePeerDependencies: - '@babel/core' - supports-color - react-dom@18.3.1(react@18.3.1): + react-dom@19.0.0(react@19.0.0): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + react: 19.0.0 + scheduler: 0.25.0 - react-draggable@4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-draggable@4.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: clsx: 1.2.1 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - react-grid-layout@1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-grid-layout@1.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: clsx: 2.1.1 fast-equals: 4.0.3 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-draggable: 4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-resizable: 3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-draggable: 4.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-resizable: 3.0.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) resize-observer-polyfill: 1.5.1 react-is@16.13.1: {} react-lifecycles-compat@3.0.4: {} - react-modal@3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-modal@3.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: exenv: 1.2.2 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) react-lifecycles-compat: 3.0.4 warning: 4.0.3 - react-redux@9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1): + react-redux@9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.3 - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) + react: 19.0.0 + use-sync-external-store: 1.4.0(react@19.0.0) optionalDependencies: - '@types/react': 18.3.14 + '@types/react': 19.0.1 redux: 5.0.1 react-refresh@0.14.2: {} - react-resizable@3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-resizable@3.0.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: prop-types: 15.8.1 - react: 18.3.1 - react-draggable: 4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 19.0.0 + react-draggable: 4.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) transitivePeerDependencies: - react-dom - react-responsive@10.0.0(react@18.3.1): + react-responsive@10.0.0(react@19.0.0): dependencies: hyphenate-style-name: 1.1.0 matchmediaquery: 0.4.2 prop-types: 15.8.1 - react: 18.3.1 + react: 19.0.0 shallow-equal: 3.1.0 - react-router-dom@6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@remix-run/router': 1.21.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.28.0(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-router: 6.28.0(react@19.0.0) - react-router@6.28.0(react@18.3.1): + react-router@6.28.0(react@19.0.0): dependencies: '@remix-run/router': 1.21.0 - react: 18.3.1 + react: 19.0.0 - react-toastify@10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-toastify@10.0.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - react-tooltip@5.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-tooltip@5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@floating-ui/dom': 1.6.12 classnames: 2.5.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - react-use-measure@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-use-measure@2.1.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: debounce: 1.2.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - react@18.3.1: - dependencies: - loose-envify: 1.4.0 + react@19.0.0: {} read-cache@1.0.0: dependencies: @@ -7058,9 +7068,7 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 + scheduler@0.25.0: {} semver@6.3.1: {} @@ -7479,23 +7487,23 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-immer@0.10.0(immer@10.1.1)(react@18.3.1): + use-immer@0.10.0(immer@10.1.1)(react@19.0.0): dependencies: immer: 10.1.1 - react: 18.3.1 + react: 19.0.0 - use-memo-one@1.1.3(react@18.3.1): + use-memo-one@1.1.3(react@19.0.0): dependencies: - react: 18.3.1 + react: 19.0.0 - use-sync-external-store@1.4.0(react@18.3.1): + use-sync-external-store@1.4.0(react@19.0.0): dependencies: - react: 18.3.1 + react: 19.0.0 - usehooks-ts@3.1.0(react@18.3.1): + usehooks-ts@3.1.0(react@19.0.0): dependencies: lodash.debounce: 4.0.8 - react: 18.3.1 + react: 19.0.0 util-deprecate@1.0.2: {} @@ -7508,14 +7516,16 @@ snapshots: transitivePeerDependencies: - rollup - vite@5.4.11(@types/node@22.10.1): + vite@6.0.3(@types/node@22.10.1)(jiti@1.21.6)(yaml@2.6.1): dependencies: - esbuild: 0.21.5 + esbuild: 0.24.0 postcss: 8.4.49 rollup: 4.28.1 optionalDependencies: '@types/node': 22.10.1 fsevents: 2.3.3 + jiti: 1.21.6 + yaml: 2.6.1 warning@4.0.3: dependencies: diff --git a/src/components/Collection/constants.ts b/src/components/Collection/constants.ts index 1d5492e06..47ccbbbc9 100644 --- a/src/components/Collection/constants.ts +++ b/src/components/Collection/constants.ts @@ -1,6 +1,7 @@ import type React from 'react'; import type { ImageType } from '@/core/types/api/common'; +import type { SeriesType } from '@/core/types/api/series'; export const posterItemSize = { width: 209, @@ -18,4 +19,5 @@ export const listItemSize = { export type SeriesContextType = { backdrop?: ImageType; scrollRef: React.RefObject; + series: SeriesType; }; diff --git a/src/components/Layout/TopNav.tsx b/src/components/Layout/TopNav.tsx index 853677704..42ced171d 100644 --- a/src/components/Layout/TopNav.tsx +++ b/src/components/Layout/TopNav.tsx @@ -185,7 +185,7 @@ function TopNav() { - cx({ 'text-header-icon-primary': isActive, 'opacity-65 pointer-events-none': layoutEditMode })} + cx({ 'text-topnav-text-primary': isActive, 'opacity-65 pointer-events-none': layoutEditMode })} onClick={closeModalsAndSubmenus} data-tooltip-id="tooltip" data-tooltip-content="Settings" @@ -348,7 +348,7 @@ function TopNav() { icon={mdiFileSearchOutline} onClick={closeModalsAndSubmenus} path="utilities/file-search" - text="Files Search" + text="File Search" /> void; +}; + +const Episode = ({ episode, setFileOptions, type }: Props) => { + const [options, setOptions] = useState( + () => { + const tempOptions: ReleaseManagementOptionsType = {}; + if (!episode) return tempOptions; + + if (type === 'multiples') { + forEach(episode.Files, (file) => { + if (file.IsVariation) tempOptions[file.ID] = 'variation'; + else tempOptions[file.ID] = 'keep'; + }); + return tempOptions; + } + + forEach( + flatMap(episode.Files, file => file.Locations), + (location) => { + tempOptions[location.ID] = 'keep'; + }, + ); + return tempOptions; + }, + ); + + const optionCounts = useMemo(() => countBy(options), [options]); + + useEffect(() => { + setFileOptions(options); + }, [options, setFileOptions]); + + if (!episode) return null; + + const handleOptionChange = (fileId: number, value: 'keep' | 'variation' | 'delete') => { + setOptions(tempOptions => ( + { ...tempOptions, [fileId]: value } + )); + }; + + return ( + <> +
+ {`${getEpisodePrefix(episode.AniDB?.Type)}${episode.AniDB?.EpisodeNumber} - ${episode.Name}`} +
+ {optionCounts.keep ?? 0} +  Kept |  + {type === 'multiples' && ( + <> + {optionCounts.variation ?? 0} +  Variation |  + + )} + {optionCounts.delete ?? 0} +  Delete +
+
+ + {type === 'duplicates' && flatMap(episode.Files, file => + map(file.Locations, (location, index) => { + const absolutePath = location.AbsolutePath ?? '??'; + const fileName = absolutePath.split(/[/\\]+/).pop(); + const folderPath = absolutePath.slice(0, absolutePath.replaceAll('\\', '/').lastIndexOf('/') + 1); + + return ( +
+
+
+
+
File Name
+ {fileName} +
+
+
Location
+ {folderPath} +
+
+
+ +
+ + + {file.AniDB?.ID && ( + +
+ ); + }))} + + {type === 'multiples' && episode.Files?.map(file => ( +
+ + +
+ + + {file.AniDB?.ID && ( + +
+ ))} + + ); +}; + +export default Episode; diff --git a/src/components/Utilities/ReleaseManagement/MultiplesUtilEpisode.tsx b/src/components/Utilities/ReleaseManagement/MultiplesUtilEpisode.tsx deleted file mode 100644 index 6039efd19..000000000 --- a/src/components/Utilities/ReleaseManagement/MultiplesUtilEpisode.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { mdiOpenInNew } from '@mdi/js'; -import { Icon } from '@mdi/react'; -import { countBy, forEach } from 'lodash'; - -import FileInfo from '@/components/FileInfo'; -import Select from '@/components/Input/Select'; -import { getEpisodePrefix } from '@/core/utilities/getEpisodePrefix'; - -import type { MultipleFileOptionsType } from '@/components/Utilities/constants'; -import type { EpisodeType } from '@/core/types/api/episode'; - -type Props = { - episode: EpisodeType | undefined; - setFileOptions: (options: MultipleFileOptionsType) => void; -}; - -const MultiplesUtilEpisode = ({ episode, setFileOptions }: Props) => { - const [options, setOptions] = useState( - () => { - const tempOptions: MultipleFileOptionsType = {}; - if (!episode) return tempOptions; - - forEach(episode.Files, (file) => { - if (file.IsVariation) tempOptions[file.ID] = 'variation'; - else tempOptions[file.ID] = 'keep'; - }); - return tempOptions; - }, - ); - - const optionCounts = useMemo(() => countBy(options), [options]); - - useEffect(() => { - setFileOptions(options); - }, [options, setFileOptions]); - - if (!episode) return null; - - const handleOptionChange = (fileId: number, value: 'keep' | 'variation' | 'delete') => { - setOptions(tempOptions => ( - { ...tempOptions, [fileId]: value } - )); - }; - - return ( - <> -
- {`${getEpisodePrefix(episode.AniDB?.Type)}${episode.AniDB?.EpisodeNumber} - ${episode.Name}`} -
- {optionCounts.keep ?? 0} -  Kept |  - {optionCounts.variation ?? 0} -  Variation |  - {optionCounts.delete ?? 0} -  Delete -
-
- - {episode.Files?.map(file => ( -
- - -
- - - {file.AniDB?.ID && ( - -
- ))} - - ); -}; - -export default MultiplesUtilEpisode; diff --git a/src/components/Utilities/ReleaseManagement/MultiplesUtilList.tsx b/src/components/Utilities/ReleaseManagement/SeriesList.tsx similarity index 63% rename from src/components/Utilities/ReleaseManagement/MultiplesUtilList.tsx rename to src/components/Utilities/ReleaseManagement/SeriesList.tsx index 0361e2eec..d0de8c38f 100644 --- a/src/components/Utilities/ReleaseManagement/MultiplesUtilList.tsx +++ b/src/components/Utilities/ReleaseManagement/SeriesList.tsx @@ -1,20 +1,21 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { mdiLoading, mdiOpenInNew } from '@mdi/js'; import { Icon } from '@mdi/react'; +import { forEach } from 'lodash'; import UtilitiesTable from '@/components/Utilities/UtilitiesTable'; import { - useSeriesEpisodesWithMultipleReleases, - useSeriesWithMultipleReleases, + useReleaseManagementSeries, + useReleaseManagementSeriesEpisodes, } from '@/core/react-query/release-management/queries'; import { getEpisodePrefix } from '@/core/utilities/getEpisodePrefix'; import useFlattenListResult from '@/hooks/useFlattenListResult'; import type { UtilityHeaderType } from '@/components/Utilities/constants'; import type { EpisodeType } from '@/core/types/api/episode'; -import type { SeriesWithMultipleReleasesType } from '@/core/types/api/series'; +import type { ReleaseManagementSeriesType } from '@/core/types/api/series'; -const seriesColumns: UtilityHeaderType[] = [ +const seriesColumns: UtilityHeaderType[] = [ { id: 'series', name: 'Series (AniDB ID)', @@ -57,58 +58,76 @@ const seriesColumns: UtilityHeaderType[] = [ }, ]; -const episodeColumns: UtilityHeaderType[] = [ - { - id: 'episode', - name: 'Episode Name', - className: 'line-clamp-1 grow basis-0 overflow-hidden', - item: episode => ( -
- - {getEpisodePrefix(episode.AniDB?.Type)} - {episode.AniDB?.EpisodeNumber} -  -  - {episode.Name} - -
- ( - {episode.IDs.AniDB} - ) -
- event.stopPropagation()} - > - - +const episodeNameColumn: UtilityHeaderType = { + id: 'episode', + name: 'Episode Name', + className: 'line-clamp-1 grow basis-0 overflow-hidden', + item: episode => ( +
+ + {getEpisodePrefix(episode.AniDB?.Type)} + {episode.AniDB?.EpisodeNumber} +  -  + {episode.Name} + +
+ ( + {episode.IDs.AniDB} + )
- ), + event.stopPropagation()} + > + + +
+ ), +}; + +const multiplesEpisodeFileCountColumn: UtilityHeaderType = { + id: 'file-count', + name: 'File Count', + className: 'w-28', + item: (episode) => { + const count = episode.Files?.length ?? 0; + return ( + <> + {count} + {count === 1 ? ' File' : ' Files'} + + ); }, - { - id: 'file-count', - name: 'File Count', - className: 'w-28', - item: (episode) => { - const count = episode.Files?.length ?? 0; - return ( - <> - {count} - {count === 1 ? ' File' : ' Files'} - - ); - }, +}; + +const duplicatesEpisodeFileCountColumn: UtilityHeaderType = { + id: 'duplicate-count', + name: 'Duplicate Count', + className: 'w-40', + item: (episode) => { + let count = 0; + forEach(episode.Files, (file) => { + if (file.Locations.length > 1) count += 1; + }); + return ( + <> + {count} + {count === 1 ? ' Duplicate' : ' Duplicates'} + + ); }, -]; +}; type Props = { + type: 'multiples' | 'duplicates'; ignoreVariations: boolean; onlyFinishedSeries: boolean; setSelectedEpisode: (episode: EpisodeType) => void; @@ -116,15 +135,16 @@ type Props = { setSeriesCount: (count: number) => void; }; -const MultiplesUtilList = ( - { ignoreVariations, onlyFinishedSeries, setSelectedEpisode, setSelectedSeriesId, setSeriesCount }: Props, +const SeriesList = ( + { ignoreVariations, onlyFinishedSeries, setSelectedEpisode, setSelectedSeriesId, setSeriesCount, type }: Props, ) => { const [selectedSeries, setSelectedSeries] = useState(0); - const seriesQuery = useSeriesWithMultipleReleases({ ignoreVariations, onlyFinishedSeries, pageSize: 25 }); + const seriesQuery = useReleaseManagementSeries(type, { ignoreVariations, onlyFinishedSeries, pageSize: 25 }); const [series, seriesCount] = useFlattenListResult(seriesQuery.data); - const episodesQuery = useSeriesEpisodesWithMultipleReleases( + const episodesQuery = useReleaseManagementSeriesEpisodes( + type, selectedSeries, { ignoreVariations, includeDataFrom: ['AniDB'], includeAbsolutePaths: true, pageSize: 25 }, selectedSeries > 0, @@ -141,6 +161,11 @@ const MultiplesUtilList = ( setSelectedSeries(0); }, [seriesQuery.data]); + const episodeColumns = useMemo(() => [ + episodeNameColumn, + type === 'multiples' ? multiplesEpisodeFileCountColumn : duplicatesEpisodeFileCountColumn, + ], [type]); + return ( <>
@@ -152,7 +177,8 @@ const MultiplesUtilList = ( {!seriesQuery.isPending && seriesCount === 0 && (
- No series with multiple files! + No series with + {type === 'multiples' ? ' multiple releases!' : ' duplicate files!'}
)} @@ -196,4 +222,4 @@ const MultiplesUtilList = ( ); }; -export default MultiplesUtilList; +export default SeriesList; diff --git a/src/components/Utilities/ReleaseManagement/Title.tsx b/src/components/Utilities/ReleaseManagement/Title.tsx index 4300cd9fa..1fdcb7089 100644 --- a/src/components/Utilities/ReleaseManagement/Title.tsx +++ b/src/components/Utilities/ReleaseManagement/Title.tsx @@ -19,8 +19,8 @@ const Title = () => ( Release Management - {/*
|
*/} - {/* */} +
|
+
); diff --git a/src/components/Utilities/constants.tsx b/src/components/Utilities/constants.tsx index 476a8c2cd..4bad515c9 100644 --- a/src/components/Utilities/constants.tsx +++ b/src/components/Utilities/constants.tsx @@ -6,16 +6,16 @@ import { dayjs } from '@/core/util'; import type { EpisodeType } from '@/core/types/api/episode'; import type { FileType } from '@/core/types/api/file'; -import type { SeriesType, SeriesWithMultipleReleasesType } from '@/core/types/api/series'; +import type { ReleaseManagementSeriesType, SeriesType } from '@/core/types/api/series'; -export type UtilityHeaderType = { +export type UtilityHeaderType = { id: string; name: string; className: string; item: (_: T) => React.ReactNode; }; -export type MultipleFileOptionsType = Record; +export type ReleaseManagementOptionsType = Record; export const criteriaMap = { importFolder: FileSortCriteriaEnum.ImportFolderName, diff --git a/src/core/react-query/file/mutations.ts b/src/core/react-query/file/mutations.ts index 90c4894ef..802187c9b 100644 --- a/src/core/react-query/file/mutations.ts +++ b/src/core/react-query/file/mutations.ts @@ -6,6 +6,7 @@ import { axios } from '@/core/axios'; import queryClient, { invalidateQueries } from '@/core/react-query/queryClient'; import type { + DeleteFileLocationRequestType, DeleteFileRequestType, DeleteFilesRequestType, IgnoreFileRequestType, @@ -68,6 +69,11 @@ export const useDeleteFileLinkMutation = () => ), }); +export const useDeleteFileLocationMutation = () => + useMutation({ + mutationFn: ({ locationId }: DeleteFileLocationRequestType) => axios.delete(`File/Location/${locationId}`), + }); + export const useIgnoreFileMutation = () => useMutation({ mutationFn: ({ fileId, ignore }: IgnoreFileRequestType) => diff --git a/src/core/react-query/file/types.ts b/src/core/react-query/file/types.ts index 2e039bfd7..c61d67b3e 100644 --- a/src/core/react-query/file/types.ts +++ b/src/core/react-query/file/types.ts @@ -8,6 +8,12 @@ export type DeleteFileRequestType = { removeFolder: boolean; }; +export type DeleteFileLocationRequestType = { + locationId: number; + deleteFile?: boolean; + deleteFolder?: boolean; +}; + export type IgnoreFileRequestType = { fileId: number; ignore: boolean; diff --git a/src/core/react-query/release-management/queries.ts b/src/core/react-query/release-management/queries.ts index 9d4b6e35e..1ad7de7db 100644 --- a/src/core/react-query/release-management/queries.ts +++ b/src/core/react-query/release-management/queries.ts @@ -3,19 +3,22 @@ import { useInfiniteQuery } from '@tanstack/react-query'; import { axios } from '@/core/axios'; import type { - SeriesEpisodesWithMultipleReleasesType, - SeriesWithMultipleReleasesRequestType, + ReleaseManagementSeriesEpisodesType, + ReleaseManagementSeriesRequestType, } from '@/core/react-query/release-management/types'; import type { ListResultType } from '@/core/types/api'; import type { EpisodeType } from '@/core/types/api/episode'; -import type { SeriesWithMultipleReleasesType } from '@/core/types/api/series'; +import type { ReleaseManagementSeriesType } from '@/core/types/api/series'; -export const useSeriesWithMultipleReleases = (params: SeriesWithMultipleReleasesRequestType) => - useInfiniteQuery>({ - queryKey: ['release-management', 'series', params], +export const useReleaseManagementSeries = ( + type: 'multiples' | 'duplicates', + params: ReleaseManagementSeriesRequestType, +) => + useInfiniteQuery>({ + queryKey: ['release-management', 'series', type, params], queryFn: ({ pageParam }) => axios.get( - 'ReleaseManagement/Series', + `ReleaseManagement/${type === 'multiples' ? 'MultipleReleases' : 'DuplicateFiles'}/Series`, { params: { ...params, @@ -31,16 +34,17 @@ export const useSeriesWithMultipleReleases = (params: SeriesWithMultipleReleases }, }); -export const useSeriesEpisodesWithMultipleReleases = ( +export const useReleaseManagementSeriesEpisodes = ( + type: 'multiples' | 'duplicates', seriesId: number, - params: SeriesEpisodesWithMultipleReleasesType, + params: ReleaseManagementSeriesEpisodesType, enabled = true, ) => useInfiniteQuery>({ - queryKey: ['release-management', 'series', 'episodes', seriesId, params], + queryKey: ['release-management', 'series', 'episodes', type, seriesId, params], queryFn: ({ pageParam }) => axios.get( - `ReleaseManagement/Series/${seriesId}`, + `ReleaseManagement/${type === 'multiples' ? 'MultipleReleases' : 'DuplicateFiles'}/Series/${seriesId}/Episodes`, { params: { ...params, diff --git a/src/core/react-query/release-management/types.ts b/src/core/react-query/release-management/types.ts index 262b71e92..17b4575e6 100644 --- a/src/core/react-query/release-management/types.ts +++ b/src/core/react-query/release-management/types.ts @@ -1,13 +1,13 @@ import type { PaginationType } from '@/core/types/api'; import type { DataSourceType } from '@/core/types/api/common'; -export type SeriesWithMultipleReleasesRequestType = { +export type ReleaseManagementSeriesRequestType = { ignoreVariations?: boolean; includeDataFrom?: DataSourceType[]; onlyFinishedSeries?: boolean; } & PaginationType; -export type SeriesEpisodesWithMultipleReleasesType = { +export type ReleaseManagementSeriesEpisodesType = { includeDataFrom?: DataSourceType[]; includeFiles?: boolean; includeMediaInfo?: boolean; diff --git a/src/core/router/index.tsx b/src/core/router/index.tsx index 0cc0a0c53..d9db4e36e 100644 --- a/src/core/router/index.tsx +++ b/src/core/router/index.tsx @@ -41,7 +41,7 @@ import MetadataSitesSettings from '@/pages/settings/tabs/MetadataSitesSettings'; import UserManagementSettings from '@/pages/settings/tabs/UserManagementSettings'; import UnsupportedPage from '@/pages/unsupported/UnsupportedPage'; import FileSearch from '@/pages/utilities/FileSearch'; -import MultiplesUtil from '@/pages/utilities/ReleaseManagementUtilityTabs/MultiplesUtil'; +import ReleaseManagement from '@/pages/utilities/ReleaseManagement'; import Renamer from '@/pages/utilities/Renamer'; import SeriesWithoutFilesUtility from '@/pages/utilities/SeriesWithoutFilesUtility'; import IgnoredFilesTab from '@/pages/utilities/UnrecognizedUtilityTabs/IgnoredFilesTab'; @@ -91,7 +91,8 @@ const router = sentryCreateBrowserRouter( } /> } /> } /> - } /> + } /> + } /> } /> } /> } /> diff --git a/src/core/types/api/file.ts b/src/core/types/api/file.ts index 6676d853f..0acf23146 100644 --- a/src/core/types/api/file.ts +++ b/src/core/types/api/file.ts @@ -9,6 +9,8 @@ type XRefsType = { }; type FileTypeLocation = { + ID: number; + FileID: number; ImportFolderID: number; RelativePath: string; AbsolutePath?: string; diff --git a/src/core/types/api/series.ts b/src/core/types/api/series.ts index acde6fff3..243590d7d 100644 --- a/src/core/types/api/series.ts +++ b/src/core/types/api/series.ts @@ -19,7 +19,7 @@ export type SeriesType = { }; }; -export type SeriesWithMultipleReleasesType = { +export type ReleaseManagementSeriesType = { EpisodeCount: number; } & SeriesType; diff --git a/src/pages/collection/Collection.tsx b/src/pages/collection/Collection.tsx index 2b1b29ca3..28b8172d8 100644 --- a/src/pages/collection/Collection.tsx +++ b/src/pages/collection/Collection.tsx @@ -219,57 +219,60 @@ function Collection() { }); return ( -
-
- - -
-
- -
+ {`${isSeries ? groupQuery?.data?.Name : 'Collection'} | Shoko`} +
+
+ + +
+
+ +
+ +
+ {isSeries && !showFilterSidebar && ( + )} - > -
- {isSeries && !showFilterSidebar && ( - - )} + +
- - -
+ ); } diff --git a/src/pages/collection/Series.tsx b/src/pages/collection/Series.tsx index b1322bff0..b6228cbb7 100644 --- a/src/pages/collection/Series.tsx +++ b/src/pages/collection/Series.tsx @@ -155,7 +155,7 @@ const Series = () => { - +
{ - const { seriesId } = useParams(); + const { series } = useOutletContext(); const { isPending: pendingRefreshAniDb, mutate: refreshAniDbMutation } = useRefreshSeriesAniDBInfoMutation(); const refreshAniDb = useEventCallback(() => { - refreshAniDbMutation({ seriesId: toNumber(seriesId), force: true }, { + refreshAniDbMutation({ seriesId: series.IDs.ID, force: true }, { onSuccess: () => toast.success('AniDB refresh queued!'), }); }); @@ -61,7 +61,7 @@ const SeriesCredits = () => { setSearch(event.target.value); }); - const cast = useSeriesCastQuery(toNumber(seriesId!), !!seriesId).data; + const cast = useSeriesCastQuery(series.IDs.ID).data; const castByType = useMemo(() => ({ Character: cast?.filter(credit => credit.RoleName === 'Seiyuu') ?? [], Staff: cast?.filter(credit => credit.RoleName !== 'Seiyuu') ?? [], @@ -84,47 +84,48 @@ const SeriesCredits = () => { return 0; })), [castByType, mode, search, roleFilter]); - if (!seriesId) return null; - return ( -
-
- -
+ <> + {`${series.Name} > Credits | Shoko`} +
+
+ +
-
-
-
- Credits |  - {(search !== '' || roleFilter.size > 0) && ( - <> - - {filteredCast.length} - -  of  - - )} - - {castByType[mode].length ?? 0} - -   - {mode === 'Character' ? 'Characters' : mode} -  Listed +
+
+
+ Credits |  + {(search !== '' || roleFilter.size > 0) && ( + <> + + {filteredCast.length} + +  of  + + )} + + {castByType[mode].length ?? 0} + +   + {mode === 'Character' ? 'Characters' : mode} +  Listed +
+
- +
-
-
+ ); }; diff --git a/src/pages/collection/series/SeriesEpisodes.tsx b/src/pages/collection/series/SeriesEpisodes.tsx index 134475715..ae76ac647 100644 --- a/src/pages/collection/series/SeriesEpisodes.tsx +++ b/src/pages/collection/series/SeriesEpisodes.tsx @@ -1,10 +1,9 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { useParams } from 'react-router'; import { useOutletContext, useSearchParams } from 'react-router-dom'; import { mdiCloseCircleOutline, mdiEyeOutline, mdiLoading } from '@mdi/js'; import { Icon } from '@mdi/react'; import { useVirtualizer } from '@tanstack/react-virtual'; -import { debounce, toNumber } from 'lodash'; +import { debounce } from 'lodash'; import { useDebounceValue } from 'usehooks-ts'; import EpisodeSearchAndFilterPanel from '@/components/Collection/Episode/EpisodeSearchAndFilterPanel'; @@ -13,7 +12,7 @@ import EpisodeWatchModal from '@/components/Collection/Episode/EpisodeWatchModal import Button from '@/components/Input/Button'; import toast from '@/components/Toast'; import { useWatchSeriesEpisodesMutation } from '@/core/react-query/series/mutations'; -import { useSeriesEpisodesInfiniteQuery, useSeriesQuery } from '@/core/react-query/series/queries'; +import { useSeriesEpisodesInfiniteQuery } from '@/core/react-query/series/queries'; import { IncludeOnlyFilterEnum } from '@/core/react-query/series/types'; import { EpisodeTypeEnum } from '@/core/types/api/episode'; import { dayjs } from '@/core/util'; @@ -34,7 +33,8 @@ type FilterOptionsType = { }; const SeriesEpisodes = () => { - const { seriesId } = useParams(); + const { series } = useOutletContext(); + const [searchParams, setSearchParams] = useSearchParams(); const [showOptionsModal, setShowOptionsModal] = useState(false); @@ -71,15 +71,13 @@ const SeriesEpisodes = () => { setSelectedEpisodes(new Set()); }, [filterOptions]); - const seriesQueryData = useSeriesQuery(toNumber(seriesId!), { includeDataFrom: ['AniDB', 'TMDB'] }, !!seriesId).data; const seriesEpisodesQuery = useSeriesEpisodesInfiniteQuery( - toNumber(seriesId!), + series.IDs.ID, { pageSize, includeDataFrom: ['AniDB'], ...filterOptions, }, - !!seriesId, ); const { data, @@ -92,20 +90,18 @@ const SeriesEpisodes = () => { const { mutate: watchEpisode } = useWatchSeriesEpisodesMutation(); - const anidbSeriesId = useMemo(() => seriesQueryData?.IDs.AniDB ?? 0, [seriesQueryData]); - const hasMissingEpisodes = useMemo( - () => ((seriesQueryData?.Sizes.Missing.Episodes ?? 0) > 0), - [seriesQueryData?.Sizes], + () => ((series.Sizes.Missing.Episodes ?? 0) > 0), + [series.Sizes], ); const startDate = useMemo( - () => (seriesQueryData?.AniDB?.AirDate != null ? dayjs(seriesQueryData?.AniDB?.AirDate) : null), - [seriesQueryData], + () => (series.AniDB?.AirDate != null ? dayjs(series.AniDB?.AirDate) : null), + [series], ); const endDate = useMemo( - () => (seriesQueryData?.AniDB?.EndDate != null ? dayjs(seriesQueryData?.AniDB?.EndDate) : null), - [seriesQueryData], + () => (series.AniDB?.EndDate != null ? dayjs(series.AniDB?.EndDate) : null), + [series], ); const hasUnairedEpisodes = useMemo( () => (!!startDate && (endDate === null || endDate.isAfter(dayjs()))), @@ -133,7 +129,7 @@ const SeriesEpisodes = () => { const handleMarkWatched = useEventCallback((watched: boolean) => { watchEpisode({ - seriesId: toNumber(seriesId), + seriesId: series.IDs.ID, value: watched, ...filterOptions, }, { @@ -150,105 +146,108 @@ const SeriesEpisodes = () => { const openOptionsModal = useEventCallback(() => setShowOptionsModal(true)); return ( -
-