@things-factory/organization 6.2.71 → 6.2.77

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 (30) hide show
  1. package/client/pages/approval-line/common-approval-line-templates-page.ts +2 -2
  2. package/client/pages/approval-line/my-approval-line-templates-page.ts +2 -2
  3. package/client/pages/department/department-tree-page.ts +567 -0
  4. package/client/pages/employee/employee-list-page.ts +7 -2
  5. package/client/route.ts +4 -0
  6. package/dist-client/pages/approval-line/common-approval-line-templates-page.js +2 -2
  7. package/dist-client/pages/approval-line/common-approval-line-templates-page.js.map +1 -1
  8. package/dist-client/pages/approval-line/my-approval-line-templates-page.js +2 -2
  9. package/dist-client/pages/approval-line/my-approval-line-templates-page.js.map +1 -1
  10. package/dist-client/pages/department/department-tree-page.d.ts +53 -0
  11. package/dist-client/pages/department/department-tree-page.js +533 -0
  12. package/dist-client/pages/department/department-tree-page.js.map +1 -0
  13. package/dist-client/pages/employee/employee-list-page.js +7 -2
  14. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  15. package/dist-client/route.d.ts +1 -1
  16. package/dist-client/route.js +3 -0
  17. package/dist-client/route.js.map +1 -1
  18. package/dist-client/tsconfig.tsbuildinfo +1 -1
  19. package/dist-server/service/department/department-query.js +16 -6
  20. package/dist-server/service/department/department-query.js.map +1 -1
  21. package/dist-server/service/employee/employee-type.js +11 -2
  22. package/dist-server/service/employee/employee-type.js.map +1 -1
  23. package/dist-server/service/employee/employee.js +2 -1
  24. package/dist-server/service/employee/employee.js.map +1 -1
  25. package/dist-server/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +5 -5
  27. package/server/service/department/department-query.ts +19 -7
  28. package/server/service/employee/employee-type.ts +9 -2
  29. package/server/service/employee/employee.ts +2 -1
  30. package/things-factory.config.js +1 -0
@@ -28,8 +28,8 @@ export class CommonApprovalLineTemplatesPage extends connect(store)(localize(i18
28
28
 
29
29
  width: 100%;
30
30
 
31
- --grid-record-emphasized-background-color: red;
32
- --grid-record-emphasized-color: yellow;
31
+ --grid-record-emphasized-background-color: #8b0000;
32
+ --grid-record-emphasized-color: #ff6b6b;
33
33
  }
34
34
 
35
35
  ox-grist {
@@ -28,8 +28,8 @@ export class MyApprovalLineTemplatesPage extends connect(store)(localize(i18next
28
28
 
29
29
  width: 100%;
30
30
 
31
- --grid-record-emphasized-background-color: red;
32
- --grid-record-emphasized-color: yellow;
31
+ --grid-record-emphasized-background-color: #8b0000;
32
+ --grid-record-emphasized-color: #ff6b6b;
33
33
  }
34
34
 
35
35
  ox-grist {
@@ -0,0 +1,567 @@
1
+ import '@operato/data-tree'
2
+ import '@operato/context/ox-context-page-toolbar.js'
3
+
4
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
5
+ import { PageView, store } from '@operato/shell'
6
+ import { css, html } from 'lit'
7
+ import { customElement, property, query, state } from 'lit/decorators.js'
8
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements'
9
+ import { client } from '@operato/graphql'
10
+ import { i18next, localize } from '@operato/i18n'
11
+ import { isMobileDevice } from '@operato/utils'
12
+ import { DataGrist, FetchOption, GristRecord } from '@operato/data-grist'
13
+
14
+ import { connect } from 'pwa-helpers/connect-mixin'
15
+ import gql from 'graphql-tag'
16
+
17
+ import { DepartmentImporter } from './department-importer'
18
+ import { Department } from '../../types/department'
19
+
20
+ import { DepartmentView } from '../../component/department-view'
21
+
22
+ const departmentFragment = gql`
23
+ fragment Department_department on Department {
24
+ id
25
+ controlNo
26
+ name
27
+ description
28
+
29
+ manager {
30
+ id
31
+ name
32
+ controlNo
33
+ photo
34
+ email
35
+ }
36
+ active
37
+ state
38
+ picture
39
+
40
+ updater {
41
+ id
42
+ name
43
+ }
44
+ updatedAt
45
+ }
46
+ `
47
+
48
+ @customElement('department-tree-page')
49
+ export class DepartmentTreePage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
50
+ static styles = [
51
+ ScrollbarStyles,
52
+ CommonHeaderStyles,
53
+ css`
54
+ :host {
55
+ display: flex;
56
+
57
+ width: 100%;
58
+
59
+ --grid-record-emphasized-background-color: #8b0000;
60
+ --grid-record-emphasized-color: #ff6b6b;
61
+ }
62
+
63
+ ox-grist {
64
+ overflow-y: auto;
65
+ flex: 1;
66
+ }
67
+ `
68
+ ]
69
+
70
+ static get scopedElements() {
71
+ return {
72
+ 'department-importer': DepartmentImporter
73
+ }
74
+ }
75
+
76
+ @state() root?: Department
77
+ @state() selected?: Department
78
+
79
+ @query('ox-grist') private grist!: DataGrist
80
+
81
+ get context() {
82
+ return {
83
+ title: i18next.t('title.department list'),
84
+ help: 'organization/department',
85
+ actions: [
86
+ {
87
+ icon: 'add',
88
+ title: i18next.t('button.add'),
89
+ action: this.create.bind(this)
90
+ },
91
+ {
92
+ icon: 'save',
93
+ title: i18next.t('button.save'),
94
+ action: this.save.bind(this)
95
+ },
96
+ {
97
+ icon: 'delete',
98
+ title: i18next.t('button.delete'),
99
+ action: this.delete.bind(this)
100
+ }
101
+ ].filter(Boolean),
102
+ exportable: {
103
+ name: i18next.t('title.department list'),
104
+ data: this.exportHandler.bind(this)
105
+ },
106
+ importable: {
107
+ handler: this.importHandler.bind(this)
108
+ },
109
+ toolbar: false
110
+ }
111
+ }
112
+
113
+ @property({ type: Object }) gristConfig: any
114
+
115
+ render() {
116
+ const mode = isMobileDevice() ? 'CARD' : 'GRID'
117
+
118
+ return html`
119
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
120
+ <div slot="headroom" class="header">
121
+ <div class="title">
122
+ <mwc-icon>summarize</mwc-icon>
123
+ ${i18next.t('title.employee list')}
124
+ </div>
125
+
126
+ <div class="filters">
127
+ <ox-filters-form class="filter" autofocus without-search></ox-filters-form>
128
+ </div>
129
+
130
+ <ox-context-page-toolbar class="actions" .context=${this.context}></ox-context-page-toolbar>
131
+ </div>
132
+ </ox-grist>
133
+ `
134
+ }
135
+
136
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
137
+ const response = await client.query({
138
+ query: gql`
139
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
140
+ responses: departmentRoot {
141
+ ...Department_department
142
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
143
+ ...Department_department
144
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
145
+ ...Department_department
146
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
147
+ ...Department_department
148
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
149
+ ...Department_department
150
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
151
+ ...Department_department
152
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
153
+ ...Department_department
154
+ children(filters: $filters, pagination: $pagination, sortings: $sortings) {
155
+ ...Department_department
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ ${departmentFragment}
167
+ `,
168
+ variables: {
169
+ filters,
170
+ pagination: { page, limit },
171
+ sortings
172
+ }
173
+ })
174
+
175
+ const root = response.data.responses
176
+
177
+ return {
178
+ total: 1, //response.data.responses.total || 0,
179
+ records: [root]
180
+ }
181
+ }
182
+
183
+ async delete() {
184
+ if (!this.selected) {
185
+ alert('select department first.')
186
+ }
187
+
188
+ const children = this.selected?.children
189
+ if (children && children.length > 0) {
190
+ alert('Department having children cannot be deleted.')
191
+ }
192
+
193
+ if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
194
+ const { id } = this.selected || {}
195
+
196
+ const response = await client.mutate({
197
+ mutation: gql`
198
+ mutation ($id: String!) {
199
+ deleteDepartment(id: $id)
200
+ }
201
+ `,
202
+ variables: {
203
+ id
204
+ }
205
+ })
206
+
207
+ this.selected = {}
208
+ this.updateContext()
209
+
210
+ await this.grist.fetch()
211
+ }
212
+ }
213
+
214
+ async pageInitialized(lifecycle: any) {
215
+ this.gristConfig = {
216
+ pagination: { pages: [50, 100, 200] },
217
+ list: {
218
+ thumbnail: 'profile',
219
+ fields: ['controlNo', 'name'],
220
+ details: ['email', 'manager', 'updatedAt']
221
+ },
222
+ columns: [
223
+ {
224
+ type: 'gutter',
225
+ gutterName: 'dirty',
226
+ fixed: true
227
+ },
228
+ {
229
+ type: 'tree',
230
+ name: 'name',
231
+ label: true,
232
+ header: i18next.t('label.name'),
233
+ record: {
234
+ editable: false,
235
+ options: {
236
+ childrenProperty: 'children',
237
+ selectable: true
238
+ }
239
+ },
240
+ filter: 'search',
241
+ sortable: true,
242
+ width: 200,
243
+ fixed: true
244
+ },
245
+ { name: 'id', hidden: true },
246
+ {
247
+ type: 'string',
248
+ name: 'controlNo',
249
+ header: i18next.t('label.control-no'),
250
+ record: {
251
+ editable: true
252
+ },
253
+ filter: 'search',
254
+ sortable: true,
255
+ width: 110
256
+ },
257
+ {
258
+ type: 'string',
259
+ name: 'description',
260
+ header: i18next.t('label.description'),
261
+ record: {
262
+ editable: true
263
+ },
264
+ filter: 'search',
265
+ sortable: true,
266
+ width: 110
267
+ },
268
+ {
269
+ type: 'string',
270
+ name: 'state',
271
+ header: i18next.t('label.state'),
272
+ record: {
273
+ editable: true
274
+ },
275
+ sortable: true,
276
+ width: 110
277
+ },
278
+ {
279
+ type: 'resource-object',
280
+ name: 'manager',
281
+ header: i18next.t('label.manager'),
282
+ record: {
283
+ editable: true,
284
+ options: {
285
+ title: i18next.t('title.employee list'),
286
+ queryName: 'employees',
287
+ pagination: { pages: [50, 100, 200] },
288
+ basicArgs: {
289
+ filters: [
290
+ {
291
+ name: 'active',
292
+ operator: 'eq',
293
+ value: true
294
+ }
295
+ ]
296
+ },
297
+ list: { fields: ['controlNo', 'name', 'email'] },
298
+ columns: [
299
+ { name: 'id', hidden: true },
300
+ {
301
+ name: 'controlNo',
302
+ width: 120,
303
+ header: { renderer: () => i18next.t('field.control-no') },
304
+ filter: 'search',
305
+ sortable: true
306
+ },
307
+ {
308
+ name: 'name',
309
+ width: 120,
310
+ header: { renderer: () => i18next.t('field.name') },
311
+ filter: 'search',
312
+ sortable: true
313
+ },
314
+ {
315
+ name: 'email',
316
+ width: 150,
317
+ header: { renderer: () => i18next.t('label.email') },
318
+ filter: 'search',
319
+ sortable: true
320
+ }
321
+ ],
322
+ valueField: 'id',
323
+ nameField: 'name',
324
+ descriptionField: 'controlNo'
325
+ }
326
+ },
327
+ sortable: true,
328
+ width: 120
329
+ },
330
+ {
331
+ type: 'checkbox',
332
+ name: 'active',
333
+ label: true,
334
+ header: i18next.t('field.active'),
335
+ width: 70,
336
+ record: {
337
+ align: 'center',
338
+ editable: true
339
+ },
340
+ filter: true,
341
+ sortable: true
342
+ },
343
+ {
344
+ type: 'resource-object',
345
+ name: 'updater',
346
+ header: i18next.t('field.updater'),
347
+ width: 90,
348
+ sortable: false
349
+ },
350
+ {
351
+ type: 'datetime',
352
+ name: 'updatedAt',
353
+ header: i18next.t('field.updated_at'),
354
+ width: 180,
355
+ sortable: true
356
+ },
357
+ {
358
+ type: 'image',
359
+ name: 'picture',
360
+ record: {
361
+ renderer: function (value, column, record, rowIndex, field) {
362
+ return html`<ox-pfp-view
363
+ style="height:90%; width: unset; aspect-ratio: 1 / 1;"
364
+ .profile=${record.picture}
365
+ .name=${record.name}
366
+ ></ox-pfp-view>`
367
+ }
368
+ },
369
+ hidden: true
370
+ }
371
+ ],
372
+ rows: {
373
+ selectable: {
374
+ multiple: true
375
+ }
376
+ },
377
+ sorters: [
378
+ {
379
+ name: 'controlNo'
380
+ }
381
+ ]
382
+ }
383
+ }
384
+
385
+ async pageUpdated(changes: any, lifecycle: any) {
386
+ if (this.active) {
387
+ // do something here when this page just became as active
388
+ }
389
+ }
390
+
391
+ async create() {
392
+ // const { id: parentId } = this.selected || {}
393
+ // const { controlNo, name, description, state, picture, active, manager } = this.grist.department
394
+
395
+ // var department = {
396
+ // controlNo,
397
+ // name,
398
+ // description,
399
+ // state,
400
+ // manager,
401
+ // active
402
+ // } as any
403
+
404
+ // if (picture instanceof File) {
405
+ // department.picture = picture
406
+ // }
407
+
408
+ // if (parentId) {
409
+ // department.parent = { id: parentId }
410
+ // }
411
+
412
+ // const response = await client.mutate({
413
+ // mutation: gql`
414
+ // mutation ($department: NewDepartment!) {
415
+ // createDepartment(department: $department) {
416
+ // ...Department_department
417
+ // }
418
+ // }
419
+
420
+ // ${departmentFragment}
421
+ // `,
422
+ // variables: {
423
+ // department
424
+ // },
425
+ // context: {
426
+ // hasUpload: true
427
+ // }
428
+ // })
429
+
430
+ // this.selected = response.data.createDepartment
431
+ // this.updateContext()
432
+
433
+ await this.grist.fetch()
434
+ }
435
+
436
+ // async _deleteDataSet() {
437
+ // if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
438
+ // const ids = this.grist.selected.map(record => record.id)
439
+ // if (ids && ids.length > 0) {
440
+ // const response = await client.mutate({
441
+ // mutation: gql`
442
+ // mutation ($ids: [String!]!) {
443
+ // deleteDataSets(ids: $ids)
444
+ // }
445
+ // `,
446
+ // variables: {
447
+ // ids
448
+ // }
449
+ // })
450
+
451
+ // if (!response.errors) {
452
+ // this.grist.fetch()
453
+ // notify({
454
+ // message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
455
+ // })
456
+ // }
457
+ // }
458
+ // }
459
+ // }
460
+
461
+ // async _copyDataSet() {
462
+ // var selected = this.grist.selected
463
+ // if (selected.length == 0) return
464
+
465
+ // if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.copy') }))) return
466
+ // var response = await client.mutate({
467
+ // mutation: gql`
468
+ // mutation ($ids: [String!]!) {
469
+ // copyDataSets(ids: $ids) {
470
+ // id
471
+ // }
472
+ // }
473
+ // `,
474
+ // variables: {
475
+ // ids: selected.map(r => r.id)
476
+ // }
477
+ // })
478
+
479
+ // if (!response.errors) {
480
+ // this.grist.fetch()
481
+ // }
482
+ // }
483
+
484
+ // async save() {
485
+ // const { id, controlNo, name, description, state, picture, active, manager } = this.departmentView.department
486
+
487
+ // if (!id) {
488
+ // alert('Please select department first.')
489
+ // }
490
+
491
+ // var patch = {
492
+ // controlNo,
493
+ // name,
494
+ // description,
495
+ // state,
496
+ // active,
497
+ // manager
498
+ // } as any
499
+
500
+ // if (picture instanceof File) {
501
+ // patch.picture = picture
502
+ // }
503
+
504
+ // const response = await client.mutate({
505
+ // mutation: gql`
506
+ // mutation ($id: String!, $patch: DepartmentPatch!) {
507
+ // updateDepartment(id: $id, patch: $patch) {
508
+ // ...Department_department
509
+ // }
510
+ // }
511
+
512
+ // ${departmentFragment}
513
+ // `,
514
+ // variables: {
515
+ // id,
516
+ // patch
517
+ // },
518
+ // context: {
519
+ // hasUpload: true
520
+ // }
521
+ // })
522
+
523
+ // this.selected = response.data.updateDepartment
524
+
525
+ // this.fetch()
526
+ // }
527
+
528
+ async save() {
529
+ let patches = this.grist.dirtyRecords
530
+ if (patches && patches.length) {
531
+ patches = patches.map(patch => {
532
+ let patchField: any = patch.id ? { id: patch.id } : {}
533
+ const dirtyFields = patch.__dirtyfields__
534
+ for (let key in dirtyFields) {
535
+ patchField[key] = dirtyFields[key].after
536
+ }
537
+ patchField.cuFlag = patch.__dirty__
538
+
539
+ return patchField
540
+ })
541
+
542
+ const response = await client.mutate({
543
+ mutation: gql`
544
+ mutation ($patches: [DepartmentPatch!]!) {
545
+ updateMultipleDepartment(patches: $patches) {
546
+ name
547
+ }
548
+ }
549
+ `,
550
+ variables: {
551
+ patches
552
+ },
553
+ context: {
554
+ hasUpload: true
555
+ }
556
+ })
557
+
558
+ if (!response.errors) {
559
+ this.grist.fetch()
560
+ }
561
+ }
562
+ }
563
+
564
+ async exportHandler() {}
565
+
566
+ async importHandler(records) {}
567
+ }
@@ -30,8 +30,13 @@ export class EmployeeListPage extends connect(store)(localize(i18next)(ScopedEle
30
30
 
31
31
  width: 100%;
32
32
 
33
- --grid-record-emphasized-background-color: red;
34
- --grid-record-emphasized-color: yellow;
33
+ --grid-record-emphasized-background-color: #8b0000;
34
+ --grid-record-emphasized-color: #ff6b6b;
35
+ }
36
+
37
+ ox-grist {
38
+ overflow-y: auto;
39
+ flex: 1;
35
40
  }
36
41
  `
37
42
  ]
package/client/route.ts CHANGED
@@ -8,6 +8,10 @@ export default function route(page: string) {
8
8
  import('./pages/department/department-list-page')
9
9
  return page
10
10
 
11
+ case 'department-tree':
12
+ import('./pages/department/department-tree-page')
13
+ return page
14
+
11
15
  case 'employees-by-department':
12
16
  import('./pages/employee/employees-by-department')
13
17
  return page
@@ -339,8 +339,8 @@ CommonApprovalLineTemplatesPage.styles = [
339
339
 
340
340
  width: 100%;
341
341
 
342
- --grid-record-emphasized-background-color: red;
343
- --grid-record-emphasized-color: yellow;
342
+ --grid-record-emphasized-background-color: #8b0000;
343
+ --grid-record-emphasized-color: #ff6b6b;
344
344
  }
345
345
 
346
346
  ox-grist {