fix: Step case overwriting prevention by hypothetical ID (#396)

This commit is contained in:
Han Sen
2026-03-03 14:31:59 +09:00
committed by GitHub
parent a065c1800f
commit 93e66d0122

View File

@@ -60,7 +60,7 @@ export default function CaseEditor({
const [testCase, setTestCase] = useState<CaseType>(defaultTestCase); const [testCase, setTestCase] = useState<CaseType>(defaultTestCase);
const [isTitleInvalid] = useState<boolean>(false); const [isTitleInvalid] = useState<boolean>(false);
const [isUpdating, setIsUpdating] = useState<boolean>(false); const [isUpdating, setIsUpdating] = useState<boolean>(false);
const [plusCount, setPlusCount] = useState<number>(0); const [idCounter, setIdCounter] = useState<number>(0);
const [isDirty, setIsDirty] = useState(false); const [isDirty, setIsDirty] = useState(false);
const [selectedTags, setSelectedTags] = useState<{ id: number; name: string }[]>([]); const [selectedTags, setSelectedTags] = useState<{ id: number; name: string }[]>([]);
@@ -68,9 +68,14 @@ export default function CaseEditor({
useFormGuard(isDirty, messages.areYouSureLeave); useFormGuard(isDirty, messages.areYouSureLeave);
const onPlusClick = async (newStepNo: number) => { const onPlusClick = async (newStepNo: number) => {
if (!testCase.Steps) {
return;
}
setIsDirty(true); setIsDirty(true);
const nextId = idCounter + 1;
const newStep: StepType = { const newStep: StepType = {
id: plusCount, // hypothetical ID
id: nextId,
step: '', step: '',
result: '', result: '',
createdAt: new Date(), createdAt: new Date(),
@@ -78,66 +83,65 @@ export default function CaseEditor({
caseSteps: { caseSteps: {
stepNo: newStepNo, stepNo: newStepNo,
}, },
uid: `uid${plusCount}`, uid: `uid${nextId}`,
editState: 'new', editState: 'new',
}; };
setPlusCount(plusCount + 1);
if (testCase.Steps) { const updatedSteps = testCase.Steps.map((step) => {
const updatedSteps = testCase.Steps.map((step) => { if (step.caseSteps.stepNo >= newStepNo) {
if (step.caseSteps.stepNo >= newStepNo) { return {
return { ...step,
...step, editState: step.editState === 'notChanged' ? 'changed' : step.editState,
editState: step.editState === 'notChanged' ? 'changed' : step.editState, caseSteps: {
caseSteps: { ...step.caseSteps,
...step.caseSteps, stepNo: step.caseSteps.stepNo + 1,
stepNo: step.caseSteps.stepNo + 1, },
}, };
}; }
} return step;
return step; });
});
updatedSteps.push(newStep); updatedSteps.push(newStep);
setTestCase({ setTestCase({
...testCase, ...testCase,
Steps: updatedSteps, Steps: updatedSteps,
}); });
} setIdCounter(nextId);
}; };
const onDeleteClick = async (stepId: number) => { const onDeleteClick = async (stepId: number) => {
setIsDirty(true); setIsDirty(true);
if (!testCase.Steps) {
// find deletedStep's stepNo return;
if (testCase.Steps) {
const deletedStep = testCase.Steps.find((step) => step.id === stepId);
if (!deletedStep) {
return;
}
const deletedStepNo = deletedStep.caseSteps.stepNo;
deletedStep.editState = 'deleted';
const updatedSteps = testCase.Steps.map((step) => {
if (step.caseSteps.stepNo > deletedStepNo) {
return {
...step,
editState: step.editState === 'notChanged' ? 'changed' : step.editState,
caseSteps: {
...step.caseSteps,
stepNo: step.caseSteps.stepNo - 1,
},
};
}
return step;
});
setTestCase({
...testCase,
Steps: updatedSteps,
});
} }
// find deletedStep's stepNo
const deletedStep = testCase.Steps.find((step) => step.id === stepId);
if (!deletedStep) {
return;
}
const deletedStepNo = deletedStep.caseSteps.stepNo;
deletedStep.editState = 'deleted';
const updatedSteps = testCase.Steps.map((step) => {
if (step.caseSteps.stepNo > deletedStepNo) {
return {
...step,
editState: step.editState === 'notChanged' ? 'changed' : step.editState,
caseSteps: {
...step.caseSteps,
stepNo: step.caseSteps.stepNo - 1,
},
};
}
return step;
});
setTestCase({
...testCase,
Steps: updatedSteps,
});
}; };
const handleDrop = (event: DragEvent<HTMLElement>) => { const handleDrop = (event: DragEvent<HTMLElement>) => {
@@ -201,18 +205,20 @@ export default function CaseEditor({
changeStep.editState = 'changed'; changeStep.editState = 'changed';
} }
if (testCase.Steps) { if (!testCase.Steps) {
setTestCase({ return;
...testCase,
Steps: testCase.Steps.map((step) => {
if (step.id === stepId) {
return changeStep;
} else {
return step;
}
}),
});
} }
setTestCase({
...testCase,
Steps: testCase.Steps.map((step) => {
if (step.id === stepId) {
return changeStep;
} else {
return step;
}
}),
});
}; };
useEffect(() => { useEffect(() => {
@@ -223,6 +229,11 @@ export default function CaseEditor({
data.Steps.forEach((step: StepType) => { data.Steps.forEach((step: StepType) => {
step.editState = 'notChanged'; step.editState = 'notChanged';
}); });
// set idCounter to the max step id to avoid id conflict for new steps
// id is not reflected on database
const maxStepId = data.Steps.reduce((maxId: number, step: StepType) => Math.max(maxId, step.id), 0);
setIdCounter(maxStepId);
setTestCase(data); setTestCase(data);
if (data.Tags) { if (data.Tags) {
setSelectedTags(Array.isArray(data.Tags) ? data.Tags : []); setSelectedTags(Array.isArray(data.Tags) ? data.Tags : []);