Add system updates page to admin section

Add a new API endpoint and UI section for checking system updates, including internationalized locale strings and necessary dependency updates.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 1e6de894-7c78-4557-b01a-a2c1c01f4155
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/1WKAcHk
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
riyadhafraa
2026-05-17 14:59:36 +00:00
parent 191e072353
commit b5efd9eb12
12 changed files with 568 additions and 3 deletions
@@ -9,6 +9,32 @@ export interface HealthStatus {
status: string;
}
export interface SystemVersionInfo {
version: string;
build: string;
}
export type SystemVersionResponseStatus =
(typeof SystemVersionResponseStatus)[keyof typeof SystemVersionResponseStatus];
export const SystemVersionResponseStatus = {
"up-to-date": "up-to-date",
"update-available": "update-available",
"not-configured": "not-configured",
error: "error",
} as const;
export interface SystemVersionResponse {
current: SystemVersionInfo;
latest: SystemVersionInfo | null;
status: SystemVersionResponseStatus;
/** @nullable */
errorMessage: string | null;
/** @nullable */
checkedAt: string | null;
configured: boolean;
}
export interface ErrorResponse {
error: string;
}
+81
View File
@@ -110,6 +110,7 @@ import type {
ServiceOrder,
SubscribePushBody,
SuccessResponse,
SystemVersionResponse,
UnsubscribePushBody,
UpdateAppBody,
UpdateAppSettingsBody,
@@ -217,6 +218,86 @@ export function useHealthCheck<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Returns the local build version (read from version.json embedded at
build time) and, if `LATEST_VERSION_URL` is configured on the
server, the latest published version fetched from that URL. Admin
only. Never performs an update — pure read.
* @summary Get current and latest system version
*/
export const getGetSystemVersionUrl = () => {
return `/api/system/version`;
};
export const getSystemVersion = async (
options?: RequestInit,
): Promise<SystemVersionResponse> => {
return customFetch<SystemVersionResponse>(getGetSystemVersionUrl(), {
...options,
method: "GET",
});
};
export const getGetSystemVersionQueryKey = () => {
return [`/api/system/version`] as const;
};
export const getGetSystemVersionQueryOptions = <
TData = Awaited<ReturnType<typeof getSystemVersion>>,
TError = ErrorType<unknown>,
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getSystemVersion>>,
TError,
TData
>;
request?: SecondParameter<typeof customFetch>;
}) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetSystemVersionQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getSystemVersion>>
> = ({ signal }) => getSystemVersion({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getSystemVersion>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetSystemVersionQueryResult = NonNullable<
Awaited<ReturnType<typeof getSystemVersion>>
>;
export type GetSystemVersionQueryError = ErrorType<unknown>;
/**
* @summary Get current and latest system version
*/
export function useGetSystemVersion<
TData = Awaited<ReturnType<typeof getSystemVersion>>,
TError = ErrorType<unknown>,
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getSystemVersion>>,
TError,
TData
>;
request?: SecondParameter<typeof customFetch>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetSystemVersionQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Register a new user
*/
+58
View File
@@ -30,6 +30,8 @@ tags:
description: Object storage upload and serving endpoints
- name: audit
description: Admin audit log
- name: system
description: System metadata (version, update availability)
paths:
/healthz:
@@ -45,6 +47,24 @@ paths:
schema:
$ref: "#/components/schemas/HealthStatus"
/system/version:
get:
operationId: getSystemVersion
tags: [system]
summary: Get current and latest system version
description: |
Returns the local build version (read from version.json embedded at
build time) and, if `LATEST_VERSION_URL` is configured on the
server, the latest published version fetched from that URL. Admin
only. Never performs an update — pure read.
responses:
"200":
description: System version info
content:
application/json:
schema:
$ref: "#/components/schemas/SystemVersionResponse"
# Auth
/auth/register:
post:
@@ -2927,6 +2947,44 @@ components:
required:
- status
SystemVersionInfo:
type: object
properties:
version:
type: string
build:
type: string
required:
- version
- build
SystemVersionResponse:
type: object
properties:
current:
$ref: "#/components/schemas/SystemVersionInfo"
latest:
oneOf:
- $ref: "#/components/schemas/SystemVersionInfo"
- type: "null"
status:
type: string
enum: [up-to-date, update-available, not-configured, error]
errorMessage:
type: ["string", "null"]
checkedAt:
type: ["string", "null"]
format: date-time
configured:
type: boolean
required:
- current
- latest
- status
- errorMessage
- checkedAt
- configured
ErrorResponse:
type: object
properties:
+31
View File
@@ -14,6 +14,37 @@ export const HealthCheckResponse = zod.object({
status: zod.string(),
});
/**
* Returns the local build version (read from version.json embedded at
build time) and, if `LATEST_VERSION_URL` is configured on the
server, the latest published version fetched from that URL. Admin
only. Never performs an update — pure read.
* @summary Get current and latest system version
*/
export const GetSystemVersionResponse = zod.object({
current: zod.object({
version: zod.string(),
build: zod.string(),
}),
latest: zod.union([
zod.object({
version: zod.string(),
build: zod.string(),
}),
zod.null(),
]),
status: zod.enum([
"up-to-date",
"update-available",
"not-configured",
"error",
]),
errorMessage: zod.string().nullable(),
checkedAt: zod.coerce.date().nullable(),
configured: zod.boolean(),
});
/**
* @summary Register a new user
*/