openflexure-microscope-server/webapp/src/components/labThingsComponents/propertyControl.vue
Richard Bowman cbd8b090ec Replace tasksubmitter with action-button
I've changed tasksubmitter to accept a "thing" and "action" rather than a single URL. This seems more in keeping with
propertyControl, and eliminates the need for loads of
computed properties.

I've also deleted (rather than just commenting out) chunks of the web app that are no longer in use. These may be
reinstated in the future - but we can get them from git
history. It's less confusing not to have vestigial
code in the repo.

This builds OK but is not, as yet, tested with hardware.
2024-02-29 21:44:39 +00:00

274 lines
6.9 KiB
Vue

<template>
<div>
<label v-if="dataType == 'number'" class="uk-form-label"
>{{ label }}
<div class="input-and-buttons-container">
<input
v-model="value"
class="uk-form-small numeric-setting-line-input"
type="number"
@focusin="focusIn"
@focusout="focusOut"
@keydown="keyDown"
/>
<a class="button-next-to-input" @click="readProperty">
<span class="material-symbols-outlined">refresh</span>
</a>
</div>
</label>
<div v-if="dataType == 'boolean'" class="input-and-buttons-container">
<label class="uk-form-label numeric-setting-line-input">
<input
ref="checkbox"
v-model="value"
class="uk-checkbox"
type="checkbox"
@change="writeProperty"
/>
{{ label }}
</label>
<a class="button-next-to-input" @click="readProperty">
<span class="material-symbols-outlined">refresh</span>
</a>
</div>
<label v-if="dataType == 'number_array'" class="uk-form-label"
>{{ label }}
<div class="input-and-buttons-container">
<input
v-for="i in valueLength"
:key="i"
v-model="value[i - 1]"
class="uk-form-small numeric-setting-line-input"
type="number"
@focusin="focusIn"
@focusout="focusOut"
@keydown="keyDown"
/>
<a class="button-next-to-input" @click="readProperty">
<span class="material-symbols-outlined">refresh</span>
</a>
</div>
</label>
<label v-if="dataType == 'number_object'" class="uk-form-label"
>{{ label }}
<div class="input-and-buttons-container">
<input
v-for="(_v, key) in value"
:key="key"
v-model="value[key]"
class="uk-form-small numeric-setting-line-input"
type="number"
@focusin="focusIn"
@focusout="focusOut"
@keydown="keyDown"
/>
<a class="button-next-to-input" @click="readProperty">
<span class="material-symbols-outlined">refresh</span>
</a>
</div>
</label>
<label v-if="dataType == 'other'" class="uk-form-label"
>{{ label }}
<div class="input-and-buttons-container">
<input
:value="value"
class="uk-form-small numeric-setting-line-input"
type="text"
disabled="true"
/>
</div>
</label>
</div>
</template>
<script>
export default {
name: "PropertyControl",
props: {
label: {
type: String,
default: ""
},
propertyName: {
type: String,
required: true
},
thingName: {
type: String,
required: true
},
readBackDelay: {
type: Number,
default: undefined,
required: false
}
},
data: () => {
return {
value: undefined,
valueOnEnter: undefined,
focused: false
};
},
computed: {
valueLength: function() {
if (this.dataType == "number_array") {
if (this.value == undefined) {
return 0;
}
return this.value.length;
} else {
return 1;
}
},
readBack: function() {
return this.readBackDelay !== undefined;
},
propertyDescription: function() {
try {
return this.thingDescription(this.thingName).properties[
this.propertyName
];
} catch (error) {
return undefined;
}
},
dataType: function() {
let prop = this.propertyDescription;
if (prop == undefined) {
return "undefined";
}
const num_types = ["integer", "float", "number"];
if (num_types.includes(prop.type)) {
return "number";
}
if (prop.type == "array") {
if (num_types.includes(prop.items.type)) {
return "number_array";
}
if (Array.isArray(prop.items)) {
if (prop.items.every(t => num_types.includes(t.type))) {
return "number_array";
}
}
}
if (prop.type == "boolean") {
return "boolean";
}
if (prop.type == "object") {
let numeric = true;
for (let key in prop.properties) {
if (!num_types.includes(prop.properties[key].type)) {
numeric = false;
break;
}
}
if (numeric) {
return "number_object";
}
}
return "other";
}
},
watch: {
propertyDescription: function() {
// Ensure we read the property once the URL is known
this.readProperty();
}
},
mounted: function() {
// Read the property when we're mounted - usually this won't
// work because the URL isn't set yet. However, it's helpful if
// the app is reloaded (e.g. from a dev server).
if (this.value == undefined) {
this.readProperty();
}
},
methods: {
readProperty: async function() {
let data = await this.readThingProperty(
this.thingName,
this.propertyName
);
this.value = data;
return data;
},
writeProperty: async function() {
try {
let requestedValue = this.value;
console.log("writing", requestedValue);
await this.writeThingProperty(
this.thingName,
this.propertyName,
requestedValue
);
if (this.readBack) {
await new Promise(r => setTimeout(r, this.readBackDelay));
let newVal = await this.readProperty();
if (newVal == requestedValue) {
await this.modalNotify(`Set ${this.label} to ${newVal}.`);
} else {
await this.modalNotify(
`Set ${this.label} to ${newVal} (requested ${requestedValue}).`
);
}
} else {
await this.modalNotify(`Set ${this.label} to ${this.value}.`);
}
} catch (error) {
this.modalError(error); // Let mixin handle error
}
},
checkboxUpdated: function() {
if (this.value != this.$refs.checkbox.checked) {
this.value = this.$refs.checkbox.checked;
this.writeProperty();
}
},
focusIn: function(event) {
this.valueOnEnter = event.target.value;
},
focusOut: function(event) {
if (this.valueOnEnter != event.target.value) {
this.writeProperty(event.target.value);
}
},
keyDown: function(event) {
// Pressing enter should set the property, whether or not we think it's changed.
if (event.keyCode == 13) {
this.writeProperty();
}
}
}
};
</script>
<style scoped>
.input-and-buttons-container {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-content: stretch;
align-items: center;
width: 100%;
}
.numeric-setting-line-input {
flex-grow: 1;
margin-left: 5px;
margin-right: 5px;
width: 6em;
}
.button-next-to-input {
flex-grow: 0;
padding-left: 5px;
padding-right: 5px;
vertical-align: middle;
cursor: pointer;
}
</style>