412 lines
13 KiB
Vue
412 lines
13 KiB
Vue
<template>
|
|
<div class="connectDisplay uk-padding uk-padding-remove-left">
|
|
<div
|
|
uk-grid
|
|
class="uk-height-1-1 uk-margin-remove uk-padding-remove uk-flex-column"
|
|
margin="0"
|
|
>
|
|
<div class="uk-width-auto">
|
|
<div
|
|
id="new-connection-card"
|
|
class="uk-card uk-card-default uk-padding-remove uk-width-medium connect-card-align-top"
|
|
>
|
|
<div class="uk-card-body uk-padding-small">
|
|
<form id="formConnectToHost" @submit.prevent="handleSubmit">
|
|
<div class="uk-form-controls uk-margin">
|
|
<label
|
|
><input
|
|
v-model="computedLocalMode"
|
|
class="uk-radio"
|
|
type="radio"
|
|
name="radio_local"
|
|
:value="true"
|
|
/>
|
|
Connect locally</label
|
|
><br />
|
|
<label
|
|
><input
|
|
v-model="computedLocalMode"
|
|
class="uk-radio"
|
|
type="radio"
|
|
name="radio_local"
|
|
:value="false"
|
|
checked
|
|
/>
|
|
Connect remotely</label
|
|
>
|
|
</div>
|
|
<div v-if="!localMode">
|
|
<div class="uk-inline uk-width-1-1">
|
|
<span class="uk-form-icon"
|
|
><i class="material-icons">dns</i></span
|
|
>
|
|
<input
|
|
v-model="hostname"
|
|
:class="IpFormClasses"
|
|
class="uk-input uk-form-small"
|
|
type="text"
|
|
placeholder="Hostname or IP address"
|
|
/>
|
|
</div>
|
|
<label class="uk-form-label" for="form-stacked-text"
|
|
>Port</label
|
|
>
|
|
<div class="uk-form-controls">
|
|
<input
|
|
id="form-stacked-text"
|
|
v-model="computedPort"
|
|
class="uk-input uk-form-small"
|
|
type="number"
|
|
value="5000"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="uk-card-footer uk-padding-small">
|
|
<button
|
|
type="submit"
|
|
form="formConnectToHost"
|
|
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
|
@click="handleSubmit"
|
|
>
|
|
Connect
|
|
</button>
|
|
|
|
<button
|
|
v-if="$store.getters.ready"
|
|
class="uk-button uk-button-default uk-form-small uk-margin-small uk-width-1-1"
|
|
@click="saveHost()"
|
|
>
|
|
Save Current
|
|
</button>
|
|
|
|
<button
|
|
v-if="$store.getters.ready"
|
|
class="uk-button uk-button-danger uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
|
@click="$store.commit('resetState')"
|
|
>
|
|
Disconnect
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="uk-width-expand">
|
|
<ul uk-accordion="multiple: true; animation: false">
|
|
<li v-show="isElectron" id="nearby-connections-grid" class="uk-open">
|
|
<a class="uk-accordion-title" href="#">Nearby devices</a>
|
|
<div class="uk-accordion-content">
|
|
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
|
<div v-for="host in foundHostArray" :key="host.name">
|
|
<hostCard
|
|
:name="host.name"
|
|
:hostname="host.hostname"
|
|
:port="host.port"
|
|
:deletable="false"
|
|
@connect="handleConnectButton(host)"
|
|
></hostCard>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
|
|
<li id="saved-connections-grid" class="uk-open">
|
|
<a class="uk-accordion-title" href="#">Saved devices</a>
|
|
<div class="uk-accordion-content">
|
|
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
|
<div v-for="host in savedHosts" :key="host.name">
|
|
<hostCard
|
|
:name="host.name"
|
|
:hostname="host.hostname"
|
|
:port="host.port"
|
|
@connect="handleConnectButton(host)"
|
|
@delete="delSavedHost(host)"
|
|
></hostCard>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
// Import mDNS package if running in Electron
|
|
import isElectron from "../../modules/isElectron";
|
|
if (isElectron()) {
|
|
var mdns = require("mdns-js");
|
|
}
|
|
|
|
import axios from "axios";
|
|
|
|
import hostCard from "./connectComponents/hostCard.vue";
|
|
|
|
// Export main app
|
|
export default {
|
|
name: "ConnectDisplay",
|
|
|
|
components: {
|
|
hostCard
|
|
},
|
|
|
|
data: function() {
|
|
return {
|
|
isElectron: isElectron(),
|
|
localMode: true,
|
|
hostname: "",
|
|
port: 5000,
|
|
selectedHost: "",
|
|
savedHosts: [],
|
|
foundHosts: {}
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
foundHostArray: function() {
|
|
return Object.values(this.foundHosts);
|
|
},
|
|
// Stylises the hostname input box based on connection status
|
|
IpFormClasses: function() {
|
|
return {
|
|
"uk-form-danger": !this.$store.state.available,
|
|
"uk-form-success": this.$store.getters.ready
|
|
};
|
|
},
|
|
|
|
computedLocalMode: {
|
|
get: function() {
|
|
return this.localMode;
|
|
},
|
|
set: function(state) {
|
|
this.localMode = state;
|
|
this.setLocalMode(state);
|
|
}
|
|
},
|
|
|
|
computedPort: {
|
|
get: function() {
|
|
if (this.hostname.includes(":")) {
|
|
var port = parseInt(this.hostname.split(":")[1]);
|
|
return !isNaN(port) ? port : this.port;
|
|
} else {
|
|
return this.port;
|
|
}
|
|
},
|
|
set: function(newPort) {
|
|
this.port = newPort;
|
|
if (this.hostname.includes(":")) {
|
|
this.hostname = this.hostname.split(":")[0] + ":" + this.port;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// When savedHosts changes, serialise to JSON and save to localStorage
|
|
watch: {
|
|
savedHosts() {
|
|
this.setLocalStorageObj("savedHosts", this.savedHosts);
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
// Propagate localMode settings
|
|
this.setLocalMode(this.localMode);
|
|
|
|
// Try loading savedHosts from localStorage. If null, don't change.
|
|
this.savedHosts = this.getLocalStorageObj("savedHosts") || this.savedHosts;
|
|
|
|
// Handle mDNS browsing
|
|
if (mdns) {
|
|
// TODO: Have this run periodically on a timer
|
|
|
|
// Create a browser to search for 'openflexure' type services
|
|
var browser = mdns.createBrowser(mdns.tcp("openflexure"));
|
|
|
|
// Start discovering services when ready
|
|
browser.on("ready", function() {
|
|
browser.discover();
|
|
});
|
|
|
|
browser.on("update", data => {
|
|
console.log(data);
|
|
|
|
// We will be checking if it's a valid openflexure device
|
|
var validDevice = false;
|
|
|
|
// Go through each type of the host, make valid if 'openflexure' appears
|
|
data.type.forEach(element => {
|
|
console.log(element);
|
|
if (element.name === "openflexure") {
|
|
validDevice = true;
|
|
}
|
|
});
|
|
|
|
var hostData = {
|
|
hostname: data.addresses[0],
|
|
name: `${data.host} on ${data.networkInterface}`,
|
|
port: data.port
|
|
};
|
|
|
|
if (typeof data.port !== "undefined" && validDevice === true) {
|
|
this.$set(this.foundHosts, hostData.hostname, hostData);
|
|
}
|
|
|
|
console.log(this.foundHosts);
|
|
});
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
connectToHost: function(host) {
|
|
console.log(host);
|
|
// Set the global form values
|
|
this.hostname = host.hostname;
|
|
this.port = host.port;
|
|
|
|
// Commit the hostname and port to store
|
|
this.$store.commit("resetState");
|
|
this.$store.commit("changeHost", [host.hostname, host.port]);
|
|
this.$store.commit("changeWaiting", true);
|
|
// Try to get list of available routes
|
|
axios
|
|
.get(`${this.$store.getters.baseUri}/routes`)
|
|
.then(response => {
|
|
console.log(response.data);
|
|
// If the /api/v2 route is available
|
|
if (Object.keys(response.data).includes("/api/v2/")) {
|
|
console.log("API v2 available");
|
|
// Tell Vuex store that we're connected
|
|
this.$store.commit("setConnected");
|
|
// Check client and server match
|
|
this.checkServerVersion();
|
|
} else {
|
|
// Error and no-connect if API v2 is missing
|
|
var ApiVersionError = `Your microscope is running an old API version.\
|
|
You must update your microscope software to continue.\
|
|
<br><br>
|
|
For API upgrades, burning the latest Raspbian-OpenFlexure to your SD card is recommended.\
|
|
<br><br>
|
|
<b>Downloads and instructions can be found <a target="_blank" href="https://openflexure.org/projects/microscope/install">here</a></b>`;
|
|
this.modalDialog("API upgrade required", ApiVersionError);
|
|
this.$store.commit("setError");
|
|
}
|
|
})
|
|
.catch(error => {
|
|
this.$store.commit("setError");
|
|
this.modalError(error); // Let mixin handle error
|
|
});
|
|
},
|
|
|
|
handleSubmit: function() {
|
|
// Split host and port if needed
|
|
if (this.hostname.includes(":")) {
|
|
this.port = this.computedPort;
|
|
this.hostname = this.hostname.split(":")[0];
|
|
}
|
|
|
|
// Handle auto-local-connect
|
|
var hostname;
|
|
if (this.localMode) {
|
|
hostname = "localhost";
|
|
} else {
|
|
hostname = this.hostname;
|
|
}
|
|
|
|
var selectedHost = {
|
|
hostname: hostname,
|
|
port: this.port
|
|
};
|
|
|
|
this.connectToHost(selectedHost);
|
|
},
|
|
|
|
handleConnectButton: function(host) {
|
|
this.computedLocalMode = false;
|
|
this.connectToHost(host);
|
|
},
|
|
|
|
checkServerVersion: function() {
|
|
var versionUri = `${this.$store.getters.baseUri}/api/v2/instrument/configuration/application/version`;
|
|
axios
|
|
.get(versionUri)
|
|
.then(response => {
|
|
var serverVersion = response.data;
|
|
var clientVersion = process.env.PACKAGE.version;
|
|
var clientVersionMajor = clientVersion.substring(0, 3);
|
|
console.log(clientVersionMajor);
|
|
|
|
if (serverVersion != undefined) {
|
|
var serverVersionMajor = serverVersion.substring(0, 3);
|
|
}
|
|
console.log(serverVersionMajor);
|
|
|
|
if (
|
|
serverVersion == undefined ||
|
|
serverVersionMajor != clientVersionMajor
|
|
) {
|
|
var versionWarning = `Client and microscope versions do not match.\
|
|
Consider updating your microscope software.\
|
|
Some functionality may currently be broken.<br><br> \
|
|
<b>Client version:</b> ${clientVersion}<br> \
|
|
<b>Server version:</b> ${serverVersion}<br><br>`;
|
|
if (serverVersion < 1.1) {
|
|
versionWarning =
|
|
versionWarning +
|
|
"You may need to install a never server version on a clean SD card.";
|
|
} else {
|
|
versionWarning =
|
|
versionWarning +
|
|
"Try running 'ofm upgrade' on your microscope.";
|
|
}
|
|
this.modalDialog("Version mismatch", versionWarning);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
this.modalError(error); // Let mixin handle error
|
|
});
|
|
},
|
|
|
|
setLocalMode: function(state) {
|
|
this.$store.commit("changeSetting", ["trackWindow", state]);
|
|
this.$store.commit("changeSetting", ["disableStream", state]);
|
|
this.$store.commit("changeSetting", ["autoGpuPreview", state]);
|
|
//this.$root.$emit('globalTogglePreview', state)
|
|
},
|
|
|
|
delSavedHost: function(host) {
|
|
console.log(host);
|
|
var index = this.savedHosts.indexOf(host);
|
|
if (index > -1) {
|
|
this.savedHosts.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
saveHost: function() {
|
|
// URI to get hostname directly from settings
|
|
var hostnameUri = `${this.$store.getters.baseUri}/api/v2/instrument/settings/name`;
|
|
axios
|
|
.get(hostnameUri)
|
|
.then(response => {
|
|
// Get device name from response
|
|
var deviceName = response.data;
|
|
// We use unshift instead of push to add the entry to the beginning of the array
|
|
this.savedHosts.unshift({
|
|
name: deviceName,
|
|
hostname: this.$store.state.host,
|
|
port: this.$store.state.port
|
|
});
|
|
})
|
|
.catch(error => {
|
|
this.modalError(error); // Let mixin handle error
|
|
});
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
<style scoped lang="less"></style>
|