Merge branch 'integrated-slidescan' into 'master'
Integrated slidescan See merge request openflexure/openflexure-microscope-server!71
This commit is contained in:
commit
fa20475ab7
9 changed files with 496 additions and 59 deletions
|
|
@ -10,7 +10,7 @@
|
||||||
"license": "GNU General Public License v3.0 ",
|
"license": "GNU General Public License v3.0 ",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vue-cli-service build --mode production",
|
"build": "vue-cli-service build --mode production",
|
||||||
"serve": "vue-cli-service serve --mode development"
|
"serve": "vue-cli-service serve --mode development"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"material-design-icons": "^3.0.1",
|
"material-design-icons": "^3.0.1",
|
||||||
|
|
|
||||||
|
|
@ -55,15 +55,20 @@
|
||||||
>
|
>
|
||||||
<i class="material-icons">camera_alt</i>
|
<i class="material-icons">camera_alt</i>
|
||||||
</tabIcon>
|
</tabIcon>
|
||||||
<tabIcon
|
|
||||||
id="settings-tab-icon"
|
<template v-if="$store.state.globalSettings.IHIEnabled">
|
||||||
tab-i-d="settings"
|
<hr id="extension-tab-divider" />
|
||||||
:require-connection="false"
|
|
||||||
:current-tab="currentTab"
|
<tabIcon
|
||||||
@set-tab="setTab"
|
id="slidescan-tab-icon"
|
||||||
>
|
tab-i-d="slidescan"
|
||||||
<i class="material-icons">settings</i>
|
:require-connection="true"
|
||||||
</tabIcon>
|
:current-tab="currentTab"
|
||||||
|
@set-tab="setTab"
|
||||||
|
>
|
||||||
|
<i class="material-icons">settings_overscan</i>
|
||||||
|
</tabIcon>
|
||||||
|
</template>
|
||||||
|
|
||||||
<hr id="extension-tab-divider" />
|
<hr id="extension-tab-divider" />
|
||||||
|
|
||||||
|
|
@ -81,8 +86,18 @@
|
||||||
</tabIcon>
|
</tabIcon>
|
||||||
|
|
||||||
<tabIcon
|
<tabIcon
|
||||||
id="about-tab-icon"
|
id="settings-tab-icon"
|
||||||
class="uk-margin-auto-top"
|
class="uk-margin-auto-top"
|
||||||
|
tab-i-d="settings"
|
||||||
|
:require-connection="false"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
@set-tab="setTab"
|
||||||
|
>
|
||||||
|
<i class="material-icons">settings</i>
|
||||||
|
</tabIcon>
|
||||||
|
|
||||||
|
<tabIcon
|
||||||
|
id="about-tab-icon"
|
||||||
tab-i-d="about"
|
tab-i-d="about"
|
||||||
:require-connection="false"
|
:require-connection="false"
|
||||||
:current-tab="currentTab"
|
:current-tab="currentTab"
|
||||||
|
|
@ -125,6 +140,17 @@
|
||||||
>
|
>
|
||||||
<captureContent />
|
<captureContent />
|
||||||
</tabContent>
|
</tabContent>
|
||||||
|
|
||||||
|
<template v-if="$store.state.globalSettings.IHIEnabled">
|
||||||
|
<tabContent
|
||||||
|
tab-i-d="slidescan"
|
||||||
|
:require-connection="true"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
>
|
||||||
|
<slideScanContent />
|
||||||
|
</tabContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
<tabContent
|
<tabContent
|
||||||
tab-i-d="settings"
|
tab-i-d="settings"
|
||||||
:require-connection="false"
|
:require-connection="false"
|
||||||
|
|
@ -170,6 +196,7 @@ import tabContent from "./genericComponents/tabContent";
|
||||||
// Import new content components
|
// Import new content components
|
||||||
import navigateContent from "./tabContentComponents/navigateContent.vue";
|
import navigateContent from "./tabContentComponents/navigateContent.vue";
|
||||||
import captureContent from "./tabContentComponents/captureContent.vue";
|
import captureContent from "./tabContentComponents/captureContent.vue";
|
||||||
|
import slideScanContent from "./tabContentComponents/slideScanContent.vue";
|
||||||
import viewContent from "./tabContentComponents/viewContent.vue";
|
import viewContent from "./tabContentComponents/viewContent.vue";
|
||||||
import settingsContent from "./tabContentComponents/settingsContent.vue";
|
import settingsContent from "./tabContentComponents/settingsContent.vue";
|
||||||
import galleryContent from "./tabContentComponents/galleryContent.vue";
|
import galleryContent from "./tabContentComponents/galleryContent.vue";
|
||||||
|
|
@ -188,6 +215,7 @@ export default {
|
||||||
tabContent,
|
tabContent,
|
||||||
navigateContent,
|
navigateContent,
|
||||||
captureContent,
|
captureContent,
|
||||||
|
slideScanContent,
|
||||||
viewContent,
|
viewContent,
|
||||||
settingsContent,
|
settingsContent,
|
||||||
galleryContent,
|
galleryContent,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,313 @@
|
||||||
|
<template>
|
||||||
|
<div class="uk-padding-small">
|
||||||
|
<div v-show="!scanUri">No scan extension found</div>
|
||||||
|
<div v-show="scanUri">
|
||||||
|
<form @submit.prevent @keyup.enter="increment()">
|
||||||
|
<div v-show="stepValue == 0" id="step-user">
|
||||||
|
<h3>User information (1/4)</h3>
|
||||||
|
|
||||||
|
<label for="username">Your name:</label>
|
||||||
|
<input
|
||||||
|
id="username"
|
||||||
|
v-model="username"
|
||||||
|
class="uk-input"
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<label for="currentTime">Current time (check this is correct):</label>
|
||||||
|
<input
|
||||||
|
id="currentTime"
|
||||||
|
v-model="currentTimeForm"
|
||||||
|
class="uk-input"
|
||||||
|
type="datetime-local"
|
||||||
|
name="currentTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="stepValue == 1" id="step-patient">
|
||||||
|
<h3>Patient information (2/4)</h3>
|
||||||
|
|
||||||
|
<label for="patientID">Patient ID:</label>
|
||||||
|
<input
|
||||||
|
id="patientID"
|
||||||
|
v-model="patientID"
|
||||||
|
class="uk-input"
|
||||||
|
type="text"
|
||||||
|
name="patientID"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="stepValue == 2" id="step-sample">
|
||||||
|
<h3>Sample information (3/4)</h3>
|
||||||
|
|
||||||
|
<label>Sample type:</label>
|
||||||
|
<br />
|
||||||
|
<input
|
||||||
|
id="typeThin"
|
||||||
|
v-model="sampleType"
|
||||||
|
class="uk-radio"
|
||||||
|
type="radio"
|
||||||
|
value="thin"
|
||||||
|
/>
|
||||||
|
<label for="typeThin">Thin smear</label>
|
||||||
|
<br />
|
||||||
|
<input
|
||||||
|
id="typeThick"
|
||||||
|
v-model="sampleType"
|
||||||
|
class="uk-radio"
|
||||||
|
type="radio"
|
||||||
|
value="thick"
|
||||||
|
/>
|
||||||
|
<label for="typeThick">Thick smear</label>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="stepValue == 3" id="step-scan">
|
||||||
|
<h3>Start scan (4/4)</h3>
|
||||||
|
|
||||||
|
<label>Check details:</label>
|
||||||
|
<p>
|
||||||
|
<b>Your name:</b>
|
||||||
|
{{ username }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Patient ID:</b>
|
||||||
|
{{ patientID }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Sample type:</b>
|
||||||
|
{{ sampleType }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="form-stepper">
|
||||||
|
<p class="warning">{{ message }}</p>
|
||||||
|
<taskSubmitter
|
||||||
|
v-if="scanUri"
|
||||||
|
v-show="stepValue == 3"
|
||||||
|
:submit-url="scanUri"
|
||||||
|
:submit-data="payload"
|
||||||
|
submit-label="Start scan"
|
||||||
|
@submit="scanRunning = true"
|
||||||
|
@response="scanRunning = false"
|
||||||
|
@error="scanRunning = false"
|
||||||
|
></taskSubmitter>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div v-show="!scanRunning" class="grid-container">
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-primary"
|
||||||
|
:disabled="stepValue <= 0"
|
||||||
|
type="button"
|
||||||
|
@click="decrement()"
|
||||||
|
>
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-primary"
|
||||||
|
:disabled="stepValue >= 3"
|
||||||
|
type="button"
|
||||||
|
@click="increment()"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<button
|
||||||
|
v-show="stepValue == 3 && !scanRunning"
|
||||||
|
class="uk-button uk-button-danger uk-width-1-1"
|
||||||
|
:disabled="scanRunning"
|
||||||
|
type="button"
|
||||||
|
@click="restart()"
|
||||||
|
>
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
import taskSubmitter from "../genericComponents/taskSubmitter";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
taskSubmitter
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
scanUri: null,
|
||||||
|
stepValue: 0,
|
||||||
|
hostDeviceName: null,
|
||||||
|
message: null,
|
||||||
|
// Scan info
|
||||||
|
username: "",
|
||||||
|
currentTime: this.getLocalDatetimeString(),
|
||||||
|
patientID: "",
|
||||||
|
sampleType: "thin",
|
||||||
|
scanRunning: false,
|
||||||
|
// Scan settings
|
||||||
|
bayer: false,
|
||||||
|
grid: [10, 10, 9],
|
||||||
|
stride_size: [800, 600, 10],
|
||||||
|
fast_autofocus: true,
|
||||||
|
autofocus_dz: 2000,
|
||||||
|
use_video_port: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
pluginsUri: function() {
|
||||||
|
return `${this.$store.getters.baseUri}/api/v2/extensions`;
|
||||||
|
},
|
||||||
|
currentTimeForm: {
|
||||||
|
get() {
|
||||||
|
// Chop the timezone information from the end
|
||||||
|
return this.currentTime.substr(0, 19);
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
console.log(val);
|
||||||
|
// Get timezone
|
||||||
|
var dt = new Date();
|
||||||
|
var tzo = -dt.getTimezoneOffset(),
|
||||||
|
dif = tzo >= 0 ? "+" : "-",
|
||||||
|
pad = function(num) {
|
||||||
|
var norm = Math.floor(Math.abs(num));
|
||||||
|
return (norm < 10 ? "0" : "") + norm;
|
||||||
|
};
|
||||||
|
// Stick to the end of the new timestring from the form
|
||||||
|
this.currentTime = val + dif + pad(tzo / 60) + ":" + pad(tzo % 60);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
payload: {
|
||||||
|
get() {
|
||||||
|
return {
|
||||||
|
filename: `${this.patientID}_${this.sampleType}`,
|
||||||
|
temporary: false,
|
||||||
|
bayer: this.bayer,
|
||||||
|
grid: this.grid,
|
||||||
|
stride_size: this.stride_size,
|
||||||
|
fast_autofocus: this.fast_autofocus,
|
||||||
|
autofocus_dz: this.autofocus_dz,
|
||||||
|
use_video_port: this.use_video_port,
|
||||||
|
annotations: {
|
||||||
|
patientID: this.patientID,
|
||||||
|
username: this.username,
|
||||||
|
clientDatetime: this.currentTime
|
||||||
|
},
|
||||||
|
tags: ["slidescan"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function() {
|
||||||
|
this.updateScanUri();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateScanUri: function() {
|
||||||
|
axios
|
||||||
|
.get(this.pluginsUri) // Get a list of plugins
|
||||||
|
.then(response => {
|
||||||
|
var plugins = response.data;
|
||||||
|
var foundExtension = plugins.find(
|
||||||
|
e => e.title === "org.openflexure.scan"
|
||||||
|
);
|
||||||
|
// if ScanPlugin is enabled
|
||||||
|
if (foundExtension) {
|
||||||
|
// Get plugin action link
|
||||||
|
this.scanUri = foundExtension.links.tile.href;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.modalError(error); // Let mixin handle error
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
decrement: function() {
|
||||||
|
if (this.stepValue > 0) {
|
||||||
|
this.stepValue = this.stepValue - 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
increment: function() {
|
||||||
|
// Validate sections
|
||||||
|
if (this.stepValue == 0) {
|
||||||
|
if (!this.username) {
|
||||||
|
this.message = "Please enter your name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.stepValue == 1) {
|
||||||
|
if (!this.patientID) {
|
||||||
|
this.message = "Please enter a patient ID";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Upper bound on section number
|
||||||
|
if (this.stepValue < 3) {
|
||||||
|
this.stepValue = this.stepValue + 1;
|
||||||
|
this.message = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
restart: function() {
|
||||||
|
this.stepValue = 0;
|
||||||
|
this.patientID = "";
|
||||||
|
this.currentTime = this.getLocalDatetimeString();
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocalDatetimeString: function() {
|
||||||
|
var dt = new Date();
|
||||||
|
var tzo = -dt.getTimezoneOffset(),
|
||||||
|
dif = tzo >= 0 ? "+" : "-",
|
||||||
|
pad = function(num) {
|
||||||
|
var norm = Math.floor(Math.abs(num));
|
||||||
|
return (norm < 10 ? "0" : "") + norm;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
dt.getFullYear() +
|
||||||
|
"-" +
|
||||||
|
pad(dt.getMonth() + 1) +
|
||||||
|
"-" +
|
||||||
|
pad(dt.getDate()) +
|
||||||
|
"T" +
|
||||||
|
pad(dt.getHours()) +
|
||||||
|
":" +
|
||||||
|
pad(dt.getMinutes()) +
|
||||||
|
":" +
|
||||||
|
pad(dt.getSeconds()) +
|
||||||
|
dif +
|
||||||
|
pad(tzo / 60) +
|
||||||
|
":" +
|
||||||
|
pad(tzo % 60)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
grid-column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: #c11;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
class="uk-button uk-button-danger uk-margin-remove uk-float-right uk-width-1-1"
|
class="uk-button uk-button-danger uk-margin-remove uk-float-right uk-width-1-1"
|
||||||
@click="terminateTask()"
|
@click="terminateTask()"
|
||||||
>
|
>
|
||||||
Terminate
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -193,32 +193,29 @@ export default {
|
||||||
|
|
||||||
var checkCondition = (resolve, reject) => {
|
var checkCondition = (resolve, reject) => {
|
||||||
// If the condition is met, we're done!
|
// If the condition is met, we're done!
|
||||||
axios
|
axios.get(this.taskUrl).then(response => {
|
||||||
.get(this.taskUrl)
|
console.log(response.data.status);
|
||||||
.then(response => {
|
var result = response.data.status;
|
||||||
console.log(response.data.status);
|
// If the task ends with success
|
||||||
var result = response.data.status;
|
if (result == "completed") {
|
||||||
// If the task ends with success
|
resolve(response.data);
|
||||||
if (result == "completed") {
|
}
|
||||||
resolve(response.data);
|
// If task ends with an error
|
||||||
}
|
else if (result == "error") {
|
||||||
// If task ends with an error
|
// Pass the error string back with reject
|
||||||
else if (result == "error") {
|
reject(new Error(response.data.return));
|
||||||
// Pass the error string back with reject
|
}
|
||||||
reject(new Error(response.data.return));
|
// If task ends with termination
|
||||||
}
|
else if (result == "cancelled") {
|
||||||
// If task ends with termination
|
// Pass a generic termination error back with reject
|
||||||
else if (result == "cancelled") {
|
reject(new Error("Task cancelled"));
|
||||||
// Pass a generic termination error back with reject
|
} else {
|
||||||
reject(new Error("Task cancelled"));
|
// Since the task is still running, we can update the progress bar
|
||||||
}
|
this.progress = response.data.progress;
|
||||||
else {
|
// Check again after timeout
|
||||||
// Since the task is still running, we can update the progress bar
|
setTimeout(checkCondition, interval, resolve, reject);
|
||||||
this.progress = response.data.progress;
|
}
|
||||||
// Check again after timeout
|
});
|
||||||
setTimeout(checkCondition, interval, resolve, reject);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise(checkCondition);
|
return new Promise(checkCondition);
|
||||||
|
|
@ -227,20 +224,16 @@ export default {
|
||||||
pollProgress: function() {
|
pollProgress: function() {
|
||||||
console.log("Starting progress polling");
|
console.log("Starting progress polling");
|
||||||
|
|
||||||
axios
|
axios.get(this.taskUrl).then(response => {
|
||||||
.get(this.taskUrl)
|
console.log("PROGRESS RESPONSE: ", response.data.progress);
|
||||||
.then(response => {
|
this.progress = response.data.progress;
|
||||||
console.log("PROGRESS RESPONSE: ", response.data.progress);
|
});
|
||||||
this.progress = response.data.progress;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
terminateTask: function() {
|
terminateTask: function() {
|
||||||
axios
|
axios.delete(this.taskUrl).then(response => {
|
||||||
.delete(this.taskUrl)
|
console.log("TERMINATION RESPONSE: ", response.data);
|
||||||
.then(response => {
|
});
|
||||||
console.log("TERMINATION RESPONSE: ", response.data);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<!-- Grid managing tab content -->
|
||||||
|
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove">
|
||||||
|
<div class="control-component">
|
||||||
|
<paneSlideScan />
|
||||||
|
</div>
|
||||||
|
<div class="view-component uk-width-expand">
|
||||||
|
<streamDisplay />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import paneSlideScan from "../controlComponents/paneSlideScan";
|
||||||
|
import streamDisplay from "../viewComponents/streamDisplay.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SlideScanContent",
|
||||||
|
|
||||||
|
components: {
|
||||||
|
paneSlideScan,
|
||||||
|
streamDisplay
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<div id="appSettings">
|
||||||
|
<h3>Additional features</h3>
|
||||||
|
<p class="uk-margin-small">
|
||||||
|
<label
|
||||||
|
><input v-model="IHIEnabled" class="uk-checkbox" type="checkbox" />
|
||||||
|
Enable IHI Slide Scan</label
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="uk-margin-small uk-width-xlarge">
|
||||||
|
Enabling IHI Slide Scan will add a new tab designed to simplify
|
||||||
|
acquiring blood smear tile scans. </br>
|
||||||
|
While this may be useful for other applications, it is primarily designed
|
||||||
|
for use in clinics acquiring blood smear samples using a 100x oil-immersion
|
||||||
|
objective, with a Raspberry Pi Camera v2.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Export main app
|
||||||
|
export default {
|
||||||
|
name: "FeaturesSettings",
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
IHIEnabled: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.globalSettings.IHIEnabled;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit("changeSetting", ["IHIEnabled", value]);
|
||||||
|
this.$root.$emit("globalSafeTogglePreview", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
IHIEnabled() {
|
||||||
|
console.log("Saving IHIEnabled setting");
|
||||||
|
this.setLocalStorageObj("IHIEnabled", this.IHIEnabled);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
// Try loading settings from localStorage. If null, don't change.
|
||||||
|
this.IHIEnabled = this.getLocalStorageObj("IHIEnabled") || this.IHIEnabled;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less"></style>
|
||||||
|
|
@ -17,6 +17,19 @@
|
||||||
Display
|
Display
|
||||||
</tabIcon>
|
</tabIcon>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<tabIcon
|
||||||
|
id="settings-features-icon"
|
||||||
|
tab-i-d="features"
|
||||||
|
:show-title="false"
|
||||||
|
:show-tooltip="false"
|
||||||
|
:require-connection="false"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
@set-tab="setTab"
|
||||||
|
>
|
||||||
|
Features
|
||||||
|
</tabIcon>
|
||||||
|
</li>
|
||||||
<li class="uk-nav-header">Microscope settings</li>
|
<li class="uk-nav-header">Microscope settings</li>
|
||||||
<li>
|
<li>
|
||||||
<tabIcon
|
<tabIcon
|
||||||
|
|
@ -71,6 +84,16 @@
|
||||||
</div>
|
</div>
|
||||||
</tabContent>
|
</tabContent>
|
||||||
|
|
||||||
|
<tabContent
|
||||||
|
tab-i-d="features"
|
||||||
|
:require-connection="false"
|
||||||
|
:current-tab="currentTab"
|
||||||
|
>
|
||||||
|
<div class="settings-pane uk-padding-small">
|
||||||
|
<featuresSettings />
|
||||||
|
</div>
|
||||||
|
</tabContent>
|
||||||
|
|
||||||
<tabContent
|
<tabContent
|
||||||
tab-i-d="camera"
|
tab-i-d="camera"
|
||||||
:require-connection="true"
|
:require-connection="true"
|
||||||
|
|
@ -116,6 +139,7 @@ import streamSettings from "./settingsComponents/streamSettings.vue";
|
||||||
import microscopeSettings from "./settingsComponents/microscopeSettings.vue";
|
import microscopeSettings from "./settingsComponents/microscopeSettings.vue";
|
||||||
import cameraSettings from "./settingsComponents/cameraSettings.vue";
|
import cameraSettings from "./settingsComponents/cameraSettings.vue";
|
||||||
import appSettings from "./settingsComponents/appSettings.vue";
|
import appSettings from "./settingsComponents/appSettings.vue";
|
||||||
|
import featuresSettings from "./settingsComponents/featuresSettings.vue";
|
||||||
import cameraStageMappingSettings from "./settingsComponents/cameraStageMappingSettings.vue";
|
import cameraStageMappingSettings from "./settingsComponents/cameraStageMappingSettings.vue";
|
||||||
|
|
||||||
// Import generic components
|
// Import generic components
|
||||||
|
|
@ -132,6 +156,7 @@ export default {
|
||||||
microscopeSettings,
|
microscopeSettings,
|
||||||
cameraStageMappingSettings,
|
cameraStageMappingSettings,
|
||||||
appSettings,
|
appSettings,
|
||||||
|
featuresSettings,
|
||||||
tabIcon,
|
tabIcon,
|
||||||
tabContent
|
tabContent
|
||||||
},
|
},
|
||||||
|
|
@ -157,9 +182,6 @@ export default {
|
||||||
// Custom UIkit CSS modifications
|
// Custom UIkit CSS modifications
|
||||||
@import "../../assets/less/theme.less";
|
@import "../../assets/less/theme.less";
|
||||||
|
|
||||||
.settings-pane {
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-nav {
|
.settings-nav {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export default new Vuex.Store({
|
||||||
disableStream: false,
|
disableStream: false,
|
||||||
autoGpuPreview: false,
|
autoGpuPreview: false,
|
||||||
trackWindow: true,
|
trackWindow: true,
|
||||||
|
IHIEnabled: false,
|
||||||
appTheme: "system"
|
appTheme: "system"
|
||||||
},
|
},
|
||||||
activeStreams: {}
|
activeStreams: {}
|
||||||
|
|
|
||||||
14
poetry.lock
generated
14
poetry.lock
generated
|
|
@ -302,7 +302,7 @@ webargs = "^6.0.0"
|
||||||
zeroconf = ">=0.24.5,<0.29.0"
|
zeroconf = ">=0.24.5,<0.29.0"
|
||||||
|
|
||||||
[package.source]
|
[package.source]
|
||||||
reference = "c79e6f28d5ffbd61dcfe7fc94130db604cdb4e2d"
|
reference = "bf41b5009e8e0e465222399f38c0cd2104dbd0b7"
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/labthings/python-labthings.git"
|
url = "https://github.com/labthings/python-labthings.git"
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -718,16 +718,16 @@ description = "Declarative parsing and validation of HTTP request objects, with
|
||||||
name = "webargs"
|
name = "webargs"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
version = "6.1.0"
|
version = "6.1.1"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
marshmallow = ">=2.15.2"
|
marshmallow = ">=2.15.2"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["pytest", "webtest (2.0.35)", "webtest-aiohttp (2.0.0)", "pytest-aiohttp (>=0.3.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)", "mypy (0.770)", "flake8 (3.7.9)", "flake8-bugbear (20.1.4)", "pre-commit (>=1.20,<3.0)", "tox", "mock"]
|
dev = ["pytest", "webtest (2.0.35)", "webtest-aiohttp (2.0.0)", "pytest-aiohttp (>=0.3.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)", "mypy (0.782)", "flake8 (3.8.3)", "flake8-bugbear (20.1.4)", "pre-commit (>=2.4,<3.0)", "tox", "mock"]
|
||||||
docs = ["Sphinx (3.0.3)", "sphinx-issues (1.2.0)", "sphinx-typlog-theme (0.8.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)"]
|
docs = ["Sphinx (3.2.1)", "sphinx-issues (1.2.0)", "sphinx-typlog-theme (0.8.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)"]
|
||||||
frameworks = ["Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)"]
|
frameworks = ["Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)"]
|
||||||
lint = ["mypy (0.770)", "flake8 (3.7.9)", "flake8-bugbear (20.1.4)", "pre-commit (>=1.20,<3.0)"]
|
lint = ["mypy (0.782)", "flake8 (3.8.3)", "flake8-bugbear (20.1.4)", "pre-commit (>=2.4,<3.0)"]
|
||||||
tests = ["pytest", "webtest (2.0.35)", "webtest-aiohttp (2.0.0)", "pytest-aiohttp (>=0.3.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)", "mock"]
|
tests = ["pytest", "webtest (2.0.35)", "webtest-aiohttp (2.0.0)", "pytest-aiohttp (>=0.3.0)", "Flask (>=0.12.2)", "Django (>=1.11.16)", "bottle (>=0.12.13)", "tornado (>=4.5.2)", "pyramid (>=1.9.1)", "webapp2 (>=3.0.0b1)", "falcon (>=2.0.0)", "aiohttp (>=3.0.0)", "mock"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1220,8 +1220,8 @@ urllib3 = [
|
||||||
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
|
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
|
||||||
]
|
]
|
||||||
webargs = [
|
webargs = [
|
||||||
{file = "webargs-6.1.0-py2.py3-none-any.whl", hash = "sha256:cf0b5e2fdfb81f28b9332fce15621069d3fbc910a01c7ca8a5e166371699927b"},
|
{file = "webargs-6.1.1-py2.py3-none-any.whl", hash = "sha256:2ead6ce38559152043ab4ada4d389aef6c804b0c169482e7c92b3f498f690b2c"},
|
||||||
{file = "webargs-6.1.0.tar.gz", hash = "sha256:ebb47fb35c3c4fc764213a17d1686e82fec54759ebed2b0715907d566668bb3f"},
|
{file = "webargs-6.1.1.tar.gz", hash = "sha256:412ecadd977afdea0ed6fa5f5b65ddd13a099269e622ec537f9c74c443ce4d0b"},
|
||||||
]
|
]
|
||||||
werkzeug = [
|
werkzeug = [
|
||||||
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue