From 87df758156dd26f9e46634b0c1be79d60c0c224e Mon Sep 17 00:00:00 2001 From: neopostmodern Date: Sat, 6 May 2023 21:56:28 +0200 Subject: [PATCH] fix(client): remove unshared tag from cached notes - rename `removeNoteFromCache` to `removeEntityFromCache` --- .../components/TagWithContextMenu.tsx | 4 +- client/src/renderer/generated/graphql.ts | 47 +++++++++++++++++++ client/src/renderer/hooks/useDeleteNote.tsx | 4 +- .../renderer/hooks/useEntitiesUpdatedSince.ts | 40 ++++++++++++++++ client/src/renderer/utils/cache.ts | 6 +-- 5 files changed, 94 insertions(+), 7 deletions(-) diff --git a/client/src/renderer/components/TagWithContextMenu.tsx b/client/src/renderer/components/TagWithContextMenu.tsx index 693938f..279d925 100644 --- a/client/src/renderer/components/TagWithContextMenu.tsx +++ b/client/src/renderer/components/TagWithContextMenu.tsx @@ -10,7 +10,7 @@ import { } from '../generated/graphql'; import { hasPermission } from '../hooks/useHasPermission'; import useUserId from '../hooks/useUserId'; -import { removeNoteFromCache } from '../utils/cache'; +import { removeEntityFromCache } from '../utils/cache'; import { DisplayOnlyTag } from '../utils/types'; import ErrorSnackbar from './ErrorSnackbar'; import Tag from './Tag'; @@ -47,7 +47,7 @@ const TagWithContextMenu = ({ } if (!hasPermission(userId, data.removeTagByIdFromNote, 'notes', 'read')) { - removeNoteFromCache(cache, data.removeTagByIdFromNote); + removeEntityFromCache(cache, data.removeTagByIdFromNote); if (location.href.includes(data.removeTagByIdFromNote._id)) { dispatch(goBack()); } diff --git a/client/src/renderer/generated/graphql.ts b/client/src/renderer/generated/graphql.ts index ec1db64..30fae24 100644 --- a/client/src/renderer/generated/graphql.ts +++ b/client/src/renderer/generated/graphql.ts @@ -522,6 +522,13 @@ export type UpdatedNotesCacheQueryQueryVariables = Exact<{ [key: string]: never; export type UpdatedNotesCacheQueryQuery = { __typename: 'Query', notes: Array<{ __typename: 'Link', _id: string, name: string, createdAt: any, updatedAt: any, archivedAt?: any | null, deletedAt?: any | null, description: string, url: string, domain: string, tags: Array<{ __typename: 'Tag', _id: string }>, user: { __typename: 'User', _id: string, name: string } } | { __typename: 'Text', _id: string, name: string, createdAt: any, updatedAt: any, archivedAt?: any | null, deletedAt?: any | null, description: string, tags: Array<{ __typename: 'Tag', _id: string }>, user: { __typename: 'User', _id: string, name: string } }> }; +export type TagWithNoteIdsQueryVariables = Exact<{ + tagId: Scalars['ID']; +}>; + + +export type TagWithNoteIdsQuery = { __typename: 'Query', tag: { __typename: 'Tag', _id: string, notes?: Array<{ __typename: 'Link', _id: string } | { __typename: 'Text', _id: string } | null> | null } }; + export type ToggleArchivedNoteMutationVariables = Exact<{ noteId: Scalars['ID']; }>; @@ -1711,6 +1718,46 @@ export function useUpdatedNotesCacheQueryLazyQuery(baseOptions?: Apollo.LazyQuer export type UpdatedNotesCacheQueryQueryHookResult = ReturnType; export type UpdatedNotesCacheQueryLazyQueryHookResult = ReturnType; export type UpdatedNotesCacheQueryQueryResult = Apollo.QueryResult; +export const TagWithNoteIdsDocument = gql` + query TagWithNoteIds($tagId: ID!) { + tag(tagId: $tagId) { + _id + notes { + ... on INote { + _id + } + } + } +} + `; + +/** + * __useTagWithNoteIdsQuery__ + * + * To run a query within a React component, call `useTagWithNoteIdsQuery` and pass it any options that fit your needs. + * When your component renders, `useTagWithNoteIdsQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useTagWithNoteIdsQuery({ + * variables: { + * tagId: // value for 'tagId' + * }, + * }); + */ +export function useTagWithNoteIdsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(TagWithNoteIdsDocument, options); + } +export function useTagWithNoteIdsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(TagWithNoteIdsDocument, options); + } +export type TagWithNoteIdsQueryHookResult = ReturnType; +export type TagWithNoteIdsLazyQueryHookResult = ReturnType; +export type TagWithNoteIdsQueryResult = Apollo.QueryResult; export const ToggleArchivedNoteDocument = gql` mutation ToggleArchivedNote($noteId: ID!) { toggleArchivedNote(noteId: $noteId) { diff --git a/client/src/renderer/hooks/useDeleteNote.tsx b/client/src/renderer/hooks/useDeleteNote.tsx index c554578..dedc6c4 100644 --- a/client/src/renderer/hooks/useDeleteNote.tsx +++ b/client/src/renderer/hooks/useDeleteNote.tsx @@ -6,7 +6,7 @@ import { ToggleDeletedNoteMutation, ToggleDeletedNoteMutationVariables, } from '../generated/graphql'; -import { removeNoteFromCache } from '../utils/cache'; +import { removeEntityFromCache } from '../utils/cache'; const TOGGLE_DELETED_NOTE_MUTATION = gql` mutation ToggleDeletedNote($noteId: ID!) { @@ -36,7 +36,7 @@ const useDeleteNote = (note: { _id: string }) => { throw Error("[useDeletedLink.update] Can't handle un-delete yet."); } - removeNoteFromCache(cache, data.toggleDeletedNote); + removeEntityFromCache(cache, data.toggleDeletedNote); }, }); diff --git a/client/src/renderer/hooks/useEntitiesUpdatedSince.ts b/client/src/renderer/hooks/useEntitiesUpdatedSince.ts index ea484ef..323b35e 100644 --- a/client/src/renderer/hooks/useEntitiesUpdatedSince.ts +++ b/client/src/renderer/hooks/useEntitiesUpdatedSince.ts @@ -12,7 +12,10 @@ import { EntitiesUpdatedSinceQueryVariables, NotesForListQuery, TagsQuery, + TagWithNoteIdsQuery, + TagWithNoteIdsQueryVariables, } from '../generated/graphql'; +import { removeEntityFromCache } from '../utils/cache'; import { BASE_NOTE_FRAGMENT, BASE_TAG_FRAGMENT, @@ -173,6 +176,43 @@ const useEntitiesUpdatedSince = () => { }); if (entitiesUpdatedSince.removedTagIds.length) { + entitiesUpdatedSince.removedTagIds.forEach((tagId) => { + const tagQuery = cache.readQuery< + TagWithNoteIdsQuery, + TagWithNoteIdsQueryVariables + >({ + query: gql` + query TagWithNoteIds($tagId: ID!) { + tag(tagId: $tagId) { + _id + notes { + ... on INote { + _id + } + } + } + } + `, + variables: { tagId }, + }); + if (!tagQuery?.tag) { + return; + } + const { tag } = tagQuery; + tag.notes?.forEach((note) => { + cache.modify({ + id: cache.identify(note!), + fields: { + tags(currentTagsOnNote: Array<{ __ref: string }> = []) { + return currentTagsOnNote.filter( + ({ __ref }) => __ref.split(':')[1] !== tagId + ); + }, + }, + }); + }); + removeEntityFromCache(cache, tag); + }); cachedTags = cachedTags.filter( ({ _id }) => !entitiesUpdatedSince.removedTagIds.includes(_id) ); diff --git a/client/src/renderer/utils/cache.ts b/client/src/renderer/utils/cache.ts index ee701a8..0f6f3bc 100644 --- a/client/src/renderer/utils/cache.ts +++ b/client/src/renderer/utils/cache.ts @@ -7,11 +7,11 @@ export const clearApolloCache = () => { cachePersistor.purge(); }; -export const removeNoteFromCache = ( +export const removeEntityFromCache = ( cache: ApolloCache, - note: { _id: string; __typename: string } + entity: { _id: string; __typename: string } ): void => { - const normalizedId = cache.identify(note); + const normalizedId = cache.identify(entity); cache.evict({ id: normalizedId }); cache.gc(); // https://stackoverflow.com/questions/63192774/apollo-client-delete-item-from-cache#comment121727251_66713628 return;