@things-factory/organization 8.0.0-beta.8 → 8.0.0

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 (94) hide show
  1. package/client/bootstrap.ts +23 -0
  2. package/client/component/approval-line-brief.ts +119 -0
  3. package/client/component/approval-line-items-editor-popup.ts +91 -0
  4. package/client/component/approval-line-items-editor.ts +325 -0
  5. package/client/component/approval-line-selector.ts +235 -0
  6. package/client/component/approval-line-templates-manager.ts +229 -0
  7. package/client/component/approval-line-view.ts +122 -0
  8. package/client/component/assignees-editor-popup.ts +79 -0
  9. package/client/component/assignees-editor.ts +217 -0
  10. package/client/component/assignees-view.ts +55 -0
  11. package/client/component/department-selector.ts +151 -0
  12. package/client/component/department-view.ts +107 -0
  13. package/client/component/index.ts +16 -0
  14. package/client/component/recipients-editor-popup.ts +79 -0
  15. package/client/component/recipients-editor.ts +212 -0
  16. package/client/component/recipients-view.ts +55 -0
  17. package/client/grist-editor/grist-editor-approval-line.ts +70 -0
  18. package/client/grist-editor/grist-editor-assignees.ts +69 -0
  19. package/client/grist-editor/grist-editor-department-object.ts +78 -0
  20. package/client/grist-editor/grist-editor-recipients.ts +69 -0
  21. package/client/grist-editor/grist-renderer-approval-line.ts +13 -0
  22. package/client/grist-editor/grist-renderer-assignees.ts +13 -0
  23. package/client/grist-editor/grist-renderer-department-object.ts +13 -0
  24. package/client/grist-editor/grist-renderer-recipients.ts +13 -0
  25. package/client/index.ts +2 -0
  26. package/client/pages/approval-line/common-approval-line-templates-page.ts +382 -0
  27. package/client/pages/approval-line/my-approval-line-templates-page.ts +385 -0
  28. package/client/pages/department/department-importer.ts +87 -0
  29. package/client/pages/department/department-list-page.ts +450 -0
  30. package/client/pages/department/department-tree-page.ts +379 -0
  31. package/client/pages/employee/employee-importer.ts +87 -0
  32. package/client/pages/employee/employee-list-page.ts +772 -0
  33. package/client/pages/employee/employees-by-department.ts +519 -0
  34. package/client/route.ts +27 -0
  35. package/client/tsconfig.json +13 -0
  36. package/client/types/approval-line.ts +52 -0
  37. package/client/types/contact.ts +51 -0
  38. package/client/types/department.ts +29 -0
  39. package/client/types/employee.ts +50 -0
  40. package/client/types/index.ts +5 -0
  41. package/client/types/org-member.ts +27 -0
  42. package/dist-client/bootstrap.js +1 -8
  43. package/dist-client/bootstrap.js.map +1 -1
  44. package/dist-client/pages/employee/employee-list-page.js +3 -3
  45. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  46. package/dist-client/pages/employee/employees-by-department.js +2 -2
  47. package/dist-client/pages/employee/employees-by-department.js.map +1 -1
  48. package/dist-client/tsconfig.tsbuildinfo +1 -1
  49. package/dist-server/service/employee/employee-history.d.ts +2 -6
  50. package/dist-server/service/employee/employee-history.js +3 -23
  51. package/dist-server/service/employee/employee-history.js.map +1 -1
  52. package/dist-server/service/employee/employee-query.js +1 -1
  53. package/dist-server/service/employee/employee-query.js.map +1 -1
  54. package/dist-server/service/employee/employee-type.d.ts +5 -13
  55. package/dist-server/service/employee/employee-type.js +7 -39
  56. package/dist-server/service/employee/employee-type.js.map +1 -1
  57. package/dist-server/service/employee/employee.d.ts +2 -6
  58. package/dist-server/service/employee/employee.js +3 -23
  59. package/dist-server/service/employee/employee.js.map +1 -1
  60. package/dist-server/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +12 -12
  62. package/server/controllers/register-employee-as-system-user.ts +136 -0
  63. package/server/index.ts +3 -0
  64. package/server/migrations/1723861013111-seed-organization-codes.ts +127 -0
  65. package/server/migrations/index.ts +9 -0
  66. package/server/routes.ts +26 -0
  67. package/server/service/approval-line/approval-line-item.ts +42 -0
  68. package/server/service/approval-line/approval-line-mutation.ts +394 -0
  69. package/server/service/approval-line/approval-line-query.ts +208 -0
  70. package/server/service/approval-line/approval-line-type.ts +63 -0
  71. package/server/service/approval-line/approval-line.ts +123 -0
  72. package/server/service/approval-line/index.ts +7 -0
  73. package/server/service/department/department-history.ts +141 -0
  74. package/server/service/department/department-mutation.ts +231 -0
  75. package/server/service/department/department-query.ts +131 -0
  76. package/server/service/department/department-type.ts +74 -0
  77. package/server/service/department/department.ts +116 -0
  78. package/server/service/department/event-subscriber.ts +17 -0
  79. package/server/service/department/index.ts +9 -0
  80. package/server/service/employee/employee-history.ts +173 -0
  81. package/server/service/employee/employee-mutation.ts +386 -0
  82. package/server/service/employee/employee-query.ts +172 -0
  83. package/server/service/employee/employee-type.ts +176 -0
  84. package/server/service/employee/employee.ts +177 -0
  85. package/server/service/employee/event-subscriber.ts +17 -0
  86. package/server/service/employee/index.ts +9 -0
  87. package/server/service/index.ts +39 -0
  88. package/server/tsconfig.json +10 -0
  89. package/dist-client/filters-form/filter-department-object.d.ts +0 -3
  90. package/dist-client/filters-form/filter-department-object.js +0 -8
  91. package/dist-client/filters-form/filter-department-object.js.map +0 -1
  92. package/dist-client/filters-form/ox-filter-department-object.d.ts +0 -15
  93. package/dist-client/filters-form/ox-filter-department-object.js +0 -130
  94. package/dist-client/filters-form/ox-filter-department-object.js.map +0 -1
@@ -0,0 +1,385 @@
1
+ import '@operato/data-grist'
2
+ import '@operato/context/ox-context-page-toolbar.js'
3
+ import '../../component/approval-line-items-editor-popup'
4
+
5
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
6
+ import { PageView, store } from '@operato/shell'
7
+ import { css, html } from 'lit'
8
+
9
+ import { customElement, property, query } from 'lit/decorators.js'
10
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements'
11
+ import { getRenderer, DataGrist, FetchOption } from '@operato/data-grist'
12
+ import { client } from '@operato/graphql'
13
+ import { i18next, localize } from '@operato/i18n'
14
+ import { notify, openPopup } from '@operato/layout'
15
+ import { isMobileDevice } from '@operato/utils'
16
+
17
+ import { connect } from 'pwa-helpers/connect-mixin'
18
+ import gql from 'graphql-tag'
19
+
20
+ @customElement('my-approval-line-templates-page')
21
+ export class MyApprovalLineTemplatesPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
22
+ static styles = [
23
+ ScrollbarStyles,
24
+ CommonHeaderStyles,
25
+ css`
26
+ :host {
27
+ display: flex;
28
+
29
+ width: 100%;
30
+
31
+ --grid-record-emphasized-background-color: #8b0000;
32
+ --grid-record-emphasized-color: #ff6b6b;
33
+ }
34
+
35
+ ox-grist {
36
+ flex: 1;
37
+ }
38
+
39
+ .header {
40
+ grid-template-areas: 'filters actions';
41
+ }
42
+ `
43
+ ]
44
+
45
+ @property({ type: Object }) gristConfig: any
46
+ @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
47
+
48
+ @query('ox-grist') private grist!: DataGrist
49
+
50
+ get context() {
51
+ return {
52
+ title: i18next.t('title.my-approval-line template list'),
53
+ search: {
54
+ handler: (search: string) => {
55
+ this.grist.searchText = search
56
+ },
57
+ value: this.grist?.searchText || ''
58
+ },
59
+ filter: {
60
+ handler: () => {
61
+ this.grist.toggleHeadroom()
62
+ }
63
+ },
64
+ help: 'organization/approval-line',
65
+ actions: [
66
+ {
67
+ icon: 'save',
68
+ title: i18next.t('button.save'),
69
+ action: this.updateApprovalLines.bind(this)
70
+ },
71
+ {
72
+ icon: 'delete',
73
+ title: i18next.t('button.delete'),
74
+ action: this.deleteApprovalLines.bind(this),
75
+ emphasis: {
76
+ danger: true
77
+ }
78
+ }
79
+ ],
80
+ toolbar: false
81
+ }
82
+ }
83
+
84
+ render() {
85
+ const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
86
+
87
+ return html`
88
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
89
+ <div slot="headroom" class="header">
90
+ <ox-context-page-toolbar class="actions" .context=${this.context}></ox-context-page-toolbar>
91
+ </div>
92
+ </ox-grist>
93
+ `
94
+ }
95
+
96
+ async pageInitialized(lifecycle: any) {
97
+ this.gristConfig = {
98
+ list: {
99
+ fields: ['name', 'description'],
100
+ details: ['updatedAt']
101
+ },
102
+ columns: [
103
+ { type: 'gutter', gutterName: 'sequence', fixed: true },
104
+ { type: 'gutter', gutterName: 'row-selector', fixed: true, multiple: true },
105
+ {
106
+ type: 'gutter',
107
+ gutterName: 'button',
108
+ fixed: true,
109
+ icon: record => (!record ? 'reorder' : record.id ? 'reorder' : ''),
110
+ iconOnly: false,
111
+ title: record => (!record ? i18next.t('button.edit') : record.id ? i18next.t('button.edit') : ''),
112
+ width: 72,
113
+ handlers: {
114
+ click: (columns, data, column, record, rowIndex) => {
115
+ if (!record.id) {
116
+ return
117
+ }
118
+
119
+ const { id, model } = record
120
+ const popup = openPopup(
121
+ html`
122
+ <approval-line-items-editor-popup
123
+ .confirmCallback=${async model => {
124
+ await this.updateApprovalLine(id, model)
125
+ await this.grist.fetch()
126
+
127
+ return false
128
+ }}
129
+ .value=${model}
130
+ ></approval-line-items-editor-popup>
131
+ `,
132
+ {
133
+ backdrop: true,
134
+ help: 'organization/approval-line-items-editor',
135
+ size: 'large',
136
+ title: i18next.t('title.approval-line item list')
137
+ }
138
+ )
139
+ popup.onclosed = () => {
140
+ this.grist?.fetch()
141
+ }
142
+ }
143
+ }
144
+ },
145
+ {
146
+ type: 'string',
147
+ name: 'name',
148
+ fixed: true,
149
+ header: i18next.t('field.name'),
150
+ record: {
151
+ editable: true
152
+ },
153
+ filter: 'search',
154
+ sortable: true,
155
+ width: 300
156
+ },
157
+ {
158
+ type: 'string',
159
+ name: 'description',
160
+ header: i18next.t('field.description'),
161
+ record: {
162
+ editable: true
163
+ },
164
+ filter: 'search',
165
+ width: 325
166
+ },
167
+ {
168
+ type: 'string',
169
+ name: 'ownerType',
170
+ header: i18next.t('field.owner-type'),
171
+ width: 120
172
+ },
173
+ {
174
+ type: 'resource-object',
175
+ name: 'owner',
176
+ header: i18next.t('field.owner'),
177
+ record: {
178
+ editable: false,
179
+ renderer: function (value, column, record, rowIndex, field) {
180
+ var options = {}
181
+ switch (record.ownerType) {
182
+ case 'Employee':
183
+ options = {
184
+ valueField: 'id',
185
+ nameField: 'name',
186
+ descriptionField: 'controlNo'
187
+ }
188
+ break
189
+ case 'Common':
190
+ default:
191
+ return
192
+ }
193
+
194
+ var dynamicRecord = { ...column.record, options }
195
+ return getRenderer(column.type)(value, { ...column, record: dynamicRecord }, record, rowIndex, field)
196
+ }
197
+ },
198
+ width: 180
199
+ },
200
+ {
201
+ type: 'resource-object',
202
+ name: 'updater',
203
+ header: i18next.t('field.updater'),
204
+ record: {
205
+ editable: false
206
+ },
207
+ sortable: true,
208
+ width: 90
209
+ },
210
+ {
211
+ type: 'datetime',
212
+ name: 'updatedAt',
213
+ header: i18next.t('field.updated_at'),
214
+ record: {
215
+ editable: false
216
+ },
217
+ sortable: true,
218
+ width: 180
219
+ }
220
+ ],
221
+ rows: {
222
+ selectable: {
223
+ multiple: true
224
+ }
225
+ },
226
+ sorters: [
227
+ {
228
+ name: 'name'
229
+ }
230
+ ]
231
+ }
232
+ }
233
+
234
+ async pageUpdated(changes: any, lifecycle: any) {
235
+ if (this.active) {
236
+ // do something here when this page just became as active
237
+ }
238
+ }
239
+
240
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
241
+ const response = await client.query({
242
+ query: gql`
243
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
244
+ responses: myApprovalLines(filters: $filters, pagination: $pagination, sortings: $sortings) {
245
+ items {
246
+ id
247
+ name
248
+ description
249
+ ownerType
250
+ owner {
251
+ id
252
+ name
253
+ description
254
+ controlNo
255
+ }
256
+ model {
257
+ type
258
+ approver {
259
+ id
260
+ name
261
+ description
262
+ controlNo
263
+ }
264
+ }
265
+ updater {
266
+ id
267
+ name
268
+ }
269
+ updatedAt
270
+ }
271
+ total
272
+ }
273
+ }
274
+ `,
275
+ variables: {
276
+ filters,
277
+ pagination: { page, limit },
278
+ sortings
279
+ }
280
+ })
281
+
282
+ return {
283
+ total: response.data.responses.total || 0,
284
+ records: response.data.responses.items || []
285
+ }
286
+ }
287
+
288
+ async deleteApprovalLines() {
289
+ if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
290
+ const ids = this.grist.selected.map(record => record.id)
291
+ if (ids && ids.length > 0) {
292
+ const response = await client.mutate({
293
+ mutation: gql`
294
+ mutation ($ids: [String!]!) {
295
+ deleteMyApprovalLines(ids: $ids)
296
+ }
297
+ `,
298
+ variables: {
299
+ ids
300
+ }
301
+ })
302
+
303
+ if (!response.errors) {
304
+ this.grist.fetch()
305
+ notify({
306
+ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
307
+ })
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ async updateApprovalLines() {
314
+ let patches = this.grist.dirtyRecords
315
+ if (patches && patches.length) {
316
+ patches = patches.map(patch => {
317
+ let patchField: any = patch.id ? { id: patch.id } : {}
318
+ const dirtyFields = patch.__dirtyfields__
319
+ for (let key in dirtyFields) {
320
+ patchField[key] = dirtyFields[key].after
321
+ }
322
+ patchField.cuFlag = patch.__dirty__
323
+
324
+ return patchField
325
+ })
326
+
327
+ const response = await client.mutate({
328
+ mutation: gql`
329
+ mutation ($patches: [ApprovalLinePatch!]!) {
330
+ updateMultipleMyApprovalLine(patches: $patches) {
331
+ name
332
+ }
333
+ }
334
+ `,
335
+ variables: {
336
+ patches
337
+ }
338
+ })
339
+
340
+ if (!response.errors) {
341
+ this.grist.fetch()
342
+ }
343
+ }
344
+ }
345
+
346
+ async updateApprovalLine(id, model) {
347
+ const response = await client.mutate({
348
+ mutation: gql`
349
+ mutation ($id: String!, $patch: ApprovalLinePatch!) {
350
+ updateApprovalLine(id: $id, patch: $patch) {
351
+ id
352
+ name
353
+ model {
354
+ type
355
+ approver {
356
+ id
357
+ name
358
+ description
359
+ controlNo
360
+ }
361
+ }
362
+ }
363
+ }
364
+ `,
365
+ variables: {
366
+ id,
367
+ patch: {
368
+ model,
369
+ cuFlag: 'M'
370
+ }
371
+ }
372
+ })
373
+ if (!response.errors) {
374
+ await document.dispatchEvent(
375
+ new CustomEvent('notify', {
376
+ detail: {
377
+ message: i18next.t('text.info_x_successfully', {
378
+ x: i18next.t('button.save')
379
+ })
380
+ }
381
+ })
382
+ )
383
+ }
384
+ }
385
+ }
@@ -0,0 +1,87 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@operato/data-grist'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html, LitElement } from 'lit'
6
+ import { property } from 'lit/decorators.js'
7
+
8
+ import { client } from '@operato/graphql'
9
+ import { i18next } from '@operato/i18n'
10
+ import { isMobileDevice } from '@operato/utils'
11
+ import { CommonHeaderStyles } from '@operato/styles'
12
+
13
+ export class DepartmentImporter extends LitElement {
14
+ static styles = [
15
+ CommonHeaderStyles,
16
+ css`
17
+ :host {
18
+ display: flex;
19
+ flex-direction: column;
20
+
21
+ background-color: var(--md-sys-color-surface);
22
+ }
23
+
24
+ ox-grist {
25
+ flex: 1;
26
+ }
27
+ `
28
+ ]
29
+
30
+ @property({ type: Array }) departments: any[] = []
31
+ @property({ type: Object }) columns = {
32
+ list: { fields: ['name', 'description'] },
33
+ pagination: { infinite: true },
34
+ columns: [
35
+ {
36
+ type: 'string',
37
+ name: 'name',
38
+ header: i18next.t('field.name'),
39
+ width: 150
40
+ },
41
+ {
42
+ type: 'string',
43
+ name: 'description',
44
+ header: i18next.t('field.description'),
45
+ width: 200
46
+ },
47
+ {
48
+ type: 'checkbox',
49
+ name: 'active',
50
+ header: i18next.t('field.active'),
51
+ width: 60
52
+ }
53
+ ]
54
+ }
55
+
56
+ render() {
57
+ return html`
58
+ <ox-grist
59
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
60
+ .config=${this.columns}
61
+ .data=${{
62
+ records: this.departments
63
+ }}
64
+ ></ox-grist>
65
+
66
+ <div class="footer">
67
+ <div filler></div>
68
+ <button @click=${this.save.bind(this)} done><md-icon>save</md-icon>${i18next.t('button.save')}</button>
69
+ </div>
70
+ `
71
+ }
72
+
73
+ async save() {
74
+ const response = await client.mutate({
75
+ mutation: gql`
76
+ mutation importDepartments($departments: [DepartmentPatch!]!) {
77
+ importDepartments(departments: $departments)
78
+ }
79
+ `,
80
+ variables: { departments: this.departments }
81
+ })
82
+
83
+ if (response.errors?.length) return
84
+
85
+ this.dispatchEvent(new CustomEvent('imported'))
86
+ }
87
+ }