69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
import { PERMS } from "@/lib/permission-slugs";
|
|
import { authorizeHousekeeping } from "../../foundation/authorization";
|
|
import {
|
|
anyCapability,
|
|
fail,
|
|
type HousekeepingCapabilityContext,
|
|
type HousekeepingWidgetDefinition,
|
|
ok,
|
|
} from "../../foundation/contracts";
|
|
import { studioOperationRepository } from "./queries/studio";
|
|
|
|
export const HOTEL_WIDGET_IDS = ["hotel.studio.active-operations"] as const;
|
|
|
|
type HotelWidgetLoader = (
|
|
context: HousekeepingCapabilityContext,
|
|
signal: AbortSignal,
|
|
) => Promise<Readonly<Record<string, number>>>;
|
|
|
|
export interface HotelWidgetAdapters {
|
|
readonly activeOperations: HotelWidgetLoader;
|
|
}
|
|
|
|
export function createHotelWidgets(
|
|
adapters: HotelWidgetAdapters,
|
|
): readonly HousekeepingWidgetDefinition[] {
|
|
const capability = anyCapability(PERMS.ASSETS_IMPORT, PERMS.CATALOG_EDIT);
|
|
return [
|
|
{
|
|
id: "hotel.studio.active-operations",
|
|
owner: "hotel",
|
|
kind: "mandatory",
|
|
capability,
|
|
async load(context, signal) {
|
|
const authorization = authorizeHousekeeping(context, capability);
|
|
if (!authorization.ok) return authorization;
|
|
try {
|
|
if (signal.aborted) throw new Error("aborted Hotel widget");
|
|
return ok(
|
|
await adapters.activeOperations(context, signal),
|
|
authorization.correlationId,
|
|
);
|
|
} catch {
|
|
return fail(
|
|
"DEPENDENCY_UNAVAILABLE",
|
|
"errors.housekeeping.dependencyUnavailable",
|
|
authorization.correlationId,
|
|
);
|
|
}
|
|
},
|
|
},
|
|
];
|
|
}
|
|
|
|
export const HOTEL_WIDGETS = createHotelWidgets({
|
|
async activeOperations(_context, signal) {
|
|
if (signal.aborted) throw new Error("aborted Hotel operations widget");
|
|
const { items } = await studioOperationRepository.list({
|
|
pageSize: 100,
|
|
offset: 0,
|
|
});
|
|
return {
|
|
queued: items.filter((item) => item.phase === "queued").length,
|
|
running: items.filter((item) => item.phase === "running").length,
|
|
partial: items.filter((item) => item.phase === "partial").length,
|
|
failed: items.filter((item) => item.phase === "failed").length,
|
|
};
|
|
},
|
|
});
|