@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.
Files changed (205) hide show
  1. package/.all-contributorsrc +57 -0
  2. package/.browserslistrc +4 -0
  3. package/.editorconfig +5 -0
  4. package/.env +1 -0
  5. package/.eslintrc-auto-import.json +73 -0
  6. package/.eslintrc.js +126 -0
  7. package/.github/FUNDING.yml +3 -0
  8. package/.github/workflows/release-client.yml +94 -0
  9. package/.github/workflows/vue-publish.yml +26 -0
  10. package/.prettierignore +15 -0
  11. package/.prettierrc.cjs +7 -0
  12. package/.whitesource +12 -0
  13. package/.yarn/releases/yarn-4.5.1.cjs +934 -0
  14. package/.yarnrc.yml +3 -0
  15. package/CODE_OF_CONDUCT.md +46 -0
  16. package/README.md +93 -0
  17. package/RELEASE_NOTES.MD +11 -0
  18. package/index.html +16 -0
  19. package/package.default.json +42 -0
  20. package/package.json +26 -0
  21. package/public/favicon.ico +0 -0
  22. package/public/img/DavidZwart.jpg +0 -0
  23. package/public/img/OIG.JYDC2RaWdz7g9.jpg +0 -0
  24. package/public/img/OIG.jpg +0 -0
  25. package/public/img/icons/android-chrome-192x192.png +0 -0
  26. package/public/img/icons/android-chrome-256x256.png +0 -0
  27. package/public/img/icons/android-chrome-384x384.png +0 -0
  28. package/public/img/icons/android-chrome-512x512.png +0 -0
  29. package/public/img/icons/favicon.svg +1 -0
  30. package/public/img/logo.png +0 -0
  31. package/public/img/logo.svg +1 -0
  32. package/public/img/manifest.webmanifest +33 -0
  33. package/public/img/octoprint-tentacle.svg +144 -0
  34. package/public/img/thumbail_unknown.jpg +0 -0
  35. package/public/img/vbanner.jpg +0 -0
  36. package/public/index.html +17 -0
  37. package/public/robots.txt +2 -0
  38. package/renovate.json +30 -0
  39. package/src/App.vue +60 -0
  40. package/src/AppLoader.vue +383 -0
  41. package/src/assets/adjectives.json +1468 -0
  42. package/src/assets/android-chrome-192x192.png +0 -0
  43. package/src/assets/logo.png +0 -0
  44. package/src/assets/logo.svg +6 -0
  45. package/src/assets/nouns.json +4309 -0
  46. package/src/auto-imports.d.ts +139 -0
  47. package/src/backend/app.service.ts +39 -0
  48. package/src/backend/auth.service.ts +56 -0
  49. package/src/backend/base.service.ts +57 -0
  50. package/src/backend/batch.service.ts +37 -0
  51. package/src/backend/camera-stream.service.ts +33 -0
  52. package/src/backend/custom-gcode.service.ts +11 -0
  53. package/src/backend/dto/octoprint-settings.dto.ts +168 -0
  54. package/src/backend/first-time-setup.service.ts +17 -0
  55. package/src/backend/floor.service.ts +84 -0
  56. package/src/backend/index.ts +4 -0
  57. package/src/backend/print-completions.service.ts +11 -0
  58. package/src/backend/printer-file.service.ts +91 -0
  59. package/src/backend/printer-group.service.ts +62 -0
  60. package/src/backend/printer-job.service.ts +20 -0
  61. package/src/backend/printer-settings.service.ts +28 -0
  62. package/src/backend/printers.service.ts +136 -0
  63. package/src/backend/server-private.service.ts +55 -0
  64. package/src/backend/server.api.ts +132 -0
  65. package/src/backend/settings.service.ts +85 -0
  66. package/src/backend/user.service.ts +51 -0
  67. package/src/components/AboutHelp/AboutView.vue +164 -0
  68. package/src/components/CameraGrid/CameraGridView.vue +111 -0
  69. package/src/components/FirstTimeSetup/FirstTimeSetupView.vue +354 -0
  70. package/src/components/Generic/Actions/PrinterConnectionAction.vue +56 -0
  71. package/src/components/Generic/Actions/PrinterCreateAction.vue +22 -0
  72. package/src/components/Generic/Actions/PrinterDeleteAction.vue +29 -0
  73. package/src/components/Generic/Actions/PrinterQuickStopAction.vue +35 -0
  74. package/src/components/Generic/Actions/PrinterSettingsAction.vue +35 -0
  75. package/src/components/Generic/Actions/PrinterUrlAction.vue +24 -0
  76. package/src/components/Generic/Actions/RefreshFilesAction.vue +50 -0
  77. package/src/components/Generic/Actions/SyncPrinterNameAction.vue +36 -0
  78. package/src/components/Generic/Dialogs/AddOrUpdateCameraStreamDialog.vue +131 -0
  79. package/src/components/Generic/Dialogs/AddOrUpdateFloorDialog.vue +141 -0
  80. package/src/components/Generic/Dialogs/AddOrUpdatePrinterDialog.vue +303 -0
  81. package/src/components/Generic/Dialogs/BaseDialog.vue +81 -0
  82. package/src/components/Generic/Dialogs/BatchJsonCreateDialog.vue +109 -0
  83. package/src/components/Generic/Dialogs/BatchReprintDialog.vue +190 -0
  84. package/src/components/Generic/Dialogs/PrinterChecksPanel.vue +37 -0
  85. package/src/components/Generic/Dialogs/PrinterControlDialog.vue +202 -0
  86. package/src/components/Generic/Dialogs/PrinterMaintenanceDialog.vue +130 -0
  87. package/src/components/Generic/Dialogs/YamlImportExportDialog.vue +186 -0
  88. package/src/components/Generic/Dialogs/dialog.constants.ts +19 -0
  89. package/src/components/Generic/FileExplorerSideNav.vue +734 -0
  90. package/src/components/Generic/Loaders/GridLoader.vue +68 -0
  91. package/src/components/Generic/NavigationDrawer.vue +69 -0
  92. package/src/components/Generic/PrintJobsMenu.vue +148 -0
  93. package/src/components/Generic/Snackbars/AppErrorSnackbar.vue +64 -0
  94. package/src/components/Generic/Snackbars/AppInfoSnackbar.vue +63 -0
  95. package/src/components/Generic/Snackbars/AppProgressSnackbar.vue +158 -0
  96. package/src/components/Generic/Vuetify/TooltipButton.vue +47 -0
  97. package/src/components/HelpOverlay/HelpOverlay.vue +57 -0
  98. package/src/components/Login/LoginForm.vue +206 -0
  99. package/src/components/Login/LoginView.spec.ts +64 -0
  100. package/src/components/Login/LoginView.vue +65 -0
  101. package/src/components/Login/Logo.vue +13 -0
  102. package/src/components/Login/PermissionDenied.vue +109 -0
  103. package/src/components/Login/RegistrationForm.vue +207 -0
  104. package/src/components/Login/RegistrationView.vue +17 -0
  105. package/src/components/Login/__snapshots__/LoginView.spec.ts.snap +1051 -0
  106. package/src/components/NotFound/NotFoundView.vue +39 -0
  107. package/src/components/PrintStatistics/PrintStatistics.vue +168 -0
  108. package/src/components/PrintStatistics/PrintStatisticsView.vue +15 -0
  109. package/src/components/PrinterGrid/HomeToolbar.vue +90 -0
  110. package/src/components/PrinterGrid/PrinterGrid.vue +164 -0
  111. package/src/components/PrinterGrid/PrinterGridTile.vue +438 -0
  112. package/src/components/PrinterGrid/PrinterGridView.vue +210 -0
  113. package/src/components/PrinterList/FileControlList.vue +40 -0
  114. package/src/components/PrinterList/PrinterDetails.vue +91 -0
  115. package/src/components/PrinterList/PrintersView.vue +492 -0
  116. package/src/components/Settings/AccountSettings.vue +163 -0
  117. package/src/components/Settings/DiagnosticsSettings.vue +137 -0
  118. package/src/components/Settings/EmergencyCommands.vue +265 -0
  119. package/src/components/Settings/FloorSettings.vue +276 -0
  120. package/src/components/Settings/GridSettings.vue +127 -0
  121. package/src/components/Settings/OctoPrintSettings.vue +188 -0
  122. package/src/components/Settings/ServerProtectionSettings.vue +370 -0
  123. package/src/components/Settings/SettingsView.vue +73 -0
  124. package/src/components/Settings/SoftwareUpgradeSettings.vue +297 -0
  125. package/src/components/Settings/UserManagementSettings.vue +257 -0
  126. package/src/components/TopBar.vue +147 -0
  127. package/src/components.d.ts +70 -0
  128. package/src/directives/file-upload.directive.ts +117 -0
  129. package/src/directives/printer-drop-position.directive.ts +92 -0
  130. package/src/env.d.ts +6 -0
  131. package/src/main.ts +76 -0
  132. package/src/models/batch/reprint.dto.ts +79 -0
  133. package/src/models/batch.model.ts +11 -0
  134. package/src/models/camera-streams/camera-stream.ts +19 -0
  135. package/src/models/floors/floor.model.ts +30 -0
  136. package/src/models/octoprint/connection-options.model.ts +8 -0
  137. package/src/models/plugins/firmware-updates/prusa-firmware-release.model.ts +57 -0
  138. package/src/models/print-completions/print-completions.model.ts +49 -0
  139. package/src/models/printers/crud/create-printer.model.ts +26 -0
  140. package/src/models/printers/file-upload-commands.model.ts +4 -0
  141. package/src/models/printers/gcode/gcode-analysis.model.ts +30 -0
  142. package/src/models/printers/printer-current-job.model.ts +90 -0
  143. package/src/models/printers/printer-file.model.ts +48 -0
  144. package/src/models/printers/printer.model.ts +18 -0
  145. package/src/models/server/client-releases.model.ts +27 -0
  146. package/src/models/server/export-yaml.model.ts +11 -0
  147. package/src/models/server/features.model.ts +37 -0
  148. package/src/models/server/github-rate-limit.model.ts +21 -0
  149. package/src/models/server/version.model.ts +14 -0
  150. package/src/models/settings/printer-file-clean-settings.model.ts +5 -0
  151. package/src/models/settings/server-settings.dto.ts +19 -0
  152. package/src/models/settings/settings.model.ts +57 -0
  153. package/src/models/socketio-messages/socketio-message.model.ts +53 -0
  154. package/src/models/uploads/queued-upload.model.ts +12 -0
  155. package/src/models/user.model.ts +15 -0
  156. package/src/plugins/README.md +3 -0
  157. package/src/plugins/index.ts +17 -0
  158. package/src/plugins/vuetify.ts +53 -0
  159. package/src/router/index.ts +192 -0
  160. package/src/router/route-names.ts +14 -0
  161. package/src/router/utils.ts +23 -0
  162. package/src/shared/alert.events.ts +14 -0
  163. package/src/shared/app.constants.ts +23 -0
  164. package/src/shared/auth.constants.ts +34 -0
  165. package/src/shared/dialog.composable.ts +41 -0
  166. package/src/shared/drag.constants.ts +19 -0
  167. package/src/shared/experimental.constants.ts +1 -0
  168. package/src/shared/http-client.ts +162 -0
  169. package/src/shared/noun-adjectives.data.ts +24 -0
  170. package/src/shared/printer-grid.constants.ts +5 -0
  171. package/src/shared/printer-state.constants.ts +194 -0
  172. package/src/shared/snackbar.composable.ts +66 -0
  173. package/src/shared/socketio.service.ts +104 -0
  174. package/src/store/auth.store.ts +255 -0
  175. package/src/store/connection.store.ts +66 -0
  176. package/src/store/dialog.store.ts +114 -0
  177. package/src/store/features.store.ts +57 -0
  178. package/src/store/floor.store.ts +173 -0
  179. package/src/store/grid.store.ts +10 -0
  180. package/src/store/index.ts +4 -0
  181. package/src/store/printer-state.store.ts +246 -0
  182. package/src/store/printer.store.ts +236 -0
  183. package/src/store/profile.store.ts +25 -0
  184. package/src/store/settings.store.ts +64 -0
  185. package/src/store/test-printer.store.ts +70 -0
  186. package/src/store/uploads.store.ts +75 -0
  187. package/src/styles/README.md +3 -0
  188. package/src/styles/settings.scss +10 -0
  189. package/src/types/global.d.ts +15 -0
  190. package/src/utils/array.utils.ts +15 -0
  191. package/src/utils/date.utils.ts +5 -0
  192. package/src/utils/download-file.util.ts +25 -0
  193. package/src/utils/error.utils.ts +3 -0
  194. package/src/utils/file-size.util.ts +11 -0
  195. package/src/utils/id.type.ts +1 -0
  196. package/src/utils/sentry.util.ts +8 -0
  197. package/src/utils/test.util.ts +30 -0
  198. package/src/utils/time.utils.ts +2 -0
  199. package/src/utils/uploads-state.utils.ts +58 -0
  200. package/src/utils/validation.utils.ts +14 -0
  201. package/src/vite-env.d.ts +7 -0
  202. package/test/setup-axios-mock.ts +15 -0
  203. package/tsconfig.json +47 -0
  204. package/tsconfig.node.json +9 -0
  205. 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>