Compare commits

..

6 Commits

Author SHA1 Message Date
1d950b7721 Merge pull request '[FA-misc] Whoops' (#53) from hotfix/FA-misc_LintFix into master
All checks were successful
CI / build-backend (push) Successful in 56s
CI / build-frontend (push) Successful in 39s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 49s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 49s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 49s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 46s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 3m54s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 2m10s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m56s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m58s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m58s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 3m28s
Release / build-frontend (push) Successful in 1m38s
Build Gateway / build-gateway (push) Successful in 4m7s
Reviewed-on: #53
2025-12-11 20:21:15 +00:00
gamer147
7738bcf438 [FA-misc] Whoops
Some checks failed
CI / build-frontend (pull_request) Has been cancelled
CI / build-backend (pull_request) Has been cancelled
2025-12-11 15:21:04 -05:00
61e0cb69d8 Merge pull request '[FA-misc] Add delete button' (#52) from hotfix/FA-misc_FixNovelRedownloads into master
Some checks failed
CI / build-backend (push) Successful in 1m3s
CI / build-frontend (push) Failing after 26s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 52s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 43s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 2m3s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 2m54s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m45s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m42s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m50s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 1m53s
Build Gateway / build-gateway (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Reviewed-on: #52
2025-12-11 20:01:43 +00:00
gamer147
02525d611a [FA-misc] Add delete button
Some checks failed
CI / build-backend (pull_request) Successful in 2m35s
CI / build-frontend (pull_request) Failing after 27s
2025-12-11 15:00:55 -05:00
c21fe0fbd5 Merge pull request '[FA-misc] Fix an oversight in the update process' (#51) from feature/FA-misc_NovelpiaResiliency into master
Some checks failed
CI / build-backend (push) Successful in 1m2s
CI / build-frontend (push) Successful in 41s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 1m1s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 48s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 45s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 42s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 2m12s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 2m3s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m48s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m44s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m58s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 1m55s
Release / build-frontend (push) Failing after 59s
Build Gateway / build-gateway (push) Successful in 3m38s
Reviewed-on: #51
2025-12-11 19:16:39 +00:00
5527c15ae7 Merge pull request '[FA-misc] Adds standard Polly Resiliency to Novelpia Http Clients' (#50) from feature/FA-misc_NovelpiaResiliency into master
All checks were successful
CI / build-backend (push) Successful in 1m0s
CI / build-frontend (push) Successful in 41s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 51s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 48s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 49s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 52s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 2m23s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 2m24s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m43s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m38s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m51s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 1m34s
Release / build-frontend (push) Successful in 1m33s
Build Gateway / build-gateway (push) Successful in 4m1s
Reviewed-on: #50
2025-12-11 14:54:12 +00:00
5 changed files with 198 additions and 8 deletions

View File

@@ -7,6 +7,7 @@ using FictionArchive.Service.NovelService.Services;
using FictionArchive.Service.NovelService.Services.SourceAdapters;
using FictionArchive.Service.Shared.Services.EventBus;
using HotChocolate.Authorization;
using HotChocolate.Types;
using Microsoft.EntityFrameworkCore;
namespace FictionArchive.Service.NovelService.GraphQL;
@@ -26,4 +27,12 @@ public class Mutation
{
return await service.QueueChapterPull(novelId, chapterNumber);
}
[Error<KeyNotFoundException>]
[Authorize]
public async Task<bool> DeleteNovel(uint novelId, NovelUpdateService service)
{
await service.DeleteNovel(novelId);
return true;
}
}

View File

@@ -379,12 +379,23 @@ public class NovelUpdateService
var chapter = novel.Chapters.Where(chapter => chapter.Order == chapterNumber).FirstOrDefault();
var adapter = _sourceAdapters.FirstOrDefault(adapter => adapter.SourceDescriptor.Key == novel.Source.Key);
var rawChapter = await adapter.GetRawChapter(chapter.Url);
var localizationText = new LocalizationText()
// If we already have the raw for this, overwrite it for now. Revisions will come later.
var localizationText = chapter.Body.Texts.FirstOrDefault(text => text.Language == novel.RawLanguage);
if (localizationText == null)
{
localizationText = new LocalizationText()
{
Text = rawChapter.Text,
Language = novel.RawLanguage
};
chapter.Body.Texts.Add(localizationText);
}
else
{
localizationText.Text = rawChapter.Text;
}
chapter.Images = rawChapter.ImageData.Select(img => new Image()
{
OriginalPath = img.Url
@@ -477,4 +488,49 @@ public class NovelUpdateService
await _eventBus.Publish(chapterPullEvent);
return chapterPullEvent;
}
public async Task DeleteNovel(uint novelId)
{
var novel = await _dbContext.Novels
.Include(n => n.CoverImage)
.Include(n => n.Name).ThenInclude(k => k.Texts)
.Include(n => n.Description).ThenInclude(k => k.Texts)
.Include(n => n.Chapters).ThenInclude(c => c.Images)
.Include(n => n.Chapters).ThenInclude(c => c.Name).ThenInclude(k => k.Texts)
.Include(n => n.Chapters).ThenInclude(c => c.Body).ThenInclude(k => k.Texts)
.FirstOrDefaultAsync(n => n.Id == novelId);
if (novel == null)
throw new KeyNotFoundException($"Novel with ID '{novelId}' not found");
// Collect all LocalizationKey IDs for cleanup
var locKeyIds = new List<Guid> { novel.Name.Id, novel.Description.Id };
locKeyIds.AddRange(novel.Chapters.Select(c => c.Name.Id));
locKeyIds.AddRange(novel.Chapters.Select(c => c.Body.Id));
// 1. Remove LocalizationRequests referencing these keys
var locRequests = await _dbContext.LocalizationRequests
.Where(r => locKeyIds.Contains(r.KeyRequestedForTranslation.Id))
.ToListAsync();
_dbContext.LocalizationRequests.RemoveRange(locRequests);
// 2. Remove LocalizationTexts (NO ACTION FK - won't cascade)
_dbContext.RemoveRange(novel.Name.Texts);
_dbContext.RemoveRange(novel.Description.Texts);
foreach (var chapter in novel.Chapters)
{
_dbContext.RemoveRange(chapter.Name.Texts);
_dbContext.RemoveRange(chapter.Body.Texts);
}
// 3. Remove Images (NO ACTION FK - won't cascade)
if (novel.CoverImage != null)
_dbContext.Images.Remove(novel.CoverImage);
foreach (var chapter in novel.Chapters)
_dbContext.Images.RemoveRange(chapter.Images);
// 4. Remove novel - cascades: chapters, localization keys, tag mappings
_dbContext.Novels.Remove(novel);
await _dbContext.SaveChangesAsync();
}
}

View File

@@ -32,7 +32,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { client } from '$lib/graphql/client';
import { NovelDocument, ImportNovelDocument } from '$lib/graphql/__generated__/graphql';
import { NovelDocument, ImportNovelDocument, DeleteNovelDocument } from '$lib/graphql/__generated__/graphql';
import { isAuthenticated } from '$lib/auth/authStore';
import { Card, CardContent, CardHeader } from '$lib/components/ui/card';
import { Badge } from '$lib/components/ui/badge';
@@ -53,6 +53,7 @@
import ChevronDown from '@lucide/svelte/icons/chevron-down';
import ChevronUp from '@lucide/svelte/icons/chevron-up';
import RefreshCw from '@lucide/svelte/icons/refresh-cw';
import Trash2 from '@lucide/svelte/icons/trash-2';
import X from '@lucide/svelte/icons/x';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
@@ -71,6 +72,11 @@
let refreshError: string | null = $state(null);
let refreshSuccess = $state(false);
// Delete state
let showDeleteConfirm = $state(false);
let deleting = $state(false);
let deleteError: string | null = $state(null);
// Image viewer state
type GalleryImage = {
src: string;
@@ -119,7 +125,6 @@
const isNsfw = $derived(novel?.tags?.some((tag) => tag.key === SystemTags.Nsfw) ?? false);
const canRefresh = $derived(() => {
if (status === 'COMPLETED') return false;
if (!lastUpdated) return true;
const sixHoursAgo = Date.now() - 6 * 60 * 60 * 1000;
return lastUpdated.getTime() < sixHoursAgo;
@@ -251,6 +256,32 @@
}
}
async function deleteNovel() {
if (!novel) return;
deleting = true;
deleteError = null;
try {
const result = await client
.mutation(DeleteNovelDocument, { input: { novelId: novel.id } })
.toPromise();
if (result.error) {
deleteError = result.error.message;
} else if (result.data?.deleteNovel?.errors?.length) {
deleteError = result.data.deleteNovel.errors[0].message;
} else {
// Successfully deleted - redirect to novels list
window.location.href = '/novels';
}
} catch (e) {
deleteError = e instanceof Error ? e.message : 'Failed to delete';
} finally {
deleting = false;
}
}
onMount(() => {
fetchNovel();
});
@@ -359,11 +390,20 @@
</TooltipTrigger>
{#if !canRefresh()}
<TooltipContent>
{status === 'COMPLETED' ? 'Cannot refresh completed novels' : 'Updated less than 6 hours ago'}
Updated less than 6 hours ago
</TooltipContent>
{/if}
</Tooltip>
</TooltipProvider>
<Button
variant="destructive"
size="sm"
onclick={() => (showDeleteConfirm = true)}
class="gap-1.5 h-6 text-xs"
>
<Trash2 class="h-3 w-3" />
Delete
</Button>
{/if}
{#if refreshSuccess}
<Badge variant="outline" class="bg-green-500/10 text-green-600 border-green-500/30">
@@ -622,3 +662,53 @@
</div>
</div>
{/if}
<!-- Delete Confirmation Modal -->
{#if showDeleteConfirm && novel}
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm"
onclick={() => !deleting && (showDeleteConfirm = false)}
onkeydown={(e) => e.key === 'Escape' && !deleting && (showDeleteConfirm = false)}
role="dialog"
aria-modal="true"
aria-labelledby="delete-modal-title"
tabindex="-1"
>
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div onclick={(e: MouseEvent) => e.stopPropagation()}>
<Card class="w-full max-w-md mx-4 shadow-xl">
<CardHeader>
<h2 id="delete-modal-title" class="text-lg font-semibold">Delete Novel</h2>
</CardHeader>
<CardContent class="space-y-4">
<p class="text-muted-foreground">
Are you sure you want to delete <strong class="text-foreground">{novel.name}</strong>?
</p>
<p class="text-sm text-muted-foreground">
This will permanently delete the novel, all chapters, images, and translations. This action cannot be undone.
</p>
{#if deleteError}
<p class="text-sm text-destructive">{deleteError}</p>
{/if}
<div class="flex justify-end gap-2 pt-2">
<Button
variant="outline"
onclick={() => (showDeleteConfirm = false)}
disabled={deleting}
>
Cancel
</Button>
<Button
variant="destructive"
onclick={deleteNovel}
disabled={deleting}
>
{deleting ? 'Deleting...' : 'Delete'}
</Button>
</div>
</CardContent>
</Card>
</div>
</div>
{/if}

View File

@@ -88,6 +88,17 @@ export type DeleteJobPayload = {
errors: Maybe<Array<DeleteJobError>>;
};
export type DeleteNovelError = KeyNotFoundError;
export type DeleteNovelInput = {
novelId: Scalars['UnsignedInt']['input'];
};
export type DeleteNovelPayload = {
boolean: Maybe<Scalars['Boolean']['output']>;
errors: Maybe<Array<DeleteNovelError>>;
};
export type DuplicateNameError = Error & {
message: Scalars['String']['output'];
};
@@ -201,6 +212,7 @@ export type ListFilterInputTypeOfNovelTagDtoFilterInput = {
export type Mutation = {
deleteJob: DeleteJobPayload;
deleteNovel: DeleteNovelPayload;
fetchChapterContents: FetchChapterContentsPayload;
importNovel: ImportNovelPayload;
registerUser: RegisterUserPayload;
@@ -215,6 +227,11 @@ export type MutationDeleteJobArgs = {
};
export type MutationDeleteNovelArgs = {
input: DeleteNovelInput;
};
export type MutationFetchChapterContentsArgs = {
input: FetchChapterContentsInput;
};
@@ -707,6 +724,13 @@ export type UuidOperationFilterInput = {
nlte?: InputMaybe<Scalars['UUID']['input']>;
};
export type DeleteNovelMutationVariables = Exact<{
input: DeleteNovelInput;
}>;
export type DeleteNovelMutation = { deleteNovel: { boolean: boolean | null, errors: Array<{ message: string }> | null } };
export type ImportNovelMutationVariables = Exact<{
input: ImportNovelInput;
}>;
@@ -740,6 +764,7 @@ export type NovelsQueryVariables = Exact<{
export type NovelsQuery = { novels: { edges: Array<{ cursor: string, node: { id: any, url: string, name: string, description: string, rawStatus: NovelStatus, lastUpdatedTime: any, coverImage: { newPath: string | null } | null, chapters: Array<{ order: any, name: string }>, tags: Array<{ key: string, displayName: string, tagType: TagType }> } }> | null, pageInfo: { hasNextPage: boolean, endCursor: string | null } } | null };
export const DeleteNovelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNovel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteNovelInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNovel"},"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":"boolean"}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Error"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]}}]}}]}}]} as unknown as DocumentNode<DeleteNovelMutation, DeleteNovelMutationVariables>;
export const ImportNovelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ImportNovel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImportNovelInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"importNovel"},"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":"novelUpdateRequestedEvent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"novelUrl"}}]}}]}}]}}]} as unknown as DocumentNode<ImportNovelMutation, ImportNovelMutationVariables>;
export const GetChapterDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapter"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"novelId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UnsignedInt"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"chapterOrder"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UnsignedInt"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"novelId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"novelId"}}},{"kind":"Argument","name":{"kind":"Name","value":"chapterOrder"},"value":{"kind":"Variable","name":{"kind":"Name","value":"chapterOrder"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"order"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"revision"}},{"kind":"Field","name":{"kind":"Name","value":"createdTime"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedTime"}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}},{"kind":"Field","name":{"kind":"Name","value":"novelId"}},{"kind":"Field","name":{"kind":"Name","value":"novelName"}},{"kind":"Field","name":{"kind":"Name","value":"totalChapters"}},{"kind":"Field","name":{"kind":"Name","value":"prevChapterOrder"}},{"kind":"Field","name":{"kind":"Name","value":"nextChapterOrder"}}]}}]}}]} as unknown as DocumentNode<GetChapterQuery, GetChapterQueryVariables>;
export const NovelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Novel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UnsignedInt"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"novels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"rawLanguage"}},{"kind":"Field","name":{"kind":"Name","value":"rawStatus"}},{"kind":"Field","name":{"kind":"Name","value":"statusOverride"}},{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"createdTime"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedTime"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"externalUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"source"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"tagType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"chapters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"order"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedTime"}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<NovelQuery, NovelQueryVariables>;

View File

@@ -0,0 +1,10 @@
mutation DeleteNovel($input: DeleteNovelInput!) {
deleteNovel(input: $input) {
boolean
errors {
... on Error {
message
}
}
}
}