Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/src/graphql/generated/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ export type Mutation = {
connectSignIn: Scalars['Boolean']['output'];
connectSignOut: Scalars['Boolean']['output'];
createNotification: Notification;
deleteAllNotifications: NotificationOverview;
deleteNotification: NotificationOverview;
/** Delete a user */
deleteUser?: Maybe<User>;
Expand Down Expand Up @@ -1723,7 +1724,7 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs


/** Mapping of interface types */
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = ResolversObject<{
export type ResolversInterfaceTypes<_RefType extends Record<string, unknown>> = ResolversObject<{
Node: ( ArrayType ) | ( Config ) | ( Connect ) | ( Docker ) | ( Info ) | ( Network ) | ( Notification ) | ( Notifications ) | ( Service ) | ( Vars );
UserAccount: ( Me ) | ( User );
}>;
Expand Down Expand Up @@ -2355,6 +2356,7 @@ export type MutationResolvers<ContextType = Context, ParentType extends Resolver
connectSignIn?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<MutationconnectSignInArgs, 'input'>>;
connectSignOut?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
createNotification?: Resolver<ResolversTypes['Notification'], ParentType, ContextType, RequireFields<MutationcreateNotificationArgs, 'input'>>;
deleteAllNotifications?: Resolver<ResolversTypes['NotificationOverview'], ParentType, ContextType>;
deleteNotification?: Resolver<ResolversTypes['NotificationOverview'], ParentType, ContextType, RequireFields<MutationdeleteNotificationArgs, 'id' | 'type'>>;
deleteUser?: Resolver<Maybe<ResolversTypes['User']>, ParentType, ContextType, RequireFields<MutationdeleteUserArgs, 'input'>>;
enableDynamicRemoteAccess?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<MutationenableDynamicRemoteAccessArgs, 'input'>>;
Expand Down
26 changes: 23 additions & 3 deletions api/src/graphql/generated/client/fragment-masking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,45 @@ export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
): TType;
// return nullable if `fragmentType` is undefined
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined
): TType | undefined;
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null
): TType | null;
// return nullable if `fragmentType` is nullable or undefined
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>
): Array<TType>;
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): Array<TType> | null | undefined;
// return readonly array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
): ReadonlyArray<TType>;
// return array of nullable if `fragmentType` is array of nullable
// return readonly array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | ReadonlyArray<TType> | null | undefined {
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | Array<FragmentType<DocumentTypeDecoration<TType, any>>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | Array<TType> | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}

Expand Down
1 change: 1 addition & 0 deletions api/src/graphql/generated/client/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
* 3. It does not support dead code elimination, so it will add unused operations.
*
* Therefore it is highly recommended to use the babel or swc plugin for production.
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
*/
const documents = {
"\n mutation sendRemoteGraphQLResponse($input: RemoteGraphQLServerInput!) {\n remoteGraphQLResponse(input: $input)\n }\n": types.sendRemoteGraphQLResponseDocument,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Query {
type Mutation {
createNotification(input: NotificationData!): Notification!
deleteNotification(id: String!, type: NotificationType!): NotificationOverview!
deleteAllNotifications: NotificationOverview!
"""
Marks a notification as archived.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ export class NotificationsResolver {
return overview;
}

@Mutation()
public async deleteAllNotifications(): Promise<NotificationOverview> {
return this.notificationsService.deleteAllNotifications();
}

@Mutation()
public archiveNotification(@Args('id') id: string) {
return this.notificationsService.archiveNotification({ id });
Expand Down
60 changes: 47 additions & 13 deletions web/components/Notifications/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@ import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/co
import { useMutation } from '@vue/apollo-composable';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- false positive :(
import { Importance, NotificationType } from '~/composables/gql/graphql';
import { archiveAllNotifications } from './graphql/notification.query';
import { archiveAllNotifications, deleteAllNotifications } from './graphql/notification.query';

const { mutate: archiveAll, loading: loadingArchiveAll } = useMutation(archiveAllNotifications);
const { mutate: deleteAll, loading: loadingDeleteAll } = useMutation(deleteAllNotifications);
const { teleportTarget, determineTeleportTarget } = useTeleport();
const importance = ref<Importance | undefined>(undefined);

const confirmAndArchiveAll = async () => {
if (
confirm('This will archive all notifications on your Unraid server. Continue?')
) {
await archiveAll();
}
};

const confirmAndDeleteAll = async () => {
if (
confirm('This will permanently delete all notifications currently on your Unraid server. Continue?')
) {
await deleteAll();
}
};
</script>

<template>
Expand All @@ -20,8 +37,13 @@ const importance = ref<Importance | undefined>(undefined);
<!-- We remove the horizontal padding from the container to keep the NotificationList's scrollbar in the right place -->
<SheetContent :to="teleportTarget" class="w-full sm:max-w-[540px] h-screen px-0">
<div class="flex flex-col h-full gap-3">
<SheetHeader class="ml-1 px-6">
<SheetTitle>Notifications</SheetTitle>
<SheetHeader class="ml-1 px-6 flex items-baseline gap-0">
<SheetTitle class="text-2xl">Notifications</SheetTitle>
<a href="/Settings/Notifications">
<Button variant="link" size="sm" class="text-muted-foreground text-base p-0">
Edit Settings
</Button>
</a>
</SheetHeader>

<!-- min-h-0 prevents the flex container from expanding beyond its containing bounds. -->
Expand All @@ -33,16 +55,28 @@ const importance = ref<Importance | undefined>(undefined);
<TabsTrigger value="unread"> Unread </TabsTrigger>
<TabsTrigger value="archived"> Archived </TabsTrigger>
</TabsList>

<Button
:disabled="loadingArchiveAll"
variant="link"
size="sm"
class="text-muted-foreground text-base p-0"
@click="archiveAll"
>
Archive All
</Button>
<TabsContent value="unread">
<Button
:disabled="loadingArchiveAll"
variant="link"
size="sm"
class="text-muted-foreground text-base p-0"
@click="confirmAndArchiveAll"
>
Archive All
</Button>
</TabsContent>
<TabsContent value="archived">
<Button
:disabled="loadingDeleteAll"
variant="link"
size="sm"
class="text-muted-foreground text-base p-0"
@click="confirmAndDeleteAll"
>
Delete All
</Button>
</TabsContent>

<Select
@update:model-value="
Expand Down
13 changes: 13 additions & 0 deletions web/components/Notifications/graphql/notification.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ export const deleteNotification = graphql(/* GraphQL */ `
}
`);

export const deleteAllNotifications = graphql(/* GraphQL */ `
mutation DeleteAllNotifications {
deleteAllNotifications {
archive {
total
}
unread {
total
}
}
}
`);

export const unreadOverview = graphql(/* GraphQL */ `
query Overview {
notifications {
Expand Down
5 changes: 5 additions & 0 deletions web/composables/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const documents = {
"\n mutation ArchiveNotification($id: String!) {\n archiveNotification(id: $id) {\n ...NotificationFragment\n }\n }\n": types.ArchiveNotificationDocument,
"\n mutation ArchiveAllNotifications {\n archiveAll {\n unread {\n total\n }\n archive {\n info\n warning\n alert\n total\n }\n }\n }\n": types.ArchiveAllNotificationsDocument,
"\n mutation DeleteNotification($id: String!, $type: NotificationType!) {\n deleteNotification(id: $id, type: $type) {\n archive {\n total\n }\n }\n }\n": types.DeleteNotificationDocument,
"\n mutation DeleteAllNotifications {\n deleteAllNotifications {\n archive {\n total\n }\n unread {\n total\n }\n }\n }\n": types.DeleteAllNotificationsDocument,
"\n query Overview {\n notifications {\n overview {\n unread {\n info\n warning\n alert\n total\n }\n }\n }\n }\n": types.OverviewDocument,
"\n mutation ConnectSignIn($input: ConnectSignInInput!) {\n connectSignIn(input: $input)\n }\n": types.ConnectSignInDocument,
"\n mutation SignOut {\n connectSignOut\n }\n": types.SignOutDocument,
Expand Down Expand Up @@ -69,6 +70,10 @@ export function graphql(source: "\n mutation ArchiveAllNotifications {\n arc
* 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 DeleteNotification($id: String!, $type: NotificationType!) {\n deleteNotification(id: $id, type: $type) {\n archive {\n total\n }\n }\n }\n"): (typeof documents)["\n mutation DeleteNotification($id: String!, $type: NotificationType!) {\n deleteNotification(id: $id, type: $type) {\n archive {\n total\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 DeleteAllNotifications {\n deleteAllNotifications {\n archive {\n total\n }\n unread {\n total\n }\n }\n }\n"): (typeof documents)["\n mutation DeleteAllNotifications {\n deleteAllNotifications {\n archive {\n total\n }\n unread {\n total\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
6 changes: 6 additions & 0 deletions web/composables/gql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,11 @@ export type DeleteNotificationMutationVariables = Exact<{

export type DeleteNotificationMutation = { __typename?: 'Mutation', deleteNotification: { __typename?: 'NotificationOverview', archive: { __typename?: 'NotificationCounts', total: number } } };

export type DeleteAllNotificationsMutationVariables = Exact<{ [key: string]: never; }>;


export type DeleteAllNotificationsMutation = { __typename?: 'Mutation', deleteAllNotifications: { __typename?: 'NotificationOverview', archive: { __typename?: 'NotificationCounts', total: number }, unread: { __typename?: 'NotificationCounts', total: number } } };

export type OverviewQueryVariables = Exact<{ [key: string]: never; }>;


Expand Down Expand Up @@ -1752,6 +1757,7 @@ export const NotificationsDocument = {"kind":"Document","definitions":[{"kind":"
export const ArchiveNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ArchiveNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"archiveNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Notification"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"subject"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"importance"}},{"kind":"Field","name":{"kind":"Name","value":"link"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}}]} as unknown as DocumentNode<ArchiveNotificationMutation, ArchiveNotificationMutationVariables>;
export const ArchiveAllNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ArchiveAllNotifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"archiveAll"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unread"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"archive"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"info"}},{"kind":"Field","name":{"kind":"Name","value":"warning"}},{"kind":"Field","name":{"kind":"Name","value":"alert"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}}]}}]}}]} as unknown as DocumentNode<ArchiveAllNotificationsMutation, ArchiveAllNotificationsMutationVariables>;
export const DeleteNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationType"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"archive"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}}]}}]}}]}}]} as unknown as DocumentNode<DeleteNotificationMutation, DeleteNotificationMutationVariables>;
export const DeleteAllNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteAllNotifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteAllNotifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"archive"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"unread"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}}]}}]}}]}}]} as unknown as DocumentNode<DeleteAllNotificationsMutation, DeleteAllNotificationsMutationVariables>;
export const OverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Overview"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"overview"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unread"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"info"}},{"kind":"Field","name":{"kind":"Name","value":"warning"}},{"kind":"Field","name":{"kind":"Name","value":"alert"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}}]}}]}}]}}]} as unknown as DocumentNode<OverviewQuery, OverviewQueryVariables>;
export const ConnectSignInDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ConnectSignIn"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConnectSignInInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connectSignIn"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<ConnectSignInMutation, ConnectSignInMutationVariables>;
export const SignOutDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SignOut"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connectSignOut"}}]}}]} as unknown as DocumentNode<SignOutMutation, SignOutMutationVariables>;
Expand Down
Loading