Route kebab Customize through the prefilled policy wizard so existing methods and values can be renamed, reordered, and kept in that field order on the card after Finalize.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilallo
2026-08-21 13:51:37 -06:00
co-authored by Cursor
parent e9951f260b
commit 4006fe5c6c
31 changed files with 3062 additions and 1530 deletions
@@ -214,4 +214,39 @@ describe("applyFinalReviewChipEditPatch", () => {
"1": { meaning: "m2", signals: "s2" },
});
});
it("merges customMethodCardFieldBlocksById for a core values patch", () => {
const state: CreateFlowState = {
customMethodCardFieldBlocksById: {
other: [
{
kind: "text",
id: "x",
blockTitle: "T",
placeholderText: "keep",
},
],
},
};
const patch: FinalReviewChipEditPatch = {
groupKey: "coreValues",
overrideKey: "1",
value: { meaning: "m", signals: "s" },
customMethodCardFieldBlocks: [
{
kind: "text",
id: "facet-meaning",
blockTitle: "Meaning",
placeholderText: "m",
},
],
};
const result = applyFinalReviewChipEditPatch(state, patch);
expect(result.customMethodCardFieldBlocksById).toEqual({
other: state.customMethodCardFieldBlocksById?.other,
"1": patch.customMethodCardFieldBlocks,
});
});
});
+278
View File
@@ -0,0 +1,278 @@
import { describe, expect, it } from "vitest";
import {
buildMethodCardWizardInitialValues,
coreValueDetailsFromWizardFieldBlocks,
facetDetailsToWizardFieldBlocks,
} from "../../lib/create/methodCardWizardPrefill";
import type { CustomMethodCardFieldBlock } from "../../lib/create/customMethodCardFieldBlocks";
const cardId = "signal";
const blocks: CustomMethodCardFieldBlock[] = [
{ kind: "text", id: "b1", blockTitle: "Notes", placeholderText: "…" },
];
const commHeadings = {
corePrinciple: "Core Principle & Scope",
logisticsAdmin: "Logistics, Admin & Norms",
codeOfConduct: "Code of Conduct",
};
describe("buildMethodCardWizardInitialValues", () => {
it("uses fallback title and description when meta is missing", () => {
expect(
buildMethodCardWizardInitialValues({
cardId,
fallbackTitle: "Signal",
fallbackDescription: "Encrypted messaging.",
meta: {},
persistedBlocks: {},
draftFieldBlocks: null,
}),
).toEqual({
title: "Signal",
description: "Encrypted messaging.",
fieldBlocks: [],
});
});
it("maps facet body fields onto wizard blocks when none exist yet", () => {
expect(
buildMethodCardWizardInitialValues({
cardId,
fallbackTitle: "Signal",
fallbackDescription: "Encrypted messaging.",
meta: {},
persistedBlocks: {},
draftFieldBlocks: null,
facetPrefill: {
group: "communication",
draft: {
corePrinciple: "Privacy first.",
logisticsAdmin: "Admins steward access.",
codeOfConduct: "No leaks.",
},
headings: commHeadings,
},
}).fieldBlocks,
).toEqual([
{
kind: "text",
id: "facet-corePrinciple",
blockTitle: "Core Principle & Scope",
placeholderText: "Privacy first.",
},
{
kind: "text",
id: "facet-logisticsAdmin",
blockTitle: "Logistics, Admin & Norms",
placeholderText: "Admins steward access.",
},
{
kind: "text",
id: "facet-codeOfConduct",
blockTitle: "Code of Conduct",
placeholderText: "No leaks.",
},
]);
});
it("prefers persisted meta title and description over fallbacks", () => {
expect(
buildMethodCardWizardInitialValues({
cardId,
fallbackTitle: "Signal",
fallbackDescription: "Encrypted messaging.",
meta: {
[cardId]: { label: "Our Signal", supportText: "Private ops." },
},
persistedBlocks: { [cardId]: blocks },
draftFieldBlocks: null,
}),
).toEqual({
title: "Our Signal",
description: "Private ops.",
fieldBlocks: blocks,
});
});
it("overlays current facet field values onto matching persisted blocks", () => {
const persisted: CustomMethodCardFieldBlock[] = [
{
kind: "text",
id: "facet-corePrinciple",
blockTitle: "Core Principle & Scope",
placeholderText: "Stale principle",
},
{
kind: "text",
id: "extra-notes",
blockTitle: "Notes",
placeholderText: "keep",
},
];
expect(
buildMethodCardWizardInitialValues({
cardId,
fallbackTitle: "Signal",
fallbackDescription: "Encrypted messaging.",
meta: {},
persistedBlocks: { [cardId]: persisted },
draftFieldBlocks: null,
facetPrefill: {
group: "communication",
draft: {
corePrinciple: "Updated principle",
logisticsAdmin: "Updated logistics",
codeOfConduct: "Updated coc",
},
headings: commHeadings,
},
}).fieldBlocks,
).toEqual([
{
kind: "text",
id: "facet-corePrinciple",
blockTitle: "Core Principle & Scope",
placeholderText: "Updated principle",
},
{
kind: "text",
id: "extra-notes",
blockTitle: "Notes",
placeholderText: "keep",
},
{
kind: "text",
id: "facet-logisticsAdmin",
blockTitle: "Logistics, Admin & Norms",
placeholderText: "Updated logistics",
},
{
kind: "text",
id: "facet-codeOfConduct",
blockTitle: "Code of Conduct",
placeholderText: "Updated coc",
},
]);
});
it("prefers in-modal field-block drafts over persisted blocks", () => {
const draft: CustomMethodCardFieldBlock[] = [
{ kind: "proportion", id: "p1", blockTitle: "Share", defaultPercent: 40 },
];
expect(
buildMethodCardWizardInitialValues({
cardId,
fallbackTitle: "Signal",
fallbackDescription: "Encrypted messaging.",
meta: {
[cardId]: { label: "Our Signal", supportText: "Private ops." },
},
persistedBlocks: { [cardId]: blocks },
draftFieldBlocks: draft,
}).fieldBlocks,
).toEqual(draft);
});
});
describe("facetDetailsToWizardFieldBlocks", () => {
it("returns no blocks when facet copy is empty", () => {
expect(
facetDetailsToWizardFieldBlocks({
group: "communication",
draft: {
corePrinciple: " ",
logisticsAdmin: "",
codeOfConduct: "",
},
headings: commHeadings,
}),
).toEqual([]);
});
it("maps decision scope chips to a badge block", () => {
const blocksOut = facetDetailsToWizardFieldBlocks({
group: "decisionApproaches",
draft: {
corePrinciple: "Momentum.",
applicableScope: ["Daily Operations"],
selectedApplicableScope: [],
stepByStepInstructions: "Post a deadline.",
consensusLevel: 100,
objectionsDeadlocks: "Any member can block.",
},
headings: {
corePrinciple: "Core Principle",
applicableScope: "Applicable Scope",
stepByStepInstructions: "Step-by-Step Instructions",
consensusLevel: "Consensus Level",
objectionsDeadlocks: "Objections & Deadlocks",
},
});
expect(blocksOut.find((b) => b.kind === "badges")).toMatchObject({
kind: "badges",
blockTitle: "Applicable Scope",
options: ["Daily Operations"],
});
expect(blocksOut.find((b) => b.kind === "proportion")).toMatchObject({
defaultPercent: 100,
});
});
it("maps core value meaning and signals onto text blocks", () => {
expect(
facetDetailsToWizardFieldBlocks({
group: "coreValues",
draft: {
meaning: "Everyone can join.",
signals: "Inaccessible venues.",
},
headings: {
meaning: "What does this value mean to your group?",
signals: "Signals of Violation",
},
}),
).toEqual([
{
kind: "text",
id: "facet-meaning",
blockTitle: "What does this value mean to your group?",
placeholderText: "Everyone can join.",
},
{
kind: "text",
id: "facet-signals",
blockTitle: "Signals of Violation",
placeholderText: "Inaccessible venues.",
},
]);
});
});
describe("coreValueDetailsFromWizardFieldBlocks", () => {
it("reads meaning and signals from facet block ids", () => {
expect(
coreValueDetailsFromWizardFieldBlocks(
[
{
kind: "text",
id: "facet-meaning",
blockTitle: "Meaning",
placeholderText: "Updated meaning",
},
{
kind: "text",
id: "facet-signals",
blockTitle: "Signals",
placeholderText: "Updated signals",
},
],
{ meaning: "old m", signals: "old s", supportText: "keep" },
),
).toEqual({
meaning: "Updated meaning",
signals: "Updated signals",
supportText: "keep",
});
});
});
@@ -113,4 +113,16 @@ describe("usesWizardFieldBlocksModalBody", () => {
}),
).toBe(true);
});
it("is true for catalog ids when the wizard draft has blocks", () => {
expect(
usesWizardFieldBlocksModalBody({
methodId: "signal",
meta: {},
fieldBlocksById: {},
modalEditUnlocked: false,
draftFieldBlocks: blocks,
}),
).toBe(true);
});
});