fix(custom-widgets): address final v2 review feedback (#6451)
This commit is contained in:
1 parent
df967751f6
commit
4f6e335f72
20 files changed
+186
-92
No files matched your search
@@ -1,8 +1,8 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
getPrivateWorkshopSourceNames,
|
||||
publishWorkshopDefinition,
|
||||
serializeWorkshopDefinition,
|
||||
workshopDefinitionChanged,
|
||||
} from "./workshop-publish-definition";
|
||||
@@ -26,16 +26,27 @@ describe("Workshop publish definition inspection", () => {
|
||||
expect(workshopDefinitionChanged(definition, { ...definition, name: "Updated" })).toBe(true);
|
||||
});
|
||||
|
||||
it("submits the same refreshed export that passed the change check", () => {
|
||||
const source = readFileSync(
|
||||
`${process.cwd()}/apps/nextjs/src/components/workshop/workshop-publish-modal.tsx`,
|
||||
"utf8",
|
||||
);
|
||||
expect(source).toContain("customWidget.export.useQuery");
|
||||
expect(source).toContain("await definition.refetch()");
|
||||
expect(source).toContain("workshopDefinitionChanged(inspectedDefinition, refreshed.data)");
|
||||
expect(source).toContain("content: serializeWorkshopDefinition(refreshed.data)");
|
||||
expect(source).toMatch(/disabled=\{[\s\S]*!definition\.data[\s\S]*definition\.isError/u);
|
||||
expect(serializeWorkshopDefinition(definition)).toBe(JSON.stringify(definition));
|
||||
it("blocks publishing when the definition changes after inspection", async () => {
|
||||
const publish = vi.fn(async () => undefined);
|
||||
await expect(
|
||||
publishWorkshopDefinition({
|
||||
inspectedDefinition: definition,
|
||||
refetchDefinition: async () => ({ ...definition, name: "Updated" }),
|
||||
publish,
|
||||
}),
|
||||
).resolves.toBe("changed");
|
||||
expect(publish).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("publishes the same refreshed export that passed the change check", async () => {
|
||||
const publish = vi.fn(async () => undefined);
|
||||
await expect(
|
||||
publishWorkshopDefinition({
|
||||
inspectedDefinition: definition,
|
||||
refetchDefinition: async () => definition,
|
||||
publish,
|
||||
}),
|
||||
).resolves.toBe("published");
|
||||
expect(publish).toHaveBeenCalledWith(serializeWorkshopDefinition(definition));
|
||||
});
|
||||
});
|
||||
@@ -11,6 +11,22 @@ export const serializeWorkshopDefinition = (definition: unknown): string => {
|
||||
export const workshopDefinitionChanged = (previous: unknown, current: unknown) =>
|
||||
serializeWorkshopDefinition(previous) !== serializeWorkshopDefinition(current);
|
||||
|
||||
export async function publishWorkshopDefinition({
|
||||
inspectedDefinition,
|
||||
refetchDefinition,
|
||||
publish,
|
||||
}: {
|
||||
inspectedDefinition: unknown;
|
||||
refetchDefinition: () => Promise<unknown | undefined>;
|
||||
publish: (content: string) => Promise<unknown>;
|
||||
}) {
|
||||
const refreshedDefinition = await refetchDefinition();
|
||||
if (refreshedDefinition === undefined) return "unavailable" as const;
|
||||
if (workshopDefinitionChanged(inspectedDefinition, refreshedDefinition)) return "changed" as const;
|
||||
await publish(serializeWorkshopDefinition(refreshedDefinition));
|
||||
return "published" as const;
|
||||
}
|
||||
|
||||
export const getPrivateWorkshopSourceNames = (definition: PublishableWorkshopDefinition | undefined) =>
|
||||
Object.entries(definition?.sources ?? {}).flatMap(([sourceId, source]) =>
|
||||
source.networkScope === "public" ? [] : [source.name ?? sourceId],
|
||||
|
||||
@@ -12,8 +12,8 @@ import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { createWorkshopClient } from "./workshop-client";
|
||||
import {
|
||||
getPrivateWorkshopSourceNames,
|
||||
publishWorkshopDefinition,
|
||||
serializeWorkshopDefinition,
|
||||
workshopDefinitionChanged,
|
||||
} from "./workshop-publish-definition";
|
||||
|
||||
export function WorkshopPublishModal({
|
||||
@@ -60,22 +60,26 @@ export function WorkshopPublishModal({
|
||||
try {
|
||||
if (!definition.data) throw new Error(t("publish.error"));
|
||||
const inspectedDefinition = definition.data;
|
||||
const refreshed = await definition.refetch();
|
||||
if (!refreshed.data) throw new Error(t("publish.error"));
|
||||
if (workshopDefinitionChanged(inspectedDefinition, refreshed.data)) {
|
||||
const result = await publishWorkshopDefinition({
|
||||
inspectedDefinition,
|
||||
refetchDefinition: async () => (await definition.refetch()).data,
|
||||
publish: (content) =>
|
||||
createSubmission.mutateAsync({
|
||||
input: {
|
||||
type: "customWidget",
|
||||
title,
|
||||
description,
|
||||
content,
|
||||
},
|
||||
screenshots,
|
||||
}),
|
||||
});
|
||||
if (result === "unavailable") throw new Error(t("publish.error"));
|
||||
if (result === "changed") {
|
||||
setSourceUrlsReviewed(false);
|
||||
setError(t("publish.error"));
|
||||
setError(t("publish.definitionChanged"));
|
||||
return;
|
||||
}
|
||||
await createSubmission.mutateAsync({
|
||||
input: {
|
||||
type: "customWidget",
|
||||
title,
|
||||
description,
|
||||
content: serializeWorkshopDefinition(refreshed.data),
|
||||
},
|
||||
screenshots,
|
||||
});
|
||||
setPublished(true);
|
||||
} catch (cause) {
|
||||
setError(cause instanceof Error ? cause.message : t("publish.error"));
|
||||
|
||||
Reference in new issue
Block a user