fix(path-editor): filter machine options to only show available machine (TRU-91)
The path editor previously rendered all 12 program buttons and all 12 program wheel positions regardless of whether the current lane had a configured, non-deleted machine type. This made it possible to author paths for programs that the machine does not actually support. Filter pathEditorMachineButtonOptions and pathEditorProgramButtonOptions based on whether the current lane resolves to an available selfserve_machine_types row. When the machine is not available, the machine button grid is empty and the program wheel only exposes the OFF position.
This commit is contained in:
+51
-6
@@ -1264,14 +1264,19 @@ const createPathEditorQuestion = async () => {
|
|||||||
await loadPathOutcomes({ force: true });
|
await loadPathOutcomes({ force: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
const pathEditorProgramButtonOptions = computed(() => [
|
const pathEditorProgramButtonOptions = computed(() => {
|
||||||
|
if (!pathEditorMachineIsAvailable.value) {
|
||||||
|
return [{ id: 0, value: "0", label: "0 = OFF" }];
|
||||||
|
}
|
||||||
|
return [
|
||||||
{ id: 0, value: "0", label: "0 = OFF" },
|
{ id: 0, value: "0", label: "0 = OFF" },
|
||||||
...Array.from({ length: 12 }, (_, index) => ({
|
...Array.from({ length: 12 }, (_, index) => ({
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
value: String(index + 1),
|
value: String(index + 1),
|
||||||
label: `Wheel position #${index + 1}`,
|
label: `Wheel position #${index + 1}`,
|
||||||
})),
|
})),
|
||||||
]);
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1392,16 +1397,56 @@ const pathVerificationSelectedCaseHasRun = computed(() =>
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const pathEditorMachineButtonOptions = computed(() =>
|
// TRU-91: Filter path editor machine options to only show enabled/available
|
||||||
Array.from({ length: 12 }, (_, index) => {
|
// machine programs for the current scope. A machine is considered "available"
|
||||||
|
// when the current lane has a machine_type_id that resolves to a non-deleted
|
||||||
|
// selfserve_machine_types row in the lookups.
|
||||||
|
const pathEditorCurrentLaneRow = computed(() => {
|
||||||
|
const laneId = parseIntOrZero(selectedSimulatorLaneId.value);
|
||||||
|
if (laneId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return laneRowById(laneId);
|
||||||
|
});
|
||||||
|
|
||||||
|
const pathEditorCurrentMachineType = computed(() => {
|
||||||
|
const lane = pathEditorCurrentLaneRow.value;
|
||||||
|
if (!lane) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const machineTypeId = parseNullableInt(lane.machine_type_id);
|
||||||
|
if (!machineTypeId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const machineTypeRow = lookupRowById("machine_types", machineTypeId);
|
||||||
|
if (!machineTypeRow) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
machineTypeRow.deleted_at !== null &&
|
||||||
|
machineTypeRow.deleted_at !== undefined &&
|
||||||
|
machineTypeRow.deleted_at !== ""
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return machineTypeRow;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pathEditorMachineIsAvailable = computed(() => Boolean(pathEditorCurrentMachineType.value));
|
||||||
|
|
||||||
|
const pathEditorMachineButtonOptions = computed(() => {
|
||||||
|
if (!pathEditorMachineIsAvailable.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return Array.from({ length: 12 }, (_, index) => {
|
||||||
const option = taskButtonOptions.find((entry) => entry.id === index);
|
const option = taskButtonOptions.find((entry) => entry.id === index);
|
||||||
return {
|
return {
|
||||||
id: index,
|
id: index,
|
||||||
label: option?.description || `Machine button ${index}`,
|
label: option?.description || `Machine button ${index}`,
|
||||||
description: option?.name || `Program ${index + 1}`,
|
description: option?.name || `Program ${index + 1}`,
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
const pathEditorTaskTitleKeySlug = (key) => String(key || "").replace(/[^a-zA-Z0-9_-]/g, "-");
|
const pathEditorTaskTitleKeySlug = (key) => String(key || "").replace(/[^a-zA-Z0-9_-]/g, "-");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
const readSource = (relativePath) => readFileSync(join(process.cwd(), relativePath), "utf8");
|
||||||
|
|
||||||
|
describe("self-serve studio path editor machine filter (TRU-91)", () => {
|
||||||
|
const studioSource = readSource(
|
||||||
|
"src/views/dashboards/departmentDashboard/modules/self-serve/DepartmentSelfServeStudio.vue"
|
||||||
|
);
|
||||||
|
|
||||||
|
it("defines a path editor machine-availability check tied to the current lane and machine type", () => {
|
||||||
|
expect(studioSource).toContain("pathEditorCurrentLaneRow");
|
||||||
|
expect(studioSource).toContain("pathEditorCurrentMachineType");
|
||||||
|
expect(studioSource).toContain("pathEditorMachineIsAvailable");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns an empty machine button list when the machine is not available", () => {
|
||||||
|
expect(studioSource).toMatch(
|
||||||
|
/pathEditorMachineButtonOptions[\s\S]{0,400}if\s*\(\s*!pathEditorMachineIsAvailable\.value\s*\)\s*\{\s*return\s*\[\s*\]\s*;\s*\}/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("limits program wheel options to the OFF position when the machine is not available", () => {
|
||||||
|
expect(studioSource).toMatch(
|
||||||
|
/pathEditorProgramButtonOptions[\s\S]{0,600}if\s*\(\s*!pathEditorMachineIsAvailable\.value\s*\)[\s\S]{0,200}return\s*\[\s*\{\s*id:\s*0,\s*value:\s*"0",\s*label:\s*"0 = OFF"\s*\}\s*\]/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("considers a machine type deleted when its deleted_at is set", () => {
|
||||||
|
expect(studioSource).toMatch(/machineTypeRow\.deleted_at[\s\S]{0,80}return\s+null/);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user