From f2c9ec04b8900fe41a2e4b84138cedc44c727879 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Thu, 25 Jan 2024 12:11:04 +0100 Subject: [PATCH] Add delete mutation, flesh out update mutation for highlights --- client/src/__generated__/gql.ts | 19 ++++- client/src/__generated__/graphql.ts | 77 ++++++++++++++--- .../content-blocks/ContentComponent.vue | 82 +++++++++++++++++-- .../highlights/HighlightPopover.vue | 4 +- .../highlights/HighlightSidebar.vue | 19 ++++- .../gql/fragments/contentBlockParts.gql | 2 +- .../graphql/gql/fragments/highlightParts.gql | 10 ++- client/src/helpers/highlight-sidebar.ts | 3 +- client/src/helpers/popover.ts | 8 +- .../notes/migrations/0006_highlight_note.py | 20 +++++ server/notes/models.py | 1 + server/notes/mutations.py | 62 +++++++++++++- server/schema.graphql | 28 ++++++- 13 files changed, 302 insertions(+), 33 deletions(-) create mode 100644 server/notes/migrations/0006_highlight_note.py diff --git a/client/src/__generated__/gql.ts b/client/src/__generated__/gql.ts index ce01b74a..273b2e7e 100644 --- a/client/src/__generated__/gql.ts +++ b/client/src/__generated__/gql.ts @@ -13,12 +13,15 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n text\n color\n }\n": types.HighlightPartsFragmentDoc, + "\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n note {\n text\n }\n color\n contentBlock {\n id\n }\n }\n": types.HighlightPartsFragmentDoc, "\n fragment ContentBlockHighlightsFragment on ContentBlockNode {\n id\n __typename\n highlights {\n ...HighlightParts\n }\n }\n": types.ContentBlockHighlightsFragmentFragmentDoc, "\n mutation AddHighlight($input: AddHighlightInput!) {\n addHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n ": types.AddHighlightDocument, "\n query LanguageQuery {\n me {\n language @client\n }\n }\n ": types.LanguageQueryDocument, "\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n ": types.SetLanguageDocument, "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n ": types.ReadOnlyQueryDocument, + "\n mutation UpdateHighlight($input: UpdateHighlightInput!) {\n updateHighlight(input: $input) {\n highlight {\n ...HighlightParts\n }\n }\n }\n ": types.UpdateHighlightDocument, + "\n mutation DeleteHighlight($input: DeleteHighlightInput!) {\n deleteHighlight(input: $input) {\n success\n }\n }\n ": types.DeleteHighlightDocument, + "\n fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode {\n highlights {\n id\n }\n }\n ": types.ContentBlockHighlightsWithIdOnlyFragmentFragmentDoc, "\n fragment ModuleLevelFragment on ModuleLevelNode {\n name\n id\n filterAttributeType\n }\n": types.ModuleLevelFragmentFragmentDoc, "\n query ModuleFilterQuery {\n moduleLevels {\n ...ModuleLevelFragment\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n ": types.ModuleFilterQueryDocument, "\n mutation UpdateLastModuleLevelMutation($input: UpdateLastModuleLevelInput!) {\n updateLastModuleLevel(input: $input) {\n clientMutationId\n user {\n username\n id\n lastModuleLevel {\n ...ModuleLevelFragment\n }\n }\n }\n }\n ": types.UpdateLastModuleLevelMutationDocument, @@ -53,7 +56,7 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n text\n color\n }\n"): (typeof documents)["\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n text\n color\n }\n"]; +export function graphql(source: "\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n note {\n text\n }\n color\n contentBlock {\n id\n }\n }\n"): (typeof documents)["\n fragment HighlightParts on HighlightNode {\n id\n contentIndex\n paragraphIndex\n selectionLength\n contentUuid\n startPosition\n note {\n text\n }\n color\n contentBlock {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -74,6 +77,18 @@ export function graphql(source: "\n mutation SetLanguage($language: String!) * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "): (typeof documents)["\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n "]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation UpdateHighlight($input: UpdateHighlightInput!) {\n updateHighlight(input: $input) {\n highlight {\n ...HighlightParts\n }\n }\n }\n "): (typeof documents)["\n mutation UpdateHighlight($input: UpdateHighlightInput!) {\n updateHighlight(input: $input) {\n highlight {\n ...HighlightParts\n }\n }\n }\n "]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation DeleteHighlight($input: DeleteHighlightInput!) {\n deleteHighlight(input: $input) {\n success\n }\n }\n "): (typeof documents)["\n mutation DeleteHighlight($input: DeleteHighlightInput!) {\n deleteHighlight(input: $input) {\n success\n }\n }\n "]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode {\n highlights {\n id\n }\n }\n "): (typeof documents)["\n fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode {\n highlights {\n id\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/client/src/__generated__/graphql.ts b/client/src/__generated__/graphql.ts index 1f0277bd..4167e2fa 100644 --- a/client/src/__generated__/graphql.ts +++ b/client/src/__generated__/graphql.ts @@ -70,7 +70,7 @@ export type AddContentBlockPayload = { export type AddHighlightArgument = { color: Scalars['String']['input']; - contentBlockId: Scalars['String']['input']; + contentBlock: Scalars['String']['input']; contentIndex: Scalars['Int']['input']; contentUuid: Scalars['UUID']['input']; paragraphIndex: Scalars['Int']['input']; @@ -560,6 +560,17 @@ export type DeleteContentBlockPayload = { success?: Maybe; }; +export type DeleteHighlightInput = { + clientMutationId?: InputMaybe; + id: Scalars['ID']['input']; +}; + +export type DeleteHighlightPayload = { + __typename?: 'DeleteHighlightPayload'; + clientMutationId?: Maybe; + success: Scalars['Boolean']['output']; +}; + export type DeleteObjectiveInput = { clientMutationId?: InputMaybe; id: Scalars['ID']['input']; @@ -720,10 +731,10 @@ export type HighlightNode = Node & { contentUuid: Scalars['UUID']['output']; /** The ID of the object */ id: Scalars['ID']['output']; + note: NoteNode; paragraphIndex: Scalars['Int']['output']; selectionLength: Scalars['Int']['output']; startPosition: Scalars['Int']['output']; - text: Scalars['String']['output']; user: PrivateUserNode; }; @@ -1044,6 +1055,7 @@ export type Mutation = { createSnapshot?: Maybe; createTeam?: Maybe; deleteContentBlock?: Maybe; + deleteHighlight?: Maybe; deleteObjective?: Maybe; deleteProject?: Maybe; deleteProjectEntry?: Maybe; @@ -1066,6 +1078,7 @@ export type Mutation = { updateChapterBookmark?: Maybe; updateChapterVisibility?: Maybe; updateContentBookmark?: Maybe; + updateHighlight?: Maybe; updateInstrumentBookmark?: Maybe; updateLastModule?: Maybe; updateLastModuleLevel?: Maybe; @@ -1176,6 +1189,11 @@ export type MutationDeleteContentBlockArgs = { }; +export type MutationDeleteHighlightArgs = { + input: DeleteHighlightInput; +}; + + export type MutationDeleteObjectiveArgs = { input: DeleteObjectiveInput; }; @@ -1276,6 +1294,11 @@ export type MutationUpdateContentBookmarkArgs = { }; +export type MutationUpdateHighlightArgs = { + input: UpdateHighlightInput; +}; + + export type MutationUpdateInstrumentBookmarkArgs = { input: UpdateInstrumentBookmarkInput; }; @@ -1414,6 +1437,7 @@ export type NoteNode = Node & { __typename?: 'NoteNode'; chapterbookmark?: Maybe; contentblockbookmark?: Maybe; + highlight?: Maybe; /** The ID of the object */ id: Scalars['ID']['output']; instrumentbookmark?: Maybe; @@ -1625,7 +1649,6 @@ export type Query = { chapter?: Maybe; chapters?: Maybe; contentBlock?: Maybe; - highlight?: Maybe; instrument?: Maybe; instrumentCategories?: Maybe>>; instrumentTypes?: Maybe>>; @@ -1705,11 +1728,6 @@ export type QueryContentBlockArgs = { }; -export type QueryHighlightArgs = { - id: Scalars['ID']['input']; -}; - - export type QueryInstrumentArgs = { id?: InputMaybe; slug?: InputMaybe; @@ -2324,6 +2342,19 @@ export type UpdateError = { field?: Maybe; }; +export type UpdateHighlightInput = { + clientMutationId?: InputMaybe; + color?: InputMaybe; + id: Scalars['ID']['input']; + note?: InputMaybe; +}; + +export type UpdateHighlightPayload = { + __typename?: 'UpdateHighlightPayload'; + clientMutationId?: Maybe; + highlight?: Maybe; +}; + export type UpdateInstrumentBookmarkInput = { bookmarked: Scalars['Boolean']['input']; clientMutationId?: InputMaybe; @@ -2629,7 +2660,7 @@ export type UserGroupBlockVisibility = { schoolClassId: Scalars['ID']['input']; }; -export type HighlightPartsFragment = { __typename?: 'HighlightNode', id: string, contentIndex: number, paragraphIndex: number, selectionLength: number, contentUuid: any, startPosition: number, text: string, color: string } & { ' $fragmentName'?: 'HighlightPartsFragment' }; +export type HighlightPartsFragment = { __typename?: 'HighlightNode', id: string, contentIndex: number, paragraphIndex: number, selectionLength: number, contentUuid: any, startPosition: number, color: string, note: { __typename?: 'NoteNode', text: string }, contentBlock: { __typename?: 'ContentBlockNode', id: string } } & { ' $fragmentName'?: 'HighlightPartsFragment' }; export type ContentBlockHighlightsFragmentFragment = { __typename: 'ContentBlockNode', id: string, highlights?: Array<( { __typename?: 'HighlightNode' } @@ -2663,6 +2694,25 @@ export type ReadOnlyQueryQueryVariables = Exact<{ [key: string]: never; }>; export type ReadOnlyQueryQuery = { __typename?: 'Query', me?: { __typename?: 'PrivateUserNode', readOnly?: boolean | null, selectedClass?: { __typename?: 'SchoolClassNode', readOnly?: boolean | null } | null } | null }; +export type UpdateHighlightMutationVariables = Exact<{ + input: UpdateHighlightInput; +}>; + + +export type UpdateHighlightMutation = { __typename?: 'Mutation', updateHighlight?: { __typename?: 'UpdateHighlightPayload', highlight?: ( + { __typename?: 'HighlightNode' } + & { ' $fragmentRefs'?: { 'HighlightPartsFragment': HighlightPartsFragment } } + ) | null } | null }; + +export type DeleteHighlightMutationVariables = Exact<{ + input: DeleteHighlightInput; +}>; + + +export type DeleteHighlightMutation = { __typename?: 'Mutation', deleteHighlight?: { __typename?: 'DeleteHighlightPayload', success: boolean } | null }; + +export type ContentBlockHighlightsWithIdOnlyFragmentFragment = { __typename?: 'ContentBlockNode', highlights?: Array<{ __typename?: 'HighlightNode', id: string } | null> | null } & { ' $fragmentName'?: 'ContentBlockHighlightsWithIdOnlyFragmentFragment' }; + export type ModuleLevelFragmentFragment = { __typename?: 'ModuleLevelNode', name: string, id: string, filterAttributeType: BooksModuleLevelFilterAttributeTypeChoices } & { ' $fragmentName'?: 'ModuleLevelFragmentFragment' }; export type ModuleFilterQueryQueryVariables = Exact<{ [key: string]: never; }>; @@ -2753,16 +2803,19 @@ export type ModuleSolutionsQueryVariables = Exact<{ export type ModuleSolutionsQuery = { __typename?: 'Query', module?: { __typename?: 'ModuleNode', solutionsEnabled?: boolean | null, slug: string } | null }; -export const HighlightPartsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; -export const ContentBlockHighlightsFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ContentBlockHighlightsFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ContentBlockNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"highlights"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightParts"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; +export const HighlightPartsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"note"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"text"}}]}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"contentBlock"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const ContentBlockHighlightsFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ContentBlockHighlightsFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ContentBlockNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"highlights"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightParts"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"note"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"text"}}]}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"contentBlock"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const ContentBlockHighlightsWithIdOnlyFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ContentBlockHighlightsWithIdOnlyFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ContentBlockNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"highlights"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const ModuleLevelFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ModuleLevelFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ModuleLevelNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}}]} as unknown as DocumentNode; export const SnapshotListItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shared"}}]}}]} as unknown as DocumentNode; export const SnapshotTitleFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotTitleFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]} as unknown as DocumentNode; export const SnapshotDetailsFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotDetailsFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"shared"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"creator"}},{"kind":"Field","name":{"kind":"Name","value":"mine"}}]}}]} as unknown as DocumentNode; -export const AddHighlightDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddHighlight"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AddHighlightInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addHighlight"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"highlight"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightParts"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; +export const AddHighlightDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddHighlight"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AddHighlightInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addHighlight"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"highlight"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightParts"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"note"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"text"}}]}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"contentBlock"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const LanguageQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LanguageQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]}]}}]}}]} as unknown as DocumentNode; export const SetLanguageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetLanguage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setLanguage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"language"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const ReadOnlyQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ReadOnlyQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"selectedClass"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]}}]}}]} as unknown as DocumentNode; +export const UpdateHighlightDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateHighlight"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateHighlightInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateHighlight"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"highlight"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightParts"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightParts"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HighlightNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contentIndex"}},{"kind":"Field","name":{"kind":"Name","value":"paragraphIndex"}},{"kind":"Field","name":{"kind":"Name","value":"selectionLength"}},{"kind":"Field","name":{"kind":"Name","value":"contentUuid"}},{"kind":"Field","name":{"kind":"Name","value":"startPosition"}},{"kind":"Field","name":{"kind":"Name","value":"note"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"text"}}]}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"contentBlock"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const DeleteHighlightDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteHighlight"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteHighlightInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteHighlight"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; export const ModuleFilterQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleFilterQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"moduleLevels"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ModuleLevelFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"moduleCategories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ModuleLevelFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ModuleLevelNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}}]} as unknown as DocumentNode; export const UpdateLastModuleLevelMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateLastModuleLevelMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateLastModuleLevelInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateLastModuleLevel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"clientMutationId"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lastModuleLevel"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ModuleLevelFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ModuleLevelFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ModuleLevelNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"filterAttributeType"}}]}}]} as unknown as DocumentNode; export const ModuleTitleQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleTitleQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; diff --git a/client/src/components/content-blocks/ContentComponent.vue b/client/src/components/content-blocks/ContentComponent.vue index 775cc700..411b3903 100644 --- a/client/src/components/content-blocks/ContentComponent.vue +++ b/client/src/components/content-blocks/ContentComponent.vue @@ -152,7 +152,7 @@ const paragraphs = computed(() => ); watch( - () => filteredHighlights.value.length, + () => filteredHighlights.value.map((h) => h.color), () => { for (const paragraph of paragraphs.value) { const instance = new Mark(paragraph); @@ -201,8 +201,8 @@ const bookmarkContent = (bookmarked: boolean) => { const { mutate: doUpdateHighlight } = useMutation( graphql(` - mutation UpdateHighlight($color: String!) { - updateHighlight(color: $color) { + mutation UpdateHighlight($input: UpdateHighlightInput!) { + updateHighlight(input: $input) { highlight { ...HighlightParts } @@ -211,6 +211,16 @@ const { mutate: doUpdateHighlight } = useMutation( `) ); +const { mutate: doDeleteHighlight } = useMutation( + graphql(` + mutation DeleteHighlight($input: DeleteHighlightInput!) { + deleteHighlight(input: $input) { + success + } + } + `) +); + const markHighlights = () => { for (const highlight of filteredHighlights.value) { const element = paragraphs.value[highlight.paragraphIndex]; @@ -225,21 +235,79 @@ const markHighlights = () => { className: `highlight highlight--${highlight.color}`, each: (newMark: HTMLElement) => { newMark.dataset.id = highlight.id; - console.log(newMark); newMark.addEventListener('click', () => { - console.log('clicked'); if (contentComponentDiv.value) { popover.show({ wrapper: contentComponentDiv.value, offsetTop: 0, onChooseColor: (color: string) => { doUpdateHighlight({ - color: color, + input: { + color: color, + id: highlight.id, + }, }); }, + onDelete: () => { + console.log(`deleting ${highlight.id}`); + doDeleteHighlight( + { + input: { + id: highlight.id, + }, + }, + { + update: ( + cache, + { + data: { + deleteHighlight: { success }, + }, + } + ) => { + if (success) { + const fragment = graphql(` + fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode { + highlights { + id + } + } + `); + const id = cache.identify({ + __typename: 'ContentBlockNode', + id: highlight.contentBlock.id, + }); + const contentBlock = cache.readFragment({ + fragment, + id, + }); + const data = { + ...contentBlock, + highlights: contentBlock.highlights.filter((h) => h.id !== highlight.id), + }; + cache.writeFragment({ + fragment, + id, + data, + }); + } + }, + } + ); + }, }); } - highlightSidebar.open(highlight); + highlightSidebar.open({ + highlight, + onUpdateText: (text: string) => { + doUpdateHighlight({ + input: { + note: text, + id: highlight.id, + }, + }); + }, + }); }); }, }); diff --git a/client/src/components/highlights/HighlightPopover.vue b/client/src/components/highlights/HighlightPopover.vue index 6f1803f0..4706f269 100644 --- a/client/src/components/highlights/HighlightPopover.vue +++ b/client/src/components/highlights/HighlightPopover.vue @@ -23,7 +23,7 @@
@@ -60,6 +60,7 @@ defineProps(); box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.25) inset; background-color: white; border-radius: 50%; + cursor: pointer; &--yellow { background-color: var(--mark-alpha); @@ -94,6 +95,7 @@ defineProps(); &__icon { width: 40px; height: 40px; + cursor: pointer; } } diff --git a/client/src/components/highlights/HighlightSidebar.vue b/client/src/components/highlights/HighlightSidebar.vue index f0e4c33c..0360071e 100644 --- a/client/src/components/highlights/HighlightSidebar.vue +++ b/client/src/components/highlights/HighlightSidebar.vue @@ -23,8 +23,13 @@ class="borderless-textarea" placeholder="Notiz erfassen..." v-auto-grow + v-model="note" > - Speichern + Speichern @@ -32,19 +37,25 @@