mirror of
https://github.com/unraid/api.git
synced 2026-02-18 05:58:28 -06:00
feat: add date formatting helper (#938)
This commit is contained in:
@@ -591,6 +591,7 @@ export function NotificationSchema(): z.ZodObject<Properties<Notification>> {
|
||||
return z.object({
|
||||
__typename: z.literal('Notification').optional(),
|
||||
description: z.string(),
|
||||
formattedTimestamp: z.string().nullish(),
|
||||
id: z.string(),
|
||||
importance: ImportanceSchema,
|
||||
link: z.string().nullish(),
|
||||
|
||||
@@ -817,6 +817,7 @@ export type Node = {
|
||||
export type Notification = Node & {
|
||||
__typename?: 'Notification';
|
||||
description: Scalars['String']['output'];
|
||||
formattedTimestamp?: Maybe<Scalars['String']['output']>;
|
||||
id: Scalars['ID']['output'];
|
||||
importance: Importance;
|
||||
link?: Maybe<Scalars['String']['output']>;
|
||||
@@ -2403,6 +2404,7 @@ export type NodeResolvers<ContextType = Context, ParentType extends ResolversPar
|
||||
|
||||
export type NotificationResolvers<ContextType = Context, ParentType extends ResolversParentTypes['Notification'] = ResolversParentTypes['Notification']> = ResolversObject<{
|
||||
description?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
formattedTimestamp?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
|
||||
importance?: Resolver<ResolversTypes['Importance'], ParentType, ContextType>;
|
||||
link?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
|
||||
@@ -17,15 +17,21 @@ type Query {
|
||||
type Mutation {
|
||||
createNotification(input: NotificationData!): Notification!
|
||||
deleteNotification(id: String!, type: NotificationType!): NotificationOverview!
|
||||
"""Marks a notification as archived."""
|
||||
"""
|
||||
Marks a notification as archived.
|
||||
"""
|
||||
archiveNotification(id: String!): Notification!
|
||||
"""Marks a notification as unread."""
|
||||
"""
|
||||
Marks a notification as unread.
|
||||
"""
|
||||
unreadNotification(id: String!): Notification!
|
||||
archiveNotifications(ids: [String!]): NotificationOverview!
|
||||
unarchiveNotifications(ids: [String!]): NotificationOverview!
|
||||
archiveAll(importance: Importance): NotificationOverview!
|
||||
unarchiveAll(importance: Importance): NotificationOverview!
|
||||
"""Reads each notification to recompute & update the overview."""
|
||||
"""
|
||||
Reads each notification to recompute & update the overview.
|
||||
"""
|
||||
recalculateOverview: NotificationOverview!
|
||||
}
|
||||
|
||||
@@ -42,7 +48,9 @@ enum Importance {
|
||||
|
||||
type Notifications implements Node {
|
||||
id: ID!
|
||||
"""A cached overview of the notifications in the system & their severity."""
|
||||
"""
|
||||
A cached overview of the notifications in the system & their severity.
|
||||
"""
|
||||
overview: NotificationOverview!
|
||||
list(filter: NotificationFilter!): [Notification!]!
|
||||
}
|
||||
@@ -62,6 +70,7 @@ type Notification implements Node {
|
||||
ISO Timestamp for when the notification occurred
|
||||
"""
|
||||
timestamp: String
|
||||
formattedTimestamp: String
|
||||
}
|
||||
|
||||
input NotificationData {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { createSubscription, PUBSUB_CHANNEL } from '@app/core/pubsub';
|
||||
import { NotificationsService } from './notifications.service';
|
||||
import { Importance } from '@app/graphql/generated/client/graphql';
|
||||
import { AppError } from '@app/core/errors/app-error';
|
||||
import { formatTimestamp } from '@app/utils';
|
||||
|
||||
@Resolver('Notifications')
|
||||
export class NotificationsResolver {
|
||||
@@ -41,7 +42,11 @@ export class NotificationsResolver {
|
||||
@Args('filter')
|
||||
filters: NotificationFilter
|
||||
) {
|
||||
return await this.notificationsService.getNotifications(filters);
|
||||
const notifications = await this.notificationsService.getNotifications(filters);
|
||||
return notifications.map((notification) => ({
|
||||
...notification,
|
||||
formattedTimestamp: formatTimestamp(notification.timestamp),
|
||||
}));
|
||||
}
|
||||
|
||||
/**============================================
|
||||
@@ -97,7 +102,9 @@ export class NotificationsResolver {
|
||||
}
|
||||
|
||||
@Mutation()
|
||||
public async unarchiveAll(@Args('importance') importance?: Importance): Promise<NotificationOverview> {
|
||||
public async unarchiveAll(
|
||||
@Args('importance') importance?: Importance
|
||||
): Promise<NotificationOverview> {
|
||||
const { overview } = await this.notificationsService.unarchiveAll(importance);
|
||||
return overview;
|
||||
}
|
||||
@@ -106,7 +113,7 @@ export class NotificationsResolver {
|
||||
public async recalculateOverview() {
|
||||
const { overview, error } = await this.notificationsService.recalculateOverview();
|
||||
if (error) {
|
||||
throw new AppError("Failed to refresh overview", 500);
|
||||
throw new AppError('Failed to refresh overview', 500);
|
||||
}
|
||||
return overview;
|
||||
}
|
||||
|
||||
@@ -101,3 +101,29 @@ export function updateObject(
|
||||
iterations++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a timestamp into a human-readable format: "MMM D, YYYY"
|
||||
* Example: "Oct 24, 2024"
|
||||
*
|
||||
* @param timestamp - ISO date string or Unix timestamp in seconds
|
||||
* @returns Formatted date string or null if timestamp is invalid
|
||||
*/
|
||||
export function formatTimestamp(timestamp: string | number | null | undefined): string | null {
|
||||
if (!timestamp) return null;
|
||||
|
||||
try {
|
||||
// Convert Unix timestamp (seconds) to milliseconds if needed
|
||||
const date = typeof timestamp === 'number' ? new Date(timestamp * 1_000) : new Date(timestamp);
|
||||
|
||||
if (isNaN(date.getTime())) return null;
|
||||
|
||||
return date.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user