@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,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-container
|
|
3
|
+
v-if="printer"
|
|
4
|
+
v-drop-upload="{ printers: [printer] }"
|
|
5
|
+
:style="dragging ? 'background-color:red' : ''"
|
|
6
|
+
transition="scale-transition"
|
|
7
|
+
>
|
|
8
|
+
<v-row>
|
|
9
|
+
<v-col>
|
|
10
|
+
Name: {{ printer.name }} <br />
|
|
11
|
+
URL: {{ printer.printerURL }} <br />
|
|
12
|
+
Host:
|
|
13
|
+
<v-chip size="small">
|
|
14
|
+
{{ apiState }}
|
|
15
|
+
</v-chip>
|
|
16
|
+
<br />
|
|
17
|
+
WebSocket:
|
|
18
|
+
<v-chip size="small">
|
|
19
|
+
{{ socketState }}
|
|
20
|
+
</v-chip>
|
|
21
|
+
<br />
|
|
22
|
+
Printer:
|
|
23
|
+
<v-chip size="small">
|
|
24
|
+
{{ printerTextState }}
|
|
25
|
+
</v-chip>
|
|
26
|
+
</v-col>
|
|
27
|
+
<v-col>
|
|
28
|
+
<RefreshFilesAction
|
|
29
|
+
:printer="printer"
|
|
30
|
+
class="d-flex justify-end"
|
|
31
|
+
/>
|
|
32
|
+
</v-col>
|
|
33
|
+
</v-row>
|
|
34
|
+
</v-container>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script lang="ts">
|
|
38
|
+
import { defineComponent, PropType } from 'vue'
|
|
39
|
+
import { PrinterDto } from '@/models/printers/printer.model'
|
|
40
|
+
import RefreshFilesAction from '@/components/Generic/Actions/RefreshFilesAction.vue'
|
|
41
|
+
import { usePrinterStore } from '@/store/printer.store'
|
|
42
|
+
import { usePrinterStateStore } from '@/store/printer-state.store'
|
|
43
|
+
|
|
44
|
+
interface Data {
|
|
45
|
+
dragging: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default defineComponent({
|
|
49
|
+
name: 'PrinterDetails',
|
|
50
|
+
components: {
|
|
51
|
+
// FileControlList,
|
|
52
|
+
RefreshFilesAction
|
|
53
|
+
},
|
|
54
|
+
props: {
|
|
55
|
+
printer: Object as PropType<PrinterDto>
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
setup: () => {
|
|
59
|
+
return {
|
|
60
|
+
printersStore: usePrinterStore(),
|
|
61
|
+
printerStateStore: usePrinterStateStore()
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
data: (): Data => ({
|
|
66
|
+
dragging: false
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
computed: {
|
|
70
|
+
printerId() {
|
|
71
|
+
return this.printer?.id
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
socketState() {
|
|
75
|
+
if (!this.printerId) return
|
|
76
|
+
return this.printerStateStore.socketStatesById[this.printerId]?.socket
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
apiState() {
|
|
80
|
+
if (!this.printerId) return
|
|
81
|
+
return this.printerStateStore.socketStatesById[this.printerId]?.api
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
printerTextState() {
|
|
85
|
+
if (!this.printerId) return
|
|
86
|
+
return this.printerStateStore.printerEventsById[this.printerId]?.current
|
|
87
|
+
?.payload?.state.text
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
</script>
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<v-card>
|
|
4
|
+
<v-card-title>
|
|
5
|
+
Printers
|
|
6
|
+
<v-spacer />
|
|
7
|
+
<v-select
|
|
8
|
+
v-if="hasPrinterGroupFeature && groupsWithPrinters.length"
|
|
9
|
+
v-model="filteredGroupsWithPrinters"
|
|
10
|
+
multiple
|
|
11
|
+
:items="groupsWithPrinters"
|
|
12
|
+
item-title="name"
|
|
13
|
+
:return-object="true"
|
|
14
|
+
placeholder="Select group to filter by"
|
|
15
|
+
prepend-icon="filter_list"
|
|
16
|
+
label="Filter by groups"
|
|
17
|
+
/>
|
|
18
|
+
<v-text-field
|
|
19
|
+
v-model="search"
|
|
20
|
+
class="p-2"
|
|
21
|
+
clearable
|
|
22
|
+
label="Printer search"
|
|
23
|
+
prepend-icon="search"
|
|
24
|
+
single-line
|
|
25
|
+
/>
|
|
26
|
+
</v-card-title>
|
|
27
|
+
|
|
28
|
+
<v-data-table
|
|
29
|
+
:expanded.sync="expanded"
|
|
30
|
+
:headers="tableHeaders"
|
|
31
|
+
:items="printers"
|
|
32
|
+
:search="search"
|
|
33
|
+
single-expand
|
|
34
|
+
class="elevation-1"
|
|
35
|
+
item-key="id"
|
|
36
|
+
show-expand
|
|
37
|
+
@click:row="clickRow"
|
|
38
|
+
>
|
|
39
|
+
<template #no-data>
|
|
40
|
+
<div class="mt-4 mb-4">
|
|
41
|
+
<h3 v-if="printers.length === 0">
|
|
42
|
+
No printer has been created yet. Create one here:
|
|
43
|
+
</h3>
|
|
44
|
+
<h3 v-else>
|
|
45
|
+
No printer has been found. Adjust your filters or search criteria.
|
|
46
|
+
</h3>
|
|
47
|
+
<PrinterCreateAction />
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
<template #top>
|
|
51
|
+
<v-toolbar flat>
|
|
52
|
+
<v-toolbar-title>
|
|
53
|
+
Showing {{ printers.length || 0 }} printers
|
|
54
|
+
</v-toolbar-title>
|
|
55
|
+
<v-btn
|
|
56
|
+
class="ml-3"
|
|
57
|
+
variant="outlined"
|
|
58
|
+
type="button"
|
|
59
|
+
@click="openImportJsonPrintersDialog()"
|
|
60
|
+
>
|
|
61
|
+
<v-icon>publish</v-icon>
|
|
62
|
+
Import OctoFarm Printers
|
|
63
|
+
</v-btn>
|
|
64
|
+
<v-btn
|
|
65
|
+
class="ml-3"
|
|
66
|
+
variant="outlined"
|
|
67
|
+
type="button"
|
|
68
|
+
@click="openCreatePrinterDialog()"
|
|
69
|
+
>
|
|
70
|
+
<v-icon>add</v-icon>
|
|
71
|
+
Create Printer
|
|
72
|
+
</v-btn>
|
|
73
|
+
<v-btn
|
|
74
|
+
class="ml-3"
|
|
75
|
+
color="primary"
|
|
76
|
+
type="button"
|
|
77
|
+
@click="openYamlImportExportDialog()"
|
|
78
|
+
>
|
|
79
|
+
<v-icon>publish</v-icon>
|
|
80
|
+
Import/Export YAML
|
|
81
|
+
</v-btn>
|
|
82
|
+
<v-spacer />
|
|
83
|
+
</v-toolbar>
|
|
84
|
+
</template>
|
|
85
|
+
<template #item.enabled="{ item }">
|
|
86
|
+
<v-switch
|
|
87
|
+
v-model="item.enabled"
|
|
88
|
+
color="primary"
|
|
89
|
+
dark
|
|
90
|
+
inset
|
|
91
|
+
@click.native.capture.stop="toggleEnabled(item)"
|
|
92
|
+
>
|
|
93
|
+
{{ item.enabled }}
|
|
94
|
+
</v-switch>
|
|
95
|
+
</template>
|
|
96
|
+
<template #item.name="{ item }">
|
|
97
|
+
<v-chip
|
|
98
|
+
color="primary"
|
|
99
|
+
dark
|
|
100
|
+
>
|
|
101
|
+
{{ item.name || item.printerURL }}
|
|
102
|
+
</v-chip>
|
|
103
|
+
</template>
|
|
104
|
+
<template #item.floor="{ item }">
|
|
105
|
+
<v-chip
|
|
106
|
+
v-if="item.id"
|
|
107
|
+
color="primary"
|
|
108
|
+
>
|
|
109
|
+
{{ floorOfPrinter(item.id)?.name }}
|
|
110
|
+
</v-chip>
|
|
111
|
+
</template>
|
|
112
|
+
<template
|
|
113
|
+
v-if="hasPrinterGroupFeature"
|
|
114
|
+
#item.group="{ item }"
|
|
115
|
+
>
|
|
116
|
+
<v-chip
|
|
117
|
+
v-for="group of groupsOfPrinter(item.id)"
|
|
118
|
+
:key="group.id"
|
|
119
|
+
closable
|
|
120
|
+
size="small"
|
|
121
|
+
class="ml-2"
|
|
122
|
+
@click:close="deletePrinterFromGroup(group.id, item.id)"
|
|
123
|
+
>
|
|
124
|
+
{{ group.name }}
|
|
125
|
+
</v-chip>
|
|
126
|
+
|
|
127
|
+
<v-menu offset-y>
|
|
128
|
+
<template #activator="{ props }">
|
|
129
|
+
<v-chip
|
|
130
|
+
:disabled="!groupsWithPrinters.length"
|
|
131
|
+
class="ml-2"
|
|
132
|
+
size="small"
|
|
133
|
+
v-bind="props"
|
|
134
|
+
>
|
|
135
|
+
<v-icon size="small">add</v-icon>
|
|
136
|
+
</v-chip>
|
|
137
|
+
</template>
|
|
138
|
+
|
|
139
|
+
<v-list
|
|
140
|
+
density="compact"
|
|
141
|
+
style="border: 1px solid dimgray"
|
|
142
|
+
>
|
|
143
|
+
<v-list-subheader> ADD TO GROUP </v-list-subheader>
|
|
144
|
+
<v-list-item-group>
|
|
145
|
+
<v-list-item
|
|
146
|
+
v-for="(group, index) in nonGroupsOfPrinter(item.id)"
|
|
147
|
+
:key="index"
|
|
148
|
+
@click="addPrinterToGroup(group.id, item.id)"
|
|
149
|
+
>
|
|
150
|
+
<v-list-item-title>
|
|
151
|
+
{{ group.name }}
|
|
152
|
+
</v-list-item-title>
|
|
153
|
+
</v-list-item>
|
|
154
|
+
</v-list-item-group>
|
|
155
|
+
</v-list>
|
|
156
|
+
</v-menu>
|
|
157
|
+
</template>
|
|
158
|
+
<template #item.actions="{ item }">
|
|
159
|
+
<PrinterUrlAction :printer="item" />
|
|
160
|
+
<PrinterConnectionAction :printer="item" />
|
|
161
|
+
<PrinterQuickStopAction :printer="item" />
|
|
162
|
+
<SyncPrinterNameAction :printer="item" />
|
|
163
|
+
<PrinterDeleteAction :printer="item" />
|
|
164
|
+
<PrinterSettingsAction
|
|
165
|
+
:printer="item"
|
|
166
|
+
@update:show="openEditDialog(item)"
|
|
167
|
+
/>
|
|
168
|
+
</template>
|
|
169
|
+
<template #item.socketupdate="{ item }">
|
|
170
|
+
<span v-if="currentEventReceivedAt[item.id]">
|
|
171
|
+
Updated {{ diffSeconds(currentEventReceivedAt[item.id]) }} seconds
|
|
172
|
+
ago
|
|
173
|
+
</span>
|
|
174
|
+
<span v-else> No update received (silence) </span>
|
|
175
|
+
</template>
|
|
176
|
+
<template #expanded-row="{ item, columns }">
|
|
177
|
+
<td :colspan="columns.length">
|
|
178
|
+
<PrinterDetails :printer="item" />
|
|
179
|
+
</td>
|
|
180
|
+
</template>
|
|
181
|
+
</v-data-table>
|
|
182
|
+
</v-card>
|
|
183
|
+
|
|
184
|
+
<v-card
|
|
185
|
+
v-if="hasPrinterGroupFeature"
|
|
186
|
+
class="mt-4"
|
|
187
|
+
>
|
|
188
|
+
<v-card-title> Printer Groups </v-card-title>
|
|
189
|
+
|
|
190
|
+
<v-card-text>
|
|
191
|
+
<h3>Existing groups:</h3>
|
|
192
|
+
|
|
193
|
+
<v-container>
|
|
194
|
+
<v-chip-group
|
|
195
|
+
v-model="selectedGroup"
|
|
196
|
+
selected-class="primary--text"
|
|
197
|
+
column
|
|
198
|
+
@update:model-value="selectGroupForUpdatingName()"
|
|
199
|
+
>
|
|
200
|
+
<v-chip
|
|
201
|
+
v-for="group of groupsWithPrinters"
|
|
202
|
+
:key="group.id"
|
|
203
|
+
size="small"
|
|
204
|
+
closable
|
|
205
|
+
class="mr-3"
|
|
206
|
+
@click:close="deleteGroup(group.id)"
|
|
207
|
+
>
|
|
208
|
+
{{ group.name }}
|
|
209
|
+
</v-chip>
|
|
210
|
+
</v-chip-group>
|
|
211
|
+
</v-container>
|
|
212
|
+
|
|
213
|
+
<h3 class="mt-3">Update group name</h3>
|
|
214
|
+
<v-container>
|
|
215
|
+
<v-alert v-if="!selectedGroupObject">
|
|
216
|
+
Select a group to update its name.
|
|
217
|
+
</v-alert>
|
|
218
|
+
<v-text-field
|
|
219
|
+
v-model="updatedGroupName"
|
|
220
|
+
:disabled="!selectedGroupObject"
|
|
221
|
+
label="Group Name"
|
|
222
|
+
placeholder="Type group name here"
|
|
223
|
+
>
|
|
224
|
+
Name
|
|
225
|
+
</v-text-field>
|
|
226
|
+
<v-btn @click="updateGroupName(selectedGroupObject)">
|
|
227
|
+
Update name
|
|
228
|
+
</v-btn>
|
|
229
|
+
</v-container>
|
|
230
|
+
|
|
231
|
+
<h3 class="mt-3">Add group</h3>
|
|
232
|
+
|
|
233
|
+
<v-container>
|
|
234
|
+
<v-text-field
|
|
235
|
+
v-model="newGroupName"
|
|
236
|
+
label="Group Name"
|
|
237
|
+
placeholder="Type group name here"
|
|
238
|
+
>
|
|
239
|
+
Name
|
|
240
|
+
</v-text-field>
|
|
241
|
+
<v-btn @click="createGroup()"> Create new group </v-btn>
|
|
242
|
+
</v-container>
|
|
243
|
+
</v-card-text>
|
|
244
|
+
</v-card>
|
|
245
|
+
</div>
|
|
246
|
+
</template>
|
|
247
|
+
|
|
248
|
+
<script lang="ts" setup>
|
|
249
|
+
import { computed, ref } from 'vue'
|
|
250
|
+
import { PrintersService } from '@/backend/printers.service'
|
|
251
|
+
import PrinterDetails from '@/components/PrinterList/PrinterDetails.vue'
|
|
252
|
+
import PrinterUrlAction from '@/components/Generic/Actions/PrinterUrlAction.vue'
|
|
253
|
+
import PrinterSettingsAction from '@/components/Generic/Actions/PrinterSettingsAction.vue'
|
|
254
|
+
import PrinterConnectionAction from '@/components/Generic/Actions/PrinterConnectionAction.vue'
|
|
255
|
+
import PrinterQuickStopAction from '@/components/Generic/Actions/PrinterQuickStopAction.vue'
|
|
256
|
+
import SyncPrinterNameAction from '@/components/Generic/Actions/SyncPrinterNameAction.vue'
|
|
257
|
+
|
|
258
|
+
import { usePrinterStore } from '@/store/printer.store'
|
|
259
|
+
import { useDialogsStore } from '@/store/dialog.store'
|
|
260
|
+
import { DialogName } from '@/components/Generic/Dialogs/dialog.constants'
|
|
261
|
+
import PrinterCreateAction from '@/components/Generic/Actions/PrinterCreateAction.vue'
|
|
262
|
+
import PrinterDeleteAction from '@/components/Generic/Actions/PrinterDeleteAction.vue'
|
|
263
|
+
import { useFloorStore } from '@/store/floor.store'
|
|
264
|
+
import { usePrinterStateStore } from '@/store/printer-state.store'
|
|
265
|
+
import { IdType } from '@/utils/id.type'
|
|
266
|
+
import { PrinterDto } from '@/models/printers/printer.model'
|
|
267
|
+
import { useFeatureStore } from '@/store/features.store'
|
|
268
|
+
import { useQuery } from '@tanstack/vue-query'
|
|
269
|
+
import { useSnackbar } from '@/shared/snackbar.composable'
|
|
270
|
+
import {
|
|
271
|
+
GroupWithPrintersDto,
|
|
272
|
+
PrinterGroupService
|
|
273
|
+
} from '@/backend/printer-group.service'
|
|
274
|
+
import { useDialog } from '@/shared/dialog.composable'
|
|
275
|
+
import { VDataTable } from 'vuetify/components'
|
|
276
|
+
|
|
277
|
+
const snackbar = useSnackbar()
|
|
278
|
+
const printerStore = usePrinterStore()
|
|
279
|
+
const loading = ref<boolean>(false)
|
|
280
|
+
const printerStateStore = usePrinterStateStore()
|
|
281
|
+
const floorStore = useFloorStore()
|
|
282
|
+
const dialogsStore = useDialogsStore()
|
|
283
|
+
const featureStore = useFeatureStore()
|
|
284
|
+
const groupsWithPrinters = ref<GroupWithPrintersDto<IdType>[]>([])
|
|
285
|
+
const filteredGroupsWithPrinters = ref<GroupWithPrintersDto<IdType>[]>([])
|
|
286
|
+
const newGroupName = ref('')
|
|
287
|
+
const updatedGroupName = ref('')
|
|
288
|
+
const selectedGroup = ref<number>()
|
|
289
|
+
|
|
290
|
+
type ReadonlyHeaders = VDataTable['$props']['headers']
|
|
291
|
+
|
|
292
|
+
const search = ref('')
|
|
293
|
+
const expanded = ref<string[]>([])
|
|
294
|
+
const hasPrinterGroupFeature = computed(() =>
|
|
295
|
+
featureStore.hasFeature('printerGroupsApi')
|
|
296
|
+
)
|
|
297
|
+
const tableHeaders = computed(
|
|
298
|
+
() =>
|
|
299
|
+
[
|
|
300
|
+
{ title: 'Enabled', key: 'enabled' },
|
|
301
|
+
{ title: 'Printer Name', align: 'start', sortable: true, key: 'name' },
|
|
302
|
+
{ title: 'Floor', key: 'floor', sortable: false },
|
|
303
|
+
...(featureStore.hasFeature('printerGroupsApi')
|
|
304
|
+
? [{ title: 'Group(s)', key: 'group', sortable: true }]
|
|
305
|
+
: []),
|
|
306
|
+
{ title: 'Actions', key: 'actions', sortable: false },
|
|
307
|
+
{ title: 'Socket Update', key: 'socketupdate', sortable: false },
|
|
308
|
+
{ title: '', key: 'data-table-expand' }
|
|
309
|
+
] as ReadonlyHeaders
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
async function loadData() {
|
|
313
|
+
loading.value = true
|
|
314
|
+
await featureStore.loadFeatures()
|
|
315
|
+
if (featureStore.hasFeature('printerGroupsApi')) {
|
|
316
|
+
const response = await PrinterGroupService.getGroupsWithPrinters()
|
|
317
|
+
groupsWithPrinters.value = response
|
|
318
|
+
}
|
|
319
|
+
loading.value = false
|
|
320
|
+
return groupsWithPrinters
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const printerGroupsQuery = useQuery({
|
|
324
|
+
queryKey: ['printerGroups'],
|
|
325
|
+
queryFn: loadData
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
const printers = computed(() => {
|
|
329
|
+
if (
|
|
330
|
+
!featureStore.hasFeature('printerGroupsApi') ||
|
|
331
|
+
!filteredGroupsWithPrinters.value?.length
|
|
332
|
+
) {
|
|
333
|
+
return printerStore.printers
|
|
334
|
+
}
|
|
335
|
+
const printerIdsInFilteredGroups =
|
|
336
|
+
filteredGroupsWithPrinters.value.flatMap((g) =>
|
|
337
|
+
g.printers.map((p) => p.printerId)
|
|
338
|
+
) || []
|
|
339
|
+
return printerStore.printers.filter((p) =>
|
|
340
|
+
printerIdsInFilteredGroups.includes(p.id)
|
|
341
|
+
)
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
const currentEventReceivedAt = computed(
|
|
345
|
+
() => printerStateStore.printerCurrentEventReceivedAtById
|
|
346
|
+
)
|
|
347
|
+
const selectedGroupObject = computed(() => {
|
|
348
|
+
if (!selectedGroup.value && selectedGroup.value !== 0) return
|
|
349
|
+
|
|
350
|
+
return groupsWithPrinters.value[selectedGroup.value]
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
const diffSeconds = (timestamp: number) => {
|
|
354
|
+
if (!timestamp) return
|
|
355
|
+
const now = Date.now()
|
|
356
|
+
return (now - timestamp) / 1000
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const groupsOfPrinter = (printerId: IdType) => {
|
|
360
|
+
return groupsWithPrinters.value.filter((g) =>
|
|
361
|
+
g.printers.find((p) => p.printerId === printerId)
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const nonGroupsOfPrinter = (printerId: IdType) => {
|
|
366
|
+
return groupsWithPrinters.value.filter(
|
|
367
|
+
(g) => !g.printers.find((p) => p.printerId === printerId)
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const floorOfPrinter = (printerId: IdType) => {
|
|
372
|
+
return floorStore.floorOfPrinter(printerId)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const openEditDialog = (printer: PrinterDto) => {
|
|
376
|
+
printerStore.setUpdateDialogPrinter(printer)
|
|
377
|
+
dialogsStore.openDialogWithContext(DialogName.AddOrUpdatePrinterDialog)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const openCreatePrinterDialog = () => {
|
|
381
|
+
dialogsStore.openDialogWithContext(DialogName.AddOrUpdatePrinterDialog)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const clickRow = (item: PrinterDto, event: any) => {
|
|
385
|
+
console.log(item, event)
|
|
386
|
+
|
|
387
|
+
if (event.isExpanded) {
|
|
388
|
+
const index = expanded.value.findIndex((i) => i === item.id)
|
|
389
|
+
expanded.value.splice(index, 1)
|
|
390
|
+
} else {
|
|
391
|
+
expanded.value.push(item.id.toString())
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const openImportJsonPrintersDialog = () => {
|
|
396
|
+
dialogsStore.openDialogWithContext(DialogName.BatchJsonCreate)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const openYamlImportExportDialog = () => {
|
|
400
|
+
useDialog(DialogName.YamlImportExport).openDialog()
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const createGroup = async () => {
|
|
404
|
+
if (!newGroupName.value?.trim()?.length) {
|
|
405
|
+
throw new Error('Please set a non-empty group name')
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
await PrinterGroupService.createGroup(newGroupName.value.trim())
|
|
409
|
+
await printerGroupsQuery.refetch()
|
|
410
|
+
newGroupName.value = ''
|
|
411
|
+
snackbar.info('Created group')
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const selectGroupForUpdatingName = () => {
|
|
415
|
+
if (!selectedGroupObject.value) return
|
|
416
|
+
|
|
417
|
+
updatedGroupName.value = selectedGroupObject.value?.name
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const updateGroupName = async (group?: GroupWithPrintersDto<IdType>) => {
|
|
421
|
+
if (!group?.id) {
|
|
422
|
+
throw new Error('Group id was not defined')
|
|
423
|
+
}
|
|
424
|
+
const existingGroup = groupsWithPrinters.value.find((g) => g.id === group.id)
|
|
425
|
+
if (!existingGroup) {
|
|
426
|
+
throw new Error('Group was not found, please reload the page')
|
|
427
|
+
}
|
|
428
|
+
if (!updatedGroupName.value?.trim()?.length) {
|
|
429
|
+
throw new Error('Please set a non-empty group name')
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
await PrinterGroupService.updateGroupName(
|
|
433
|
+
group.id,
|
|
434
|
+
updatedGroupName.value.trim()
|
|
435
|
+
)
|
|
436
|
+
await printerGroupsQuery.refetch()
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const deleteGroup = async (groupId: IdType) => {
|
|
440
|
+
const existingGroup = groupsWithPrinters.value.find((g) => g.id === groupId)
|
|
441
|
+
if (!existingGroup) {
|
|
442
|
+
throw new Error('Group was not found, please reload the page')
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const printerCount = existingGroup.printers.length
|
|
446
|
+
if (
|
|
447
|
+
printerCount > 0 &&
|
|
448
|
+
!confirm(
|
|
449
|
+
`This group contains ${printerCount} printers, are you sure to delete it?`
|
|
450
|
+
)
|
|
451
|
+
) {
|
|
452
|
+
return
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
await PrinterGroupService.deleteGroup(groupId)
|
|
456
|
+
await printerGroupsQuery.refetch()
|
|
457
|
+
snackbar.info('Deleted group')
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const addPrinterToGroup = async (groupId: IdType, printerId: IdType) => {
|
|
461
|
+
await PrinterGroupService.addPrinterToGroup(groupId, printerId)
|
|
462
|
+
await printerGroupsQuery.refetch()
|
|
463
|
+
snackbar.info('Added printer to group')
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const deletePrinterFromGroup = async (groupId: IdType, printerId: IdType) => {
|
|
467
|
+
await PrinterGroupService.deletePrinterFromGroup(groupId, printerId)
|
|
468
|
+
await printerGroupsQuery.refetch()
|
|
469
|
+
snackbar.info('Removed printer from group')
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const toggleEnabled = async (printer: PrinterDto) => {
|
|
473
|
+
if (!printer.id) {
|
|
474
|
+
throw new Error('Printer ID not set, cant toggle enabled')
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
printer.enabled = !printer.enabled
|
|
478
|
+
await PrintersService.toggleEnabled(printer.id, printer.enabled)
|
|
479
|
+
}
|
|
480
|
+
</script>
|
|
481
|
+
|
|
482
|
+
<style lang="scss">
|
|
483
|
+
.disabled-highlight tbody {
|
|
484
|
+
tr:hover {
|
|
485
|
+
background-color: transparent !important;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.reorder-row-icon {
|
|
490
|
+
cursor: move;
|
|
491
|
+
}
|
|
492
|
+
</style>
|