Merge branch 'master' into 'stable'
v1.1.0 See merge request openflexure/openflexure-microscope-jsclient!34
This commit is contained in:
commit
be881c482e
48 changed files with 2437 additions and 897 deletions
3
.env.development.web
Normal file
3
.env.development.web
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
NODE_ENV=development
|
||||||
|
VUE_APP_PLATFORM=web
|
||||||
|
VUE_APP_TARGET=web
|
||||||
3
.env.production.app
Normal file
3
.env.production.app
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_PLATFORM=web
|
||||||
|
VUE_APP_TARGET=electron-renderer
|
||||||
3
.env.production.web
Normal file
3
.env.production.web
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_PLATFORM=web
|
||||||
|
VUE_APP_TARGET=web
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
|
/app/dist
|
||||||
/release-builds
|
/release-builds
|
||||||
/installers/release-builds
|
/installers/release-builds
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
- package
|
|
||||||
- meta
|
- meta
|
||||||
|
|
||||||
# Cache modules in between jobs
|
# Cache modules in between jobs
|
||||||
|
|
@ -9,13 +8,13 @@ cache:
|
||||||
paths:
|
paths:
|
||||||
- node_modules/
|
- node_modules/
|
||||||
|
|
||||||
# Build basic webapp
|
# Basic webapp build
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
image: electronuserland/builder:wine
|
image: electronuserland/builder:wine
|
||||||
script:
|
script:
|
||||||
- npm install
|
- npm install
|
||||||
- npm run build
|
- npm run build:web
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "build"
|
name: "build"
|
||||||
paths:
|
paths:
|
||||||
|
|
@ -25,20 +24,20 @@ build:
|
||||||
- tags
|
- tags
|
||||||
- web
|
- web
|
||||||
|
|
||||||
# Platform-specific Electron builds
|
# Electron app build
|
||||||
package:
|
package:
|
||||||
stage: package
|
stage: build
|
||||||
dependencies:
|
|
||||||
- build
|
|
||||||
image: electronuserland/builder:wine
|
image: electronuserland/builder:wine
|
||||||
retry: 2
|
|
||||||
script:
|
script:
|
||||||
|
- npm install
|
||||||
|
- npm run build:app
|
||||||
- npm run release
|
- npm run release
|
||||||
|
- shopt -s extglob
|
||||||
- mv ./release-builds/*.AppImage .
|
- mv ./release-builds/*.AppImage .
|
||||||
- mv ./release-builds/*.deb .
|
- mv ./release-builds/*.deb .
|
||||||
- mv ./release-builds/*.exe .
|
- mv ./release-builds/*.exe .
|
||||||
- mv ./release-builds/*.exe.blockmap .
|
- mv ./release-builds/*.exe.blockmap .
|
||||||
- mv ./release-builds/latest*.yml .
|
- mv ./release-builds/?(beta*.yml|latest*.yml) .
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "dist"
|
name: "dist"
|
||||||
paths:
|
paths:
|
||||||
|
|
@ -47,6 +46,7 @@ package:
|
||||||
- "*.exe"
|
- "*.exe"
|
||||||
- "*.exe.blockmap"
|
- "*.exe.blockmap"
|
||||||
- "latest*.yml"
|
- "latest*.yml"
|
||||||
|
- "beta*.yml"
|
||||||
only:
|
only:
|
||||||
- stable
|
- stable
|
||||||
- tags
|
- tags
|
||||||
|
|
@ -74,6 +74,4 @@ meta:choco:
|
||||||
- tools/chocolateyInstall.ps1
|
- tools/chocolateyInstall.ps1
|
||||||
- ./*.nupkg
|
- ./*.nupkg
|
||||||
only:
|
only:
|
||||||
- stable
|
|
||||||
- tags
|
- tags
|
||||||
- web
|
|
||||||
|
|
|
||||||
55
app/app.js
55
app/app.js
|
|
@ -6,6 +6,9 @@ const autoUpdater = updater.autoUpdater;
|
||||||
const contextMenu = require('electron-context-menu')
|
const contextMenu = require('electron-context-menu')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
|
// Attach settings store
|
||||||
|
const { store } = require('./store')
|
||||||
|
|
||||||
// Auto upadater
|
// Auto upadater
|
||||||
autoUpdater.autoDownload = false;
|
autoUpdater.autoDownload = false;
|
||||||
|
|
||||||
|
|
@ -14,9 +17,7 @@ autoUpdater.setFeedURL({
|
||||||
url: "https://gitlab.com/openflexure/openflexure-microscope-jsclient/-/jobs/artifacts/stable/raw?job=package"
|
url: "https://gitlab.com/openflexure/openflexure-microscope-jsclient/-/jobs/artifacts/stable/raw?job=package"
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('checking-for-update', function () {
|
autoUpdater.on('checking-for-update', function () {});
|
||||||
sendStatusToWindow('Checking for update...');
|
|
||||||
});
|
|
||||||
|
|
||||||
autoUpdater.on('update-available', function (info) {
|
autoUpdater.on('update-available', function (info) {
|
||||||
sendStatusToWindow('Update available.' + info)
|
sendStatusToWindow('Update available.' + info)
|
||||||
|
|
@ -70,56 +71,76 @@ const app = electron.app
|
||||||
const BrowserWindow = electron.BrowserWindow
|
const BrowserWindow = electron.BrowserWindow
|
||||||
|
|
||||||
// Set the window content
|
// Set the window content
|
||||||
let url = `file://${path.join(__dirname, '../dist/index.html')}`
|
let url = `file://${path.join(__dirname, '/dist/index.html')}`
|
||||||
let mainWindow
|
let mainWindow
|
||||||
|
|
||||||
// Set the application menu
|
// Set the application menu
|
||||||
require('./menu.js')
|
require('./menu.js')
|
||||||
|
|
||||||
|
// Handle redrawing the mainWindow
|
||||||
|
let recreatingWindowInProgress = false;
|
||||||
|
|
||||||
|
function toggleCustomTitleBar () {
|
||||||
|
// Mark window as being recreated, to prevent stopping the application
|
||||||
|
recreatingWindowInProgress = true
|
||||||
|
|
||||||
|
// Invert the drawCustomTitleBar setting
|
||||||
|
store.set('drawCustomTitleBar', !store.get('drawCustomTitleBar'))
|
||||||
|
|
||||||
|
// Destroy old window
|
||||||
|
mainWindow.destroy()
|
||||||
|
// Create new window
|
||||||
|
createWindow()
|
||||||
|
|
||||||
|
// Mark window as no longer being recreated
|
||||||
|
recreatingWindowInProgress = false
|
||||||
|
}
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
|
frame: !store.get('drawCustomTitleBar'),
|
||||||
width: 1124,
|
width: 1124,
|
||||||
height: 800,
|
height: 800,
|
||||||
icon: path.join(__dirname, '/icons/png/64x64.png')
|
icon: path.join(__dirname, '/icons/png/64x64.png')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Make a context menu
|
||||||
contextMenu({
|
contextMenu({
|
||||||
showCopyImageAddress: true,
|
showCopyImageAddress: true,
|
||||||
showSaveImageAs: true,
|
showSaveImageAs: true,
|
||||||
showInspectElement: false,
|
showInspectElement: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load window contents
|
||||||
mainWindow.loadURL(url)
|
mainWindow.loadURL(url)
|
||||||
|
|
||||||
|
// Check for updates
|
||||||
autoUpdater.checkForUpdates();
|
autoUpdater.checkForUpdates();
|
||||||
|
|
||||||
// Emitted when the window is closed.
|
// Emitted when the window is closed.
|
||||||
mainWindow.on('closed', function() {
|
mainWindow.on('closed', function() {
|
||||||
// Dereference the window object, usually you would store windows
|
mainWindow = null // Dereference the window object
|
||||||
// in an array if your app supports multi windows, this is the time
|
|
||||||
// when you should delete the corresponding element.
|
|
||||||
mainWindow = null
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
|
||||||
// initialization and is ready to create browser windows.
|
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
app.on('ready', createWindow)
|
app.on('ready', () => {
|
||||||
|
createWindow()
|
||||||
|
})
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', function() {
|
app.on('window-all-closed', function() {
|
||||||
// On OS X it is common for applications and their menu bar
|
if ((process.platform !== 'darwin') && recreatingWindowInProgress != true) {
|
||||||
// to stay active until the user quits explicitly with Cmd + Q
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit()
|
app.quit()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('activate', function() {
|
app.on('activate', function() {
|
||||||
// On OS X it's common to re-create a window in the app when the
|
|
||||||
// dock icon is clicked and there are no other windows open.
|
|
||||||
if (mainWindow === null) {
|
if (mainWindow === null) {
|
||||||
createWindow()
|
createWindow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Export toggleCustomTitleBar for use in ./menu.js
|
||||||
|
module.exports.toggleCustomTitleBar = toggleCustomTitleBar
|
||||||
|
|
@ -41,7 +41,7 @@ echo "Nupkg version: $version"
|
||||||
|
|
||||||
# Build installer URL
|
# Build installer URL
|
||||||
pipelineURL="$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_REF_NAME/raw"
|
pipelineURL="$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_REF_NAME/raw"
|
||||||
instURL="$pipelineURL/openflexure-ev-win.exe?job=package:win32"
|
instURL="$pipelineURL/openflexure-ev-win.exe?job=package"
|
||||||
nuspecURL="$CI_JOB_URL/artifacts/browse"
|
nuspecURL="$CI_JOB_URL/artifacts/browse"
|
||||||
|
|
||||||
echo "$instURL"
|
echo "$instURL"
|
||||||
|
|
|
||||||
23
app/menu.js
23
app/menu.js
|
|
@ -1,10 +1,13 @@
|
||||||
const { app, Menu } = require('electron')
|
const { app, shell, Menu } = require('electron')
|
||||||
const updater = require("electron-updater");
|
const updater = require("electron-updater");
|
||||||
const autoUpdater = updater.autoUpdater;
|
const autoUpdater = updater.autoUpdater;
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const openAboutWindow = require('about-window').default
|
const openAboutWindow = require('about-window').default
|
||||||
|
|
||||||
|
const main = require('./app')
|
||||||
|
const { store } = require('./store')
|
||||||
|
|
||||||
const template = [
|
const template = [
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
|
|
@ -26,7 +29,16 @@ const template = [
|
||||||
{ role: 'forcereload' },
|
{ role: 'forcereload' },
|
||||||
{ role: 'toggledevtools' },
|
{ role: 'toggledevtools' },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ role: 'togglefullscreen' }
|
{ role: 'togglefullscreen' },
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: store.get('drawCustomTitleBar'),
|
||||||
|
label: 'Custom titlebar',
|
||||||
|
click () {
|
||||||
|
main.toggleCustomTitleBar()
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -50,6 +62,13 @@ const template = [
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Homepage',
|
||||||
|
click () {
|
||||||
|
shell.openExternal('https://openflexure.org')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
label: 'Check for Updates',
|
label: 'Check for Updates',
|
||||||
click () {
|
click () {
|
||||||
|
|
|
||||||
9
app/store.js
Normal file
9
app/store.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
const Store = require('electron-store');
|
||||||
|
const store = new Store();
|
||||||
|
|
||||||
|
if (store.has('drawCustomTitleBar') !== true) {
|
||||||
|
// Default to false if on MacOS, otherwise true
|
||||||
|
store.set('drawCustomTitleBar', (process.platform !== 'darwin') ? true : false)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.store = store
|
||||||
1144
package-lock.json
generated
1144
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "openflexure-ev",
|
"name": "openflexure-ev",
|
||||||
"version": "0.2.6",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "An electron-based user client for the OpenFlexure Microscope Server",
|
"description": "An electron-based user client for the OpenFlexure Microscope Server",
|
||||||
"author": "OpenFlexure <contact@openflexure.org> (https://www.openflexure.org)",
|
"author": "OpenFlexure <contact@openflexure.org> (https://www.openflexure.org)",
|
||||||
|
|
@ -11,21 +11,24 @@
|
||||||
"license": "GNU General Public License v3.0 ",
|
"license": "GNU General Public License v3.0 ",
|
||||||
"main": "./app/app.js",
|
"main": "./app/app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"release": "electron-builder --linux --config app/builder-config-raspi.yaml & electron-builder --win --linux --config app/builder-config-x86_64.yaml",
|
"build:web": "vue-cli-service build --mode production.web",
|
||||||
|
"build:app": "vue-cli-service build --mode production.app",
|
||||||
|
"serve": "vue-cli-service serve --mode development.web",
|
||||||
|
"start": "npm run build:app && electron app/app.js",
|
||||||
"dist:linux": "electron-builder --linux --config app/builder-config-x86_64.yaml",
|
"dist:linux": "electron-builder --linux --config app/builder-config-x86_64.yaml",
|
||||||
"dist:raspi": "electron-builder --linux --config app/builder-config-raspi.yaml",
|
"dist:raspi": "electron-builder --linux --config app/builder-config-raspi.yaml",
|
||||||
"dist:win": "electron-builder --win --config app/builder-config-x86_64.yaml",
|
"dist:win": "electron-builder --win --config app/builder-config-x86_64.yaml",
|
||||||
"dist:dmg": "electron-builder --mac --config app/builder-config-x86_64.yaml",
|
"dist:dmg": "electron-builder --mac --config app/builder-config-x86_64.yaml",
|
||||||
"dist:appx": "electron-builder --win --config app/builder-config-appx.yaml",
|
"dist:appx": "electron-builder --win --config app/builder-config-appx.yaml",
|
||||||
"build": "vue-cli-service build",
|
"release": "electron-builder --linux --config app/builder-config-raspi.yaml & electron-builder --win --linux --config app/builder-config-x86_64.yaml"
|
||||||
"electron:run": "electron .",
|
|
||||||
"electron:dev": "electron app/app.dev.js",
|
|
||||||
"serve": "vue-cli-service serve"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"about-window": "^1.12.1",
|
"about-window": "^1.12.1",
|
||||||
|
"custom-electron-titlebar": "^3.0.8",
|
||||||
"electron-context-menu": "^0.11.0",
|
"electron-context-menu": "^0.11.0",
|
||||||
"electron-updater": "^4.0.6"
|
"electron-store": "^3.2.0",
|
||||||
|
"electron-updater": "^4.0.6",
|
||||||
|
"material-design-icons": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.3.0",
|
"@vue/cli-plugin-babel": "^3.3.0",
|
||||||
|
|
@ -33,10 +36,10 @@
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"css-loader": "^2.1.1",
|
"css-loader": "^2.1.1",
|
||||||
"electron": "^4.1.4",
|
"electron": "^4.1.4",
|
||||||
"electron-builder": "^20.39.0",
|
"electron-builder": "^21.0.1",
|
||||||
"less": "^3.9.0",
|
"less": "^3.9.0",
|
||||||
"less-loader": "^4.1.0",
|
"less-loader": "^4.1.0",
|
||||||
"uikit": "3.1.1",
|
"uikit": "^3.1.1",
|
||||||
"vue": "^2.5.21",
|
"vue": "^2.5.21",
|
||||||
"vue-template-compiler": "^2.6.10",
|
"vue-template-compiler": "^2.6.10",
|
||||||
"vuex": "^3.0.1"
|
"vuex": "^3.0.1"
|
||||||
|
|
|
||||||
9
public/titleicon.svg
Normal file
9
public/titleicon.svg
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 90 56" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;">
|
||||||
|
<g transform="matrix(1,0,0,1,-30.245,-47.0254)">
|
||||||
|
<g id="path3773" transform="matrix(0.12596,0,0,0.12596,28.1368,19.1335)">
|
||||||
|
<path d="M212.85,344.652C234.052,276.913 297.347,227.702 372.047,227.702C446.747,227.702 510.042,276.913 531.245,344.652L531.245,344.652L531.246,344.656C531.789,346.391 532.304,348.138 532.791,349.896C556.452,421.618 655.593,393.868 655.593,393.868L721.09,563.056L472.356,659.347L430.306,550.728L430.129,550.794L406.853,490.142C408.621,489.464 410.361,488.736 412.072,487.962C419.736,484.232 426.404,480.109 432.198,475.703C447.995,463.209 459.586,446.041 465.257,426.69C473.38,395.32 463.384,366.691 463.101,365.891C449.309,328.959 413.54,302.366 372.047,302.366C330.554,302.366 294.785,328.959 280.994,365.891C280.711,366.689 270.714,395.319 278.838,426.69C284.509,446.041 296.099,463.209 311.897,475.703C317.69,480.109 324.359,484.232 332.023,487.962C333.734,488.736 335.474,489.464 337.242,490.142L337.166,490.34C337.166,490.34 313.965,550.794 313.965,550.794L313.788,550.728L271.739,659.347L23.004,563.056L88.501,393.868C88.501,393.868 187.642,421.618 211.303,349.896C211.79,348.138 212.306,346.391 212.849,344.656L212.85,344.652L212.85,344.652Z" style="fill:white;fill-rule:nonzero;stroke:white;stroke-width:12.54px;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
92
src/App.vue
92
src/App.vue
|
|
@ -1,82 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app" v-bind:class="handleTheme">
|
<div id="app" v-bind:class="handleTheme">
|
||||||
|
|
||||||
|
<!-- Grid managing whole app -->
|
||||||
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove" margin=0>
|
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove" margin=0>
|
||||||
<div id="sidebar-container" v-bind:class="{ 'overlay-panel': this.window.width<850 }" class="uk-padding-remove uk-first-column uk-inline uk-height-1-1">
|
<panelLeft/>
|
||||||
<div id="overlay-toggle">
|
<panelRight/>
|
||||||
<a href="" class="uk-icon-button uk-box-shadow-small uk-box-shadow-hover-medium action-btn-outline" uk-icon="menu" uk-toggle="target: #left-panel-container; animation: uk-animation-slide-left-small, uk-animation-slide-left-small" ></a>
|
|
||||||
</div>
|
|
||||||
<div id="left-panel-container" class="uk-padding-remove uk-card uk-card-default uk-width-auto uk-height-1-1" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
|
||||||
<panelLeft/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="main-panel-container" class="uk-padding-remove uk-height-1-1 uk-width-expand">
|
|
||||||
<panelDisplay/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Import axios for HTTP requests
|
// Import axios for HTTP requests
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
// Import basic UIkit
|
|
||||||
import UIkit from 'uikit';
|
|
||||||
|
|
||||||
// Import components
|
// Import components
|
||||||
import panelLeft from './components/panelLeft.vue'
|
import panelLeft from './components/panelLeft.vue'
|
||||||
import panelDisplay from './components/panelDisplay.vue'
|
import panelRight from './components/panelRight.vue'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
panelLeft,
|
panelRight,
|
||||||
panelDisplay
|
panelLeft
|
||||||
},
|
},
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {}
|
||||||
window: {
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
created: function () {
|
created: function () {
|
||||||
var context = this
|
|
||||||
|
|
||||||
function handleSidebarEvent(context, event){
|
|
||||||
if (event.target.id == 'left-panel-container') {
|
|
||||||
console.log("Sidebar hidden")
|
|
||||||
context.$root.$emit('globalResizePreview')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UIkit.util.on(document, 'hidden', '#left-panel-container', function (e) {
|
|
||||||
handleSidebarEvent(context, e)
|
|
||||||
})
|
|
||||||
UIkit.util.on(document, 'shown', '#left-panel-container', function (e) {
|
|
||||||
handleSidebarEvent(context, e)
|
|
||||||
})
|
|
||||||
|
|
||||||
window.addEventListener('resize', this.handleResize)
|
|
||||||
this.handleResize();
|
|
||||||
|
|
||||||
window.addEventListener('beforeunload', this.handleExit)
|
window.addEventListener('beforeunload', this.handleExit)
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy: function () {
|
|
||||||
window.removeEventListener('resize', this.handleResize)
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleResize: function(event) {
|
|
||||||
this.window.width = window.innerWidth;
|
|
||||||
this.window.height = window.innerHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleExit: function(event) {
|
handleExit: function(event) {
|
||||||
console.log("Triggered beforeunload")
|
console.log("Triggered beforeunload")
|
||||||
this.$root.$emit('globalTogglePreview', false)
|
this.$root.$emit('globalTogglePreview', false)
|
||||||
|
|
@ -114,38 +73,9 @@ body, html {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay-panel {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay-toggle {
|
|
||||||
width: 0px;
|
|
||||||
height: 30px;
|
|
||||||
z-index: 999;
|
|
||||||
position: absolute;
|
|
||||||
right: -20px;
|
|
||||||
top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-btn-outline {
|
|
||||||
border: 1px solid lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-light .uk-icon-button {
|
|
||||||
background-color: rgb(52, 52, 52);
|
|
||||||
}
|
|
||||||
.uk-light .uk-icon-button:hover, .uk-light .uk-icon-button:focus {
|
|
||||||
background-color: rgb(70, 70, 70);
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-light .uk-card-default {
|
|
||||||
background: #222
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-disabled {
|
.uk-disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.5;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
17
src/assets/less/app.less
Normal file
17
src/assets/less/app.less
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Theming specific to the electron app
|
||||||
|
|
||||||
|
.menubar-menu-container {
|
||||||
|
box-shadow: 0.5px 1px 4px 0px rgba(0,0,0,0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menubar-menu-container > * {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menubar-menu-container .action-menu-item, .menubar-menu-container .action-label {
|
||||||
|
cursor: default
|
||||||
|
}
|
||||||
|
|
||||||
|
.menubar-menu-container a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,14 @@
|
||||||
// Highlight.js
|
// Highlight.js
|
||||||
@import "./highlight.less";
|
@import "./highlight.less";
|
||||||
|
|
||||||
|
// Electron app theming
|
||||||
|
@import "./app.less";
|
||||||
|
|
||||||
// Custom OpenFlexure theming
|
// Custom OpenFlexure theming
|
||||||
@global-primary-background: #C32280;
|
@global-primary-background: #C32280;
|
||||||
|
|
||||||
|
@inverse-primary-muted-color: lighten(@global-primary-background, 15%);
|
||||||
|
|
||||||
// UIkit
|
// UIkit
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
|
|
@ -120,6 +125,10 @@
|
||||||
@inverse-global-color: fade(@global-inverse-color, 80%);
|
@inverse-global-color: fade(@global-inverse-color, 80%);
|
||||||
@inverse-global-muted-color: fade(@global-inverse-color, 60%);
|
@inverse-global-muted-color: fade(@global-inverse-color, 60%);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Paper
|
||||||
|
//
|
||||||
|
@paper-border-radius: 4px;
|
||||||
|
|
||||||
|
|
||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
|
|
@ -134,103 +143,14 @@
|
||||||
@sidebar-right-left-xl: 60px;
|
@sidebar-right-left-xl: 60px;
|
||||||
|
|
||||||
|
|
||||||
/* HTML
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
/* UIkit modifiers
|
||||||
* Force vertical scrollbar
|
|
||||||
* 1. `overflow-x` has to be on the `body` element for Safari to prevent horizontal scrolling on touch
|
|
||||||
This causes a random bug showing a vertical scrollbar in combination with some fonts like `Poppins`
|
|
||||||
This is why `overflow-y` must also be set to `hidden`
|
|
||||||
*/
|
|
||||||
|
|
||||||
html { overflow-y: scroll; }
|
|
||||||
|
|
||||||
/* 1 */
|
|
||||||
body { overflow: hidden; }
|
|
||||||
|
|
||||||
|
|
||||||
/* Documentation Sidebars
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sidebar Left
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-sidebar-left {
|
|
||||||
position: fixed;
|
|
||||||
top: @navbar-nav-item-height;
|
|
||||||
bottom: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: @sidebar-left-width !important;
|
|
||||||
padding: 40px 40px 60px 40px;
|
|
||||||
border-right: 1px @global-border solid;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sidebar Right
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-sidebar-right {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: ~'calc(100% + @{sidebar-right-left})';
|
|
||||||
width: @sidebar-right-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tablet landscape and bigger */
|
|
||||||
@media (min-width: @breakpoint-medium) {
|
|
||||||
|
|
||||||
.tm-sidebar-left + .tm-main { padding-left: @sidebar-left-width; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Desktop and bigger */
|
|
||||||
@media (min-width: @breakpoint-large) {
|
|
||||||
|
|
||||||
.tm-sidebar-right { left: ~'calc(100% + @{sidebar-right-left})'; }
|
|
||||||
|
|
||||||
.tm-sidebar-left + .tm-main { padding-left: @sidebar-left-width - (@sidebar-right-width + @sidebar-right-left); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Large screen and bigger */
|
|
||||||
@media (min-width: 1400px) {
|
|
||||||
|
|
||||||
.tm-sidebar-left {
|
|
||||||
width: @sidebar-left-width-xl !important;
|
|
||||||
padding: 45px 45px 60px 45px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-sidebar-right { left: ~'calc(100% + @{sidebar-right-left-xl})'; }
|
|
||||||
|
|
||||||
.tm-sidebar-left + .tm-main { padding-left: @sidebar-left-width-xl - (@sidebar-right-width + @sidebar-right-left-xl); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* UIkit modifier
|
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Navbar
|
* Navbar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.tm-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background: linear-gradient(to left, #28a5f5, @global-primary-background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-navbar-container .uk-navbar-nav > li > a,
|
|
||||||
.tm-navbar-container .uk-navbar-item:not(.uk-logo),
|
|
||||||
.tm-navbar-container .uk-navbar-toggle {
|
|
||||||
height: 70px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Color Mode
|
|
||||||
.tm-navbar-container:not(.uk-navbar-transparent):extend(.uk-light all) {}
|
|
||||||
|
|
||||||
// Line Mode
|
// Line Mode
|
||||||
@navbar-nav-item-line-margin-vertical: 20px;
|
@navbar-nav-item-line-margin-vertical: 20px;
|
||||||
@navbar-nav-item-line-margin-horizontal: @navbar-nav-item-padding-horizontal;
|
@navbar-nav-item-line-margin-horizontal: @navbar-nav-item-padding-horizontal;
|
||||||
|
|
@ -238,271 +158,115 @@ body { overflow: hidden; }
|
||||||
@navbar-nav-item-line-background: currentColor;
|
@navbar-nav-item-line-background: currentColor;
|
||||||
@navbar-nav-item-line-transition-duration: 0.3s;
|
@navbar-nav-item-line-transition-duration: 0.3s;
|
||||||
|
|
||||||
.tm-navbar-container .uk-navbar-nav > li > a {
|
.uk-navbar-dropdown.uk-open {
|
||||||
position: relative;
|
border-radius: @paper-border-radius;
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
left: @navbar-nav-item-line-margin-horizontal;
|
|
||||||
right: ~'calc(102% - @{navbar-nav-item-line-margin-horizontal})';
|
|
||||||
bottom: @navbar-nav-item-line-margin-vertical;
|
|
||||||
height: @navbar-nav-item-line-height;
|
|
||||||
background-color: @navbar-nav-item-line-background;
|
|
||||||
transition: @navbar-nav-item-line-transition-duration ease-in-out;
|
|
||||||
transition-property: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-navbar-container .uk-navbar-nav > li > a:hover::before { right: @navbar-nav-item-line-margin-horizontal; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Nav
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-nav > li.uk-active > a { position: relative; }
|
|
||||||
|
|
||||||
.tm-nav > li.uk-active > a:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 15px;
|
|
||||||
left: -25px;
|
|
||||||
width: 15px;
|
|
||||||
border-top: 1px solid @global-primary-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-nav .uk-nav-header {
|
|
||||||
padding: 8px 0;
|
|
||||||
border-bottom: 1px solid @global-border;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subnav
|
* Cards
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Tablet landscape and bigger */
|
.uk-card {
|
||||||
@media (min-width: @breakpoint-medium) {
|
border-radius: @paper-border-radius;
|
||||||
|
|
||||||
.tm-subnav { margin-left: -50px; }
|
|
||||||
.tm-subnav > * { padding-left: 50px; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tm-subnav > * > :first-child { text-transform: capitalize; }
|
.uk-card-media-top img {
|
||||||
|
border-radius: @paper-border-radius @paper-border-radius 0 0;
|
||||||
/*
|
|
||||||
* Label (Changelog()
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-label-changelog {
|
|
||||||
width: 80px;
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
.uk-card-default .uk-card-footer {
|
||||||
* Button
|
border-top: 1px solid rgba(180, 180, 180, 0.25);
|
||||||
*/
|
}
|
||||||
.uk-button {
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-button-default,
|
.uk-card-primary .uk-card-footer {
|
||||||
.tm-button-primary { border-radius: 500px; }
|
border-top: 1px solid rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
.tm-button-default {}
|
|
||||||
|
|
||||||
.tm-button-large { line-height: 48px; }
|
|
||||||
|
|
||||||
.tm-button-primary {}
|
|
||||||
|
|
||||||
.hook-inverse() {
|
.hook-inverse() {
|
||||||
|
// Override background colour in dark mode
|
||||||
.tm-button-default {
|
.uk-card-default {
|
||||||
color: @inverse-global-color;
|
background-color: #2a2a2a !important;
|
||||||
border-color: @inverse-global-muted-color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tm-button-primary {
|
// Lighten on hover to show depth in dark mode
|
||||||
background: #fff !important;
|
.uk-card-default:hover {
|
||||||
color: @global-primary-background !important;
|
transition: background-color @animation-fast-duration ease;
|
||||||
|
background-color: #333 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tm-button-primary:hover { box-shadow: 0 10px 40px rgba(30,135,240,1); }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Section
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-section-primary {
|
|
||||||
background: linear-gradient(to left top, #28a5f5, @global-primary-background) 0 0 no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-section-intro {
|
|
||||||
background: linear-gradient(to left top, #28a5f5, @global-primary-background) 0 0 no-repeat,
|
|
||||||
#fff;
|
|
||||||
background-size: 100% 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Heading
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-h4,
|
|
||||||
.tm-h5,
|
|
||||||
.tm-h6 {
|
|
||||||
font-family: Montserrat;
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
color: @global-muted-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-h4 { font-size: 14px; }
|
|
||||||
.tm-h5 { font-size: 12px; }
|
|
||||||
.tm-h6 { font-size: 11px; }
|
|
||||||
|
|
||||||
.hook-inverse() {
|
|
||||||
|
|
||||||
.tm-h4,
|
|
||||||
.tm-h5,
|
|
||||||
.tm-h6 { color: rgba(255, 255, 255, 0.7); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Text
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-text-large { font-size: 18px; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Box shadow
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-box-shadow-medium {
|
|
||||||
box-shadow: 2px 12px 35px rgba(0,0,0,0.1),
|
|
||||||
0 1px 6px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-box-shadow-large {
|
|
||||||
box-shadow: -40px 40px 160px 0 rgba(0,0,0,0.08),
|
|
||||||
-8px 8px 15px 0 rgba(120,120,120,0.04),
|
|
||||||
3px 3px 30px 0 rgba(0,0,0,0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-box-shadow-modal { box-shadow: 3px 3px 40px 0 rgba(0,0,0,0.06); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overlay
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tm-overlay-default { background: fade(@global-background, 50%); }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modal
|
* Modal
|
||||||
*/
|
*/
|
||||||
|
.uk-modal-dialoge {
|
||||||
.tm-modal-dialog { background: @global-muted-background; }
|
border-radius: @paper-border-radius;
|
||||||
|
box-shadow: 0 14px 25px rgba(0, 0, 0, 0.16);
|
||||||
.tm-modal-header { padding: 20px 30px; }
|
transition: 0.3s ease !important;
|
||||||
.tm-modal-body { padding: 0; }
|
|
||||||
|
|
||||||
/* Phone landscape and bigger */
|
|
||||||
@media (min-width: @breakpoint-small) {
|
|
||||||
|
|
||||||
.tm-modal-header { padding: 25px 50px; }
|
|
||||||
.tm-modal-body { padding: 0 50px; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Desktop and bigger */
|
|
||||||
@media (min-width: @breakpoint-xlarge) {
|
|
||||||
|
|
||||||
.tm-modal-header { padding: 50px 120px; }
|
|
||||||
.tm-modal-body { padding: 0 120px; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.tm-modal-close-full {
|
|
||||||
background: transparent;
|
|
||||||
padding: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Phone landscape and bigger */
|
|
||||||
@media (min-width: @breakpoint-small) {
|
|
||||||
|
|
||||||
.tm-modal-close-full { padding: @global-medium-margin; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Utilities
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Heading fragment
|
* Notifications
|
||||||
*/
|
*/
|
||||||
|
.uk-notification-message {
|
||||||
.tm-heading-fragment > a {
|
border-radius: @paper-border-radius;
|
||||||
color: inherit;
|
box-shadow: 0 14px 25px rgba(0, 0, 0, 0.16);
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phone landscape and bigger */
|
.uk-notification-message-danger {
|
||||||
@media (min-width: @breakpoint-small) {
|
border: 1px solid @notification-message-danger-color
|
||||||
|
}
|
||||||
|
|
||||||
h2.tm-heading-fragment > a:before {
|
.uk-notification-message-warning {
|
||||||
content: "#";
|
border: 1px solid @notification-message-warning-color
|
||||||
position: absolute;
|
}
|
||||||
width: 25px;
|
|
||||||
margin-left: -25px;
|
.uk-notification-message-success {
|
||||||
color: @global-muted-color;
|
border: 1px solid @notification-message-success-color
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Links
|
||||||
|
*/
|
||||||
|
.uk-link, .uk-button-link {
|
||||||
|
color: @global-muted-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uk-link:hover, .uk-button-link:hover, a:hover {
|
||||||
|
color: @global-primary-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hook-inverse() {
|
||||||
|
.uk-link:hover, .uk-button-link:hover, a:hover {
|
||||||
|
color: @inverse-primary-muted-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buttons
|
||||||
|
*/
|
||||||
|
.uk-button {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uk-button-danger {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #f0506e;
|
||||||
|
border: 1px solid #f0506e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hook-inverse() {
|
||||||
|
.uk-button-primary{
|
||||||
|
background-color: rgba(180, 180, 180, 0.15);
|
||||||
|
color: @inverse-primary-muted-color;
|
||||||
|
border-color: @inverse-primary-muted-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
.uk-button-primary:hover {
|
||||||
|
background-color: @inverse-primary-muted-color;
|
||||||
|
color: #fff;
|
||||||
/* Reset container for docs
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.tm-main .uk-container {
|
|
||||||
padding-left: @container-padding-horizontal;
|
|
||||||
padding-right: @container-padding-horizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Phone landscape and bigger */
|
|
||||||
@media (min-width: @breakpoint-small) {
|
|
||||||
|
|
||||||
.tm-main .uk-container {
|
|
||||||
padding-left: @container-padding-horizontal-s;
|
|
||||||
padding-right: @container-padding-horizontal-s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tablet landscape and bigger */
|
.uk-icon-button, .uk-icon-button:hover {
|
||||||
@media (min-width: @breakpoint-medium) {
|
text-decoration: none
|
||||||
|
}
|
||||||
.tm-main .uk-container {
|
|
||||||
padding-left: @container-padding-horizontal-m;
|
|
||||||
padding-right: @container-padding-horizontal-m;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Pro
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/* Desktop and bigger */
|
|
||||||
@media (min-width: @breakpoint-large) {
|
|
||||||
.tm-intro-text { margin-top: 30px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Large screen and bigger */
|
|
||||||
@media (min-width: @breakpoint-xlarge) {
|
|
||||||
.tm-intro-text { margin-top: 90px; }
|
|
||||||
.tm-intro-image { margin-right: -75px; }
|
|
||||||
}
|
|
||||||
|
|
@ -42,20 +42,7 @@
|
||||||
<a class="uk-accordion-title" href="#">Metadata</a>
|
<a class="uk-accordion-title" href="#">Metadata</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
|
|
||||||
<form @submit.prevent="handleMetadataSubmit">
|
<keyvalList v-model="metadata"/>
|
||||||
<div class="uk-margin-small uk-grid-small" uk-grid>
|
|
||||||
<div class="uk-margin-remove-top uk-width-2-5"><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-top uk-width-2-5"><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-width-1-5"><button class="uk-button uk-button-default uk-form-small uk-float-right" uk-icon="plus"></button></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div v-for="(value, key) in customMetadata" :key="key" 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>{{ key }}: </b>{{ value }}</div>
|
|
||||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-auto">
|
|
||||||
<a href="#" v-on:click="delMetadataKey(key)" class="uk-icon-link" uk-icon="trash"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -63,16 +50,7 @@
|
||||||
<li>
|
<li>
|
||||||
<a class="uk-accordion-title" href="#">Tags</a>
|
<a class="uk-accordion-title" href="#">Tags</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
|
<tagList v-model="tags"/>
|
||||||
<form @submit.prevent="handleTagSubmit">
|
|
||||||
<div class="uk-margin-small uk-grid-small" uk-grid>
|
|
||||||
<div class="uk-margin-remove-top uk-width-4-5"><input v-model="newTag" class="uk-input uk-form-width-small uk-form-small" type="text" name="flavor" placeholder="Tag"></div>
|
|
||||||
<div class="uk-margin-remove-top uk-width-1-5"><button class="uk-button uk-button-default uk-form-small uk-float-right" uk-icon="plus"></button></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<span v-for="tag in tags" :key="tag" v-on:click="delTag(tag)" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
@ -176,10 +154,19 @@
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import tagList from "../fieldComponents/tagList"
|
||||||
|
import keyvalList from "../fieldComponents/keyvalList"
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'paneCapture',
|
name: 'paneCapture',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
tagList,
|
||||||
|
keyvalList
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
filename: '',
|
filename: '',
|
||||||
|
|
@ -203,42 +190,14 @@ export default {
|
||||||
z: 5
|
z: 5
|
||||||
},
|
},
|
||||||
resizeDims: [640, 480],
|
resizeDims: [640, 480],
|
||||||
newTag: "",
|
|
||||||
tags: [],
|
tags: [],
|
||||||
customMetadata: {
|
metadata: {
|
||||||
Client: "openflexure.vue"
|
Client: `${process.env.PACKAGE.name}.${process.env.PACKAGE.version}`
|
||||||
},
|
|
||||||
newMetadata: {
|
|
||||||
key: "",
|
|
||||||
value: ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleMetadataSubmit: function () {
|
|
||||||
console.log("Adding metadata");
|
|
||||||
this.customMetadata[this.newMetadata.key] = this.newMetadata.value
|
|
||||||
this.newMetadata.key = "";
|
|
||||||
this.newMetadata.value = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
delMetadataKey: function (key) {
|
|
||||||
this.$delete(this.customMetadata, key)
|
|
||||||
},
|
|
||||||
|
|
||||||
handleTagSubmit: function () {
|
|
||||||
this.tags.push(this.newTag)
|
|
||||||
this.newTag = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
delTag: function (tag) {
|
|
||||||
console.log(tag)
|
|
||||||
var index = this.tags.indexOf(tag);
|
|
||||||
if (index > -1) {
|
|
||||||
this.tags.splice(index, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleCapture: function() {
|
handleCapture: function() {
|
||||||
var payload = this.basePayload
|
var payload = this.basePayload
|
||||||
|
|
@ -336,7 +295,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional metadata
|
// Additional metadata
|
||||||
payload.metadata = this.customMetadata
|
payload.metadata = this.metadata
|
||||||
payload.tags = this.tags
|
payload.tags = this.tags
|
||||||
|
|
||||||
// Attach notes
|
// Attach notes
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
<div class="host-input">
|
<div class="host-input">
|
||||||
<div class="uk-margin">
|
<div class="uk-margin">
|
||||||
|
|
||||||
<h3>Connect</h3>
|
|
||||||
|
|
||||||
<form @submit.prevent="handleSubmit">
|
<form @submit.prevent="handleSubmit">
|
||||||
<div class="uk-form-controls uk-margin">
|
<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="true"> Connect locally</label><br>
|
||||||
|
|
@ -12,7 +10,7 @@
|
||||||
|
|
||||||
<div v-if="!localMode">
|
<div v-if="!localMode">
|
||||||
<div class="uk-inline uk-width-1-1">
|
<div class="uk-inline uk-width-1-1">
|
||||||
<span class="uk-form-icon" uk-icon="icon: server"></span>
|
<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">
|
<input v-model="hostname" v-bind:class="IpFormClasses" class="uk-input uk-form-small" type="text" placeholder="Hostname or IP address">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -23,10 +21,11 @@
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
<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">
|
<div class="uk-form-controls">
|
||||||
<input v-model="computedPort" class="uk-input uk-form-width-medium uk-form-small" id="form-stacked-text" type="number" value=5000>
|
<input v-model="computedPort" class="uk-input uk-form-small" id="form-stacked-text" type="number" value=5000>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a class="uk-accordion-title" href="#">Status</a>
|
<a class="uk-accordion-title" href="#">Status</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
|
|
@ -35,29 +34,35 @@
|
||||||
<p><b>Base URI:</b> {{ $store.getters.uri }}</p>
|
<p><b>Base URI:</b> {{ $store.getters.uri }}</p>
|
||||||
<p v-if="$store.state.apiConfig.name"><b>Device name:</b> {{ $store.state.apiConfig.name }}</p>
|
<p v-if="$store.state.apiConfig.name"><b>Device name:</b> {{ $store.state.apiConfig.name }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="$store.state.waiting"><div uk-spinner></div></div>
|
<div v-else-if="$store.state.waiting"><div uk-spinner></div></div>
|
||||||
<div v-else-if="$store.state.error"><b>Error:</b> {{ $store.state.error }}</div>
|
<div v-else-if="$store.state.error"><b>Error:</b> {{ $store.state.error }}</div>
|
||||||
<div v-else>No active connection</div>
|
<div v-else>No active connection</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li v-if="!localMode" class="uk-open">
|
<li v-if="!localMode" class="uk-open">
|
||||||
<a class="uk-accordion-title" href="#">Saved hosts</a>
|
<a class="uk-accordion-title" href="#">Saved hosts</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
<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">Save Current</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">Save Current</button>
|
||||||
|
<div v-for="host in savedHosts" :key="host.name" class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle">
|
||||||
<div v-for="host in savedHosts" :key="host.name" class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-grid">
|
<a href="#" v-on:click="autofillHost(host)" class="uk-link uk-padding-remove uk-width-expand host-description"><b>{{ host.name }}</b> ({{ host.hostname }}:{{ host.port }})</a>
|
||||||
<a href="#" v-on:click="autofillHost(host)" class="uk-icon-link uk-padding-remove uk-width-expand"><b>{{ host.name }}</b> ({{ host.hostname }}:{{ host.port }})</a>
|
<a href="#" v-on:click="delSavedHost(host)" class="uk-icon uk-width-auto host-delete"><i class="material-icons">delete</i></a>
|
||||||
<a href="#" v-on:click="delSavedHost(host)" class="uk-icon-link uk-width-auto" uk-icon="trash"></a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<button class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">Connect</button>
|
<button class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">Connect</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
Disconnect
|
||||||
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -122,6 +127,29 @@ export default {
|
||||||
this.$store.dispatch('firstConnect')
|
this.$store.dispatch('firstConnect')
|
||||||
.then (() => {
|
.then (() => {
|
||||||
console.log("Connected!")
|
console.log("Connected!")
|
||||||
|
this.checkServerVersion()
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.modalError(error) // Let mixin handle error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if ((serverVersion == undefined) || (serverVersionMajor != clientVersionMajor)) {
|
||||||
|
this.modalDialog("Version mismatch", "Client and microscope versions do not match. Consider updating your microscope software. Some functionality may currently be broken.", status='warning')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.modalError(error) // Let mixin handle error
|
this.modalError(error) // Let mixin handle error
|
||||||
|
|
@ -132,7 +160,7 @@ export default {
|
||||||
this.$store.commit("changeSetting", ['trackWindow', state]);
|
this.$store.commit("changeSetting", ['trackWindow', state]);
|
||||||
this.$store.commit("changeSetting", ['disableStream', state]);
|
this.$store.commit("changeSetting", ['disableStream', state]);
|
||||||
this.$store.commit("changeSetting", ['autoGpuPreview', state]);
|
this.$store.commit("changeSetting", ['autoGpuPreview', state]);
|
||||||
this.$root.$emit('globalTogglePreview', state)
|
//this.$root.$emit('globalTogglePreview', state)
|
||||||
},
|
},
|
||||||
|
|
||||||
autofillHost: function (host) {
|
autofillHost: function (host) {
|
||||||
|
|
@ -217,4 +245,14 @@ export default {
|
||||||
.host-input {
|
.host-input {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.host-description {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.host-delete {
|
||||||
|
padding: 0 2px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -64,26 +64,23 @@
|
||||||
|
|
||||||
<li class="uk-open">
|
<li class="uk-open">
|
||||||
<a class="uk-accordion-title" href="#">Autofocus</a>
|
<a class="uk-accordion-title" href="#">Autofocus</a>
|
||||||
<div class="uk-text-center uk-container" v-if="isAutofocusing">
|
<div class="uk-accordion-content">
|
||||||
<div class="center-spinner" uk-spinner></div>
|
|
||||||
</div>
|
|
||||||
<div class="uk-accordion-content" v-else>
|
|
||||||
|
|
||||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
<div v-if="isAutofocusing">
|
||||||
|
<progressBar/>
|
||||||
<div>
|
</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 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>
|
||||||
|
<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>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -94,6 +91,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import progressBar from "../genericComponents/progressBar"
|
||||||
|
|
||||||
// Key Codes
|
// Key Codes
|
||||||
const keyCodes = {
|
const keyCodes = {
|
||||||
|
|
@ -111,6 +109,10 @@ const keyCodes = {
|
||||||
export default {
|
export default {
|
||||||
name: 'paneNavigate',
|
name: 'paneNavigate',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
progressBar
|
||||||
|
},
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
keysDown: {},
|
keysDown: {},
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="paneSettings">
|
<div id="paneSettings">
|
||||||
|
|
||||||
<h3>Settings</h3>
|
|
||||||
<appSettings/>
|
<appSettings/>
|
||||||
|
|
||||||
<ul uk-accordion="multiple: true">
|
<ul uk-accordion="multiple: true">
|
||||||
|
|
@ -26,10 +25,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import streamSettings from './paneSettingsComponents/streamSettings.vue'
|
import streamSettings from './settingsComponents/streamSettings.vue'
|
||||||
import microscopeSettings from './paneSettingsComponents/microscopeSettings.vue'
|
import microscopeSettings from './settingsComponents/microscopeSettings.vue'
|
||||||
import cameraSettings from './paneSettingsComponents/cameraSettings.vue'
|
import cameraSettings from './settingsComponents/cameraSettings.vue'
|
||||||
import appSettings from './paneSettingsComponents/appSettings.vue'
|
import appSettings from './settingsComponents/appSettings.vue'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -4,30 +4,31 @@
|
||||||
<div>
|
<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">
|
<div class="uk-form-controls">
|
||||||
<input v-model="shutterSpeed" class="uk-input uk-form-small" type="number">
|
<input v-model="displayShutterSpeed" class="uk-input uk-form-small" type="number">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
<div class="uk-form-controls">
|
||||||
<input v-model="analogGain" class="uk-input uk-form-small" type="number">
|
<input v-model="displayAnalogGain" class="uk-input uk-form-small" type="number" step="0.01">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
<div class="uk-form-controls">
|
||||||
<input v-model="digitalGain" class="uk-input uk-form-small" type="number">
|
<input v-model="displayDigitalGain" class="uk-input uk-form-small" type="number" step="0.01">
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<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>
|
||||||
|
|
||||||
<div class="uk-text-center uk-container" v-if="isCalibrating">
|
<div v-if="isCalibrating">
|
||||||
<div class="center-spinner" uk-spinner></div>
|
<progressBar/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
|
||||||
|
<div v-bind:hidden="isCalibrating">
|
||||||
<button type="button" v-on:click="recalibrateConfirm()" class="uk-button uk-button-default uk-form-small uk-float-right uk-margin-small uk-width-1-1">Auto-Calibrate</button>
|
<button type="button" v-on:click="recalibrateConfirm()" class="uk-button uk-button-default uk-form-small uk-float-right uk-margin-small uk-width-1-1">Auto-Calibrate</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -40,35 +41,42 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import progressBar from "../../genericComponents/progressBar"
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'microscopeSettings',
|
name: 'microscopeSettings',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
progressBar
|
||||||
|
},
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
shutterSpeed: this.$store.state.apiConfig.picamera_settings.shutter_speed,
|
shutterSpeed: this.$store.state.apiConfig.camera_settings.picamera_settings.shutter_speed,
|
||||||
analogGain: this.$store.state.apiConfig.picamera_settings.analog_gain,
|
analogGain: this.$store.state.apiConfig.camera_settings.picamera_settings.analog_gain,
|
||||||
digitalGain: this.$store.state.apiConfig.picamera_settings.digital_gain,
|
digitalGain: this.$store.state.apiConfig.camera_settings.picamera_settings.digital_gain,
|
||||||
isCalibrating: false
|
isCalibrating: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateInputValues: function () {
|
updateInputValues: function () {
|
||||||
this.shutterSpeed = this.$store.state.apiConfig.picamera_settings.shutter_speed
|
this.shutterSpeed = this.$store.state.apiConfig.camera_settings.picamera_settings.shutter_speed
|
||||||
this.digitalGain = this.$store.state.apiConfig.picamera_settings.digital_gain
|
this.digitalGain = this.$store.state.apiConfig.camera_settings.picamera_settings.digital_gain
|
||||||
this.analogGain = this.$store.state.apiConfig.picamera_settings.analog_gain
|
this.analogGain = this.$store.state.apiConfig.camera_settings.picamera_settings.analog_gain
|
||||||
},
|
},
|
||||||
|
|
||||||
applyConfigRequest: function() {
|
applyConfigRequest: function() {
|
||||||
console.log("Applying config to the microscope")
|
console.log("Applying config to the microscope")
|
||||||
var payload = {picamera_settings:{}}
|
var payload = {
|
||||||
|
picamera_settings: {}
|
||||||
|
}
|
||||||
|
|
||||||
//if (this.shutterSpeed != this.$store.state.apiConfig.picamera_settings.shutter_speed) {
|
//if (this.shutterSpeed != this.$store.state.apiConfig.picamera_settings.shutter_speed) {
|
||||||
payload.picamera_settings.shutter_speed = this.shutterSpeed
|
payload.camera_settings.picamera_settings.shutter_speed = this.shutterSpeed
|
||||||
payload.picamera_settings.analog_gain = this.analogGain
|
payload.camera_settings.picamera_settings.analog_gain = this.analogGain
|
||||||
payload.picamera_settings.digital_gain = this.digitalGain
|
payload.camera_settings.picamera_settings.digital_gain = this.digitalGain
|
||||||
//};
|
//};
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
|
|
@ -119,6 +127,15 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
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 () {
|
recalibrateApiUri: function () {
|
||||||
return this.$store.getters.uri + "/plugin/default/camera_calibration/recalibrate"
|
return this.$store.getters.uri + "/plugin/default/camera_calibration/recalibrate"
|
||||||
},
|
},
|
||||||
|
|
@ -52,27 +52,31 @@ export default {
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
microscopeName: this.$store.state.apiConfig.name,
|
microscopeName: this.$store.state.apiConfig.name,
|
||||||
stageBacklash: this.$store.state.apiConfig.backlash
|
stageBacklash: this.$store.state.apiConfig.stage_settings.backlash
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateInputValues: function () {
|
updateInputValues: function () {
|
||||||
this.microscopeName = this.$store.state.apiConfig.name;
|
this.microscopeName = this.$store.state.apiConfig.name;
|
||||||
this.stageBacklash = this.$store.state.apiConfig.backlash
|
this.stageBacklash = this.$store.state.apiConfig.stage_settings.backlash
|
||||||
},
|
},
|
||||||
|
|
||||||
applyConfigRequest: function() {
|
applyConfigRequest: function() {
|
||||||
var payload = {}
|
var payload = {
|
||||||
|
stage_settings: {}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.microscopeName != this.$store.state.apiConfig.name) {
|
if (this.microscopeName != this.$store.state.apiConfig.name) {
|
||||||
payload.name = this.microscopeName
|
payload.name = this.microscopeName
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.stageBacklash != this.$store.state.apiConfig.backlash) {
|
if (this.stageBacklash != this.$store.state.apiConfig.stage_settings.backlash) {
|
||||||
payload.backlash = this.stageBacklash
|
payload.stage_settings.backlash = this.stageBacklash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(payload)
|
||||||
|
|
||||||
// Send request to update config
|
// Send request to update config
|
||||||
axios.post(this.configApiUri, payload)
|
axios.post(this.configApiUri, payload)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
52
src/components/fieldComponents/checkList.vue
Normal file
52
src/components/fieldComponents/checkList.vue
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<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)">
|
||||||
|
{{ option }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'checkList',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'options',
|
||||||
|
'name',
|
||||||
|
'label',
|
||||||
|
'value'
|
||||||
|
],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateValue(target) {
|
||||||
|
var newSelected = this.value != null ? [...this.value] : [] // Clone value array
|
||||||
|
|
||||||
|
if (target.checked) {
|
||||||
|
if (!newSelected.includes(target.value)) {
|
||||||
|
newSelected.push(target.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (newSelected.includes(target.value)) {
|
||||||
|
var newSelected = newSelected.filter(function(value, index, arr){
|
||||||
|
return value != target.value;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit('input', newSelected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
19
src/components/fieldComponents/htmlBlock.vue
Normal file
19
src/components/fieldComponents/htmlBlock.vue
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p v-html="content"></p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'htmlBlock',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'label',
|
||||||
|
'name',
|
||||||
|
'content'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
84
src/components/fieldComponents/keyvalList.vue
Normal file
84
src/components/fieldComponents/keyvalList.vue
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
<template>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<a href="#" v-on:click="handleMetadataSubmit()" class="uk-icon uk-margin-left"><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 class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import labelInput from "../fieldComponents/labelInput"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'keyvalList',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
labelInput
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
newMetadata: {
|
||||||
|
key: "",
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'value'
|
||||||
|
],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleMetadataSubmit: function () {
|
||||||
|
var newSelected = {}
|
||||||
|
|
||||||
|
if (this.value != null) {
|
||||||
|
Object.assign(newSelected, this.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
newSelected[this.newMetadata.key] = this.newMetadata.value
|
||||||
|
this.newMetadata.key = "";
|
||||||
|
this.newMetadata.value = "";
|
||||||
|
|
||||||
|
this.$emit('input', newSelected)
|
||||||
|
},
|
||||||
|
|
||||||
|
delMetadataKey: function (key) {
|
||||||
|
var newSelected = {}
|
||||||
|
|
||||||
|
if (this.value != null) {
|
||||||
|
Object.assign(newSelected, this.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$delete(newSelected, key)
|
||||||
|
|
||||||
|
this.$emit('input', newSelected)
|
||||||
|
},
|
||||||
|
|
||||||
|
modifyValue: function (e, v) {
|
||||||
|
console.log(e)
|
||||||
|
console.log(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
58
src/components/fieldComponents/labelInput.vue
Normal file
58
src/components/fieldComponents/labelInput.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<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">
|
||||||
|
|
||||||
|
<div v-show="editing == false">
|
||||||
|
<label> {{value}} </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
v-show="editing == true"
|
||||||
|
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)"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'labelInput',
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
editing: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'name',
|
||||||
|
'label',
|
||||||
|
'value'
|
||||||
|
],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setEditing(editing) {
|
||||||
|
this.editing = editing
|
||||||
|
if (editing == true) {
|
||||||
|
this.$nextTick(() => this.$refs.textinput.focus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
33
src/components/fieldComponents/numberInput.vue
Normal file
33
src/components/fieldComponents/numberInput.vue
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<label class="uk-form-label">{{label}}</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class="uk-input uk-form-small"
|
||||||
|
type="number"
|
||||||
|
:name="name"
|
||||||
|
:value="value"
|
||||||
|
@input="$emit('input', $event.target.value)"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'numberInput',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'placeholder',
|
||||||
|
'label',
|
||||||
|
'name',
|
||||||
|
'value'
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
29
src/components/fieldComponents/radioList.vue
Normal file
29
src/components/fieldComponents/radioList.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'radioList',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'options',
|
||||||
|
'name',
|
||||||
|
'label',
|
||||||
|
'value'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
33
src/components/fieldComponents/selectList.vue
Normal file
33
src/components/fieldComponents/selectList.vue
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'selectList',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'multi',
|
||||||
|
'options',
|
||||||
|
'name',
|
||||||
|
'label',
|
||||||
|
'value'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
63
src/components/fieldComponents/tagList.vue
Normal file
63
src/components/fieldComponents/tagList.vue
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
<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">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="#" v-on:click="handleTagSubmit()" class="uk-icon uk-margin-left"><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>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tagList',
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
newTag: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'value'
|
||||||
|
],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleTagSubmit: function () {
|
||||||
|
var newSelected = this.value != null ? [...this.value] : [] // Clone value array
|
||||||
|
|
||||||
|
newSelected.push(this.newTag)
|
||||||
|
this.newTag = "";
|
||||||
|
|
||||||
|
this.$emit('input', newSelected)
|
||||||
|
},
|
||||||
|
|
||||||
|
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;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('input', newSelected)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
30
src/components/fieldComponents/textInput.vue
Normal file
30
src/components/fieldComponents/textInput.vue
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<label class="uk-form-label">{{label}}</label>
|
||||||
|
|
||||||
|
<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)"
|
||||||
|
>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'textInput',
|
||||||
|
|
||||||
|
props: [
|
||||||
|
'placeholder',
|
||||||
|
'label',
|
||||||
|
'name',
|
||||||
|
'value'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
142
src/components/genericComponents/progressBar.vue
Normal file
142
src/components/genericComponents/progressBar.vue
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
<template>
|
||||||
|
<div class="progress uk-margin-top uk-margin-horizontal-remove uk-padding-remove">
|
||||||
|
<div class="indeterminate"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "../../assets/less/theme.less";
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
position: relative;
|
||||||
|
height: 5px;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(180, 180, 180, 0.15);
|
||||||
|
border-radius: 2px;
|
||||||
|
background-clip: padding-box;
|
||||||
|
margin: 0.5rem 0 1rem 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress .determinate {
|
||||||
|
position: absolute;
|
||||||
|
background-color: inherit;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
transition: width .3s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress .indeterminate, .progress .determinate {
|
||||||
|
background-color: @global-primary-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hook-inverse() {
|
||||||
|
.progress .indeterminate, .progress .determinate{
|
||||||
|
background-color: @inverse-primary-muted-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress .indeterminate:before {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress .indeterminate:after {
|
||||||
|
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-delay: 1.15s;
|
||||||
|
animation-delay: 1.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes indeterminate {
|
||||||
|
0% {
|
||||||
|
left: -35%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
}
|
||||||
|
@keyframes indeterminate {
|
||||||
|
0% {
|
||||||
|
left: -35%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
}
|
||||||
|
@-webkit-keyframes indeterminate-short {
|
||||||
|
0% {
|
||||||
|
left: -200%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
100% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
}
|
||||||
|
@keyframes indeterminate-short {
|
||||||
|
0% {
|
||||||
|
left: -200%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
100% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
46
src/components/genericComponents/tabContent.vue
Normal file
46
src/components/genericComponents/tabContent.vue
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="!(this.requireConnection && !this.$store.getters.ready)"
|
||||||
|
v-bind: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',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: String,
|
||||||
|
currentTab: String,
|
||||||
|
requireConnection: Boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {},
|
||||||
|
computed: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
.section-heading {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: 20px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-content, .section-heading {
|
||||||
|
padding: 9px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
62
src/components/genericComponents/tabIcon.vue
Normal file
62
src/components/genericComponents/tabIcon.vue
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="uk-link"
|
||||||
|
:class="classObject"
|
||||||
|
:uk-tooltip="tooltipOptions"
|
||||||
|
@click="setThisTab">
|
||||||
|
<slot></slot>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'tabIcon',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: String,
|
||||||
|
currentTab: String,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
// Custom UIkit CSS modifications
|
||||||
|
@import "../../assets/less/theme.less";
|
||||||
|
|
||||||
|
.tabicon-active {
|
||||||
|
color: @global-primary-background !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hook-inverse() {
|
||||||
|
.tabicon-active {
|
||||||
|
color: @inverse-primary-muted-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -1,59 +1,160 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="panelLeft" class="uk-flex uk-flex-column uk-margin-remove uk-padding-remove uk-height-1-1">
|
<div id="panel-left" class="uk-margin-remove uk-padding-remove uk-height-1-1" uk-grid>
|
||||||
<ul class="uk-flex-none uk-flex-center uk-margin-remove-top uk-margin-remove-bottom" uk-tab="swiping: false">
|
|
||||||
<li><a href="#" uk-switcher-item="connect" uk-icon="server" uk-tooltip="Connect"></a></li>
|
<!-- Vertical tab bar -->
|
||||||
<li v-bind:class="disableIfDisconnected"><a href="#" uk-switcher-item="navigate" uk-icon="location" uk-tooltip="Navigate"></a></li>
|
<div id="switcher-left" class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1">
|
||||||
<li v-bind:class="disableIfDisconnected"><a href="#" uk-switcher-item="capture" uk-icon="camera" uk-tooltip="Capture"></a></li>
|
<tabIcon id="connect" :requireConnection="false" :currentTab="currentTab" @set-tab="setTab">
|
||||||
<li v-bind:class="disableIfDisconnected"><a href="#" uk-switcher-item="plugins" uk-icon="git-fork" uk-tooltip="Plugins"></a></li>
|
<i class="material-icons">settings_ethernet</i>
|
||||||
<li><a href="#" uk-switcher-item="settings" uk-icon="settings" uk-tooltip="Settings"></a></li>
|
</tabIcon>
|
||||||
</ul>
|
<tabIcon id="navigate" :requireConnection="true" :currentTab="currentTab" @set-tab="setTab">
|
||||||
<ul class="uk-switcher uk-padding-small uk-flex uk-flex-1 panel-content">
|
<i class="material-icons">gamepad</i>
|
||||||
<li class="uk-width-expand"><paneConnect/></li>
|
</tabIcon>
|
||||||
<li class="uk-width-expand"><div v-if="$store.getters.ready"><paneNavigate/></div></li>
|
<tabIcon id="capture" :requireConnection="true" :currentTab="currentTab" @set-tab="setTab">
|
||||||
<li class="uk-width-expand"><div v-if="$store.getters.ready"><paneCapture/></div></li>
|
<i class="material-icons">camera_alt</i>
|
||||||
<li class="uk-width-expand"><div v-if="$store.getters.ready"><panePlugins/></div></li>
|
</tabIcon>
|
||||||
<li class="uk-width-expand"><paneSettings/></li>
|
<tabIcon id="settings" :requireConnection="false" :currentTab="currentTab" @set-tab="setTab">
|
||||||
</ul>
|
<i class="material-icons">settings</i>
|
||||||
|
</tabIcon>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
</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="connect" :requireConnection="false" :currentTab="currentTab">
|
||||||
|
<paneConnect/>
|
||||||
|
</tabContent>
|
||||||
|
<tabContent id="navigate" :requireConnection="true" :currentTab="currentTab">
|
||||||
|
<paneNavigate/>
|
||||||
|
</tabContent>
|
||||||
|
<tabContent id="capture" :requireConnection="true" :currentTab="currentTab">
|
||||||
|
<paneCapture/>
|
||||||
|
</tabContent>
|
||||||
|
<tabContent id="settings" :requireConnection="false" :currentTab="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
|
||||||
|
:name="form.name"
|
||||||
|
:route="form.route"
|
||||||
|
:isTask="form.isTask"
|
||||||
|
:submitLabel="form.submitLabel"
|
||||||
|
:selfUpdate="form.selfUpdate"
|
||||||
|
:schema="form.schema"/>
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</tabContent>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Import components
|
// Import axios for HTTP requests
|
||||||
import paneConnect from './paneConnect.vue'
|
import axios from 'axios'
|
||||||
import paneNavigate from './paneNavigate.vue'
|
|
||||||
import paneCapture from './paneCapture.vue'
|
// Import generic components
|
||||||
import panePlugins from './panePlugins.vue'
|
import tabIcon from './genericComponents/tabIcon'
|
||||||
import paneSettings from './paneSettings.vue'
|
import tabContent from './genericComponents/tabContent'
|
||||||
|
|
||||||
|
// Import pane components
|
||||||
|
import paneConnect from './controlComponents/paneConnect'
|
||||||
|
import paneNavigate from './controlComponents/paneNavigate'
|
||||||
|
import paneCapture from './controlComponents/paneCapture'
|
||||||
|
import paneSettings from './controlComponents/paneSettings'
|
||||||
|
|
||||||
|
// Import plugin components
|
||||||
|
import JsonForm from './pluginComponents/JsonForm'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'panelLeft',
|
name: 'panelLeft',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
tabIcon,
|
||||||
|
tabContent,
|
||||||
paneConnect,
|
paneConnect,
|
||||||
paneNavigate,
|
paneNavigate,
|
||||||
paneCapture,
|
paneCapture,
|
||||||
panePlugins,
|
paneSettings,
|
||||||
paneSettings
|
JsonForm
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
currentTab: 'connect',
|
||||||
|
showControlBar: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setTab: function(event, tab) {
|
||||||
|
if (this.currentTab == tab) {
|
||||||
|
this.showControlBar = !this.showControlBar
|
||||||
|
this.currentTab = 'none'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.showControlBar = true
|
||||||
|
this.currentTab = tab
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
disableIfDisconnected: function () {
|
pluginApiUri: function () {
|
||||||
return {
|
return this.$store.getters.uri + "/plugin"
|
||||||
'uk-disabled': !this.$store.getters.ready
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style scoped lang="less">
|
||||||
.uk-tab {
|
|
||||||
padding-left: 0;
|
#component-left {
|
||||||
}
|
|
||||||
.panel-content {
|
|
||||||
width: 300px;
|
width: 300px;
|
||||||
overflow: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#container-left {
|
||||||
|
overflow: hidden auto;
|
||||||
|
background-color: rgba(180, 180, 180, 0.025);
|
||||||
|
}
|
||||||
|
|
||||||
|
#container-left, #switcher-left {
|
||||||
|
border-width: 0 1px 0 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: rgba(180, 180, 180, 0.25)
|
||||||
|
}
|
||||||
|
|
||||||
|
#switcher-left a{
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#switcher-left{
|
||||||
|
background-color: rgba(180, 180, 180, 0.1);
|
||||||
|
padding-top: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="panelDisplay" class="uk-flex uk-flex-column uk-margin-remove uk-padding-remove uk-height-1-1">
|
<!-- 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" uk-tab="swiping: false">
|
<ul class="uk-flex-none uk-flex-center uk-margin-remove-bottom uk-text-center" uk-tab="swiping: false">
|
||||||
<li><a href="#" uk-switcher-item="preview" uk-icon="play-circle" uk-tooltip="Live"></a></li>
|
<li><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" uk-icon="image" uk-tooltip="Captures"></a></li>
|
<li v-bind:class="{'uk-disabled': !this.$store.getters.ready}"><a href="#" uk-switcher-item="gallery">Gallery</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="uk-switcher uk-flex uk-flex-1">
|
<ul class="uk-switcher uk-flex uk-flex-1">
|
||||||
<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 clickableTab" id="streamDisplayTab"><streamDisplay/></li>
|
||||||
<li class="uk-height-1-1 uk-width-1-1 uk-overflow-auto" id="galleryDisplayTab"><galleryDisplay/></li>
|
<li class="uk-height-1-1 uk-width-1-1 uk-overflow-auto" id="galleryDisplayTab"><galleryDisplay/></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Import axios for HTTP requests
|
||||||
|
import axios from 'axios'
|
||||||
|
// Import basic UIkit
|
||||||
import UIkit from 'uikit';
|
import UIkit from 'uikit';
|
||||||
|
|
||||||
// Import components
|
// Import components
|
||||||
import streamDisplay from './paneDisplayComponents/streamDisplay.vue'
|
import streamDisplay from './viewComponents/streamDisplay.vue'
|
||||||
import galleryDisplay from './paneDisplayComponents/galleryDisplay.vue'
|
import galleryDisplay from './viewComponents/galleryDisplay.vue'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'panelDisplay',
|
name: 'panelRight',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
streamDisplay,
|
streamDisplay,
|
||||||
galleryDisplay
|
galleryDisplay,
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -54,4 +58,9 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
.uk-tab {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
233
src/components/pluginComponents/JsonForm.vue
Normal file
233
src/components/pluginComponents/JsonForm.vue
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<form @submit.prevent="submitForm" class="uk-form-stacked">
|
||||||
|
|
||||||
|
<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">
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<component
|
||||||
|
:is="field.fieldType"
|
||||||
|
v-model="formData[field.name]"
|
||||||
|
v-bind="field">
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="taskRunning">
|
||||||
|
<progressBar/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button v-bind:hidden="taskRunning" class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1">{{ submitLabel }}</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
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 progressBar from "../genericComponents/progressBar"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsonForm',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
numberInput,
|
||||||
|
selectList,
|
||||||
|
textInput,
|
||||||
|
htmlBlock,
|
||||||
|
radioList,
|
||||||
|
checkList,
|
||||||
|
tagList,
|
||||||
|
keyvalList,
|
||||||
|
progressBar
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
'name': {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: "Plugin"
|
||||||
|
},
|
||||||
|
'schema': {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
'route': {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
'isTask': {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
'submitLabel': {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: "Submit"
|
||||||
|
},
|
||||||
|
'selfUpdate': {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
formData: {},
|
||||||
|
taskRunning: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.initialiseFormData()
|
||||||
|
|
||||||
|
if (this.selfUpdate) {
|
||||||
|
this.getFormData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
initialiseFormData() {
|
||||||
|
/*
|
||||||
|
This function initialises the form data.
|
||||||
|
Limitations in Vue mean that newly created formData properties are not reactive.
|
||||||
|
GETting formData values from the server creates the properties, but the form components
|
||||||
|
don't get updated because of this limitation.
|
||||||
|
Here, we step through the form schema, and properly create reactive properties for each component.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
|
||||||
|
submitForm() {
|
||||||
|
if (this.isTask == true) {
|
||||||
|
this.newLongRequest(this.formData)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.newQuickRequest(this.formData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getFormData: function() {
|
||||||
|
// Send a quick request
|
||||||
|
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
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
newQuickRequest: function(params) {
|
||||||
|
console.log(this.submitApiUri)
|
||||||
|
console.log(params)
|
||||||
|
// Send a quick request
|
||||||
|
axios.post(this.submitApiUri, params)
|
||||||
|
.then(response => {
|
||||||
|
// Do something with the response
|
||||||
|
console.log(response)
|
||||||
|
// Update the form data if we're self-updating
|
||||||
|
if (this.selfUpdate) {
|
||||||
|
this.getFormData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.modalError(error) // Let mixin handle error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
newLongRequest: function(params) {
|
||||||
|
this.taskRunning = true
|
||||||
|
axios.post(this.submitApiUri, params)
|
||||||
|
.then(response => {
|
||||||
|
console.log("Task ID: " + response.data.id)
|
||||||
|
// Start the store polling TaskId for success
|
||||||
|
return this.$store.dispatch('pollTask', [response.data.id, null, null])
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
// Do something with the response
|
||||||
|
console.log(response)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.modalError(error) // Let mixin handle error
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
console.log("Cleaning up after task.")
|
||||||
|
this.taskRunning = false
|
||||||
|
// Update the form data if we're self-updating
|
||||||
|
if (this.selfUpdate) {
|
||||||
|
this.getFormData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
pluginApiUri: function () {
|
||||||
|
return this.$store.getters.uri + "/plugin"
|
||||||
|
},
|
||||||
|
|
||||||
|
submitApiUri: function () {
|
||||||
|
return this.pluginApiUri + this.route
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container > div {
|
||||||
|
flex-basis: 100%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="captureCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium uk-margin-right" 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" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
||||||
|
|
||||||
<div class="uk-card-media-top">
|
<div class="uk-card-media-top">
|
||||||
|
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
<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-expand">{{ metadata.filename }}</div>
|
||||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-auto">
|
<div class="uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||||
<a href="#" v-on:click="delCaptureConfirm()" class="uk-icon-link" uk-icon="trash"></a>
|
<a href="#" v-on:click="delCaptureConfirm()" class="uk-icon">
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -59,7 +61,7 @@
|
||||||
<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">
|
<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">
|
<div class="uk-inline">
|
||||||
<span class="uk-form-icon" uk-icon="icon: tag"></span>
|
<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">
|
<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 class="uk-button uk-button-default uk-margin-left uk-form-small uk-modal-close" type="button">Cancel</button>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium uk-margin-right">
|
<div class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium">
|
||||||
|
|
||||||
<div class="uk-card-media-top">
|
<div class="uk-card-media-top">
|
||||||
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
<nav class="uk-navbar-container uk-navbar-transparent navbar" uk-navbar="mode: click">
|
<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">
|
<div class="uk-navbar-left uk-padding-remove-top uk-padding-remove-bottom">
|
||||||
<ul class="uk-navbar-nav">
|
<ul class="uk-navbar-nav">
|
||||||
<li v-bind:class="[sortDescending ? 'uk-active' : '']"><a v-on:click="sortDescending=true;" class="uk-icon-link" href="#" uk-icon="icon: arrow-down"></a></li>
|
<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-link" href="#" uk-icon="icon: arrow-up"></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>
|
<li>
|
||||||
<a href="#">Filter</a>
|
<a href="#">Filter</a>
|
||||||
<div class="uk-navbar-dropdown" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }">
|
<div class="uk-navbar-dropdown" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }">
|
||||||
|
|
@ -25,14 +25,16 @@
|
||||||
|
|
||||||
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
||||||
|
|
||||||
<div v-if="(galleryFolder)" class="uk-padding uk-padding-remove-right uk-padding-remove-bottom">
|
<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-button" uk-icon="arrow-left"></a>
|
<a href="#" v-on:click="galleryFolder=''" class="uk-icon uk-margin-remove"><i class="material-icons">arrow_back</i></a>
|
||||||
<h3 class="uk-inline uk-float-right uk-margin-remove"><b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}</h3>
|
<div class="uk-margin-left">
|
||||||
|
<h3 class="uk-margin-remove uk-margin-left"><b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}</h3>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="uk-grid-medium uk-padding uk-padding-remove-right uk-grid-match" uk-grid>
|
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
||||||
|
|
||||||
<div v-for="item in sortedItems" :key="item.metadata.id" class="uk-remove-padding-remove-left" >
|
<div v-for="item in sortedItems" :key="item.metadata.id">
|
||||||
<scanCard
|
<scanCard
|
||||||
v-if="'isScan' in item"
|
v-if="'isScan' in item"
|
||||||
:metadata="item.metadata"
|
:metadata="item.metadata"
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="streamDisplay uk-width-1-1 uk-height-1-1 scrollTarget" id="streamDisplay" ref="streamDisplay">
|
<div ref="streamDisplay" class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget" id="stream-display">
|
||||||
|
|
||||||
<img class="uk-align-center uk-margin-remove-bottom" v-on:dblclick="clickmonitor" v-if="showStream" v-bind:src="streamImgUri" alt="Stream">
|
<img class="uk-align-center uk-margin-remove-bottom" v-on:dblclick="clickmonitor" v-if="showStream" v-bind:src="streamImgUri" alt="Stream">
|
||||||
|
|
||||||
|
|
@ -23,33 +23,37 @@ import axios from 'axios'
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
name: 'streamDisplay',
|
name: 'stream-display',
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
displaySize: [0, 0],
|
displaySize: [0, 0],
|
||||||
displayPosition: [0, 0],
|
displayPosition: [0, 0],
|
||||||
GpuPreviewActive: false,
|
GpuPreviewActive: false,
|
||||||
resizeTeimoutId: setTimeout(this.doneResizing, 500)
|
resizeTimeoutId: setTimeout(this.doneResizing, 500)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// A global signal listener to change the GPU preview state
|
|
||||||
this.$root.$on('globalResizePreview', (state) => {
|
|
||||||
this.handleDoneResize()
|
|
||||||
})
|
|
||||||
// A global signal listener to change the GPU preview state
|
// A global signal listener to change the GPU preview state
|
||||||
this.$root.$on('globalTogglePreview', (state) => {
|
this.$root.$on('globalTogglePreview', (state) => {
|
||||||
console.log(`Toggling preview to ${state}`)
|
console.log(`Toggling preview to ${state}`)
|
||||||
this.previewRequest(state)
|
this.previewRequest(state)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
created: function () {
|
created: function () {
|
||||||
// Add resize listener
|
|
||||||
window.addEventListener('resize', this.handleResize);
|
|
||||||
|
|
||||||
// Watch for host 'ready'
|
// Watch for host 'ready'
|
||||||
this.$store.watch(
|
this.$store.watch(
|
||||||
(state)=>{
|
(state)=>{
|
||||||
|
|
@ -57,29 +61,27 @@ export default {
|
||||||
},
|
},
|
||||||
(newValue, oldValue)=>{
|
(newValue, oldValue)=>{
|
||||||
// 'ready' changed, so do something
|
// 'ready' changed, so do something
|
||||||
console.log(oldValue)
|
|
||||||
console.log(newValue)
|
|
||||||
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview)
|
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy: function () {
|
beforeDestroy: function () {
|
||||||
// Remove resize listener
|
// Disconnect the size observer
|
||||||
window.removeEventListener('resize', this.handleResize)
|
this.sizeObserver.disconnect()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
clickmonitor: function(event) {
|
clickmonitor: function(event) {
|
||||||
// Calculate steps from event coordinates and store config FOV
|
// Calculate steps from event coordinates and store config FOV
|
||||||
var xCoordinate = event.offsetX;
|
let xCoordinate = event.offsetX;
|
||||||
var yCoordinate = event.offsetY;
|
let yCoordinate = event.offsetY;
|
||||||
|
|
||||||
var xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
let xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
||||||
var yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
let yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
||||||
|
|
||||||
var xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
let xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
||||||
var ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
let ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
||||||
|
|
||||||
// Emit a signal to move, acted on by panelNavigate.vue
|
// Emit a signal to move, acted on by panelNavigate.vue
|
||||||
this.$root.$emit('globalMoveEvent', xSteps, ySteps, 0, false)
|
this.$root.$emit('globalMoveEvent', xSteps, ySteps, 0, false)
|
||||||
|
|
@ -87,12 +89,13 @@ export default {
|
||||||
|
|
||||||
handleResize: function(event) {
|
handleResize: function(event) {
|
||||||
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
||||||
clearTimeout(this.resizeTeimoutId);
|
clearTimeout(this.resizeTimeoutId);
|
||||||
this.resizeTeimoutId = setTimeout(this.handleDoneResize, 500)
|
this.resizeTimeoutId = setTimeout(this.handleDoneResize, 250)
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDoneResize: function() {
|
handleDoneResize: function() {
|
||||||
// Recalculate size
|
// Recalculate size
|
||||||
|
console.log("Recalculating frame size")
|
||||||
this.recalculateSize();
|
this.recalculateSize();
|
||||||
if (this.$store.state.globalSettings.autoGpuPreview == true && this.GpuPreviewActive == true) {
|
if (this.$store.state.globalSettings.autoGpuPreview == true && this.GpuPreviewActive == true) {
|
||||||
// Reload preview
|
// Reload preview
|
||||||
|
|
@ -101,23 +104,24 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
recalculateSize: function () {
|
recalculateSize: function () {
|
||||||
console.log("Recalculating window dimensions...")
|
let element = this.$refs.streamDisplay.parentNode;
|
||||||
// Stacking parentNode is a hacky fix
|
let bound = element.getBoundingClientRect()
|
||||||
// For some reason, when switching tabs, width was always half what it should be,
|
|
||||||
// until the size was recalculated at some later time. Probably something to do
|
|
||||||
// with tab transition. This parentNode stuff instead reads the size of the tab
|
|
||||||
// container, irrespective of WHICH tab is selected. It's nasty, but works.
|
|
||||||
let element = this.$refs.streamDisplay.parentNode.parentNode;
|
|
||||||
|
|
||||||
let size = [element.clientWidth, element.clientHeight];
|
let elementSize = [bound.width, bound.height]
|
||||||
|
|
||||||
let elem_pos = [element.getBoundingClientRect().left, element.getBoundingClientRect().top];
|
let elementPositionOnWindow = [bound.left, bound.top]
|
||||||
let wind_pos = [window.screenX, window.screenY];
|
let windowPositionOnDisplay = [window.screenX, window.screenY]
|
||||||
let navHeight = window.outerHeight - window.innerHeight;
|
let windowChromeHeight = window.outerHeight - window.innerHeight
|
||||||
let position = [Math.max(0, wind_pos[0] + elem_pos[0]), Math.max(0, wind_pos[1] + elem_pos[1] + navHeight)];
|
let elementPositionOnDisplay = [
|
||||||
|
Math.max(0, windowPositionOnDisplay[0] + elementPositionOnWindow[0]),
|
||||||
|
Math.max(0, windowPositionOnDisplay[1] + elementPositionOnWindow[1] + windowChromeHeight)
|
||||||
|
]
|
||||||
|
|
||||||
this.displaySize = size;
|
this.displaySize = elementSize
|
||||||
this.displayPosition = position;
|
this.displayPosition = elementPositionOnDisplay
|
||||||
|
|
||||||
|
console.log(`Size: ${this.displaySize}`)
|
||||||
|
console.log(`Position: ${this.displayPosition}`)
|
||||||
},
|
},
|
||||||
|
|
||||||
previewRequest: function(state) {
|
previewRequest: function(state) {
|
||||||
|
|
@ -147,7 +151,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var letpayload = {}
|
var payload = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send preview request
|
// Send preview request
|
||||||
|
|
@ -182,13 +186,13 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.streamDisplay img {
|
.stream-display img {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
object-fit: contain
|
object-fit: contain
|
||||||
}
|
}
|
||||||
|
|
||||||
.streamDisplay {
|
.stream-display {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
15
src/main.app.js
Normal file
15
src/main.app.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Load settings store from main process
|
||||||
|
const { store } = require('electron').remote.require('./store')
|
||||||
|
|
||||||
|
// Load extra modules we'll be using
|
||||||
|
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'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Loaded main.app.js for electron-renderer functionality")
|
||||||
24
src/main.js
24
src/main.js
|
|
@ -3,9 +3,9 @@ import App from './App.vue'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
|
||||||
import UIkit from 'uikit';
|
import UIkit from 'uikit';
|
||||||
// Import UIkit icon set
|
|
||||||
import Icons from 'uikit/dist/js/uikit-icons';
|
// Import MD icons
|
||||||
UIkit.use(Icons);
|
import 'material-design-icons/iconfont/material-icons.css'
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
|
@ -36,8 +36,20 @@ Vue.mixin({
|
||||||
return new Promise(showModal)
|
return new Promise(showModal)
|
||||||
},
|
},
|
||||||
|
|
||||||
modalNotify: function(message) {
|
modalNotify: function(message, status = 'success') {
|
||||||
UIkit.notification({message: message, status: 'success'})
|
UIkit.notification({message: message, status: status})
|
||||||
|
},
|
||||||
|
|
||||||
|
modalDialog: function(title, message) {
|
||||||
|
UIkit.modal.dialog(`
|
||||||
|
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||||
|
<div class="uk-modal-header">
|
||||||
|
<h2 class="uk-modal-title">${title}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="uk-modal-body">
|
||||||
|
<p>${message}</p>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
},
|
},
|
||||||
|
|
||||||
modalError: function(error) {
|
modalError: function(error) {
|
||||||
|
|
@ -66,7 +78,7 @@ Vue.mixin({
|
||||||
console.log(errormsg)
|
console.log(errormsg)
|
||||||
}
|
}
|
||||||
this.$store.commit('setError', errormsg);
|
this.$store.commit('setError', errormsg);
|
||||||
UIkit.notification({message: `<span uk-icon=\'icon: warning\'></span> ${errormsg}`, status: 'danger'})
|
UIkit.notification({message: `${errormsg}`, status: 'danger'})
|
||||||
},
|
},
|
||||||
|
|
||||||
getLocalStorageObj: function(keyName) {
|
getLocalStorageObj: function(keyName) {
|
||||||
|
|
|
||||||
31
src/store.js
31
src/store.js
|
|
@ -15,6 +15,7 @@ export default new Vuex.Store({
|
||||||
error: '',
|
error: '',
|
||||||
apiConfig: {},
|
apiConfig: {},
|
||||||
apiState: {},
|
apiState: {},
|
||||||
|
apiPlugins: [],
|
||||||
globalSettings: {
|
globalSettings: {
|
||||||
disableStream: false,
|
disableStream: false,
|
||||||
autoGpuPreview: false,
|
autoGpuPreview: false,
|
||||||
|
|
@ -38,6 +39,9 @@ export default new Vuex.Store({
|
||||||
commitState(state, stateData) {
|
commitState(state, stateData) {
|
||||||
state.apiState = stateData;
|
state.apiState = stateData;
|
||||||
},
|
},
|
||||||
|
commitPlugins(state, pluginData) {
|
||||||
|
state.apiPlugins = pluginData;
|
||||||
|
},
|
||||||
changeSetting(state, [key, value]) {
|
changeSetting(state, [key, value]) {
|
||||||
state.globalSettings[key] = value;
|
state.globalSettings[key] = value;
|
||||||
},
|
},
|
||||||
|
|
@ -47,6 +51,7 @@ export default new Vuex.Store({
|
||||||
state.error = null
|
state.error = null
|
||||||
state.apiConfig = {}
|
state.apiConfig = {}
|
||||||
state.apiState = {}
|
state.apiState = {}
|
||||||
|
state.apiPlugins = []
|
||||||
},
|
},
|
||||||
setConnected(state) {
|
setConnected(state) {
|
||||||
state.waiting = false
|
state.waiting = false
|
||||||
|
|
@ -72,6 +77,9 @@ export default new Vuex.Store({
|
||||||
.then (() => {
|
.then (() => {
|
||||||
context.dispatch('updateState')
|
context.dispatch('updateState')
|
||||||
})
|
})
|
||||||
|
.then (() => {
|
||||||
|
context.dispatch('updatePlugins')
|
||||||
|
})
|
||||||
.then (() => {
|
.then (() => {
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
|
|
@ -116,6 +124,25 @@ export default new Vuex.Store({
|
||||||
return new Promise(sendRequest)
|
return new Promise(sendRequest)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updatePlugins(context, uri=`${context.getters.uri}/plugin`) {
|
||||||
|
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')
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
reject(new Error(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return new Promise(sendRequest)
|
||||||
|
},
|
||||||
|
|
||||||
pollTask(context, [taskId, timeout, interval]) {
|
pollTask(context, [taskId, timeout, interval]) {
|
||||||
var endTime = Number(new Date()) + (timeout*1000 || 30000);
|
var endTime = Number(new Date()) + (timeout*1000 || 30000);
|
||||||
interval = interval*1000 || 500;
|
interval = interval*1000 || 500;
|
||||||
|
|
@ -128,7 +155,7 @@ export default new Vuex.Store({
|
||||||
var result = response.data.status
|
var result = response.data.status
|
||||||
// If the task ends with success
|
// If the task ends with success
|
||||||
if(result == 'success') {
|
if(result == 'success') {
|
||||||
resolve(response.data.return)
|
resolve(response.data)
|
||||||
}
|
}
|
||||||
// If task ends with an error
|
// If task ends with an error
|
||||||
else if (result == 'error') {
|
else if (result == 'error') {
|
||||||
|
|
@ -136,7 +163,7 @@ export default new Vuex.Store({
|
||||||
}
|
}
|
||||||
// If the condition isn't met but the timeout hasn't elapsed, go again
|
// If the condition isn't met but the timeout hasn't elapsed, go again
|
||||||
else if (Number(new Date()) < endTime) {
|
else if (Number(new Date()) < endTime) {
|
||||||
setTimeout(checkCondition, interval, resolve, reject)
|
setTimeout(checkCondition, interval, resolve, reject)
|
||||||
}
|
}
|
||||||
// Didn't match and too much time, reject!
|
// Didn't match and too much time, reject!
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
var webpack = require('webpack');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
configureWebpack: config => {
|
||||||
|
config.target = process.env.VUE_APP_TARGET || 'web',
|
||||||
|
config.entry = (process.env.VUE_APP_TARGET == 'electron-renderer')
|
||||||
|
? {
|
||||||
|
main: './src/main.js',
|
||||||
|
app: './src/main.app.js'
|
||||||
|
}
|
||||||
|
:{
|
||||||
|
main: './src/main.js',
|
||||||
|
},
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
PACKAGE: JSON.stringify(require('./package.json'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
outputDir: (process.env.VUE_APP_TARGET == 'electron-renderer') ? './app/dist' : './dist',
|
||||||
publicPath: ''
|
publicPath: ''
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue