Great big ESLint
This commit is contained in:
parent
051eabbdc3
commit
ebcb938da1
48 changed files with 3890 additions and 2536 deletions
69
src/App.vue
69
src/App.vue
|
|
@ -1,57 +1,55 @@
|
|||
<template>
|
||||
<div id="app" v-bind:class="handleTheme">
|
||||
|
||||
<div id="app" :class="handleTheme">
|
||||
<!-- Grid managing whole app -->
|
||||
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove" margin=0>
|
||||
<panelLeft/>
|
||||
<panelRight/>
|
||||
<div
|
||||
uk-grid
|
||||
class="uk-height-1-1 uk-margin-remove uk-padding-remove"
|
||||
margin="0"
|
||||
>
|
||||
<panelLeft />
|
||||
<panelRight />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Import axios for HTTP requests
|
||||
import axios from 'axios'
|
||||
|
||||
// Import components
|
||||
import panelLeft from './components/panelLeft.vue'
|
||||
import panelRight from './components/panelRight.vue'
|
||||
import panelLeft from "./components/panelLeft.vue";
|
||||
import panelRight from "./components/panelRight.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'app',
|
||||
name: "App",
|
||||
|
||||
components: {
|
||||
panelRight,
|
||||
panelLeft
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {}
|
||||
},
|
||||
|
||||
created: function () {
|
||||
window.addEventListener('beforeunload', this.handleExit)
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleExit: function(event) {
|
||||
console.log("Triggered beforeunload")
|
||||
this.$root.$emit('globalTogglePreview', false)
|
||||
}
|
||||
data: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
computed: {
|
||||
handleTheme: function () {
|
||||
handleTheme: function() {
|
||||
return {
|
||||
'uk-light': this.$store.state.globalSettings.darkMode,
|
||||
'uk-background-secondary': this.$store.state.globalSettings.darkMode
|
||||
}
|
||||
"uk-light": this.$store.state.globalSettings.darkMode,
|
||||
"uk-background-secondary": this.$store.state.globalSettings.darkMode
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {
|
||||
window.addEventListener("beforeunload", this.handleExit);
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleExit: function() {
|
||||
console.log("Triggered beforeunload");
|
||||
this.$root.$emit("globalTogglePreview", false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
|
@ -63,7 +61,8 @@ export default {
|
|||
// We override the custom-electron-titlebar z-index
|
||||
// UIKit lightbox must be able to draw over the titlebar
|
||||
// as it currently always spawns at the root of the DOM
|
||||
.titlebar, .titlebar > * {
|
||||
.titlebar,
|
||||
.titlebar > * {
|
||||
z-index: 1000 !important;
|
||||
}
|
||||
|
||||
|
|
@ -71,10 +70,11 @@ export default {
|
|||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: left;
|
||||
height: 100%
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body, html {
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
@ -83,5 +83,4 @@ body, html {
|
|||
pointer-events: none;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
// Theming specific to the electron app
|
||||
|
||||
.menubar-menu-container {
|
||||
box-shadow: 0.5px 1px 4px 0px rgba(0,0,0,0.3) !important;
|
||||
box-shadow: 0.5px 1px 4px 0px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
.menubar-menu-container > * {
|
||||
box-shadow: none !important;
|
||||
.menubar-menu-container>* {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.menubar-menu-container .action-menu-item, .menubar-menu-container .action-label {
|
||||
.menubar-menu-container .action-menu-item,
|
||||
.menubar-menu-container .action-label {
|
||||
cursor: default
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,35 +8,49 @@
|
|||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta { color: #969896; }
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote { color: @global-danger-background; }
|
||||
.hljs-quote {
|
||||
color: @global-danger-background;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type { color: #1f34aa; }
|
||||
.hljs-type {
|
||||
color: #1f34aa;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute { color: #0086b3; }
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name { color: #63a35c; }
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag { color: #333; }
|
||||
.hljs-tag {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo { color: #795da3; }
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
|
|
@ -48,4 +62,6 @@
|
|||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link { text-decoration: underline; }
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
@ -15,31 +15,31 @@
|
|||
// UIkit
|
||||
// ========================================================================
|
||||
|
||||
@global-font-family: ProximaNova, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
@global-font-size: 14px;
|
||||
@global-font-family: ProximaNova, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
@global-font-size: 14px;
|
||||
|
||||
@global-xxlarge-font-size: 38px;
|
||||
@global-xlarge-font-size: 30px;
|
||||
@global-large-font-size: 24px;
|
||||
@global-medium-font-size: 20px;
|
||||
@global-small-font-size: 14px;
|
||||
@global-xxlarge-font-size: 38px;
|
||||
@global-xlarge-font-size: 30px;
|
||||
@global-large-font-size: 24px;
|
||||
@global-medium-font-size: 20px;
|
||||
@global-small-font-size: 14px;
|
||||
|
||||
@global-emphasis-color: #222;
|
||||
@global-emphasis-color: #222;
|
||||
|
||||
//
|
||||
// Base
|
||||
//
|
||||
|
||||
@base-code-font-family: 'Roboto Mono', monospace;
|
||||
@base-code-font-size: 12px;
|
||||
@base-code-font-family: 'Roboto Mono', monospace;
|
||||
@base-code-font-size: 12px;
|
||||
|
||||
@base-heading-font-weight: 300;
|
||||
@base-heading-font-weight: 300;
|
||||
|
||||
@base-pre-font-size: 12px;
|
||||
@base-pre-padding: 25px;
|
||||
@base-pre-background: @global-muted-background;
|
||||
@base-pre-border-width: 0;
|
||||
@base-pre-border-radius: 0;
|
||||
@base-pre-font-size: 12px;
|
||||
@base-pre-padding: 25px;
|
||||
@base-pre-background: @global-muted-background;
|
||||
@base-pre-border-width: 0;
|
||||
@base-pre-border-radius: 0;
|
||||
|
||||
.hook-base-body() {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
|
@ -51,96 +51,103 @@
|
|||
// Container
|
||||
//
|
||||
|
||||
@container-max-width: 1380px;
|
||||
@container-small-max-width: 650px;
|
||||
@container-max-width: 1380px;
|
||||
@container-small-max-width: 650px;
|
||||
|
||||
//
|
||||
// Navbar
|
||||
//
|
||||
|
||||
@inverse-navbar-nav-item-color: @inverse-global-color;
|
||||
@inverse-navbar-nav-item-hover-color: @inverse-global-emphasis-color;
|
||||
@inverse-navbar-nav-item-color: @inverse-global-color;
|
||||
@inverse-navbar-nav-item-hover-color: @inverse-global-emphasis-color;
|
||||
|
||||
//
|
||||
// Nav
|
||||
//
|
||||
|
||||
@nav-header-font-size: 12px;
|
||||
@nav-header-font-size: 12px;
|
||||
|
||||
//
|
||||
// Subnav
|
||||
//
|
||||
|
||||
@inverse-subnav-item-color: @inverse-global-color;
|
||||
@inverse-subnav-item-hover-color: @inverse-global-emphasis-color;
|
||||
@inverse-subnav-item-color: @inverse-global-color;
|
||||
@inverse-subnav-item-hover-color: @inverse-global-emphasis-color;
|
||||
|
||||
//
|
||||
// Tab
|
||||
//
|
||||
|
||||
@tab-item-padding-horizontal: 10px;
|
||||
@tab-item-padding-vertical: 9px;
|
||||
@tab-item-border-width: 2px;
|
||||
@tab-item-font-size: 12px;
|
||||
@tab-item-padding-horizontal: 10px;
|
||||
@tab-item-padding-vertical: 9px;
|
||||
@tab-item-border-width: 2px;
|
||||
@tab-item-font-size: 12px;
|
||||
|
||||
.hook-tab-item() { line-height: 20px; }
|
||||
.hook-tab-item() {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
//
|
||||
// Table
|
||||
//
|
||||
|
||||
@table-header-cell-font-size: 12px;
|
||||
@table-header-cell-font-size: 12px;
|
||||
|
||||
//
|
||||
// Label
|
||||
//
|
||||
|
||||
@label-font-size: 12px;
|
||||
@label-font-size: 12px;
|
||||
|
||||
//
|
||||
// Text
|
||||
//
|
||||
|
||||
.hook-text-lead() { font-weight: 300; }
|
||||
.hook-text-large() { font-weight: 300; }
|
||||
.hook-text-lead() {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.hook-text-large() {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
//
|
||||
// Utility
|
||||
//
|
||||
|
||||
@inverse-logo-color: @inverse-global-emphasis-color;
|
||||
@inverse-logo-hover-color: @inverse-global-emphasis-color;
|
||||
@inverse-logo-color: @inverse-global-emphasis-color;
|
||||
@inverse-logo-hover-color: @inverse-global-emphasis-color;
|
||||
|
||||
//
|
||||
// Off-canvas
|
||||
//
|
||||
|
||||
@offcanvas-bar-background: #fff;
|
||||
@offcanvas-bar-color-mode: dark;
|
||||
@offcanvas-bar-background: #fff;
|
||||
@offcanvas-bar-color-mode: dark;
|
||||
|
||||
//
|
||||
// Inverse
|
||||
//
|
||||
|
||||
@inverse-global-color: fade(@global-inverse-color, 80%);
|
||||
@inverse-global-muted-color: fade(@global-inverse-color, 60%);
|
||||
@inverse-global-color: fade(@global-inverse-color, 80%);
|
||||
@inverse-global-muted-color: fade(@global-inverse-color, 60%);
|
||||
|
||||
//
|
||||
// Paper
|
||||
//
|
||||
@paper-border-radius: 4px;
|
||||
@paper-border-radius: 4px;
|
||||
|
||||
|
||||
/* ========================================================================
|
||||
Theme
|
||||
========================================================================== */
|
||||
|
||||
@sidebar-left-width: 240px;
|
||||
@sidebar-left-width-xl: 300px;
|
||||
@sidebar-left-width: 240px;
|
||||
@sidebar-left-width-xl: 300px;
|
||||
|
||||
@sidebar-right-width: 200px;
|
||||
@sidebar-right-left: 0px;
|
||||
@sidebar-right-left-xl: 60px;
|
||||
@sidebar-right-width: 200px;
|
||||
@sidebar-right-left: 0px;
|
||||
@sidebar-right-left-xl: 60px;
|
||||
|
||||
|
||||
|
||||
|
|
@ -152,11 +159,11 @@
|
|||
*/
|
||||
|
||||
// Line Mode
|
||||
@navbar-nav-item-line-margin-vertical: 20px;
|
||||
@navbar-nav-item-line-margin-horizontal: @navbar-nav-item-padding-horizontal;
|
||||
@navbar-nav-item-line-height: 1px;
|
||||
@navbar-nav-item-line-background: currentColor;
|
||||
@navbar-nav-item-line-transition-duration: 0.3s;
|
||||
@navbar-nav-item-line-margin-vertical: 20px;
|
||||
@navbar-nav-item-line-margin-horizontal: @navbar-nav-item-padding-horizontal;
|
||||
@navbar-nav-item-line-height: 1px;
|
||||
@navbar-nav-item-line-background: currentColor;
|
||||
@navbar-nav-item-line-transition-duration: 0.3s;
|
||||
|
||||
.uk-navbar-dropdown.uk-open {
|
||||
border-radius: @paper-border-radius;
|
||||
|
|
@ -168,7 +175,7 @@
|
|||
|
||||
.uk-card {
|
||||
border-radius: @paper-border-radius;
|
||||
border: 1px solid rgba(180, 180, 180, 0.25);
|
||||
border: 1px solid rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
|
||||
.uk-card-media-top img {
|
||||
|
|
@ -176,14 +183,15 @@
|
|||
}
|
||||
|
||||
.uk-card-default .uk-card-footer {
|
||||
border-top: 1px solid rgba(180, 180, 180, 0.25);
|
||||
border-top: 1px solid rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
|
||||
.uk-card-primary .uk-card-footer {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.075);
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
|
||||
// Override background colour in dark mode
|
||||
.uk-card-default {
|
||||
background-color: #2a2a2a !important;
|
||||
|
|
@ -228,16 +236,22 @@
|
|||
/*
|
||||
* Links
|
||||
*/
|
||||
.uk-link, .uk-button-link {
|
||||
.uk-link,
|
||||
.uk-button-link {
|
||||
color: @global-muted-color;
|
||||
}
|
||||
|
||||
.uk-link:hover, .uk-button-link:hover, a:hover {
|
||||
.uk-link:hover,
|
||||
.uk-button-link:hover,
|
||||
a:hover {
|
||||
color: @global-primary-background;
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.uk-link:hover, .uk-button-link:hover, a:hover {
|
||||
|
||||
.uk-link:hover,
|
||||
.uk-button-link:hover,
|
||||
a:hover {
|
||||
color: @inverse-primary-muted-color;
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +270,7 @@
|
|||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.uk-button-primary{
|
||||
.uk-button-primary {
|
||||
background-color: rgba(180, 180, 180, 0.15);
|
||||
color: @inverse-primary-muted-color;
|
||||
border-color: @inverse-primary-muted-color;
|
||||
|
|
@ -268,7 +282,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.uk-icon-button, .uk-icon-button:hover {
|
||||
.uk-icon-button,
|
||||
.uk-icon-button:hover {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +311,7 @@
|
|||
background-color: #333;
|
||||
}
|
||||
|
||||
.uk-open > .uk-accordion-title::before {
|
||||
.uk-open>.uk-accordion-title::before {
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
|
||||
mask-position: 100% 50%;
|
||||
background-image: none;
|
||||
|
|
|
|||
|
|
@ -1,30 +1,70 @@
|
|||
<template>
|
||||
<div id="paneCapture">
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Filename</label>
|
||||
<input v-model="filename" class="uk-input uk-width-1-1 uk-form-small" name="inputFilename" placeholder="Leave blank for default">
|
||||
<input
|
||||
v-model="filename"
|
||||
class="uk-input uk-width-1-1 uk-form-small"
|
||||
name="inputFilename"
|
||||
placeholder="Leave blank for default"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p uk-tooltip="title: Capture will be removed automatically; delay: 500"><label><input v-model="temporary" class="uk-checkbox" type="checkbox"> Temporary</label></p>
|
||||
<p uk-tooltip="title: Capture will be removed automatically; delay: 500">
|
||||
<label
|
||||
><input v-model="temporary" class="uk-checkbox" type="checkbox" />
|
||||
Temporary</label
|
||||
>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<p><label><input v-model="fullResolution" class="uk-checkbox" type="checkbox"> Full resolution</label></p>
|
||||
<p><label><input v-model="storeBayer" class="uk-checkbox" type="checkbox"> Store raw data</label></p>
|
||||
<p>
|
||||
<label
|
||||
><input
|
||||
v-model="fullResolution"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
Full resolution</label
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<label
|
||||
><input v-model="storeBayer" class="uk-checkbox" type="checkbox" />
|
||||
Store raw data</label
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<p><label><input v-model="resizeCapture" class="uk-checkbox" type="checkbox"> Resize capture</label></p>
|
||||
<p>
|
||||
<label
|
||||
><input v-model="resizeCapture" class="uk-checkbox" type="checkbox" />
|
||||
Resize capture</label
|
||||
>
|
||||
</p>
|
||||
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<div>
|
||||
<input v-bind:class="resizeClass" v-model="resizeDims[0]" class="uk-input uk-form-width-medium uk-form-small" type="number" name="inputResizeW">
|
||||
<input
|
||||
v-model="resizeDims[0]"
|
||||
:class="resizeClass"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="number"
|
||||
name="inputResizeW"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input v-bind:class="resizeClass" v-model="resizeDims[1]" class="uk-input uk-form-width-medium uk-form-small" type="number" name="inputResizeH">
|
||||
<input
|
||||
v-model="resizeDims[1]"
|
||||
:class="resizeClass"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="number"
|
||||
name="inputResizeH"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -33,7 +73,12 @@
|
|||
<a class="uk-accordion-title" href="#">Notes</a>
|
||||
<div class="uk-accordion-content">
|
||||
<div class="uk-margin-small">
|
||||
<textarea v-model="captureNotes" class="uk-textarea" rows="5" placeholder="Capture notes"></textarea>
|
||||
<textarea
|
||||
v-model="captureNotes"
|
||||
class="uk-textarea"
|
||||
rows="5"
|
||||
placeholder="Capture notes"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
|
@ -41,84 +86,129 @@
|
|||
<li>
|
||||
<a class="uk-accordion-title" href="#">Metadata</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<keyvalList v-model="metadata"/>
|
||||
|
||||
<keyvalList v-model="metadata" />
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a class="uk-accordion-title" href="#">Tags</a>
|
||||
<div class="uk-accordion-content">
|
||||
<tagList v-model="tags"/>
|
||||
<tagList v-model="tags" />
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<ul uk-accordion="multiple: true; animation: false">
|
||||
|
||||
<!--Show stack and scan if default plugin is enabled-->
|
||||
<li v-if="this.$store.state.apiState.plugin.includes('default_scan')">
|
||||
<a class="uk-accordion-title" href="#">Stack and Scan</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<div class="uk-margin">
|
||||
<label><input v-model="scanCapture" class="uk-checkbox" type="checkbox"> Scan capture</label>
|
||||
<label
|
||||
><input
|
||||
v-model="scanCapture"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
Scan capture</label
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-bind:class="{ 'uk-disabled': !scanCapture }" >
|
||||
|
||||
<div :class="{ 'uk-disabled': !scanCapture }">
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x step-size</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>x step-size</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanStepSize.x" class="uk-input uk-form-small" type="number" name="inputPositionX">
|
||||
<input
|
||||
v-model="scanStepSize.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionX"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y step-size</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>y step-size</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanStepSize.y" class="uk-input uk-form-small" type="number" name="inputPositionY">
|
||||
<input
|
||||
v-model="scanStepSize.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionY"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z step-size</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>z step-size</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanStepSize.z" class="uk-input uk-form-small" type="number" name="inputPositionZx">
|
||||
<input
|
||||
v-model="scanStepSize.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionZx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x steps</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>x steps</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanSteps.x" class="uk-input uk-form-small" type="number" name="inputPositionX">
|
||||
<input
|
||||
v-model="scanSteps.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionX"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y steps</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>y steps</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanSteps.y" class="uk-input uk-form-small" type="number" name="inputPositionY">
|
||||
<input
|
||||
v-model="scanSteps.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionY"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z steps</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>z steps</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="scanSteps.z" class="uk-input uk-form-small" type="number" name="inputPositionZx">
|
||||
<input
|
||||
v-model="scanSteps.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionZx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-margin-small uk-margin-remove-bottom">
|
||||
<label class="uk-form-label" for="form-stacked-text">Autofocus</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Autofocus</label
|
||||
>
|
||||
<select v-model="scanDeltaZ" class="uk-select">
|
||||
<option>Off</option>
|
||||
<option>Coarse</option>
|
||||
|
|
@ -129,44 +219,51 @@
|
|||
</div>
|
||||
|
||||
<div class="uk-margin-small uk-margin-remove-bottom">
|
||||
<label class="uk-form-label" for="form-stacked-text">Scan Style</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Scan Style</label
|
||||
>
|
||||
<select v-model="scanStyle" class="uk-select">
|
||||
<option>Raster</option>
|
||||
<option>Snake</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<taskSubmitter v-if="scanCapture"
|
||||
v-bind:submitURL="scanApiUri"
|
||||
v-bind:submitData="scanPayload"
|
||||
v-bind:submitLabel="'Start Scan'"
|
||||
v-on:submit="onScanSubmit"
|
||||
v-on:response="onScanResponse"
|
||||
v-on:error="onScanError">
|
||||
<taskSubmitter
|
||||
v-if="scanCapture"
|
||||
:submit-u-r-l="scanApiUri"
|
||||
:submit-data="scanPayload"
|
||||
:submit-label="'Start Scan'"
|
||||
@submit="onScanSubmit"
|
||||
@response="onScanResponse"
|
||||
@error="onScanError"
|
||||
>
|
||||
</taskSubmitter>
|
||||
|
||||
<button v-else v-on:click="handleCapture()" class="uk-button uk-button-primary uk-form-small uk-margin uk-margin-remove-top uk-float-right uk-width-1-1">Capture</button>
|
||||
|
||||
<button
|
||||
v-else
|
||||
class="uk-button uk-button-primary uk-form-small uk-margin uk-margin-remove-top uk-float-right uk-width-1-1"
|
||||
@click="handleCapture()"
|
||||
>
|
||||
Capture
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
import tagList from "../fieldComponents/tagList"
|
||||
import keyvalList from "../fieldComponents/keyvalList"
|
||||
import tagList from "../fieldComponents/tagList";
|
||||
import keyvalList from "../fieldComponents/keyvalList";
|
||||
|
||||
import taskSubmitter from "../genericComponents/taskSubmitter"
|
||||
import taskSubmitter from "../genericComponents/taskSubmitter";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'paneCapture',
|
||||
name: "PaneCapture",
|
||||
|
||||
components: {
|
||||
tagList,
|
||||
|
|
@ -174,26 +271,25 @@ export default {
|
|||
taskSubmitter
|
||||
},
|
||||
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
filename: '',
|
||||
filename: "",
|
||||
temporary: false,
|
||||
fullResolution: false,
|
||||
storeBayer: false,
|
||||
resizeCapture: false,
|
||||
captureNotes: "",
|
||||
scanCapture: false,
|
||||
scanDeltaZ: 'Medium',
|
||||
scanStyle: 'Raster',
|
||||
scanDeltaZ: "Medium",
|
||||
scanStyle: "Raster",
|
||||
scanStepSize: {
|
||||
x: parseInt(0.8*this.$store.state.apiConfig.fov[0]),
|
||||
y: parseInt(0.8*this.$store.state.apiConfig.fov[1]),
|
||||
x: parseInt(0.8 * this.$store.state.apiConfig.fov[0]),
|
||||
y: parseInt(0.8 * this.$store.state.apiConfig.fov[1]),
|
||||
z: 50
|
||||
},
|
||||
scanSteps: {
|
||||
x: 3,
|
||||
y: 3,
|
||||
x: 3,
|
||||
y: 3,
|
||||
z: 5
|
||||
},
|
||||
resizeDims: [640, 480],
|
||||
|
|
@ -201,73 +297,27 @@ export default {
|
|||
metadata: {
|
||||
Client: `${process.env.PACKAGE.name}.${process.env.PACKAGE.version}`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
handleCapture: function() {
|
||||
var payload = this.basePayload
|
||||
|
||||
// Do capture
|
||||
this.newCaptureRequest(payload)
|
||||
},
|
||||
|
||||
handleScan: function() {
|
||||
var payload = this.scanPayload
|
||||
|
||||
// Do capture
|
||||
this.newScanRequest(payload)
|
||||
},
|
||||
|
||||
newCaptureRequest: function(params) {
|
||||
// Send move request
|
||||
axios.post(this.captureApiUri, params)
|
||||
.then(response => {
|
||||
// Flash the stream (capture animation)
|
||||
this.$root.$emit('globalFlashStream')
|
||||
// Update the global capture list
|
||||
this.$root.$emit('globalUpdateCaptureList')
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
},
|
||||
|
||||
onScanSubmit: function(submitData) {
|
||||
// We don't need to do anything on this event yet
|
||||
console.log("onScanSubmit event triggered")
|
||||
},
|
||||
|
||||
onScanResponse: function(responseData) {
|
||||
console.log("Scan finished with response data: ", responseData)
|
||||
this.modalNotify("Finished scan.")
|
||||
},
|
||||
|
||||
onScanError: function(error) {
|
||||
this.modalError(error)
|
||||
}
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
resizeClass: function () {
|
||||
resizeClass: function() {
|
||||
return {
|
||||
'uk-disabled': !this.resizeCapture
|
||||
}
|
||||
"uk-disabled": !this.resizeCapture
|
||||
};
|
||||
},
|
||||
captureApiUri: function () {
|
||||
return this.$store.getters.uri + "/camera/capture"
|
||||
captureApiUri: function() {
|
||||
return this.$store.getters.uri + "/camera/capture";
|
||||
},
|
||||
scanApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin/default/scan/tile"
|
||||
scanApiUri: function() {
|
||||
return this.$store.getters.uri + "/plugin/default/scan/tile";
|
||||
},
|
||||
basePayload: function () {
|
||||
var payload = {}
|
||||
|
||||
basePayload: function() {
|
||||
var payload = {};
|
||||
|
||||
// Filename
|
||||
if (Boolean(this.filename)) {
|
||||
payload.filename = this.filename
|
||||
if (this.filename) {
|
||||
payload.filename = this.filename;
|
||||
}
|
||||
|
||||
// Basic boolean params
|
||||
|
|
@ -280,28 +330,32 @@ export default {
|
|||
payload.size = {
|
||||
width: this.resizeDims[0],
|
||||
height: this.resizeDims[1]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Additional metadata
|
||||
payload.metadata = this.metadata
|
||||
payload.tags = this.tags
|
||||
payload.metadata = this.metadata;
|
||||
payload.tags = this.tags;
|
||||
|
||||
// Attach notes
|
||||
if (this.captureNotes) {
|
||||
payload.metadata['Notes'] = this.captureNotes
|
||||
payload.metadata["Notes"] = this.captureNotes;
|
||||
}
|
||||
|
||||
return payload
|
||||
return payload;
|
||||
},
|
||||
|
||||
scanPayload: function() {
|
||||
var payload = this.basePayload
|
||||
var payload = this.basePayload;
|
||||
|
||||
// Scan params
|
||||
payload.grid = [this.scanSteps.x, this.scanSteps.y, this.scanSteps.z]
|
||||
payload.step_size = [this.scanStepSize.x, this.scanStepSize.y, this.scanStepSize.z]
|
||||
payload.style = this.scanStyle.toLowerCase()
|
||||
payload.grid = [this.scanSteps.x, this.scanSteps.y, this.scanSteps.z];
|
||||
payload.step_size = [
|
||||
this.scanStepSize.x,
|
||||
this.scanStepSize.y,
|
||||
this.scanStepSize.z
|
||||
];
|
||||
payload.style = this.scanStyle.toLowerCase();
|
||||
|
||||
// Convert AF selector to dz
|
||||
var afDeltas = {
|
||||
|
|
@ -310,17 +364,57 @@ export default {
|
|||
Medium: 30,
|
||||
Fine: 10,
|
||||
Fast: 1500
|
||||
}
|
||||
};
|
||||
|
||||
payload.autofocus_dz = afDeltas[this.scanDeltaZ]
|
||||
payload.fast_autofocus = this.scanDeltaZ == "Fast"
|
||||
payload.autofocus_dz = afDeltas[this.scanDeltaZ];
|
||||
payload.fast_autofocus = this.scanDeltaZ == "Fast";
|
||||
|
||||
return payload
|
||||
return payload;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleCapture: function() {
|
||||
var payload = this.basePayload;
|
||||
|
||||
// Do capture
|
||||
this.newCaptureRequest(payload);
|
||||
},
|
||||
|
||||
}
|
||||
handleScan: function() {
|
||||
var payload = this.scanPayload;
|
||||
|
||||
}
|
||||
// Do capture
|
||||
this.newScanRequest(payload);
|
||||
},
|
||||
|
||||
newCaptureRequest: function(params) {
|
||||
// Send move request
|
||||
axios
|
||||
.post(this.captureApiUri, params)
|
||||
.then(() => {
|
||||
// Flash the stream (capture animation)
|
||||
this.$root.$emit("globalFlashStream");
|
||||
// Update the global capture list
|
||||
this.$root.$emit("globalUpdateCaptureList");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
onScanSubmit: function() {},
|
||||
|
||||
onScanResponse: function(responseData) {
|
||||
console.log("Scan finished with response data: ", responseData);
|
||||
this.modalNotify("Finished scan.");
|
||||
},
|
||||
|
||||
onScanError: function(error) {
|
||||
this.modalError(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
|
@ -331,5 +425,4 @@ export default {
|
|||
.deletable-label:hover {
|
||||
background-color: #f0506e;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,98 +1,144 @@
|
|||
<template>
|
||||
<div id="paneNavigate">
|
||||
|
||||
<ul uk-accordion="multiple: true; animation: false">
|
||||
<li>
|
||||
<a class="uk-accordion-title" href="#">Configure</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x-y step size</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="stepXy" class="uk-input uk-form-width-medium uk-form-small" type="number" name="inputStepXy">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z step size</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="stepZz" class="uk-input uk-form-width-medium uk-form-small" type="number" name="inputStepZz">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="uk-open">
|
||||
<a class="uk-accordion-title" href="#">Move-to</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div id="paneNavigate">
|
||||
<ul uk-accordion="multiple: true; animation: false">
|
||||
<li>
|
||||
<a class="uk-accordion-title" href="#">Configure</a>
|
||||
<div class="uk-accordion-content">
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>x-y step size</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="setPosition.x" class="uk-input uk-form-small" type="number" name="inputPositionX">
|
||||
<input
|
||||
v-model="stepXy"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="number"
|
||||
name="inputStepXy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>z step size</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="setPosition.y" class="uk-input uk-form-small" type="number" name="inputPositionY">
|
||||
<input
|
||||
v-model="stepZz"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="number"
|
||||
name="inputStepZz"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="uk-open">
|
||||
<a class="uk-accordion-title" href="#">Move-to</a>
|
||||
<div class="uk-accordion-content">
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="setPosition.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionX"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="setPosition.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionY"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="setPosition.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
name="inputPositionZx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<button
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-width-1-1"
|
||||
>
|
||||
Move
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!--Show autofocus if default plugin is enabled-->
|
||||
<li
|
||||
v-if="this.$store.state.apiState.plugin.includes('default_autofocus')"
|
||||
class="uk-open"
|
||||
>
|
||||
<a class="uk-accordion-title" href="#">Autofocus</a>
|
||||
<div class="uk-accordion-content">
|
||||
<div v-if="isAutofocusing">
|
||||
<progressBar />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="uk-grid-small uk-child-width-1-3"
|
||||
:hidden="isAutofocusing"
|
||||
uk-grid
|
||||
>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="setPosition.z" class="uk-input uk-form-small" type="number" name="inputPositionZx">
|
||||
</div>
|
||||
<button
|
||||
class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1"
|
||||
@click="runFastAutofocus(2000, 300)"
|
||||
>
|
||||
Fast
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1"
|
||||
@click="runAutofocus([-60, -30, 0, 30, 60])"
|
||||
>
|
||||
Medium
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1"
|
||||
@click="runAutofocus([-20, -10, 0, 10, 20])"
|
||||
>
|
||||
Fine
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<button class="uk-button uk-button-primary uk-form-small uk-float-right uk-width-1-1">Move</button>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!--Show autofocus if default plugin is enabled-->
|
||||
<li v-if="this.$store.state.apiState.plugin.includes('default_autofocus')" class="uk-open">
|
||||
<a class="uk-accordion-title" href="#">Autofocus</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<div v-if="isAutofocusing">
|
||||
<progressBar/>
|
||||
</div>
|
||||
|
||||
<div class="uk-grid-small uk-child-width-1-3" v-bind:hidden="isAutofocusing" uk-grid>
|
||||
<div>
|
||||
<button v-on:click="runFastAutofocus(2000, 300);" class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1">Fast</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-on:click="runAutofocus([-60,-30,0,30,60]);" class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1">Medium</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-on:click="runAutofocus([-20,-10,0,10,20]);" class="uk-button uk-button-default uk-form-small uk-float-right uk-width-1-1">Fine</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import progressBar from "../genericComponents/progressBar"
|
||||
import axios from "axios";
|
||||
import progressBar from "../genericComponents/progressBar";
|
||||
|
||||
// Key Codes
|
||||
const keyCodes = {
|
||||
|
|
@ -104,17 +150,17 @@ const keyCodes = {
|
|||
down: 40,
|
||||
enter: 13,
|
||||
esc: 27
|
||||
}
|
||||
};
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'paneNavigate',
|
||||
name: "PaneNavigate",
|
||||
|
||||
components: {
|
||||
progressBar
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
keysDown: {},
|
||||
stepXy: 200,
|
||||
|
|
@ -122,40 +168,57 @@ export default {
|
|||
setPosition: this.$store.state.apiState.stage.position,
|
||||
isAutofocusing: false,
|
||||
moveLock: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
positionApiUri: function() {
|
||||
return this.$store.getters.uri + "/stage/position";
|
||||
},
|
||||
autofocusApiUri: function() {
|
||||
return this.$store.getters.uri + "/plugin/default/autofocus/autofocus";
|
||||
},
|
||||
fastAutofocusApiUri: function() {
|
||||
return (
|
||||
this.$store.getters.uri + "/plugin/default/autofocus/fast_autofocus"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
created: function () {
|
||||
window.addEventListener('keydown', this.keyDownMonitor);
|
||||
created: function() {
|
||||
window.addEventListener("keydown", this.keyDownMonitor);
|
||||
window.addEventListener("keyup", this.keyUpMonitor);
|
||||
window.addEventListener('wheel', this.wheelMonitor);
|
||||
window.addEventListener("wheel", this.wheelMonitor);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to perform a move action
|
||||
this.$root.$on('globalMoveEvent', (x, y, z, absolute) => {
|
||||
this.moveRequest(x, y, z, absolute)
|
||||
})
|
||||
this.$root.$on("globalMoveEvent", (x, y, z, absolute) => {
|
||||
this.moveRequest(x, y, z, absolute);
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
beforeDestroy() {
|
||||
// Remove global signal listener to perform a move action
|
||||
this.$root.$off('globalMoveEvent')
|
||||
this.$root.$off("globalMoveEvent");
|
||||
},
|
||||
|
||||
destroyed: function () {
|
||||
window.removeEventListener('keydown', this.keyDownMonitor);
|
||||
destroyed: function() {
|
||||
window.removeEventListener("keydown", this.keyDownMonitor);
|
||||
window.removeEventListener("keyup", this.keyUpMonitor);
|
||||
window.removeEventListener('wheel', this.wheelMonitor);
|
||||
window.removeEventListener("wheel", this.wheelMonitor);
|
||||
},
|
||||
|
||||
methods: {
|
||||
// Handle global mouse wheel events to be associated with navigation
|
||||
wheelMonitor: function(event) {
|
||||
// Only capture scroll if the event target's parent contains the "scrollTarget" class
|
||||
if (event.target.parentNode.classList.contains("scrollTarget") || event.target.classList.contains("scrollTarget")) {
|
||||
var z_rel = (event.deltaY)/100 * this.stepZz
|
||||
this.moveRequest(0, 0, z_rel, false)
|
||||
if (
|
||||
event.target.parentNode.classList.contains("scrollTarget") ||
|
||||
event.target.classList.contains("scrollTarget")
|
||||
) {
|
||||
var z_rel = (event.deltaY / 100) * this.stepZz;
|
||||
this.moveRequest(0, 0, z_rel, false);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -164,9 +227,15 @@ export default {
|
|||
this.keysDown[event.keyCode] = true; //Add key to array
|
||||
|
||||
// Convert keyCode dict into a list of key codes
|
||||
var keyCodeList = Object.keys(keyCodes).map(function(key){return keyCodes[key];});
|
||||
var keyCodeList = Object.keys(keyCodes).map(function(key) {
|
||||
return keyCodes[key];
|
||||
});
|
||||
|
||||
if (!(event.target instanceof HTMLInputElement) && !(event.target.classList.contains('lightbox-link')) && keyCodeList.includes(event.keyCode)) {
|
||||
if (
|
||||
!(event.target instanceof HTMLInputElement) &&
|
||||
!event.target.classList.contains("lightbox-link") &&
|
||||
keyCodeList.includes(event.keyCode)
|
||||
) {
|
||||
//console.log(this.keysDown)
|
||||
// Calculate movement array
|
||||
var x_rel = 0;
|
||||
|
|
@ -192,7 +261,7 @@ export default {
|
|||
}
|
||||
|
||||
// Make a position request
|
||||
this.moveRequest(x_rel, y_rel, z_rel, false)
|
||||
this.moveRequest(x_rel, y_rel, z_rel, false);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -200,105 +269,102 @@ export default {
|
|||
delete this.keysDown[event.keyCode]; //Remove key from array
|
||||
},
|
||||
|
||||
handleSubmit: function(event) {
|
||||
handleSubmit: function() {
|
||||
this.moveRequest(
|
||||
this.setPosition.x,
|
||||
this.setPosition.y,
|
||||
this.setPosition.z,
|
||||
true,
|
||||
)
|
||||
true
|
||||
);
|
||||
},
|
||||
|
||||
moveRequest: function(x, y, z, absolute) {
|
||||
console.log(`Sending move request of ${x}, ${y}, ${z}`)
|
||||
console.log(`Sending move request of ${x}, ${y}, ${z}`);
|
||||
// If not movement-locked
|
||||
if (!this.moveLock) {
|
||||
// Lock move requests
|
||||
this.moveLock = true
|
||||
this.moveLock = true;
|
||||
|
||||
// Send move request
|
||||
axios.post(this.positionApiUri, {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
absolute: absolute
|
||||
})
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateState'); // Update store state
|
||||
this.setPosition = response.data.stage.position; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
.then(() => {
|
||||
this.moveLock = false // Release the move lock
|
||||
})
|
||||
axios
|
||||
.post(this.positionApiUri, {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
absolute: absolute
|
||||
})
|
||||
.then(response => {
|
||||
this.$store.dispatch("updateState"); // Update store state
|
||||
this.setPosition = response.data.stage.position; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
})
|
||||
.then(() => {
|
||||
this.moveLock = false; // Release the move lock
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
runAutofocus: function(dz) {
|
||||
if (!this.moveLock) {
|
||||
// Lock move requests
|
||||
this.moveLock = true
|
||||
this.isAutofocusing = true
|
||||
axios.post(this.autofocusApiUri, {dz: dz})
|
||||
.then(response => {
|
||||
console.log("Autofocus Task ID: " + response.data.id)
|
||||
// Start the store polling TaskId for success
|
||||
return this.$store.dispatch('pollTask', [response.data.id, null, null])
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Successfully finished autofocus")
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after autofocus.")
|
||||
this.isAutofocusing = false;
|
||||
this.moveLock = false // Release the move lock
|
||||
})
|
||||
this.moveLock = true;
|
||||
this.isAutofocusing = true;
|
||||
axios
|
||||
.post(this.autofocusApiUri, { dz: dz })
|
||||
.then(response => {
|
||||
console.log("Autofocus Task ID: " + response.data.id);
|
||||
// Start the store polling TaskId for success
|
||||
return this.$store.dispatch("pollTask", [
|
||||
response.data.id,
|
||||
null,
|
||||
null
|
||||
]);
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Successfully finished autofocus");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after autofocus.");
|
||||
this.isAutofocusing = false;
|
||||
this.moveLock = false; // Release the move lock
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
runFastAutofocus: function(dz, backlash) {
|
||||
if (!this.moveLock) {
|
||||
// Lock move requests
|
||||
this.moveLock = true
|
||||
this.isAutofocusing = true
|
||||
axios.post(this.fastAutofocusApiUri, {dz: dz, backlash: backlash})
|
||||
.then(response => {
|
||||
console.log("Autofocus Task ID: " + response.data.id)
|
||||
// Start the store polling TaskId for success
|
||||
return this.$store.dispatch('pollTask', [response.data.id, null, null])
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Successfully finished autofocus")
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after autofocus.")
|
||||
this.isAutofocusing = false
|
||||
this.moveLock = false // Release the move lock
|
||||
})
|
||||
this.moveLock = true;
|
||||
this.isAutofocusing = true;
|
||||
axios
|
||||
.post(this.fastAutofocusApiUri, { dz: dz, backlash: backlash })
|
||||
.then(response => {
|
||||
console.log("Autofocus Task ID: " + response.data.id);
|
||||
// Start the store polling TaskId for success
|
||||
return this.$store.dispatch("pollTask", [
|
||||
response.data.id,
|
||||
null,
|
||||
null
|
||||
]);
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Successfully finished autofocus");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after autofocus.");
|
||||
this.isAutofocusing = false;
|
||||
this.moveLock = false; // Release the move lock
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
positionApiUri: function () {
|
||||
return this.$store.getters.uri + "/stage/position"
|
||||
},
|
||||
autofocusApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin/default/autofocus/autofocus"
|
||||
},
|
||||
fastAutofocusApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin/default/autofocus/fast_autofocus"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<div id="panePlugins">
|
||||
<h3>Plugins</h3>
|
||||
<div class="uk-placeholder uk-text-center">Plugin support coming soon...</div>
|
||||
<div class="uk-placeholder uk-text-center">
|
||||
Plugin support coming soon...
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'panePlugins',
|
||||
}
|
||||
name: "PanePlugins"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
<style lang="less"></style>
|
||||
|
|
|
|||
|
|
@ -1,38 +1,35 @@
|
|||
<template>
|
||||
<div id="paneSettings">
|
||||
|
||||
<appSettings/>
|
||||
<appSettings />
|
||||
|
||||
<ul uk-accordion="multiple: true; animation: false">
|
||||
<li>
|
||||
<a class="uk-accordion-title" href="#">Stream settings</a>
|
||||
<div class="uk-accordion-content"><streamSettings/></div>
|
||||
<div class="uk-accordion-content"><streamSettings /></div>
|
||||
</li>
|
||||
|
||||
<li v-if="$store.getters.ready">
|
||||
<a class="uk-accordion-title" href="#">Camera settings</a>
|
||||
<div class="uk-accordion-content"><cameraSettings/></div>
|
||||
<div class="uk-accordion-content"><cameraSettings /></div>
|
||||
</li>
|
||||
|
||||
|
||||
<li v-if="$store.getters.ready">
|
||||
<a class="uk-accordion-title" href="#">Microscope settings</a>
|
||||
<div class="uk-accordion-content"><microscopeSettings/></div>
|
||||
<div class="uk-accordion-content"><microscopeSettings /></div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import streamSettings from './settingsComponents/streamSettings.vue'
|
||||
import microscopeSettings from './settingsComponents/microscopeSettings.vue'
|
||||
import cameraSettings from './settingsComponents/cameraSettings.vue'
|
||||
import appSettings from './settingsComponents/appSettings.vue'
|
||||
import streamSettings from "./settingsComponents/streamSettings.vue";
|
||||
import microscopeSettings from "./settingsComponents/microscopeSettings.vue";
|
||||
import cameraSettings from "./settingsComponents/cameraSettings.vue";
|
||||
import appSettings from "./settingsComponents/appSettings.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'paneSettings',
|
||||
name: "PaneSettings",
|
||||
|
||||
components: {
|
||||
streamSettings,
|
||||
|
|
@ -40,9 +37,7 @@ export default {
|
|||
microscopeSettings,
|
||||
appSettings
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
<style lang="less"></style>
|
||||
|
|
|
|||
|
|
@ -1,70 +1,71 @@
|
|||
<template>
|
||||
<div class="host-input">
|
||||
|
||||
<div v-if="$store.getters.ready">
|
||||
<div v-if="$store.state.apiConfig.name"><b>Device name:</b> <br> {{ $store.state.apiConfig.name }}</div>
|
||||
<hr>
|
||||
<div class="uk-margin-small-bottom">
|
||||
<b>Host:</b>
|
||||
<br>
|
||||
{{ $store.state.host }}
|
||||
<div class="host-input">
|
||||
<div v-if="$store.getters.ready">
|
||||
<div v-if="$store.state.apiConfig.name">
|
||||
<b>Device name:</b> <br />
|
||||
{{ $store.state.apiConfig.name }}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="uk-margin-small-bottom">
|
||||
<b>Host:</b>
|
||||
<br />
|
||||
{{ $store.state.host }}
|
||||
</div>
|
||||
<div>
|
||||
<b>Server version:</b> <br />
|
||||
{{ $store.state.apiState.version }}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="uk-margin-small-bottom">
|
||||
<b>Camera:</b>
|
||||
<br />
|
||||
<div v-if="$store.state.apiState.camera.board">
|
||||
{{ $store.state.apiState.camera.board }}
|
||||
</div>
|
||||
<div v-else class="uk-text-danger"><b>No camera connected</b></div>
|
||||
</div>
|
||||
<div>
|
||||
<b>Stage:</b>
|
||||
<br />
|
||||
<div v-if="$store.state.apiState.stage.board">
|
||||
{{ $store.state.apiState.stage.board }}
|
||||
</div>
|
||||
<div v-else class="uk-text-danger"><b>No stage connected</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div><b>Server version:</b> <br> {{ $store.state.apiState.version }}</div>
|
||||
<hr>
|
||||
<div class="uk-margin-small-bottom">
|
||||
<b>Camera:</b>
|
||||
<br>
|
||||
<div v-if="$store.state.apiState.camera.board">{{ $store.state.apiState.camera.board }}</div>
|
||||
<div v-else class="uk-text-danger"><b>No camera connected</b></div>
|
||||
<div v-else-if="$store.state.waiting">
|
||||
<progressBar></progressBar>
|
||||
</div>
|
||||
<div>
|
||||
<b>Stage:</b>
|
||||
<br>
|
||||
<div v-if="$store.state.apiState.stage.board">{{ $store.state.apiState.stage.board }}</div>
|
||||
<div v-else class="uk-text-danger"><b>No stage connected</b></div>
|
||||
<div v-else-if="$store.state.error">
|
||||
<b>Error:</b> {{ $store.state.error }}
|
||||
</div>
|
||||
|
||||
<div v-else>No active connection</div>
|
||||
</div>
|
||||
<div v-else-if="$store.state.waiting">
|
||||
<progressBar></progressBar>
|
||||
</div>
|
||||
<div v-else-if="$store.state.error"><b>Error:</b> {{ $store.state.error }}</div>
|
||||
<div v-else>No active connection</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import progressBar from "../genericComponents/progressBar"
|
||||
|
||||
import progressBar from "../genericComponents/progressBar";
|
||||
|
||||
export default {
|
||||
name: 'paneStatus',
|
||||
name: "PaneStatus",
|
||||
|
||||
components: {
|
||||
progressBar
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
}
|
||||
data: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
},
|
||||
computed: {},
|
||||
|
||||
watch: {
|
||||
},
|
||||
watch: {},
|
||||
|
||||
methods: {
|
||||
},
|
||||
mounted() {},
|
||||
|
||||
computed: {
|
||||
}
|
||||
|
||||
}
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="less">
|
||||
</style>
|
||||
<style scoped lang="less"></style>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,21 @@
|
|||
<template>
|
||||
<div id="appSettings">
|
||||
|
||||
<p><label><input v-model="darkMode" class="uk-checkbox" type="checkbox"> Enable dark theme</label></p>
|
||||
|
||||
</div>
|
||||
<div id="appSettings">
|
||||
<p>
|
||||
<label
|
||||
><input v-model="darkMode" class="uk-checkbox" type="checkbox" /> Enable
|
||||
dark theme</label
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'appSettings',
|
||||
name: "AppSettings",
|
||||
|
||||
data: function () {
|
||||
return {}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Try loading settings from localStorage. If null, don't change.
|
||||
this.darkMode = this.getLocalStorageObj('darkMode') || this.darkMode
|
||||
},
|
||||
|
||||
watch: {
|
||||
darkMode(newdarkMode) {
|
||||
console.log("Saving darkmode setting")
|
||||
this.setLocalStorageObj('darkMode', this.darkMode)
|
||||
}
|
||||
data: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
@ -34,13 +24,23 @@ export default {
|
|||
return this.$store.state.globalSettings.darkMode;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeSetting", ['darkMode', value]);
|
||||
this.$store.commit("changeSetting", ["darkMode", value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
watch: {
|
||||
darkMode() {
|
||||
console.log("Saving darkmode setting");
|
||||
this.setLocalStorageObj("darkMode", this.darkMode);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Try loading settings from localStorage. If null, don't change.
|
||||
this.darkMode = this.getLocalStorageObj("darkMode") || this.darkMode;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
<style lang="less"></style>
|
||||
|
|
|
|||
|
|
@ -1,138 +1,181 @@
|
|||
<template>
|
||||
<div id="cameraSettings">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<div id="cameraSettings">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Exposure time</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Exposure time</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-bind:value="displayShutterSpeed" v-on:input="shutterSpeed = $event.target.value" class="uk-input uk-form-small" type="number">
|
||||
<input
|
||||
:value="displayShutterSpeed"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
@input="shutterSpeed = $event.target.value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Analogue gain</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Analogue gain</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-bind:value="displayAnalogGain" v-on:input="analogGain = $event.target.value" class="uk-input uk-form-small" type="number" step="0.1">
|
||||
<input
|
||||
:value="displayAnalogGain"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="0.1"
|
||||
@input="analogGain = $event.target.value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Digital gain</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Digital gain</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-bind:value="displayDigitalGain" v-on:input="digitalGain = $event.target.value" class="uk-input uk-form-small" type="number" step="0.1">
|
||||
<input
|
||||
:value="displayDigitalGain"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="0.1"
|
||||
@input="digitalGain = $event.target.value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">Apply Settings</button>
|
||||
|
||||
<!--Show auto calibrate if default plugin is enabled-->
|
||||
<div v-if="this.$store.state.apiState.plugin.includes('default_camera_calibration')">
|
||||
<taskSubmitter
|
||||
v-bind:canTerminate="false"
|
||||
v-bind:requiresConfirmation="true"
|
||||
v-bind:confirmationMessage="'Start recalibration? This may take a while, and the microscope will be locked during this time.'"
|
||||
v-bind:submitURL="recalibrateApiUri"
|
||||
v-bind:submitLabel="'Auto-Calibrate (Task)'"
|
||||
v-on:response="onRecalibrateResponse"
|
||||
v-on:error="onRecalibrateError">
|
||||
</taskSubmitter>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1"
|
||||
>
|
||||
Apply Settings
|
||||
</button>
|
||||
|
||||
<!--Show auto calibrate if default plugin is enabled-->
|
||||
<div
|
||||
v-if="
|
||||
this.$store.state.apiState.plugin.includes(
|
||||
'default_camera_calibration'
|
||||
)
|
||||
"
|
||||
>
|
||||
<taskSubmitter
|
||||
:can-terminate="false"
|
||||
:requires-confirmation="true"
|
||||
:confirmation-message="
|
||||
'Start recalibration? This may take a while, and the microscope will be locked during this time.'
|
||||
"
|
||||
:submit-u-r-l="recalibrateApiUri"
|
||||
:submit-label="'Auto-Calibrate (Task)'"
|
||||
@response="onRecalibrateResponse"
|
||||
@error="onRecalibrateError"
|
||||
>
|
||||
</taskSubmitter>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import taskSubmitter from "../../genericComponents/taskSubmitter"
|
||||
import axios from "axios";
|
||||
import taskSubmitter from "../../genericComponents/taskSubmitter";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'microscopeSettings',
|
||||
name: "MicroscopeSettings",
|
||||
|
||||
components: {
|
||||
taskSubmitter
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
shutterSpeed: this.$store.state.apiConfig.camera_settings.picamera_settings.shutter_speed,
|
||||
analogGain: this.$store.state.apiConfig.camera_settings.picamera_settings.analog_gain,
|
||||
digitalGain: this.$store.state.apiConfig.camera_settings.picamera_settings.digital_gain,
|
||||
shutterSpeed: this.$store.state.apiConfig.camera_settings
|
||||
.picamera_settings.shutter_speed,
|
||||
analogGain: this.$store.state.apiConfig.camera_settings.picamera_settings
|
||||
.analog_gain,
|
||||
digitalGain: this.$store.state.apiConfig.camera_settings.picamera_settings
|
||||
.digital_gain,
|
||||
isCalibrating: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayDigitalGain: function() {
|
||||
return Number(this.digitalGain).toFixed(2);
|
||||
},
|
||||
displayAnalogGain: function() {
|
||||
return Number(this.analogGain).toFixed(2);
|
||||
},
|
||||
displayShutterSpeed: function() {
|
||||
return this.shutterSpeed != "0" ? this.shutterSpeed : "auto";
|
||||
},
|
||||
recalibrateApiUri: function() {
|
||||
return (
|
||||
this.$store.getters.uri +
|
||||
"/plugin/default/camera_calibration/recalibrate"
|
||||
);
|
||||
},
|
||||
configApiUri: function() {
|
||||
return this.$store.getters.uri + "/config";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateInputValues: function () {
|
||||
this.shutterSpeed = this.$store.state.apiConfig.camera_settings.picamera_settings.shutter_speed
|
||||
this.digitalGain = this.$store.state.apiConfig.camera_settings.picamera_settings.digital_gain
|
||||
this.analogGain = this.$store.state.apiConfig.camera_settings.picamera_settings.analog_gain
|
||||
updateInputValues: function() {
|
||||
this.shutterSpeed = this.$store.state.apiConfig.camera_settings.picamera_settings.shutter_speed;
|
||||
this.digitalGain = this.$store.state.apiConfig.camera_settings.picamera_settings.digital_gain;
|
||||
this.analogGain = this.$store.state.apiConfig.camera_settings.picamera_settings.analog_gain;
|
||||
},
|
||||
|
||||
applyConfigRequest: function() {
|
||||
console.log("Applying config to the microscope")
|
||||
console.log("Applying config to the microscope");
|
||||
var payload = {
|
||||
camera_settings: {
|
||||
picamera_settings: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//if (this.shutterSpeed != this.$store.state.apiConfig.picamera_settings.shutter_speed) {
|
||||
payload.camera_settings.picamera_settings.shutter_speed = this.shutterSpeed
|
||||
payload.camera_settings.picamera_settings.analog_gain = this.analogGain
|
||||
payload.camera_settings.picamera_settings.digital_gain = this.digitalGain
|
||||
payload.camera_settings.picamera_settings.shutter_speed = this.shutterSpeed;
|
||||
payload.camera_settings.picamera_settings.analog_gain = this.analogGain;
|
||||
payload.camera_settings.picamera_settings.digital_gain = this.digitalGain;
|
||||
//};
|
||||
|
||||
// Send request
|
||||
axios.post(this.configApiUri, payload)
|
||||
.then(response => { return new Promise(r => setTimeout(r, 500))}) // why is there no built-in for this??!
|
||||
.then(response => {
|
||||
return this.$store.dispatch('updateConfig');
|
||||
axios
|
||||
.post(this.configApiUri, payload)
|
||||
.then(() => {
|
||||
return new Promise(r => setTimeout(r, 500));
|
||||
}) // why is there no built-in for this??!
|
||||
.then(() => {
|
||||
return this.$store.dispatch("updateConfig");
|
||||
})
|
||||
.then(this.updateInputValues)
|
||||
.then(r=>{console.log("Updated Config: ", payload)})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
.then(() => {
|
||||
console.log("Updated Config: ", payload);
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
onRecalibrateResponse: function() {
|
||||
this.modalNotify("Finished recalibration.")
|
||||
return new Promise(r => setTimeout(r, 500)) // wait 500ms before updating config, so it's fresh
|
||||
this.modalNotify("Finished recalibration.");
|
||||
return new Promise(r => setTimeout(r, 500)); // wait 500ms before updating config, so it's fresh
|
||||
},
|
||||
|
||||
onRecalibrateError: function(error) {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayDigitalGain: function () {
|
||||
return Number(this.digitalGain).toFixed(2)
|
||||
},
|
||||
displayAnalogGain: function () {
|
||||
return Number(this.analogGain).toFixed(2)
|
||||
},
|
||||
displayShutterSpeed: function () {
|
||||
return (this.shutterSpeed != "0") ? this.shutterSpeed : "auto"
|
||||
},
|
||||
recalibrateApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin/default/camera_calibration/recalibrate"
|
||||
},
|
||||
configApiUri: function () {
|
||||
return this.$store.getters.uri + "/config"
|
||||
this.modalError(error); // Let mixin handle error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.center-spinner {
|
||||
margin-left: auto;
|
||||
margin-right: auto
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,108 +1,133 @@
|
|||
<template>
|
||||
<div id="microscopeSettings">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<h4>Stage</h4>
|
||||
<div id="microscopeSettings">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<h4>Stage</h4>
|
||||
|
||||
<label class="uk-form-label" for="form-stacked-text">Backlash compensation</label>
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="stageBacklash.x" class="uk-input uk-form-small" type="number">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Backlash compensation</label
|
||||
>
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="stageBacklash.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="stageBacklash.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="stageBacklash.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="stageBacklash.y" class="uk-input uk-form-small" type="number">
|
||||
</div>
|
||||
</div>
|
||||
<h4>Microscope</h4>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="stageBacklash.z" class="uk-input uk-form-small" type="number">
|
||||
</div>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Microscope name</label
|
||||
>
|
||||
<input
|
||||
v-model="microscopeName"
|
||||
class="uk-input uk-width-1-1 uk-form-small"
|
||||
name="inputFilename"
|
||||
placeholder="Leave blank for default"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>Microscope</h4>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Microscope name</label>
|
||||
<input v-model="microscopeName" class="uk-input uk-width-1-1 uk-form-small" name="inputFilename" placeholder="Leave blank for default">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">Apply Settings</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1"
|
||||
>
|
||||
Apply Settings
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'microscopeSettings',
|
||||
name: "MicroscopeSettings",
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
microscopeName: this.$store.state.apiConfig.name,
|
||||
stageBacklash: this.$store.state.apiConfig.stage_settings.backlash
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
configApiUri: function() {
|
||||
return this.$store.getters.uri + "/config";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateInputValues: function () {
|
||||
updateInputValues: function() {
|
||||
this.microscopeName = this.$store.state.apiConfig.name;
|
||||
this.stageBacklash = this.$store.state.apiConfig.stage_settings.backlash
|
||||
this.stageBacklash = this.$store.state.apiConfig.stage_settings.backlash;
|
||||
},
|
||||
|
||||
applyConfigRequest: function() {
|
||||
var payload = {
|
||||
stage_settings: {}
|
||||
}
|
||||
|
||||
if (this.microscopeName != this.$store.state.apiConfig.name) {
|
||||
payload.name = this.microscopeName
|
||||
};
|
||||
|
||||
if (this.stageBacklash != this.$store.state.apiConfig.stage_settings.backlash) {
|
||||
payload.stage_settings.backlash = this.stageBacklash
|
||||
if (this.microscopeName != this.$store.state.apiConfig.name) {
|
||||
payload.name = this.microscopeName;
|
||||
}
|
||||
|
||||
console.log(payload)
|
||||
if (
|
||||
this.stageBacklash !=
|
||||
this.$store.state.apiConfig.stage_settings.backlash
|
||||
) {
|
||||
payload.stage_settings.backlash = this.stageBacklash;
|
||||
}
|
||||
|
||||
console.log(payload);
|
||||
|
||||
// Send request to update config
|
||||
axios.post(this.configApiUri, payload)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateConfig');
|
||||
this.updateInputValues
|
||||
this.modalNotify("Microscope config applied.")
|
||||
axios
|
||||
.post(this.configApiUri, payload)
|
||||
.then(() => {
|
||||
this.$store.dispatch("updateConfig");
|
||||
this.updateInputValues;
|
||||
this.modalNotify("Microscope config applied.");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
configApiUri: function () {
|
||||
return this.$store.getters.uri + "/config"
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.center-spinner {
|
||||
margin-left: auto;
|
||||
margin-right: auto
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,49 @@
|
|||
<template>
|
||||
<div id="streamSettings">
|
||||
<div id="streamSettings">
|
||||
<p>
|
||||
<label
|
||||
><input v-model="disableStream" class="uk-checkbox" type="checkbox" />
|
||||
Disable live stream</label
|
||||
>
|
||||
</p>
|
||||
|
||||
<p><label><input v-model="disableStream" class="uk-checkbox" type="checkbox"> Disable live stream</label></p>
|
||||
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<p><label v-bind:class="[{'uk-disabled': !this.$store.getters.ready}]"><input v-model="autoGpuPreview" class="uk-checkbox" type="checkbox"> GPU preview</label></p>
|
||||
<p><label v-bind:class="[{'uk-disabled': !this.$store.getters.ready}]"><input v-model="trackWindow" class="uk-checkbox" type="checkbox"> Track window</label></p>
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<p>
|
||||
<label :class="[{ 'uk-disabled': !this.$store.getters.ready }]"
|
||||
><input
|
||||
v-model="autoGpuPreview"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
GPU preview</label
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<label :class="[{ 'uk-disabled': !this.$store.getters.ready }]"
|
||||
><input v-model="trackWindow" class="uk-checkbox" type="checkbox" />
|
||||
Track window</label
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'streamSettings',
|
||||
name: "StreamSettings",
|
||||
|
||||
data: function () {
|
||||
return {}
|
||||
data: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
disableStream: {
|
||||
get() {
|
||||
return this.$store.state.globalSettings.disableStream;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeSetting", ['disableStream', value]);
|
||||
this.$store.commit("changeSetting", ["disableStream", value]);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -37,8 +52,8 @@ export default {
|
|||
return this.$store.state.globalSettings.autoGpuPreview;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeSetting", ['autoGpuPreview', value]);
|
||||
this.$root.$emit('globalTogglePreview', value)
|
||||
this.$store.commit("changeSetting", ["autoGpuPreview", value]);
|
||||
this.$root.$emit("globalTogglePreview", value);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -47,13 +62,11 @@ export default {
|
|||
return this.$store.state.globalSettings.trackWindow;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeSetting", ['trackWindow', value]);
|
||||
this.$store.commit("changeSetting", ["trackWindow", value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
<style lang="less"></style>
|
||||
|
|
|
|||
|
|
@ -1,52 +1,66 @@
|
|||
<template>
|
||||
<div>
|
||||
<label>{{label}}</label>
|
||||
<label>{{ label }}</label>
|
||||
|
||||
<div class="uk-form-controls">
|
||||
|
||||
<div v-for="option in options" :key="option">
|
||||
<label>
|
||||
<input class="uk-checkbox" type="checkbox" v-bind:value="option" v-bind:checked="(value && value.includes(option))" @change="updateValue($event.target)">
|
||||
<input
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
:value="option"
|
||||
:checked="value && value.includes(option)"
|
||||
@change="updateValue($event.target)"
|
||||
/>
|
||||
{{ option }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'checkList',
|
||||
name: "CheckList",
|
||||
|
||||
props: [
|
||||
'options',
|
||||
'name',
|
||||
'label',
|
||||
'value'
|
||||
],
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateValue(target) {
|
||||
var newSelected = this.value != null ? [...this.value] : [] // Clone value array
|
||||
var newSelected = this.value != null ? [...this.value] : []; // Clone value array
|
||||
|
||||
if (target.checked) {
|
||||
if (!newSelected.includes(target.value)) {
|
||||
newSelected.push(target.value)
|
||||
newSelected.push(target.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (newSelected.includes(target.value)) {
|
||||
var newSelected = newSelected.filter(function(value, index, arr){
|
||||
return value != target.value;
|
||||
})
|
||||
newSelected = newSelected.filter(function(value) {
|
||||
return value != target.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
this.$emit('input', newSelected)
|
||||
this.$emit("input", newSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,23 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: 'htmlBlock',
|
||||
name: "HtmlBlock",
|
||||
|
||||
props: [
|
||||
'label',
|
||||
'name',
|
||||
'content'
|
||||
]
|
||||
}
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -2,83 +2,117 @@
|
|||
<div>
|
||||
<form @submit.prevent="handleMetadataSubmit">
|
||||
<div class="uk-margin-remove uk-flex uk-flex-middle">
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-grid-small uk-width-expand" uk-grid>
|
||||
<div class="uk-margin-remove uk-width-1-2"><input v-model="newMetadata.key" class="uk-input uk-form-width-small uk-form-small" type="text" name="flavor" placeholder="Key"></div>
|
||||
<div class="uk-margin-remove uk-width-1-2"><input v-model="newMetadata.value" class="uk-input uk-form-width-small uk-form-small" type="text" name="flavor" placeholder="Value"></div>
|
||||
<div
|
||||
class="uk-margin-remove-top uk-padding-remove uk-grid-small uk-width-expand"
|
||||
uk-grid
|
||||
>
|
||||
<div class="uk-margin-remove uk-width-1-2">
|
||||
<input
|
||||
v-model="newMetadata.key"
|
||||
class="uk-input uk-form-width-small uk-form-small"
|
||||
type="text"
|
||||
name="flavor"
|
||||
placeholder="Key"
|
||||
/>
|
||||
</div>
|
||||
<div class="uk-margin-remove uk-width-1-2">
|
||||
<input
|
||||
v-model="newMetadata.value"
|
||||
class="uk-input uk-form-width-small uk-form-small"
|
||||
type="text"
|
||||
name="flavor"
|
||||
placeholder="Value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="#" v-on:click="handleMetadataSubmit()" class="uk-icon uk-margin-left"><i class="material-icons">add_circle</i></a>
|
||||
|
||||
<a
|
||||
href="#"
|
||||
class="uk-icon uk-margin-left"
|
||||
@click="handleMetadataSubmit()"
|
||||
><i class="material-icons">add_circle</i></a
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div v-for="(val, key) in value" :key="key" class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle">
|
||||
<div
|
||||
v-for="(val, key) in value"
|
||||
:key="key"
|
||||
class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle"
|
||||
>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||
<labelInput :label="key" :value="value[key]" @input="value[key]=$event"/>
|
||||
<labelInput
|
||||
:label="key"
|
||||
:value="value[key]"
|
||||
@input="value[key] = $event"
|
||||
/>
|
||||
</div>
|
||||
<a href="#" v-on:click="delMetadataKey(key)" class="uk-icon uk-width-auto"><i class="material-icons">delete</i></a>
|
||||
<a href="#" class="uk-icon uk-width-auto" @click="delMetadataKey(key)"
|
||||
><i class="material-icons">delete</i></a
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import labelInput from "../fieldComponents/labelInput"
|
||||
import labelInput from "../fieldComponents/labelInput";
|
||||
|
||||
export default {
|
||||
name: 'keyvalList',
|
||||
name: "KeyvalList",
|
||||
|
||||
components: {
|
||||
labelInput
|
||||
},
|
||||
|
||||
data: function () {
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
newMetadata: {
|
||||
key: "",
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
props: [
|
||||
'value'
|
||||
],
|
||||
|
||||
methods: {
|
||||
handleMetadataSubmit: function () {
|
||||
var newSelected = {}
|
||||
handleMetadataSubmit: function() {
|
||||
var newSelected = {};
|
||||
|
||||
if (this.value != null) {
|
||||
Object.assign(newSelected, this.value)
|
||||
Object.assign(newSelected, this.value);
|
||||
}
|
||||
|
||||
newSelected[this.newMetadata.key] = this.newMetadata.value
|
||||
newSelected[this.newMetadata.key] = this.newMetadata.value;
|
||||
this.newMetadata.key = "";
|
||||
this.newMetadata.value = "";
|
||||
|
||||
this.$emit('input', newSelected)
|
||||
this.$emit("input", newSelected);
|
||||
},
|
||||
|
||||
delMetadataKey: function (key) {
|
||||
var newSelected = {}
|
||||
delMetadataKey: function(key) {
|
||||
var newSelected = {};
|
||||
|
||||
if (this.value != null) {
|
||||
Object.assign(newSelected, this.value)
|
||||
Object.assign(newSelected, this.value);
|
||||
}
|
||||
|
||||
this.$delete(newSelected, key)
|
||||
this.$delete(newSelected, key);
|
||||
|
||||
this.$emit('input', newSelected)
|
||||
this.$emit("input", newSelected);
|
||||
},
|
||||
|
||||
modifyValue: function (e, v) {
|
||||
console.log(e)
|
||||
console.log(v)
|
||||
modifyValue: function(e, v) {
|
||||
console.log(e);
|
||||
console.log(v);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,58 +1,65 @@
|
|||
<template>
|
||||
<div>
|
||||
<label class="uk-form-label uk-text-bold">{{label}}</label>
|
||||
|
||||
<div @click="setEditing(true)" uk-tooltip="title: Click to edit value; delay: 250">
|
||||
<label class="uk-form-label uk-text-bold">{{ label }}</label>
|
||||
|
||||
<div
|
||||
uk-tooltip="title: Click to edit value; delay: 250"
|
||||
@click="setEditing(true)"
|
||||
>
|
||||
<div v-show="editing == false">
|
||||
<label> {{value}} </label>
|
||||
<label> {{ value }} </label>
|
||||
</div>
|
||||
|
||||
<input
|
||||
v-show="editing == true"
|
||||
ref="textinput"
|
||||
class="uk-input uk-form-small"
|
||||
type="text"
|
||||
v-bind:name="name"
|
||||
v-bind:value="value"
|
||||
ref="textinput"
|
||||
v-on:blur= "setEditing(false)"
|
||||
@keyup.enter = "setEditing(false)"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
:name="name"
|
||||
:value="value"
|
||||
autofocus
|
||||
>
|
||||
@blur="setEditing(false)"
|
||||
@keyup.enter="setEditing(false)"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'labelInput',
|
||||
name: "LabelInput",
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
editing: false
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
props: [
|
||||
'name',
|
||||
'label',
|
||||
'value'
|
||||
],
|
||||
data: function() {
|
||||
return {
|
||||
editing: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
setEditing(editing) {
|
||||
this.editing = editing
|
||||
this.editing = editing;
|
||||
if (editing == true) {
|
||||
this.$nextTick(() => this.$refs.textinput.focus())
|
||||
this.$nextTick(() => this.$refs.textinput.focus());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,33 +1,41 @@
|
|||
<template>
|
||||
<div>
|
||||
<label class="uk-form-label">{{label}}</label>
|
||||
<label class="uk-form-label">{{ label }}</label>
|
||||
|
||||
<input
|
||||
<input
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
:name="name"
|
||||
:value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
:placeholder="placeholder"
|
||||
>
|
||||
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'numberInput',
|
||||
|
||||
props: [
|
||||
'placeholder',
|
||||
'label',
|
||||
'name',
|
||||
'value'
|
||||
]
|
||||
|
||||
}
|
||||
name: "NumberInput",
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
placeholder: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,48 @@
|
|||
<template>
|
||||
<div>
|
||||
<label>{{label}}</label>
|
||||
<label>{{ label }}</label>
|
||||
|
||||
<div class="uk-form-controls">
|
||||
|
||||
<div v-for="option in options" :key="option">
|
||||
<label><input class="uk-radio" type="radio" :name="name" :value="option" :checked="value==option" @input="$emit('input', $event.target.value)"> {{ option }}</label>
|
||||
<label
|
||||
><input
|
||||
class="uk-radio"
|
||||
type="radio"
|
||||
:name="name"
|
||||
:value="option"
|
||||
:checked="value == option"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
{{ option }}</label
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'radioList',
|
||||
name: "RadioList",
|
||||
|
||||
props: [
|
||||
'options',
|
||||
'name',
|
||||
'label',
|
||||
'value'
|
||||
]
|
||||
}
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,33 +1,42 @@
|
|||
<template>
|
||||
<div>
|
||||
<label class="uk-form-label">{{label}}</label>
|
||||
<label class="uk-form-label">{{ label }}</label>
|
||||
|
||||
<select
|
||||
class="uk-select uk-form-small"
|
||||
:multiple="multi"
|
||||
:value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<option v-for="option in options" :key="option">
|
||||
{{option}}
|
||||
{{ option }}
|
||||
</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'selectList',
|
||||
name: "SelectList",
|
||||
|
||||
props: [
|
||||
'multi',
|
||||
'options',
|
||||
'name',
|
||||
'label',
|
||||
'value'
|
||||
]
|
||||
}
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,63 +1,79 @@
|
|||
<template>
|
||||
<div>
|
||||
|
||||
<form @submit.prevent="handleTagSubmit">
|
||||
<div class="uk-margin-small uk-flex uk-flex-middle">
|
||||
|
||||
<div class="uk-margin-remove-top uk-width-expand">
|
||||
<div class="uk-inline uk-width-1-1">
|
||||
<span class="uk-form-icon"><i class="material-icons">label</i></span>
|
||||
<input v-model="newTag" class="uk-input uk-form-small" type="text" name="flavor" placeholder="Tag">
|
||||
<span class="uk-form-icon"
|
||||
><i class="material-icons">label</i></span
|
||||
>
|
||||
<input
|
||||
v-model="newTag"
|
||||
class="uk-input uk-form-small"
|
||||
type="text"
|
||||
name="flavor"
|
||||
placeholder="Tag"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="#" v-on:click="handleTagSubmit()" class="uk-icon uk-margin-left"><i class="material-icons">add_circle</i></a>
|
||||
<a href="#" class="uk-icon uk-margin-left" @click="handleTagSubmit()"
|
||||
><i class="material-icons">add_circle</i></a
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<span v-for="tag in value" :key="tag" v-on:click="delTag(tag)" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||
|
||||
<span
|
||||
v-for="tag in value"
|
||||
:key="tag"
|
||||
class="uk-label uk-margin-small-right deletable-label"
|
||||
@click="delTag(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'tagList',
|
||||
name: "TagList",
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
newTag: ""
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
props: [
|
||||
'value'
|
||||
],
|
||||
data: function() {
|
||||
return {
|
||||
newTag: ""
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleTagSubmit: function () {
|
||||
var newSelected = this.value != null ? [...this.value] : [] // Clone value array
|
||||
handleTagSubmit: function() {
|
||||
var newSelected = this.value != null ? [...this.value] : []; // Clone value array
|
||||
|
||||
newSelected.push(this.newTag)
|
||||
newSelected.push(this.newTag);
|
||||
this.newTag = "";
|
||||
|
||||
this.$emit('input', newSelected)
|
||||
this.$emit("input", newSelected);
|
||||
},
|
||||
|
||||
delTag: function (tag) {
|
||||
var newSelected = this.value != null ? [...this.value] : [] // Clone value array
|
||||
delTag: function(tag) {
|
||||
var newSelected = this.value != null ? [...this.value] : []; // Clone value array
|
||||
|
||||
if (newSelected.includes(tag)) {
|
||||
var newSelected = newSelected.filter(function(value, index, arr){
|
||||
return value != tag;
|
||||
})
|
||||
newSelected = newSelected.filter(function(value) {
|
||||
return value != tag;
|
||||
});
|
||||
}
|
||||
|
||||
this.$emit('input', newSelected)
|
||||
this.$emit("input", newSelected);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,41 @@
|
|||
<template>
|
||||
<div>
|
||||
<label class="uk-form-label">{{label}}</label>
|
||||
<label class="uk-form-label">{{ label }}</label>
|
||||
|
||||
<input
|
||||
<input
|
||||
class="uk-input uk-form-small"
|
||||
type="text"
|
||||
v-bind:name="name"
|
||||
v-bind:value="value"
|
||||
v-bind:placeholder="placeholder"
|
||||
@input="$emit('input',$event.target.value)"
|
||||
>
|
||||
|
||||
:name="name"
|
||||
:value="value"
|
||||
:placeholder="placeholder"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'textInput',
|
||||
name: "TextInput",
|
||||
|
||||
props: [
|
||||
'placeholder',
|
||||
'label',
|
||||
'name',
|
||||
'value'
|
||||
]
|
||||
}
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,38 +1,37 @@
|
|||
<template>
|
||||
<div class="progress uk-margin-top uk-margin-horizontal-remove uk-padding-remove">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
<div
|
||||
class="progress uk-margin-top uk-margin-horizontal-remove uk-padding-remove"
|
||||
>
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'progressBar',
|
||||
name: "ProgressBar",
|
||||
|
||||
props: {},
|
||||
|
||||
methods: {
|
||||
setThisTab(event, value) {
|
||||
this.$emit('set-tab', event, this.id);
|
||||
computed: {
|
||||
tooltipOptions: function() {
|
||||
var title = this.id.charAt(0).toUpperCase() + this.id.slice(1);
|
||||
return `pos: right; title: ${title}; delay: 500`;
|
||||
},
|
||||
|
||||
classObject: function() {
|
||||
return {
|
||||
"tabicon-active": this.currentTab == this.id,
|
||||
"uk-disabled": this.requireConnection && !this.$store.getters.ready
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipOptions: function () {
|
||||
var title = this.id.charAt(0).toUpperCase() + this.id.slice(1);
|
||||
return `pos: right; title: ${title}; delay: 500`
|
||||
},
|
||||
|
||||
classObject: function () {
|
||||
return {
|
||||
'tabicon-active': this.currentTab == this.id,
|
||||
'uk-disabled': (this.requireConnection && !this.$store.getters.ready)
|
||||
}
|
||||
methods: {
|
||||
setThisTab(event) {
|
||||
this.$emit("set-tab", event, this.id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -47,7 +46,7 @@ export default {
|
|||
border-radius: 2px;
|
||||
background-clip: padding-box;
|
||||
margin: 0.5rem 0 1rem 0;
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress .determinate {
|
||||
|
|
@ -55,88 +54,104 @@ export default {
|
|||
background-color: inherit;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: width .3s linear;
|
||||
transition: width 0.3s linear;
|
||||
}
|
||||
|
||||
.progress .indeterminate, .progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.progress .indeterminate, .progress .determinate{
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
}
|
||||
|
||||
.progress .indeterminate:before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395)
|
||||
infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
}
|
||||
|
||||
.progress .indeterminate:after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
-webkit-animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
<template>
|
||||
|
||||
<div
|
||||
<div
|
||||
v-if="!(this.requireConnection && !this.$store.getters.ready)"
|
||||
v-bind:hidden="currentTab!=id"
|
||||
:hidden="currentTab != id"
|
||||
class="uk-width-expand"
|
||||
>
|
||||
<div class="section-heading">{{ id }}</div>
|
||||
<div class="section-content"><slot></slot></div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'tabContent',
|
||||
name: "TabContent",
|
||||
|
||||
props: {
|
||||
id: String,
|
||||
currentTab: String,
|
||||
requireConnection: Boolean,
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
currentTab: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
requireConnection: Boolean
|
||||
},
|
||||
computed: {},
|
||||
|
||||
methods: {},
|
||||
computed: {}
|
||||
}
|
||||
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.section-heading {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
|
|
@ -39,8 +39,8 @@ export default {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.section-content, .section-heading {
|
||||
.section-content,
|
||||
.section-heading {
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,48 +1,51 @@
|
|||
<template>
|
||||
<a
|
||||
href="#"
|
||||
<a
|
||||
href="#"
|
||||
class="uk-link"
|
||||
:class="classObject"
|
||||
:class="classObject"
|
||||
:uk-tooltip="tooltipOptions"
|
||||
@click="setThisTab">
|
||||
@click="setThisTab"
|
||||
>
|
||||
<slot></slot>
|
||||
</a>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'tabIcon',
|
||||
name: "TabIcon",
|
||||
|
||||
props: {
|
||||
id: String,
|
||||
currentTab: String,
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
currentTab: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
requireConnection: Boolean
|
||||
},
|
||||
|
||||
methods: {
|
||||
setThisTab(event, value) {
|
||||
this.$emit('set-tab', event, this.id);
|
||||
computed: {
|
||||
tooltipOptions: function() {
|
||||
var title = this.id.charAt(0).toUpperCase() + this.id.slice(1);
|
||||
return `pos: right; title: ${title}; delay: 500`;
|
||||
},
|
||||
|
||||
classObject: function() {
|
||||
return {
|
||||
"tabicon-active": this.currentTab == this.id,
|
||||
"uk-disabled": this.requireConnection && !this.$store.getters.ready
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
tooltipOptions: function () {
|
||||
var title = this.id.charAt(0).toUpperCase() + this.id.slice(1);
|
||||
return `pos: right; title: ${title}; delay: 500`
|
||||
},
|
||||
|
||||
classObject: function () {
|
||||
return {
|
||||
'tabicon-active': this.currentTab == this.id,
|
||||
'uk-disabled': (this.requireConnection && !this.$store.getters.ready)
|
||||
}
|
||||
methods: {
|
||||
setThisTab(event) {
|
||||
this.$emit("set-tab", event, this.id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -54,9 +57,8 @@ export default {
|
|||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.tabicon-active {
|
||||
color: @inverse-primary-muted-color !important;
|
||||
}
|
||||
.tabicon-active {
|
||||
color: @inverse-primary-muted-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,31 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class="progress uk-margin-top uk-margin-horizontal-remove uk-padding-remove"
|
||||
>
|
||||
<div
|
||||
v-if="progress"
|
||||
class="determinate"
|
||||
:style="barWidthFromProgress"
|
||||
></div>
|
||||
<div v-else class="indeterminate"></div>
|
||||
</div>
|
||||
|
||||
<div class="progress uk-margin-top uk-margin-horizontal-remove uk-padding-remove">
|
||||
<div v-if="progress" class="determinate" :style="barWidthFromProgress"></div>
|
||||
<div v-else class="indeterminate"></div>
|
||||
<button
|
||||
type="button"
|
||||
class="uk-button uk-button-danger uk-form-small uk-float-right uk-width-1-1"
|
||||
@click="terminateTask()"
|
||||
>
|
||||
Terminate
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" v-on:click="terminateTask()" class="uk-button uk-button-danger uk-form-small uk-float-right uk-width-1-1">Terminate</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: 'taskProgress',
|
||||
name: "TaskProgress",
|
||||
|
||||
props: {
|
||||
taskId: {
|
||||
|
|
@ -26,54 +36,54 @@ export default {
|
|||
type: Number,
|
||||
required: false,
|
||||
default: 500
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
polling: null,
|
||||
polling: null,
|
||||
progress: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
barWidthFromProgress: function() {
|
||||
var progress = this.progress <= 100 ? this.progress : 100;
|
||||
var styleString = `width: ${progress}%`;
|
||||
return styleString;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.polling = setInterval(() => {
|
||||
this.pollProgress()
|
||||
}, this.pollInterval)
|
||||
this.pollProgress();
|
||||
}, this.pollInterval);
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
clearInterval(this.polling)
|
||||
beforeDestroy() {
|
||||
clearInterval(this.polling);
|
||||
},
|
||||
|
||||
methods: {
|
||||
pollProgress: function() {
|
||||
console.log("Starting progress polling")
|
||||
axios.get(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("PROGRESS RESPONSE: ", response.data.progress)
|
||||
this.progress = response.data.progress
|
||||
})
|
||||
console.log("Starting progress polling");
|
||||
axios
|
||||
.get(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("PROGRESS RESPONSE: ", response.data.progress);
|
||||
this.progress = response.data.progress;
|
||||
});
|
||||
},
|
||||
|
||||
terminateTask: function() {
|
||||
axios.delete(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("TERMINATION RESPONSE: ", response.data)
|
||||
})
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
barWidthFromProgress: function () {
|
||||
var progress = ((this.progress <= 100) ? this.progress : 100)
|
||||
var styleString = `width: ${progress}%`
|
||||
return styleString
|
||||
},
|
||||
axios
|
||||
.delete(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("TERMINATION RESPONSE: ", response.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -88,7 +98,7 @@ export default {
|
|||
border-radius: 2px;
|
||||
background-clip: padding-box;
|
||||
margin: 0.5rem 0 1rem 0;
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress .determinate {
|
||||
|
|
@ -96,88 +106,104 @@ export default {
|
|||
background-color: inherit;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: width .3s linear;
|
||||
transition: width 0.3s linear;
|
||||
}
|
||||
|
||||
.progress .indeterminate, .progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.progress .indeterminate, .progress .determinate{
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
}
|
||||
|
||||
.progress .indeterminate:before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395)
|
||||
infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
}
|
||||
|
||||
.progress .indeterminate:after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
-webkit-animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,43 @@
|
|||
<template>
|
||||
<div class="uk-margin-horizontal-remove uk-padding-remove">
|
||||
<div
|
||||
class="uk-margin-horizontal-remove uk-margin-small-top uk-padding-remove"
|
||||
>
|
||||
<div v-if="taskRunning" ref="isPollingElement">
|
||||
<div class="progress">
|
||||
<div
|
||||
v-if="progress"
|
||||
class="determinate"
|
||||
:style="barWidthFromProgress"
|
||||
></div>
|
||||
<div v-else class="indeterminate"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="taskRunning" ref="isPollingElement">
|
||||
<div class="progress">
|
||||
<div v-if="progress" class="determinate" :style="barWidthFromProgress"></div>
|
||||
<div v-else class="indeterminate"></div>
|
||||
<button
|
||||
v-if="canTerminate"
|
||||
type="button"
|
||||
class="uk-button uk-button-danger uk-form-small uk-margin uk-float-right uk-width-1-1"
|
||||
@click="terminateTask()"
|
||||
>
|
||||
Terminate
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button v-if="canTerminate" type="button" v-on:click="terminateTask()" class="uk-button uk-button-danger uk-form-small uk-margin uk-float-right uk-width-1-1">Terminate</button>
|
||||
<button
|
||||
type="button"
|
||||
:hidden="taskRunning"
|
||||
class="uk-button uk-button-primary uk-form-small uk-margin uk-float-right uk-width-1-1"
|
||||
@click="bootstrapTask()"
|
||||
>
|
||||
{{ submitLabel }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" v-on:click="bootstrapTask()" v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-margin uk-float-right uk-width-1-1">{{ submitLabel }}</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: 'taskSubmitter',
|
||||
name: "TaskSubmitter",
|
||||
|
||||
props: {
|
||||
submitURL: {
|
||||
|
|
@ -63,148 +81,152 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
taskId: null,
|
||||
polling: null,
|
||||
polling: null,
|
||||
progress: null,
|
||||
taskRunning: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
barWidthFromProgress: function() {
|
||||
var progress = this.progress <= 100 ? this.progress : 100;
|
||||
var styleString = `width: ${progress}%`;
|
||||
return styleString;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
created() {},
|
||||
|
||||
beforeDestroy () {
|
||||
},
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
bootstrapTask: function() {
|
||||
if (this.requiresConfirmation) {
|
||||
this.modalConfirm(this.confirmationMessage)
|
||||
.then(() => {
|
||||
this.startTask()
|
||||
}, () => {})
|
||||
}
|
||||
else {
|
||||
this.startTask()
|
||||
this.modalConfirm(this.confirmationMessage).then(
|
||||
() => {
|
||||
this.startTask();
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
} else {
|
||||
this.startTask();
|
||||
}
|
||||
},
|
||||
|
||||
startTask: function() {
|
||||
console.log("Task start clicked")
|
||||
this.$emit('submit', this.submitData)
|
||||
console.log("Task start clicked");
|
||||
this.$emit("submit", this.submitData);
|
||||
// Send a request to start a task
|
||||
axios.post(this.submitURL, this.submitData)
|
||||
// Get the returned Task ID
|
||||
.then(response => {
|
||||
// Fetch the task ID
|
||||
console.log("Task ID: " + response.data.id)
|
||||
this.taskId = response.data.id
|
||||
// Start the store polling TaskId for success
|
||||
this.taskRunning = true
|
||||
// Return the poll-task promise (starts polling the task)
|
||||
return this.pollTask(this.taskId, this.pollTimeout, this.pollInterval)
|
||||
})
|
||||
.then(response => {
|
||||
// Do something with the final response
|
||||
console.log("Emitting onResponse: ", response)
|
||||
this.$emit('response', response)
|
||||
})
|
||||
.catch(error => {
|
||||
if (!error) {
|
||||
error = Error("Unknown error")
|
||||
}
|
||||
console.log("Emitting onError: ", error)
|
||||
this.$emit('error', error)
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after task.")
|
||||
// Reset taskRunning and taskId
|
||||
this.taskRunning = false
|
||||
this.taskId = null
|
||||
// Update the form data if we're self-updating
|
||||
if (this.selfUpdate) {
|
||||
this.getFormData()
|
||||
}
|
||||
})
|
||||
axios
|
||||
.post(this.submitURL, this.submitData)
|
||||
// Get the returned Task ID
|
||||
.then(response => {
|
||||
// Fetch the task ID
|
||||
console.log("Task ID: " + response.data.id);
|
||||
this.taskId = response.data.id;
|
||||
// Start the store polling TaskId for success
|
||||
this.taskRunning = true;
|
||||
// Return the poll-task promise (starts polling the task)
|
||||
return this.pollTask(
|
||||
this.taskId,
|
||||
this.pollTimeout,
|
||||
this.pollInterval
|
||||
);
|
||||
})
|
||||
.then(response => {
|
||||
// Do something with the final response
|
||||
console.log("Emitting onResponse: ", response);
|
||||
this.$emit("response", response);
|
||||
})
|
||||
.catch(error => {
|
||||
if (!error) {
|
||||
error = Error("Unknown error");
|
||||
}
|
||||
console.log("Emitting onError: ", error);
|
||||
this.$emit("error", error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Cleaning up after task.");
|
||||
// Reset taskRunning and taskId
|
||||
this.taskRunning = false;
|
||||
this.taskId = null;
|
||||
// Update the form data if we're self-updating
|
||||
if (this.selfUpdate) {
|
||||
this.getFormData();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
pollTask: function(taskId, timeout, interval) {
|
||||
var endTime = Number(new Date()) + (timeout*1000 || 30000);
|
||||
interval = interval*1000 || 500;
|
||||
var endTime = Number(new Date()) + (timeout * 1000 || 30000);
|
||||
interval = interval * 1000 || 500;
|
||||
|
||||
var checkCondition = (resolve, reject) => {
|
||||
// If the condition is met, we're done!
|
||||
axios.get(`${this.$store.getters.uri}/task/${taskId}`)
|
||||
.then(response => {
|
||||
console.log(response.data.status)
|
||||
var result = response.data.status
|
||||
// If the task ends with success
|
||||
if(result == 'success') {
|
||||
resolve(response.data)
|
||||
}
|
||||
// If task ends with an error
|
||||
else if (result == 'error') {
|
||||
// Pass the error string back with reject
|
||||
reject(new Error(response.data.return))
|
||||
}
|
||||
// If task ends with termination
|
||||
else if (result == 'terminated') {
|
||||
// Pass a generic termination error back with reject
|
||||
reject(new Error("Task terminated"))
|
||||
}
|
||||
// If task ends in any other way
|
||||
else if (result != 'running') {
|
||||
// Pass status string as error
|
||||
reject(new Error(result))
|
||||
}
|
||||
// If the condition isn't met but the timeout hasn't elapsed, go again
|
||||
else if (Number(new Date()) < endTime) {
|
||||
// Since the task is still running, we can update the progress bar
|
||||
this.progress = response.data.progress
|
||||
// Check again after timeout
|
||||
setTimeout(checkCondition, interval, resolve, reject)
|
||||
}
|
||||
// Didn't match and too much time, reject!
|
||||
else {
|
||||
reject(new Error('Polling timed out'))
|
||||
}
|
||||
})
|
||||
// If the condition is met, we're done!
|
||||
axios
|
||||
.get(`${this.$store.getters.uri}/task/${taskId}`)
|
||||
.then(response => {
|
||||
console.log(response.data.status);
|
||||
var result = response.data.status;
|
||||
// If the task ends with success
|
||||
if (result == "success") {
|
||||
resolve(response.data);
|
||||
}
|
||||
// If task ends with an error
|
||||
else if (result == "error") {
|
||||
// Pass the error string back with reject
|
||||
reject(new Error(response.data.return));
|
||||
}
|
||||
// If task ends with termination
|
||||
else if (result == "terminated") {
|
||||
// Pass a generic termination error back with reject
|
||||
reject(new Error("Task terminated"));
|
||||
}
|
||||
// If task ends in any other way
|
||||
else if (result != "running") {
|
||||
// Pass status string as error
|
||||
reject(new Error(result));
|
||||
}
|
||||
// If the condition isn't met but the timeout hasn't elapsed, go again
|
||||
else if (Number(new Date()) < endTime) {
|
||||
// Since the task is still running, we can update the progress bar
|
||||
this.progress = response.data.progress;
|
||||
// Check again after timeout
|
||||
setTimeout(checkCondition, interval, resolve, reject);
|
||||
}
|
||||
// Didn't match and too much time, reject!
|
||||
else {
|
||||
reject(new Error("Polling timed out"));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(checkCondition);
|
||||
},
|
||||
|
||||
pollProgress: function() {
|
||||
console.log("Starting progress polling")
|
||||
|
||||
axios.get(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("PROGRESS RESPONSE: ", response.data.progress)
|
||||
this.progress = response.data.progress
|
||||
})
|
||||
console.log("Starting progress polling");
|
||||
|
||||
axios
|
||||
.get(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("PROGRESS RESPONSE: ", response.data.progress);
|
||||
this.progress = response.data.progress;
|
||||
});
|
||||
},
|
||||
|
||||
terminateTask: function() {
|
||||
axios.delete(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("TERMINATION RESPONSE: ", response.data)
|
||||
})
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
barWidthFromProgress: function () {
|
||||
var progress = ((this.progress <= 100) ? this.progress : 100)
|
||||
var styleString = `width: ${progress}%`
|
||||
return styleString
|
||||
},
|
||||
axios
|
||||
.delete(`${this.$store.getters.uri}/task/${this.taskId}`)
|
||||
.then(response => {
|
||||
console.log("TERMINATION RESPONSE: ", response.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -219,7 +241,7 @@ export default {
|
|||
border-radius: 2px;
|
||||
background-clip: padding-box;
|
||||
margin: 0.5rem 0 1rem 0;
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress .determinate {
|
||||
|
|
@ -227,88 +249,104 @@ export default {
|
|||
background-color: inherit;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: width .3s linear;
|
||||
transition: width 0.3s linear;
|
||||
}
|
||||
|
||||
.progress .indeterminate, .progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @global-primary-background;
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.progress .indeterminate, .progress .determinate{
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
.progress .indeterminate,
|
||||
.progress .determinate {
|
||||
background-color: @inverse-primary-muted-color;
|
||||
}
|
||||
}
|
||||
|
||||
.progress .indeterminate:before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395)
|
||||
infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
}
|
||||
|
||||
.progress .indeterminate:after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1)
|
||||
infinite;
|
||||
-webkit-animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
animation-delay: 1.15s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
right: -90%;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
@keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
right: 100%;
|
||||
}
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
right: -8%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,95 +1,147 @@
|
|||
<template>
|
||||
<div id="panel-left" class="uk-margin-remove uk-padding-remove uk-height-1-1" uk-grid>
|
||||
|
||||
<div
|
||||
id="panel-left"
|
||||
class="uk-margin-remove uk-padding-remove uk-height-1-1"
|
||||
uk-grid
|
||||
>
|
||||
<!-- Vertical tab bar -->
|
||||
<div id="switcher-left" class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1">
|
||||
<tabIcon id="status" :requireConnection="false" :currentTab="currentTab" @set-tab="setTab">
|
||||
<div
|
||||
id="switcher-left"
|
||||
class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1"
|
||||
>
|
||||
<tabIcon
|
||||
id="status"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">bug_report</i>
|
||||
</tabIcon>
|
||||
<tabIcon id="navigate" :requireConnection="true" :currentTab="currentTab" @set-tab="setTab">
|
||||
<i class="material-icons">gamepad</i>
|
||||
<tabIcon
|
||||
id="navigate"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">gamepad</i>
|
||||
</tabIcon>
|
||||
<tabIcon id="capture" :requireConnection="true" :currentTab="currentTab" @set-tab="setTab">
|
||||
<tabIcon
|
||||
id="capture"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">camera_alt</i>
|
||||
</tabIcon>
|
||||
<tabIcon id="settings" :requireConnection="false" :currentTab="currentTab" @set-tab="setTab">
|
||||
<i class="material-icons">settings</i>
|
||||
<tabIcon
|
||||
id="settings"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">settings</i>
|
||||
</tabIcon>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<tabIcon v-for="plugin in $store.state.apiPlugins" @set-tab="setTab"
|
||||
:key="plugin.id"
|
||||
:id="plugin.id"
|
||||
:requireConnection="plugin.requiresConnection"
|
||||
:currentTab="currentTab">
|
||||
<i class="material-icons">{{ plugin.icon || "extension" }}</i>
|
||||
<tabIcon
|
||||
v-for="plugin in $store.state.apiPlugins"
|
||||
:id="plugin.id"
|
||||
:key="plugin.id"
|
||||
:require-connection="plugin.requiresConnection"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">{{ plugin.icon || "extension" }}</i>
|
||||
</tabIcon>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Corresponding vertical tab content -->
|
||||
<div v-bind:hidden="!showControlBar" id="container-left" class="uk-padding-remove uk-height-1-1 uk-width-expand">
|
||||
<div id="component-left" class="uk-padding-remove uk-flex uk-flex-1 panel-content">
|
||||
<tabContent id="status" :requireConnection="false" :currentTab="currentTab">
|
||||
<paneStatus/>
|
||||
<div
|
||||
id="container-left"
|
||||
:hidden="!showControlBar"
|
||||
class="uk-padding-remove uk-height-1-1 uk-width-expand"
|
||||
>
|
||||
<div
|
||||
id="component-left"
|
||||
class="uk-padding-remove uk-flex uk-flex-1 panel-content"
|
||||
>
|
||||
<tabContent
|
||||
id="status"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<paneStatus />
|
||||
</tabContent>
|
||||
<tabContent id="navigate" :requireConnection="true" :currentTab="currentTab">
|
||||
<paneNavigate/>
|
||||
<tabContent
|
||||
id="navigate"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<paneNavigate />
|
||||
</tabContent>
|
||||
<tabContent id="capture" :requireConnection="true" :currentTab="currentTab">
|
||||
<paneCapture/>
|
||||
<tabContent
|
||||
id="capture"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<paneCapture />
|
||||
</tabContent>
|
||||
<tabContent id="settings" :requireConnection="false" :currentTab="currentTab">
|
||||
<paneSettings/>
|
||||
<tabContent
|
||||
id="settings"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<paneSettings />
|
||||
</tabContent>
|
||||
|
||||
<tabContent v-for="plugin in $store.state.apiPlugins"
|
||||
:key="plugin.id"
|
||||
:id="plugin.id"
|
||||
:requireConnection="plugin.requiresConnection"
|
||||
:currentTab="currentTab">
|
||||
|
||||
<div class="uk-flex uk-flex-column" v-for="form in plugin.forms" :key="`${form.route}/${form.name}`.replace(/\s+/g, '-').toLowerCase()" >
|
||||
<JsonForm
|
||||
<tabContent
|
||||
v-for="plugin in $store.state.apiPlugins"
|
||||
:id="plugin.id"
|
||||
:key="plugin.id"
|
||||
:require-connection="plugin.requiresConnection"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<div
|
||||
v-for="form in plugin.forms"
|
||||
:key="
|
||||
`${form.route}/${form.name}`.replace(/\s+/g, '-').toLowerCase()
|
||||
"
|
||||
class="uk-flex uk-flex-column"
|
||||
>
|
||||
<JsonForm
|
||||
:name="form.name"
|
||||
:route="form.route"
|
||||
:isTask="form.isTask"
|
||||
:submitLabel="form.submitLabel"
|
||||
:selfUpdate="form.selfUpdate"
|
||||
:schema="form.schema"/>
|
||||
<hr>
|
||||
:is-task="form.isTask"
|
||||
:submit-label="form.submitLabel"
|
||||
:self-update="form.selfUpdate"
|
||||
:schema="form.schema"
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
</tabContent>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Import axios for HTTP requests
|
||||
import axios from 'axios'
|
||||
|
||||
// Import generic components
|
||||
import tabIcon from './genericComponents/tabIcon'
|
||||
import tabContent from './genericComponents/tabContent'
|
||||
import tabIcon from "./genericComponents/tabIcon";
|
||||
import tabContent from "./genericComponents/tabContent";
|
||||
|
||||
// Import pane components
|
||||
import paneStatus from './controlComponents/paneStatus'
|
||||
import paneNavigate from './controlComponents/paneNavigate'
|
||||
import paneCapture from './controlComponents/paneCapture'
|
||||
import paneSettings from './controlComponents/paneSettings'
|
||||
import paneStatus from "./controlComponents/paneStatus";
|
||||
import paneNavigate from "./controlComponents/paneNavigate";
|
||||
import paneCapture from "./controlComponents/paneCapture";
|
||||
import paneSettings from "./controlComponents/paneSettings";
|
||||
|
||||
// Import plugin components
|
||||
import JsonForm from './pluginComponents/JsonForm'
|
||||
import JsonForm from "./pluginComponents/JsonForm";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'panelLeft',
|
||||
name: "PanelLeft",
|
||||
|
||||
components: {
|
||||
tabIcon,
|
||||
|
|
@ -101,38 +153,34 @@ export default {
|
|||
JsonForm
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
currentTab: 'status',
|
||||
currentTab: "status",
|
||||
showControlBar: true
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginApiUri: function() {
|
||||
return this.$store.getters.uri + "/plugin";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setTab: function(event, tab) {
|
||||
if (this.currentTab == tab) {
|
||||
this.showControlBar = !this.showControlBar
|
||||
this.currentTab = 'none'
|
||||
this.showControlBar = !this.showControlBar;
|
||||
this.currentTab = "none";
|
||||
} else {
|
||||
this.showControlBar = true;
|
||||
this.currentTab = tab;
|
||||
}
|
||||
else {
|
||||
this.showControlBar = true
|
||||
this.currentTab = tab
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
#component-left {
|
||||
width: 300px;
|
||||
}
|
||||
|
|
@ -142,19 +190,19 @@ export default {
|
|||
background-color: rgba(180, 180, 180, 0.025);
|
||||
}
|
||||
|
||||
#container-left, #switcher-left {
|
||||
#container-left,
|
||||
#switcher-left {
|
||||
border-width: 0 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: rgba(180, 180, 180, 0.25)
|
||||
border-color: rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
|
||||
#switcher-left a{
|
||||
#switcher-left a {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
#switcher-left{
|
||||
#switcher-left {
|
||||
background-color: rgba(180, 180, 180, 0.1);
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,81 +1,98 @@
|
|||
<template>
|
||||
<!-- Tabbed panel for gallery and live views -->
|
||||
<div id="panel-right" class="uk-flex uk-flex-column uk-margin-remove uk-padding-remove uk-width-expand uk-height-1-1">
|
||||
<ul class="uk-flex-none uk-flex-center uk-margin-remove-bottom uk-text-center" id="tabContainer" uk-tab="swiping: false">
|
||||
<div
|
||||
id="panel-right"
|
||||
class="uk-flex uk-flex-column uk-margin-remove uk-padding-remove uk-width-expand uk-height-1-1"
|
||||
>
|
||||
<ul
|
||||
id="tabContainer"
|
||||
class="uk-flex-none uk-flex-center uk-margin-remove-bottom uk-text-center"
|
||||
uk-tab="swiping: false"
|
||||
>
|
||||
<li><a href="#" uk-switcher-item="connect">Connect</a></li>
|
||||
<li v-bind:class="{'uk-disabled': !this.$store.getters.ready}"><a href="#" uk-switcher-item="preview">Live</a></li>
|
||||
<li v-bind:class="{'uk-disabled': !this.$store.getters.ready}"><a href="#" uk-switcher-item="gallery">Gallery</a></li>
|
||||
<li :class="{ 'uk-disabled': !this.$store.getters.ready }">
|
||||
<a href="#" uk-switcher-item="preview">Live</a>
|
||||
</li>
|
||||
<li :class="{ 'uk-disabled': !this.$store.getters.ready }">
|
||||
<a href="#" uk-switcher-item="gallery">Gallery</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="uk-switcher uk-flex uk-flex-1 uk-overflow-auto">
|
||||
<li class="uk-height-1-1 uk-width-1-1" id="connectDisplayTab"><connectDisplay/></li>
|
||||
<li class="uk-height-1-1 uk-width-1-1 clickableTab" id="streamDisplayTab"><streamDisplay/></li>
|
||||
<li class="uk-height-1-1 uk-width-1-1" id="galleryDisplayTab"><galleryDisplay/></li>
|
||||
<li id="connectDisplayTab" class="uk-height-1-1 uk-width-1-1">
|
||||
<connectDisplay />
|
||||
</li>
|
||||
<li id="streamDisplayTab" class="uk-height-1-1 uk-width-1-1 clickableTab">
|
||||
<streamDisplay />
|
||||
</li>
|
||||
<li id="galleryDisplayTab" class="uk-height-1-1 uk-width-1-1">
|
||||
<galleryDisplay />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Import axios for HTTP requests
|
||||
import axios from 'axios'
|
||||
// Import basic UIkit
|
||||
import UIkit from 'uikit';
|
||||
import UIkit from "uikit";
|
||||
|
||||
// Import components
|
||||
import connectDisplay from './viewComponents/connectDisplay.vue'
|
||||
import streamDisplay from './viewComponents/streamDisplay.vue'
|
||||
import galleryDisplay from './viewComponents/galleryDisplay.vue'
|
||||
import connectDisplay from "./viewComponents/connectDisplay.vue";
|
||||
import streamDisplay from "./viewComponents/streamDisplay.vue";
|
||||
import galleryDisplay from "./viewComponents/galleryDisplay.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'panelRight',
|
||||
name: "PanelRight",
|
||||
|
||||
components: {
|
||||
connectDisplay,
|
||||
streamDisplay,
|
||||
galleryDisplay,
|
||||
galleryDisplay
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Attach methods to UIkit events for tab switching
|
||||
var context = this;
|
||||
// Gallery tab
|
||||
UIkit.util.on('#streamDisplayTab', 'hidden', function(event, area) {
|
||||
console.log("Stream tab hidden")
|
||||
|
||||
// Stream tab leave
|
||||
UIkit.util.on("#streamDisplayTab", "hidden", function() {
|
||||
console.log("Stream tab hidden");
|
||||
if (context.$store.state.globalSettings.trackWindow == true) {
|
||||
context.$root.$emit('globalTogglePreview', false)
|
||||
context.$root.$emit("globalTogglePreview", false);
|
||||
}
|
||||
context.$root.$emit('globalUpdateCaptureList');
|
||||
});
|
||||
|
||||
// Stream tab
|
||||
UIkit.util.on('#streamDisplayTab', 'shown', function(event, area) {
|
||||
console.log("Stream tab entered")
|
||||
UIkit.update()
|
||||
// Stream tab enter
|
||||
UIkit.util.on("#streamDisplayTab", "shown", function() {
|
||||
console.log("Stream tab entered");
|
||||
UIkit.update();
|
||||
if (context.$store.state.globalSettings.trackWindow == true) {
|
||||
context.$root.$emit('globalTogglePreview', true)
|
||||
context.$root.$emit("globalTogglePreview", true);
|
||||
}
|
||||
});
|
||||
|
||||
// Gallery tab enter
|
||||
UIkit.util.on("#galleryDisplayTab", "shown", function() {
|
||||
console.log("Gallery tab entered");
|
||||
UIkit.update();
|
||||
context.$root.$emit("globalUpdateCaptureList");
|
||||
});
|
||||
|
||||
// Create a global event to switch the active tab
|
||||
var switcherObj = UIkit.tab('#tabContainer')
|
||||
console.log(switcherObj)
|
||||
this.$root.$on('globalTogglePanelRightTab', (state) => {
|
||||
console.log(`Toggling panelRight tab to ${state}`)
|
||||
switcherObj.show(1)
|
||||
})
|
||||
|
||||
var switcherObj = UIkit.tab("#tabContainer");
|
||||
console.log(switcherObj);
|
||||
this.$root.$on("globalTogglePanelRightTab", state => {
|
||||
console.log(`Toggling panelRight tab to ${state}`);
|
||||
switcherObj.show(1);
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
}
|
||||
|
||||
}
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
.uk-tab {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,68 +1,86 @@
|
|||
<template>
|
||||
<div>
|
||||
|
||||
<div class="uk-flex">
|
||||
<div class="uk-text-bold uk-text-uppercase uk-width-expand">{{ name }}</div>
|
||||
<a href="#" v-if="selfUpdate" v-on:click="getFormData()" class="uk-icon uk-width-auto"><i class="material-icons">cached</i></a>
|
||||
<div class="uk-text-bold uk-text-uppercase uk-width-expand">
|
||||
{{ name }}
|
||||
</div>
|
||||
<a
|
||||
v-if="selfUpdate"
|
||||
href="#"
|
||||
class="uk-icon uk-width-auto"
|
||||
@click="getFormData()"
|
||||
><i class="material-icons">cached</i></a
|
||||
>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="" class="uk-form-stacked" ref="formContainer">
|
||||
|
||||
<div v-for="(field, index) in schema" :key="index">
|
||||
<div v-if="Array.isArray(field)" class="uk-grid-small uk-width-1-1 uk-child-width-expand" uk-grid>
|
||||
<div v-for="(subfield, subindex) in field" :key="subindex">
|
||||
<form ref="formContainer" class="uk-form-stacked" @submit.prevent="">
|
||||
<div v-for="(field, index) in schema" :key="index">
|
||||
<div
|
||||
v-if="Array.isArray(field)"
|
||||
class="uk-grid-small uk-width-1-1 uk-child-width-expand"
|
||||
uk-grid
|
||||
>
|
||||
<div v-for="(subfield, subindex) in field" :key="subindex">
|
||||
<component
|
||||
:is="subfield.fieldType"
|
||||
v-model="formData[subfield.name]"
|
||||
v-bind="subfield">
|
||||
v-bind="subfield"
|
||||
>
|
||||
</component>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<component
|
||||
:is="field.fieldType"
|
||||
v-model="formData[field.name]"
|
||||
v-bind="field">
|
||||
v-bind="field"
|
||||
>
|
||||
</component>
|
||||
</div>
|
||||
|
||||
<taskSubmitter v-if="isTask"
|
||||
v-bind:submitURL="submitApiUri"
|
||||
v-bind:submitData="formData"
|
||||
v-bind:submitLabel="submitLabel"
|
||||
v-on:submit="onTaskSubmit"
|
||||
v-on:response="onTaskResponse"
|
||||
v-on:error="onTaskError">
|
||||
<taskSubmitter
|
||||
v-if="isTask"
|
||||
:submit-u-r-l="submitApiUri"
|
||||
:submit-data="formData"
|
||||
:submit-label="submitLabel"
|
||||
@submit="onTaskSubmit"
|
||||
@response="onTaskResponse"
|
||||
@error="onTaskError"
|
||||
>
|
||||
</taskSubmitter>
|
||||
|
||||
<button v-else type="button" v-on:click="newQuickRequest(formData);" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button>
|
||||
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1"
|
||||
@click="newQuickRequest(formData)"
|
||||
>
|
||||
{{ submitLabel }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
import numberInput from "../fieldComponents/numberInput"
|
||||
import selectList from "../fieldComponents/selectList"
|
||||
import textInput from "../fieldComponents/textInput"
|
||||
import htmlBlock from "../fieldComponents/htmlBlock"
|
||||
import radioList from "../fieldComponents/radioList"
|
||||
import checkList from "../fieldComponents/checkList"
|
||||
import tagList from "../fieldComponents/tagList"
|
||||
import keyvalList from "../fieldComponents/keyvalList"
|
||||
import numberInput from "../fieldComponents/numberInput";
|
||||
import selectList from "../fieldComponents/selectList";
|
||||
import textInput from "../fieldComponents/textInput";
|
||||
import htmlBlock from "../fieldComponents/htmlBlock";
|
||||
import radioList from "../fieldComponents/radioList";
|
||||
import checkList from "../fieldComponents/checkList";
|
||||
import tagList from "../fieldComponents/tagList";
|
||||
import keyvalList from "../fieldComponents/keyvalList";
|
||||
|
||||
import taskSubmitter from "../genericComponents/taskSubmitter"
|
||||
import taskSubmitter from "../genericComponents/taskSubmitter";
|
||||
|
||||
export default {
|
||||
name: 'JsonForm',
|
||||
name: "JsonForm",
|
||||
|
||||
components: {
|
||||
numberInput,
|
||||
selectList,
|
||||
components: {
|
||||
numberInput,
|
||||
selectList,
|
||||
textInput,
|
||||
htmlBlock,
|
||||
radioList,
|
||||
|
|
@ -73,47 +91,57 @@ export default {
|
|||
},
|
||||
|
||||
props: {
|
||||
'name': {
|
||||
name: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "Plugin"
|
||||
},
|
||||
'schema': {
|
||||
schema: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
'route': {
|
||||
route: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
'isTask': {
|
||||
isTask: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
'submitLabel': {
|
||||
submitLabel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "Submit"
|
||||
},
|
||||
'selfUpdate': {
|
||||
selfUpdate: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
formData: {}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginApiUri: function() {
|
||||
return this.$store.getters.uri + "/plugin";
|
||||
},
|
||||
|
||||
submitApiUri: function() {
|
||||
return this.pluginApiUri + this.route;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.initialiseFormData()
|
||||
this.initialiseFormData();
|
||||
|
||||
if (this.selfUpdate) {
|
||||
this.getFormData()
|
||||
this.getFormData();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -129,83 +157,67 @@ export default {
|
|||
for (const field of this.schema) {
|
||||
if (Array.isArray(field)) {
|
||||
for (const subfield of field) {
|
||||
console.log(subfield.name)
|
||||
this.$set(this.formData, subfield.name, null)
|
||||
console.log(subfield.name);
|
||||
this.$set(this.formData, subfield.name, null);
|
||||
}
|
||||
} else {
|
||||
console.log(field.name);
|
||||
this.$set(this.formData, field.name, null);
|
||||
}
|
||||
else {
|
||||
console.log(field.name)
|
||||
this.$set(this.formData, field.name, null)
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
updateForm(fieldName, value) {
|
||||
this.$set(this.formData, fieldName, value);
|
||||
this.$emit('input', this.formData)
|
||||
this.$emit("input", this.formData);
|
||||
},
|
||||
|
||||
getFormData: function() {
|
||||
// Send a quick request
|
||||
axios.get(this.submitApiUri)
|
||||
.then(response => {
|
||||
console.log(response.data)
|
||||
Object.assign(this.formData, response.data)
|
||||
axios
|
||||
.get(this.submitApiUri)
|
||||
.then(response => {
|
||||
console.log(response.data);
|
||||
Object.assign(this.formData, response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
newQuickRequest: function(params) {
|
||||
console.log(this.submitApiUri)
|
||||
console.log(params)
|
||||
console.log(this.submitApiUri);
|
||||
console.log(params);
|
||||
// Send a quick request
|
||||
axios.post(this.submitApiUri, params)
|
||||
.then(response => {
|
||||
axios
|
||||
.post(this.submitApiUri, params)
|
||||
.then(response => {
|
||||
// Do something with the response
|
||||
console.log(response)
|
||||
console.log(response);
|
||||
// Update the form data if we're self-updating
|
||||
if (this.selfUpdate) {
|
||||
this.getFormData()
|
||||
this.getFormData();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
onTaskSubmit: function(submitData) {
|
||||
// We don't need to do anything on this event yet
|
||||
console.log("onTaskSubmit event triggered")
|
||||
},
|
||||
onTaskSubmit: function() {},
|
||||
|
||||
onTaskResponse: function(responseData) {
|
||||
console.log("Task finished with response data: ", responseData)
|
||||
console.log("Task finished with response data: ", responseData);
|
||||
if (this.selfUpdate) {
|
||||
this.getFormData()
|
||||
this.getFormData();
|
||||
}
|
||||
},
|
||||
|
||||
onTaskError: function(error) {
|
||||
this.modalError(error)
|
||||
this.modalError(error);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginApiUri: function () {
|
||||
return this.$store.getters.uri + "/plugin"
|
||||
},
|
||||
|
||||
submitApiUri: function () {
|
||||
return this.pluginApiUri + this.route
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -214,6 +226,6 @@ export default {
|
|||
}
|
||||
|
||||
.flex-container > div {
|
||||
flex-basis: 100%
|
||||
flex-basis: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,40 +1,62 @@
|
|||
<template>
|
||||
<div class="hostCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
||||
|
||||
<div
|
||||
class="hostCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium"
|
||||
:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
<div class="snapshot-container uk-width-1-1 uk-height-auto">
|
||||
<img class="uk-width-1-1" v-bind:data-src="snapshotSrc" width="300" height="225" uk-img>
|
||||
<div v-if="!snapshotAvailable" class="uk-position-cover uk-flex uk-flex-center uk-flex-middle">Snapshot unavailable</div>
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="snapshotSrc"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
/>
|
||||
<div
|
||||
v-if="!snapshotAvailable"
|
||||
class="uk-position-cover uk-flex uk-flex-center uk-flex-middle"
|
||||
>
|
||||
Snapshot unavailable
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle">
|
||||
<div
|
||||
class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle"
|
||||
>
|
||||
<div class="uk-width-expand host-description">
|
||||
<div class="host-description"><b>{{ name }}</b></div>
|
||||
<div class="host-description">
|
||||
<b>{{ name }}</b>
|
||||
</div>
|
||||
<div class="host-description">{{ hostname }}:{{ port }}</div>
|
||||
</div>
|
||||
<a href="#" v-on:click="$emit('delete')" class="uk-icon uk-width-auto host-delete"><i class="material-icons">delete</i></a>
|
||||
<a
|
||||
href="#"
|
||||
class="uk-icon uk-width-auto host-delete"
|
||||
@click="$emit('delete')"
|
||||
><i class="material-icons">delete</i></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<button
|
||||
<button
|
||||
class="uk-button uk-button-default uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
||||
v-on:click="$emit('connect')"
|
||||
>Connect</button>
|
||||
@click="$emit('connect')"
|
||||
>
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UIkit from 'uikit';
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'hostCard',
|
||||
name: "HostCard",
|
||||
|
||||
props: {
|
||||
name: {
|
||||
|
|
@ -51,23 +73,32 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
snapshotSrc: "",
|
||||
snapshotAvailable: false,
|
||||
polling: null
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
routesURL: function() {
|
||||
return `http://${this.hostname}:${this.port}/routes`;
|
||||
},
|
||||
snapshotURL: function() {
|
||||
return `http://${this.hostname}:${this.port}/api/v1/snapshot`;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Try to load the microscope snapshot when mounted
|
||||
this.checkSnapshotAvailable()
|
||||
this.checkSnapshotAvailable();
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
beforeDestroy() {
|
||||
// Clear the polling timer
|
||||
if (this.polling !== null) {
|
||||
clearInterval(this.polling)
|
||||
clearInterval(this.polling);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -77,52 +108,42 @@ export default {
|
|||
// a snapshot timer if the snapshot route is available
|
||||
|
||||
// Send tag request
|
||||
axios.get(this.routesURL)
|
||||
.then((response) => {
|
||||
// If the host has a snapshot route available
|
||||
if ("/api/v1/snapshot" in response.data) {
|
||||
// Tell the view that a snapshot is available
|
||||
this.snapshotAvailable = true
|
||||
// Update the snapshot URL
|
||||
this.updateSnapshotURL()
|
||||
// If not already polling, start polling
|
||||
if (this.polling === null) {
|
||||
this.updateSnapshotPoll()
|
||||
axios
|
||||
.get(this.routesURL)
|
||||
.then(response => {
|
||||
// If the host has a snapshot route available
|
||||
if ("/api/v1/snapshot" in response.data) {
|
||||
// Tell the view that a snapshot is available
|
||||
this.snapshotAvailable = true;
|
||||
// Update the snapshot URL
|
||||
this.updateSnapshotURL();
|
||||
// If not already polling, start polling
|
||||
if (this.polling === null) {
|
||||
this.updateSnapshotPoll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
// Tell the view that a snapshot is not available, and ignore
|
||||
this.snapshotAvailable = false
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
// Tell the view that a snapshot is not available, and ignore
|
||||
this.snapshotAvailable = false;
|
||||
});
|
||||
},
|
||||
|
||||
updateSnapshotURL: function() {
|
||||
// Set the snapshot image src to the snapshot URL,
|
||||
// adding a timestamp argument to act as a cache-breaker
|
||||
this.snapshotSrc = `${this.snapshotURL}?${Date.now()}`
|
||||
console.log(`Updating snapshot URL to ${this.snapshotSrc}`)
|
||||
this.snapshotSrc = `${this.snapshotURL}?${Date.now()}`;
|
||||
console.log(`Updating snapshot URL to ${this.snapshotSrc}`);
|
||||
},
|
||||
|
||||
updateSnapshotPoll: function() {
|
||||
// Start a timer to call updateSnapshotURL periodically
|
||||
this.polling = setInterval(() => {
|
||||
this.updateSnapshotURL()
|
||||
}, 15000)
|
||||
this.updateSnapshotURL();
|
||||
}, 15000);
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
routesURL: function () {
|
||||
return `http://${this.hostname}:${this.port}/routes`
|
||||
},
|
||||
snapshotURL: function () {
|
||||
return `http://${this.hostname}:${this.port}/api/v1/snapshot`
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
@ -135,8 +156,7 @@ export default {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
img[data-src][src*='data:image'] {
|
||||
background: rgba(127,127,127,0.1);
|
||||
img[data-src][src*="data:image"] {
|
||||
background: rgba(127, 127, 127, 0.1);
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,63 @@
|
|||
<template>
|
||||
<div class="connectDisplay uk-padding uk-padding-remove-left">
|
||||
|
||||
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove" margin=0>
|
||||
|
||||
<div class="connectDisplay uk-padding uk-padding-remove-left">
|
||||
<div
|
||||
uk-grid
|
||||
class="uk-height-1-1 uk-margin-remove uk-padding-remove"
|
||||
margin="0"
|
||||
>
|
||||
<div class="uk-width-auto">
|
||||
|
||||
<div class="uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium connect-card-align-top">
|
||||
|
||||
<div
|
||||
class="uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium connect-card-align-top"
|
||||
>
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="uk-form-controls uk-margin">
|
||||
<label><input class="uk-radio" type="radio" name="radio_local" v-model="computedLocalMode" v-bind:value="true"> Connect locally</label><br>
|
||||
<label><input class="uk-radio" type="radio" name="radio_local" v-model="computedLocalMode" v-bind:value="false" checked> Connect remotely</label>
|
||||
<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" v-bind:class="IpFormClasses" class="uk-input uk-form-small" type="text" placeholder="Hostname or IP address">
|
||||
<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>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Port</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="computedPort" class="uk-input uk-form-small" id="form-stacked-text" type="number" value=5000>
|
||||
<input
|
||||
id="form-stacked-text"
|
||||
v-model="computedPort"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
value="5000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -28,102 +65,90 @@
|
|||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<button
|
||||
v-on:click="handleSubmit"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">
|
||||
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"
|
||||
v-on:click="saveHost()"
|
||||
class="uk-button uk-button-default uk-form-small uk-margin-small uk-width-1-1">
|
||||
<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"
|
||||
v-on:click="$store.commit('resetState')"
|
||||
class="uk-button uk-button-danger uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">
|
||||
<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 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"
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
:port="host.port"
|
||||
v-on:connect="handleConnectButton(host)"
|
||||
v-on:delete="delSavedHost(host)"
|
||||
@connect="handleConnectButton(host)"
|
||||
@delete="delSavedHost(host)"
|
||||
></hostCard>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li 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"
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
:port="host.port"
|
||||
:deletable="false"
|
||||
v-on:connect="handleConnectButton(host)"
|
||||
@connect="handleConnectButton(host)"
|
||||
></hostCard>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { version } from 'punycode';
|
||||
|
||||
// Import mDNS package if running in Electron
|
||||
import isElectron from '../../modules/isElectron';
|
||||
import isElectron from "../../modules/isElectron";
|
||||
if (isElectron()) {
|
||||
var mdns = require('mdns-js');
|
||||
var mdns = require("mdns-js");
|
||||
}
|
||||
|
||||
import hostCard from './connectComponents/hostCard.vue'
|
||||
import hostCard from "./connectComponents/hostCard.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'connectDisplay',
|
||||
name: "ConnectDisplay",
|
||||
|
||||
components: {
|
||||
hostCard
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
localMode: true,
|
||||
hostname: "",
|
||||
|
|
@ -131,161 +156,205 @@ export default {
|
|||
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)
|
||||
this.setLocalMode(this.localMode);
|
||||
|
||||
// Try loading savedHosts from localStorage. If null, don't change.
|
||||
this.savedHosts = this.getLocalStorageObj('savedHosts') || this.savedHosts
|
||||
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'));
|
||||
var browser = mdns.createBrowser(mdns.tcp("openflexure"));
|
||||
|
||||
// Start discovering services when ready
|
||||
browser.on('ready', function () {
|
||||
browser.discover();
|
||||
browser.on("ready", function() {
|
||||
browser.discover();
|
||||
});
|
||||
|
||||
browser.on('update', (data) => {
|
||||
console.log(data)
|
||||
browser.on("update", data => {
|
||||
console.log(data);
|
||||
|
||||
// We will be checking if it's a valid openflexure device
|
||||
var validDevice = false
|
||||
var validDevice = false;
|
||||
|
||||
// Go through each type of the host, make valid if 'openflexure' appears
|
||||
data.type.forEach((element) => {
|
||||
console.log(element)
|
||||
data.type.forEach(element => {
|
||||
console.log(element);
|
||||
if (element.name === "openflexure") {
|
||||
validDevice = true
|
||||
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);
|
||||
}
|
||||
|
||||
if ((typeof data.port !== "undefined") && (validDevice === true)) {
|
||||
this.$set(this.foundHosts, hostData.hostname, hostData)
|
||||
}
|
||||
|
||||
console.log(this.foundHosts)
|
||||
console.log(this.foundHosts);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// When savedHosts changes, serialise to JSON and save to localStorage
|
||||
watch: {
|
||||
savedHosts(newSavedHosts) {
|
||||
this.setLocalStorageObj('savedHosts', this.savedHosts)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
connectToHost: function(host) {
|
||||
console.log(host)
|
||||
console.log(host);
|
||||
// Set the global form values
|
||||
this.hostname = host.hostname
|
||||
this.port = host.port
|
||||
|
||||
this.hostname = host.hostname;
|
||||
this.port = host.port;
|
||||
|
||||
// Commit the hostname and port to store
|
||||
this.$store.commit('changeHost', [
|
||||
host.hostname,
|
||||
host.port
|
||||
]);
|
||||
this.$store.commit("changeHost", [host.hostname, host.port]);
|
||||
// Try to get config and state JSON from the newly submitted host
|
||||
this.$store.dispatch('firstConnect')
|
||||
.then (() => {
|
||||
console.log("Connected!")
|
||||
// Check client and server match
|
||||
this.checkServerVersion()
|
||||
// Switch to live view tab
|
||||
this.$root.$emit('globalTogglePanelRightTab', 'preview')
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
this.$store
|
||||
.dispatch("firstConnect")
|
||||
.then(() => {
|
||||
console.log("Connected!");
|
||||
// Check client and server match
|
||||
this.checkServerVersion();
|
||||
// Switch to live view tab
|
||||
this.$root.$emit("globalTogglePanelRightTab", "preview");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
handleSubmit: function(event) {
|
||||
handleSubmit: function() {
|
||||
// Split host and port if needed
|
||||
if (this.hostname.includes(':')) {
|
||||
if (this.hostname.includes(":")) {
|
||||
this.port = this.computedPort;
|
||||
this.hostname = this.hostname.split(':')[0];
|
||||
this.hostname = this.hostname.split(":")[0];
|
||||
}
|
||||
|
||||
// Handle auto-local-connect
|
||||
var hostname;
|
||||
if (this.localMode) {
|
||||
var hostname = "localhost";
|
||||
}
|
||||
else {
|
||||
var hostname = this.hostname;
|
||||
hostname = "localhost";
|
||||
} else {
|
||||
hostname = this.hostname;
|
||||
}
|
||||
|
||||
var selectedHost = {
|
||||
hostname: hostname,
|
||||
port: this.port
|
||||
}
|
||||
};
|
||||
|
||||
this.connectToHost(selectedHost)
|
||||
this.connectToHost(selectedHost);
|
||||
},
|
||||
|
||||
handleConnectButton: function(host) {
|
||||
this.computedLocalMode = false
|
||||
this.connectToHost(host)
|
||||
this.computedLocalMode = false;
|
||||
this.connectToHost(host);
|
||||
},
|
||||
|
||||
checkServerVersion: function () {
|
||||
this.$store.dispatch('updateState')
|
||||
.then (() => {
|
||||
var clientVersion = process.env.PACKAGE.version
|
||||
var clientVersionMajor = clientVersion.substring(0, 3)
|
||||
console.log(clientVersionMajor)
|
||||
checkServerVersion: function() {
|
||||
this.$store
|
||||
.dispatch("updateState")
|
||||
.then(() => {
|
||||
var clientVersion = process.env.PACKAGE.version;
|
||||
var clientVersionMajor = clientVersion.substring(0, 3);
|
||||
console.log(clientVersionMajor);
|
||||
|
||||
var serverVersion = this.$store.state.apiState.version
|
||||
if (serverVersion != undefined) {
|
||||
var serverVersionMajor = serverVersion.substring(0, 3)
|
||||
}
|
||||
console.log(serverVersionMajor)
|
||||
var serverVersion = this.$store.state.apiState.version;
|
||||
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.\
|
||||
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."
|
||||
<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);
|
||||
}
|
||||
else {
|
||||
versionWarning = versionWarning + "Try running 'ofm upgrade' on your microscope."
|
||||
}
|
||||
this.modalDialog("Version mismatch", versionWarning, status='warning')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
})
|
||||
.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]);
|
||||
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)
|
||||
delSavedHost: function(host) {
|
||||
console.log(host);
|
||||
var index = this.savedHosts.indexOf(host);
|
||||
if (index > -1) {
|
||||
this.savedHosts.splice(index, 1);
|
||||
|
|
@ -294,67 +363,19 @@ export default {
|
|||
|
||||
saveHost: function() {
|
||||
// We use unshift instead of push to add the entry to the beginning of the array
|
||||
this.savedHosts.unshift(
|
||||
{
|
||||
name: this.$store.state.apiConfig.name,
|
||||
hostname: this.$store.state.host,
|
||||
port: this.$store.state.port
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.savedHosts.unshift({
|
||||
name: this.$store.state.apiConfig.name,
|
||||
hostname: this.$store.state.host,
|
||||
port: this.$store.state.port
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="less">
|
||||
|
||||
.connect-card-align-top {
|
||||
margin-top: 52px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,86 +1,137 @@
|
|||
<template>
|
||||
<div class="captureCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
||||
|
||||
<div
|
||||
class="captureCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium"
|
||||
:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
<a class="lightbox-link" v-bind:href="imgURL" v-bind:data-caption="metadata.filename">
|
||||
<img class="uk-width-1-1" v-bind:data-src="thumbURL" v-bind:alt="metadata.id" width="300" height="225" uk-img>
|
||||
<a class="lightbox-link" :href="imgURL" :data-caption="metadata.filename">
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="thumbURL"
|
||||
:alt="metadata.id"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">{{ metadata.filename }}</div>
|
||||
<div
|
||||
class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right"
|
||||
uk-grid
|
||||
>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||
{{ metadata.filename }}
|
||||
</div>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a href="#" v-on:click="delCaptureConfirm()" class="uk-icon">
|
||||
<a href="#" class="uk-icon" @click="delCaptureConfirm()">
|
||||
<i class="material-icons">delete</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"><time>{{ betterTimestring }}</time></div>
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a v-bind:href="metadataModalTarget" uk-toggle>More...</a>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
|
||||
>
|
||||
<time>{{ betterTimestring }}</time>
|
||||
</div>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
|
||||
>
|
||||
<a :href="metadataModalTarget" uk-toggle>More...</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<div v-for="tag in tags" :key="tag">
|
||||
<span v-if="tag==='temporary'" class="uk-label uk-label-danger uk-margin-small-right" uk-tooltip="title: Capture will be removed automatically; delay: 500">Temporary</span>
|
||||
<span v-else v-on:click="delTagConfirm(tag)" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||
<span
|
||||
v-if="tag === 'temporary'"
|
||||
class="uk-label uk-label-danger uk-margin-small-right"
|
||||
uk-tooltip="title: Capture will be removed automatically; delay: 500"
|
||||
>Temporary</span
|
||||
>
|
||||
<span
|
||||
v-else
|
||||
class="uk-label uk-margin-small-right deletable-label"
|
||||
@click="delTagConfirm(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a v-bind:href="tagModalTarget" uk-toggle>
|
||||
<a :href="tagModalTarget" uk-toggle>
|
||||
<span class="uk-label uk-label-success uk-margin-small-right">Add</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-bind:id="metadataModalID" uk-modal>
|
||||
<div :id="metadataModalID" uk-modal>
|
||||
<div
|
||||
class="uk-modal-dialog uk-modal-body"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
>
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.filename }}</h2>
|
||||
<p><b>Path: </b>{{ path }}</p>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>ID: </b>{{ metadata.id }}</p>
|
||||
<p><b>Format: </b>{{ metadata.format }}</p>
|
||||
|
||||
<div class="uk-modal-dialog uk-modal-body" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }" >
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.filename }}</h2>
|
||||
<p><b>Path: </b>{{ path }}</p>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>ID: </b>{{ metadata.id }}</p>
|
||||
<p><b>Format: </b>{{ metadata.format }}</p>
|
||||
|
||||
<div v-for="(value, key) in metadata.custom" :key="key" >
|
||||
<p><b>{{ key }}: </b>{{ value }}</p>
|
||||
</div>
|
||||
<div v-for="(value, key) in metadata.custom" :key="key">
|
||||
<p>
|
||||
<b>{{ key }}: </b>{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-bind:id="tagModalID" uk-modal>
|
||||
|
||||
<form class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }" @submit.prevent="handleTagSubmit">
|
||||
|
||||
<div class="uk-inline">
|
||||
<span class="uk-form-icon"><i class="material-icons">label</i></span>
|
||||
<input v-model="newtag" class="uk-input uk-form-width-medium uk-form-small" type="text" name="tagname" placeholder="tag">
|
||||
|
||||
<button class="uk-button uk-button-default uk-margin-left uk-form-small uk-modal-close" type="button">Cancel</button>
|
||||
<button type="submit" class="uk-button uk-button-primary uk-margin-left uk-form-small">Save</button>
|
||||
</div>
|
||||
<div :id="tagModalID" uk-modal>
|
||||
<form
|
||||
class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
@submit.prevent="handleTagSubmit"
|
||||
>
|
||||
<div class="uk-inline">
|
||||
<span class="uk-form-icon"><i class="material-icons">label</i></span>
|
||||
<input
|
||||
v-model="newtag"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="text"
|
||||
name="tagname"
|
||||
placeholder="tag"
|
||||
/>
|
||||
|
||||
<button
|
||||
class="uk-button uk-button-default uk-margin-left uk-form-small uk-modal-close"
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-margin-left uk-form-small"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UIkit from 'uikit';
|
||||
import axios from 'axios'
|
||||
import UIkit from "uikit";
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'captureCard',
|
||||
name: "CaptureCard",
|
||||
|
||||
props: {
|
||||
metadata: {
|
||||
|
|
@ -93,11 +144,48 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
tags: [],
|
||||
newtag: "",
|
||||
}
|
||||
newtag: ""
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function() {
|
||||
return this.makeModalName("tag-modal-");
|
||||
},
|
||||
tagModalTarget: function() {
|
||||
return "#" + this.tagModalID;
|
||||
},
|
||||
metadataModalID: function() {
|
||||
return this.makeModalName("metadata-modal-");
|
||||
},
|
||||
metadataModalTarget: function() {
|
||||
return "#" + this.metadataModalID;
|
||||
},
|
||||
thumbURL: function() {
|
||||
return this.captureURL + "/download?thumbnail=true";
|
||||
},
|
||||
imgURL: function() {
|
||||
return this.captureURL + "/download/" + this.metadata.filename;
|
||||
},
|
||||
tagURL: function() {
|
||||
return this.captureURL + "/tags";
|
||||
},
|
||||
captureURL: function() {
|
||||
return this.$store.getters.uri + "/camera/capture/" + this.metadata.id;
|
||||
},
|
||||
betterTimestring: function() {
|
||||
var dtSplit = this.metadata.time.split("_");
|
||||
var date = dtSplit[0];
|
||||
var time = dtSplit[1].replace(/-/g, ":");
|
||||
return date + " " + time;
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {
|
||||
this.getTagRequest();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
@ -106,114 +194,78 @@ export default {
|
|||
console.log(this.newtag);
|
||||
this.newTagRequest(this.newtag);
|
||||
this.newtag = "";
|
||||
UIkit.modal(event.target.parentNode).hide(); // TODO: Remove somehow
|
||||
UIkit.modal(event.target.parentNode).hide(); // TODO: Remove somehow
|
||||
},
|
||||
|
||||
delCaptureConfirm: function(tag_string) {
|
||||
var context = this
|
||||
this.modalConfirm('Permanantly delete capture?')
|
||||
.then(function() {
|
||||
context.delCaptureRequest()
|
||||
delCaptureConfirm: function() {
|
||||
var context = this;
|
||||
this.modalConfirm("Permanantly delete capture?").then(function() {
|
||||
context.delCaptureRequest();
|
||||
});
|
||||
},
|
||||
|
||||
delCaptureRequest: function() {
|
||||
// Send tag DELETE request
|
||||
axios.delete(this.captureURL)
|
||||
.then(response => {
|
||||
// Emit signal to update capture list
|
||||
this.$root.$emit('globalUpdateCaptureList')
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.delete(this.captureURL)
|
||||
.then(() => {
|
||||
// Emit signal to update capture list
|
||||
this.$root.$emit("globalUpdateCaptureList");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
newTagRequest: function(tag_string) {
|
||||
// Send tag PUT request
|
||||
axios.put(this.tagURL, [tag_string])
|
||||
.then(response => {
|
||||
// Update tag array
|
||||
this.getTagRequest()
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.put(this.tagURL, [tag_string])
|
||||
.then(() => {
|
||||
// Update tag array
|
||||
this.getTagRequest();
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
delTagConfirm: function(tag_string) {
|
||||
var context = this;
|
||||
this.modalConfirm(`Remove tag '${tag_string}'?`).then(function() {
|
||||
context.delTagRequest(tag_string)
|
||||
context.delTagRequest(tag_string);
|
||||
});
|
||||
},
|
||||
|
||||
delTagRequest: function(tag_string) {
|
||||
console.log(tag_string)
|
||||
console.log(tag_string);
|
||||
// Send tag DELETE request
|
||||
axios.delete(this.tagURL, {data: [tag_string]})
|
||||
.then(response => {
|
||||
// Update tag array
|
||||
this.getTagRequest()
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.delete(this.tagURL, { data: [tag_string] })
|
||||
.then(() => {
|
||||
// Update tag array
|
||||
this.getTagRequest();
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
getTagRequest: function() {
|
||||
// Send tag request
|
||||
axios.get(this.tagURL)
|
||||
.then(response => {
|
||||
this.tags = response.data.metadata.tags
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.get(this.tagURL)
|
||||
.then(response => {
|
||||
this.tags = response.data.metadata.tags;
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
created: function () {
|
||||
this.getTagRequest()
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function () {
|
||||
return this.makeModalName("tag-modal-")
|
||||
},
|
||||
tagModalTarget: function () {
|
||||
return "#" + this.tagModalID
|
||||
},
|
||||
metadataModalID: function () {
|
||||
return this.makeModalName("metadata-modal-")
|
||||
},
|
||||
metadataModalTarget: function () {
|
||||
return "#" + this.metadataModalID
|
||||
},
|
||||
thumbURL: function () {
|
||||
return this.captureURL + "/download?thumbnail=true"
|
||||
},
|
||||
imgURL: function () {
|
||||
return this.captureURL + "/download/" + this.metadata.filename
|
||||
},
|
||||
tagURL: function () {
|
||||
return this.captureURL + "/tags"
|
||||
},
|
||||
captureURL: function () {
|
||||
return this.$store.getters.uri + "/camera/capture/" + this.metadata.id
|
||||
},
|
||||
betterTimestring: function () {
|
||||
var dtSplit = this.metadata.time.split("_");
|
||||
var date = dtSplit[0]
|
||||
var time = dtSplit[1].replace(/-/g, ":")
|
||||
return date + " " + time
|
||||
return prefix + this.metadata.id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,54 +1,76 @@
|
|||
<template>
|
||||
<div class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium">
|
||||
|
||||
<div
|
||||
class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
|
||||
<a href="#" >
|
||||
<img class="uk-width-1-1" v-bind:data-src="thumbnail" v-bind:alt="metadata.scan_id" width="300" height="225" v-on:click="$root.$emit('globalUpdateCaptureFolder', metadata.custom.scan_id)" uk-img>
|
||||
<a href="#">
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="thumbnail"
|
||||
:alt="metadata.scan_id"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
@click="
|
||||
$root.$emit('globalUpdateCaptureFolder', metadata.custom.scan_id)
|
||||
"
|
||||
/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand"><b>Scan:</b> {{ metadata.custom.basename }}</div>
|
||||
<div
|
||||
class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right"
|
||||
uk-grid
|
||||
>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||
<b>Scan:</b> {{ metadata.custom.basename }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"><time>{{ betterTimestring }}</time></div>
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a v-bind:href="metadataModalTarget" uk-toggle>More...</a>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
|
||||
>
|
||||
<time>{{ betterTimestring }}</time>
|
||||
</div>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
|
||||
>
|
||||
<a :href="metadataModalTarget" uk-toggle>More...</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<span v-for="tag in metadata.tags" :key="tag" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||
<span
|
||||
v-for="tag in metadata.tags"
|
||||
:key="tag"
|
||||
class="uk-label uk-margin-small-right deletable-label"
|
||||
>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-bind:id="metadataModalID" uk-modal>
|
||||
|
||||
<div :id="metadataModalID" uk-modal>
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.basename }}</h2>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>Scan ID: </b>{{ metadata.custom.scan_id }}</p>
|
||||
|
||||
<div v-for="(value, key) in metadata.custom" :key="key" >
|
||||
<p><b>{{ key }}: </b>{{ value }}</p>
|
||||
<div v-for="(value, key) in metadata.custom" :key="key">
|
||||
<p>
|
||||
<b>{{ key }}: </b>{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'captureCard',
|
||||
name: "CaptureCard",
|
||||
|
||||
props: {
|
||||
metadata: {
|
||||
|
|
@ -61,33 +83,31 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id
|
||||
computed: {
|
||||
tagModalID: function() {
|
||||
return this.makeModalName("tag-modal-");
|
||||
},
|
||||
tagModalTarget: function() {
|
||||
return "#" + this.tagModalID;
|
||||
},
|
||||
metadataModalID: function() {
|
||||
return this.makeModalName("metadata-modal-");
|
||||
},
|
||||
metadataModalTarget: function() {
|
||||
return "#" + this.metadataModalID;
|
||||
},
|
||||
betterTimestring: function() {
|
||||
var dtSplit = this.metadata.custom.time.split("_");
|
||||
var date = dtSplit[0];
|
||||
var time = dtSplit[1].replace(/-/g, ":");
|
||||
return date + " " + time;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function () {
|
||||
return this.makeModalName("tag-modal-")
|
||||
},
|
||||
tagModalTarget: function () {
|
||||
return "#" + this.tagModalID
|
||||
},
|
||||
metadataModalID: function () {
|
||||
return this.makeModalName("metadata-modal-")
|
||||
},
|
||||
metadataModalTarget: function () {
|
||||
return "#" + this.metadataModalID
|
||||
},
|
||||
betterTimestring: function () {
|
||||
var dtSplit = this.metadata.custom.time.split("_");
|
||||
var date = dtSplit[0]
|
||||
var time = dtSplit[1].replace(/-/g, ":")
|
||||
return date + " " + time
|
||||
methods: {
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,108 +1,255 @@
|
|||
<template>
|
||||
<div class="galleryDisplay uk-padding uk-padding-remove-top">
|
||||
|
||||
<nav class="uk-navbar-container uk-navbar-transparent navbar" uk-navbar="mode: click">
|
||||
<div class="uk-navbar-left uk-padding-remove-top uk-padding-remove-bottom">
|
||||
<ul class="uk-navbar-nav">
|
||||
<li v-bind:class="[sortDescending ? 'uk-active' : '']"><a v-on:click="sortDescending=true;" class="uk-icon" href="#"><i class="material-icons">keyboard_arrow_down</i></a></li>
|
||||
<li v-bind:class="[!sortDescending ? 'uk-active' : '']"><a v-on:click="sortDescending=false;" class="uk-icon" href="#"><i class="material-icons">keyboard_arrow_up</i></a></li>
|
||||
<li>
|
||||
<a href="#">Filter</a>
|
||||
<div class="uk-navbar-dropdown" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }">
|
||||
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||
<form class="uk-form-stacked">
|
||||
<div v-for="tag in allTags" :key="tag" class="uk-margin-small">
|
||||
<label><input class="uk-checkbox" type="checkbox" v-bind:id="tag" v-bind:value="tag" v-model="checkedTags" checked> {{ tag }}</label>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="galleryDisplay uk-padding uk-padding-remove-top">
|
||||
<nav
|
||||
class="uk-navbar-container uk-navbar-transparent navbar"
|
||||
uk-navbar="mode: click"
|
||||
>
|
||||
<div
|
||||
class="uk-navbar-left uk-padding-remove-top uk-padding-remove-bottom"
|
||||
>
|
||||
<ul class="uk-navbar-nav">
|
||||
<li :class="[sortDescending ? 'uk-active' : '']">
|
||||
<a class="uk-icon" href="#" @click="sortDescending = true"
|
||||
><i class="material-icons">keyboard_arrow_down</i></a
|
||||
>
|
||||
</li>
|
||||
<li :class="[!sortDescending ? 'uk-active' : '']">
|
||||
<a class="uk-icon" href="#" @click="sortDescending = false"
|
||||
><i class="material-icons">keyboard_arrow_up</i></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Filter</a>
|
||||
<div
|
||||
class="uk-navbar-dropdown"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
>
|
||||
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||
<form class="uk-form-stacked">
|
||||
<div
|
||||
v-for="tag in allTags"
|
||||
:key="tag"
|
||||
class="uk-margin-small"
|
||||
>
|
||||
<label
|
||||
><input
|
||||
:id="tag"
|
||||
v-model="checkedTags"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
:value="tag"
|
||||
checked
|
||||
/>
|
||||
{{ tag }}</label
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
||||
|
||||
<div v-if="(galleryFolder)" class="uk-flex uk-flex-middle uk-padding uk-padding-remove-horizontal uk-padding-remove-bottom">
|
||||
<a href="#" v-on:click="galleryFolder=''" class="uk-icon uk-margin-remove"><i class="material-icons">arrow_back</i></a>
|
||||
<div
|
||||
v-if="$store.getters.ready"
|
||||
class="uk-padding-remove-top"
|
||||
uk-lightbox="toggle: .lightbox-link"
|
||||
>
|
||||
<div
|
||||
v-if="galleryFolder"
|
||||
class="uk-flex uk-flex-middle uk-padding uk-padding-remove-horizontal uk-padding-remove-bottom"
|
||||
>
|
||||
<a href="#" class="uk-icon uk-margin-remove" @click="galleryFolder = ''"
|
||||
><i class="material-icons">arrow_back</i></a
|
||||
>
|
||||
<div class="uk-margin-left">
|
||||
<h3 class="uk-margin-remove uk-margin-left"><b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}</h3>
|
||||
<h3 class="uk-margin-remove uk-margin-left">
|
||||
<b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
||||
|
||||
<div v-for="item in sortedItems" :key="item.metadata.id">
|
||||
<scanCard
|
||||
<scanCard
|
||||
v-if="'isScan' in item"
|
||||
:metadata="item.metadata"
|
||||
:thumbnail="item.thumbnail"
|
||||
/>
|
||||
<captureCard
|
||||
<captureCard
|
||||
v-else
|
||||
:metadata="item.metadata"
|
||||
:temporary="item.temporary"
|
||||
:path="item.path"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import captureCard from './galleryComponents/captureCard.vue'
|
||||
import scanCard from './galleryComponents/scanCard.vue'
|
||||
import axios from "axios";
|
||||
import captureCard from "./galleryComponents/captureCard.vue";
|
||||
import scanCard from "./galleryComponents/scanCard.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'galleryDisplay',
|
||||
name: "GalleryDisplay",
|
||||
|
||||
components: {
|
||||
captureCard,
|
||||
scanCard
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
captureList: [],
|
||||
checkedTags: [],
|
||||
sortDescending: true,
|
||||
galleryFolder: "",
|
||||
scanTag: 'scan'
|
||||
}
|
||||
scanTag: "scan"
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
captureApiUri: function() {
|
||||
return this.$store.getters.uri + "/camera/capture";
|
||||
},
|
||||
|
||||
allTags: function() {
|
||||
// Return an array of unique tags across all captures
|
||||
var tags = [];
|
||||
for (var capture of this.captureList) {
|
||||
for (var tag of capture.metadata.tags) {
|
||||
if (!tags.includes(tag)) {
|
||||
tags.push(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags.sort();
|
||||
},
|
||||
|
||||
noScanCaptureList: function() {
|
||||
var captures = [];
|
||||
for (var capture of this.captureList) {
|
||||
// Filter by selected tags
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
// Add to capture list if matched
|
||||
if (!tags.includes(this.scanTag)) {
|
||||
captures.push(capture);
|
||||
}
|
||||
}
|
||||
|
||||
return captures;
|
||||
},
|
||||
|
||||
allScans: function() {
|
||||
// Return an array of unique tags across all captures
|
||||
var scans = {};
|
||||
|
||||
for (var capture of this.captureList) {
|
||||
var custom = capture.metadata.custom;
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
if ("scan_id" in custom) {
|
||||
var id = custom["scan_id"];
|
||||
|
||||
// If this scan ID hasn't been seen before
|
||||
if (!(id in scans)) {
|
||||
scans[id] = {};
|
||||
scans[id].isScan = true;
|
||||
scans[id].captureList = [];
|
||||
scans[id].metadata = {
|
||||
filename: custom.basename,
|
||||
time: custom.time,
|
||||
id: custom.scan_id
|
||||
};
|
||||
scans[id].metadata.tags = [];
|
||||
scans[id].metadata.custom = {};
|
||||
}
|
||||
|
||||
// Add the capture object to the scan
|
||||
scans[id].captureList.push(capture);
|
||||
|
||||
// Add missing scan metadata, prioritising first capture
|
||||
for (var key of Object.keys(custom)) {
|
||||
if (!(key in scans[id].metadata.custom)) {
|
||||
scans[id].metadata.custom[key] = custom[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Append missing tags
|
||||
for (var tag of tags) {
|
||||
if (!scans[id].metadata.tags.includes(tag)) {
|
||||
scans[id].metadata.tags.push(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a preview thumbnail
|
||||
if (!("thumbnail" in scans[id])) {
|
||||
scans[id].thumbnail =
|
||||
this.$store.getters.uri +
|
||||
"/camera/capture/" +
|
||||
capture.metadata.id +
|
||||
"/download?thumbnail=true";
|
||||
}
|
||||
}
|
||||
}
|
||||
return scans;
|
||||
},
|
||||
|
||||
scanList: function() {
|
||||
return Object.values(this.allScans);
|
||||
},
|
||||
|
||||
itemList: function() {
|
||||
if (this.galleryFolder) {
|
||||
console.log(this.allScans[this.galleryFolder].captureList);
|
||||
return this.allScans[this.galleryFolder].captureList;
|
||||
} else {
|
||||
return this.noScanCaptureList.concat(this.scanList);
|
||||
}
|
||||
},
|
||||
|
||||
filteredItems: function() {
|
||||
return this.filterCaptureList(this.itemList, this.checkedTags);
|
||||
},
|
||||
|
||||
sortedItems: function() {
|
||||
return this.sortCaptureList(this.filteredItems);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to perform a gallery refresh
|
||||
this.$root.$on('globalUpdateCaptureList', () => {
|
||||
this.updateCaptureList()
|
||||
})
|
||||
this.$root.$on("globalUpdateCaptureList", () => {
|
||||
this.updateCaptureList();
|
||||
});
|
||||
// A global signal listener to set the gallery folder
|
||||
this.$root.$on('globalUpdateCaptureFolder', (folder) => {
|
||||
this.galleryFolder = folder
|
||||
})
|
||||
this.$root.$on("globalUpdateCaptureFolder", folder => {
|
||||
this.galleryFolder = folder;
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateCaptureList: function() {
|
||||
console.log("Updating capture list...")
|
||||
console.log("Updating capture list...");
|
||||
// Send move request
|
||||
axios.get(this.captureApiUri)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateState'); // Update store state for good measure
|
||||
this.captureList = response.data; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.get(this.captureApiUri)
|
||||
.then(response => {
|
||||
this.$store.dispatch("updateState"); // Update store state for good measure
|
||||
this.captureList = response.data; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
filterCaptureList: function(list, filterTags) {
|
||||
|
|
@ -120,153 +267,33 @@ export default {
|
|||
// Add to capture list if matched
|
||||
if (includeCapture == true) {
|
||||
result.push(capture);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return result
|
||||
return result;
|
||||
},
|
||||
|
||||
sortCaptureList: function(list) {
|
||||
function compare(a, b) {
|
||||
if (a.metadata.time < b.metadata.time)
|
||||
return -1;
|
||||
if (a.metadata.time > b.metadata.time)
|
||||
return 1;
|
||||
if (a.metadata.time < b.metadata.time) return -1;
|
||||
if (a.metadata.time > b.metadata.time) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this.sortDescending == true) {
|
||||
return list.sort(compare).reverse();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return list.sort(compare);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
captureApiUri: function () {
|
||||
return this.$store.getters.uri + "/camera/capture"
|
||||
},
|
||||
|
||||
allTags: function () {
|
||||
// Return an array of unique tags across all captures
|
||||
var tags = [];
|
||||
for (var capture of this.captureList) {
|
||||
for (var tag of capture.metadata.tags) {
|
||||
if (!tags.includes(tag)) {
|
||||
tags.push(tag);
|
||||
};
|
||||
};
|
||||
};
|
||||
return tags.sort()
|
||||
},
|
||||
|
||||
noScanCaptureList: function () {
|
||||
var captures = [];
|
||||
for (var capture of this.captureList) {
|
||||
// Assume exclusion
|
||||
var includeCapture = false;
|
||||
|
||||
// Filter by selected tags
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
// Add to capture list if matched
|
||||
if (!tags.includes(this.scanTag)) {
|
||||
captures.push(capture);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return captures
|
||||
},
|
||||
|
||||
allScans: function () {
|
||||
// Return an array of unique tags across all captures
|
||||
var scans = {};
|
||||
|
||||
for (var capture of this.captureList) {
|
||||
var custom = capture.metadata.custom;
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
if ('scan_id' in custom) {
|
||||
var id = custom['scan_id']
|
||||
|
||||
// If this scan ID hasn't been seen before
|
||||
if (!(id in scans)) {
|
||||
scans[id] = {}
|
||||
scans[id].isScan = true
|
||||
scans[id].captureList = []
|
||||
scans[id].metadata = {
|
||||
filename: custom.basename,
|
||||
time: custom.time,
|
||||
id: custom.scan_id
|
||||
}
|
||||
scans[id].metadata.tags = []
|
||||
scans[id].metadata.custom = {}
|
||||
};
|
||||
|
||||
// Add the capture object to the scan
|
||||
scans[id].captureList.push(capture)
|
||||
|
||||
// Add missing scan metadata, prioritising first capture
|
||||
for (var key of Object.keys(custom)) {
|
||||
if (!(key in scans[id].metadata.custom)) {
|
||||
scans[id].metadata.custom[key] = custom[key]
|
||||
};
|
||||
};
|
||||
|
||||
// Append missing tags
|
||||
for (var tag of tags) {
|
||||
if (!scans[id].metadata.tags.includes(tag)) {
|
||||
scans[id].metadata.tags.push(tag)
|
||||
};
|
||||
};
|
||||
|
||||
// Create a preview thumbnail
|
||||
if (!('thumbnail' in scans[id])) {
|
||||
scans[id].thumbnail = this.$store.getters.uri + "/camera/capture/" + capture.metadata.id + "/download?thumbnail=true"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
return scans
|
||||
},
|
||||
|
||||
scanList: function () {
|
||||
return Object.values(this.allScans)
|
||||
},
|
||||
|
||||
itemList: function () {
|
||||
if (this.galleryFolder) {
|
||||
console.log(this.allScans[this.galleryFolder].captureList)
|
||||
return this.allScans[this.galleryFolder].captureList
|
||||
}
|
||||
else {
|
||||
return this.noScanCaptureList.concat(this.scanList)
|
||||
}
|
||||
},
|
||||
|
||||
filteredItems: function () {
|
||||
return this.filterCaptureList(this.itemList, this.checkedTags)
|
||||
},
|
||||
|
||||
sortedItems: function () {
|
||||
return this.sortCaptureList(this.filteredItems)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.navbar {
|
||||
border-width: 0 0 1px 0;
|
||||
border-style: solid;
|
||||
border-color: rgba(180, 180, 180, 0.25)
|
||||
border-color: rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,221 +1,246 @@
|
|||
<template>
|
||||
<div ref="streamDisplay" class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget" id="stream-display">
|
||||
<div
|
||||
id="stream-display"
|
||||
ref="streamDisplay"
|
||||
class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget"
|
||||
>
|
||||
<img
|
||||
ref="click-frame"
|
||||
class="uk-align-center uk-margin-remove-bottom"
|
||||
:hidden="!showStream"
|
||||
:src="streamImgUri"
|
||||
alt="Stream"
|
||||
@dblclick="clickMonitor"
|
||||
/>
|
||||
|
||||
<img class="uk-align-center uk-margin-remove-bottom" v-on:dblclick="clickMonitor" v-bind:hidden="!showStream" v-bind:src="streamImgUri" alt="Stream" ref="click-frame">
|
||||
<div v-if="!showStream">
|
||||
<div v-if="$store.state.waiting" class="uk-position-center">
|
||||
<div uk-spinner="ratio: 4.5"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="!showStream">
|
||||
<div v-if="$store.state.waiting" class="uk-position-center">
|
||||
<div uk-spinner="ratio: 4.5" ></div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="$store.state.globalSettings.disableStream"
|
||||
class="uk-position-center position-relative text-center"
|
||||
>
|
||||
Stream preview disabled
|
||||
</div>
|
||||
|
||||
<div v-else-if="$store.state.globalSettings.disableStream" class="uk-position-center position-relative text-center">
|
||||
Stream preview disabled
|
||||
</div>
|
||||
|
||||
<div v-else class="uk-position-center position-relative text-center">
|
||||
No active connection
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-else class="uk-position-center position-relative text-center">
|
||||
No active connection
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'stream-display',
|
||||
name: "StreamDisplay",
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
displaySize: [0, 0],
|
||||
displayPosition: [0, 0],
|
||||
GpuPreviewActive: false,
|
||||
resizeTimeoutId: setTimeout(this.doneResizing, 500)
|
||||
displaySize: [0, 0],
|
||||
displayPosition: [0, 0],
|
||||
GpuPreviewActive: false,
|
||||
resizeTimeoutId: setTimeout(this.doneResizing, 500)
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
showStream: function() {
|
||||
return (
|
||||
this.$store.getters.ready &&
|
||||
!this.$store.state.globalSettings.disableStream
|
||||
);
|
||||
},
|
||||
streamImgUri: function() {
|
||||
return this.$store.getters.uri + "/stream";
|
||||
},
|
||||
startPreviewUri: function() {
|
||||
return this.$store.getters.uri + "/camera/preview/start";
|
||||
},
|
||||
stopPreviewUri: function() {
|
||||
return this.$store.getters.uri + "/camera/preview/stop";
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to change the GPU preview state
|
||||
this.$root.$on('globalTogglePreview', (state) => {
|
||||
console.log(`Toggling preview to ${state}`)
|
||||
this.previewRequest(state)
|
||||
})
|
||||
this.$root.$on("globalTogglePreview", state => {
|
||||
console.log(`Toggling preview to ${state}`);
|
||||
this.previewRequest(state);
|
||||
});
|
||||
// A global signal listener to flash the stream element
|
||||
this.$root.$on('globalFlashStream', (state) => {
|
||||
this.flashStream()
|
||||
})
|
||||
this.$root.$on("globalFlashStream", () => {
|
||||
this.flashStream();
|
||||
});
|
||||
|
||||
// Mutation observer
|
||||
this.sizeObserver = new ResizeObserver(entries => {
|
||||
this.handleResize() // For any element attached to the observer, run handleResize() on change
|
||||
entries.forEach(entry => {}) // Optional: Run something per entry
|
||||
});
|
||||
// Fetch streamDisplay by ref
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
// Mutation observer
|
||||
this.sizeObserver = new ResizeObserver(() => {
|
||||
this.handleResize(); // For any element attached to the observer, run handleResize() on change
|
||||
});
|
||||
// Fetch streamDisplay by ref
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
},
|
||||
|
||||
},
|
||||
created: function() {
|
||||
// Watch for host 'ready'
|
||||
this.$store.watch(
|
||||
(state, getters) => {
|
||||
return getters.ready;
|
||||
},
|
||||
(newValue, oldValue) => {
|
||||
// 'ready' changed, so do something
|
||||
console.log(`Updating from ${oldValue} to ${newValue}`);
|
||||
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
created: function () {
|
||||
// Watch for host 'ready'
|
||||
this.$store.watch(
|
||||
(state)=>{
|
||||
return this.$store.getters.ready
|
||||
},
|
||||
(newValue, oldValue)=>{
|
||||
// 'ready' changed, so do something
|
||||
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
beforeDestroy: function () {
|
||||
// Disconnect the size observer
|
||||
this.sizeObserver.disconnect()
|
||||
},
|
||||
beforeDestroy: function() {
|
||||
// Disconnect the size observer
|
||||
this.sizeObserver.disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
clickMonitor: function(event) {
|
||||
// Calculate steps from event coordinates and store config FOV
|
||||
let xCoordinate = event.offsetX;
|
||||
let yCoordinate = event.offsetY;
|
||||
// Calculate steps from event coordinates and store config FOV
|
||||
let xCoordinate = event.offsetX;
|
||||
let yCoordinate = event.offsetY;
|
||||
|
||||
let xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
||||
let yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
||||
let xRelative =
|
||||
(0.5 * event.target.offsetWidth - xCoordinate) /
|
||||
event.target.offsetWidth;
|
||||
let yRelative =
|
||||
(0.5 * event.target.offsetHeight - yCoordinate) /
|
||||
event.target.offsetHeight;
|
||||
|
||||
let xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
||||
let ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
||||
let xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
||||
let ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
||||
|
||||
// Emit a signal to move, acted on by panelNavigate.vue
|
||||
this.$root.$emit('globalMoveEvent', xSteps, ySteps, 0, false)
|
||||
},
|
||||
|
||||
flashStream: function() {
|
||||
let element = this.$refs.streamDisplay
|
||||
element.classList.remove("uk-animation-fade");
|
||||
element.offsetHeight; /* trigger reflow */
|
||||
element.classList.add("uk-animation-fade");
|
||||
},
|
||||
|
||||
handleResize: function(event) {
|
||||
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
||||
clearTimeout(this.resizeTimeoutId);
|
||||
this.resizeTimeoutId = setTimeout(this.handleDoneResize, 250)
|
||||
},
|
||||
|
||||
handleDoneResize: function() {
|
||||
// Recalculate size
|
||||
console.log("Recalculating frame size")
|
||||
this.recalculateSize();
|
||||
if (this.$store.state.globalSettings.autoGpuPreview == true && this.GpuPreviewActive == true) {
|
||||
// Reload preview
|
||||
this.$root.$emit('globalTogglePreview', true)
|
||||
}
|
||||
},
|
||||
|
||||
recalculateSize: function () {
|
||||
let element = this.$refs.streamDisplay.parentNode;
|
||||
let bound = element.getBoundingClientRect()
|
||||
|
||||
let elementSize = [bound.width, bound.height]
|
||||
|
||||
let elementPositionOnWindow = [bound.left, bound.top]
|
||||
let windowPositionOnDisplay = [window.screenX, window.screenY]
|
||||
let windowChromeHeight = window.outerHeight - window.innerHeight
|
||||
let elementPositionOnDisplay = [
|
||||
Math.max(0, windowPositionOnDisplay[0] + elementPositionOnWindow[0]),
|
||||
Math.max(0, windowPositionOnDisplay[1] + elementPositionOnWindow[1] + windowChromeHeight)
|
||||
]
|
||||
|
||||
this.displaySize = elementSize
|
||||
this.displayPosition = elementPositionOnDisplay
|
||||
|
||||
console.log(`Size: ${this.displaySize}`)
|
||||
console.log(`Position: ${this.displayPosition}`)
|
||||
},
|
||||
|
||||
previewRequest: function(state) {
|
||||
if (this.$store.getters.ready == true) {
|
||||
// Create URI and set this.GpuPreviewActive depending on if starting or stopping preview
|
||||
if (state == true) {
|
||||
this.GpuPreviewActive = true
|
||||
var requestUri = this.startPreviewUri;
|
||||
}
|
||||
else {
|
||||
this.GpuPreviewActive = false;
|
||||
var requestUri = this.stopPreviewUri;
|
||||
}
|
||||
|
||||
// Generate payload if tracking window position
|
||||
if (this.$store.state.globalSettings.trackWindow == true && state == true) {
|
||||
// Recalculate frame dimensions and position
|
||||
this.recalculateSize()
|
||||
// Copy data into payload array
|
||||
var payload = {
|
||||
window : [
|
||||
this.displayPosition[0],
|
||||
this.displayPosition[1],
|
||||
this.displaySize[0],
|
||||
this.displaySize[1],
|
||||
]
|
||||
}
|
||||
}
|
||||
else {
|
||||
var payload = {}
|
||||
}
|
||||
|
||||
// Send preview request
|
||||
axios.post(requestUri, payload)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateState'); // Update store state
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
}
|
||||
// Emit a signal to move, acted on by panelNavigate.vue
|
||||
this.$root.$emit("globalMoveEvent", xSteps, ySteps, 0, false);
|
||||
},
|
||||
|
||||
},
|
||||
flashStream: function() {
|
||||
let element = this.$refs.streamDisplay;
|
||||
element.classList.remove("uk-animation-fade");
|
||||
element.offsetHeight; /* trigger reflow */
|
||||
element.classList.add("uk-animation-fade");
|
||||
},
|
||||
|
||||
computed: {
|
||||
showStream: function () {
|
||||
return this.$store.getters.ready && !this.$store.state.globalSettings.disableStream
|
||||
},
|
||||
streamImgUri: function () {
|
||||
return this.$store.getters.uri + "/stream"
|
||||
},
|
||||
startPreviewUri: function () {
|
||||
return this.$store.getters.uri + "/camera/preview/start"
|
||||
},
|
||||
stopPreviewUri: function () {
|
||||
return this.$store.getters.uri + "/camera/preview/stop"
|
||||
}
|
||||
}
|
||||
handleResize: function() {
|
||||
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
||||
clearTimeout(this.resizeTimeoutId);
|
||||
this.resizeTimeoutId = setTimeout(this.handleDoneResize, 250);
|
||||
},
|
||||
|
||||
}
|
||||
handleDoneResize: function() {
|
||||
// Recalculate size
|
||||
console.log("Recalculating frame size");
|
||||
this.recalculateSize();
|
||||
if (
|
||||
this.$store.state.globalSettings.autoGpuPreview == true &&
|
||||
this.GpuPreviewActive == true
|
||||
) {
|
||||
// Reload preview
|
||||
this.$root.$emit("globalTogglePreview", true);
|
||||
}
|
||||
},
|
||||
|
||||
recalculateSize: function() {
|
||||
let element = this.$refs.streamDisplay.parentNode;
|
||||
let bound = element.getBoundingClientRect();
|
||||
|
||||
let elementSize = [bound.width, bound.height];
|
||||
|
||||
let elementPositionOnWindow = [bound.left, bound.top];
|
||||
let windowPositionOnDisplay = [window.screenX, window.screenY];
|
||||
let windowChromeHeight = window.outerHeight - window.innerHeight;
|
||||
let elementPositionOnDisplay = [
|
||||
Math.max(0, windowPositionOnDisplay[0] + elementPositionOnWindow[0]),
|
||||
Math.max(
|
||||
0,
|
||||
windowPositionOnDisplay[1] +
|
||||
elementPositionOnWindow[1] +
|
||||
windowChromeHeight
|
||||
)
|
||||
];
|
||||
|
||||
this.displaySize = elementSize;
|
||||
this.displayPosition = elementPositionOnDisplay;
|
||||
|
||||
console.log(`Size: ${this.displaySize}`);
|
||||
console.log(`Position: ${this.displayPosition}`);
|
||||
},
|
||||
|
||||
previewRequest: function(state) {
|
||||
if (this.$store.getters.ready == true) {
|
||||
var requestUri = null;
|
||||
// Create URI and set this.GpuPreviewActive depending on if starting or stopping preview
|
||||
if (state == true) {
|
||||
this.GpuPreviewActive = true;
|
||||
requestUri = this.startPreviewUri;
|
||||
} else {
|
||||
this.GpuPreviewActive = false;
|
||||
requestUri = this.stopPreviewUri;
|
||||
}
|
||||
|
||||
// Generate payload if tracking window position
|
||||
var payload = {};
|
||||
if (
|
||||
this.$store.state.globalSettings.trackWindow == true &&
|
||||
state == true
|
||||
) {
|
||||
// Recalculate frame dimensions and position
|
||||
this.recalculateSize();
|
||||
// Copy data into payload array
|
||||
payload = {
|
||||
window: [
|
||||
this.displayPosition[0],
|
||||
this.displayPosition[1],
|
||||
this.displaySize[0],
|
||||
this.displaySize[1]
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Send preview request
|
||||
axios
|
||||
.post(requestUri, payload)
|
||||
.then(() => {
|
||||
this.$store.dispatch("updateState"); // Update store state
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.stream-display img {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
object-fit: contain
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.stream-display {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.position-relative {
|
||||
position: relative !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// Load settings store from main process
|
||||
const { store } = require('electron').remote.require('./store')
|
||||
const { store } = require("electron").remote.require("./store");
|
||||
|
||||
// Load extra modules we'll be using
|
||||
const { Titlebar, Color } = require('custom-electron-titlebar');
|
||||
const { Titlebar, Color } = require("custom-electron-titlebar");
|
||||
|
||||
// Only show custom menubar if current window has no frame
|
||||
if (store.get('drawCustomTitleBar') == true) {
|
||||
new Titlebar({
|
||||
backgroundColor: Color.fromHex('#c5247f'),
|
||||
icon: './titleicon.svg'
|
||||
});
|
||||
if (store.get("drawCustomTitleBar") == true) {
|
||||
new Titlebar({
|
||||
backgroundColor: Color.fromHex("#c5247f"),
|
||||
icon: "./titleicon.svg"
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Loaded main.app.js for electron-renderer functionality")
|
||||
console.log("Loaded main.app.js for electron-renderer functionality");
|
||||
|
|
|
|||
109
src/main.js
109
src/main.js
|
|
@ -1,43 +1,50 @@
|
|||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './store'
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import store from "./store";
|
||||
|
||||
import UIkit from 'uikit';
|
||||
import UIkit from "uikit";
|
||||
|
||||
// Import MD icons
|
||||
import 'material-design-icons/iconfont/material-icons.css'
|
||||
import "material-design-icons/iconfont/material-icons.css";
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
modalConfirm: function(modalText) {
|
||||
var context = this
|
||||
var context = this;
|
||||
|
||||
// Stop GPU preview to show modal
|
||||
context.$root.$emit('globalTogglePreview', false)
|
||||
|
||||
context.$root.$emit("globalTogglePreview", false);
|
||||
|
||||
var showModal = function(resolve, reject) {
|
||||
UIkit.modal.confirm(modalText)
|
||||
.then(function() {
|
||||
resolve()
|
||||
}, function () {
|
||||
reject()
|
||||
})
|
||||
.finally(function() {
|
||||
// Reenable the GPU preview, if it was active before the modal
|
||||
console.log("Re-enabling GPU preview")
|
||||
if (context.$store.state.globalSettings.autoGpuPreview) {
|
||||
console.log("Re-enabling preview")
|
||||
context.$root.$emit('globalTogglePreview', true)
|
||||
}
|
||||
})
|
||||
}
|
||||
return new Promise(showModal)
|
||||
UIkit.modal
|
||||
.confirm(modalText)
|
||||
.then(
|
||||
function() {
|
||||
resolve();
|
||||
},
|
||||
function() {
|
||||
reject();
|
||||
}
|
||||
)
|
||||
.finally(function() {
|
||||
// Reenable the GPU preview, if it was active before the modal
|
||||
console.log("Re-enabling GPU preview");
|
||||
if (context.$store.state.globalSettings.autoGpuPreview) {
|
||||
console.log("Re-enabling preview");
|
||||
context.$root.$emit("globalTogglePreview", true);
|
||||
}
|
||||
});
|
||||
};
|
||||
return new Promise(showModal);
|
||||
},
|
||||
|
||||
modalNotify: function(message, status = 'success') {
|
||||
UIkit.notification({message: message, status: status})
|
||||
modalNotify: function(message, status = "success") {
|
||||
UIkit.notification({
|
||||
message: message,
|
||||
status: status
|
||||
});
|
||||
},
|
||||
|
||||
modalDialog: function(title, message) {
|
||||
|
|
@ -53,55 +60,57 @@ Vue.mixin({
|
|||
},
|
||||
|
||||
modalError: function(error) {
|
||||
console.log(error)
|
||||
var errormsg = ''
|
||||
console.log(error);
|
||||
var errormsg = "";
|
||||
|
||||
// If a response was obtained
|
||||
if (error.response) {
|
||||
// If the response is a nicely formatted JSON response from the server
|
||||
if (error.response.data.message) {
|
||||
errormsg = `${error.response.status}: ${error.response.data.message}`
|
||||
console.log(errormsg)
|
||||
errormsg = `${error.response.status}: ${error.response.data.message}`;
|
||||
console.log(errormsg);
|
||||
}
|
||||
// If the response is just some generic error response
|
||||
else {
|
||||
errormsg = `${error.response.status}: ${error.response.data}`
|
||||
console.log(errormsg)
|
||||
errormsg = `${error.response.status}: ${error.response.data}`;
|
||||
console.log(errormsg);
|
||||
}
|
||||
// If the error occured during the request
|
||||
// If the error occured during the request
|
||||
} else if (error.request) {
|
||||
errormsg = `${error.message}`
|
||||
console.log(errormsg)
|
||||
// Everything else
|
||||
errormsg = `${error.message}`;
|
||||
console.log(errormsg);
|
||||
// Everything else
|
||||
} else {
|
||||
errormsg = `${error.message}`
|
||||
console.log(errormsg)
|
||||
errormsg = `${error.message}`;
|
||||
console.log(errormsg);
|
||||
}
|
||||
this.$store.commit('setError', errormsg);
|
||||
UIkit.notification({message: `${errormsg}`, status: 'danger'})
|
||||
this.$store.commit("setError", errormsg);
|
||||
UIkit.notification({
|
||||
message: `${errormsg}`,
|
||||
status: "danger"
|
||||
});
|
||||
},
|
||||
|
||||
getLocalStorageObj: function(keyName) {
|
||||
if (localStorage.getItem(keyName)) {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(keyName))
|
||||
} catch(e) {
|
||||
console.log("Malformed entry. Removing from localStorage")
|
||||
localStorage.removeItem(keyName)
|
||||
return null
|
||||
return JSON.parse(localStorage.getItem(keyName));
|
||||
} catch (e) {
|
||||
console.log("Malformed entry. Removing from localStorage");
|
||||
localStorage.removeItem(keyName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setLocalStorageObj: function(keyName, object) {
|
||||
const parsed = JSON.stringify(object)
|
||||
const parsed = JSON.stringify(object);
|
||||
localStorage.setItem(keyName, parsed);
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
new Vue({
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
}).$mount("#app");
|
||||
|
|
|
|||
|
|
@ -1,20 +1,32 @@
|
|||
function isElectron() {
|
||||
// Renderer process
|
||||
if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {
|
||||
return true;
|
||||
}
|
||||
// Renderer process
|
||||
if (
|
||||
typeof window !== "undefined" &&
|
||||
typeof window.process === "object" &&
|
||||
window.process.type === "renderer"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main process
|
||||
if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {
|
||||
return true;
|
||||
}
|
||||
// Main process
|
||||
if (
|
||||
typeof process !== "undefined" &&
|
||||
typeof process.versions === "object" &&
|
||||
!!process.versions.electron
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Detect the user agent when the `nodeIntegration` option is set to true
|
||||
if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
|
||||
return true;
|
||||
}
|
||||
// Detect the user agent when the `nodeIntegration` option is set to true
|
||||
if (
|
||||
typeof navigator === "object" &&
|
||||
typeof navigator.userAgent === "string" &&
|
||||
navigator.userAgent.indexOf("Electron") >= 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
export default isElectron;
|
||||
export default isElectron;
|
||||
|
|
|
|||
218
src/store.js
218
src/store.js
|
|
@ -1,18 +1,17 @@
|
|||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import axios from 'axios'
|
||||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import axios from "axios";
|
||||
|
||||
Vue.use(Vuex)
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
|
||||
state: {
|
||||
host: '',
|
||||
host: "",
|
||||
port: 5000,
|
||||
apiVer: 'v1',
|
||||
apiVer: "v1",
|
||||
available: true,
|
||||
waiting: false,
|
||||
error: '',
|
||||
error: "",
|
||||
apiConfig: {},
|
||||
apiState: {},
|
||||
apiPlugins: [],
|
||||
|
|
@ -25,13 +24,13 @@ export default new Vuex.Store({
|
|||
},
|
||||
|
||||
mutations: {
|
||||
changeHost(state, [host, port, apiVer='v1']) {
|
||||
changeHost(state, [host, port, apiVer = "v1"]) {
|
||||
state.host = host;
|
||||
state.port = port;
|
||||
state.apiVer = apiVer;
|
||||
},
|
||||
changeWaiting(state, waiting) {
|
||||
state.waiting = waiting
|
||||
state.waiting = waiting;
|
||||
},
|
||||
commitConfig(state, configData) {
|
||||
state.apiConfig = configData;
|
||||
|
|
@ -46,155 +45,158 @@ export default new Vuex.Store({
|
|||
state.globalSettings[key] = value;
|
||||
},
|
||||
resetState(state) {
|
||||
state.waiting = false
|
||||
state.available = true
|
||||
state.error = null
|
||||
state.apiConfig = {}
|
||||
state.apiState = {}
|
||||
state.apiPlugins = []
|
||||
state.waiting = false;
|
||||
state.available = true;
|
||||
state.error = null;
|
||||
state.apiConfig = {};
|
||||
state.apiState = {};
|
||||
state.apiPlugins = [];
|
||||
},
|
||||
setConnected(state) {
|
||||
state.waiting = false
|
||||
state.available = true
|
||||
state.waiting = false;
|
||||
state.available = true;
|
||||
},
|
||||
setError(state, msg) {
|
||||
state.waiting = false
|
||||
state.available = false
|
||||
state.error = msg
|
||||
state.waiting = false;
|
||||
state.available = false;
|
||||
state.error = msg;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
firstConnect(context) {
|
||||
// Reset the state when reconnecting starts
|
||||
context.commit('resetState')
|
||||
context.commit("resetState");
|
||||
// Mark as loading
|
||||
context.commit('changeWaiting', true)
|
||||
context.commit("changeWaiting", true);
|
||||
|
||||
var sendRequest = function(resolve, reject) {
|
||||
// Do requests
|
||||
context.dispatch('updateConfig')
|
||||
.then (() => context.dispatch('updateState'))
|
||||
.then (() => context.dispatch('updatePlugins'))
|
||||
.then (() => {
|
||||
console.log("Finished first connect")
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
}
|
||||
return new Promise(sendRequest)
|
||||
context
|
||||
.dispatch("updateConfig")
|
||||
.then(() => context.dispatch("updateState"))
|
||||
.then(() => context.dispatch("updatePlugins"))
|
||||
.then(() => {
|
||||
console.log("Finished first connect");
|
||||
resolve();
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
};
|
||||
return new Promise(sendRequest);
|
||||
},
|
||||
|
||||
updateConfig(context, uri=`${context.getters.uri}/config`) {
|
||||
console.log("Updating config")
|
||||
context.commit('changeWaiting', true)
|
||||
|
||||
updateConfig(context, uri = `${context.getters.uri}/config`) {
|
||||
console.log("Updating config");
|
||||
context.commit("changeWaiting", true);
|
||||
|
||||
var sendRequest = function(resolve, reject) {
|
||||
axios.get(uri)
|
||||
.then(response => {
|
||||
context.commit('commitConfig', response.data)
|
||||
context.commit('setConnected')
|
||||
console.log("Updating config finished")
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error))
|
||||
})
|
||||
}
|
||||
return new Promise(sendRequest)
|
||||
axios
|
||||
.get(uri)
|
||||
.then(response => {
|
||||
context.commit("commitConfig", response.data);
|
||||
context.commit("setConnected");
|
||||
console.log("Updating config finished");
|
||||
resolve();
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error));
|
||||
});
|
||||
};
|
||||
return new Promise(sendRequest);
|
||||
},
|
||||
|
||||
updateState(context, uri=`${context.getters.uri}/state`) {
|
||||
console.log("Updating state")
|
||||
context.commit('changeWaiting', true)
|
||||
|
||||
updateState(context, uri = `${context.getters.uri}/state`) {
|
||||
console.log("Updating state");
|
||||
context.commit("changeWaiting", true);
|
||||
|
||||
var sendRequest = function(resolve, reject) {
|
||||
axios.get(uri)
|
||||
.then(response => {
|
||||
context.commit('commitState', response.data)
|
||||
context.commit('setConnected')
|
||||
console.log("Updating state finished")
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error))
|
||||
})
|
||||
}
|
||||
return new Promise(sendRequest)
|
||||
axios
|
||||
.get(uri)
|
||||
.then(response => {
|
||||
context.commit("commitState", response.data);
|
||||
context.commit("setConnected");
|
||||
console.log("Updating state finished");
|
||||
resolve();
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error));
|
||||
});
|
||||
};
|
||||
return new Promise(sendRequest);
|
||||
},
|
||||
|
||||
updatePlugins(context, uri=`${context.getters.uri}/plugin`) {
|
||||
console.log("Updating plugins")
|
||||
context.commit('changeWaiting', true)
|
||||
|
||||
updatePlugins(context, uri = `${context.getters.uri}/plugin`) {
|
||||
console.log("Updating plugins");
|
||||
context.commit("changeWaiting", true);
|
||||
|
||||
var sendRequest = function(resolve, reject) {
|
||||
axios.get(uri)
|
||||
.then(response => {
|
||||
console.log("PLUGINS")
|
||||
console.log(response.data)
|
||||
context.commit('commitPlugins', response.data)
|
||||
context.commit('setConnected')
|
||||
console.log("Updating plugins finished")
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error))
|
||||
})
|
||||
}
|
||||
return new Promise(sendRequest)
|
||||
axios
|
||||
.get(uri)
|
||||
.then(response => {
|
||||
console.log("PLUGINS");
|
||||
console.log(response.data);
|
||||
context.commit("commitPlugins", response.data);
|
||||
context.commit("setConnected");
|
||||
console.log("Updating plugins finished");
|
||||
resolve();
|
||||
})
|
||||
.catch(error => {
|
||||
reject(new Error(error));
|
||||
});
|
||||
};
|
||||
return new Promise(sendRequest);
|
||||
},
|
||||
|
||||
pollTask(context, [taskId, timeout, interval]) {
|
||||
var endTime = Number(new Date()) + (timeout*1000 || 30000);
|
||||
interval = interval*1000 || 500;
|
||||
var endTime = Number(new Date()) + (timeout * 1000 || 30000);
|
||||
interval = interval * 1000 || 500;
|
||||
|
||||
var checkCondition = function(resolve, reject) {
|
||||
// If the condition is met, we're done!
|
||||
axios.get(`${context.getters.uri}/task/${taskId}`)
|
||||
.then(response => {
|
||||
console.log(response.data.status)
|
||||
var result = response.data.status
|
||||
// If the condition is met, we're done!
|
||||
axios.get(`${context.getters.uri}/task/${taskId}`).then(response => {
|
||||
console.log(response.data.status);
|
||||
var result = response.data.status;
|
||||
// If the task ends with success
|
||||
if(result == 'success') {
|
||||
resolve(response.data)
|
||||
if (result == "success") {
|
||||
resolve(response.data);
|
||||
}
|
||||
// If task ends with an error
|
||||
else if (result == 'error') {
|
||||
else if (result == "error") {
|
||||
// Pass the error string back with reject
|
||||
reject(new Error(response.data.return))
|
||||
reject(new Error(response.data.return));
|
||||
}
|
||||
// If task ends with termination
|
||||
else if (result == 'terminated') {
|
||||
else if (result == "terminated") {
|
||||
// Pass a generic termination error back with reject
|
||||
reject(new Error("Task terminated"))
|
||||
reject(new Error("Task terminated"));
|
||||
}
|
||||
// If task ends in any other way
|
||||
else if (result != 'running') {
|
||||
else if (result != "running") {
|
||||
// Pass status string as error
|
||||
reject(new Error(result))
|
||||
reject(new Error(result));
|
||||
}
|
||||
// If the condition isn't met but the timeout hasn't elapsed, go again
|
||||
else if (Number(new Date()) < endTime) {
|
||||
setTimeout(checkCondition, interval, resolve, reject)
|
||||
setTimeout(checkCondition, interval, resolve, reject);
|
||||
}
|
||||
// Didn't match and too much time, reject!
|
||||
else {
|
||||
reject(new Error('Polling timed out'))
|
||||
reject(new Error("Polling timed out"));
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(checkCondition);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
uri: state => `http://${state.host}:${state.port}/api/${state.apiVer}`,
|
||||
ready: state => ((state.available) && (Object.keys(state.apiConfig).length !== 0) && (Object.keys(state.apiState).length !== 0))
|
||||
ready: state =>
|
||||
state.available &&
|
||||
Object.keys(state.apiConfig).length !== 0 &&
|
||||
Object.keys(state.apiState).length !== 0
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue