From 7207d7a458e5b2f29e48712e7382ea8cdb30c64f Mon Sep 17 00:00:00 2001 From: Robonau <30987265+Robonau@users.noreply.github> Date: Sat, 16 Nov 2024 04:02:13 +0000 Subject: [PATCH 1/2] woops missed an r --- versionToServerVersionMapping.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versionToServerVersionMapping.json b/versionToServerVersionMapping.json index 9bf75a5..a5c1316 100644 --- a/versionToServerVersionMapping.json +++ b/versionToServerVersionMapping.json @@ -5,7 +5,7 @@ }, { "tag": "v1.1.0", - "uiVersion": "1153", + "uiVersion": "r1153", "serverVersion": "r1502", "comment": "the server version is between 1.0.0 and 1.1.0 release", "comment2": "because its the preview version that implemented the breaking changes" From 99a6dea053343d036cd17b807df06edd81da809a Mon Sep 17 00:00:00 2001 From: Robonau <30987265+Robonau@users.noreply.github> Date: Sat, 16 Nov 2024 11:41:03 +0000 Subject: [PATCH 2/2] update mangas categories change + fix lightswitch warping --- src/lib/components/lightswitch.svelte | 10 +- src/lib/gql/Fragments.ts | 3 + src/lib/gql/Mutations.ts | 34 +- src/lib/gql/Queries.ts | 41 +-- src/lib/gql/graphqlClient.ts | 306 ++++-------------- src/lib/simpleStores.svelte.ts | 9 +- src/lib/util.svelte.ts | 9 + .../(library)/LibraryMassCategoryModal.svelte | 60 ++-- .../manga/[MangaID]/migrateModal.svelte | 8 +- .../(manga)/MangaCatagoryModal.svelte | 6 +- .../[MangaID]/(manga)/TrackingModal.svelte | 2 - src/routes/(app)/settings/+page.svelte | 4 +- 12 files changed, 141 insertions(+), 351 deletions(-) diff --git a/src/lib/components/lightswitch.svelte b/src/lib/components/lightswitch.svelte index 279a4e2..72cc6fc 100644 --- a/src/lib/components/lightswitch.svelte +++ b/src/lib/components/lightswitch.svelte @@ -21,7 +21,7 @@ height?: CssClasses; ring?: CssClasses; rounded?: CssClasses; - class?: CssClasses; + [key: string]: unknown; } let { @@ -29,11 +29,11 @@ bgDark = 'bg-surface-900', fillLight = 'fill-surface-50', fillDark = 'fill-surface-900', - width = 'w-12', - height = 'h-6', + width = 'w-16', + height = 'h-8', ring = 'ring-[1px] ring-surface-500/30', rounded = 'rounded-token', - class: className + ...rest }: Props = $props(); const cTransition = `transition-all duration-[200ms]`; @@ -49,7 +49,7 @@ let thumbPosition = $derived(!gmState.value.dark ? 'translate-x-[100%]' : ''); // Reactive let classesTrack = $derived( - `cursor-pointer ${cTransition} ${width} ${height} ${ring} ${rounded} ${trackBg} ${className ?? ''}` + `cursor-pointer ${cTransition} ${width} ${height} ${ring} ${rounded} ${trackBg} ${rest.class ?? ''}` ); let classesThumb = $derived( `aspect-square scale-[0.8] flex justify-center items-center ${cTransition} ${height} ${rounded} ${thumbBg} ${thumbPosition}` diff --git a/src/lib/gql/Fragments.ts b/src/lib/gql/Fragments.ts index 7cafd50..d80ad89 100644 --- a/src/lib/gql/Fragments.ts +++ b/src/lib/gql/Fragments.ts @@ -61,6 +61,9 @@ export const MangaTypeFragment = graphql( fetchedAt id } + chapters { + totalCount + } latestUploadedChapter { uploadDate id diff --git a/src/lib/gql/Mutations.ts b/src/lib/gql/Mutations.ts index 922959c..b309d00 100644 --- a/src/lib/gql/Mutations.ts +++ b/src/lib/gql/Mutations.ts @@ -485,41 +485,19 @@ export const updateMangasCategories = graphql( $addTo: [Int!] = null $clear: Boolean = null $id: [Int!]! + $removeFrom: [Int!] = null ) { updateMangasCategories( input: { ids: $id - patch: { addToCategories: $addTo, clearCategories: $clear } - } - ) { - mangas { - id - categories { - nodes { - id - } + patch: { + addToCategories: $addTo + clearCategories: $clear + removeFromCategories: $removeFrom } } - } - } - `, - [] -); - -export const updateMangaCategories = graphql( - ` - mutation updateMangaCategories( - $addTo: [Int!] = null - $clear: Boolean = null - $id: Int! - ) { - updateMangaCategories( - input: { - id: $id - patch: { addToCategories: $addTo, clearCategories: $clear } - } ) { - manga { + mangas { id categories { nodes { diff --git a/src/lib/gql/Queries.ts b/src/lib/gql/Queries.ts index e77d37c..a50d3bf 100644 --- a/src/lib/gql/Queries.ts +++ b/src/lib/gql/Queries.ts @@ -11,8 +11,7 @@ import { MangaTypeFragment, PreferenceFragment, SourceTypeFragment, - TrackerTypeFragment, - TrackRecordTypeFragment + TrackerTypeFragment } from './Fragments'; import { graphql } from './graphql'; @@ -36,47 +35,13 @@ export const getCategory = graphql( id mangas { nodes { - id - title - inLibrary - thumbnailUrl - unreadCount - downloadCount - latestFetchedChapter { - fetchedAt - id - } - latestUploadedChapter { - uploadDate - id - } - lastReadChapter { - lastReadAt - id - } - chapters { - totalCount - } - artist - author - description - genre - status - source { - displayName - id - } - trackRecords { - nodes { - ...TrackRecordTypeFragment - } - } + ...MangaTypeFragment } } } } `, - [TrackRecordTypeFragment] + [MangaTypeFragment] ); export const getManga = graphql( diff --git a/src/lib/gql/graphqlClient.ts b/src/lib/gql/graphqlClient.ts index de90609..838c7a9 100644 --- a/src/lib/gql/graphqlClient.ts +++ b/src/lib/gql/graphqlClient.ts @@ -38,7 +38,6 @@ import type { trackProgress, unbindTrack, updateExtension, - updateMangaCategories, updateMangas, updateMangasCategories, updateTrack @@ -183,13 +182,6 @@ export const client = new Client({ >; deleteMangaMetaUpdater(res, variables, cache); }, - updateMangaCategories(result, _, cache, info) { - const res = result as ResultOf; - const variables = info.variables as VariablesOf< - typeof updateMangaCategories - >; - updateMangaCategoriesUpdater(res, variables, cache); - }, updateMangas(result, _, cache, info) { const res = result as ResultOf; const variables = info.variables as VariablesOf< @@ -393,126 +385,6 @@ function getSingleChapterUpdater( }); } -function updateMangaCategoriesUpdater( - data: ResultOf | undefined, - vars: VariablesOf, - cache: Cache -) { - if (!data?.updateMangaCategories?.manga.categories.nodes) return; - const nodes = data.updateMangaCategories.manga.categories.nodes; - // update this mangas categories - try { - const manga = cache.readFragment(MangaTypeFragment, { - id: vars.id - } as ResultOf); - if (!manga) throw new Error('Manga not found in cache'); - manga.categories.nodes = nodes; - cache.writeFragment(MangaTypeFragment, manga, { id: vars.id }); - } catch {} - - // update the categories in library - const dat = cache.readQuery({ - query: getManga, - variables: { id: vars.id } - }); - if (!dat) return; - const oldNodes = dat.manga?.categories.nodes; - if (!oldNodes) return; - try { - const currentManga: ResultOf< - typeof getCategory - >['category']['mangas']['nodes'][0] = { - id: vars.id, - title: dat.manga.title, - inLibrary: dat.manga.inLibrary ?? true, - thumbnailUrl: dat.manga.thumbnailUrl, - unreadCount: dat.manga.unreadCount ?? 0, - downloadCount: dat.manga.downloadCount ?? 0, - latestFetchedChapter: dat.manga.latestFetchedChapter, - lastReadChapter: dat.manga.lastReadChapter, - latestUploadedChapter: dat.manga.latestUploadedChapter, - trackRecords: dat.manga.trackRecords, - source: dat.manga.source, - status: dat.manga.status, - genre: dat.manga.genre, - description: dat.manga.description, - author: dat.manga.author, - artist: dat.manga.artist, - chapters: dat.manga.chapters ?? { - totalCount: 0 - } - }; - // add to categories that now have it - nodes.forEach((newNode) => { - if (oldNodes.find((oldNode) => oldNode.id === newNode.id)) return; - try { - cache.updateQuery( - { - query: getCategory, - variables: { id: newNode.id } - }, - (Category) => { - if (!Category) return Category; - Category.category.mangas.nodes.push(currentManga); - return Category; - } - ); - } catch {} - }); - // add to 0 if now in default - if (nodes.length === 0 && oldNodes.length > 0) { - try { - cache.updateQuery( - { - query: getCategory, - variables: { id: 0 } - }, - (Category) => { - if (!Category) return Category; - Category.category.mangas.nodes.push(currentManga); - return Category; - } - ); - } catch {} - } - } catch {} - //remove from categories that no longer have it - oldNodes.forEach((oldNode) => { - if (nodes.find((newNode) => oldNode.id === newNode.id)) return; - try { - cache.updateQuery( - { - query: getCategory, - variables: { id: oldNode.id } - }, - (Category) => { - if (!Category) return Category; - Category.category.mangas.nodes = - Category.category.mangas.nodes.filter((e) => e.id !== vars.id); - return Category; - } - ); - } catch {} - }); - // remove from 0 if no longer in default - if (oldNodes.length === 0 && nodes.length > 0) { - try { - cache.updateQuery( - { - query: getCategory, - variables: { id: 0 } - }, - (Category) => { - if (!Category) return Category; - Category.category.mangas.nodes = - Category.category.mangas.nodes.filter((e) => e.id !== vars.id); - return Category; - } - ); - } catch {} - } -} - function deleteMangaMetaUpdater( data: ResultOf | undefined, vars: VariablesOf, @@ -655,33 +527,9 @@ function fetchMangaInfoUpdater( ) { if (!data?.fetchManga) return; const fetchManga = data.fetchManga; - cache.updateQuery( - { - query: getManga, - variables: { - id: vars.id - } - }, - (manga) => { - if (!manga?.manga) - return { - manga: { - __typename: 'MangaType', - chapters: { - __typename: 'ChapterNodeList', - nodes: [], - totalCount: 0 - }, - ...fetchManga.manga - } - }; - manga.manga = { - ...manga.manga, - ...fetchManga.manga - }; - return manga; - } - ); + cache.writeFragment(MangaTypeFragment, fetchManga.manga, { + id: vars.id + }); } function bindTrackUpdater( @@ -800,99 +648,83 @@ function updateMangasCategoriesUpdater( ) { if (!variables.addTo || !data?.updateMangasCategories) return; const mangaIds = data.updateMangasCategories.mangas.map((manga) => manga.id); - const defaultCategory = variables.addTo?.length === 0 ? [0] : variables.addTo; mangaIds.forEach((id) => { - try { - const oldData = cache.readQuery({ - query: getManga, - variables: { id } - }); - if (!oldData) throw new Error(); - const manga = oldData.manga; - manga.categories.nodes = - variables.addTo?.map((categoryId) => ({ + cache.updateQuery({ query: getManga, variables: { id } }, (manga) => { + if (!manga) return manga; + manga.manga.categories.nodes = manga.manga.categories.nodes.filter( + (ee) => !variables.removeFrom?.includes(ee.id) + ); + variables.addTo?.forEach((categoryId) => { + if (manga.manga.categories.nodes.find((ee) => ee.id === categoryId)) + return; + manga.manga.categories.nodes.push({ id: categoryId - })) ?? manga.categories.nodes; - cache.writeFragment(MangaTypeFragment, manga, { - id: manga.id + }); }); - } catch {} - }); - - const currentCategoryId = parseInt( - new URLSearchParams(window.location.search).get('tab') ?? '0' - ); - const currentCategoryData = cache.readQuery({ - query: getCategory, - variables: { id: currentCategoryId } + return manga; + }); }); - if (!currentCategoryData) return; - const mangas = currentCategoryData.category.mangas.nodes.filter((manga) => - mangaIds.includes(manga.id) - ); const categories = cache.readQuery({ query: getCategories }); - categories?.categories.nodes.forEach((frag) => { - const category = frag; - try { - const oldCategoryData = cache.readQuery({ - query: getCategory, - variables: { id: category.id } + if (!categories) return; + categories.categories.nodes.forEach((category) => { + const mangas = variables.id + .map((id) => { + const manga = cache.readFragment(MangaTypeFragment, { + id + } as ResultOf); + return manga; + }) + .filter((manga) => manga !== null); + + mangas.forEach((manga) => { + const addto = variables.addTo ?? []; + + if (manga.categories.nodes.length === 0) { + addto.push(0); + } + + addto.forEach((cat) => { + cache.updateQuery( + { + query: getCategory, + variables: { id: cat } + }, + (data) => { + if (!data) return data; + data.category.mangas.nodes = data.category.mangas.nodes.filter( + (e) => e.id !== manga.id + ); + data.category.mangas.nodes.push(manga); + return data; + } + ); }); - if (!oldCategoryData) return; - if (defaultCategory.includes(category.id)) { - const mangasToAdd: ResultOf< - typeof getCategory - >['category']['mangas']['nodes'] = []; - mangas.forEach((manga) => { - if ( - !oldCategoryData.category.mangas.nodes.find( - (m) => m.id === manga.id - ) - ) { - mangasToAdd.push(manga); + + if ( + variables.removeFrom?.includes(category.id) || + (category.id === 0 && manga.categories.nodes.length !== 0) || + (variables.clear && + (!manga.categories.nodes.find((e) => e.id === category.id) || + (manga.categories.nodes.length === 0 && category.id === 0))) + ) { + cache.updateQuery( + { + query: getCategory, + variables: { id: category.id } + }, + (data) => { + if (!data) return data; + data.category.mangas.nodes = data.category.mangas.nodes.filter( + (e) => e.id !== manga.id + ); + return data; } - }); - oldCategoryData.category.mangas.nodes.push(...mangasToAdd); - } else { - oldCategoryData.category.mangas.nodes = - oldCategoryData.category.mangas.nodes.filter( - (m) => !mangaIds.includes(m.id) - ); + ); } - cache.updateQuery( - { - query: getCategory, - variables: { id: category.id } - }, - (oldCategoryData) => { - if (!oldCategoryData) return oldCategoryData; - if (defaultCategory.includes(category.id)) { - const mangasToAdd: ResultOf< - typeof getCategory - >['category']['mangas']['nodes'] = []; - mangas.forEach((manga) => { - if ( - !oldCategoryData.category.mangas.nodes.find( - (m) => m.id === manga.id - ) - ) { - mangasToAdd.push(manga); - } - }); - oldCategoryData.category.mangas.nodes.push(...mangasToAdd); - } else { - oldCategoryData.category.mangas.nodes = - oldCategoryData.category.mangas.nodes.filter( - (m) => !mangaIds.includes(m.id) - ); - } - return oldCategoryData; - } - ); - } catch {} + }); }); } diff --git a/src/lib/simpleStores.svelte.ts b/src/lib/simpleStores.svelte.ts index 003484e..f68916a 100644 --- a/src/lib/simpleStores.svelte.ts +++ b/src/lib/simpleStores.svelte.ts @@ -24,17 +24,10 @@ import { import { getManga, metas } from './gql/Queries'; import { client } from './gql/graphqlClient'; import type { presetConst } from './presets'; -import type { TriState } from './util.svelte'; +import { getObjectKeys, type TriState } from './util.svelte'; import { browser } from '$app/environment'; import { untrack } from 'svelte'; -// function getObjectEntries(obj: T): [keyof T, T[keyof T]][] { -// return Object.entries(obj) as [keyof T, T[keyof T]][]; -// } -function getObjectKeys(obj: T): (keyof T)[] { - return Object.keys(obj) as (keyof T)[]; -} - export const toastStore = writable(null); type Themes = (typeof presetConst)[number]['name']; diff --git a/src/lib/util.svelte.ts b/src/lib/util.svelte.ts index c2299d5..ee0d7ea 100644 --- a/src/lib/util.svelte.ts +++ b/src/lib/util.svelte.ts @@ -38,6 +38,15 @@ export type OperationResultF< fetching: boolean; }; +export function getObjectEntries( + obj: T +): [string, T[keyof T]][] { + return Object.entries(obj) as [string, T[keyof T]][]; +} +export function getObjectKeys(obj: T): (keyof T)[] { + return Object.keys(obj) as (keyof T)[]; +} + export function HelpDoSelect( update: T, e: MouseEvent & { currentTarget: EventTarget & HTMLAnchorElement }, diff --git a/src/routes/(app)/(library)/LibraryMassCategoryModal.svelte b/src/routes/(app)/(library)/LibraryMassCategoryModal.svelte index 6661e5e..8bf496f 100644 --- a/src/routes/(app)/(library)/LibraryMassCategoryModal.svelte +++ b/src/routes/(app)/(library)/LibraryMassCategoryModal.svelte @@ -8,36 +8,53 @@