Edit flow configured
This commit is contained in:
+2
-2
@@ -292,8 +292,8 @@ export type MyPublishedRule = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Lists the signed-in user’s published rules (newest first). Returns `null` on
|
||||
* network failure or unauthenticated response.
|
||||
* Lists the signed-in user’s published rules (**last updated first**, stable by id).
|
||||
* Returns `null` on network failure or unauthenticated response.
|
||||
*/
|
||||
export async function fetchMyPublishedRules(): Promise<
|
||||
MyPublishedRule[] | null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Bridges final-review → completed without query strings, and re-opens a rule
|
||||
* from profile (`/create/completed?ruleId=…`) after GET /api/rules/[id].
|
||||
* from profile (`/create/completed?ruleId=…`) after GET /api/rules/[id]. Profile
|
||||
* "Manage" links here; "View" uses `/rules/[id]`.
|
||||
*/
|
||||
export const CREATE_FLOW_LAST_PUBLISHED_KEY = "createFlow.lastPublished";
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Reorders facet-ranked method presets so explicitly confirmed selections pin
|
||||
* to the top while the remainder keeps score-based ranking (recommended before
|
||||
* default).
|
||||
*/
|
||||
|
||||
/** Selected ids first (selection array order); then tail in `ranked` order. */
|
||||
export function orderRankedMethodsWithPinnedSelection<T extends { id: string }>(
|
||||
rankedMethods: readonly T[],
|
||||
selectedIds: readonly string[],
|
||||
pinActive: boolean,
|
||||
): T[] {
|
||||
if (!pinActive || selectedIds.length === 0) {
|
||||
return [...rankedMethods];
|
||||
}
|
||||
const byId = new Map(rankedMethods.map((m) => [m.id, m] as const));
|
||||
const head: T[] = [];
|
||||
const picked = new Set<string>();
|
||||
for (const id of selectedIds) {
|
||||
const row = byId.get(id);
|
||||
if (!row || picked.has(id)) continue;
|
||||
picked.add(id);
|
||||
head.push(row);
|
||||
}
|
||||
const tail = rankedMethods.filter((m) => !picked.has(m.id));
|
||||
return [...head, ...tail];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer selected ids in compact slots (up to `limit`), then facet-derived
|
||||
* `baseCompact.compactCardIds`, then remaining methods in showcase order so
|
||||
* selected cards surface even when they are outside the unpinned facet top-N.
|
||||
*/
|
||||
export function mergeCompactCardIdsWithPinnedSelected(
|
||||
showcaseOrderIds: readonly string[],
|
||||
baseCompactCardIds: readonly string[],
|
||||
selectedIds: readonly string[],
|
||||
pinActive: boolean,
|
||||
limit: number,
|
||||
): string[] {
|
||||
if (!pinActive || selectedIds.length === 0) {
|
||||
return [...baseCompactCardIds].slice(0, limit);
|
||||
}
|
||||
const valid = new Set(showcaseOrderIds);
|
||||
const out: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
for (const id of selectedIds) {
|
||||
if (out.length >= limit) break;
|
||||
if (!valid.has(id) || seen.has(id)) continue;
|
||||
seen.add(id);
|
||||
out.push(id);
|
||||
}
|
||||
for (const id of baseCompactCardIds) {
|
||||
if (out.length >= limit) break;
|
||||
if (!valid.has(id) || seen.has(id)) continue;
|
||||
seen.add(id);
|
||||
out.push(id);
|
||||
}
|
||||
for (const id of showcaseOrderIds) {
|
||||
if (out.length >= limit) break;
|
||||
if (seen.has(id)) continue;
|
||||
seen.add(id);
|
||||
out.push(id);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -65,7 +65,8 @@ export type OwnerPublishedRuleListItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Lists published rules owned by the given user (alphabetical by title, then id).
|
||||
* Lists published rules owned by the given user (**most recently updated first**,
|
||||
* then stable `id` tie-break).
|
||||
* Returns `null` when the database is not configured or the query throws.
|
||||
*/
|
||||
export async function listPublishedRulesForUser(
|
||||
@@ -79,7 +80,7 @@ export async function listPublishedRulesForUser(
|
||||
try {
|
||||
return await prisma.publishedRule.findMany({
|
||||
where: { userId },
|
||||
orderBy: [{ title: "asc" }, { id: "asc" }],
|
||||
orderBy: [{ updatedAt: "desc" }, { id: "asc" }],
|
||||
take: clamped,
|
||||
select: PUBLISHED_RULE_OWNER_LIST_SELECT,
|
||||
});
|
||||
|
||||
@@ -112,6 +112,15 @@ export const createFlowStateSchema = z
|
||||
conflictManagementDetailsById: z
|
||||
.record(conflictManagementDetailEntrySchema)
|
||||
.optional(),
|
||||
methodSectionsPinCommitted: z
|
||||
.object({
|
||||
communication: z.boolean().optional(),
|
||||
membership: z.boolean().optional(),
|
||||
decisionApproaches: z.boolean().optional(),
|
||||
conflictManagement: z.boolean().optional(),
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
pendingTemplateAction: z
|
||||
.object({
|
||||
slug: z.string().max(200),
|
||||
|
||||
@@ -13,6 +13,12 @@ export type GovernanceTemplateCatalogEntry = {
|
||||
backgroundColor: string;
|
||||
/** Path under public/ for getAssetPath() — Figma Asset / Template Mark */
|
||||
iconPath: string;
|
||||
/**
|
||||
* When true, the templates grid shows the “RECOMMENDED” tag (facet-based
|
||||
* scores will set this in `ruleTemplateToGridEntry` when wired; catalog
|
||||
* entries omit unless intentionally static).
|
||||
*/
|
||||
recommended?: boolean;
|
||||
};
|
||||
|
||||
/** SVGs in `public/assets/template-mark/<slug>.svg` (kebab-case slug). */
|
||||
|
||||
@@ -11,16 +11,24 @@ import {
|
||||
export const TEMPLATE_GRID_FALLBACK_PRESENTATION = {
|
||||
iconPath: governanceTemplateIconPath("consensus"),
|
||||
backgroundColor: "bg-[var(--color-surface-invert-brand-teal)]",
|
||||
recommended: false,
|
||||
} as const;
|
||||
|
||||
export type TemplateGridCardEntry = GovernanceTemplateCatalogEntry;
|
||||
|
||||
function presentationForSlug(slug: string): Pick<
|
||||
GovernanceTemplateCatalogEntry,
|
||||
"iconPath" | "backgroundColor"
|
||||
"iconPath" | "backgroundColor" | "recommended"
|
||||
> {
|
||||
const catalog = getGovernanceTemplateCatalogEntry(slug);
|
||||
return catalog ?? TEMPLATE_GRID_FALLBACK_PRESENTATION;
|
||||
if (catalog) {
|
||||
return {
|
||||
iconPath: catalog.iconPath,
|
||||
backgroundColor: catalog.backgroundColor,
|
||||
recommended: catalog.recommended === true,
|
||||
};
|
||||
}
|
||||
return TEMPLATE_GRID_FALLBACK_PRESENTATION;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,6 +43,7 @@ export function ruleTemplateToGridEntry(template: RuleTemplateDto): TemplateGrid
|
||||
description,
|
||||
iconPath: pres.iconPath,
|
||||
backgroundColor: pres.backgroundColor,
|
||||
recommended: pres.recommended,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user