@fdm-monster/client-next 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.all-contributorsrc +57 -0
- package/.browserslistrc +4 -0
- package/.editorconfig +5 -0
- package/.env +1 -0
- package/.eslintrc-auto-import.json +73 -0
- package/.eslintrc.js +126 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/workflows/release-client.yml +94 -0
- package/.github/workflows/vue-publish.yml +26 -0
- package/.prettierignore +15 -0
- package/.prettierrc.cjs +7 -0
- package/.whitesource +12 -0
- package/.yarn/releases/yarn-4.5.1.cjs +934 -0
- package/.yarnrc.yml +3 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/README.md +93 -0
- package/RELEASE_NOTES.MD +11 -0
- package/index.html +16 -0
- package/package.default.json +42 -0
- package/package.json +26 -0
- package/public/favicon.ico +0 -0
- package/public/img/DavidZwart.jpg +0 -0
- package/public/img/OIG.JYDC2RaWdz7g9.jpg +0 -0
- package/public/img/OIG.jpg +0 -0
- package/public/img/icons/android-chrome-192x192.png +0 -0
- package/public/img/icons/android-chrome-256x256.png +0 -0
- package/public/img/icons/android-chrome-384x384.png +0 -0
- package/public/img/icons/android-chrome-512x512.png +0 -0
- package/public/img/icons/favicon.svg +1 -0
- package/public/img/logo.png +0 -0
- package/public/img/logo.svg +1 -0
- package/public/img/manifest.webmanifest +33 -0
- package/public/img/octoprint-tentacle.svg +144 -0
- package/public/img/thumbail_unknown.jpg +0 -0
- package/public/img/vbanner.jpg +0 -0
- package/public/index.html +17 -0
- package/public/robots.txt +2 -0
- package/renovate.json +30 -0
- package/src/App.vue +60 -0
- package/src/AppLoader.vue +383 -0
- package/src/assets/adjectives.json +1468 -0
- package/src/assets/android-chrome-192x192.png +0 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/logo.svg +6 -0
- package/src/assets/nouns.json +4309 -0
- package/src/auto-imports.d.ts +139 -0
- package/src/backend/app.service.ts +39 -0
- package/src/backend/auth.service.ts +56 -0
- package/src/backend/base.service.ts +57 -0
- package/src/backend/batch.service.ts +37 -0
- package/src/backend/camera-stream.service.ts +33 -0
- package/src/backend/custom-gcode.service.ts +11 -0
- package/src/backend/dto/octoprint-settings.dto.ts +168 -0
- package/src/backend/first-time-setup.service.ts +17 -0
- package/src/backend/floor.service.ts +84 -0
- package/src/backend/index.ts +4 -0
- package/src/backend/print-completions.service.ts +11 -0
- package/src/backend/printer-file.service.ts +91 -0
- package/src/backend/printer-group.service.ts +62 -0
- package/src/backend/printer-job.service.ts +20 -0
- package/src/backend/printer-settings.service.ts +28 -0
- package/src/backend/printers.service.ts +136 -0
- package/src/backend/server-private.service.ts +55 -0
- package/src/backend/server.api.ts +132 -0
- package/src/backend/settings.service.ts +85 -0
- package/src/backend/user.service.ts +51 -0
- package/src/components/AboutHelp/AboutView.vue +164 -0
- package/src/components/CameraGrid/CameraGridView.vue +111 -0
- package/src/components/FirstTimeSetup/FirstTimeSetupView.vue +354 -0
- package/src/components/Generic/Actions/PrinterConnectionAction.vue +56 -0
- package/src/components/Generic/Actions/PrinterCreateAction.vue +22 -0
- package/src/components/Generic/Actions/PrinterDeleteAction.vue +29 -0
- package/src/components/Generic/Actions/PrinterQuickStopAction.vue +35 -0
- package/src/components/Generic/Actions/PrinterSettingsAction.vue +35 -0
- package/src/components/Generic/Actions/PrinterUrlAction.vue +24 -0
- package/src/components/Generic/Actions/RefreshFilesAction.vue +50 -0
- package/src/components/Generic/Actions/SyncPrinterNameAction.vue +36 -0
- package/src/components/Generic/Dialogs/AddOrUpdateCameraStreamDialog.vue +131 -0
- package/src/components/Generic/Dialogs/AddOrUpdateFloorDialog.vue +141 -0
- package/src/components/Generic/Dialogs/AddOrUpdatePrinterDialog.vue +303 -0
- package/src/components/Generic/Dialogs/BaseDialog.vue +81 -0
- package/src/components/Generic/Dialogs/BatchJsonCreateDialog.vue +109 -0
- package/src/components/Generic/Dialogs/BatchReprintDialog.vue +190 -0
- package/src/components/Generic/Dialogs/PrinterChecksPanel.vue +37 -0
- package/src/components/Generic/Dialogs/PrinterControlDialog.vue +202 -0
- package/src/components/Generic/Dialogs/PrinterMaintenanceDialog.vue +130 -0
- package/src/components/Generic/Dialogs/YamlImportExportDialog.vue +186 -0
- package/src/components/Generic/Dialogs/dialog.constants.ts +19 -0
- package/src/components/Generic/FileExplorerSideNav.vue +734 -0
- package/src/components/Generic/Loaders/GridLoader.vue +68 -0
- package/src/components/Generic/NavigationDrawer.vue +69 -0
- package/src/components/Generic/PrintJobsMenu.vue +148 -0
- package/src/components/Generic/Snackbars/AppErrorSnackbar.vue +64 -0
- package/src/components/Generic/Snackbars/AppInfoSnackbar.vue +63 -0
- package/src/components/Generic/Snackbars/AppProgressSnackbar.vue +158 -0
- package/src/components/Generic/Vuetify/TooltipButton.vue +47 -0
- package/src/components/HelpOverlay/HelpOverlay.vue +57 -0
- package/src/components/Login/LoginForm.vue +206 -0
- package/src/components/Login/LoginView.spec.ts +64 -0
- package/src/components/Login/LoginView.vue +65 -0
- package/src/components/Login/Logo.vue +13 -0
- package/src/components/Login/PermissionDenied.vue +109 -0
- package/src/components/Login/RegistrationForm.vue +207 -0
- package/src/components/Login/RegistrationView.vue +17 -0
- package/src/components/Login/__snapshots__/LoginView.spec.ts.snap +1051 -0
- package/src/components/NotFound/NotFoundView.vue +39 -0
- package/src/components/PrintStatistics/PrintStatistics.vue +168 -0
- package/src/components/PrintStatistics/PrintStatisticsView.vue +15 -0
- package/src/components/PrinterGrid/HomeToolbar.vue +90 -0
- package/src/components/PrinterGrid/PrinterGrid.vue +164 -0
- package/src/components/PrinterGrid/PrinterGridTile.vue +438 -0
- package/src/components/PrinterGrid/PrinterGridView.vue +210 -0
- package/src/components/PrinterList/FileControlList.vue +40 -0
- package/src/components/PrinterList/PrinterDetails.vue +91 -0
- package/src/components/PrinterList/PrintersView.vue +492 -0
- package/src/components/Settings/AccountSettings.vue +163 -0
- package/src/components/Settings/DiagnosticsSettings.vue +137 -0
- package/src/components/Settings/EmergencyCommands.vue +265 -0
- package/src/components/Settings/FloorSettings.vue +276 -0
- package/src/components/Settings/GridSettings.vue +127 -0
- package/src/components/Settings/OctoPrintSettings.vue +188 -0
- package/src/components/Settings/ServerProtectionSettings.vue +370 -0
- package/src/components/Settings/SettingsView.vue +73 -0
- package/src/components/Settings/SoftwareUpgradeSettings.vue +297 -0
- package/src/components/Settings/UserManagementSettings.vue +257 -0
- package/src/components/TopBar.vue +147 -0
- package/src/components.d.ts +70 -0
- package/src/directives/file-upload.directive.ts +117 -0
- package/src/directives/printer-drop-position.directive.ts +92 -0
- package/src/env.d.ts +6 -0
- package/src/main.ts +76 -0
- package/src/models/batch/reprint.dto.ts +79 -0
- package/src/models/batch.model.ts +11 -0
- package/src/models/camera-streams/camera-stream.ts +19 -0
- package/src/models/floors/floor.model.ts +30 -0
- package/src/models/octoprint/connection-options.model.ts +8 -0
- package/src/models/plugins/firmware-updates/prusa-firmware-release.model.ts +57 -0
- package/src/models/print-completions/print-completions.model.ts +49 -0
- package/src/models/printers/crud/create-printer.model.ts +26 -0
- package/src/models/printers/file-upload-commands.model.ts +4 -0
- package/src/models/printers/gcode/gcode-analysis.model.ts +30 -0
- package/src/models/printers/printer-current-job.model.ts +90 -0
- package/src/models/printers/printer-file.model.ts +48 -0
- package/src/models/printers/printer.model.ts +18 -0
- package/src/models/server/client-releases.model.ts +27 -0
- package/src/models/server/export-yaml.model.ts +11 -0
- package/src/models/server/features.model.ts +37 -0
- package/src/models/server/github-rate-limit.model.ts +21 -0
- package/src/models/server/version.model.ts +14 -0
- package/src/models/settings/printer-file-clean-settings.model.ts +5 -0
- package/src/models/settings/server-settings.dto.ts +19 -0
- package/src/models/settings/settings.model.ts +57 -0
- package/src/models/socketio-messages/socketio-message.model.ts +53 -0
- package/src/models/uploads/queued-upload.model.ts +12 -0
- package/src/models/user.model.ts +15 -0
- package/src/plugins/README.md +3 -0
- package/src/plugins/index.ts +17 -0
- package/src/plugins/vuetify.ts +53 -0
- package/src/router/index.ts +192 -0
- package/src/router/route-names.ts +14 -0
- package/src/router/utils.ts +23 -0
- package/src/shared/alert.events.ts +14 -0
- package/src/shared/app.constants.ts +23 -0
- package/src/shared/auth.constants.ts +34 -0
- package/src/shared/dialog.composable.ts +41 -0
- package/src/shared/drag.constants.ts +19 -0
- package/src/shared/experimental.constants.ts +1 -0
- package/src/shared/http-client.ts +162 -0
- package/src/shared/noun-adjectives.data.ts +24 -0
- package/src/shared/printer-grid.constants.ts +5 -0
- package/src/shared/printer-state.constants.ts +194 -0
- package/src/shared/snackbar.composable.ts +66 -0
- package/src/shared/socketio.service.ts +104 -0
- package/src/store/auth.store.ts +255 -0
- package/src/store/connection.store.ts +66 -0
- package/src/store/dialog.store.ts +114 -0
- package/src/store/features.store.ts +57 -0
- package/src/store/floor.store.ts +173 -0
- package/src/store/grid.store.ts +10 -0
- package/src/store/index.ts +4 -0
- package/src/store/printer-state.store.ts +246 -0
- package/src/store/printer.store.ts +236 -0
- package/src/store/profile.store.ts +25 -0
- package/src/store/settings.store.ts +64 -0
- package/src/store/test-printer.store.ts +70 -0
- package/src/store/uploads.store.ts +75 -0
- package/src/styles/README.md +3 -0
- package/src/styles/settings.scss +10 -0
- package/src/types/global.d.ts +15 -0
- package/src/utils/array.utils.ts +15 -0
- package/src/utils/date.utils.ts +5 -0
- package/src/utils/download-file.util.ts +25 -0
- package/src/utils/error.utils.ts +3 -0
- package/src/utils/file-size.util.ts +11 -0
- package/src/utils/id.type.ts +1 -0
- package/src/utils/sentry.util.ts +8 -0
- package/src/utils/test.util.ts +30 -0
- package/src/utils/time.utils.ts +2 -0
- package/src/utils/uploads-state.utils.ts +58 -0
- package/src/utils/validation.utils.ts +14 -0
- package/src/vite-env.d.ts +7 -0
- package/test/setup-axios-mock.ts +15 -0
- package/tsconfig.json +47 -0
- package/tsconfig.node.json +9 -0
- package/vite.config.mts +106 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { DialogName } from '@/components/Generic/Dialogs/dialog.constants'
|
|
3
|
+
|
|
4
|
+
interface DialogReference<T = any> {
|
|
5
|
+
id: DialogName
|
|
6
|
+
opened: boolean
|
|
7
|
+
beforeOpenedCallback?: (input?: T) => void | Promise<void>
|
|
8
|
+
openedCallback?: (input?: T) => void | Promise<void>
|
|
9
|
+
context?: any
|
|
10
|
+
output?: any
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type DialogsById = { [k: string]: DialogReference }
|
|
14
|
+
|
|
15
|
+
interface State {
|
|
16
|
+
ids: DialogName[]
|
|
17
|
+
dialogsById: DialogsById
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useDialogsStore = defineStore('Dialog', {
|
|
21
|
+
state: (): State => ({
|
|
22
|
+
ids: [],
|
|
23
|
+
dialogsById: {}
|
|
24
|
+
}),
|
|
25
|
+
getters: {
|
|
26
|
+
dialogs(): DialogReference[] {
|
|
27
|
+
return this.ids.map((i) => this.dialogsById[i])
|
|
28
|
+
},
|
|
29
|
+
getBeforeOpenedCallback() {
|
|
30
|
+
return (id: DialogName) => this.dialogsById[id]?.beforeOpenedCallback
|
|
31
|
+
},
|
|
32
|
+
getOpenedCallback() {
|
|
33
|
+
return (id: DialogName) => this.dialogsById[id]?.openedCallback
|
|
34
|
+
},
|
|
35
|
+
getContext() {
|
|
36
|
+
return (id: DialogName) => {
|
|
37
|
+
return this.dialogsById[id]?.context
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
getOutput() {
|
|
41
|
+
return (id: DialogName) => {
|
|
42
|
+
return this.dialogsById[id]?.output
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
isDialogOpened() {
|
|
46
|
+
return (id: DialogName) => {
|
|
47
|
+
return this.dialogsById[id]?.opened
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
actions: {
|
|
52
|
+
openDialogWithContext<T = any>(id: DialogName, context?: T) {
|
|
53
|
+
let dialog = this.dialogsById[id]
|
|
54
|
+
if (!dialog) {
|
|
55
|
+
dialog = this.registerDialogReference(id)
|
|
56
|
+
}
|
|
57
|
+
dialog.opened = true
|
|
58
|
+
dialog.context = context
|
|
59
|
+
// Vue 2 reactivity issue
|
|
60
|
+
this.dialogsById = {
|
|
61
|
+
...this.dialogsById
|
|
62
|
+
}
|
|
63
|
+
console.debug(`[Pinia Dialog ${id}] Opened with context`, context)
|
|
64
|
+
},
|
|
65
|
+
closeDialog(id: DialogName, output?: any) {
|
|
66
|
+
let dialog = this.dialogsById[id]
|
|
67
|
+
if (!dialog) {
|
|
68
|
+
dialog = this.registerDialogReference(id)
|
|
69
|
+
}
|
|
70
|
+
dialog.opened = false
|
|
71
|
+
delete dialog.context
|
|
72
|
+
dialog.output = output
|
|
73
|
+
// Vue 2 reactivity issue
|
|
74
|
+
this.dialogsById = {
|
|
75
|
+
...this.dialogsById
|
|
76
|
+
}
|
|
77
|
+
console.debug(`[Pinia Dialog ${id}] Closed`)
|
|
78
|
+
},
|
|
79
|
+
unregisterDialogReference(id: DialogName) {
|
|
80
|
+
delete this.dialogsById[id]
|
|
81
|
+
this.ids = this.ids.filter((i) => i !== id)
|
|
82
|
+
},
|
|
83
|
+
registerDialogReference<T = any>(
|
|
84
|
+
id?: DialogName,
|
|
85
|
+
callbacks?: {
|
|
86
|
+
beforeOpenedCallback?: (input?: T) => void
|
|
87
|
+
openedCallback?: (input?: T) => void
|
|
88
|
+
}
|
|
89
|
+
) {
|
|
90
|
+
if (!id) {
|
|
91
|
+
throw new Error('Cannot unregister undefined dialog reference')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.debug(`[Pinia Dialog ${id}] Registered`)
|
|
95
|
+
const existingDialog = this.dialogsById[id]
|
|
96
|
+
if (existingDialog) {
|
|
97
|
+
console.debug(
|
|
98
|
+
`[Pinia Dialog ${id}] Already registered dialog, not registering again`
|
|
99
|
+
)
|
|
100
|
+
return existingDialog
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const dialogRef = {
|
|
104
|
+
id,
|
|
105
|
+
opened: false,
|
|
106
|
+
beforeOpenedCallback: callbacks?.beforeOpenedCallback,
|
|
107
|
+
openedCallback: callbacks?.openedCallback
|
|
108
|
+
}
|
|
109
|
+
this.dialogsById[id] = dialogRef
|
|
110
|
+
this.ids.push(id)
|
|
111
|
+
return dialogRef
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import {
|
|
3
|
+
TFeatureFlags,
|
|
4
|
+
FeaturesModel,
|
|
5
|
+
IFeatureFlag
|
|
6
|
+
} from '@/models/server/features.model'
|
|
7
|
+
import { AppService } from '@/backend/app.service'
|
|
8
|
+
|
|
9
|
+
interface State {
|
|
10
|
+
features: FeaturesModel | undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useFeatureStore = defineStore('Feature', {
|
|
14
|
+
state: (): State => ({
|
|
15
|
+
features: undefined
|
|
16
|
+
}),
|
|
17
|
+
getters: {
|
|
18
|
+
getFeatures(): FeaturesModel | undefined {
|
|
19
|
+
return this.features
|
|
20
|
+
},
|
|
21
|
+
hasFeature:
|
|
22
|
+
(state) =>
|
|
23
|
+
(feature: TFeatureFlags): boolean => {
|
|
24
|
+
if (!state.features) {
|
|
25
|
+
console.debug('Feature store not loaded')
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const featureDefined = state.features[feature] as
|
|
30
|
+
| IFeatureFlag
|
|
31
|
+
| undefined
|
|
32
|
+
if (!featureDefined) {
|
|
33
|
+
console.debug(
|
|
34
|
+
`Feature ${feature} not defined. Options:`,
|
|
35
|
+
Object.keys(state.features)
|
|
36
|
+
)
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return featureDefined?.available
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
actions: {
|
|
44
|
+
async loadFeatures() {
|
|
45
|
+
debugger
|
|
46
|
+
try {
|
|
47
|
+
const features = await AppService.getFeatures()
|
|
48
|
+
this.setFeatures(features)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.features = {}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
setFeatures(features: FeaturesModel) {
|
|
54
|
+
this.features = features
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
})
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { FloorDto } from '@/models/floors/floor.model'
|
|
3
|
+
import { useSettingsStore } from './settings.store'
|
|
4
|
+
import { PrinterDto } from '@/models/printers/printer.model'
|
|
5
|
+
import { usePrinterStore } from './printer.store'
|
|
6
|
+
import { FloorService } from '@/backend/floor.service'
|
|
7
|
+
import { IdType } from '@/utils/id.type'
|
|
8
|
+
|
|
9
|
+
export interface State {
|
|
10
|
+
floors: FloorDto[]
|
|
11
|
+
selectedFloor: FloorDto | null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const useFloorStore = defineStore('Floors', {
|
|
15
|
+
state: (): State => ({
|
|
16
|
+
floors: [],
|
|
17
|
+
selectedFloor: null
|
|
18
|
+
}),
|
|
19
|
+
getters: {
|
|
20
|
+
sortedFloors(state) {
|
|
21
|
+
return state.floors.sort((f, f2) => f.floor - f2.floor)
|
|
22
|
+
},
|
|
23
|
+
floor(state) {
|
|
24
|
+
return (floorId: IdType) => state.floors.find((pf) => pf.id === floorId)
|
|
25
|
+
},
|
|
26
|
+
floorNames(state) {
|
|
27
|
+
return state.floors.map((f) => f.name)
|
|
28
|
+
},
|
|
29
|
+
floorOfPrinter() {
|
|
30
|
+
return (printerId: IdType) => {
|
|
31
|
+
return this.floors.find((f: FloorDto) =>
|
|
32
|
+
f.printers.map((pid) => pid.printerId).includes(printerId)
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
floorlessPrinters(state): PrinterDto[] {
|
|
37
|
+
const printersStore = usePrinterStore()
|
|
38
|
+
return printersStore.printers.filter(
|
|
39
|
+
(p) =>
|
|
40
|
+
!state.floors.find((f) =>
|
|
41
|
+
f.printers.find((fp) => fp.printerId === p.id)
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
gridSortedPrinters() {
|
|
46
|
+
const settingsStore = useSettingsStore()
|
|
47
|
+
const gridCols = settingsStore.gridCols
|
|
48
|
+
const gridRows = settingsStore.gridRows
|
|
49
|
+
|
|
50
|
+
const printersStore = usePrinterStore()
|
|
51
|
+
const printers = printersStore.printers
|
|
52
|
+
if (!printers.length) return []
|
|
53
|
+
if (!this.selectedFloor) return []
|
|
54
|
+
|
|
55
|
+
const positions = this.selectedFloor.printers
|
|
56
|
+
const matrix: (PrinterDto | undefined)[][] = []
|
|
57
|
+
for (let i = 0; i < gridCols; i++) {
|
|
58
|
+
const row: (PrinterDto | undefined)[] = []
|
|
59
|
+
matrix.push(row)
|
|
60
|
+
for (let j = 0; j < gridRows; j++) {
|
|
61
|
+
const position = positions.find((p) => p.x === i && p.y === j)
|
|
62
|
+
if (!position) {
|
|
63
|
+
row.push(undefined)
|
|
64
|
+
} else {
|
|
65
|
+
const printer = printers.find((p) => p.id === position.printerId)
|
|
66
|
+
row.push(printer)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return matrix
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
actions: {
|
|
74
|
+
async loadFloors() {
|
|
75
|
+
const floors = await FloorService.getFloors()
|
|
76
|
+
this.saveFloors(floors)
|
|
77
|
+
return floors
|
|
78
|
+
},
|
|
79
|
+
async createFloor(newPrinterFloor: FloorDto) {
|
|
80
|
+
const data = await FloorService.createFloor(newPrinterFloor)
|
|
81
|
+
this.floors.push(data)
|
|
82
|
+
return data
|
|
83
|
+
},
|
|
84
|
+
saveFloors(floors: FloorDto[]) {
|
|
85
|
+
if (!floors?.length) return
|
|
86
|
+
this.floors = floors.sort((f, f2) => f.floor - f2.floor)
|
|
87
|
+
const floorId = this.selectedFloor?.id
|
|
88
|
+
const foundFloor = this.floors.find((f) => f.id === floorId)
|
|
89
|
+
this.selectedFloor = !foundFloor ? this.floors[0] : foundFloor
|
|
90
|
+
},
|
|
91
|
+
async deleteFloor(floorId: IdType) {
|
|
92
|
+
await FloorService.deleteFloor(floorId)
|
|
93
|
+
this._popPrinterFloor(floorId)
|
|
94
|
+
},
|
|
95
|
+
async updateFloorName({
|
|
96
|
+
floorId,
|
|
97
|
+
name
|
|
98
|
+
}: {
|
|
99
|
+
floorId: IdType
|
|
100
|
+
name: string
|
|
101
|
+
}) {
|
|
102
|
+
const floor = await FloorService.updateFloorName(floorId, name)
|
|
103
|
+
this._replaceFloor(floor)
|
|
104
|
+
return floor
|
|
105
|
+
},
|
|
106
|
+
async updateFloorNumber({
|
|
107
|
+
floorId,
|
|
108
|
+
floorNumber
|
|
109
|
+
}: {
|
|
110
|
+
floorId: IdType
|
|
111
|
+
floorNumber: number
|
|
112
|
+
}) {
|
|
113
|
+
const floor = await FloorService.updateFloorNumber(floorId, floorNumber)
|
|
114
|
+
this._replaceFloor(floor)
|
|
115
|
+
return floor
|
|
116
|
+
},
|
|
117
|
+
async addPrinterToFloor({
|
|
118
|
+
floorId,
|
|
119
|
+
printerId,
|
|
120
|
+
x,
|
|
121
|
+
y
|
|
122
|
+
}: {
|
|
123
|
+
floorId: IdType
|
|
124
|
+
printerId: IdType
|
|
125
|
+
x: number
|
|
126
|
+
y: number
|
|
127
|
+
}) {
|
|
128
|
+
const result = await FloorService.addPrinterToFloor(floorId, {
|
|
129
|
+
printerId,
|
|
130
|
+
x,
|
|
131
|
+
y
|
|
132
|
+
})
|
|
133
|
+
this._replaceFloor(result)
|
|
134
|
+
},
|
|
135
|
+
async changeSelectedFloorByIndex(selectedPrinterFloorIndex: number) {
|
|
136
|
+
if (!this.floors?.length) return
|
|
137
|
+
if (this.floors.length <= selectedPrinterFloorIndex) return
|
|
138
|
+
|
|
139
|
+
const newFloor = this.floors[selectedPrinterFloorIndex]
|
|
140
|
+
// TODO throw warning?
|
|
141
|
+
if (!newFloor) return
|
|
142
|
+
this.selectedFloor = newFloor
|
|
143
|
+
return newFloor
|
|
144
|
+
},
|
|
145
|
+
async deletePrinterFromFloor({
|
|
146
|
+
floorId,
|
|
147
|
+
printerId
|
|
148
|
+
}: {
|
|
149
|
+
floorId: IdType
|
|
150
|
+
printerId: IdType
|
|
151
|
+
}) {
|
|
152
|
+
const result = await FloorService.deletePrinterFromFloor(
|
|
153
|
+
floorId,
|
|
154
|
+
printerId
|
|
155
|
+
)
|
|
156
|
+
this._replaceFloor(result)
|
|
157
|
+
},
|
|
158
|
+
_popPrinterFloor(floorId: IdType) {
|
|
159
|
+
const foundFloorIndex = this.floors.findIndex((pg) => pg.id === floorId)
|
|
160
|
+
if (foundFloorIndex !== -1) {
|
|
161
|
+
this.floors.splice(foundFloorIndex, 1)
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
_replaceFloor(printerFloor: FloorDto) {
|
|
165
|
+
const foundFloorIndex = this.floors.findIndex(
|
|
166
|
+
(pf) => pf.id === printerFloor.id
|
|
167
|
+
)
|
|
168
|
+
if (foundFloorIndex !== -1) {
|
|
169
|
+
this.floors[foundFloorIndex] = printerFloor
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
})
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { PrinterDto } from '@/models/printers/printer.model'
|
|
3
|
+
import {
|
|
4
|
+
PrinterStateDto,
|
|
5
|
+
SocketState
|
|
6
|
+
} from '@/models/socketio-messages/socketio-message.model'
|
|
7
|
+
import { usePrinterStore } from './printer.store'
|
|
8
|
+
import { PrinterFileService } from '@/backend'
|
|
9
|
+
import { useSettingsStore } from './settings.store'
|
|
10
|
+
import { CurrentOrHistoryPayload } from '@/models/printers/printer-current-job.model'
|
|
11
|
+
import { IdType } from '@/utils/id.type'
|
|
12
|
+
import {
|
|
13
|
+
isPrinterIdling,
|
|
14
|
+
isPrinterPrinting
|
|
15
|
+
} from '@/shared/printer-state.constants'
|
|
16
|
+
|
|
17
|
+
interface State {
|
|
18
|
+
printerIds: IdType[]
|
|
19
|
+
printerEventsById: Record<IdType, PrinterStateDto>
|
|
20
|
+
socketStatesById: Record<IdType, SocketState>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const usePrinterStateStore = defineStore('PrinterState', {
|
|
24
|
+
state: (): State => ({
|
|
25
|
+
printerIds: [],
|
|
26
|
+
printerEventsById: {},
|
|
27
|
+
socketStatesById: {}
|
|
28
|
+
}),
|
|
29
|
+
getters: {
|
|
30
|
+
operationalPrintersById() {
|
|
31
|
+
const printerStore = usePrinterStore()
|
|
32
|
+
const printersById: Record<IdType, PrinterDto> = {}
|
|
33
|
+
this.printerIds.forEach((id) => {
|
|
34
|
+
const printerEvents = this.printerEventsById[id]
|
|
35
|
+
if (printerEvents?.current?.payload?.state?.flags?.operational) {
|
|
36
|
+
const printer = printerStore.printer(id)
|
|
37
|
+
if (printer) {
|
|
38
|
+
printersById[id] = printer
|
|
39
|
+
} else {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`PrinterStore contains no printer with id ${id} but events are known`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
return printersById
|
|
47
|
+
},
|
|
48
|
+
isPrinterOperational(): (printerId: IdType) => boolean {
|
|
49
|
+
return (printerId: IdType) => {
|
|
50
|
+
return !!this.operationalPrintersById[printerId]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
printingPrintersById() {
|
|
54
|
+
const printersById: Record<IdType, PrinterStateDto> = {}
|
|
55
|
+
this.printerIds.forEach((id) => {
|
|
56
|
+
const printerEvents = this.printerEventsById[id]
|
|
57
|
+
if (printerEvents?.current?.payload?.state?.flags?.printing) {
|
|
58
|
+
printersById[id] = printerEvents
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
return printersById
|
|
62
|
+
},
|
|
63
|
+
isPrinterPrinting(): (printerId: IdType) => boolean {
|
|
64
|
+
return (printerId: IdType) => !!this.printingPrintersById[printerId]
|
|
65
|
+
},
|
|
66
|
+
isPrinterStoppable(): (printerId: IdType) => boolean {
|
|
67
|
+
return (printerId: IdType) => {
|
|
68
|
+
const printerEvents = this.printerEventsById[printerId]
|
|
69
|
+
if (!printerEvents) return false
|
|
70
|
+
const flags = printerEvents?.current?.payload?.state?.flags
|
|
71
|
+
return flags?.printing || flags?.paused
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
isPrinterPaused(): (printerId: IdType) => boolean {
|
|
75
|
+
return (printerId: IdType) => {
|
|
76
|
+
const printerEvents = this.printerEventsById[printerId]
|
|
77
|
+
if (!printerEvents) return false
|
|
78
|
+
const flags = printerEvents?.current?.payload?.state?.flags
|
|
79
|
+
return flags?.paused
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
printerCurrentEventReceivedAtById() {
|
|
83
|
+
const printerCurrentEventReceivedAtById: Record<IdType, number> = {}
|
|
84
|
+
this.printerIds.forEach((id) => {
|
|
85
|
+
const printerEvents = this.printerEventsById[id]
|
|
86
|
+
if (printerEvents?.current?.receivedAt) {
|
|
87
|
+
printerCurrentEventReceivedAtById[id] =
|
|
88
|
+
printerEvents.current.receivedAt
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
return printerCurrentEventReceivedAtById
|
|
92
|
+
},
|
|
93
|
+
onlinePrinters() {
|
|
94
|
+
const printerStore = usePrinterStore()
|
|
95
|
+
const onlinePrinters: Record<IdType, PrinterDto> = {}
|
|
96
|
+
this.printerIds.forEach((id) => {
|
|
97
|
+
const socketState = this.socketStatesById[id]
|
|
98
|
+
if (socketState?.api === 'responding') {
|
|
99
|
+
const printer = printerStore.printer(id)
|
|
100
|
+
if (printer) {
|
|
101
|
+
onlinePrinters[id] = printer
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`PrinterStore contains no printer with id ${id} but socket state is opened`
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
return onlinePrinters
|
|
110
|
+
},
|
|
111
|
+
onlinePrintersWithStates(): {
|
|
112
|
+
printerState: PrinterStateDto
|
|
113
|
+
printer: PrinterDto
|
|
114
|
+
}[] {
|
|
115
|
+
return Object.values(this.onlinePrinters).map((printer) => {
|
|
116
|
+
return {
|
|
117
|
+
printer,
|
|
118
|
+
printerState: this.printerEventsById[printer.id]
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
},
|
|
122
|
+
printingCount(): number {
|
|
123
|
+
const printerStateStore = usePrinterStateStore()
|
|
124
|
+
return Object.values(printerStateStore.onlinePrintersWithStates).filter(
|
|
125
|
+
(p) => isPrinterPrinting(p.printerState)
|
|
126
|
+
).length
|
|
127
|
+
},
|
|
128
|
+
operationalNotPrintingCount(): number {
|
|
129
|
+
return this.onlinePrintersWithStates.filter((pws) =>
|
|
130
|
+
isPrinterIdling(pws.printer, pws.printerState)
|
|
131
|
+
).length
|
|
132
|
+
},
|
|
133
|
+
isApiResponding() {
|
|
134
|
+
return (printerId: IdType) => {
|
|
135
|
+
return Object.keys(this.onlinePrinters).includes(printerId.toString())
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
isPrinterNotOnline() {
|
|
139
|
+
return (printerId: IdType) => {
|
|
140
|
+
return !this.isApiResponding(printerId)
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
printerJobsById() {
|
|
144
|
+
const printerStore = usePrinterStore()
|
|
145
|
+
const jobsRendered =
|
|
146
|
+
useSettingsStore().frontendDebugSettings.showJobsRendered
|
|
147
|
+
const printersWithJobById: Record<IdType, CurrentOrHistoryPayload> = {}
|
|
148
|
+
this.printerIds.forEach((id) => {
|
|
149
|
+
const printerEvents = this.printerEventsById[id]
|
|
150
|
+
const flags = printerEvents?.current?.payload?.state?.flags
|
|
151
|
+
if (flags?.printing || flags?.paused) {
|
|
152
|
+
const printer = printerStore.printer(id)
|
|
153
|
+
if (printer) {
|
|
154
|
+
printersWithJobById[printer.id] = printerEvents?.current?.payload
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`PrinterStore contains no printer with id ${id} but events are known`
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
if (jobsRendered) {
|
|
164
|
+
// TODO improve summary
|
|
165
|
+
console.debug(
|
|
166
|
+
'[PrinterStateStore] rendered printerJobsById',
|
|
167
|
+
printersWithJobById
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
return printersWithJobById
|
|
171
|
+
},
|
|
172
|
+
printersWithJob() {
|
|
173
|
+
const printerStore = usePrinterStore()
|
|
174
|
+
const printersWithJobById: {
|
|
175
|
+
printer: PrinterDto
|
|
176
|
+
job: CurrentOrHistoryPayload
|
|
177
|
+
}[] = []
|
|
178
|
+
this.printerIds.forEach((id) => {
|
|
179
|
+
const printerEvents = this.printerEventsById[id]
|
|
180
|
+
const flags = printerEvents?.current?.payload?.state?.flags
|
|
181
|
+
if (flags?.printing || flags?.paused) {
|
|
182
|
+
const printer = printerStore.printer(id)
|
|
183
|
+
if (printer) {
|
|
184
|
+
printersWithJobById.push({
|
|
185
|
+
printer,
|
|
186
|
+
job: printerEvents?.current?.payload
|
|
187
|
+
})
|
|
188
|
+
} else {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`PrinterStore contains no printer with id ${id} but events are known`
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
return printersWithJobById
|
|
196
|
+
},
|
|
197
|
+
printingFilePathsByPrinterId() {
|
|
198
|
+
const printingFilesByPrinterId: Record<IdType, string> = {}
|
|
199
|
+
this.printerIds.forEach((id) => {
|
|
200
|
+
const printerEvents = this.printerEventsById[id]
|
|
201
|
+
const flags = printerEvents?.current?.payload?.state?.flags
|
|
202
|
+
if (flags?.printing || flags?.paused) {
|
|
203
|
+
// TODO decide on comparing with name or path
|
|
204
|
+
printingFilesByPrinterId[id] =
|
|
205
|
+
printerEvents?.current?.payload?.job?.file?.path
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
return printingFilesByPrinterId
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
actions: {
|
|
212
|
+
setSocketStates(socketStates: Record<IdType, SocketState>) {
|
|
213
|
+
this.socketStatesById = socketStates
|
|
214
|
+
this.printerIds = Object.keys(socketStates)
|
|
215
|
+
},
|
|
216
|
+
setPrinterEvents(printerEvents: Record<IdType, PrinterStateDto>) {
|
|
217
|
+
this.printerEventsById = printerEvents
|
|
218
|
+
// TODO check id's different from printer events and socket states
|
|
219
|
+
},
|
|
220
|
+
deletePrinterEvents(printerId: IdType) {
|
|
221
|
+
delete this.printerEventsById[printerId]
|
|
222
|
+
this.printerIds = Object.keys(this.printerEventsById)
|
|
223
|
+
},
|
|
224
|
+
async selectAndPrintFile({
|
|
225
|
+
printerId,
|
|
226
|
+
fullPath
|
|
227
|
+
}: {
|
|
228
|
+
printerId: IdType
|
|
229
|
+
fullPath: string
|
|
230
|
+
}) {
|
|
231
|
+
if (!printerId) return
|
|
232
|
+
const printerStore = usePrinterStore()
|
|
233
|
+
const printer = printerStore.printer(printerId)
|
|
234
|
+
if (!printer) return
|
|
235
|
+
|
|
236
|
+
if (this.isPrinterPrinting(printerId)) {
|
|
237
|
+
alert(
|
|
238
|
+
'This printer is printing or not connected! Either way printing is not an option.'
|
|
239
|
+
)
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
await PrinterFileService.selectAndPrintFile(printerId, fullPath, true)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
})
|