@things-factory/organization 10.1.259 → 10.1.261
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/dist-client/pages/department/department-list-page.d.ts +8 -4
- package/dist-client/pages/department/department-list-page.js +28 -33
- package/dist-client/pages/department/department-list-page.js.map +1 -1
- package/dist-client/pages/employee/employee-list-page.d.ts +20 -6
- package/dist-client/pages/employee/employee-list-page.js +154 -97
- package/dist-client/pages/employee/employee-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/certificate/employment-certificates.js +3 -10
- package/dist-server/service/certificate/employment-certificates.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -7
- package/tests/department-query-shape.test.ts +1 -1
|
@@ -4,6 +4,7 @@ import '@operato/data-tree';
|
|
|
4
4
|
import '@operato/list-state/ox-empty-note.js';
|
|
5
5
|
import '@operato/list-state/ox-page-state.js';
|
|
6
6
|
import '@things-factory/contact/dist-client';
|
|
7
|
+
import '@things-factory/ai-assistant/dist-client/index.js';
|
|
7
8
|
import gql from 'graphql-tag';
|
|
8
9
|
import { css, html } from 'lit';
|
|
9
10
|
import { customElement, property, query, state } from 'lit/decorators.js';
|
|
@@ -14,17 +15,19 @@ import { client, QueryController } from '@operato/graphql';
|
|
|
14
15
|
import { i18next, localize } from '@operato/i18n';
|
|
15
16
|
import { notify, openPopup } from '@operato/layout';
|
|
16
17
|
import { PageView } from '@operato/shell';
|
|
17
|
-
import { CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
18
|
+
import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
18
19
|
import { isMobileDevice } from '@operato/utils';
|
|
19
20
|
import { p13n } from '@operato/p13n';
|
|
20
21
|
import { hasPrivilege } from '@things-factory/auth-base/dist-client';
|
|
21
22
|
import { issueDocument } from '@things-factory/pdf/dist-client';
|
|
22
|
-
import { Department } from '../../types/department';
|
|
23
23
|
import { EmployeeImporter } from './employee-importer';
|
|
24
|
+
/** The column layout 사번 · 이름 lead and stay fixed on - a person's older column order gives way to it. */
|
|
25
|
+
const COLUMNS_VERSION = 'lead-2026-11-08';
|
|
24
26
|
let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(ScopedElementsMixin(PageView))) {
|
|
25
27
|
constructor() {
|
|
26
28
|
super(...arguments);
|
|
27
29
|
this.mode = isMobileDevice() ? 'CARD' : 'GRID';
|
|
30
|
+
/** Whether the rail is showing. The department chosen on it is the grid's own filter (`departmentId`), kept in the address. */
|
|
28
31
|
this.railFolded = false;
|
|
29
32
|
/** Whether this person issues employees' certificates. */
|
|
30
33
|
this.issuesCertificates = false;
|
|
@@ -181,6 +184,23 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
181
184
|
get departments() {
|
|
182
185
|
return this.departmentsRead.data?.responses?.items;
|
|
183
186
|
}
|
|
187
|
+
/** The department the list is narrowed to: the grid's `departmentId` filter, found in the rail's tree. */
|
|
188
|
+
get selectedDepartment() {
|
|
189
|
+
const id = (this.grist?.filters || []).find(filter => filter.name === 'departmentId')?.value;
|
|
190
|
+
if (!id)
|
|
191
|
+
return undefined;
|
|
192
|
+
const find = (list = []) => {
|
|
193
|
+
for (const one of list) {
|
|
194
|
+
if (one.id === id)
|
|
195
|
+
return one;
|
|
196
|
+
const found = find(one.children);
|
|
197
|
+
if (found)
|
|
198
|
+
return found;
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
};
|
|
202
|
+
return find(this.departments);
|
|
203
|
+
}
|
|
184
204
|
get context() {
|
|
185
205
|
return {
|
|
186
206
|
title: i18next.t('title.employee list'),
|
|
@@ -197,28 +217,38 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
197
217
|
},
|
|
198
218
|
help: 'organization/employee',
|
|
199
219
|
actions: [
|
|
200
|
-
/*
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
{ icon: 'workspace_premium', title: i18next.t('button.issue-employment-certificate'), action: () => this.issueCertificate('organization.employment-certificate') },
|
|
204
|
-
{ icon: 'history_edu', title: i18next.t('button.issue-career-certificate'), action: () => this.issueCertificate('organization.career-certificate') }
|
|
205
|
-
]
|
|
206
|
-
: []),
|
|
207
|
-
{ icon: 'save', title: i18next.t('button.save'), action: this.onUpdateEmployee.bind(this) },
|
|
208
|
-
{
|
|
209
|
-
icon: 'delete',
|
|
210
|
-
title: i18next.t('button.delete'),
|
|
211
|
-
action: this.onDeleteEmployee.bind(this),
|
|
212
|
-
emphasis: { danger: true }
|
|
213
|
-
}
|
|
220
|
+
/* The only way to start an employee inline - there is no empty row under the records. */
|
|
221
|
+
{ id: 'add-row', icon: 'add', title: i18next.t('button.add-row'), action: () => this.grist.addNewRecord() },
|
|
222
|
+
{ id: 'save', title: i18next.t('button.save'), action: this.onUpdateEmployee.bind(this), ...CommonButtonStyles.save }
|
|
214
223
|
],
|
|
215
224
|
exportable: { name: i18next.t('title.employee list'), data: this.exportHandler.bind(this) },
|
|
216
225
|
importable: { handler: this.importHandler.bind(this) }
|
|
217
226
|
};
|
|
218
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* What is done with the picked employees, on the selection bar over the list (FOOTER-BUTTON-REVIEW F06): certificates
|
|
230
|
+
* of one employee - for whoever issues them (`employee-certificate`, ADR-0176 decision 5) - and deleting.
|
|
231
|
+
*/
|
|
232
|
+
get selectionActions() {
|
|
233
|
+
return [
|
|
234
|
+
...(this.issuesCertificates
|
|
235
|
+
? [
|
|
236
|
+
{ id: 'employment-certificate', icon: 'workspace_premium', title: i18next.t('button.issue-employment-certificate'), single: true, action: () => this.issueCertificate('organization.employment-certificate') },
|
|
237
|
+
{ id: 'career-certificate', icon: 'history_edu', title: i18next.t('button.issue-career-certificate'), single: true, action: () => this.issueCertificate('organization.career-certificate') }
|
|
238
|
+
]
|
|
239
|
+
: []),
|
|
240
|
+
{ id: 'delete', title: i18next.t('button.delete'), icon: 'delete_outline', emphasis: { danger: true }, action: this.onDeleteEmployee.bind(this) }
|
|
241
|
+
];
|
|
242
|
+
}
|
|
219
243
|
render() {
|
|
220
244
|
const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID');
|
|
221
245
|
return html `
|
|
246
|
+
<ox-assistant-selection-bar
|
|
247
|
+
.gridOf=${() => this.grist}
|
|
248
|
+
name=${i18next.t('title.employee list')}
|
|
249
|
+
.assistant=${false}
|
|
250
|
+
.actions=${this.selectionActions}
|
|
251
|
+
></ox-assistant-selection-bar>
|
|
222
252
|
<div body class="page-fill">
|
|
223
253
|
${this.railFolded
|
|
224
254
|
? html `<button
|
|
@@ -269,6 +299,8 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
269
299
|
.config=${this.gristConfig}
|
|
270
300
|
.fetchHandler=${this.fetchHandler.bind(this)}
|
|
271
301
|
.personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')}
|
|
302
|
+
?url-params-sensitive=${this.active}
|
|
303
|
+
@query-state-change=${() => this.requestUpdate()}
|
|
272
304
|
>
|
|
273
305
|
<div slot="headroom" class="header">
|
|
274
306
|
<div class="filters">
|
|
@@ -283,11 +315,18 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
283
315
|
}
|
|
284
316
|
/**
|
|
285
317
|
* 트리에서 고른 부서가 목록의 부서 조건이다 — 조건은 하나고, 그것을 고르는 자리도 하나다.
|
|
318
|
+
* The condition is the grid's hidden `departmentId` filter, so the address keeps it and a change reads page 1.
|
|
286
319
|
*/
|
|
287
320
|
onSelectDepartment(department) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
321
|
+
const grist = this.grist;
|
|
322
|
+
if (!grist)
|
|
323
|
+
return;
|
|
324
|
+
const next = [
|
|
325
|
+
...(grist.filters || []).filter(filter => filter.name !== 'departmentId'),
|
|
326
|
+
...(department ? [{ name: 'departmentId', operator: 'eq', value: department.id }] : [])
|
|
327
|
+
];
|
|
328
|
+
grist.dispatchEvent(new CustomEvent('fetch-params-change', { bubbles: true, composed: true, detail: { filters: next, from: 'page' } }));
|
|
329
|
+
this.requestUpdate();
|
|
291
330
|
}
|
|
292
331
|
/** One certificate of the one employee selected. */
|
|
293
332
|
async issueCertificate(kind) {
|
|
@@ -311,8 +350,31 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
311
350
|
details: ['email', 'department', 'hiredOn', 'updatedAt']
|
|
312
351
|
},
|
|
313
352
|
columns: [
|
|
353
|
+
/* A row's state (new, changed); a new row's mark removes it until it is saved (data-grist 행 제거). */
|
|
354
|
+
{ type: 'gutter', gutterName: 'dirty' },
|
|
314
355
|
{ type: 'gutter', gutterName: 'sequence', fixed: true },
|
|
315
356
|
{ type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },
|
|
357
|
+
/* Only 사번 and 이름 stay in view: data-grist fixes every column before the last fixed one, so they come right after the gutters. */
|
|
358
|
+
{
|
|
359
|
+
type: 'string',
|
|
360
|
+
name: 'controlNo',
|
|
361
|
+
fixed: true,
|
|
362
|
+
header: i18next.t('field.control-no'),
|
|
363
|
+
record: { editable: true, mandatory: true },
|
|
364
|
+
filter: 'search',
|
|
365
|
+
sortable: true,
|
|
366
|
+
width: 105
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
type: 'string',
|
|
370
|
+
name: 'name',
|
|
371
|
+
fixed: true,
|
|
372
|
+
header: i18next.t('field.name'),
|
|
373
|
+
record: { editable: true, mandatory: true },
|
|
374
|
+
filter: 'search',
|
|
375
|
+
sortable: true,
|
|
376
|
+
width: 100
|
|
377
|
+
},
|
|
316
378
|
{
|
|
317
379
|
type: 'gutter',
|
|
318
380
|
gutterName: 'button',
|
|
@@ -352,26 +414,6 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
352
414
|
}
|
|
353
415
|
}
|
|
354
416
|
},
|
|
355
|
-
{
|
|
356
|
-
type: 'string',
|
|
357
|
-
name: 'controlNo',
|
|
358
|
-
fixed: true,
|
|
359
|
-
header: i18next.t('field.control-no'),
|
|
360
|
-
record: { editable: true, mandatory: true },
|
|
361
|
-
filter: 'search',
|
|
362
|
-
sortable: true,
|
|
363
|
-
width: 105
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
type: 'string',
|
|
367
|
-
name: 'name',
|
|
368
|
-
fixed: true,
|
|
369
|
-
header: i18next.t('field.name'),
|
|
370
|
-
record: { editable: true, mandatory: true },
|
|
371
|
-
filter: 'search',
|
|
372
|
-
sortable: true,
|
|
373
|
-
width: 100
|
|
374
|
-
},
|
|
375
417
|
{
|
|
376
418
|
type: 'string',
|
|
377
419
|
name: 'alias',
|
|
@@ -566,22 +608,31 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
566
608
|
},
|
|
567
609
|
{ type: 'resource-object', name: 'updater', header: i18next.t('field.updater'), width: 90, sortable: false },
|
|
568
610
|
{ type: 'datetime', name: 'updatedAt', header: i18next.t('field.updated_at'), width: 180, sortable: true },
|
|
569
|
-
{ type: 'resource-object', name: 'contact', hidden: true }
|
|
611
|
+
{ type: 'resource-object', name: 'contact', hidden: true },
|
|
612
|
+
/* The rail's department: a filter of the grid, not drawn in the form - the rail is where it is chosen. */
|
|
613
|
+
{ type: 'string', name: 'departmentId', header: i18next.t('field.department'), hidden: true, record: { editable: false }, filter: { operator: 'eq', type: 'string', hidden: true } }
|
|
570
614
|
],
|
|
571
|
-
|
|
615
|
+
/*
|
|
616
|
+
* No empty row under the records: 「행 추가」 starts one, and a paste past the last row adds rows with the same draft -
|
|
617
|
+
* in the department picked on the rail, if one is.
|
|
618
|
+
*/
|
|
619
|
+
rows: { appendable: false, pasteAppendable: true, newRecord: () => this.draft(), selectable: { multiple: true } },
|
|
620
|
+
columnsVersion: COLUMNS_VERSION,
|
|
572
621
|
sorters: [{ name: 'controlNo' }]
|
|
573
622
|
};
|
|
574
623
|
}
|
|
624
|
+
/** A new employee starts in the department picked on the rail. */
|
|
625
|
+
draft() {
|
|
626
|
+
const department = this.selectedDepartment;
|
|
627
|
+
return department ? { department: { id: department.id, controlNo: department.controlNo, name: department.name, description: department.description } } : {};
|
|
628
|
+
}
|
|
575
629
|
async pageUpdated(changes, lifecycle) {
|
|
576
630
|
if (this.active) {
|
|
577
631
|
// do something here when this page just became as active
|
|
578
632
|
}
|
|
579
633
|
}
|
|
580
634
|
async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }) {
|
|
581
|
-
/* The rail's selection
|
|
582
|
-
if (this.selectedDepartment) {
|
|
583
|
-
filters = [...filters, { name: 'departmentId', operator: 'eq', value: this.selectedDepartment.id }];
|
|
584
|
-
}
|
|
635
|
+
/* The rail's selection arrives as the grid's own `departmentId` filter; nothing else sets one. */
|
|
585
636
|
const response = await client.query({
|
|
586
637
|
query: gql `
|
|
587
638
|
query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
|
|
@@ -644,49 +695,54 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
644
695
|
return { total: response.data.responses.total || 0, records };
|
|
645
696
|
}
|
|
646
697
|
async onDeleteEmployee() {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
698
|
+
const ids = (this.grist?.selected ?? []).map(record => record.id).filter(Boolean);
|
|
699
|
+
if (!ids.length) {
|
|
700
|
+
notify({ level: 'info', message: i18next.t('text.select-rows-to-delete') });
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (!(await OxPrompt.confirmDelete({ count: ids.length }))) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const response = await client.mutate({
|
|
707
|
+
mutation: gql `
|
|
708
|
+
mutation ($ids: [String!]!) {
|
|
709
|
+
deleteEmployees(ids: $ids)
|
|
710
|
+
}
|
|
711
|
+
`,
|
|
712
|
+
variables: { ids }
|
|
713
|
+
});
|
|
714
|
+
if (!response.errors) {
|
|
715
|
+
this.grist.fetch();
|
|
716
|
+
notify({ message: i18next.t('text.deleted') });
|
|
663
717
|
}
|
|
664
718
|
}
|
|
665
719
|
async onUpdateEmployee() {
|
|
666
|
-
|
|
667
|
-
if (
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
});
|
|
677
|
-
const response = await client.mutate({
|
|
678
|
-
mutation: gql `
|
|
679
|
-
mutation ($patches: [EmployeePatch!]!) {
|
|
680
|
-
updateMultipleEmployee(patches: $patches) {
|
|
681
|
-
name
|
|
720
|
+
const dirty = this.grist.dirtyRecords;
|
|
721
|
+
if (!dirty?.length) {
|
|
722
|
+
notify({ level: 'info', message: i18next.t('text.nothing-to-save') });
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
const patches = dirty.map(patch => {
|
|
726
|
+
let patchField = patch.id ? { id: patch.id } : {};
|
|
727
|
+
const dirtyFields = patch.__dirtyfields__;
|
|
728
|
+
for (let key in dirtyFields) {
|
|
729
|
+
patchField[key] = dirtyFields[key].after;
|
|
682
730
|
}
|
|
731
|
+
patchField.cuFlag = patch.__dirty__;
|
|
732
|
+
return patchField;
|
|
733
|
+
});
|
|
734
|
+
const response = await client.mutate({
|
|
735
|
+
mutation: gql `
|
|
736
|
+
mutation ($patches: [EmployeePatch!]!) {
|
|
737
|
+
updateMultipleEmployee(patches: $patches) {
|
|
738
|
+
name
|
|
683
739
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
740
|
+
}
|
|
741
|
+
`,
|
|
742
|
+
variables: { patches }
|
|
743
|
+
});
|
|
744
|
+
if (!response.errors) {
|
|
745
|
+
this.grist.fetch();
|
|
690
746
|
}
|
|
691
747
|
}
|
|
692
748
|
async exportHandler() {
|
|
@@ -761,16 +817,21 @@ let EmployeeListPage = class EmployeeListPage extends p13n(localize(i18next)(Sco
|
|
|
761
817
|
this.grist.fetch();
|
|
762
818
|
}
|
|
763
819
|
else if (contact?.id) {
|
|
764
|
-
|
|
820
|
+
const picked = {
|
|
821
|
+
id: contact.id,
|
|
765
822
|
name: contact.name,
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
823
|
+
email: contact.email,
|
|
824
|
+
phone: contact.phone,
|
|
825
|
+
address: contact.address
|
|
826
|
+
};
|
|
827
|
+
/* A row started with 「행 추가」 takes the contact; otherwise the contact starts a new row. */
|
|
828
|
+
if (record?.__dirty__ === '+') {
|
|
829
|
+
record.contact = picked;
|
|
830
|
+
record.name = record.name || contact.name;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
this.grist.addNewRecord({ name: contact.name, contact: picked });
|
|
834
|
+
}
|
|
774
835
|
this.grist.refresh();
|
|
775
836
|
await this.grist.requestUpdate();
|
|
776
837
|
this.grist.checkDirties();
|
|
@@ -820,13 +881,9 @@ __decorate([
|
|
|
820
881
|
__decorate([
|
|
821
882
|
query('ox-grist'),
|
|
822
883
|
__metadata("design:type", DataGrist
|
|
823
|
-
/** The department chosen on the
|
|
884
|
+
/** Whether the rail is showing. The department chosen on it is the grid's own filter (`departmentId`), kept in the address. */
|
|
824
885
|
)
|
|
825
886
|
], EmployeeListPage.prototype, "grist", void 0);
|
|
826
|
-
__decorate([
|
|
827
|
-
state(),
|
|
828
|
-
__metadata("design:type", Department)
|
|
829
|
-
], EmployeeListPage.prototype, "selectedDepartment", void 0);
|
|
830
887
|
__decorate([
|
|
831
888
|
state(),
|
|
832
889
|
__metadata("design:type", Object)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"employee-list-page.js","sourceRoot":"","sources":["../../../client/pages/employee/employee-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-tree'\nimport '@operato/list-state/ox-empty-note.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '@things-factory/contact/dist-client'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { OxPrompt } from '@operato/popup'\nimport { Contact } from '@operato/contact/ox-contact.js'\nimport { DataGrist, FetchOption, GristRecord } from '@operato/data-grist'\nimport { client, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { p13n } from '@operato/p13n'\n\nimport { hasPrivilege } from '@things-factory/auth-base/dist-client'\nimport { issueDocument } from '@things-factory/pdf/dist-client'\n\nimport { Department } from '../../types/department'\nimport { EmployeeImporter } from './employee-importer'\n\n@customElement('employee-list-page')\nexport class EmployeeListPage extends p13n(localize(i18next)(ScopedElementsMixin(PageView))) {\n static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n css`\n :host {\n --ox-pfp-size: 40px;\n --grid-record-emphasized-background-color: #8b0000;\n --grid-record-emphasized-color: #ff6b6b;\n }\n\n .header {\n grid-template-areas: 'filters';\n }\n\n /*\n * The rail is how you narrow the list to one department; the list is the content\n * (ADR-0060 decision 8, and the ruling of 2026-09-18 that folded the by-department screen\n * into this one). It folds away, because a screen looking at everyone does not need it.\n */\n [body] {\n flex: 1;\n display: flex;\n flex-direction: row;\n min-height: 0;\n }\n\n [rail] {\n display: flex;\n flex-direction: column;\n width: 240px;\n min-width: 240px;\n border-right: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n overflow: auto;\n }\n\n [rail][folded] {\n display: none;\n }\n\n [rail-head] {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n padding: var(--spacing-medium, 8px) var(--spacing-medium, 8px) 0;\n font: var(--label-font, inherit);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n /* The word keeps its line. Sharing the row with a filler let it shrink and break in half. */\n [rail-head] > span {\n flex: 0 0 auto;\n white-space: nowrap;\n }\n\n [rail-head] button,\n /*\n * Going back to everyone. Picking a department narrows the list, and without this there is no\n * way out of that except reloading the screen.\n */\n button[all-departments] {\n width: calc(100% - 16px);\n margin: 4px 8px;\n padding: 6px 10px;\n text-align: left;\n border: 1px solid transparent;\n border-radius: var(--md-sys-shape-corner-small, 6px);\n background: transparent;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font: inherit;\n cursor: pointer;\n }\n\n button[all-departments][selected] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n [rail-toggle] {\n display: flex;\n align-items: center;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n padding: 2px;\n }\n\n [rail-toggle] {\n align-self: flex-start;\n margin: var(--spacing-medium, 8px) 0 0 var(--spacing-small, 4px);\n }\n\n ox-tree {\n flex: 1;\n overflow: auto;\n }\n\n ox-grist {\n flex: 1;\n min-width: 0;\n }\n\n @media screen and (max-width: 780px) {\n [rail] {\n display: none;\n }\n }\n `\n ]\n\n static get scopedElements() {\n return { 'employee-importer': EmployeeImporter }\n }\n\n @property({ type: Object }) gristConfig: any\n @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') private grist!: DataGrist\n\n /** The department chosen on the rail, and whether the rail is showing. */\n @state() private selectedDepartment?: Department\n @state() private railFolded = false\n /** Whether this person issues employees' certificates. */\n @state() private issuesCertificates = false\n\n /**\n * The departments the rail draws (ADR-0190). departmentRoots answers with a list, and the tree draws from\n * the first root - a fragment spread straight onto the list is refused by the server.\n */\n private departmentsRead = new QueryController(\n this,\n gql`\n query {\n responses: departmentRoots {\n items {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n }\n }\n }\n }\n }\n }\n }\n\n fragment EmployeeDepartmentFragment on Department {\n id\n controlNo\n name\n description\n active\n }\n `\n )\n\n /* Every root department, not just the first - the rail draws an array. */\n private get departments(): Department[] | undefined {\n return this.departmentsRead.data?.responses?.items\n }\n\n get context() {\n return {\n title: i18next.t('title.employee list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'organization/employee',\n actions: [\n /* Certificates of the selected employee - for whoever issues them (`employee-certificate`, ADR-0176 decision 5). */\n ...(this.issuesCertificates\n ? [\n { icon: 'workspace_premium', title: i18next.t('button.issue-employment-certificate'), action: () => this.issueCertificate('organization.employment-certificate') },\n { icon: 'history_edu', title: i18next.t('button.issue-career-certificate'), action: () => this.issueCertificate('organization.career-certificate') }\n ]\n : []),\n { icon: 'save', title: i18next.t('button.save'), action: this.onUpdateEmployee.bind(this) },\n {\n icon: 'delete',\n title: i18next.t('button.delete'),\n action: this.onDeleteEmployee.bind(this),\n emphasis: { danger: true }\n }\n ],\n exportable: { name: i18next.t('title.employee list'), data: this.exportHandler.bind(this) },\n importable: { handler: this.importHandler.bind(this) }\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <div body class=\"page-fill\">\n ${\n this.railFolded\n ? html`<button\n rail-toggle\n title=${i18next.t('title.department list')}\n @click=${() => (this.railFolded = false)}\n >\n <md-icon>account_tree</md-icon>\n </button>`\n : html`<aside rail>\n <div rail-head>\n <span>${i18next.t('title.department list')}</span>\n <div filler style=\"flex: 1\"></div>\n <button title=${i18next.t('label.fold')} @click=${() => (this.railFolded = true)}>\n <md-icon>chevron_left</md-icon>\n </button>\n </div>\n <ox-page-state\n .loading=${this.departmentsRead.loading}\n .error=${this.departmentsRead.error ?? null}\n @retry=${() => this.departmentsRead.refetch()}\n >\n ${\n this.departments?.length\n ? html`<button\n all-departments\n ?selected=${!this.selectedDepartment}\n @click=${() => this.onSelectDepartment(undefined)}\n >\n ${i18next.t('text.all departments')}\n </button>\n <ox-tree\n .data=${this.departments}\n .selected=${this.selectedDepartment}\n @select=${(e: CustomEvent) => this.onSelectDepartment(e.detail as Department)}\n id-property=\"controlNo\"\n label-property=\"name\"\n ></ox-tree>`\n : html`<ox-empty-note\n icon=\"account_tree\"\n title=${i18next.t('text.no departments yet')}\n description=${i18next.t('text.departments are made on the department screen')}\n ></ox-empty-note>`\n }\n </ox-page-state>\n </aside>`\n }\n\n <ox-grist\n .mode=${mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form class=\"filter\" autofocus without-search></ox-filters-form>\n </div>\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n </div>\n `\n }\n\n /**\n * 트리에서 고른 부서가 목록의 부서 조건이다 — 조건은 하나고, 그것을 고르는 자리도 하나다.\n */\n private onSelectDepartment(department?: Department) {\n this.selectedDepartment = department\n this.grist?.fetch()\n this.updateContext()\n }\n\n /** One certificate of the one employee selected. */\n private async issueCertificate(kind: string) {\n const selected = this.grist.selected\n if (selected.length !== 1 || !selected[0].id) {\n notify({ level: 'warn', message: i18next.t('text.select-one-employee') })\n return\n }\n await issueDocument({ kind, refId: selected[0].id })\n }\n\n async pageInitialized(lifecycle: any) {\n hasPrivilege({ category: 'employee-certificate', privilege: 'mutation', domainOwnerGranted: true }).then(may => {\n this.issuesCertificates = may\n this.updateContext()\n })\n this.gristConfig = {\n pagination: { pages: [50, 100, 200] },\n list: {\n thumbnail: 'profile',\n fields: ['controlNo', 'name'],\n details: ['email', 'department', 'hiredOn', 'updatedAt']\n },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n { type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },\n {\n type: 'gutter',\n gutterName: 'button',\n header: i18next.t('field.register-account'),\n icon: record => (record.id && !record.user ? 'badge' : ''),\n iconOnly: false,\n title: record => (record.id && !record.user ? i18next.t('button.register-account') : ''),\n width: 80,\n handlers: {\n click: (columns, data, column, record, rowIndex) => {\n if (!record || !record.id || record.user) {\n return\n }\n\n this.attachSystemUser(record)\n }\n }\n },\n {\n type: 'image',\n name: 'profile',\n header: i18next.t('button.edit-contact'),\n width: 80,\n record: {\n align: 'center',\n renderer: function (value, column, record, rowIndex, field) {\n return html`<ox-pfp-view .profile=${record.profile} .name=${record.name || '+'}></ox-pfp-view>`\n }\n },\n handlers: {\n click: async (columns, data, column, record, rowIndex) => {\n if (record && record.contact) {\n this.openContactPopup(record)\n } else {\n this.openContactSelector(record)\n }\n }\n }\n },\n {\n type: 'string',\n name: 'controlNo',\n fixed: true,\n header: i18next.t('field.control-no'),\n record: { editable: true, mandatory: true },\n filter: 'search',\n sortable: true,\n width: 105\n },\n {\n type: 'string',\n name: 'name',\n fixed: true,\n header: i18next.t('field.name'),\n record: { editable: true, mandatory: true },\n filter: 'search',\n sortable: true,\n width: 100\n },\n {\n type: 'string',\n name: 'alias',\n header: i18next.t('label.alias'),\n record: { editable: true },\n filter: 'search',\n sortable: false,\n width: 110\n },\n {\n type: 'resource-object',\n name: 'user',\n header: i18next.t('field.system-user'),\n record: {\n editable: true,\n options: {\n title: i18next.t('title.lookup system-user'),\n queryName: 'users',\n basicArgs: { filters: [{ name: 'userType', operator: 'eq', value: 'user' }] },\n descriptionField: 'email',\n columns: [\n { name: 'id', hidden: true },\n { name: 'name', header: i18next.t('field.name'), filter: 'search' },\n { name: 'email', header: i18next.t('field.email'), filter: 'search' }\n ],\n list: { fields: ['name', 'email'] }\n }\n },\n sortable: false,\n filter: 'search',\n width: 100\n },\n {\n type: 'code',\n name: 'type',\n header: i18next.t('field.type', { defaultValue: 'type' }),\n width: 115,\n sortable: true,\n filter: true,\n record: { editable: true, codeName: 'EMPLOYEE_TYPE', selectDispOpt: 'name' }\n },\n {\n type: 'department-object',\n name: 'department',\n header: i18next.t('field.department'),\n record: { editable: true },\n sortable: false,\n /* The rail narrows by department; a second department field here would be the same condition twice. */\n filter: false,\n width: 130\n },\n {\n type: 'resource-object',\n name: 'supervisor',\n header: i18next.t('field.supervisor'),\n record: {\n editable: true,\n options: {\n title: i18next.t('title.employee list'),\n queryName: 'employees',\n pagination: { pages: [50, 100, 200] },\n basicArgs: { filters: [{ name: 'active', operator: 'eq', value: true }] },\n list: { fields: ['controlNo', 'name', 'alias', 'hiredOn'] },\n columns: [\n { name: 'id', hidden: true },\n {\n name: 'controlNo',\n width: 120,\n header: { renderer: () => i18next.t('field.control-no') },\n filter: 'search',\n sortable: true\n },\n {\n name: 'name',\n width: 120,\n header: { renderer: () => i18next.t('field.name') },\n filter: 'search',\n sortable: true\n },\n {\n name: 'alias',\n width: 150,\n header: { renderer: () => i18next.t('label.alias') },\n filter: 'search',\n sortable: true\n },\n {\n type: 'code',\n name: 'type',\n width: 110,\n header: { renderer: () => i18next.t('label.type', { defaultValue: 'type' }) },\n record: { editable: false, codeName: 'EMPLOYEE_TYPE', selectDispOpt: 'name' }\n },\n {\n type: 'code',\n name: 'jobPosition',\n width: 110,\n header: { renderer: () => i18next.t('label.job-position') },\n record: { editable: false, codeName: 'JOB_POSITION', selectDispOpt: 'name' }\n },\n {\n type: 'code',\n name: 'jobResponsibility',\n width: 200,\n header: { renderer: () => i18next.t('label.job-responsibility') },\n record: { editable: false, codeName: 'JOB_RESPONSIBILITY', selectDispOpt: 'name' }\n },\n { type: 'date', name: 'hiredOn', header: { renderer: () => i18next.t('field.hired-on') }, width: 120 }\n ],\n valueField: 'id',\n nameField: 'name',\n descriptionField: 'controlNo'\n }\n },\n sortable: false,\n width: 120\n },\n {\n type: 'string',\n name: 'email',\n header: i18next.t('field.email'),\n width: 200,\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n return record.contact ? record.contact.email : ''\n }\n },\n sortable: false\n },\n {\n type: 'string',\n name: 'phone',\n header: i18next.t('field.phone'),\n width: 130,\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n return record.contact ? record.contact.phone : ''\n }\n },\n sortable: false\n },\n {\n type: 'code',\n name: 'jobResponsibility',\n header: i18next.t('label.job-responsibility'),\n width: 175,\n record: { editable: true, codeName: 'JOB_RESPONSIBILITY', selectDispOpt: 'name' },\n filter: true\n },\n {\n type: 'code',\n name: 'jobPosition',\n header: i18next.t('label.job-position'),\n width: 100,\n record: { editable: true, codeName: 'JOB_POSITION', selectDispOpt: 'name' },\n filter: true\n },\n {\n type: 'date',\n name: 'hiredOn',\n header: i18next.t('field.hired-on'),\n width: 120,\n record: { editable: true },\n sortable: true\n },\n {\n type: 'date',\n name: 'retiredOn',\n header: i18next.t('label.retired-at'),\n width: 120,\n record: { editable: true }\n },\n {\n type: 'checkbox',\n name: 'active',\n label: true,\n header: i18next.t('field.active'),\n width: 70,\n record: { align: 'center', editable: true },\n filter: true,\n sortable: false\n },\n {\n type: 'string',\n name: 'note',\n header: i18next.t('field.note'),\n width: 200,\n record: { editable: true },\n filter: 'search'\n },\n { type: 'resource-object', name: 'updater', header: i18next.t('field.updater'), width: 90, sortable: false },\n { type: 'datetime', name: 'updatedAt', header: i18next.t('field.updated_at'), width: 180, sortable: true },\n { type: 'resource-object', name: 'contact', hidden: true }\n ],\n rows: { selectable: { multiple: true } },\n sorters: [{ name: 'controlNo' }]\n }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n // do something here when this page just became as active\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n /* The rail's selection is the department condition; nothing else sets one. */\n if (this.selectedDepartment) {\n filters = [...filters, { name: 'departmentId', operator: 'eq', value: this.selectedDepartment.id }]\n }\n\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: employees(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n controlNo\n name\n alias\n type\n jobResponsibility\n jobPosition\n active\n email\n phone\n user {\n id\n name\n }\n department {\n id\n __typename\n controlNo\n name\n description\n }\n supervisor {\n id\n name\n controlNo\n }\n note\n hiredOn\n retiredOn\n contact {\n id\n email\n phone\n address\n }\n profile {\n left\n top\n zoom\n picture\n }\n updater {\n id\n name\n }\n updatedAt\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings }\n })\n\n const records = response.data.responses.items\n\n return { total: response.data.responses.total || 0, records }\n }\n\n async onDeleteEmployee() {\n if (await OxPrompt.confirmDelete({ count: this.grist?.selected?.length })) {\n const ids = this.grist.selected.map(record => record.id)\n if (ids && ids.length > 0) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteEmployees(ids: $ids)\n }\n `,\n variables: { ids }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n notify({ message: i18next.t('text.deleted') })\n }\n }\n }\n }\n\n async onUpdateEmployee() {\n let patches = this.grist.dirtyRecords\n if (patches && patches.length) {\n patches = patches.map(patch => {\n let patchField: any = patch.id ? { id: patch.id } : {}\n const dirtyFields = patch.__dirtyfields__\n for (let key in dirtyFields) {\n patchField[key] = dirtyFields[key].after\n }\n patchField.cuFlag = patch.__dirty__\n\n return patchField\n })\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [EmployeePatch!]!) {\n updateMultipleEmployee(patches: $patches) {\n name\n }\n }\n `,\n variables: { patches }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n }\n }\n }\n\n async exportHandler() {\n const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records\n const targetFieldSet = new Set([\n 'id',\n 'controlNo',\n 'name',\n 'alias',\n 'type',\n 'hiredOn',\n 'retiredOn',\n 'active',\n 'note'\n ])\n\n return exportTargets.map(employee => {\n let tempObj = {}\n for (const field of targetFieldSet) {\n tempObj[field] = employee[field]\n }\n\n return tempObj\n })\n }\n\n async importHandler(records) {\n const popup = openPopup(\n html`\n <employee-importer\n .employees=${records}\n @imported=${() => {\n history.back()\n this.grist.fetch()\n }}\n ></employee-importer>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.import employee') }\n )\n\n popup.onclosed = () => {\n this.grist.fetch()\n }\n }\n\n async openContactPopup(record: GristRecord) {\n if (!record.contact?.id) {\n return\n }\n\n const popup = openPopup(\n html`\n <contact-popup\n .contactId=${record.contact.id}\n @change=${() => {\n this.grist.fetch()\n }}\n @detach=${() => {\n this.detachContact(record)\n }}\n detachable\n ></contact-popup>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.contact') }\n )\n }\n\n async openContactSelector(record: GristRecord) {\n const popup = openPopup(\n html`\n <contact-selector .confirmCallback=${selected => this.attachContact(record, selected)}></contact-selector>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.contact') }\n )\n }\n\n async attachContact(record: GristRecord, contact: Contact) {\n if (record.id) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $contactId: String!) {\n attachContact(id: $id, contactId: $contactId) {\n id\n }\n }\n `,\n variables: { id: record.id, contactId: contact.id }\n })\n\n this.grist.fetch()\n } else if (contact?.id) {\n this.grist.addRecord({\n name: contact.name,\n contact: {\n id: contact.id,\n name: contact.name,\n email: (contact as any).email,\n phone: (contact as any).phone,\n address: (contact as any).address\n }\n })\n this.grist.refresh()\n await this.grist.requestUpdate()\n\n this.grist.checkDirties()\n }\n }\n\n async detachContact(record) {\n if (record.id) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n detachContact(id: $id) {\n id\n }\n }\n `,\n variables: { id: record.id }\n })\n\n this.grist.fetch()\n } else {\n record.contact = null\n this.grist.refresh()\n }\n }\n\n async attachSystemUser(record) {\n if (!record.user) {\n await client.mutate({\n mutation: gql`\n mutation ($employeeId: String!) {\n registerEmployeeAsSystemUser(employeeId: $employeeId)\n }\n `,\n variables: { employeeId: record.id }\n })\n }\n\n this.grist.fetch()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"employee-list-page.js","sourceRoot":"","sources":["../../../client/pages/employee/employee-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-tree'\nimport '@operato/list-state/ox-empty-note.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '@things-factory/contact/dist-client'\nimport '@things-factory/ai-assistant/dist-client/index.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { OxPrompt } from '@operato/popup'\nimport { Contact } from '@operato/contact/ox-contact.js'\nimport { DataGrist, FetchOption, GristRecord } from '@operato/data-grist'\nimport { client, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { p13n } from '@operato/p13n'\n\nimport { hasPrivilege } from '@things-factory/auth-base/dist-client'\nimport { issueDocument } from '@things-factory/pdf/dist-client'\n\nimport { Department } from '../../types/department'\nimport { EmployeeImporter } from './employee-importer'\n\n/** The column layout 사번 · 이름 lead and stay fixed on - a person's older column order gives way to it. */\nconst COLUMNS_VERSION = 'lead-2026-11-08'\n\n@customElement('employee-list-page')\nexport class EmployeeListPage extends p13n(localize(i18next)(ScopedElementsMixin(PageView))) {\n static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n css`\n :host {\n --ox-pfp-size: 40px;\n --grid-record-emphasized-background-color: #8b0000;\n --grid-record-emphasized-color: #ff6b6b;\n }\n\n .header {\n grid-template-areas: 'filters';\n }\n\n /*\n * The rail is how you narrow the list to one department; the list is the content\n * (ADR-0060 decision 8, and the ruling of 2026-09-18 that folded the by-department screen\n * into this one). It folds away, because a screen looking at everyone does not need it.\n */\n [body] {\n flex: 1;\n display: flex;\n flex-direction: row;\n min-height: 0;\n }\n\n [rail] {\n display: flex;\n flex-direction: column;\n width: 240px;\n min-width: 240px;\n border-right: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n overflow: auto;\n }\n\n [rail][folded] {\n display: none;\n }\n\n [rail-head] {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n padding: var(--spacing-medium, 8px) var(--spacing-medium, 8px) 0;\n font: var(--label-font, inherit);\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n /* The word keeps its line. Sharing the row with a filler let it shrink and break in half. */\n [rail-head] > span {\n flex: 0 0 auto;\n white-space: nowrap;\n }\n\n [rail-head] button,\n /*\n * Going back to everyone. Picking a department narrows the list, and without this there is no\n * way out of that except reloading the screen.\n */\n button[all-departments] {\n width: calc(100% - 16px);\n margin: 4px 8px;\n padding: 6px 10px;\n text-align: left;\n border: 1px solid transparent;\n border-radius: var(--md-sys-shape-corner-small, 6px);\n background: transparent;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n font: inherit;\n cursor: pointer;\n }\n\n button[all-departments][selected] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n [rail-toggle] {\n display: flex;\n align-items: center;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n padding: 2px;\n }\n\n [rail-toggle] {\n align-self: flex-start;\n margin: var(--spacing-medium, 8px) 0 0 var(--spacing-small, 4px);\n }\n\n ox-tree {\n flex: 1;\n overflow: auto;\n }\n\n ox-grist {\n flex: 1;\n min-width: 0;\n }\n\n @media screen and (max-width: 780px) {\n [rail] {\n display: none;\n }\n }\n `\n ]\n\n static get scopedElements() {\n return { 'employee-importer': EmployeeImporter }\n }\n\n @property({ type: Object }) gristConfig: any\n @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') private grist!: DataGrist\n\n /** Whether the rail is showing. The department chosen on it is the grid's own filter (`departmentId`), kept in the address. */\n @state() private railFolded = false\n /** Whether this person issues employees' certificates. */\n @state() private issuesCertificates = false\n\n /**\n * The departments the rail draws (ADR-0190). departmentRoots answers with a list, and the tree draws from\n * the first root - a fragment spread straight onto the list is refused by the server.\n */\n private departmentsRead = new QueryController(\n this,\n gql`\n query {\n responses: departmentRoots {\n items {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n children {\n ...EmployeeDepartmentFragment\n }\n }\n }\n }\n }\n }\n }\n\n fragment EmployeeDepartmentFragment on Department {\n id\n controlNo\n name\n description\n active\n }\n `\n )\n\n /* Every root department, not just the first - the rail draws an array. */\n private get departments(): Department[] | undefined {\n return this.departmentsRead.data?.responses?.items\n }\n\n /** The department the list is narrowed to: the grid's `departmentId` filter, found in the rail's tree. */\n private get selectedDepartment(): Department | undefined {\n const id = (this.grist?.filters || []).find(filter => filter.name === 'departmentId')?.value\n if (!id) return undefined\n const find = (list: Department[] = []): Department | undefined => {\n for (const one of list) {\n if (one.id === id) return one\n const found = find((one as any).children)\n if (found) return found\n }\n return undefined\n }\n return find(this.departments)\n }\n\n get context() {\n return {\n title: i18next.t('title.employee list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'organization/employee',\n actions: [\n /* The only way to start an employee inline - there is no empty row under the records. */\n { id: 'add-row', icon: 'add', title: i18next.t('button.add-row'), action: () => this.grist.addNewRecord() },\n { id: 'save', title: i18next.t('button.save'), action: this.onUpdateEmployee.bind(this), ...CommonButtonStyles.save }\n ],\n exportable: { name: i18next.t('title.employee list'), data: this.exportHandler.bind(this) },\n importable: { handler: this.importHandler.bind(this) }\n }\n }\n\n /**\n * What is done with the picked employees, on the selection bar over the list (FOOTER-BUTTON-REVIEW F06): certificates\n * of one employee - for whoever issues them (`employee-certificate`, ADR-0176 decision 5) - and deleting.\n */\n private get selectionActions() {\n return [\n ...(this.issuesCertificates\n ? [\n { id: 'employment-certificate', icon: 'workspace_premium', title: i18next.t('button.issue-employment-certificate'), single: true, action: () => this.issueCertificate('organization.employment-certificate') },\n { id: 'career-certificate', icon: 'history_edu', title: i18next.t('button.issue-career-certificate'), single: true, action: () => this.issueCertificate('organization.career-certificate') }\n ]\n : []),\n { id: 'delete', title: i18next.t('button.delete'), icon: 'delete_outline', emphasis: { danger: true }, action: this.onDeleteEmployee.bind(this) }\n ]\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <ox-assistant-selection-bar\n .gridOf=${() => this.grist}\n name=${i18next.t('title.employee list')}\n .assistant=${false}\n .actions=${this.selectionActions}\n ></ox-assistant-selection-bar>\n <div body class=\"page-fill\">\n ${\n this.railFolded\n ? html`<button\n rail-toggle\n title=${i18next.t('title.department list')}\n @click=${() => (this.railFolded = false)}\n >\n <md-icon>account_tree</md-icon>\n </button>`\n : html`<aside rail>\n <div rail-head>\n <span>${i18next.t('title.department list')}</span>\n <div filler style=\"flex: 1\"></div>\n <button title=${i18next.t('label.fold')} @click=${() => (this.railFolded = true)}>\n <md-icon>chevron_left</md-icon>\n </button>\n </div>\n <ox-page-state\n .loading=${this.departmentsRead.loading}\n .error=${this.departmentsRead.error ?? null}\n @retry=${() => this.departmentsRead.refetch()}\n >\n ${\n this.departments?.length\n ? html`<button\n all-departments\n ?selected=${!this.selectedDepartment}\n @click=${() => this.onSelectDepartment(undefined)}\n >\n ${i18next.t('text.all departments')}\n </button>\n <ox-tree\n .data=${this.departments}\n .selected=${this.selectedDepartment}\n @select=${(e: CustomEvent) => this.onSelectDepartment(e.detail as Department)}\n id-property=\"controlNo\"\n label-property=\"name\"\n ></ox-tree>`\n : html`<ox-empty-note\n icon=\"account_tree\"\n title=${i18next.t('text.no departments yet')}\n description=${i18next.t('text.departments are made on the department screen')}\n ></ox-empty-note>`\n }\n </ox-page-state>\n </aside>`\n }\n\n <ox-grist\n .mode=${mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n ?url-params-sensitive=${this.active}\n @query-state-change=${() => this.requestUpdate()}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form class=\"filter\" autofocus without-search></ox-filters-form>\n </div>\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n </div>\n `\n }\n\n /**\n * 트리에서 고른 부서가 목록의 부서 조건이다 — 조건은 하나고, 그것을 고르는 자리도 하나다.\n * The condition is the grid's hidden `departmentId` filter, so the address keeps it and a change reads page 1.\n */\n private onSelectDepartment(department?: Department) {\n const grist = this.grist\n if (!grist) return\n const next = [\n ...(grist.filters || []).filter(filter => filter.name !== 'departmentId'),\n ...(department ? [{ name: 'departmentId', operator: 'eq', value: department.id }] : [])\n ]\n grist.dispatchEvent(new CustomEvent('fetch-params-change', { bubbles: true, composed: true, detail: { filters: next, from: 'page' } }))\n this.requestUpdate()\n }\n\n /** One certificate of the one employee selected. */\n private async issueCertificate(kind: string) {\n const selected = this.grist.selected\n if (selected.length !== 1 || !selected[0].id) {\n notify({ level: 'warn', message: i18next.t('text.select-one-employee') })\n return\n }\n await issueDocument({ kind, refId: selected[0].id })\n }\n\n async pageInitialized(lifecycle: any) {\n hasPrivilege({ category: 'employee-certificate', privilege: 'mutation', domainOwnerGranted: true }).then(may => {\n this.issuesCertificates = may\n this.updateContext()\n })\n this.gristConfig = {\n pagination: { pages: [50, 100, 200] },\n list: {\n thumbnail: 'profile',\n fields: ['controlNo', 'name'],\n details: ['email', 'department', 'hiredOn', 'updatedAt']\n },\n columns: [\n /* A row's state (new, changed); a new row's mark removes it until it is saved (data-grist 행 제거). */\n { type: 'gutter', gutterName: 'dirty' },\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n { type: 'gutter', gutterName: 'row-selector', multiple: true, fixed: true },\n /* Only 사번 and 이름 stay in view: data-grist fixes every column before the last fixed one, so they come right after the gutters. */\n {\n type: 'string',\n name: 'controlNo',\n fixed: true,\n header: i18next.t('field.control-no'),\n record: { editable: true, mandatory: true },\n filter: 'search',\n sortable: true,\n width: 105\n },\n {\n type: 'string',\n name: 'name',\n fixed: true,\n header: i18next.t('field.name'),\n record: { editable: true, mandatory: true },\n filter: 'search',\n sortable: true,\n width: 100\n },\n {\n type: 'gutter',\n gutterName: 'button',\n header: i18next.t('field.register-account'),\n icon: record => (record.id && !record.user ? 'badge' : ''),\n iconOnly: false,\n title: record => (record.id && !record.user ? i18next.t('button.register-account') : ''),\n width: 80,\n handlers: {\n click: (columns, data, column, record, rowIndex) => {\n if (!record || !record.id || record.user) {\n return\n }\n\n this.attachSystemUser(record)\n }\n }\n },\n {\n type: 'image',\n name: 'profile',\n header: i18next.t('button.edit-contact'),\n width: 80,\n record: {\n align: 'center',\n renderer: function (value, column, record, rowIndex, field) {\n return html`<ox-pfp-view .profile=${record.profile} .name=${record.name || '+'}></ox-pfp-view>`\n }\n },\n handlers: {\n click: async (columns, data, column, record, rowIndex) => {\n if (record && record.contact) {\n this.openContactPopup(record)\n } else {\n this.openContactSelector(record)\n }\n }\n }\n },\n {\n type: 'string',\n name: 'alias',\n header: i18next.t('label.alias'),\n record: { editable: true },\n filter: 'search',\n sortable: false,\n width: 110\n },\n {\n type: 'resource-object',\n name: 'user',\n header: i18next.t('field.system-user'),\n record: {\n editable: true,\n options: {\n title: i18next.t('title.lookup system-user'),\n queryName: 'users',\n basicArgs: { filters: [{ name: 'userType', operator: 'eq', value: 'user' }] },\n descriptionField: 'email',\n columns: [\n { name: 'id', hidden: true },\n { name: 'name', header: i18next.t('field.name'), filter: 'search' },\n { name: 'email', header: i18next.t('field.email'), filter: 'search' }\n ],\n list: { fields: ['name', 'email'] }\n }\n },\n sortable: false,\n filter: 'search',\n width: 100\n },\n {\n type: 'code',\n name: 'type',\n header: i18next.t('field.type', { defaultValue: 'type' }),\n width: 115,\n sortable: true,\n filter: true,\n record: { editable: true, codeName: 'EMPLOYEE_TYPE', selectDispOpt: 'name' }\n },\n {\n type: 'department-object',\n name: 'department',\n header: i18next.t('field.department'),\n record: { editable: true },\n sortable: false,\n /* The rail narrows by department; a second department field here would be the same condition twice. */\n filter: false,\n width: 130\n },\n {\n type: 'resource-object',\n name: 'supervisor',\n header: i18next.t('field.supervisor'),\n record: {\n editable: true,\n options: {\n title: i18next.t('title.employee list'),\n queryName: 'employees',\n pagination: { pages: [50, 100, 200] },\n basicArgs: { filters: [{ name: 'active', operator: 'eq', value: true }] },\n list: { fields: ['controlNo', 'name', 'alias', 'hiredOn'] },\n columns: [\n { name: 'id', hidden: true },\n {\n name: 'controlNo',\n width: 120,\n header: { renderer: () => i18next.t('field.control-no') },\n filter: 'search',\n sortable: true\n },\n {\n name: 'name',\n width: 120,\n header: { renderer: () => i18next.t('field.name') },\n filter: 'search',\n sortable: true\n },\n {\n name: 'alias',\n width: 150,\n header: { renderer: () => i18next.t('label.alias') },\n filter: 'search',\n sortable: true\n },\n {\n type: 'code',\n name: 'type',\n width: 110,\n header: { renderer: () => i18next.t('label.type', { defaultValue: 'type' }) },\n record: { editable: false, codeName: 'EMPLOYEE_TYPE', selectDispOpt: 'name' }\n },\n {\n type: 'code',\n name: 'jobPosition',\n width: 110,\n header: { renderer: () => i18next.t('label.job-position') },\n record: { editable: false, codeName: 'JOB_POSITION', selectDispOpt: 'name' }\n },\n {\n type: 'code',\n name: 'jobResponsibility',\n width: 200,\n header: { renderer: () => i18next.t('label.job-responsibility') },\n record: { editable: false, codeName: 'JOB_RESPONSIBILITY', selectDispOpt: 'name' }\n },\n { type: 'date', name: 'hiredOn', header: { renderer: () => i18next.t('field.hired-on') }, width: 120 }\n ],\n valueField: 'id',\n nameField: 'name',\n descriptionField: 'controlNo'\n }\n },\n sortable: false,\n width: 120\n },\n {\n type: 'string',\n name: 'email',\n header: i18next.t('field.email'),\n width: 200,\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n return record.contact ? record.contact.email : ''\n }\n },\n sortable: false\n },\n {\n type: 'string',\n name: 'phone',\n header: i18next.t('field.phone'),\n width: 130,\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n return record.contact ? record.contact.phone : ''\n }\n },\n sortable: false\n },\n {\n type: 'code',\n name: 'jobResponsibility',\n header: i18next.t('label.job-responsibility'),\n width: 175,\n record: { editable: true, codeName: 'JOB_RESPONSIBILITY', selectDispOpt: 'name' },\n filter: true\n },\n {\n type: 'code',\n name: 'jobPosition',\n header: i18next.t('label.job-position'),\n width: 100,\n record: { editable: true, codeName: 'JOB_POSITION', selectDispOpt: 'name' },\n filter: true\n },\n {\n type: 'date',\n name: 'hiredOn',\n header: i18next.t('field.hired-on'),\n width: 120,\n record: { editable: true },\n sortable: true\n },\n {\n type: 'date',\n name: 'retiredOn',\n header: i18next.t('label.retired-at'),\n width: 120,\n record: { editable: true }\n },\n {\n type: 'checkbox',\n name: 'active',\n label: true,\n header: i18next.t('field.active'),\n width: 70,\n record: { align: 'center', editable: true },\n filter: true,\n sortable: false\n },\n {\n type: 'string',\n name: 'note',\n header: i18next.t('field.note'),\n width: 200,\n record: { editable: true },\n filter: 'search'\n },\n { type: 'resource-object', name: 'updater', header: i18next.t('field.updater'), width: 90, sortable: false },\n { type: 'datetime', name: 'updatedAt', header: i18next.t('field.updated_at'), width: 180, sortable: true },\n { type: 'resource-object', name: 'contact', hidden: true },\n /* The rail's department: a filter of the grid, not drawn in the form - the rail is where it is chosen. */\n { type: 'string', name: 'departmentId', header: i18next.t('field.department'), hidden: true, record: { editable: false }, filter: { operator: 'eq', type: 'string', hidden: true } }\n ],\n /*\n * No empty row under the records: 「행 추가」 starts one, and a paste past the last row adds rows with the same draft -\n * in the department picked on the rail, if one is.\n */\n rows: { appendable: false, pasteAppendable: true, newRecord: () => this.draft(), selectable: { multiple: true } },\n columnsVersion: COLUMNS_VERSION,\n sorters: [{ name: 'controlNo' }]\n }\n }\n\n /** A new employee starts in the department picked on the rail. */\n private draft() {\n const department = this.selectedDepartment\n return department ? { department: { id: department.id, controlNo: department.controlNo, name: department.name, description: department.description } } : {}\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n // do something here when this page just became as active\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n /* The rail's selection arrives as the grid's own `departmentId` filter; nothing else sets one. */\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: employees(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n controlNo\n name\n alias\n type\n jobResponsibility\n jobPosition\n active\n email\n phone\n user {\n id\n name\n }\n department {\n id\n __typename\n controlNo\n name\n description\n }\n supervisor {\n id\n name\n controlNo\n }\n note\n hiredOn\n retiredOn\n contact {\n id\n email\n phone\n address\n }\n profile {\n left\n top\n zoom\n picture\n }\n updater {\n id\n name\n }\n updatedAt\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings }\n })\n\n const records = response.data.responses.items\n\n return { total: response.data.responses.total || 0, records }\n }\n\n async onDeleteEmployee() {\n const ids = (this.grist?.selected ?? []).map(record => record.id).filter(Boolean)\n if (!ids.length) {\n notify({ level: 'info', message: i18next.t('text.select-rows-to-delete') })\n return\n }\n if (!(await OxPrompt.confirmDelete({ count: ids.length }))) {\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteEmployees(ids: $ids)\n }\n `,\n variables: { ids }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n notify({ message: i18next.t('text.deleted') })\n }\n }\n\n async onUpdateEmployee() {\n const dirty = this.grist.dirtyRecords\n if (!dirty?.length) {\n notify({ level: 'info', message: i18next.t('text.nothing-to-save') })\n return\n }\n\n const patches = dirty.map(patch => {\n let patchField: any = patch.id ? { id: patch.id } : {}\n const dirtyFields = patch.__dirtyfields__\n for (let key in dirtyFields) {\n patchField[key] = dirtyFields[key].after\n }\n patchField.cuFlag = patch.__dirty__\n\n return patchField\n })\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [EmployeePatch!]!) {\n updateMultipleEmployee(patches: $patches) {\n name\n }\n }\n `,\n variables: { patches }\n })\n\n if (!response.errors) {\n this.grist.fetch()\n }\n }\n\n async exportHandler() {\n const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records\n const targetFieldSet = new Set([\n 'id',\n 'controlNo',\n 'name',\n 'alias',\n 'type',\n 'hiredOn',\n 'retiredOn',\n 'active',\n 'note'\n ])\n\n return exportTargets.map(employee => {\n let tempObj = {}\n for (const field of targetFieldSet) {\n tempObj[field] = employee[field]\n }\n\n return tempObj\n })\n }\n\n async importHandler(records) {\n const popup = openPopup(\n html`\n <employee-importer\n .employees=${records}\n @imported=${() => {\n history.back()\n this.grist.fetch()\n }}\n ></employee-importer>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.import employee') }\n )\n\n popup.onclosed = () => {\n this.grist.fetch()\n }\n }\n\n async openContactPopup(record: GristRecord) {\n if (!record.contact?.id) {\n return\n }\n\n const popup = openPopup(\n html`\n <contact-popup\n .contactId=${record.contact.id}\n @change=${() => {\n this.grist.fetch()\n }}\n @detach=${() => {\n this.detachContact(record)\n }}\n detachable\n ></contact-popup>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.contact') }\n )\n }\n\n async openContactSelector(record: GristRecord) {\n const popup = openPopup(\n html`\n <contact-selector .confirmCallback=${selected => this.attachContact(record, selected)}></contact-selector>\n `,\n { backdrop: true, size: 'large', title: i18next.t('title.contact') }\n )\n }\n\n async attachContact(record: GristRecord, contact: Contact) {\n if (record.id) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $contactId: String!) {\n attachContact(id: $id, contactId: $contactId) {\n id\n }\n }\n `,\n variables: { id: record.id, contactId: contact.id }\n })\n\n this.grist.fetch()\n } else if (contact?.id) {\n const picked = {\n id: contact.id,\n name: contact.name,\n email: (contact as any).email,\n phone: (contact as any).phone,\n address: (contact as any).address\n }\n /* A row started with 「행 추가」 takes the contact; otherwise the contact starts a new row. */\n if (record?.__dirty__ === '+') {\n record.contact = picked\n record.name = record.name || contact.name\n } else {\n this.grist.addNewRecord({ name: contact.name, contact: picked })\n }\n this.grist.refresh()\n await this.grist.requestUpdate()\n\n this.grist.checkDirties()\n }\n }\n\n async detachContact(record) {\n if (record.id) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n detachContact(id: $id) {\n id\n }\n }\n `,\n variables: { id: record.id }\n })\n\n this.grist.fetch()\n } else {\n record.contact = null\n this.grist.refresh()\n }\n }\n\n async attachSystemUser(record) {\n if (!record.user) {\n await client.mutate({\n mutation: gql`\n mutation ($employeeId: String!) {\n registerEmployeeAsSystemUser(employeeId: $employeeId)\n }\n `,\n variables: { employeeId: record.id }\n })\n }\n\n this.grist.fetch()\n }\n}\n"]}
|