Merge branch 'master' into develop
# Conflicts: # package.json # src/App.vue # src/components/panels/ControlPanel.vue # src/components/panels/FarmPrinterPanel.vue # src/pages/Files.vue # src/store/farm/printer/getters.ts # src/store/farm/printer/mutations.ts # src/store/files/getters.ts # src/store/printer/mutations.ts # src/store/server/history/getters.ts # src/store/socket/getters.ts
This commit is contained in:
commit
7ae0fe2209
16
src/App.vue
16
src/App.vue
@ -23,7 +23,7 @@
|
||||
<the-sidebar></the-sidebar>
|
||||
<the-topbar></the-topbar>
|
||||
|
||||
<v-main id="content" :style="{ background: mainBackground }">
|
||||
<v-main id="content" :style="mainStyle">
|
||||
<v-container fluid id="page-container" class="container px-3 px-sm-6 py-sm-6 mx-auto">
|
||||
<router-view></router-view>
|
||||
</v-container>
|
||||
@ -70,8 +70,18 @@ export default class App extends Mixins(BaseMixin) {
|
||||
return this.$store.getters['files/getMainBackground']
|
||||
}
|
||||
|
||||
get customStylesheet(): string | null {
|
||||
return this.$store.getters['files/getCustomStylesheet']
|
||||
get mainStyle() {
|
||||
let style = ''
|
||||
|
||||
if (this.mainBackground !== null) {
|
||||
style = 'background-image: url('+this.mainBackground+');'
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
|
||||
get customStylesheet () {
|
||||
return this.$store.getters["files/getCustomStylesheet"]
|
||||
}
|
||||
|
||||
get customFavicons(): string | null {
|
||||
|
@ -8,6 +8,10 @@ export default class BaseMixin extends Vue {
|
||||
return this.$store.getters['socket/getUrl']
|
||||
}
|
||||
|
||||
get hostUrl(): boolean {
|
||||
return this.$store.getters['socket/getHostUrl']
|
||||
}
|
||||
|
||||
get remoteMode() {
|
||||
return this.$store.state.socket.remoteMode
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
<span class="subheading"><v-icon left>mdi-printer-3d</v-icon>{{ printer_name }}</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-item-group v-if="this.printer_webcams.length">
|
||||
<v-item-group v-if="printer.socket.isConnected && this.printer_webcams.length">
|
||||
<v-menu :offset-y="true" title="Webcam">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn small class="px-2 minwidth-0" color="grey darken-3" v-bind="attrs" v-on="on">
|
||||
@ -64,11 +64,12 @@
|
||||
<template v-slot:default="{ hover }">
|
||||
<div>
|
||||
<v-img
|
||||
height="200px"
|
||||
:height="imageHeight"
|
||||
:src="printer_image"
|
||||
class="d-flex align-end"
|
||||
ref="imageDiv"
|
||||
>
|
||||
<div v-if="currentCamName !== 'off' && currentWebcam" class="webcamContainer">
|
||||
<div v-if="printer.socket.isConnected && currentCamName !== 'off' && currentWebcam" class="webcamContainer">
|
||||
<template v-if="'service' in currentWebcam && currentWebcam.service === 'mjpegstreamer'">
|
||||
<webcam-mjpegstreamer :cam-settings="currentWebcam"></webcam-mjpegstreamer>
|
||||
</template>
|
||||
@ -79,7 +80,12 @@
|
||||
<v-card-title class="white--text py-2" style="background-color: rgba(0,0,0,0.3); backdrop-filter: blur(3px);">
|
||||
<v-row>
|
||||
<v-col class="col-auto pr-0 d-flex align-center" style="width: 58px">
|
||||
<img class="my-auto" :src="printer_logo" style="width: 100%;" />
|
||||
<template v-if="printer_logo">
|
||||
<img :src="printer_logo" style="width: 100%;" class="my-auto" alt="Logo" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<mainsail-logo :color="printerLogoColor" style="width: 100%;" class="my-auto"></mainsail-logo>
|
||||
</template>
|
||||
</v-col>
|
||||
<v-col class="col" style="width: 100px">
|
||||
<h3 class="font-weight-regular">{{ printer_status }}</h3>
|
||||
@ -100,7 +106,7 @@
|
||||
</v-card-text>
|
||||
<v-fade-transition>
|
||||
<v-overlay v-if="hover" absolute :z-index="4" >
|
||||
<v-btn color="primary" @click="clickPrinter">{{ $t("Panels.FarmPrinterPanel.SwitchToPrinter") }}</v-btn>
|
||||
<v-btn color="primary" @click="clickPrinter">{{ printer.socket.isConnected ? $t("Panels.FarmPrinterPanel.SwitchToPrinter") : $t("Panels.FarmPrinterPanel.ReconnectToPrinter") }}</v-btn>
|
||||
</v-overlay>
|
||||
</v-fade-transition>
|
||||
</div>
|
||||
@ -110,23 +116,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
import { Component, Mixins, Prop } from 'vue-property-decorator'
|
||||
import {Component, Mixins, Prop, Ref, Vue} from 'vue-property-decorator'
|
||||
import BaseMixin from '@/components/mixins/base'
|
||||
import { FarmPrinterState } from '@/store/farm/printer/types'
|
||||
import Mjpegstreamer from '@/components/webcams/Mjpegstreamer.vue'
|
||||
import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vue'
|
||||
import MainsailLogo from '@/components/ui/MainsailLogo.vue'
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
'webcam-mjpegstreamer': Mjpegstreamer,
|
||||
'webcam-mjpegstreamer-adaptive': MjpegstreamerAdaptive,
|
||||
'mainsail-logo': MainsailLogo
|
||||
}
|
||||
})
|
||||
export default class FarmPrinterPanel extends Mixins(BaseMixin) {
|
||||
private imageHeight = 200;
|
||||
|
||||
@Prop({ type: Object, required: true }) printer!: FarmPrinterState
|
||||
@Ref() readonly imageDiv!: Vue
|
||||
|
||||
get printerUrl() {
|
||||
const thisUrl = window.location.href.split('/')
|
||||
@ -170,6 +178,10 @@ export default class FarmPrinterPanel extends Mixins(BaseMixin) {
|
||||
return this.$store.getters['farm/'+this.printer._namespace+'/getLogo']
|
||||
}
|
||||
|
||||
get printerLogoColor() {
|
||||
return this.$store.getters["farm/"+this.printer._namespace+"/getLogoColor"]
|
||||
}
|
||||
|
||||
get printer_position() {
|
||||
return this.$store.getters['farm/'+this.printer._namespace+'/getPosition']
|
||||
}
|
||||
@ -196,5 +208,20 @@ export default class FarmPrinterPanel extends Mixins(BaseMixin) {
|
||||
this.$store.dispatch('farm/'+this.printer._namespace+'/reconnect')
|
||||
}
|
||||
|
||||
mounted() {
|
||||
window.addEventListener("resize", this.resize)
|
||||
this.resize()
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
window.addEventListener("resize", this.resize)
|
||||
}
|
||||
|
||||
resize() {
|
||||
if (this.imageDiv?.$el?.clientWidth) {
|
||||
this.imageHeight = Math.round(this.imageDiv.$el.clientWidth / 3 * 2)
|
||||
} else this.imageHeight = 200
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
@ -35,9 +35,7 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
|
||||
get url() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const hostUrl = new URL(this.printerUrl === undefined ? document.URL : this.printerUrl)
|
||||
|
||||
const url = new URL(baseUrl, hostUrl.origin)
|
||||
const url = new URL(baseUrl, this.printerUrl === undefined ? this.hostUrl.toString() : this.printerUrl)
|
||||
url.searchParams.append('bypassCache', this.refresh.toString())
|
||||
|
||||
return decodeURIComponent(url.toString())
|
||||
|
@ -16,7 +16,7 @@
|
||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
||||
</div>
|
||||
<canvas ref="mjpegstreamerAdaptive" width="600" height="400" :style="webcamStyle" :class="'webcamImage '+(isLoaded ? '' : 'hiddenWebcam')"></canvas>
|
||||
<span class="webcamFpsOutput" v-if="isLoaded && showFps">{{ $t('Panels.WebcamPanel.FPS')}}: {{ currentFPS }}</span>
|
||||
<span class="webcamFpsOutput" v-if="isLoaded && showFps">{{ $t('Panels.WebcamPanel.FPS')}}: {{ fpsOutput }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -57,6 +57,10 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
return ''
|
||||
}
|
||||
|
||||
get fpsOutput() {
|
||||
return (this.currentFPS < 10) ? '0'+this.currentFPS.toString() : this.currentFPS
|
||||
}
|
||||
|
||||
visibilityChanged(isVisible: boolean) {
|
||||
this.isVisible = isVisible
|
||||
if (isVisible) this.refreshFrame()
|
||||
@ -95,15 +99,13 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
|
||||
async setFrame() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const hostUrl = new URL(this.printerUrl === undefined ? document.URL : this.printerUrl)
|
||||
|
||||
const url = new URL(baseUrl, hostUrl.origin)
|
||||
const url = new URL(baseUrl, this.printerUrl === undefined ? this.hostUrl.toString() : this.printerUrl)
|
||||
|
||||
url.searchParams.append('bypassCache', this.refresh.toString())
|
||||
url.searchParams.set('action', 'snapshot')
|
||||
|
||||
this.request_start_time = performance.now()
|
||||
this.currentFPS = Math.round(1000 / this.time)
|
||||
this.currentFPS = (this.time > 0) ? Math.round(1000 / this.time) : 0
|
||||
|
||||
let canvas = this.$refs.mjpegstreamerAdaptive
|
||||
if (canvas) {
|
||||
|
@ -32,9 +32,7 @@ export default class Uv4lMjpeg extends Mixins(BaseMixin) {
|
||||
|
||||
get url() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const hostUrl = new URL(this.printerUrl === null ? document.URL : this.printerUrl)
|
||||
|
||||
const url = new URL(baseUrl, hostUrl.origin)
|
||||
const url = new URL(baseUrl, this.printerUrl === null ? this.hostUrl.toString() : this.printerUrl)
|
||||
|
||||
return decodeURIComponent(url.toString())
|
||||
}
|
||||
|
@ -256,7 +256,8 @@
|
||||
},
|
||||
"FarmPrinterPanel": {
|
||||
"WebcamOff": "Off",
|
||||
"SwitchToPrinter": "Switch to Printer"
|
||||
"SwitchToPrinter": "Switch to Printer",
|
||||
"ReconnectToPrinter": "Reconnect"
|
||||
},
|
||||
"KlippyStatePanel": {
|
||||
"KlippyState": "Klippy-State",
|
||||
|
@ -496,7 +496,7 @@ export default class PageFiles extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
private input_rules = [
|
||||
(value: string) => value.indexOf(' ') === -1 || 'Name contain spaces!'
|
||||
(value: string) => value.indexOf(' ') === -1 || 'Name contains spaces!'
|
||||
]
|
||||
|
||||
get headers() {
|
||||
@ -792,11 +792,11 @@ export default class PageFiles extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
created() {
|
||||
this.$socket.emit('server.files.get_directory', { path: this.currentPath }, { action: 'files/getDirectory' })
|
||||
this.loadPath()
|
||||
}
|
||||
|
||||
loadPath() {
|
||||
this.$socket.emit('server.files.get_directory', { path: this.currentPath }, { action: 'files/getDirectory' })
|
||||
let dirArray = this.currentPath.split('/')
|
||||
this.files = findDirectory(this.filetree, dirArray)
|
||||
if (this.files !== null) {
|
||||
@ -804,46 +804,27 @@ export default class PageFiles extends Mixins(BaseMixin) {
|
||||
this.files = this.files.filter(file => file.filename !== 'thumbs' && file.filename.substr(0, 1) !== '.')
|
||||
}
|
||||
if (!this.showPrintedFiles) {
|
||||
this.files = this.files.filter(file => this.$store.getters['server/history/getPrintStatus']({
|
||||
filename: (this.currentPath+'/'+file.filename).substr(7),
|
||||
modified: file.modified.getTime()
|
||||
}) !== 'completed')
|
||||
this.files = this.files.filter(file => {
|
||||
if (file.isDirectory) return true
|
||||
else {
|
||||
return (this.$store.getters["server/history/getPrintStatusByFilename"](
|
||||
(this.currentPath+"/"+file.filename).substr(7),
|
||||
file.modified.getTime()
|
||||
) !== 'completed')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Watch('filetree', { deep: true })
|
||||
filetreeChanged(newVal: FileStateFile[]) {
|
||||
let dirArray = this.currentPath.split('/')
|
||||
this.files = findDirectory(newVal, dirArray)
|
||||
|
||||
if (this.files?.length && !this.showHiddenFiles) {
|
||||
this.files = this.files.filter(file => file.filename !== 'thumbs' && file.filename.substr(0, 1) !== '.')
|
||||
}
|
||||
|
||||
if (this.files?.length && !this.showPrintedFiles) {
|
||||
this.files = this.files.filter(file => this.$store.getters['server/history/getPrintStatus']({
|
||||
filename: (this.currentPath+'/'+file.filename).substr(7),
|
||||
modified: new Date(file.modified).getTime()
|
||||
}) !== 'completed')
|
||||
}
|
||||
filetreeChanged() {
|
||||
this.loadPath()
|
||||
}
|
||||
|
||||
@Watch('currentPath')
|
||||
currentPathChanged(newVal: string) {
|
||||
let dirArray = newVal.split('/')
|
||||
this.files = findDirectory(this.filetree, dirArray)
|
||||
|
||||
if (this.files?.length && !this.showHiddenFiles) {
|
||||
this.files = this.files.filter(file => file.filename !== 'thumbs' && file.filename.substr(0, 1) !== '.')
|
||||
}
|
||||
|
||||
if (this.files?.length && !this.showPrintedFiles) {
|
||||
this.files = this.files.filter(file => this.$store.getters['server/history/getPrintStatus']({
|
||||
filename: (this.currentPath+'/'+file.filename).substr(7),
|
||||
modified: new Date(file.modified).getTime()
|
||||
}) !== 'completed')
|
||||
}
|
||||
currentPathChanged() {
|
||||
this.loadPath()
|
||||
}
|
||||
|
||||
formatPrintTime(totalSeconds: number) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { themeDir } from '@/store/variables'
|
||||
import {defaultLogoColor, themeDir} from '@/store/variables'
|
||||
import {convertName} from '@/plugins/helpers'
|
||||
import {GetterTree} from 'vuex'
|
||||
import {FarmPrinterState} from '@/store/farm/printer/types'
|
||||
@ -37,6 +37,10 @@ export const getters: GetterTree<FarmPrinterState, any> = {
|
||||
return state.socket.port !== 80 ? state.socket.hostname+':'+state.socket.port : state.socket.hostname
|
||||
},
|
||||
|
||||
getLogoColor: (state) => {
|
||||
return state.data.gui?.theme?.logo ?? defaultLogoColor
|
||||
},
|
||||
|
||||
getStatus: (state, getters) => {
|
||||
if (!state.socket.isConnected) {
|
||||
return state.socket.isConnecting ? 'Connecting...' : 'Disconnected'
|
||||
@ -99,9 +103,9 @@ export const getters: GetterTree<FarmPrinterState, any> = {
|
||||
|
||||
getLogo: (state, getters) => {
|
||||
const acceptName = 'sidebar-logo'
|
||||
const acceptExtensions = ['gif', 'jpg', 'png', 'gif']
|
||||
const acceptExtensions = ['gif', 'jpg', 'png', 'gif', 'svg']
|
||||
|
||||
return getters['getThemeFileUrl'](acceptName, acceptExtensions) ?? '/img/logo.svg'
|
||||
return getters['getThemeFileUrl'](acceptName, acceptExtensions)
|
||||
},
|
||||
|
||||
getPosition: state => {
|
||||
|
@ -58,13 +58,11 @@ export const mutations: MutationTree<FarmPrinterState> = {
|
||||
setConfigDir(state, payload) {
|
||||
// eslint-disable-next-line
|
||||
Object.values(payload).forEach((file: any) => {
|
||||
if ('filename' in file) {
|
||||
if (file.filename.startsWith('.theme/')) {
|
||||
state.theme_files.push(file.filename)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
if (file.path?.startsWith(".theme/")) {
|
||||
state.theme_files.push(file.path)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
setDatabases(state, payload) {
|
||||
Vue.set(state, 'databases', payload.namespaces)
|
||||
|
@ -36,8 +36,8 @@ export const getters: GetterTree<FileState, any> = {
|
||||
const acceptName = 'main-background'
|
||||
const acceptExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg']
|
||||
|
||||
return getters['getThemeFileUrl'](acceptName, acceptExtensions) ?? 'transparent'
|
||||
},
|
||||
return getters['getThemeFileUrl'](acceptName, acceptExtensions)
|
||||
},
|
||||
|
||||
getCustomStylesheet: (state, getters) => {
|
||||
const acceptName = 'custom'
|
||||
|
@ -25,7 +25,13 @@ export const mutations: MutationTree<PrinterState> = {
|
||||
Object.keys(payload).forEach((key: string) => {
|
||||
const value = payload[key]
|
||||
|
||||
if (typeof value === 'object' && !Array.isArray(value) && key in currentState && value !== null) {
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
!Array.isArray(value) &&
|
||||
key in currentState &&
|
||||
value !== null &&
|
||||
currentState[key] !== null
|
||||
) {
|
||||
setDataDeep(currentState[key], value)
|
||||
} else if (key === 'temperature') {
|
||||
const newValue = Math.round(value * 10) / 10
|
||||
|
@ -183,7 +183,19 @@ export const getters: GetterTree<ServerHistoryState, any> = {
|
||||
return ''
|
||||
},
|
||||
|
||||
getPrintStatusChipColor: () => (status: string) => {
|
||||
getPrintStatusByFilename: (state) => (filename: string, modified: number) => {
|
||||
if (state.jobs.length) {
|
||||
const job = state.jobs.find((job) => {
|
||||
return job.filename === filename && Math.round(job.metadata?.modified*1000) === modified
|
||||
})
|
||||
|
||||
return job?.status ?? ""
|
||||
}
|
||||
|
||||
return ""
|
||||
},
|
||||
|
||||
getPrintStatusChipColor: () => (status: string) => {
|
||||
switch(status) {
|
||||
case 'in_progress': return 'blue accent-3' //'blue-grey darken-1'
|
||||
case 'completed': return 'green' //'green'
|
||||
|
@ -8,7 +8,11 @@ export const getters: GetterTree<SocketState, RootState> = {
|
||||
return '//' + state.hostname + (state.port !== 80 ? ':'+state.port : '')
|
||||
},
|
||||
|
||||
getWebsocketUrl: (state, getters) => {
|
||||
getHostUrl: (state) => {
|
||||
return (state.protocol === 'wss' ? 'https' : 'http')+"://" + state.hostname + '/'
|
||||
},
|
||||
|
||||
getWebsocketUrl: (state, getters) => {
|
||||
return state.protocol + ':' + getters['getUrl'] + '/websocket'
|
||||
},
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user