Skip to content

Commit 0d84a87

Browse files
rafavallsclaude
andcommitted
add discard all page variants button with confirmation dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9f6f841 commit 0d84a87

1 file changed

Lines changed: 140 additions & 1 deletion

File tree

web/tools/file-explorer/index.tsx

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,7 @@ interface CmsPanelProps {
15511551
onDuplicateVariant: (variantIdx: number) => void;
15521552
onRemoveVariant: (variantIdx: number) => void;
15531553
onRemoveAllVariants: () => void;
1554+
onRemoveAllPageVariants?: () => void;
15541555
pageVariants?: GetPageSectionsOutput["pageVariants"];
15551556
selectedPageVariant?: number | null;
15561557
onSelectPageVariant?: (idx: number) => void;
@@ -1605,6 +1606,7 @@ function CmsPanel({
16051606
onDuplicateVariant,
16061607
onRemoveVariant,
16071608
onRemoveAllVariants,
1609+
onRemoveAllPageVariants,
16081610
pageVariants,
16091611
selectedPageVariant,
16101612
onSelectPageVariant,
@@ -1635,6 +1637,11 @@ function CmsPanel({
16351637
const [variantCardOpen, setVariantCardOpen] = useState<boolean>(
16361638
() => localStorage.getItem("variant-card-open") !== "false",
16371639
);
1640+
1641+
const [discardSectionVariantsConfirm, setDiscardSectionVariantsConfirm] =
1642+
useState(false);
1643+
const [discardPageVariantsConfirm, setDiscardPageVariantsConfirm] =
1644+
useState(false);
16381645
const toggleVariantCard = () => {
16391646
setVariantCardOpen((prev) => {
16401647
const next = !prev;
@@ -1705,6 +1712,7 @@ function CmsPanel({
17051712
: undefined;
17061713

17071714
return (
1715+
<>
17081716
<div
17091717
className="flex h-full w-full flex-col overflow-hidden bg-background transition-colors"
17101718
style={
@@ -1761,7 +1769,7 @@ function CmsPanel({
17611769
actions={
17621770
<button
17631771
type="button"
1764-
onClick={onRemoveAllVariants}
1772+
onClick={() => setDiscardSectionVariantsConfirm(true)}
17651773
className="shrink-0 rounded p-1 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
17661774
title="Remove all variants"
17671775
>
@@ -2059,6 +2067,19 @@ function CmsPanel({
20592067
) : isPageVariantList ? (
20602068
/* ── Page-level variant list ─────────────────────────────── */
20612069
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
2070+
<div className="shrink-0 flex items-center justify-between border-b px-3 py-2">
2071+
<span className="text-xs text-muted-foreground">
2072+
Page variants
2073+
</span>
2074+
<button
2075+
type="button"
2076+
onClick={() => setDiscardPageVariantsConfirm(true)}
2077+
className="shrink-0 rounded p-1 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
2078+
title="Discard all page variants"
2079+
>
2080+
<Trash2 className="h-3.5 w-3.5" />
2081+
</button>
2082+
</div>
20622083
<div className="min-h-0 flex-1 overflow-y-auto p-2">
20632084
<DndContext
20642085
sensors={sensors}
@@ -2299,6 +2320,61 @@ function CmsPanel({
22992320
</div>
23002321
)}
23012322
</div>
2323+
2324+
<AlertDialog
2325+
open={discardSectionVariantsConfirm}
2326+
onOpenChange={setDiscardSectionVariantsConfirm}
2327+
>
2328+
<AlertDialogContent>
2329+
<AlertDialogHeader>
2330+
<AlertDialogTitle>Remove all variants?</AlertDialogTitle>
2331+
<AlertDialogDescription>
2332+
This will remove all variants from this section and keep only the
2333+
default content. This action cannot be undone.
2334+
</AlertDialogDescription>
2335+
</AlertDialogHeader>
2336+
<AlertDialogFooter>
2337+
<AlertDialogCancel>Cancel</AlertDialogCancel>
2338+
<AlertDialogAction
2339+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
2340+
onClick={() => {
2341+
setDiscardSectionVariantsConfirm(false);
2342+
onRemoveAllVariants();
2343+
}}
2344+
>
2345+
Remove all variants
2346+
</AlertDialogAction>
2347+
</AlertDialogFooter>
2348+
</AlertDialogContent>
2349+
</AlertDialog>
2350+
2351+
<AlertDialog
2352+
open={discardPageVariantsConfirm}
2353+
onOpenChange={setDiscardPageVariantsConfirm}
2354+
>
2355+
<AlertDialogContent>
2356+
<AlertDialogHeader>
2357+
<AlertDialogTitle>Discard all page variants?</AlertDialogTitle>
2358+
<AlertDialogDescription>
2359+
This will revert the page to a single version using the default
2360+
variant. All other variants will be permanently removed.
2361+
</AlertDialogDescription>
2362+
</AlertDialogHeader>
2363+
<AlertDialogFooter>
2364+
<AlertDialogCancel>Cancel</AlertDialogCancel>
2365+
<AlertDialogAction
2366+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
2367+
onClick={() => {
2368+
setDiscardPageVariantsConfirm(false);
2369+
onRemoveAllPageVariants?.();
2370+
}}
2371+
>
2372+
Discard all variants
2373+
</AlertDialogAction>
2374+
</AlertDialogFooter>
2375+
</AlertDialogContent>
2376+
</AlertDialog>
2377+
</>
23022378
);
23032379
}
23042380

@@ -4151,6 +4227,66 @@ function FileExplorerWorkspace({
41514227
}, 300);
41524228
};
41534229

4230+
const handleRemoveAllPageVariants = () => {
4231+
const snap = cmsDataRef.current;
4232+
if (!snap?.pageVariants || !app || !userEnv) return;
4233+
4234+
const mv = snap.pageData.sections as Record<string, unknown>;
4235+
const rawVariants = (
4236+
mv.variants as Array<{ value: unknown; rule: Record<string, unknown> }>
4237+
) ?? [];
4238+
4239+
const ALWAYS_TYPES = [
4240+
"website/matchers/always.ts",
4241+
"$live/matchers/MatchAlways.ts",
4242+
];
4243+
const alwaysVariant = rawVariants.find((v) => {
4244+
const rt = (v.rule.__resolveType as string) ?? "";
4245+
return ALWAYS_TYPES.includes(rt) || rt === "";
4246+
});
4247+
const baseValue = alwaysVariant?.value ?? rawVariants[0]?.value ?? [];
4248+
4249+
const updatedPageData = { ...snap.pageData, sections: baseValue };
4250+
4251+
const alwaysDisplayVariant =
4252+
snap.pageVariants.find((pv) => {
4253+
const rt = (pv.rule.__resolveType as string) ?? "";
4254+
return ALWAYS_TYPES.includes(rt) || rt === "";
4255+
}) ?? snap.pageVariants[0];
4256+
4257+
const next: GetPageSectionsOutput = {
4258+
...snap,
4259+
pageData: updatedPageData,
4260+
pageVariants: undefined,
4261+
sections: alwaysDisplayVariant?.sections ?? snap.sections,
4262+
};
4263+
setCmsData(next);
4264+
cmsDataRef.current = next;
4265+
setCmsSelectedPageVariant(null);
4266+
cmsSelectedPageVariantRef.current = null;
4267+
4268+
setCmsAutoSaving(true);
4269+
if (cmsAutoSaveTimerRef.current) clearTimeout(cmsAutoSaveTimerRef.current);
4270+
cmsAutoSaveTimerRef.current = setTimeout(async () => {
4271+
try {
4272+
const result = await app.callServerTool({
4273+
name: "write_file",
4274+
arguments: {
4275+
env: userEnv,
4276+
filepath: next.filePath,
4277+
content: JSON.stringify(updatedPageData, null, 2),
4278+
},
4279+
});
4280+
if (result?.isError) throw new Error("write_file failed");
4281+
setPreviewRefreshKey((k) => k + 1);
4282+
} catch {
4283+
toast.error("Auto-save failed");
4284+
} finally {
4285+
setCmsAutoSaving(false);
4286+
}
4287+
}, 300);
4288+
};
4289+
41544290
const handleCmsSelectSection = (idx: number) => {
41554291
if (!cmsData) return;
41564292
setCmsPanelVisible(true);
@@ -7029,6 +7165,9 @@ function FileExplorerWorkspace({
70297165
onDuplicateVariant={handleDuplicateVariant}
70307166
onRemoveVariant={handleRemoveVariant}
70317167
onRemoveAllVariants={handleRemoveAllVariants}
7168+
onRemoveAllPageVariants={
7169+
handleRemoveAllPageVariants
7170+
}
70327171
pageVariants={cmsData?.pageVariants}
70337172
selectedPageVariant={cmsSelectedPageVariant}
70347173
onSelectPageVariant={handleSelectPageVariant}

0 commit comments

Comments
 (0)