feature: move webcams to new db namespace (#401)

* refactor: create store for seperate webcam namespace

Signed-off-by: Stefan Dej <meteyou@gmail.com>

* refactor: update settings webcam and webcam panel to new namespace / store modules

Signed-off-by: Stefan Dej <meteyou@gmail.com>

* fix: types in webcam namespace

Signed-off-by: Stefan Dej <meteyou@gmail.com>

* feat: hide webcam panel, if no webcam is in the db

Signed-off-by: Stefan Dej <meteyou@gmail.com>

* refactor: remove debug output in settings webcam tab

Signed-off-by: Stefan Dej <meteyou@gmail.com>

* fix: margin between DependenciesPanel.vue and next panel

Signed-off-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
Stefan Dej 2021-11-02 22:12:57 +01:00 committed by GitHub
parent e8583181e1
commit 0338efd914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 301 additions and 206 deletions

View File

@ -127,7 +127,7 @@ export default class TheSidebar extends Mixins(BaseMixin) {
}
get boolNaviWebcam(): boolean {
return this.$store.state.gui.webcam.boolNavi
return this.$store.state.gui.webcamSettings.boolNavi
}
get moonrakerComponents(): string[] {

View File

@ -6,7 +6,6 @@
:collapsible="true"
card-class="dependencies-panel"
toolbar-color="orange darken-2"
class="mb-6 mb-md-9"
>
<v-card-text :class="index > 0 ? 'py-0' : 'pt-3 pb-0'" v-for="(dependency, index) in dependencies" v-bind:key="index">
<v-divider class="my-2" v-if="index"></v-divider>

View File

@ -20,7 +20,7 @@
</v-btn>
</template>
<v-list dense class="py-0">
<v-list-item link @click="currentCamName = 'all'">
<v-list-item link @click="currentCamId = 'all'">
<v-list-item-icon class="mr-0">
<v-icon small>mdi-view-grid</v-icon>
</v-list-item-icon>
@ -28,7 +28,7 @@
<v-list-item-title>{{ $t('Panels.WebcamPanel.All') }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item v-for="webcam of webcams" v-bind:key="webcam.name" link @click="currentCamName = webcam.name">
<v-list-item v-for="webcam of webcams" v-bind:key="webcam.id" link @click="currentCamId = webcam.id">
<v-list-item-icon class="mr-0">
<v-icon small>{{ webcam.icon }}</v-icon>
</v-list-item-icon>
@ -42,19 +42,19 @@
<v-card-text class="px-0 py-0 content d-inline-block">
<v-row>
<v-col class="pb-0" style="position: relative;">
<template v-if="'service' in this.currentCam && this.currentCam.service === 'grid'">
<template v-if="this.currentCam.service === 'grid'">
<webcam-grid :webcams="this.webcams"></webcam-grid>
</template>
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'mjpegstreamer'">
<template v-else-if="this.currentCam.service === 'mjpegstreamer'">
<webcam-mjpegstreamer :cam-settings="this.currentCam"></webcam-mjpegstreamer>
</template>
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'mjpegstreamer-adaptive'">
<template v-else-if="this.currentCam.service === 'mjpegstreamer-adaptive'">
<webcam-mjpegstreamer-adaptive :cam-settings="this.currentCam"></webcam-mjpegstreamer-adaptive>
</template>
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'uv4l-mjpeg'">
<template v-else-if="this.currentCam.service === 'uv4l-mjpeg'">
<webcam-uv4l-mjpeg :cam-settings="this.currentCam"></webcam-uv4l-mjpeg>
</template>
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'ipstream'">
<template v-else-if="this.currentCam.service === 'ipstream'">
<webcam-ipstreamer :cam-settings="this.currentCam"></webcam-ipstreamer>
</template>
<template v-else>
@ -73,10 +73,10 @@ import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
import WebcamGrid from '@/components/webcams/WebcamGrid.vue'
import Component from 'vue-class-component'
import {Mixins} from 'vue-property-decorator'
import {Mixins, Prop} from 'vue-property-decorator'
import BaseMixin from '../mixins/base'
import {GuiStateWebcam} from '@/store/gui/types'
import Panel from '@/components/ui/Panel.vue'
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
@Component({
components: {
@ -89,39 +89,35 @@ import Panel from '@/components/ui/Panel.vue'
}
})
export default class WebcamPanel extends Mixins(BaseMixin) {
@Prop({ default: 'dashboard' }) viewport?: string
get webcams(): GuiStateWebcam[] {
return this.$store.getters['gui/getWebcams']
get webcams(): GuiWebcamStateWebcam[] {
return this.$store.getters['gui/webcam/getWebcams']
}
get currentCamName(): string {
let currentCamName = this.$store.state.gui.webcam.selectedCam
if (currentCamName !== undefined && this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === currentCamName) !== -1)
return currentCamName
get currentCamId(): string {
if (this.webcams.length === 1) return this.webcams[0].id ?? 'all'
if (currentCamName !== undefined && Array.isArray(this.webcams) && this.webcams.length === 1)
return this.webcams[0].name
return 'all'
let currentCamId = this.$store.state.gui.webcamSettings.currentCam[this.viewport ?? ''] ?? 'all'
if (this.webcams.findIndex((webcam: GuiWebcamStateWebcam) => webcam.id === currentCamId) !== -1)
return currentCamId
else if (currentCamId !== undefined && this.webcams.length === 1)
return this.webcams[0].id ?? ''
else return 'all'
}
set currentCamName(newVal: string) {
this.$store.dispatch('gui/saveSetting', { name: 'webcam.selectedCam', value: newVal })
set currentCamId(newVal: string) {
this.$store.dispatch('gui/setCurrentWebcam', { viewport: this.viewport, value: newVal })
}
get currentCam(): any {
if (this.currentCamName === 'all') {
return {
name: this.$t('Panels.WebcamPanel.All'),
service: 'grid',
icon: 'mdi-view-grid',
}
} else {
const currentCam = this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === this.currentCamName)
if (currentCam !== -1) return this.webcams[currentCam]
}
const cam = this.webcams.find((cam: GuiWebcamStateWebcam) => cam.id === this.currentCamId)
return {}
return cam ?? {
name: this.$t('Panels.WebcamPanel.All'),
service: 'grid',
icon: 'mdi-view-grid',
}
}
}
</script>

View File

@ -40,6 +40,10 @@
<v-switch v-model="boolBigThumbnail" hide-details class="mt-0"></v-switch>
</settings-row>
<v-divider class="my-2"></v-divider>
<settings-row :title="$t('Settings.UiSettingsTab.ShowWebcamInNavigation')">
<v-switch v-model="boolWebcamInNavigation" hide-details class="mt-0"></v-switch>
</settings-row>
<v-divider class="my-2"></v-divider>
<settings-row :title="$t('Settings.UiSettingsTab.DisplayCANCEL_PRINT')" :sub-title="$t('Settings.UiSettingsTab.DisplayCANCEL_PRINTDescription')" :dynamicSlotWidth="true">
<v-switch v-model="displayCancelPrint" hide-details class="mt-0"></v-switch>
</settings-row>
@ -99,6 +103,14 @@ export default class SettingsUiSettingsTab extends Mixins(BaseMixin) {
this.$store.dispatch('gui/saveSetting', {name: 'dashboard.boolBigThumbnail', value: newVal })
}
get boolWebcamInNavigation() {
return this.$store.state.gui.webcamSettings.boolNavi ?? false
}
set boolWebcamInNavigation(newVal) {
this.$store.dispatch('gui/saveSetting', { name: 'webcamSettings.boolNavi', value: newVal })
}
get displayCancelPrint() {
return this.$store.state.gui.general.displayCancelPrint
}

View File

@ -2,16 +2,14 @@
<div>
<v-card flat v-if="!form.bool">
<v-card-text>
<settings-row :title="$t('Settings.WebcamTab.ShowInNavigation')">
<v-switch v-model="boolNavi" hide-details class="mt-0"></v-switch>
</settings-row>
<div v-for="(webcam) in this.webcams" v-bind:key="webcam.index">
<h3 class="text-h5 mb-3">{{ $t('Settings.WebcamTab.Webcams') }}</h3>
<div v-for="(webcam) in webcams" v-bind:key="webcam.id">
<v-divider class="my-2"></v-divider>
<settings-row :title="webcam.name" :icon="webcam.icon" :sub-title="getSubtitle(webcam)">
<v-btn small outlined @click="editWebcam(webcam)">
<v-icon small left>mdi-pencil</v-icon> {{ $t('Settings.Edit') }}
</v-btn>
<v-btn small outlined @click="deleteWebcam(webcam.index)" class="ml-3 minwidth-0 px-2" color="error">
<v-btn small outlined @click="deleteWebcam(webcam.id)" class="ml-3 minwidth-0 px-2" color="error">
<v-icon small>mdi-delete</v-icon>
</v-btn>
</settings-row>
@ -24,7 +22,7 @@
<v-card flat v-else>
<v-form v-model="form.valid" @submit.prevent="saveWebcam">
<v-card-title>
{{ form.index === null ? $t("Settings.WebcamTab.CreateWebcam") : $t("Settings.WebcamTab.EditWebcam") }}
{{ form.id === null ? $t("Settings.WebcamTab.CreateWebcam") : $t("Settings.WebcamTab.EditWebcam") }}
</v-card-title>
<v-card-text>
<v-row>
@ -64,13 +62,23 @@
<v-row>
<v-col class="py-1">
<v-text-field
v-model="form.url"
:label="$t('Settings.WebcamTab.WebcamURL')"
v-model="form.urlStream"
:label="$t('Settings.WebcamTab.UrlStream')"
hide-details="auto"
:rules="[rules.required]"
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col class="py-1">
<v-text-field
v-model="form.urlSnapshot"
:label="$t('Settings.WebcamTab.UrlSnapshot')"
hide-details="auto"
:rules="[rules.requiredMjpegAdaptive]"
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col class="py-1">
<v-select
@ -113,14 +121,14 @@
</v-col>
<v-col class="col-12 col-sm-6 text-center" align-self="center">
<vue-load-image v-if="['mjpegstreamer', 'mjpegstreamer-adaptive', 'uv4l-mjpeg'].includes(form.service)">
<img slot="image" :src="form.url" alt="Preview" :style="webcamStyle" class="webcamImage" />
<img slot="image" :src="form.service === 'mjpegstreamer-adaptive' ? form.urlSnapshot : form.urlStream" alt="Preview" :style="webcamStyle" class="webcamImage" />
<v-progress-circular slot="preloader" indeterminate color="primary"></v-progress-circular>
<template slot="error">
<v-icon x-large>mdi-webcam-off</v-icon>
<div class="subtitle-1 mt-2">{{ $t('Settings.WebcamTab.UrlNotAvailable') }}</div>
</template>
</vue-load-image>
<video v-if="['ipstream'].includes(form.service)" :src="form.url" autoplay :style="webcamStyle" />
<video v-if="['ipstream'].includes(form.service)" :src="form.urlStream" autoplay :style="webcamStyle" />
</v-col>
</v-row>
</v-card-text>
@ -136,7 +144,7 @@
text
type="submit"
>
{{ form.index === null ? $t("Settings.WebcamTab.SaveWebcam") : $t("Settings.WebcamTab.UpdateWebcam") }}
{{ form.id === null ? $t("Settings.WebcamTab.SaveWebcam") : $t("Settings.WebcamTab.UpdateWebcam") }}
</v-btn>
</v-card-actions>
</v-form>
@ -149,17 +157,18 @@
import {Component, Mixins} from 'vue-property-decorator'
import BaseMixin from '../mixins/base'
import SettingsRow from '@/components/settings/SettingsRow.vue'
import {GuiStateWebcam} from '@/store/gui/types'
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
interface webcamForm {
bool: boolean
index: number | null
id: string | null
valid: boolean
name: string
icon: string
service: string
targetFps: number
url: string
urlStream: string
urlSnapshot: string
flipX: boolean
flipY: boolean
}
@ -171,40 +180,26 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
private form: webcamForm = {
bool: false,
index: null,
id: null,
valid: false,
name: '',
icon: '',
service: '',
targetFps: 15,
url: '',
urlStream: '',
urlSnapshot: '',
flipX: false,
flipY: false,
}
private rules = {
required: (value: string) => value !== '' || this.$t('Settings.WebcamTab.Required'),
requiredMjpegAdaptive: (value: string) => (value !== '' && this.form.service === 'mjpegstreamer-adaptive') || this.$t('Settings.WebcamTab.Required'),
unique: (value: string) => !this.existsWebcamName(value) || this.$t('Settings.WebcamTab.NameAlreadyExists'),
}
get webcams() {
return this.$store.getters['gui/getWebcams'] ?? []
}
get boolDashboard() {
return this.$store.state.gui.webcam.boolDashboard ?? false
}
set boolDashboard(newVal) {
this.$store.dispatch('gui/saveSetting', { name: 'webcam.boolDashboard', value: newVal })
}
get boolNavi() {
return this.$store.state.gui.webcam.boolNavi ?? false
}
set boolNavi(newVal) {
this.$store.dispatch('gui/saveSetting', { name: 'webcam.boolNavi', value: newVal })
return this.$store.getters['gui/webcam/getWebcams'] ?? []
}
get iconItems() {
@ -240,12 +235,12 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
return ''
}
getSubtitle(webcam: GuiStateWebcam) {
return webcam.url
getSubtitle(webcam: GuiWebcamStateWebcam) {
return 'URL: '+ (webcam.service === 'mjpegstreamer-adaptive' ? webcam.urlSnapshot : webcam.urlStream)
}
existsWebcamName(name: string) {
return (this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === name && webcam.index !== this.form.index) !== -1)
return (this.webcams.findIndex((webcam: GuiWebcamStateWebcam) => webcam.name === name && webcam.id !== this.form.id) !== -1)
}
createWebcam() {
@ -254,13 +249,14 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
this.form.bool = true
}
editWebcam(webcam: GuiStateWebcam) {
this.form.index = webcam.index ?? null
editWebcam(webcam: GuiWebcamStateWebcam) {
this.form.id = webcam.id ?? null
this.form.name = webcam.name
this.form.icon = webcam.icon
this.form.service = webcam.service
this.form.targetFps = webcam.targetFps
this.form.url = webcam.url
this.form.urlStream = webcam.urlStream
this.form.urlSnapshot = webcam.urlSnapshot
this.form.flipX = webcam.flipX
this.form.flipY = webcam.flipY
@ -270,25 +266,37 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
saveWebcam() {
if (this.form.valid) {
if (this.form.index !== null) this.$store.dispatch('gui/updateWebcam', {...this.form})
else this.$store.dispatch('gui/addWebcam', {...this.form})
const values = {
name: this.form.name,
icon: this.form.icon,
service: this.form.service,
targetFps: this.form.targetFps,
urlStream: this.form.urlStream,
urlSnapshot: this.form.urlSnapshot,
flipX: this.form.flipX,
flipY: this.form.flipY,
}
if (this.form.id !== null) this.$store.dispatch('gui/webcam/update', { id: this.form.id, values: values })
else this.$store.dispatch('gui/webcam/store', { values })
this.clearDialog()
}
}
deleteWebcam(index: number) {
this.$store.dispatch('gui/deleteWebcam', { index: index })
deleteWebcam(id: string) {
this.$store.dispatch('gui/webcam/delete', id)
}
clearDialog() {
this.form.bool = false
this.form.index = null
this.form.id = null
this.form.name = ''
this.form.icon = 'mdi-webcam'
this.form.service = 'mjpegstreamer-adaptive'
this.form.targetFps = 15
this.form.url = '/webcam/?action=stream'
this.form.urlStream = '/webcam/?action=stream'
this.form.urlSnapshot = '/webcam/?action=snapshot'
this.form.flipX = false
this.form.flipY = false
}

View File

@ -26,7 +26,7 @@ export default class Ipstreamer extends Mixins(BaseMixin) {
get url() {
if (!this.isVisible) return ''
return this.camSettings.url || ''
return this.camSettings.urlStream || ''
}
get webcamStyle() {

View File

@ -40,7 +40,7 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
}
get url() {
const baseUrl = this.camSettings.url
const baseUrl = this.camSettings.urlStream
const url = new URL(baseUrl, this.printerUrl === undefined ? this.hostUrl.toString() : this.printerUrl)
url.searchParams.append('bypassCache', this.refresh.toString())

View File

@ -98,11 +98,10 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
}
async setFrame() {
const baseUrl = this.camSettings.url
const baseUrl = this.camSettings.urlSnapshot
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 = (this.time > 0) ? Math.round(1000 / this.time) : 0

View File

@ -20,18 +20,18 @@
<script lang="ts">
import {Component, Mixins, Prop} from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import {GuiStateWebcam} from '@/store/gui/types'
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
@Component
export default class Uv4lMjpeg extends Mixins(BaseMixin) {
private isVisible = true
@Prop({ required: true }) readonly camSettings!: GuiStateWebcam
@Prop({ required: true }) readonly camSettings!: GuiWebcamStateWebcam
@Prop({ default: null }) readonly printerUrl!: string | null
get url() {
const baseUrl = this.camSettings.url
const baseUrl = this.camSettings.urlStream
const url = new URL(baseUrl, this.printerUrl === null ? this.hostUrl.toString() : this.printerUrl)
return decodeURIComponent(url.toString())

View File

@ -7,19 +7,19 @@
<v-row dense>
<v-col
v-for="webcam in webcams"
:key="webcam.name"
:key="webcam.id"
cols="6"
>
<template v-if="'service' in webcam && webcam.service === 'mjpegstreamer'">
<template v-if="webcam.service === 'mjpegstreamer'">
<webcam-mjpegstreamer :cam-settings="webcam"></webcam-mjpegstreamer>
</template>
<template v-else-if="'service' in webcam && webcam.service === 'mjpegstreamer-adaptive'">
<template v-else-if="webcam.service === 'mjpegstreamer-adaptive'">
<webcam-mjpegstreamer-adaptive :cam-settings="webcam"></webcam-mjpegstreamer-adaptive>
</template>
<template v-else-if="'service' in webcam && webcam.service === 'uv4l-mjpeg'">
<template v-else-if="webcam.service === 'uv4l-mjpeg'">
<webcam-uv4l-mjpeg :cam-settings="webcam"></webcam-uv4l-mjpeg>
</template>
<template v-else-if="'service' in webcam && webcam.service === 'ipstream'">
<template v-else-if="webcam.service === 'ipstream'">
<webcam-ipstreamer :cam-settings="webcam"></webcam-ipstreamer>
</template>
<template v-else>
@ -37,7 +37,7 @@ import Mjpegstreamer from '@/components/webcams/Mjpegstreamer.vue'
import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vue'
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
import {GuiStateWebcam} from '@/store/gui/types'
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
@Component({
components: {
@ -49,6 +49,6 @@ import {GuiStateWebcam} from '@/store/gui/types'
})
export default class WebcamGrid extends Mixins(BaseMixin) {
@Prop() readonly webcams!: GuiStateWebcam[]
@Prop() readonly webcams!: GuiWebcamStateWebcam[]
}
</script>

View File

@ -526,7 +526,6 @@
},
"WebcamTab": {
"Webcams": "Webcams",
"ShowInNavigation": "Show in navigation",
"AddWebcam": "add webcam",
"CreateWebcam": "Create Webcam",
"EditWebcam": "Edit Webcam",
@ -552,7 +551,8 @@
"UrlNotAvailable": "URL not available",
"Name": "Name",
"WebcamURL": "Webcam URL",
"UrlStream": "URL Stream",
"UrlSnapshot": "URL Snapshot",
"Service": "Service",
"TargetFPS": "Target FPS",
"FlipHorizontally": "Flip webcam horizontally",
@ -666,6 +666,7 @@
"GcodeThumbnails": "Gcode thumbnails",
"GcodeThumbnailsDescription": "Click on the button to get to the instructions.",
"Guide": "Guide",
"ShowWebcamInNavigation": "Show Webcam in navigation",
"BoolBigThumbnail": "Large thumbnail",
"BoolBigThumbnailDescription": "Display a large thumbnail in the status panel during a print.",
"DisplayCANCEL_PRINT": "Display CANCEL_PRINT",

View File

@ -6,7 +6,7 @@
<div>
<v-row>
<v-col col-12>
<webcam-panel></webcam-panel>
<webcam-panel viewport="page"></webcam-panel>
</v-col>
</v-row>
</div>

View File

@ -11,6 +11,7 @@ export const actions: ActionTree<GuiState, RootState> = {
},
init({ commit, dispatch, rootState }, payload) {
window.console.debug('init gui')
if (
payload.value.dashboard?.control !== undefined &&
'useCross' in payload.value.dashboard?.control
@ -20,25 +21,34 @@ export const actions: ActionTree<GuiState, RootState> = {
delete payload.value.dashboard?.control.useCross
}
if (payload.value.webcam) {
window.console.debug('convert old webcam')
if (payload.value.webcam.configs && payload.value.webcam.configs.length) {
payload.value.webcam.configs.forEach((oldWebcam: any) => {
const newWebcam = {...oldWebcam, urlStream: oldWebcam.url, urlSnapshot: oldWebcam.url.replace('action=stream', 'action=snapshot')}
delete newWebcam.url
dispatch('webcam/store', { values: newWebcam })
})
}
commit('saveSetting', { name: 'webcamSettings.boolNavi', value: payload.value.webcam.boolNavi })
Vue.$socket.emit('server.database.delete_item', { namespace: 'mainsail', key: 'webcam' })
}
commit('setData', payload.value)
// init remote printers, when remoteMode is off
if (!rootState.socket?.remoteMode) dispatch('farm/readStoredPrinters', {}, { root: true })
dispatch('gui/webcam/init', null, { root: true })
dispatch('printer/init', null, { root: true })
},
updateDataFromDB({ commit }, payload) {
commit('saveSetting', {
name: payload.key,
value: payload.value
})
},
saveSetting({ commit }, payload) {
commit('saveSetting', payload)
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: payload.name, value: payload.value }, { action: 'gui/updateDataFromDB' })
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: payload.name, value: payload.value })
},
updateSettings(_, payload) {
@ -51,7 +61,7 @@ export const actions: ActionTree<GuiState, RootState> = {
!Array.isArray(payload.value[keyName])
) newState = Object.assign(payload.value[keyName], {...newState})
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: keyName, value: newState }, { action: 'gui/updateDataFromDB' })
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: keyName, value: newState })
},
setGcodefilesMetadata({ commit, dispatch, state }, data) {
@ -70,6 +80,14 @@ export const actions: ActionTree<GuiState, RootState> = {
})
},
setCurrentWebcam({ commit, dispatch, state }, payload) {
commit('setCurrentWebcam', payload)
dispatch('updateSettings', {
keyName: 'webcamSettings.currentCam',
newVal: state.webcamSettings.currentCam
})
},
addPreset({ commit, dispatch, state }, payload) {
commit('addPreset', payload)
dispatch('updateSettings', {
@ -118,30 +136,6 @@ export const actions: ActionTree<GuiState, RootState> = {
})
},
addWebcam({ commit, dispatch, state }, payload) {
commit('addWebcam', payload)
dispatch('updateSettings', {
keyName: 'webcam.configs',
newVal: state.webcam.configs
})
},
updateWebcam({ commit, dispatch, state }, payload) {
commit('updateWebcam', payload)
dispatch('updateSettings', {
keyName: 'webcam.configs',
newVal: state.webcam.configs
})
},
deleteWebcam({ commit, dispatch, state }, payload) {
commit('deleteWebcam', payload)
dispatch('updateSettings', {
keyName: 'webcam.configs',
newVal: state.webcam.configs
})
},
setTempchartDatasetAdditionalSensorSetting({ commit, dispatch, state }, payload) {
commit('setTempchartDatasetAdditionalSensorSetting', payload)
dispatch('updateSettings', {

View File

@ -42,16 +42,6 @@ export const getters: GetterTree<GuiState, any> = {
return output
},
getWebcams:(state) => {
const output = []
for (const [key, webcam] of Object.entries(state.webcam.configs)) {
output.push(Object.assign({}, webcam, { index: key }))
}
return caseInsensitiveSort(output, 'name')
},
getDatasetValue: (state) => (payload: { name: string, type: string }) => {
if (
payload.name in state.tempchart.datasetSettings &&
@ -133,6 +123,10 @@ export const getters: GetterTree<GuiState, any> = {
}
}
if (getters['webcam/getWebcams'].length === 0) {
panels = panels.filter((element: any) => element.name !== 'webcam')
}
return panels
}
}

View File

@ -5,6 +5,9 @@ import { mutations } from '@/store/gui/mutations'
import { getters } from '@/store/gui/getters'
import {defaultLogoColor, defaultPrimaryColor} from '@/store/variables'
// load modules
import { webcam } from '@/store/gui/webcam'
export const getDefaultState = (): GuiState => {
return {
general: {
@ -98,19 +101,12 @@ export const getDefaultState = (): GuiState => {
],
nonExpandPanels: []
},
webcam: {
selectedCam: '',
boolDashboard: false,
webcamSettings: {
currentCam: {
dashboard: 'all',
page: 'all'
},
boolNavi: false,
configs: [{
name: 'Default',
icon: 'mdi-webcam',
service: 'mjpegstreamer-adaptive',
targetFps: 15,
url: '/webcam/?action=stream',
flipX: false,
flipY: false,
}],
},
tempchart: {
autoscale: false,
@ -209,5 +205,8 @@ export const gui: Module<GuiState, any> = {
state,
getters,
actions,
mutations
mutations,
modules: {
webcam
}
}

View File

@ -28,7 +28,7 @@ export const mutations: MutationTree<GuiState> = {
saveSetting(state, payload) {
// eslint-disable-next-line
const deepSet = (obj:any, is:string[] | string, value:any):any => {
const deepSet = (obj:any, is:string[] | string, value:any):any => {
if (is !== undefined && typeof is === 'string')
return deepSet(obj,is.split('.'), value)
else if (is.length==1 && value !== undefined)
@ -62,6 +62,10 @@ export const mutations: MutationTree<GuiState> = {
Vue.set(state.gcodefiles, 'showHiddenFiles', value)
},
setCurrentWebcam(state, payload) {
Vue.set(state.webcamSettings.currentCam, payload.viewport, payload.value)
},
addPreset(state, payload) {
state.presets.push({
name: payload.name,
@ -106,43 +110,6 @@ export const mutations: MutationTree<GuiState> = {
}
},
addWebcam(state, payload) {
const newWebcam = {
name: payload.name,
icon: payload.icon,
service: payload.service,
targetFps: payload.targetFps,
url: payload.url,
flipX: payload.flipX,
flipY: payload.flipY,
}
state.webcam.configs.push(newWebcam)
},
updateWebcam(state, payload) {
if (state.webcam.configs[payload.index]) {
const webcam = {...state.webcam}
webcam.configs[payload.index] = {
name: payload.name,
icon: payload.icon,
service: payload.service,
targetFps: payload.targetFps,
url: payload.url,
flipX: payload.flipX,
flipY: payload.flipY,
}
Vue.set(state, 'webcam', webcam)
}
},
deleteWebcam(state, payload) {
if (state.webcam.configs[payload.index]) {
state.webcam.configs.splice(payload.index, 1)
}
},
setHistoryColumns(state, data) {
if (data.value && state.history.hideColums.includes(data.name)) {
state.history.hideColums.splice(state.history.hideColums.indexOf(data.name), 1)

View File

@ -1,25 +1,15 @@
export interface GuiState {
webcam: {
selectedCam: string
boolDashboard: boolean,
boolNavi: boolean,
configs: GuiStateWebcam[]
webcamSettings: {
currentCam: {
dashboard: string
page: string
}
boolNavi: boolean
}
presets: GuiStatePreset[]
[key: string]: any
}
export interface GuiStateWebcam {
index?: number | null
name: string
icon: string
service: 'mjpegstreamer' | 'mjpegstreamer-adaptive' | 'uv4l-mjpeg' | 'ipstream'
targetFps: number
url: string
flipX: boolean
flipY: boolean
}
export interface GuiStatePreset {
index?: number | null
name: string

View File

@ -0,0 +1,48 @@
import { ActionTree } from 'vuex'
import {RootState} from '@/store/types'
import {GuiWebcamState} from '@/store/gui/webcam/types'
import { v4 as uuidv4 } from 'uuid'
import Vue from 'vue'
export const actions: ActionTree<GuiWebcamState, RootState> = {
reset({ commit }) {
commit('reset')
},
init() {
window.console.debug('init gui/webcam')
Vue.$socket.emit('server.database.get_item', { namespace: 'webcams' }, { action: 'gui/webcam/initStore' })
},
initStore({ commit }, payload) {
commit('reset')
commit('initStore', payload)
},
upload(_, payload) {
Vue.$socket.emit('server.database.post_item', { namespace: 'webcams', key: payload.id, value: payload.value })
},
store({ commit, dispatch, state }, payload) {
const id = uuidv4()
commit('store', { id, values: payload.values })
dispatch('upload', {
id,
value: state.webcams[id]
})
},
update({ commit, dispatch, state }, payload) {
commit('update', payload)
dispatch('upload', {
id: payload.id,
value: state.webcams[payload.id]
})
},
delete({ commit }, payload) {
commit('delete', payload)
Vue.$socket.emit('server.database.delete_item', { namespace: 'webcams', key: payload })
},
}

View File

@ -0,0 +1,15 @@
import { GetterTree } from 'vuex'
import {GuiWebcamState, GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
// eslint-disable-next-line
export const getters: GetterTree<GuiWebcamState, any> = {
getWebcams:(state) => {
const webcams: GuiWebcamStateWebcam[] = []
Object.keys(state.webcams).forEach((id: string) => {
webcams.push({...state.webcams[id], id})
})
return webcams
},
}

View File

@ -0,0 +1,23 @@
import { Module } from 'vuex'
import { actions } from '@/store/gui/webcam/actions'
import { mutations } from '@/store/gui/webcam/mutations'
import { getters } from '@/store/gui/webcam/getters'
import {GuiWebcamState} from '@/store/gui/webcam/types'
export const getDefaultState = (): GuiWebcamState => {
return {
webcams: {}
}
}
// initial state
const state = getDefaultState()
// eslint-disable-next-line
export const webcam: Module<GuiWebcamState, any> = {
namespaced: true,
state,
getters,
actions,
mutations
}

View File

@ -0,0 +1,33 @@
import { getDefaultState } from './index'
import {MutationTree} from 'vuex'
import {GuiWebcamState} from '@/store/gui/webcam/types'
import Vue from 'vue'
export const mutations: MutationTree<GuiWebcamState> = {
reset(state) {
Object.assign(state, getDefaultState())
},
initStore(state, payload) {
Vue.set(state, 'webcams', payload.value)
},
store(state, payload) {
Vue.set(state.webcams, payload.id, payload.values)
},
update(state, payload) {
if (payload.id in state.webcams) {
const webcam = {...state.webcams[payload.id]}
Object.assign(webcam, payload.values)
Vue.set(state.webcams, payload.id, webcam)
}
},
delete(state, payload) {
if (payload in state.webcams) {
Vue.delete(state.webcams, payload)
}
},
}

View File

@ -0,0 +1,17 @@
export interface GuiWebcamState {
webcams: {
[key: string]: GuiWebcamStateWebcam
},
}
export interface GuiWebcamStateWebcam {
id?: string
name: string
icon: string
service: 'mjpegstreamer' | 'mjpegstreamer-adaptive' | 'uv4l-mjpeg' | 'ipstream'
targetFps: number
urlStream: string
urlSnapshot: string
flipX: boolean
flipY: boolean
}