mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-10-05 21:21:11 +01:00
Further notification tweaks (#671)
- Improved multi-URL notification handling - Tweak Apprise validation to catch errors earlier - Much improved notification logging and UI response - More robust notification tests
This commit is contained in:
@@ -84,7 +84,14 @@ export const ActionButton = ({ field, onAction, disabled }: ActionButtonProps) =
|
||||
: 'bg-red-500/20 text-red-700 dark:text-red-300'
|
||||
}`}
|
||||
>
|
||||
{result.message}
|
||||
<p>{result.message}</p>
|
||||
{Array.isArray(result.details) && result.details.length > 0 && (
|
||||
<ul className="mt-2 list-disc pl-5 space-y-1 text-xs opacity-90">
|
||||
{result.details.map((detail, index) => (
|
||||
<li key={`${detail}-${index}`}>{detail}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -94,6 +94,31 @@ export const isApiResponseError = (error: unknown): error is ApiResponseError =>
|
||||
return error instanceof ApiResponseError;
|
||||
};
|
||||
|
||||
const mapApiErrorToActionResult = (error: unknown): ActionResult | null => {
|
||||
if (!isApiResponseError(error) || !error.payload) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const payload = error.payload;
|
||||
const message =
|
||||
typeof payload.message === 'string'
|
||||
? payload.message
|
||||
: (typeof payload.error === 'string' ? payload.error : null);
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const details = Array.isArray(payload.details)
|
||||
? payload.details.filter((detail): detail is string => typeof detail === 'string' && detail.trim().length > 0)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message,
|
||||
...(details && details.length > 0 ? { details } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
// Default request timeout in milliseconds (30 seconds)
|
||||
const DEFAULT_TIMEOUT_MS = 30000;
|
||||
|
||||
@@ -470,10 +495,18 @@ export const executeSettingsAction = async (
|
||||
actionKey: string,
|
||||
currentValues?: Record<string, unknown>
|
||||
): Promise<ActionResult> => {
|
||||
return fetchJSON<ActionResult>(`${API.settings}/${tabName}/action/${actionKey}`, {
|
||||
method: 'POST',
|
||||
body: currentValues ? JSON.stringify(currentValues) : undefined,
|
||||
});
|
||||
try {
|
||||
return await fetchJSON<ActionResult>(`${API.settings}/${tabName}/action/${actionKey}`, {
|
||||
method: 'POST',
|
||||
body: currentValues ? JSON.stringify(currentValues) : undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
const mapped = mapApiErrorToActionResult(error);
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Onboarding API functions
|
||||
@@ -709,25 +742,41 @@ export const testAdminUserNotificationPreferences = async (
|
||||
userId: number,
|
||||
routes: Array<Record<string, unknown>>
|
||||
): Promise<import('../types/settings').ActionResult> => {
|
||||
return fetchJSON<import('../types/settings').ActionResult>(
|
||||
`${API_BASE}/admin/users/${userId}/notification-preferences/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ USER_NOTIFICATION_ROUTES: routes }),
|
||||
try {
|
||||
return await fetchJSON<import('../types/settings').ActionResult>(
|
||||
`${API_BASE}/admin/users/${userId}/notification-preferences/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ USER_NOTIFICATION_ROUTES: routes }),
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
const mapped = mapApiErrorToActionResult(error);
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const testSelfNotificationPreferences = async (
|
||||
routes: Array<Record<string, unknown>>
|
||||
): Promise<import('../types/settings').ActionResult> => {
|
||||
return fetchJSON<import('../types/settings').ActionResult>(
|
||||
`${API_BASE}/users/me/notification-preferences/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ USER_NOTIFICATION_ROUTES: routes }),
|
||||
try {
|
||||
return await fetchJSON<import('../types/settings').ActionResult>(
|
||||
`${API_BASE}/users/me/notification-preferences/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ USER_NOTIFICATION_ROUTES: routes }),
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
const mapped = mapApiErrorToActionResult(error);
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export interface SettingsOverrideUserDetail {
|
||||
|
||||
@@ -220,6 +220,7 @@ export interface SettingsResponse {
|
||||
export interface ActionResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
details?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateResult {
|
||||
|
||||
Reference in New Issue
Block a user