mirror of
https://github.com/ajnart/homarr.git
synced 2026-02-27 17:00:54 +01:00
* feat: add pi hole summary integration * feat: add pi hole summary widget * fix: type issues with integrations and integrationIds * feat: add middleware for integrations and improve cache redis channel * feat: add error boundary for widgets * fix: broken lock file * fix: format format issues * fix: typecheck issue * fix: deepsource issues * fix: widget sandbox without error boundary * chore: address pull request feedback * chore: remove todo comment and created issue * fix: format issues * fix: deepsource issue
101 lines
3.1 KiB
TypeScript
101 lines
3.1 KiB
TypeScript
import type { LoaderComponent } from "next/dynamic";
|
|
import type { DefaultErrorData } from "@trpc/server/unstable-core-do-not-import";
|
|
|
|
import type { IntegrationKind, WidgetKind } from "@homarr/definitions";
|
|
import type { stringOrTranslation } from "@homarr/translation";
|
|
import type { TablerIcon } from "@homarr/ui";
|
|
|
|
import type { WidgetImports } from ".";
|
|
import type { inferOptionsFromDefinition, WidgetOptionsRecord } from "./options";
|
|
|
|
type ServerDataLoader<TKind extends WidgetKind> = () => Promise<{
|
|
default: (props: WidgetProps<TKind>) => Promise<Record<string, unknown>>;
|
|
}>;
|
|
|
|
const createWithDynamicImport =
|
|
<
|
|
TKind extends WidgetKind,
|
|
TDefinition extends WidgetDefinition,
|
|
TServerDataLoader extends ServerDataLoader<TKind> | undefined,
|
|
>(
|
|
kind: TKind,
|
|
definition: TDefinition,
|
|
serverDataLoader: TServerDataLoader,
|
|
) =>
|
|
(
|
|
componentLoader: () => LoaderComponent<
|
|
WidgetComponentProps<TKind> &
|
|
(TServerDataLoader extends ServerDataLoader<TKind>
|
|
? {
|
|
serverData: Awaited<ReturnType<Awaited<ReturnType<TServerDataLoader>>["default"]>>;
|
|
}
|
|
: never)
|
|
>,
|
|
) => ({
|
|
definition: {
|
|
...definition,
|
|
kind,
|
|
},
|
|
kind,
|
|
serverDataLoader,
|
|
componentLoader,
|
|
});
|
|
|
|
const createWithServerData =
|
|
<TKind extends WidgetKind, TDefinition extends WidgetDefinition>(kind: TKind, definition: TDefinition) =>
|
|
<TServerDataLoader extends ServerDataLoader<TKind>>(serverDataLoader: TServerDataLoader) => ({
|
|
definition: {
|
|
...definition,
|
|
kind,
|
|
},
|
|
kind,
|
|
serverDataLoader,
|
|
withDynamicImport: createWithDynamicImport(kind, definition, serverDataLoader),
|
|
});
|
|
|
|
export const createWidgetDefinition = <TKind extends WidgetKind, TDefinition extends WidgetDefinition>(
|
|
kind: TKind,
|
|
definition: TDefinition,
|
|
) => ({
|
|
withServerData: createWithServerData(kind, definition),
|
|
withDynamicImport: createWithDynamicImport(kind, definition, undefined),
|
|
});
|
|
|
|
export interface WidgetDefinition {
|
|
icon: TablerIcon;
|
|
supportedIntegrations?: IntegrationKind[];
|
|
options: WidgetOptionsRecord;
|
|
errors?: Partial<
|
|
Record<
|
|
DefaultErrorData["code"],
|
|
{
|
|
icon: TablerIcon;
|
|
message: stringOrTranslation;
|
|
}
|
|
>
|
|
>;
|
|
}
|
|
|
|
export interface WidgetProps<TKind extends WidgetKind> {
|
|
options: inferOptionsFromDefinition<WidgetOptionsRecordOf<TKind>>;
|
|
integrationIds: string[];
|
|
}
|
|
|
|
type inferServerDataForKind<TKind extends WidgetKind> = WidgetImports[TKind] extends {
|
|
serverDataLoader: ServerDataLoader<TKind>;
|
|
}
|
|
? Awaited<ReturnType<Awaited<ReturnType<WidgetImports[TKind]["serverDataLoader"]>>["default"]>>
|
|
: undefined;
|
|
|
|
export type WidgetComponentProps<TKind extends WidgetKind> = WidgetProps<TKind> & {
|
|
serverData?: inferServerDataForKind<TKind>;
|
|
} & {
|
|
itemId: string | undefined; // undefined when in preview mode
|
|
boardId: string | undefined; // undefined when in preview mode
|
|
isEditMode: boolean;
|
|
width: number;
|
|
height: number;
|
|
};
|
|
|
|
export type WidgetOptionsRecordOf<TKind extends WidgetKind> = WidgetImports[TKind]["definition"]["options"];
|