Address follow-up review suggestions for XState roadmap integration
- Move deleteFeature actor cleanup outside set() for consistency - Skip no-op store writes when XState silently ignores events - Use 'as const' on assign action string literals for type narrowing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -265,6 +265,9 @@ export const useRoadmapStore = create<RoadmapState>((set) => ({
|
||||
const derivedStatus = mapFeatureStateToStatus(String(snapshot.value));
|
||||
const ctx = snapshot.context;
|
||||
|
||||
// Skip store write if XState silently ignored the event (no-op transition)
|
||||
if (derivedStatus === feature.status && ctx.taskOutcome === feature.taskOutcome && ctx.previousStatus === feature.previousStatus) return;
|
||||
|
||||
set((s) => {
|
||||
if (!s.roadmap) return s;
|
||||
const updatedFeatures = s.roadmap.features.map((f) =>
|
||||
@@ -363,17 +366,17 @@ export const useRoadmapStore = create<RoadmapState>((set) => ({
|
||||
});
|
||||
},
|
||||
|
||||
deleteFeature: (featureId) =>
|
||||
deleteFeature: (featureId) => {
|
||||
// Stop and remove the feature's actor outside set()
|
||||
const actor = featureActors.get(featureId);
|
||||
if (actor) {
|
||||
actor.stop();
|
||||
featureActors.delete(featureId);
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
if (!state.roadmap) return state;
|
||||
|
||||
// Stop and remove the feature's actor
|
||||
const actor = featureActors.get(featureId);
|
||||
if (actor) {
|
||||
actor.stop();
|
||||
featureActors.delete(featureId);
|
||||
}
|
||||
|
||||
const updatedFeatures = state.roadmap.features.filter(
|
||||
(feature) => feature.id !== featureId
|
||||
);
|
||||
@@ -385,7 +388,8 @@ export const useRoadmapStore = create<RoadmapState>((set) => ({
|
||||
updatedAt: new Date()
|
||||
}
|
||||
};
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
clearRoadmap: () => {
|
||||
// Stop all actors and clear Maps
|
||||
|
||||
@@ -174,12 +174,12 @@ export const roadmapFeatureMachine = createMachine(
|
||||
linkedSpecId: ({ event }) =>
|
||||
event.type === 'LINK_SPEC' ? event.specId : undefined
|
||||
}),
|
||||
savePreviousUnderReview: assign({ previousStatus: () => 'under_review' }),
|
||||
savePreviousPlanned: assign({ previousStatus: () => 'planned' }),
|
||||
savePreviousInProgress: assign({ previousStatus: () => 'in_progress' }),
|
||||
setTaskOutcomeCompleted: assign({ taskOutcome: () => 'completed' }),
|
||||
setTaskOutcomeDeleted: assign({ taskOutcome: () => 'deleted' }),
|
||||
setTaskOutcomeArchived: assign({ taskOutcome: () => 'archived' }),
|
||||
savePreviousUnderReview: assign({ previousStatus: () => 'under_review' as const }),
|
||||
savePreviousPlanned: assign({ previousStatus: () => 'planned' as const }),
|
||||
savePreviousInProgress: assign({ previousStatus: () => 'in_progress' as const }),
|
||||
setTaskOutcomeCompleted: assign({ taskOutcome: () => 'completed' as const }),
|
||||
setTaskOutcomeDeleted: assign({ taskOutcome: () => 'deleted' as const }),
|
||||
setTaskOutcomeArchived: assign({ taskOutcome: () => 'archived' as const }),
|
||||
clearDoneContext: assign({
|
||||
taskOutcome: () => undefined,
|
||||
previousStatus: () => undefined
|
||||
|
||||
Reference in New Issue
Block a user