openflexure-microscope-server/webapp/src/components/modalComponents/calibrationWizard.vue
2025-10-23 17:32:58 +01:00

198 lines
5.2 KiB
Vue

<template>
<div id="modal-example" ref="calibrationModalEl" uk-modal="bg-close: false;">
<div class="uk-modal-dialog uk-modal-body">
<h2 class="uk-modal-title">Microscope Calibration</h2>
<component
v-if="currentTask"
:is="currentTask.component"
:key="taskIndex"
v-bind="currentTask.props"
:first="isFirstTask"
:final="isFinalTask"
:startOnLast="movingBackward"
@next="nextTask"
@back="previousTask"
/>
</div>
</div>
</template>
<script>
import singleStepTask from "./calibrationWizardComponents/singleStepTask.vue";
import welcomeStep from "./calibrationWizardComponents/welcomeStep.vue";
import cameraCalibrationTask from "./calibrationWizardComponents/cameraCalibrationTask.vue";
import cameraStageMappingTask from "./calibrationWizardComponents/cameraStageMappingTask.vue";
import finalStep from "./calibrationWizardComponents/finalStep.vue";
export default {
name: "calibrationWizard",
components: {},
data: function() {
return {
isNeeded: undefined,
availableCalibrationTasks: {},
tasks: [],
taskIndex: 0,
movingBackward: false
};
},
computed: {
currentTask() {
return this.tasks[this.taskIndex] || null;
},
isFirstTask() {
return this.taskIndex === 0;
},
isFinalTask() {
return this.taskIndex === this.tasks.length - 1;
}
},
mounted() {
this.$refs["calibrationModalEl"].addEventListener("hidden", this.onHide);
// Check which Things are available on mount.
const allCalibrationTasks = {
camera: cameraCalibrationTask,
camera_stage_mapping: cameraStageMappingTask
};
this.availableCalibrationTasks = Object.fromEntries(
Object.entries(allCalibrationTasks).filter(([thing]) =>
this.thingAvailable(thing)
)
);
},
methods: {
/**
* Check all calibratable Things to see which require calibration.
*
* Iterates over `this.availableCalibrationTasks` (set during mounted()) and reads the
* `calibration_required` property.
*
* Returns a list of thing names that report calibration is required.
*/
async check_things_needing_calibration() {
const needsCalibration = [];
const calibrateableThings = Object.keys(this.availableCalibrationTasks);
for (const name of calibrateableThings) {
try {
const thingNeedsCal = await this.readThingProperty(
name,
"calibration_required"
);
if (thingNeedsCal) {
needsCalibration.push(name);
}
} catch (e) {
console.error(`${name}: missing calibration_required property`, e);
}
}
return needsCalibration;
},
resetData: function() {
this.movingBackward = false;
this.taskIndex = 0;
},
/**
* Create the calibration wizard task list dynamically.
*/
create_task_list: function(thingsToCal, includeWelcome = true) {
const tasks = [];
// Optionally include the welcome screen
if (includeWelcome) {
tasks.push({
component: singleStepTask,
props: { stepComponent: welcomeStep }
});
}
// Add calibration task for each thing
for (const thing of thingsToCal) {
const taskComponent = this.availableCalibrationTasks[thing];
tasks.push({ component: taskComponent });
}
// Always include the final step
tasks.push({
component: singleStepTask,
props: { stepComponent: finalStep }
});
this.tasks = tasks;
},
show_if_needed: async function() {
// Check if the calibration modal is needed, and only show it if it is.
let thingsToCal = await this.check_things_needing_calibration();
const needed = thingsToCal.length > 0;
// Check if this calibration wizard can actually do anything useful
if (needed) {
this.resetData();
this.create_task_list(thingsToCal);
this.show();
} else {
// If not needed, we just return the onClose event immediately
this.onHide();
}
},
// Forces modal to show on button press
force_show: function() {
const allThings = Object.keys(this.availableCalibrationTasks);
this.resetData();
this.create_task_list(allThings, false);
this.show();
},
show: function() {
// Show the modal element
var el = this.$refs["calibrationModalEl"];
this.showModalElement(el); // Calls the mixin
},
hide: function() {
// Show the modal
var el = this.$refs["calibrationModalEl"];
this.hideModalElement(el); // Calls the mixin
},
onHide: function() {
this.$emit("onClose");
},
/*
* Move to the previous task.
*/
previousTask: function() {
this.movingBackward = true;
if (this.taskIndex > 0) {
this.taskIndex = this.taskIndex - 1;
}
},
/*
* Move to the next task or close the modal if this is the final task.
*/
nextTask: function() {
this.movingBackward = false;
if (this.taskIndex < this.tasks.length - 1) {
this.taskIndex = this.taskIndex + 1;
return true;
} else {
this.hide();
}
}
}
};
</script>