74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
/** Live workspace signals used to advance the checklist without relying only on localStorage. */
|
|||
|
|
export type ActivationWorkspaceEvidence = {
|
||
|
|
hasEnabledFields?: boolean;
|
||
|
|
hasSource?: boolean;
|
||
|
|
hasMapping?: boolean;
|
||
|
|
hasSyncedSample?: boolean;
|
||
|
|
hasProcessed?: boolean;
|
||
|
|
hasStoreConnect?: boolean;
|
||
|
|
hasExport?: boolean;
|
||
|
|
};
|
||
|
|
|
||
|
|
/** Minimal step shape for gating / workspace cursor (no i18n). */
|
||
|
|
export type ActivationStepRef = {
|
||
|
|
id: string;
|
||
|
|
optional?: boolean;
|
||
|
|
feature?: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
/** Steps visible for the current plan (omit feature-gated steps the plan denies). */
|
||
|
|
export function visibleActivationSteps<T extends ActivationStepRef>(
|
||
|
|
steps: T[],
|
||
|
|
can: (featureKey: string) => boolean = () => true
|
||
|
|
): T[] {
|
||
|
|
return steps.filter((s) => !s.feature || can(s.feature));
|
||
|
|
}
|
||
|
|
|
||
|
|
const evidenceForStep: Record<
|
||
|
|
string,
|
||
|
|
(evidence: ActivationWorkspaceEvidence) => boolean | undefined
|
||
|
|
> = {
|
||
|
|
"enable-fields": (e) => e.hasEnabledFields,
|
||
|
|
"connect-source": (e) => e.hasSource,
|
||
|
|
map: (e) => e.hasMapping,
|
||
|
|
"sync-sample": (e) => e.hasSyncedSample,
|
||
|
|
process: (e) => e.hasProcessed,
|
||
|
|
"store-connect": (e) => e.hasStoreConnect,
|
||
|
|
export: (e) => e.hasExport
|
||
|
|
};
|
||
|
|
|
||
|
|
function stepEvidenceDone(step: ActivationStepRef, evidence: ActivationWorkspaceEvidence): boolean {
|
||
|
|
const getter = evidenceForStep[step.id];
|
||
|
|
return getter ? Boolean(getter(evidence)) : false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Contiguous completed-step count from workspace state (stop at first incomplete).
|
||
|
|
* Optional steps do not block later required evidence (e.g. export without a store).
|
||
|
|
*/
|
||
|
|
export function activationIndexFromWorkspace(
|
||
|
|
evidence: ActivationWorkspaceEvidence | null | undefined,
|
||
|
|
steps: ActivationStepRef[]
|
||
|
|
): number {
|
||
|
|
if (!evidence) return 0;
|
||
|
|
let count = 0;
|
||
|
|
for (let i = 0; i < steps.length; i++) {
|
||
|
|
const step = steps[i];
|
||
|
|
if (stepEvidenceDone(step, evidence)) {
|
||
|
|
count += 1;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (step.optional) {
|
||
|
|
const laterRequiredDone = steps
|
||
|
|
.slice(i + 1)
|
||
|
|
.some((s) => !s.optional && stepEvidenceDone(s, evidence));
|
||
|
|
if (laterRequiredDone) {
|
||
|
|
count += 1;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
return Math.min(count, steps.length);
|
||
|
|
}
|