refactor(custom-widgets): extract domain package
This commit is contained in:
167 files changed
+12282
-10033
No files matched your search
@@ -1,51 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
export interface CustomJsxRuntimeContextValue {
|
||||
/** The placed board item used for all authorization decisions. */
|
||||
import { fetchApi, clientApi } from "@homarr/api/client";
|
||||
import type {
|
||||
CustomJsxRequestCapability,
|
||||
CustomWidgetRuntimeMessages,
|
||||
CustomWidgetRuntimePort,
|
||||
} from "@homarr/custom-widgets/runtime";
|
||||
import { CustomWidgetRuntimeProvider } from "@homarr/custom-widgets/runtime";
|
||||
import { useConfirmModal } from "@homarr/modals";
|
||||
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
interface WidgetDefinitionProviderProps {
|
||||
itemId?: string;
|
||||
/** Kept temporarily for display-only v1 templates. Never used for network authorization. */
|
||||
definitionId?: string;
|
||||
/** Short-lived, user-bound session used only by the admin authoring preview. */
|
||||
previewSessionId?: string;
|
||||
previewLiveActions?: boolean;
|
||||
isEditMode: boolean;
|
||||
isEditMode?: boolean;
|
||||
requestCapabilities?: readonly CustomJsxRequestCapability[];
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export interface CustomJsxRequestCapability {
|
||||
id: string;
|
||||
kind: "query" | "action";
|
||||
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
||||
minimumBoardPermission: "view" | "modify" | "full";
|
||||
}
|
||||
|
||||
const CustomJsxRuntimeContext = createContext<CustomJsxRuntimeContextValue>({ isEditMode: false });
|
||||
|
||||
export function WidgetDefinitionProvider({
|
||||
itemId,
|
||||
definitionId,
|
||||
previewSessionId,
|
||||
previewLiveActions = false,
|
||||
isEditMode = false,
|
||||
requestCapabilities = [],
|
||||
children,
|
||||
}: CustomJsxRuntimeContextValue & { children: ReactNode }) {
|
||||
export function WidgetDefinitionProvider(props: WidgetDefinitionProviderProps) {
|
||||
const t = useScopedI18n("widget.customApi.customJsx");
|
||||
const utils = clientApi.useUtils();
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
const messages: CustomWidgetRuntimeMessages = {
|
||||
migrationRequired: t("migrationRequired"),
|
||||
unsavedPreview: t("unsavedPreview"),
|
||||
invalidParams: t("invalidParams"),
|
||||
loadRequest: t("loadRequest"),
|
||||
requestFailed: t("requestFailed"),
|
||||
loading: t("loading"),
|
||||
retry: t("retry"),
|
||||
widgetItemUnavailable: t("widgetItemUnavailable"),
|
||||
actionsDisabledEditMode: t("actionsDisabledEditMode"),
|
||||
actionSimulated: t("actionSimulated"),
|
||||
actionCompleted: t("actionCompleted"),
|
||||
confirmDelete: t("confirmDelete"),
|
||||
toggle: t("toggle"),
|
||||
refresh: t("refresh"),
|
||||
};
|
||||
const port: CustomWidgetRuntimePort = {
|
||||
query: async (input, signal) => {
|
||||
if (input.itemId) {
|
||||
return fetchApi.widget.customApi.queryRequest.query(
|
||||
{ itemId: input.itemId, requestId: input.requestId, params: input.params },
|
||||
{ signal },
|
||||
);
|
||||
}
|
||||
return fetchApi.customWidget.previewQuery.query(
|
||||
{ sessionId: input.previewSessionId ?? "", requestId: input.requestId, params: input.params },
|
||||
{ signal },
|
||||
);
|
||||
},
|
||||
executeAction: (input) =>
|
||||
input.itemId
|
||||
? fetchApi.widget.customApi.executeAction.mutate({
|
||||
itemId: input.itemId,
|
||||
requestId: input.requestId,
|
||||
params: input.params,
|
||||
confirmed: input.confirmed,
|
||||
})
|
||||
: fetchApi.customWidget.previewAction.mutate({
|
||||
sessionId: input.previewSessionId ?? "",
|
||||
requestId: input.requestId,
|
||||
params: input.params,
|
||||
confirmed: input.confirmed,
|
||||
}),
|
||||
invalidate: async ({ itemId, previewSessionId, targets }) => {
|
||||
if (previewSessionId) {
|
||||
await utils.customWidget.previewQuery.invalidate();
|
||||
return;
|
||||
}
|
||||
if (!itemId) return;
|
||||
const tasks: Promise<unknown>[] = [];
|
||||
if (targets.includes("parent")) tasks.push(utils.widget.customApi.getData.invalidate({ itemId }));
|
||||
if (targets.some((target) => target !== "parent")) tasks.push(utils.widget.customApi.queryRequest.invalidate());
|
||||
await Promise.all(tasks);
|
||||
},
|
||||
confirm: ({ title, message }) =>
|
||||
new Promise((resolve) => {
|
||||
openConfirmModal({ title, children: message, onConfirm: () => resolve(true), onCancel: () => resolve(false) });
|
||||
}),
|
||||
notify: ({ kind, ...notification }) =>
|
||||
kind === "success" ? showSuccessNotification(notification) : showErrorNotification(notification),
|
||||
};
|
||||
return (
|
||||
<CustomJsxRuntimeContext.Provider
|
||||
value={{ itemId, definitionId, previewSessionId, previewLiveActions, isEditMode, requestCapabilities }}
|
||||
<CustomWidgetRuntimeProvider
|
||||
itemId={props.itemId}
|
||||
definitionId={props.definitionId}
|
||||
previewSessionId={props.previewSessionId}
|
||||
previewLiveActions={props.previewLiveActions}
|
||||
isEditMode={props.isEditMode ?? false}
|
||||
requestCapabilities={props.requestCapabilities ?? []}
|
||||
port={port}
|
||||
messages={messages}
|
||||
>
|
||||
{children}
|
||||
</CustomJsxRuntimeContext.Provider>
|
||||
{props.children}
|
||||
</CustomWidgetRuntimeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useWidgetDefinitionId(): string {
|
||||
return useContext(CustomJsxRuntimeContext).definitionId ?? "";
|
||||
}
|
||||
|
||||
export function useCustomJsxRuntime(): CustomJsxRuntimeContextValue {
|
||||
return useContext(CustomJsxRuntimeContext);
|
||||
}
|
||||
Reference in new issue
Block a user