refactor(web): extract allocation drag action plans
This commit is contained in:
@@ -0,0 +1,104 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { buildAllocationBlockClickInfo, buildAllocationMutationPlan } from "./timelineAllocationActions.js";
|
||||||
|
|
||||||
|
const baseAlloc = {
|
||||||
|
allocationId: "alloc-1",
|
||||||
|
mutationAllocationId: null,
|
||||||
|
projectId: "project-1",
|
||||||
|
projectName: "Alpha",
|
||||||
|
scope: "allocation" as const,
|
||||||
|
allocationStartDate: new Date("2025-01-01T00:00:00.000Z"),
|
||||||
|
allocationEndDate: new Date("2025-01-05T00:00:00.000Z"),
|
||||||
|
originalStartDate: new Date("2025-01-01T00:00:00.000Z"),
|
||||||
|
originalEndDate: new Date("2025-01-05T00:00:00.000Z"),
|
||||||
|
currentStartDate: new Date("2025-01-02T00:00:00.000Z"),
|
||||||
|
currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("timelineAllocationActions", () => {
|
||||||
|
it("returns null click info when the drag lacks an allocation id or original dates", () => {
|
||||||
|
expect(
|
||||||
|
buildAllocationBlockClickInfo({
|
||||||
|
allocationId: null,
|
||||||
|
projectId: "project-1",
|
||||||
|
projectName: "Alpha",
|
||||||
|
originalStartDate: baseAlloc.originalStartDate,
|
||||||
|
originalEndDate: baseAlloc.originalEndDate,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildAllocationBlockClickInfo({
|
||||||
|
allocationId: "alloc-1",
|
||||||
|
projectId: "project-1",
|
||||||
|
projectName: "Alpha",
|
||||||
|
originalStartDate: null,
|
||||||
|
originalEndDate: baseAlloc.originalEndDate,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds click info with empty-string fallbacks for nullable project metadata", () => {
|
||||||
|
expect(
|
||||||
|
buildAllocationBlockClickInfo({
|
||||||
|
allocationId: "alloc-1",
|
||||||
|
projectId: null,
|
||||||
|
projectName: null,
|
||||||
|
originalStartDate: baseAlloc.originalStartDate,
|
||||||
|
originalEndDate: baseAlloc.originalEndDate,
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
allocationId: "alloc-1",
|
||||||
|
projectId: "",
|
||||||
|
projectName: "",
|
||||||
|
startDate: new Date("2025-01-01T00:00:00.000Z"),
|
||||||
|
endDate: new Date("2025-01-05T00:00:00.000Z"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns no mutation plan when the drag never produced complete current dates", () => {
|
||||||
|
expect(
|
||||||
|
buildAllocationMutationPlan({
|
||||||
|
...baseAlloc,
|
||||||
|
allocationId: null,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildAllocationMutationPlan({
|
||||||
|
...baseAlloc,
|
||||||
|
currentEndDate: null,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds mutation plans with fallback mutation ids and extraction flags", () => {
|
||||||
|
expect(
|
||||||
|
buildAllocationMutationPlan({
|
||||||
|
...baseAlloc,
|
||||||
|
scope: "segment",
|
||||||
|
allocationStartDate: new Date("2024-12-31T00:00:00.000Z"),
|
||||||
|
projectName: null,
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
activeAllocationId: "alloc-1",
|
||||||
|
currentStartDate: new Date("2025-01-02T00:00:00.000Z"),
|
||||||
|
currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
|
||||||
|
baseMutationAllocationId: "alloc-1",
|
||||||
|
requiresExtraction: true,
|
||||||
|
pendingSnapshot: {
|
||||||
|
allocationId: "alloc-1",
|
||||||
|
mutationAllocationId: "alloc-1",
|
||||||
|
projectName: "",
|
||||||
|
before: {
|
||||||
|
startDate: new Date("2025-01-01T00:00:00.000Z"),
|
||||||
|
endDate: new Date("2025-01-05T00:00:00.000Z"),
|
||||||
|
},
|
||||||
|
after: {
|
||||||
|
startDate: new Date("2025-01-02T00:00:00.000Z"),
|
||||||
|
endDate: new Date("2025-01-06T00:00:00.000Z"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import {
|
||||||
|
buildAllocationMovedSnapshot,
|
||||||
|
requiresAllocationFragmentExtraction,
|
||||||
|
type AllocationMovedSnapshotLike,
|
||||||
|
} from "./timelineAllocationFinalize.js";
|
||||||
|
|
||||||
|
type AllocationActionLike = {
|
||||||
|
allocationId: string | null;
|
||||||
|
mutationAllocationId: string | null;
|
||||||
|
projectId: string | null;
|
||||||
|
projectName: string | null;
|
||||||
|
scope: "allocation" | "segment";
|
||||||
|
allocationStartDate: Date | null;
|
||||||
|
allocationEndDate: Date | null;
|
||||||
|
originalStartDate: Date | null;
|
||||||
|
originalEndDate: Date | null;
|
||||||
|
currentStartDate: Date | null;
|
||||||
|
currentEndDate: Date | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildAllocationBlockClickInfo(
|
||||||
|
alloc: Pick<
|
||||||
|
AllocationActionLike,
|
||||||
|
"allocationId" | "projectId" | "projectName" | "originalStartDate" | "originalEndDate"
|
||||||
|
>,
|
||||||
|
): { allocationId: string; projectId: string; projectName: string; startDate: Date; endDate: Date } | null {
|
||||||
|
if (!alloc.allocationId || !alloc.originalStartDate || !alloc.originalEndDate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allocationId: alloc.allocationId,
|
||||||
|
projectId: alloc.projectId ?? "",
|
||||||
|
projectName: alloc.projectName ?? "",
|
||||||
|
startDate: alloc.originalStartDate,
|
||||||
|
endDate: alloc.originalEndDate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAllocationMutationPlan(
|
||||||
|
alloc: AllocationActionLike,
|
||||||
|
): {
|
||||||
|
activeAllocationId: string;
|
||||||
|
currentStartDate: Date;
|
||||||
|
currentEndDate: Date;
|
||||||
|
baseMutationAllocationId: string;
|
||||||
|
requiresExtraction: boolean;
|
||||||
|
pendingSnapshot: AllocationMovedSnapshotLike | null;
|
||||||
|
} | null {
|
||||||
|
if (!alloc.allocationId || !alloc.currentStartDate || !alloc.currentEndDate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeAllocationId: alloc.allocationId,
|
||||||
|
currentStartDate: alloc.currentStartDate,
|
||||||
|
currentEndDate: alloc.currentEndDate,
|
||||||
|
baseMutationAllocationId: alloc.mutationAllocationId ?? alloc.allocationId,
|
||||||
|
requiresExtraction: requiresAllocationFragmentExtraction(alloc),
|
||||||
|
pendingSnapshot: buildAllocationMovedSnapshot(alloc),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -76,28 +76,21 @@ describe("timelineAllocationFinalize", () => {
|
|||||||
it("requires extraction only for segment drags that no longer match allocation boundaries", () => {
|
it("requires extraction only for segment drags that no longer match allocation boundaries", () => {
|
||||||
expect(
|
expect(
|
||||||
requiresAllocationFragmentExtraction({
|
requiresAllocationFragmentExtraction({
|
||||||
mode: "move",
|
|
||||||
scope: "segment",
|
scope: "segment",
|
||||||
allocationId: "alloc-1",
|
originalStartDate: baseDates.originalStartDate,
|
||||||
mutationAllocationId: null,
|
originalEndDate: baseDates.originalEndDate,
|
||||||
projectName: "Alpha",
|
|
||||||
...baseDates,
|
|
||||||
allocationStartDate: new Date("2024-12-31T00:00:00.000Z"),
|
allocationStartDate: new Date("2024-12-31T00:00:00.000Z"),
|
||||||
pointerDeltaX: 0,
|
allocationEndDate: baseDates.allocationEndDate,
|
||||||
daysDelta: 1,
|
|
||||||
}),
|
}),
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
requiresAllocationFragmentExtraction({
|
requiresAllocationFragmentExtraction({
|
||||||
mode: "move",
|
|
||||||
scope: "allocation",
|
scope: "allocation",
|
||||||
allocationId: "alloc-1",
|
originalStartDate: baseDates.originalStartDate,
|
||||||
mutationAllocationId: null,
|
originalEndDate: baseDates.originalEndDate,
|
||||||
projectName: "Alpha",
|
allocationStartDate: baseDates.allocationStartDate,
|
||||||
...baseDates,
|
allocationEndDate: baseDates.allocationEndDate,
|
||||||
pointerDeltaX: 0,
|
|
||||||
daysDelta: 1,
|
|
||||||
}),
|
}),
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -105,14 +98,13 @@ describe("timelineAllocationFinalize", () => {
|
|||||||
it("returns null snapshots when required dates or ids are missing", () => {
|
it("returns null snapshots when required dates or ids are missing", () => {
|
||||||
expect(
|
expect(
|
||||||
buildAllocationMovedSnapshot({
|
buildAllocationMovedSnapshot({
|
||||||
mode: "move",
|
|
||||||
scope: "allocation",
|
|
||||||
allocationId: null,
|
allocationId: null,
|
||||||
mutationAllocationId: null,
|
mutationAllocationId: null,
|
||||||
projectName: "Alpha",
|
projectName: "Alpha",
|
||||||
...baseDates,
|
originalStartDate: baseDates.originalStartDate,
|
||||||
pointerDeltaX: 0,
|
originalEndDate: baseDates.originalEndDate,
|
||||||
daysDelta: 1,
|
currentStartDate: baseDates.currentStartDate,
|
||||||
|
currentEndDate: baseDates.currentEndDate,
|
||||||
}),
|
}),
|
||||||
).toBeNull();
|
).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -120,16 +112,13 @@ describe("timelineAllocationFinalize", () => {
|
|||||||
it("builds a mutation snapshot with fallback mutation allocation ids", () => {
|
it("builds a mutation snapshot with fallback mutation allocation ids", () => {
|
||||||
expect(
|
expect(
|
||||||
buildAllocationMovedSnapshot({
|
buildAllocationMovedSnapshot({
|
||||||
mode: "move",
|
|
||||||
scope: "allocation",
|
|
||||||
allocationId: "alloc-1",
|
allocationId: "alloc-1",
|
||||||
mutationAllocationId: null,
|
mutationAllocationId: null,
|
||||||
projectName: null,
|
projectName: null,
|
||||||
...baseDates,
|
originalStartDate: baseDates.originalStartDate,
|
||||||
|
originalEndDate: baseDates.originalEndDate,
|
||||||
currentStartDate: new Date("2025-01-02T00:00:00.000Z"),
|
currentStartDate: new Date("2025-01-02T00:00:00.000Z"),
|
||||||
currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
|
currentEndDate: new Date("2025-01-06T00:00:00.000Z"),
|
||||||
pointerDeltaX: 32,
|
|
||||||
daysDelta: 1,
|
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
allocationId: "alloc-1",
|
allocationId: "alloc-1",
|
||||||
|
|||||||
@@ -42,7 +42,12 @@ export function shouldTreatAllocationDragAsClick(
|
|||||||
return alloc.mode === "move" && alloc.daysDelta === 0 && Math.abs(alloc.pointerDeltaX) <= clickThresholdPx;
|
return alloc.mode === "move" && alloc.daysDelta === 0 && Math.abs(alloc.pointerDeltaX) <= clickThresholdPx;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requiresAllocationFragmentExtraction(alloc: AllocDragFinalizeLike): boolean {
|
export function requiresAllocationFragmentExtraction(
|
||||||
|
alloc: Pick<
|
||||||
|
AllocDragFinalizeLike,
|
||||||
|
"scope" | "originalStartDate" | "allocationStartDate" | "originalEndDate" | "allocationEndDate"
|
||||||
|
>,
|
||||||
|
): boolean {
|
||||||
return (
|
return (
|
||||||
alloc.scope === "segment" &&
|
alloc.scope === "segment" &&
|
||||||
(!datesMatch(alloc.originalStartDate, alloc.allocationStartDate) ||
|
(!datesMatch(alloc.originalStartDate, alloc.allocationStartDate) ||
|
||||||
@@ -51,7 +56,16 @@ export function requiresAllocationFragmentExtraction(alloc: AllocDragFinalizeLik
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildAllocationMovedSnapshot(
|
export function buildAllocationMovedSnapshot(
|
||||||
alloc: AllocDragFinalizeLike,
|
alloc: Pick<
|
||||||
|
AllocDragFinalizeLike,
|
||||||
|
| "allocationId"
|
||||||
|
| "mutationAllocationId"
|
||||||
|
| "projectName"
|
||||||
|
| "originalStartDate"
|
||||||
|
| "originalEndDate"
|
||||||
|
| "currentStartDate"
|
||||||
|
| "currentEndDate"
|
||||||
|
>,
|
||||||
): AllocationMovedSnapshotLike | null {
|
): AllocationMovedSnapshotLike | null {
|
||||||
if (
|
if (
|
||||||
!alloc.allocationId ||
|
!alloc.allocationId ||
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
buildAllocationMovedSnapshot,
|
buildAllocationMovedSnapshot,
|
||||||
hasAllocationDateChange,
|
hasAllocationDateChange,
|
||||||
requiresAllocationFragmentExtraction,
|
|
||||||
shouldTreatAllocationDragAsClick,
|
shouldTreatAllocationDragAsClick,
|
||||||
} from "./timelineAllocationFinalize.js";
|
} from "./timelineAllocationFinalize.js";
|
||||||
|
import { buildAllocationBlockClickInfo, buildAllocationMutationPlan } from "./timelineAllocationActions.js";
|
||||||
import {
|
import {
|
||||||
finalizeAllocationMultiDrag,
|
finalizeAllocationMultiDrag,
|
||||||
isAllocationMultiSelected,
|
isAllocationMultiSelected,
|
||||||
@@ -729,22 +729,29 @@ export function useTimelineDrag({
|
|||||||
onShiftClickAllocRef.current?.(alloc.allocationId);
|
onShiftClickAllocRef.current?.(alloc.allocationId);
|
||||||
} else {
|
} else {
|
||||||
// Normal click → open alloc popover
|
// Normal click → open alloc popover
|
||||||
onBlockClickRef.current?.({
|
const clickInfo = buildAllocationBlockClickInfo(alloc);
|
||||||
allocationId: alloc.allocationId,
|
if (clickInfo) {
|
||||||
projectId: alloc.projectId ?? "",
|
onBlockClickRef.current?.(clickInfo);
|
||||||
projectName: alloc.projectName ?? "",
|
}
|
||||||
startDate: alloc.originalStartDate!,
|
|
||||||
endDate: alloc.originalEndDate!,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (hasDateChange && alloc.allocationId && alloc.currentStartDate && alloc.currentEndDate) {
|
} else if (hasDateChange && alloc.allocationId && alloc.currentStartDate && alloc.currentEndDate) {
|
||||||
const activeAllocationId = alloc.allocationId;
|
const mutationPlan = buildAllocationMutationPlan(alloc);
|
||||||
const currentStartDate = alloc.currentStartDate;
|
if (!mutationPlan) {
|
||||||
const currentEndDate = alloc.currentEndDate;
|
allocDragRef.current = INITIAL_ALLOC_DRAG;
|
||||||
const baseMutationAllocationId = alloc.mutationAllocationId ?? activeAllocationId;
|
setAllocDragState(INITIAL_ALLOC_DRAG);
|
||||||
const requiresExtraction = requiresAllocationFragmentExtraction(alloc);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pendingSnapshotRef.current = buildAllocationMovedSnapshot(alloc);
|
const {
|
||||||
|
activeAllocationId,
|
||||||
|
currentStartDate,
|
||||||
|
currentEndDate,
|
||||||
|
baseMutationAllocationId,
|
||||||
|
requiresExtraction,
|
||||||
|
pendingSnapshot,
|
||||||
|
} = mutationPlan;
|
||||||
|
|
||||||
|
pendingSnapshotRef.current = pendingSnapshot;
|
||||||
pendingOptimisticAllocationIdRef.current = activeAllocationId;
|
pendingOptimisticAllocationIdRef.current = activeAllocationId;
|
||||||
setOptimisticAllocations((prev) => {
|
setOptimisticAllocations((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
|
|||||||
@@ -217,6 +217,21 @@ export const rules = [
|
|||||||
],
|
],
|
||||||
forbidden: [],
|
forbidden: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
file: "apps/web/src/hooks/timelineAllocationActions.ts",
|
||||||
|
maxLines: 90,
|
||||||
|
required: [
|
||||||
|
{
|
||||||
|
pattern: /\bexport function buildAllocationBlockClickInfo\b/,
|
||||||
|
message: "timeline allocation action helpers must keep popover click payload derivation centralized",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /\bexport function buildAllocationMutationPlan\b/,
|
||||||
|
message: "timeline allocation action helpers must keep mutation plan derivation centralized",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
forbidden: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
file: "apps/web/src/hooks/timelineAllocationDragState.ts",
|
file: "apps/web/src/hooks/timelineAllocationDragState.ts",
|
||||||
maxLines: 80,
|
maxLines: 80,
|
||||||
@@ -270,6 +285,10 @@ export const rules = [
|
|||||||
pattern: /from "\.\/timelineAllocationFinalize\.js"/,
|
pattern: /from "\.\/timelineAllocationFinalize\.js"/,
|
||||||
message: "timeline drag must keep allocation drag completion rules delegated to the extracted helper module",
|
message: "timeline drag must keep allocation drag completion rules delegated to the extracted helper module",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pattern: /from "\.\/timelineAllocationActions\.js"/,
|
||||||
|
message: "timeline drag must keep allocation click and mutation plan derivation delegated to the extracted helper module",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pattern: /from "\.\/timelineAllocationMultiDrag\.js"/,
|
pattern: /from "\.\/timelineAllocationMultiDrag\.js"/,
|
||||||
message: "timeline drag must keep allocation multi-drag rules delegated to the extracted helper module",
|
message: "timeline drag must keep allocation multi-drag rules delegated to the extracted helper module",
|
||||||
@@ -296,6 +315,10 @@ export const rules = [
|
|||||||
pattern: /\bfunction (?:hasAllocationDateChange|shouldTreatAllocationDragAsClick|requiresAllocationFragmentExtraction|buildAllocationMovedSnapshot|reconcileOptimisticEntries)\b/,
|
pattern: /\bfunction (?:hasAllocationDateChange|shouldTreatAllocationDragAsClick|requiresAllocationFragmentExtraction|buildAllocationMovedSnapshot|reconcileOptimisticEntries)\b/,
|
||||||
message: "timeline drag must not re-inline extracted optimistic or allocation finalize helper implementations",
|
message: "timeline drag must not re-inline extracted optimistic or allocation finalize helper implementations",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pattern: /\bfunction (?:buildAllocationBlockClickInfo|buildAllocationMutationPlan)\b/,
|
||||||
|
message: "timeline drag must not re-inline extracted allocation action helper implementations",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pattern: /\bfunction (?:isAllocationMultiSelected|startAllocationMultiDrag|updateAllocationMultiDrag|finalizeAllocationMultiDrag)\b/,
|
pattern: /\bfunction (?:isAllocationMultiSelected|startAllocationMultiDrag|updateAllocationMultiDrag|finalizeAllocationMultiDrag)\b/,
|
||||||
message: "timeline drag must not re-inline extracted allocation multi-drag helper implementations",
|
message: "timeline drag must not re-inline extracted allocation multi-drag helper implementations",
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ describe("architecture guardrails", () => {
|
|||||||
const optimisticRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineOptimisticAllocations.ts");
|
const optimisticRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineOptimisticAllocations.ts");
|
||||||
const allocationFinalizeRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationFinalize.ts");
|
const allocationFinalizeRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationFinalize.ts");
|
||||||
const allocationMultiDragRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationMultiDrag.ts");
|
const allocationMultiDragRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationMultiDrag.ts");
|
||||||
|
const allocationActionsRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationActions.ts");
|
||||||
const allocationDragStateRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationDragState.ts");
|
const allocationDragStateRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineAllocationDragState.ts");
|
||||||
const projectDragRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineProjectDrag.ts");
|
const projectDragRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineProjectDrag.ts");
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ describe("architecture guardrails", () => {
|
|||||||
assert.ok(optimisticRule);
|
assert.ok(optimisticRule);
|
||||||
assert.ok(allocationFinalizeRule);
|
assert.ok(allocationFinalizeRule);
|
||||||
assert.ok(allocationMultiDragRule);
|
assert.ok(allocationMultiDragRule);
|
||||||
|
assert.ok(allocationActionsRule);
|
||||||
assert.ok(allocationDragStateRule);
|
assert.ok(allocationDragStateRule);
|
||||||
assert.ok(projectDragRule);
|
assert.ok(projectDragRule);
|
||||||
|
|
||||||
@@ -98,6 +100,7 @@ describe("architecture guardrails", () => {
|
|||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep range preview and finalization delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep range preview and finalization delegated to the extracted helper module",
|
||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep optimistic allocation reconciliation delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep optimistic allocation reconciliation delegated to the extracted helper module",
|
||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation drag completion rules delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation drag completion rules delegated to the extracted helper module",
|
||||||
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation click and mutation plan derivation delegated to the extracted helper module",
|
||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation multi-drag rules delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation multi-drag rules delegated to the extracted helper module",
|
||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation drag bootstrap delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep allocation drag bootstrap delegated to the extracted helper module",
|
||||||
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep project drag bootstrap and mutation gating delegated to the extracted helper module",
|
"apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep project drag bootstrap and mutation gating delegated to the extracted helper module",
|
||||||
@@ -136,6 +139,10 @@ describe("architecture guardrails", () => {
|
|||||||
"apps/web/src/hooks/timelineAllocationMultiDrag.ts: missing guardrail anchor: timeline allocation multi-drag helpers must keep reset-on-release behavior centralized",
|
"apps/web/src/hooks/timelineAllocationMultiDrag.ts: missing guardrail anchor: timeline allocation multi-drag helpers must keep reset-on-release behavior centralized",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
assert.deepEqual(evaluateRule(allocationActionsRule, "export function buildAllocationBlockClickInfo() {}\n"), [
|
||||||
|
"apps/web/src/hooks/timelineAllocationActions.ts: missing guardrail anchor: timeline allocation action helpers must keep mutation plan derivation centralized",
|
||||||
|
]);
|
||||||
|
|
||||||
assert.deepEqual(evaluateRule(allocationDragStateRule, ""), [
|
assert.deepEqual(evaluateRule(allocationDragStateRule, ""), [
|
||||||
"apps/web/src/hooks/timelineAllocationDragState.ts: missing guardrail anchor: timeline allocation drag state helpers must keep drag bootstrap centralized",
|
"apps/web/src/hooks/timelineAllocationDragState.ts: missing guardrail anchor: timeline allocation drag state helpers must keep drag bootstrap centralized",
|
||||||
]);
|
]);
|
||||||
|
|||||||
Reference in New Issue
Block a user