ui_migration lint(fix): changes fixed with lint ecmaversion & es2021

This commit is contained in:
Antonio Anaya 2026-02-15 01:03:29 -06:00
parent 0741e3cf7e
commit ce19ea3fc0
52 changed files with 242 additions and 193 deletions

View file

@ -2,25 +2,20 @@ module.exports = {
root: true, root: true,
env: { env: {
node: true, node: true,
es2021: true, // ✅ Updated for modern JS es2021: true,
}, },
parser: "vue-eslint-parser", parser: "vue-eslint-parser",
parserOptions: { parserOptions: {
parser: "@babel/eslint-parser", parser: "@babel/eslint-parser",
requireConfigFile: false, requireConfigFile: false,
ecmaVersion: 2021, // ✅ Updated ecmaVersion: 2021,
sourceType: "module", sourceType: "module",
}, },
extends: [ extends: ["plugin:vue/vue3-recommended", "eslint:recommended", "@vue/prettier"],
"plugin:vue/vue3-recommended", // ✅ Changed from vue/recommended to vue3-recommended
"eslint:recommended",
"@vue/prettier"
],
rules: { rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
// ✅ Vue 3 migration warnings - detect deprecated patterns
"vue/no-deprecated-slot-attribute": "warn", "vue/no-deprecated-slot-attribute": "warn",
"vue/no-deprecated-v-on-native-modifier": "warn", "vue/no-deprecated-v-on-native-modifier": "warn",
"vue/no-deprecated-dollar-listeners-api": "warn", "vue/no-deprecated-dollar-listeners-api": "warn",
@ -37,15 +32,13 @@ module.exports = {
"vue/no-deprecated-v-is": "warn", "vue/no-deprecated-v-is": "warn",
"vue/no-lifecycle-after-await": "warn", "vue/no-lifecycle-after-await": "warn",
"vue/no-watch-after-await": "warn", "vue/no-watch-after-await": "warn",
// ✅ Vue 3 best practices "vue/require-explicit-emits": "warn", // Require emits declaration
"vue/require-explicit-emits": "warn", // Require emits declaration "vue/multi-word-component-names": "warn", // Component naming
"vue/multi-word-component-names": "warn", // Component naming "vue/no-v-for-template-key-on-child": "error", // Key placement
"vue/no-v-for-template-key-on-child": "error", // Key placement "vue/no-v-model-argument": "error", // Allow v-model arguments (Vue 3 feature)
"vue/no-v-model-argument": "off", // Allow v-model arguments (Vue 3 feature)
// ✅ Relaxed for migration period (can be stricter later)
"vue/no-unused-components": "warn", "vue/no-unused-components": "warn",
"vue/no-unused-vars": "warn", "vue/no-unused-vars": "warn",
}, },
}; };

View file

@ -1,4 +1,4 @@
<template :key="shortcut.shortcut"> <template>
<div id="app" class="uk-height-1-1 uk-margin-remove uk-padding-remove" :class="handleTheme"> <div id="app" class="uk-height-1-1 uk-margin-remove uk-padding-remove" :class="handleTheme">
<!-- this stops the app loading until setConnected is committed in the store, this means <!-- this stops the app loading until setConnected is committed in the store, this means
other components will not load until we have Thing Descriptions. --> other components will not load until we have Thing Descriptions. -->
@ -10,6 +10,7 @@
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div <div
v-for="shortcut in keyboardManual" v-for="shortcut in keyboardManual"
:key="shortcut.shortcut"
class="uk-margin-small" class="uk-margin-small"
uk-grid uk-grid
> >
@ -25,14 +26,13 @@
// Import components // Import components
import appContent from "./components/appContent.vue"; import appContent from "./components/appContent.vue";
import loadingContent from "./components/loadingContent.vue"; import loadingContent from "./components/loadingContent.vue";
import MouseTrap from "mousetrap"; import Mousetrap from "mousetrap";
// vue3 migration // vue3 migration
import { markRaw } from "vue";
import { eventBus } from "./eventBus.js"; import { eventBus } from "./eventBus.js";
MouseTrap.prototype.stopCallback = function (e, element) { Mousetrap.prototype.stopCallback = function (e, element) {
// if the element has the class "mousetrap" then no need to stop // if the element has the class "mousetrap" then no need to stop
if ((" " + element.className + " ").indexOf(" mousetrap ") > -1) { if ((" " + element.className + " ").indexOf(" Mousetrap ") > -1) {
return false; return false;
} }
@ -56,7 +56,7 @@ export default {
components: { components: {
appContent, appContent,
loadingContent loadingContent,
}, },
data: function () { data: function () {
@ -154,10 +154,10 @@ export default {
// Focus keys // Focus keys
Mousetrap.bind("pageup", () => { Mousetrap.bind("pageup", () => {
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: 1}); eventBus.emit("globalMoveStepEvent", { x: 0, y: 0, z: 1 });
}); });
Mousetrap.bind("pagedown", () => { Mousetrap.bind("pagedown", () => {
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: -1}); eventBus.emit("globalMoveStepEvent", { x: 0, y: 0, z: -1 });
}); });
this.keyboardManual.push({ this.keyboardManual.push({
shortcut: "pgup / pgdn", shortcut: "pgup / pgdn",
@ -248,9 +248,14 @@ export default {
event.target.parentNode.classList.contains("scrollTarget") || event.target.parentNode.classList.contains("scrollTarget") ||
event.target.classList.contains("scrollTarget") event.target.classList.contains("scrollTarget")
) { ) {
var z_rel = event.deltaY / 100; const z_steps = event.deltaY / 100;
// Emit a signal to move, acted on by panelControl.vue // Emit a signal to move, acted on by panelControl.vue
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: z_rel, absolute: false}); eventBus.emit("globalMoveStepEvent", {
x_steps: 0,
y_steps: 0,
z_steps: z_steps,
absolute: false,
});
} }
}, },
@ -258,7 +263,6 @@ export default {
// Calculate movement array // Calculate movement array
var x_rel = 0; var x_rel = 0;
var y_rel = 0; var y_rel = 0;
var z_rel = 0;
// 37 corresponds to the left key // 37 corresponds to the left key
if (37 in this.arrowKeysDown) { if (37 in this.arrowKeysDown) {
x_rel = x_rel - 1; x_rel = x_rel - 1;
@ -277,7 +281,7 @@ export default {
} }
// Make a position request // Make a position request
// Emit a signal to move, acted on by panelControl.vue // Emit a signal to move, acted on by panelControl.vue
eventBus.emit("globalMoveStepEvent", {x: x_rel, y: y_rel, z: 0}); eventBus.emit("globalMoveStepEvent", { x: x_rel, y: y_rel, z: 0 });
}, },
}, },
}; };

View file

@ -1,7 +1,7 @@
<template> <template>
<div id="app-content" class="uk-margin-remove uk-padding-remove uk-height-1-1" uk-grid> <div id="app-content" class="uk-margin-remove uk-padding-remove uk-height-1-1" uk-grid>
<!-- Initialisation modals --> <!-- Initialisation modals -->
<calibrationWizard ref="calibrationWizard" @onClose="enterApp()"></calibrationWizard> <calibrationWizard ref="calibrationWizard" @on-close="enterApp()"></calibrationWizard>
<!-- Vertical tab bar --> <!-- Vertical tab bar -->
<div id="switcher-left-container"> <div id="switcher-left-container">
<div <div
@ -69,7 +69,7 @@
:require-connection="true" :require-connection="true"
:current-tab="currentTab" :current-tab="currentTab"
> >
<component :is="item.component" @scrollTop="scrollToTop"></component> <component :is="item.component" @scroll-top="scrollToTop"></component>
</tabContent> </tabContent>
</div> </div>
</div> </div>
@ -91,7 +91,7 @@ import settingsContent from "./tabContentComponents/settingsContent.vue";
import slideScanContent from "./tabContentComponents/slideScanContent.vue"; import slideScanContent from "./tabContentComponents/slideScanContent.vue";
import viewContent from "./tabContentComponents/viewContent.vue"; import viewContent from "./tabContentComponents/viewContent.vue";
// vue3 migration // vue3 migration
import { shallowRef, markRaw, ref } from 'vue' import { markRaw } from "vue";
import { eventBus } from "../eventBus.js"; import { eventBus } from "../eventBus.js";
// Import modal components for device initialisation // Import modal components for device initialisation
@ -104,7 +104,7 @@ export default {
components: { components: {
tabIcon, tabIcon,
tabContent, tabContent,
calibrationWizard calibrationWizard,
}, },
data: function () { data: function () {
return { return {

View file

@ -16,7 +16,7 @@
<script> <script>
//vue3 migration //vue3 migration
import { useIntersectionObserver } from '@vueuse/core'; import { useIntersectionObserver } from "@vueuse/core";
// Export main app // Export main app
export default { export default {
@ -42,7 +42,7 @@ export default {
}, },
{ {
threshold: 0.0, threshold: 0.0,
} },
); );
}, },
}; };

View file

@ -10,6 +10,8 @@ export default {
props: {}, props: {},
emits: ["set-tab"],
computed: { computed: {
tooltipOptions: function () { tooltipOptions: function () {
var title = this.id.charAt(0).toUpperCase() + this.id.slice(1); var title = this.id.charAt(0).toUpperCase() + this.id.slice(1);

View file

@ -1,10 +1,10 @@
<template> <template>
<a <a
href="#" href="#"
class="uk-link" class="uk-link"
:class="classObject" :class="classObject"
:uk-tooltip="tooltipOptions ? tooltipOptions : null" :uk-tooltip="tooltipOptions ? tooltipOptions : null"
@click="setThisTab" @click="setThisTab"
> >
<slot></slot> <slot></slot>
<div v-if="showTitle" class="tabtitle"> <div v-if="showTitle" class="tabtitle">
@ -49,6 +49,8 @@ export default {
requireConnection: Boolean, requireConnection: Boolean,
}, },
emits: ["set-tab"],
computed: { computed: {
computedTitle: function () { computedTitle: function () {
if (this.title !== undefined) { if (this.title !== undefined) {

View file

@ -21,7 +21,7 @@
:task-running="taskRunning" :task-running="taskRunning"
:task-started="taskStarted" :task-started="taskStarted"
:task-status="taskStatus" :task-status="taskStatus"
@terminateTask="terminateTask" @terminate-task="terminateTask"
/> />
</div> </div>
</template> </template>
@ -29,33 +29,16 @@
<script> <script>
import ActionProgressBar from "./actionProgressBar.vue"; import ActionProgressBar from "./actionProgressBar.vue";
import ActionStatusModal from "./actionStatusModal.vue"; import ActionStatusModal from "./actionStatusModal.vue";
//vue3 migration //vue3 migration
import { eventBus } from "../../eventBus.js"; import { eventBus } from "../../eventBus.js";
import { useIntersectionObserver } from "@vueuse/core"; import { useIntersectionObserver } from "@vueuse/core";
export default { export default {
name: "ActionButton", name: "ActionButton",
emits: [ components: {
'update:progress',
'update:taskStarted',
'update:taskRunning',
'update:log',
'update:taskStatus',
'submit',
'taskStarted',
'taskRunning',
'response',
'completed',
'cancelled',
'finished',
'error'
],
components: {
ActionProgressBar, ActionProgressBar,
ActionStatusModal ActionStatusModal,
}, },
props: { props: {
@ -119,6 +102,22 @@ export default {
}, },
}, },
emits: [
"update:progress",
"update:taskStarted",
"update:taskRunning",
"update:log",
"update:taskStatus",
"submit",
"taskStarted",
"taskRunning",
"response",
"completed",
"cancelled",
"finished",
"error",
],
data: function () { data: function () {
return { return {
taskUrl: null, taskUrl: null,
@ -173,14 +172,14 @@ export default {
handler(newval) { handler(newval) {
this.$emit("update:log", newval); this.$emit("update:log", newval);
}, },
deep: true deep: true,
}, },
taskStatus: { taskStatus: {
handler(newval) { handler(newval) {
this.$emit("update:taskStatus", newval); this.$emit("update:taskStatus", newval);
}, },
} },
}, },
mounted() { mounted() {
useIntersectionObserver( useIntersectionObserver(

View file

@ -69,7 +69,7 @@ export default {
taskStatus: { taskStatus: {
handler() { handler() {
this.scrollToBottom(); this.scrollToBottom();
} },
}, },
}, },

View file

@ -33,10 +33,11 @@ import { eventBus } from "../../eventBus.js";
export default { export default {
name: "ActionStatusModal", name: "ActionStatusModal",
components: { components: {
ActionProgressBar, ActionProgressBar,
ActionLogDisplay ActionLogDisplay,
}, },
props: { props: {
title: { title: {
type: String, type: String,
@ -69,6 +70,8 @@ export default {
}, },
}, },
emits: ["terminateTask"],
methods: { methods: {
show() { show() {
UIkit.modal(this.$refs.modal).show(); UIkit.modal(this.$refs.modal).show();

View file

@ -106,10 +106,8 @@ export default {
name: "InputFromSchema", name: "InputFromSchema",
components: { components: {
syncPropertyButton syncPropertyButton,
}, },
compatConfig: { COMPONENT_V_MODEL: false },
props: { props: {
dataSchema: { dataSchema: {
type: Object, type: Object,
@ -130,6 +128,10 @@ export default {
}, },
}, },
emits: ["requestUpdate", "sendValue", "animationShown"],
compatConfig: { COMPONENT_V_MODEL: false },
data() { data() {
return { return {
// Initialise with a copy to try to prevent the this.modelValue prop being mutated if // Initialise with a copy to try to prevent the this.modelValue prop being mutated if
@ -139,8 +141,8 @@ export default {
internalValue: Array.isArray(this.modelValue) internalValue: Array.isArray(this.modelValue)
? [...this.modelValue] ? [...this.modelValue]
: typeof this.modelValue === "object" : typeof this.modelValue === "object"
? { ...this.modelValue } ? { ...this.modelValue }
: this.modelValue, : this.modelValue,
// Is edited can't be computed as we mutate internalValue // Is edited can't be computed as we mutate internalValue
isEdited: false, isEdited: false,
animateUpdate: null, animateUpdate: null,
@ -270,7 +272,8 @@ export default {
} }
}, },
updateIsEdited: function () { updateIsEdited: function () {
this.isEdited = this.deepStringify(this.internalValue) !== this.deepStringify(this.modelValue); this.isEdited =
this.deepStringify(this.internalValue) !== this.deepStringify(this.modelValue);
}, },
animationEnd: function () { animationEnd: function () {
this.animateUpdate = null; this.animateUpdate = null;

View file

@ -4,9 +4,9 @@
:data-schema="propertyDescription" :data-schema="propertyDescription"
:label="label" :label="label"
:animate="animate" :animate="animate"
@requestUpdate="readProperty" @request-update="readProperty"
@sendValue="writeProperty" @send-value="writeProperty"
@animationShown="resetAnimate" @animation-shown="resetAnimate"
/> />
</template> </template>
@ -15,12 +15,11 @@ import { formatValue } from "@/js_utils/formatter.mjs";
import InputFromSchema from "./inputFromSchema.vue"; import InputFromSchema from "./inputFromSchema.vue";
// vue3 migration // vue3 migration
export default { export default {
name: "PropertyControl", name: "PropertyControl",
components: { components: {
InputFromSchema InputFromSchema,
}, },
props: { props: {

View file

@ -24,7 +24,7 @@ export default {
name: "ServerSpecifiedActionButton", name: "ServerSpecifiedActionButton",
components: { components: {
ActionButton ActionButton,
}, },
props: { props: {
@ -34,6 +34,8 @@ export default {
}, },
}, },
emits: ["response", "finished"],
methods: { methods: {
/** /**
* Runs when the ActionButton's action completes successfully. * Runs when the ActionButton's action completes successfully.

View file

@ -18,7 +18,7 @@ export default {
name: "ServerSpecifiedPropertyControl", name: "ServerSpecifiedPropertyControl",
components: { components: {
PropertyControl PropertyControl,
}, },
props: { props: {

View file

@ -12,6 +12,8 @@
<script> <script>
export default { export default {
name: "SyncPropertyButton", name: "SyncPropertyButton",
emits: ["click"],
}; };
</script> </script>
@ -26,7 +28,9 @@ export default {
.material-symbols-outlined.sync-icon { .material-symbols-outlined.sync-icon {
color: #888; color: #888;
transition: transform 0.3s ease, color 0.3s ease; transition:
transform 0.3s ease,
color 0.3s ease;
} }
.material-symbols-outlined.sync-icon:hover { .material-symbols-outlined.sync-icon:hover {

View file

@ -15,14 +15,13 @@
<script> <script>
import devTools from "./tabContentComponents/aboutComponents/devTools.vue"; import devTools from "./tabContentComponents/aboutComponents/devTools.vue";
// vue3 migration // vue3 migration
import { markRaw } from "vue";
// Export main app // Export main app
export default { export default {
name: "LoadingContent", name: "LoadingContent",
components: { components: {
devTools devTools,
}, },
data: function () { data: function () {

View file

@ -30,6 +30,8 @@ export default {
components: {}, components: {},
emits: ["onClose"],
data: function () { data: function () {
return { return {
isNeeded: undefined, isNeeded: undefined,

View file

@ -66,6 +66,8 @@ export default {
}, },
}, },
emits: ["back", "next"],
data() { data() {
return { return {
stepIndex: this.startOnLast ? this.steps.length - 1 : 0, stepIndex: this.startOnLast ? this.steps.length - 1 : 0,

View file

@ -9,7 +9,7 @@
<cameraCalibrationSettings <cameraCalibrationSettings
:show-extra-settings="false" :show-extra-settings="false"
:camera-uri="cameraUri" :camera-uri="cameraUri"
@actionFinished="checkCalibrationState" @action-finished="checkCalibrationState"
/> />
</div> </div>
</template> </template>
@ -26,9 +26,11 @@ export default {
components: { components: {
stepTemplateWithStream, stepTemplateWithStream,
cameraCalibrationSettings cameraCalibrationSettings,
}, },
emits: ["awaiting-user"],
computed: { computed: {
cameraUri: function () { cameraUri: function () {
return `${this.$store.getters.baseUri}/camera/`; return `${this.$store.getters.baseUri}/camera/`;

View file

@ -19,8 +19,10 @@ import { markRaw } from "vue";
export default { export default {
name: "CameraCalibrationTask", name: "CameraCalibrationTask",
components: { components: {
calibrationWizardTask}, calibrationWizardTask,
},
props: { props: {
// Standard calibrationWizardTask props below: // Standard calibrationWizardTask props below:
first: Boolean, first: Boolean,
@ -31,9 +33,14 @@ export default {
}, },
}, },
emits: ["next", "back"],
data: function () { data: function () {
return { return {
steps: [{ component: markRaw(camCalibrationExplanation) }, { component: markRaw(cameraMainCalibrationStep)}], steps: [
{ component: markRaw(camCalibrationExplanation) },
{ component: markRaw(cameraMainCalibrationStep) },
],
}; };
}, },
}; };

View file

@ -21,7 +21,7 @@ import { markRaw } from "vue";
export default { export default {
name: "CameraCalibrationTask", name: "CameraCalibrationTask",
components: { components: {
calibrationWizardTask calibrationWizardTask,
}, },
props: { props: {
// Standard calibrationWizardTask props below: // Standard calibrationWizardTask props below:
@ -32,10 +32,15 @@ export default {
default: false, default: false,
}, },
}, },
emits: ["next", "back"],
data: function () { data: function () {
return { return {
steps: [{ component: markRaw(csmExplanation) }, { component: markRaw(focusStep) }, { component: markRaw(runCsmStep) }], steps: [
{ component: markRaw(csmExplanation) },
{ component: markRaw(focusStep) },
{ component: markRaw(runCsmStep) },
],
}; };
}, },
}; };

View file

@ -37,7 +37,7 @@ export default {
components: { components: {
stepTemplateWithStream, stepTemplateWithStream,
ActionButton ActionButton,
}, },
}; };
</script> </script>

View file

@ -8,7 +8,7 @@
<div class="action-button-container"> <div class="action-button-container">
<CSMCalibrationSettings <CSMCalibrationSettings
:show-extra-settings="false" :show-extra-settings="false"
@recalibrateResponse="checkCalibrationState" @recalibrate-response="checkCalibrationState"
/> />
</div> </div>
</template> </template>
@ -28,6 +28,8 @@ export default {
CSMCalibrationSettings, CSMCalibrationSettings,
}, },
emits: ["awaiting-user"],
mounted() { mounted() {
this.checkCalibrationState(); this.checkCalibrationState();
}, },

View file

@ -29,9 +29,10 @@ import { markRaw } from "vue";
export default { export default {
name: "SingleStepTask", name: "SingleStepTask",
components: { components: {
calibrationWizardTask calibrationWizardTask,
}, },
props: { props: {
// This must be sent // This must be sent
stepComponent: { stepComponent: {
@ -56,6 +57,8 @@ export default {
}, },
}, },
emits: ["next", "back"],
data: function () { data: function () {
return { return {
steps: [{ component: markRaw(this.stepComponent), props: this.stepProps }], steps: [{ component: markRaw(this.stepComponent), props: this.stepProps }],

View file

@ -14,7 +14,7 @@ export default {
name: "StepTemplateWithStream", name: "StepTemplateWithStream",
components: { components: {
miniStreamDisplay miniStreamDisplay,
}, },
}; };
</script> </script>

View file

@ -68,8 +68,8 @@ import ActionButton from "../../labThingsComponents/actionButton.vue";
export default { export default {
name: "StatusPane", name: "StatusPane",
components: { components: {
ActionButton ActionButton,
}, },
data: function () { data: function () {

View file

@ -31,7 +31,7 @@ export default {
components: { components: {
devTools, devTools,
statusPane statusPane,
}, },
}; };
</script> </script>

View file

@ -53,7 +53,7 @@ import { useIntersectionObserver } from "@vueuse/core";
export default { export default {
components: { components: {
ActionButton, ActionButton,
ServerSpecifiedPropertyControl ServerSpecifiedPropertyControl,
}, },
data() { data() {
@ -70,10 +70,22 @@ export default {
await this.readSettings(); await this.readSettings();
}, },
mounted() {
useIntersectionObserver(
this.$refs.backgroundDetectContent,
([{ isIntersecting }]) => {
this.visibilityChanged(isIntersecting);
},
{
threshold: 0.0,
},
);
},
methods: { methods: {
async safeReadSettings() { async safeReadSettings() {
if (!this.$store.state.connected) return; if (!this.$store.state.connected) return;
try { try {
await this.readSettings(); await this.readSettings();
} catch (error) { } catch (error) {
@ -111,18 +123,6 @@ export default {
} }
}, },
}, },
mounted() {
useIntersectionObserver(
this.$refs.backgroundDetectContent,
([{ isIntersecting }]) => {
this.visibilityChanged(isIntersecting);
},
{
threshold: 0.0,
},
);
},
}; };
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View file

@ -20,7 +20,7 @@ export default {
components: { components: {
paneBackgroundDetect, paneBackgroundDetect,
streamDisplay streamDisplay,
}, },
}; };
</script> </script>

View file

@ -9,7 +9,7 @@
:submit-label="'Autofocus'" :submit-label="'Autofocus'"
:button-primary="true" :button-primary="true"
:submit-on-event="'globalFastAutofocusEvent'" :submit-on-event="'globalFastAutofocusEvent'"
@taskStarted="onAutofocus" @task-started="onAutofocus"
@finished="afterAutofocus" @finished="afterAutofocus"
@error="modalError" @error="modalError"
/> />
@ -25,7 +25,7 @@ export default {
name: "AutofocusControl", name: "AutofocusControl",
components: { components: {
ActionButton ActionButton,
}, },
data: function () { data: function () {

View file

@ -42,7 +42,7 @@ export default {
components: { components: {
ActionButton, ActionButton,
positionControl, positionControl,
autofocusControl autofocusControl,
}, },
computed: { computed: {

View file

@ -15,8 +15,8 @@ and zero position buttons. It also includes the d-pad.
<!-- Text boxes to set and view position --> <!-- Text boxes to set and view position -->
<div class="input-and-buttons-container"> <div class="input-and-buttons-container">
<input <input
:key="`setPosition_${key}`"
v-for="(_v, key) in setPosition" v-for="(_v, key) in setPosition"
:key="`setPosition_${key}`"
v-model="setPosition[key]" v-model="setPosition[key]"
class="uk-form-small numeric-setting-line-input" class="uk-form-small numeric-setting-line-input"
type="number" type="number"
@ -70,7 +70,7 @@ export default {
components: { components: {
ActionButton, ActionButton,
syncPropertyButton, syncPropertyButton,
stageControlButtons stageControlButtons,
}, },
data: function () { data: function () {

View file

@ -43,7 +43,7 @@ export default {
name: "StageControlButtons", name: "StageControlButtons",
methods: { methods: {
move(x, y, z) { move(x, y, z) {
eventBus.emit("globalMoveStepEvent", {x, y, z, absolute: false}); eventBus.emit("globalMoveStepEvent", { x, y, z, absolute: false });
}, },
}, },
}; };

View file

@ -20,7 +20,7 @@ export default {
components: { components: {
paneControl, paneControl,
streamDisplay streamDisplay,
}, },
}; };
</script> </script>

View file

@ -91,9 +91,11 @@ export default {
components: { components: {
Paginate, Paginate,
EndpointButton EndpointButton,
}, },
emits: ["scrollTop"],
data: function () { data: function () {
return { return {
maxitems: 20, maxitems: 20,

View file

@ -61,7 +61,7 @@ export default {
([{ isIntersecting }]) => { ([{ isIntersecting }]) => {
this.visibilityChanged(isIntersecting); this.visibilityChanged(isIntersecting);
}, },
{ threshold: 0.0 } { threshold: 0.0 },
); );
if (this.src) { if (this.src) {
@ -80,19 +80,17 @@ export default {
visibilityChanged(isVisible) { visibilityChanged(isVisible) {
// adding this check to avoid error when the viewer is not yet initialized. // adding this check to avoid error when the viewer is not yet initialized.
if (isVisible) { if (isVisible) {
if (!this.osdViewer && this.src) { if (!this.osdViewer && this.src) {
this.loadOpenSeaDragon(this.src); this.loadOpenSeaDragon(this.src);
} }
} else { } else {
if (this.osdViewer) { if (this.osdViewer) {
this.osdViewer.destroy(); this.osdViewer.destroy();
this.osdViewer = null; this.osdViewer = null;
} }
} }
}, },
async loadOpenSeaDragon() { async loadOpenSeaDragon() {
if (this.osdViewer) { if (this.osdViewer) {
this.osdViewer.destroy(); this.osdViewer.destroy();

View file

@ -7,7 +7,7 @@
id="thumbnail-stitched-image" id="thumbnail-stitched-image"
class="thumbnail-fit" class="thumbnail-fit"
:src="thumbnailPath" :src="thumbnailPath"
onerror="this.src='/titleiconpink.svg';" onerror="this.src = '/titleiconpink.svg'"
@click="requestViewer" @click="requestViewer"
/> />
</div> </div>
@ -87,9 +87,9 @@ import EndpointButton from "../../labThingsComponents/endpointButton.vue";
// Export main app // Export main app
export default { export default {
name: "ScanCard", name: "ScanCard",
components: { components: {
actionButton, actionButton,
EndpointButton EndpointButton,
}, },
props: { props: {
@ -107,6 +107,8 @@ export default {
}, },
}, },
emits: ["viewer-requested", "update-requested"],
computed: { computed: {
downloadStitchFile() { downloadStitchFile() {
return `${this.$store.getters.baseUri}/smart_scan/get_stitch/${this.scanData.name}`; return `${this.$store.getters.baseUri}/smart_scan/get_stitch/${this.scanData.name}`;

View file

@ -59,8 +59,8 @@ import OpenSeadragonViewer from "./openSeadragonViewer.vue";
export default { export default {
name: "ScanViewerModal", name: "ScanViewerModal",
components: { components: {
OpenSeadragonViewer OpenSeadragonViewer,
}, },
props: { props: {
selectedScan: { selectedScan: {

View file

@ -1,8 +1,5 @@
<template> <template>
<div <div ref="galleryDisplay" class="galleryDisplay uk-padding uk-padding-remove-top">
ref="galleryDisplay"
class="galleryDisplay uk-padding uk-padding-remove-top"
>
<!-- Gallery nav bar --> <!-- Gallery nav bar -->
<nav class="gallery-navbar uk-navbar-container uk-navbar-transparent" uk-navbar="mode: click"> <nav class="gallery-navbar uk-navbar-container uk-navbar-transparent" uk-navbar="mode: click">
<!-- Right side buttons --> <!-- Right side buttons -->
@ -107,12 +104,14 @@ import { useIntersectionObserver } from "@vueuse/core";
// Export main app // Export main app
export default { export default {
name: "ScanListContent", name: "ScanListContent",
components: { components: {
actionButton, actionButton,
scanCard, scanCard,
ScanViewerModal ScanViewerModal,
}, },
emits: ["scrollTop"],
data: function () { data: function () {
return { return {
scans: [], scans: [],

View file

@ -25,7 +25,7 @@ export default {
components: { components: {
CSMCalibrationSettings, CSMCalibrationSettings,
miniStreamDisplay miniStreamDisplay,
}, },
}; };
</script> </script>

View file

@ -66,7 +66,7 @@ export default {
components: { components: {
ActionButton, ActionButton,
matrixDisplay matrixDisplay,
}, },
props: { props: {
@ -77,6 +77,8 @@ export default {
}, },
}, },
emits: ["recalibrateResponse"],
data() { data() {
return { return {
csmMatrix: undefined, csmMatrix: undefined,
@ -101,7 +103,7 @@ export default {
([{ isIntersecting }]) => { ([{ isIntersecting }]) => {
this.visibilityChanged(isIntersecting); this.visibilityChanged(isIntersecting);
}, },
{ threshold: 0.0 } { threshold: 0.0 },
); );
}, },

View file

@ -34,7 +34,7 @@ export default {
components: { components: {
cameraCalibrationSettings, cameraCalibrationSettings,
miniStreamDisplay, miniStreamDisplay,
ServerSpecifiedPropertyControl ServerSpecifiedPropertyControl,
}, },
data() { data() {

View file

@ -23,14 +23,13 @@
<script> <script>
import ServerSpecifiedActionButton from "../../../labThingsComponents/serverSpecifiedActionButton.vue"; import ServerSpecifiedActionButton from "../../../labThingsComponents/serverSpecifiedActionButton.vue";
// vue3 migration // vue3 migration
import { markRaw } from "vue";
// Export main app // Export main app
export default { export default {
name: "CameraCalibrationSettings", name: "CameraCalibrationSettings",
components: { components: {
ServerSpecifiedActionButton ServerSpecifiedActionButton,
}, },
props: { props: {
@ -45,6 +44,8 @@ export default {
}, },
}, },
emits: ["actionFinished"],
data() { data() {
return { return {
primaryCalibrationActions: [], primaryCalibrationActions: [],

View file

@ -15,7 +15,7 @@ export default {
components: { components: {
streamSettings, streamSettings,
appSettings appSettings,
}, },
}; };
</script> </script>

View file

@ -36,7 +36,7 @@ export default {
name: "StageSettings", name: "StageSettings",
components: { components: {
ActionButton ActionButton,
}, },
data: function () { data: function () {
@ -57,7 +57,7 @@ export default {
([{ isIntersecting }]) => { ([{ isIntersecting }]) => {
this.visibilityChanged(isIntersecting); this.visibilityChanged(isIntersecting);
}, },
{ threshold: 0.0 } { threshold: 0.0 },
); );
}, },

View file

@ -70,7 +70,6 @@ import tabContent from "../genericComponents/tabContent.vue";
// vue3 migration // vue3 migration
import { markRaw } from "vue"; import { markRaw } from "vue";
// Export main app // Export main app
export default { export default {
name: "SettingsContent", name: "SettingsContent",
@ -78,7 +77,7 @@ export default {
components: { components: {
tabIcon, tabIcon,
tabContent, tabContent,
calibrationWizard calibrationWizard,
}, },
data: function () { data: function () {

View file

@ -65,10 +65,10 @@
:submit-data="{ scan_name: scan_name }" :submit-data="{ scan_name: scan_name }"
submit-label="Start Smart Scan" submit-label="Start Smart Scan"
:can-terminate="true" :can-terminate="true"
@taskStarted="startScanning" @task-started="startScanning"
@beforeUpdate:taskStatus="taskStatus = $event" @before-update:task-status="taskStatus = $event"
@beforeUpdate:progress="progress = $event" @before-update:progress="progress = $event"
@beforeUpdate:log="log = $event" @before-update:log="log = $event"
/> />
</div> </div>
</div> </div>
@ -143,7 +143,7 @@ export default {
actionProgressBar, actionProgressBar,
MiniStreamDisplay, MiniStreamDisplay,
ActionButton, ActionButton,
ServerSpecifiedPropertyControl ServerSpecifiedPropertyControl,
}, },
data() { data() {
@ -176,7 +176,11 @@ export default {
async created() { async created() {
this.readSettings(); this.readSettings();
this.workflowOptions = await this.readThingProperty("smart_scan", "workflow_display_names", true); this.workflowOptions = await this.readThingProperty(
"smart_scan",
"workflow_display_names",
true,
);
}, },
mounted() { mounted() {
@ -203,16 +207,21 @@ export default {
this.workflowName = await this.readThingProperty("smart_scan", "workflow_name"); this.workflowName = await this.readThingProperty("smart_scan", "workflow_name");
if (!this.workflowName) { if (!this.workflowName) {
console.warn("Could not read workflow_name, using default"); console.warn("Could not read workflow_name, using default");
this.workflowName = "histo_scan_workflow"; this.workflowName = "histo_scan_workflow";
} }
if (this.workflowName) { if (this.workflowName) {
console.log("Current workflow name: ", this.workflowName); console.log("Current workflow name: ", this.workflowName);
this.ready = await this.readThingProperty(this.workflowName, "ready", true); this.ready = await this.readThingProperty(this.workflowName, "ready", true);
this.workflowSettings = await this.readThingProperty(this.workflowName, "settings_ui", true) || []; this.workflowSettings =
(await this.readThingProperty(this.workflowName, "settings_ui", true)) || [];
console.log(this.workflowSettings); console.log(this.workflowSettings);
this.workflowDisplayName = await this.readThingProperty(this.workflowName, "display_name", true); this.workflowDisplayName = await this.readThingProperty(
this.workflowName,
"display_name",
true,
);
this.workflowBlurb = await this.readThingProperty(this.workflowName, "ui_blurb", true); this.workflowBlurb = await this.readThingProperty(this.workflowName, "ui_blurb", true);
} }
}, },
@ -256,7 +265,7 @@ export default {
this.lastStitchedImage = `${this.$store.getters.baseUri}/smart_scan/latest_preview_stitch.jpg?t=${mtime}`; this.lastStitchedImage = `${this.$store.getters.baseUri}/smart_scan/latest_preview_stitch.jpg?t=${mtime}`;
console.log("Updated preview image URL: ", this.lastStitchedImage); console.log("Updated preview image URL: ", this.lastStitchedImage);
} }
this.lastScanName = await this.readThingProperty("smart_scan", "latest_scan_name", true); this.lastScanName = await this.readThingProperty("smart_scan", "latest_scan_name", true);
setTimeout(this.pollScan, 1000); // keep rescheduling until it's stopped setTimeout(this.pollScan, 1000); // keep rescheduling until it's stopped
} }
@ -270,7 +279,13 @@ export default {
// refresh UI // refresh UI
await this.readSettings(); await this.readSettings();
console.log("readsettings values: ", this.workflowName, this.workflowSettings, this.workflowDisplayName, this.workflowBlurb); console.log(
"readsettings values: ",
this.workflowName,
this.workflowSettings,
this.workflowDisplayName,
this.workflowBlurb,
);
} catch (err) { } catch (err) {
this.modalError(err); this.modalError(err);

View file

@ -50,7 +50,7 @@ export default {
resizeTimeoutId: setTimeout(this.doneResizing, 500), resizeTimeoutId: setTimeout(this.doneResizing, 500),
}; };
}, },
computed: { computed: {
streamEnabled: function () { streamEnabled: function () {
return this.$store.getters.ready && !this.$store.state.disableStream; return this.$store.getters.ready && !this.$store.state.disableStream;
@ -65,7 +65,7 @@ export default {
}, },
mounted() { mounted() {
//set up an intersection observer //set up an intersection observer
useIntersectionObserver( useIntersectionObserver(
this.$refs.streamDisplay, this.$refs.streamDisplay,
([{ isIntersecting }]) => { ([{ isIntersecting }]) => {
@ -73,7 +73,7 @@ export default {
}, },
{ {
threshold: 0.0, threshold: 0.0,
} },
); );
// A global signal listener to flash the stream element // A global signal listener to flash the stream element
this.onFlashStream = () => { this.onFlashStream = () => {
@ -81,7 +81,7 @@ export default {
}; };
eventBus.on("globalFlashStream", this.onFlashStream); eventBus.on("globalFlashStream", this.onFlashStream);
// Mutation observer // Mutation observer
this.sizeObserver = new ResizeObserver(() => { this.sizeObserver = new ResizeObserver(() => {
this.handleResize(); // For any element attached to the observer, run handleResize() on change this.handleResize(); // For any element attached to the observer, run handleResize() on change
@ -141,8 +141,8 @@ export default {
// Emit a signal to move, acted on by paneControl.vue // Emit a signal to move, acted on by paneControl.vue
eventBus.emit("globalMoveInImageCoordinatesEvent", { eventBus.emit("globalMoveInImageCoordinatesEvent", {
x:-xRelative, x: -xRelative,
y:-yRelative y: -yRelative,
}); });
}, },

View file

@ -10,7 +10,6 @@
<script> <script>
import streamDisplay from "./streamContent.vue"; import streamDisplay from "./streamContent.vue";
// vue3 migration // vue3 migration
import { markRaw } from "vue";
export default { export default {
name: "ViewContent", name: "ViewContent",

View file

@ -1,6 +1,5 @@
// Generic functions for formatting // Generic functions for formatting
/** /**
* Format a single number into a human-readable string. * Format a single number into a human-readable string.
* Uses exponential notation for very large/small numbers. * Uses exponential notation for very large/small numbers.
@ -30,7 +29,7 @@ export function formatNumber(num, maxDigits = 4) {
*/ */
export function formatValue(value, maxDigits = 4) { export function formatValue(value, maxDigits = 4) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const items = value.map(val => formatValue(val, maxDigits)); const items = value.map((val) => formatValue(val, maxDigits));
return `[${items.join(", ")}]`; return `[${items.join(", ")}]`;
} }
if (typeof value === "object" && value !== null) { if (typeof value === "object" && value !== null) {
@ -47,4 +46,4 @@ export function formatValue(value, maxDigits = 4) {
} }
// Only if the string will not coerce to a number do we output the value. // Only if the string will not coerce to a number do we output the value.
return value; return value;
} }

View file

@ -1,4 +1,4 @@
import { createApp } from 'vue'; import { createApp } from "vue";
import App from "./App.vue"; import App from "./App.vue";
import store from "./store"; import store from "./store";
import UIkit from "uikit"; import UIkit from "uikit";
@ -8,7 +8,7 @@ import "material-symbols/outlined.css";
//import queryMixin from "@/mixins/labThingsMixins.js"; //import queryMixin from "@/mixins/labThingsMixins.js";
import modalMixin from "@/mixins/modalMixins.js"; import modalMixin from "@/mixins/modalMixins.js";
import labThingsMixins from './mixins/labThingsMixins'; import labThingsMixins from "./mixins/labThingsMixins";
// UIKit overrides // UIKit overrides
UIkit.mixin( UIkit.mixin(

View file

@ -59,7 +59,7 @@ export default {
// `false` fails because axios somehow eats it! // `false` fails because axios somehow eats it!
// Other values should not be stringified or pydantic // Other values should not be stringified or pydantic
// can't parse them. // can't parse them.
if ((value === false) || (value === true)) { if (value === false || value === true) {
value = JSON.stringify(value); value = JSON.stringify(value);
} }
await axios.put(url, value); await axios.put(url, value);
@ -91,7 +91,7 @@ export default {
response = await axios.get(taskUrl, { baseURL: this.$store.getters.baseUri }); response = await axios.get(taskUrl, { baseURL: this.$store.getters.baseUri });
const result = response.data.status; const result = response.data.status;
if ((result === "running") || (result === "pending")) { if (result === "running" || result === "pending") {
ongoingMethod?.(response); ongoingMethod?.(response);
this.pollTimers[taskUrl] = setTimeout(() => { this.pollTimers[taskUrl] = setTimeout(() => {
this.pollUntilComplete(taskUrl, ongoingMethod, finalMethod, interval); this.pollUntilComplete(taskUrl, ongoingMethod, finalMethod, interval);

View file

@ -5,9 +5,9 @@
// Important: This is a preliminary setup, for vue2 to vue3 migration purposes. // Important: This is a preliminary setup, for vue2 to vue3 migration purposes.
// Note: Comments are generated to explain relevant configuration options. // Note: Comments are generated to explain relevant configuration options.
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from "node:url";
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import vue from '@vitejs/plugin-vue' import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@ -17,27 +17,27 @@ export default defineConfig({
compilerOptions: { compilerOptions: {
// Enable Vue 2 compatibility mode. // Enable Vue 2 compatibility mode.
compatConfig: { compatConfig: {
MODE: 2 MODE: 2,
} },
} },
} },
}), }),
], ],
resolve: { resolve: {
alias: { alias: {
// Use Vue 2 compatible build. // Use Vue 2 compatible build.
'vue': '@vue/compat', vue: "@vue/compat",
// Setup path alias for src directory. // Setup path alias for src directory.
// This allows importing modules using '@/path/to/module'. // This allows importing modules using '@/path/to/module'.
'@': fileURLToPath(new URL('./src', import.meta.url)) "@": fileURLToPath(new URL("./src", import.meta.url)),
}, },
// Recognize these file extensions for module resolution. // Recognize these file extensions for module resolution.
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'], extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
}, },
server: { server: {
host: true, host: true,
// Set the development server port to 8080. // Set the development server port to 8080.
// OFM uses port 5000, so we avoid conflicts. run, and override by using the address: // OFM uses port 5000, so we avoid conflicts. run, and override by using the address:
// http://microscope.local:8080/?overrideOrigin=http://microscope.local:5000# // http://microscope.local:8080/?overrideOrigin=http://microscope.local:5000#
port: 8080, port: 8080,
strictPort: true, strictPort: true,
@ -46,12 +46,12 @@ export default defineConfig({
preprocessorOptions: { preprocessorOptions: {
less: { less: {
// Always include math in Less files. // Always include math in Less files.
math: 'always', math: "always",
// Enable relative URLs in Less files. // Enable relative URLs in Less files.
relativeUrls: true, relativeUrls: true,
// Enable JavaScript in Less files // Enable JavaScript in Less files
javascriptEnabled: true, javascriptEnabled: true,
} },
} },
} },
}) });