fix: harden v2 custom widgets and Workshop (#6480)
This commit is contained in:
1 parent
e8a2c87c2d
commit
557ebe0a2f
138 files changed
+5151
-1976
No files matched your search
@@ -10,6 +10,7 @@ import { WidgetCustomWidgetSelectInput } from "./widget-custom-widget-select-inp
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
available: [] as Array<Record<string, unknown>>,
|
||||
permissions: ["admin"] as string[],
|
||||
setFieldValue: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -62,6 +63,10 @@ vi.mock("@homarr/api/client", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@homarr/auth/client", () => ({
|
||||
useSession: () => ({ data: { user: { permissions: mocks.permissions } } }),
|
||||
}));
|
||||
|
||||
vi.mock("@homarr/boards/context", () => ({
|
||||
useOptionalBoard: () => ({ id: "board-1" }),
|
||||
}));
|
||||
@@ -70,8 +75,9 @@ vi.mock("@homarr/translation/client", () => ({
|
||||
useScopedI18n: () => (key: string) =>
|
||||
({
|
||||
migrationRequired: "Migration required",
|
||||
migrationDescription: "Copy its redacted prompt to an LLM and import the returned v2 JSON.",
|
||||
migrationDescription: "Copy its redacted prompt to an LLM, then paste the single JSON response into Homarr.",
|
||||
manageMigration: "Open Manage custom widgets",
|
||||
contactAdmin: "Contact an administrator.",
|
||||
})[key] ?? key,
|
||||
}));
|
||||
|
||||
@@ -90,6 +96,7 @@ let host: HTMLDivElement;
|
||||
beforeEach(() => {
|
||||
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
mocks.available = [];
|
||||
mocks.permissions = ["admin"];
|
||||
mocks.setFieldValue.mockReset();
|
||||
host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
@@ -137,4 +144,26 @@ describe("custom widget picker migration status", () => {
|
||||
expect(host.textContent).toContain("Copy its redacted prompt to an LLM");
|
||||
expect(host.querySelector('a[href="/manage/custom-widgets"]')?.textContent).toBe("Open Manage custom widgets");
|
||||
});
|
||||
|
||||
it("tells non-admins to contact an administrator without linking management", async () => {
|
||||
mocks.permissions = ["board-modify-all"];
|
||||
mocks.available = [
|
||||
{
|
||||
id: "legacy-widget",
|
||||
name: "Legacy status",
|
||||
description: "Old API widget",
|
||||
iconUrl: null,
|
||||
sources: [],
|
||||
requestCapabilities: [],
|
||||
defaultOptions: {},
|
||||
updatedAt: new Date(0),
|
||||
migrationRequired: true,
|
||||
},
|
||||
];
|
||||
|
||||
await renderInput();
|
||||
|
||||
expect(host.textContent).toContain("Contact an administrator.");
|
||||
expect(host.querySelector('a[href="/manage/custom-widgets"]')).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { IconAlertTriangle, IconApi } from "@tabler/icons-react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
import { useOptionalBoard } from "@homarr/boards/context";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { Link } from "@homarr/ui";
|
||||
@@ -32,6 +33,8 @@ export const WidgetCustomWidgetSelectInput = ({
|
||||
}: CommonWidgetInputProps<"customWidgetSelect">) => {
|
||||
const t = useWidgetInputTranslation(kind, property);
|
||||
const labels = useScopedI18n("widget.customApi.picker");
|
||||
const { data: session } = useSession();
|
||||
const isAdmin = session?.user.permissions.includes("admin") ?? false;
|
||||
const form = useFormContext();
|
||||
const board = useOptionalBoard();
|
||||
const currentValue = form.values.options[property] as string;
|
||||
@@ -153,9 +156,15 @@ export const WidgetCustomWidgetSelectInput = ({
|
||||
title={labels("migrationRequired")}
|
||||
>
|
||||
<Text size="xs">{labels("migrationDescription")}</Text>
|
||||
<Anchor component={Link} href="/manage/custom-widgets" size="xs" fw={600}>
|
||||
{labels("manageMigration")}
|
||||
</Anchor>
|
||||
{isAdmin ? (
|
||||
<Anchor component={Link} href="/manage/custom-widgets" size="xs" fw={600}>
|
||||
{labels("manageMigration")}
|
||||
</Anchor>
|
||||
) : (
|
||||
<Text size="xs" fw={600}>
|
||||
{labels("contactAdmin")}
|
||||
</Text>
|
||||
)}
|
||||
</Alert>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
Reference in new issue
Block a user