@wipco/sdui 0.50.6 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DatePicker-BK_jsV7i.d.ts → DatePicker-C_TT_SOw.d.ts} +25 -0
- package/dist/{chunk-OEWTVLPZ.js → chunk-2HLXCKK7.js} +2 -2
- package/dist/{chunk-PWVHAUJC.js → chunk-2YP5N4VV.js} +6 -4
- package/dist/{chunk-QTHYLNJW.js → chunk-37SFFW37.js} +2 -13
- package/dist/{chunk-YQOMSWW5.js → chunk-5WW4MBRO.js} +1 -1
- package/dist/{chunk-LIOS3PF2.js → chunk-5XPZ3RSA.js} +3 -4
- package/dist/{chunk-ZD3VNVRF.js → chunk-7BGDSSAN.js} +5 -13
- package/dist/{chunk-Y2LIEWQX.js → chunk-7FZTUI6U.js} +6 -5
- package/dist/{chunk-HJ5VSXR4.js → chunk-7P7N43JV.js} +2 -2
- package/dist/{chunk-55VB6SDU.js → chunk-A5XQOEVH.js} +23 -20
- package/dist/{chunk-77LKJCMM.js → chunk-A6LAIGUS.js} +20 -108
- package/dist/{chunk-YXS5FXVS.js → chunk-AC5TI3BE.js} +7 -16
- package/dist/{chunk-AIOJYVJ2.js → chunk-AXGF4M57.js} +1 -1
- package/dist/{chunk-5MPK3NZK.js → chunk-B6WMC2AN.js} +3 -3
- package/dist/{chunk-C6ZV4VBN.js → chunk-C37U3GCC.js} +4 -4
- package/dist/{chunk-265YPW4W.js → chunk-DMLDKW7K.js} +1 -1
- package/dist/{chunk-FZ72IDVF.js → chunk-E6ISNQK3.js} +2 -2
- package/dist/{chunk-STX2AX6Y.js → chunk-FLAN7CV3.js} +7 -39
- package/dist/{chunk-IV5YTVHR.js → chunk-GE6BYNQJ.js} +18 -33
- package/dist/{chunk-ZX36LKJ7.js → chunk-GTGS2QRL.js} +7 -6
- package/dist/{chunk-NL3I6F2I.js → chunk-HBBTENSV.js} +3 -3
- package/dist/{chunk-RUU7WBGR.js → chunk-I45EUZC6.js} +19 -9
- package/dist/{chunk-JBKNIALK.js → chunk-I5SD7XRA.js} +9 -6
- package/dist/{chunk-X7GHY2RI.js → chunk-IFKYGJXP.js} +14 -42
- package/dist/{chunk-J3YMUR6R.js → chunk-IZ3JA2BR.js} +3 -3
- package/dist/{chunk-AUW5RP24.js → chunk-JIV4YHCZ.js} +7 -6
- package/dist/{chunk-M6KM3FJS.js → chunk-JYAR7D5U.js} +2 -2
- package/dist/{chunk-DKPNFEVU.js → chunk-KO6OEY3G.js} +19 -6
- package/dist/{chunk-JHHMFL5D.js → chunk-LFEJLOFN.js} +28 -16
- package/dist/chunk-MMIGOPO5.js +111 -0
- package/dist/{chunk-YSSNP6JM.js → chunk-N25YP7ID.js} +6 -21
- package/dist/{chunk-F2W2FWOT.js → chunk-N5RKM6IC.js} +7 -7
- package/dist/{chunk-C4HYWZML.js → chunk-O4IISNE7.js} +1 -1
- package/dist/chunk-Q4SWUINA.js +51 -0
- package/dist/{chunk-TUOG7EEI.js → chunk-RNOUXUBO.js} +418 -22
- package/dist/{chunk-4VZI3PLI.js → chunk-RYHEV5E3.js} +15 -39
- package/dist/{chunk-AVRNQOB5.js → chunk-SAPBDJJQ.js} +14 -13
- package/dist/{chunk-OPJ4DYNI.js → chunk-SJ3737RA.js} +156 -158
- package/dist/{chunk-UMANGYRD.js → chunk-TFGNKFL2.js} +1 -1
- package/dist/{chunk-KYGSMUUU.js → chunk-VY7MVBSE.js} +2 -2
- package/dist/{chunk-VDBUXYEB.js → chunk-WOYMEEPH.js} +8 -8
- package/dist/{chunk-I5Z2RVDF.js → chunk-WSLT32Q4.js} +278 -30
- package/dist/{chunk-NYUHSMUU.js → chunk-XGFDY43I.js} +2 -2
- package/dist/{chunk-ODKZF4IT.js → chunk-YOZN35HD.js} +17 -9
- package/dist/{chunk-EKP6Z3G6.js → chunk-YVTV4ZV6.js} +1 -1
- package/dist/{chunk-6BCWFPNJ.js → chunk-YWUDBLO6.js} +2 -2
- package/dist/chunk-Z4PYMTTS.js +41 -0
- package/dist/{chunk-WXIQLWIX.js → chunk-ZFNFPXPR.js} +2 -2
- package/dist/{chunk-7GOWOSX6.js → chunk-ZORQPB6B.js} +11 -5
- package/dist/index.d.ts +1096 -941
- package/dist/index.js +369 -610
- package/dist/meta.d.ts +13 -12
- package/dist/meta.js +84 -16
- package/dist/rich/ExcelUploadCard.d.ts +7 -0
- package/dist/rich/ExcelUploadCard.js +17 -13
- package/dist/rich.d.ts +1 -1
- package/dist/rich.js +25 -12
- package/dist/styles.css +10 -2
- package/dist/{types-D14eqLpf.d.ts → types-C7y9CpgF.d.ts} +7 -5
- package/dist/widgets/ApprovalLineEditor.js +7 -6
- package/dist/widgets/ApprovalOverridesEditor.d.ts +11 -1
- package/dist/widgets/ApprovalOverridesEditor.js +9 -8
- package/dist/widgets/ApprovalStepper.js +3 -3
- package/dist/widgets/AutocompleteField.d.ts +1 -0
- package/dist/widgets/AutocompleteField.js +7 -6
- package/dist/widgets/ColumnBoard.js +3 -3
- package/dist/widgets/DiffView.js +3 -3
- package/dist/widgets/Disclosure.js +3 -3
- package/dist/widgets/EventCalendar.d.ts +16 -1
- package/dist/widgets/EventCalendar.js +3 -3
- package/dist/widgets/FileDropzone.js +7 -6
- package/dist/widgets/ImageLightbox.js +5 -4
- package/dist/widgets/InlineEdit.js +3 -3
- package/dist/widgets/JsonField.js +3 -3
- package/dist/widgets/LiveClock.js +2 -2
- package/dist/widgets/OptionSchemaEditor.js +4 -4
- package/dist/widgets/OptionValueFields.d.ts +5 -0
- package/dist/widgets/OptionValueFields.js +4 -4
- package/dist/widgets/OrgChart.js +4 -3
- package/dist/widgets/OrgChartBoard.d.ts +93 -4
- package/dist/widgets/OrgChartBoard.js +9 -6
- package/dist/widgets/PeriodFilter.js +4 -4
- package/dist/widgets/PermissionMatrixEditor.d.ts +16 -0
- package/dist/widgets/PermissionMatrixEditor.js +4 -4
- package/dist/widgets/PositionSelect.d.ts +6 -1
- package/dist/widgets/PositionSelect.js +5 -4
- package/dist/widgets/PrintSheet.js +3 -3
- package/dist/widgets/ProfileEditDiffCard.d.ts +6 -0
- package/dist/widgets/ProfileEditDiffCard.js +4 -4
- package/dist/widgets/QRDisplay.js +4 -4
- package/dist/widgets/RankBoard.d.ts +6 -0
- package/dist/widgets/RankBoard.js +6 -5
- package/dist/widgets/RecordSheet.js +2 -2
- package/dist/widgets/RoleMemberPicker.d.ts +11 -5
- package/dist/widgets/RoleMemberPicker.js +5 -4
- package/dist/widgets/SearchableMultiPicker.js +5 -5
- package/dist/widgets/SecureScreen.d.ts +12 -0
- package/dist/widgets/SecureScreen.js +3 -3
- package/dist/widgets/StackedMeter.js +2 -2
- package/dist/widgets/StagePeriodEditor.js +4 -5
- package/dist/widgets/Strip.js +2 -2
- package/dist/widgets/SummaryTable.js +2 -2
- package/dist/widgets/TagMultiSelect.d.ts +0 -1
- package/dist/widgets/TagMultiSelect.js +4 -4
- package/dist/widgets/Timeline.js +4 -4
- package/dist/widgets/TreePicker.js +6 -6
- package/dist/widgets/TreeView.js +5 -5
- package/dist/widgets/index.d.ts +3 -3
- package/dist/widgets/index.js +81 -79
- package/package.json +1 -1
- package/dist/chunk-EKVA7T7P.js +0 -198
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { parseJobPositionRow } from './chunk-Z4PYMTTS.js';
|
|
2
|
+
import { usePanZoomCanvas } from './chunk-MMIGOPO5.js';
|
|
3
|
+
import { ImageLightbox } from './chunk-VY7MVBSE.js';
|
|
4
|
+
import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-KO6OEY3G.js';
|
|
5
|
+
import { warnOnce, Badge, Button, IconButton, Icon } from './chunk-RNOUXUBO.js';
|
|
6
|
+
import { boxed } from './chunk-5WW4MBRO.js';
|
|
7
|
+
import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
|
|
8
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
9
|
|
|
8
10
|
var PAGE_SIZE = 500;
|
|
9
11
|
var MAX_PAGES = 20;
|
|
10
12
|
var UNASSIGNED_GROUP_ID = "kc_unassigned_department";
|
|
13
|
+
var UNASSIGNED_GROUP_NAMES = ["\uBBF8\uC9C0\uC815"];
|
|
11
14
|
var BOARD_COLORS = [
|
|
12
15
|
"var(--wp-series-1)",
|
|
13
16
|
"var(--wp-series-2)",
|
|
@@ -38,8 +41,6 @@ var LEADER_WIDTH = 230;
|
|
|
38
41
|
var LEADER_HEIGHT = 62;
|
|
39
42
|
var TOP_GAP = 58;
|
|
40
43
|
var ROOT_ROW_GAP = 70;
|
|
41
|
-
var MIN_ZOOM = 0.35;
|
|
42
|
-
var MAX_ZOOM = 1.8;
|
|
43
44
|
var DEFAULT_VIEW = { scale: 0.82, x: 48, y: 48 };
|
|
44
45
|
var DUTY_ORDER = [
|
|
45
46
|
"\uD68C\uC7A5",
|
|
@@ -74,6 +75,34 @@ var GRADE_ORDER = [
|
|
|
74
75
|
"\uC0AC\uC6D0",
|
|
75
76
|
"\uC778\uD134"
|
|
76
77
|
];
|
|
78
|
+
var LEADERSHIP_MATCH = [
|
|
79
|
+
["\uD68C\uC7A5"],
|
|
80
|
+
["\uB300\uD45C\uC774\uC0AC"],
|
|
81
|
+
["\uB300\uD45C"],
|
|
82
|
+
["\uC0AC\uC7A5", "CEO"]
|
|
83
|
+
];
|
|
84
|
+
var DEFAULT_VOCAB = {
|
|
85
|
+
dutyOrder: DUTY_ORDER,
|
|
86
|
+
gradeOrder: GRADE_ORDER,
|
|
87
|
+
leadership: LEADERSHIP_MATCH,
|
|
88
|
+
unassignedIds: /* @__PURE__ */ new Set([UNASSIGNED_GROUP_ID]),
|
|
89
|
+
unassignedNames: UNASSIGNED_GROUP_NAMES
|
|
90
|
+
};
|
|
91
|
+
function orgVocabOf(props) {
|
|
92
|
+
const { dutyOrder, gradeOrder, leadershipMatch, unassignedGroupIds, unassignedNames } = props;
|
|
93
|
+
return {
|
|
94
|
+
dutyOrder: dutyOrder && dutyOrder.length > 0 ? dutyOrder : DUTY_ORDER,
|
|
95
|
+
gradeOrder: gradeOrder && gradeOrder.length > 0 ? gradeOrder : GRADE_ORDER,
|
|
96
|
+
leadership: leadershipMatch && leadershipMatch.length > 0 ? leadershipMatch.map((entry) => Array.isArray(entry) ? entry : [entry]) : LEADERSHIP_MATCH,
|
|
97
|
+
unassignedIds: new Set(
|
|
98
|
+
unassignedGroupIds && unassignedGroupIds.length > 0 ? unassignedGroupIds : [UNASSIGNED_GROUP_ID]
|
|
99
|
+
),
|
|
100
|
+
unassignedNames: unassignedNames && unassignedNames.length > 0 ? unassignedNames : UNASSIGNED_GROUP_NAMES
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function unassignedNamesOf(vocab) {
|
|
104
|
+
return vocab.unassignedNames ?? UNASSIGNED_GROUP_NAMES;
|
|
105
|
+
}
|
|
77
106
|
var OCB_CSS = `
|
|
78
107
|
.erp-ocb-member { transition: border-color .15s ease, background-color .15s ease; }
|
|
79
108
|
.erp-ocb-member:hover { border-color: var(--wp-border-brand); background: var(--wp-surface-hover); }
|
|
@@ -105,8 +134,20 @@ function rowsOf(body, keys) {
|
|
|
105
134
|
function pickEmployees(body) {
|
|
106
135
|
return rowsOf(body, ["data", "employees"]).flatMap((row) => {
|
|
107
136
|
if (typeof row !== "object" || row === null) return [];
|
|
108
|
-
const
|
|
109
|
-
if (typeof
|
|
137
|
+
const raw = row;
|
|
138
|
+
if (typeof raw.id !== "string" || typeof raw.name !== "string") return [];
|
|
139
|
+
const record = { ...raw };
|
|
140
|
+
if (record.department_id == null && typeof raw.departmentId === "string") {
|
|
141
|
+
record.department_id = raw.departmentId;
|
|
142
|
+
}
|
|
143
|
+
if (record.job_title == null && typeof raw.jobTitle === "string") {
|
|
144
|
+
record.job_title = raw.jobTitle;
|
|
145
|
+
}
|
|
146
|
+
const ref = record.department;
|
|
147
|
+
if (ref && typeof ref === "object" && ref.parent_id == null) {
|
|
148
|
+
const camelParent = ref.parentId;
|
|
149
|
+
if (typeof camelParent === "string") record.department = { ...ref, parent_id: camelParent };
|
|
150
|
+
}
|
|
110
151
|
return [record];
|
|
111
152
|
});
|
|
112
153
|
}
|
|
@@ -115,11 +156,12 @@ function pickGroups(body) {
|
|
|
115
156
|
if (typeof row !== "object" || row === null) return [];
|
|
116
157
|
const record = row;
|
|
117
158
|
if (typeof record.id !== "string" || typeof record.name !== "string") return [];
|
|
159
|
+
const parentId = typeof record.parent_id === "string" ? record.parent_id : typeof record.parentId === "string" ? record.parentId : null;
|
|
118
160
|
return [
|
|
119
161
|
{
|
|
120
162
|
id: record.id,
|
|
121
163
|
name: record.name,
|
|
122
|
-
parent_id:
|
|
164
|
+
parent_id: parentId,
|
|
123
165
|
path: typeof record.path === "string" ? record.path : null
|
|
124
166
|
}
|
|
125
167
|
];
|
|
@@ -127,16 +169,10 @@ function pickGroups(body) {
|
|
|
127
169
|
}
|
|
128
170
|
function pickPositions(body) {
|
|
129
171
|
return rowsOf(body, ["data"]).flatMap((row) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (typeof record.id !== "string" || typeof record.name !== "string") return [];
|
|
172
|
+
const parsed = parseJobPositionRow(row);
|
|
173
|
+
if (!parsed || parsed.id === void 0) return [];
|
|
133
174
|
return [
|
|
134
|
-
{
|
|
135
|
-
id: record.id,
|
|
136
|
-
name: record.name,
|
|
137
|
-
rank_order: typeof record.rank_order === "number" ? record.rank_order : 0,
|
|
138
|
-
is_active: typeof record.is_active === "boolean" ? record.is_active : true
|
|
139
|
-
}
|
|
175
|
+
{ id: parsed.id, name: parsed.name, rank_order: parsed.rankOrder, is_active: parsed.isActive }
|
|
140
176
|
];
|
|
141
177
|
});
|
|
142
178
|
}
|
|
@@ -179,7 +215,7 @@ function rankIn(order, value) {
|
|
|
179
215
|
});
|
|
180
216
|
return best;
|
|
181
217
|
}
|
|
182
|
-
function compareGrades(a, b, positionRanks) {
|
|
218
|
+
function compareGrades(a, b, positionRanks, gradeOrder) {
|
|
183
219
|
const rankA = jobPositionRankOf(positionRanks, a);
|
|
184
220
|
const rankB = jobPositionRankOf(positionRanks, b);
|
|
185
221
|
if (rankA !== null || rankB !== null) {
|
|
@@ -187,12 +223,12 @@ function compareGrades(a, b, positionRanks) {
|
|
|
187
223
|
if (rankB === null) return -1;
|
|
188
224
|
return rankA - rankB;
|
|
189
225
|
}
|
|
190
|
-
return rankIn(
|
|
226
|
+
return rankIn(gradeOrder, a) - rankIn(gradeOrder, b);
|
|
191
227
|
}
|
|
192
|
-
function compareMembers(a, b, positionRanks) {
|
|
193
|
-
const dutyDiff = rankIn(
|
|
228
|
+
function compareMembers(a, b, positionRanks, dutyOrder = DUTY_ORDER, gradeOrder = GRADE_ORDER) {
|
|
229
|
+
const dutyDiff = rankIn(dutyOrder, a.job_title) - rankIn(dutyOrder, b.job_title);
|
|
194
230
|
if (dutyDiff !== 0) return dutyDiff;
|
|
195
|
-
const gradeDiff = compareGrades(a.grade, b.grade, positionRanks);
|
|
231
|
+
const gradeDiff = compareGrades(a.grade, b.grade, positionRanks, gradeOrder);
|
|
196
232
|
if (gradeDiff !== 0) return gradeDiff;
|
|
197
233
|
const levelDiff = (b.level ?? 0) - (a.level ?? 0);
|
|
198
234
|
if (levelDiff !== 0) return levelDiff;
|
|
@@ -201,40 +237,45 @@ function compareMembers(a, b, positionRanks) {
|
|
|
201
237
|
function positionText(employee) {
|
|
202
238
|
return (employee.grade ?? "").trim() || (employee.job_title ?? "").trim() || "-";
|
|
203
239
|
}
|
|
204
|
-
function isUnassignedGroup(group) {
|
|
205
|
-
return group.id
|
|
240
|
+
function isUnassignedGroup(group, unassignedIds = DEFAULT_VOCAB.unassignedIds, unassignedNames = UNASSIGNED_GROUP_NAMES) {
|
|
241
|
+
return unassignedIds.has(group.id) || unassignedNames.includes((group.name ?? "").trim()) || unassignedNames.includes(group.id.trim());
|
|
206
242
|
}
|
|
207
243
|
function employeeGroupId(employee) {
|
|
208
244
|
return employee.department_id ?? employee.department?.id ?? "";
|
|
209
245
|
}
|
|
210
|
-
function groupsFromEmployees(employees) {
|
|
246
|
+
function groupsFromEmployees(employees, vocab) {
|
|
247
|
+
const names = unassignedNamesOf(vocab);
|
|
211
248
|
const groupsById = /* @__PURE__ */ new Map();
|
|
212
249
|
for (const employee of employees) {
|
|
213
250
|
const ref = employee.department;
|
|
214
251
|
const id = employee.department_id ?? ref?.id ?? "";
|
|
215
252
|
if (!id || groupsById.has(id)) continue;
|
|
216
|
-
const name = (ref?.name ?? "").trim() || "\uBBF8\uC9C0\uC815";
|
|
217
|
-
if (isUnassignedGroup({ id, name })) continue;
|
|
253
|
+
const name = (ref?.name ?? "").trim() || (names[0] ?? "\uBBF8\uC9C0\uC815");
|
|
254
|
+
if (isUnassignedGroup({ id, name }, vocab.unassignedIds, names)) continue;
|
|
218
255
|
groupsById.set(id, { id, name, parent_id: ref?.parent_id ?? null });
|
|
219
256
|
}
|
|
220
257
|
return Array.from(groupsById.values());
|
|
221
258
|
}
|
|
222
|
-
function mergeEmployeeGroups(groups, employees) {
|
|
259
|
+
function mergeEmployeeGroups(groups, employees, vocab) {
|
|
260
|
+
const names = unassignedNamesOf(vocab);
|
|
223
261
|
const groupsById = new Map(
|
|
224
|
-
groups.filter((group) => !isUnassignedGroup(group)).map((group) => [group.id, group])
|
|
262
|
+
groups.filter((group) => !isUnassignedGroup(group, vocab.unassignedIds, names)).map((group) => [group.id, group])
|
|
225
263
|
);
|
|
226
264
|
for (const employee of employees) {
|
|
227
265
|
const ref = employee.department;
|
|
228
266
|
const id = employee.department_id ?? ref?.id ?? "";
|
|
229
267
|
if (!id || groupsById.has(id)) continue;
|
|
230
|
-
const name = (ref?.name ?? "").trim() || "\uBBF8\uC9C0\uC815";
|
|
231
|
-
if (isUnassignedGroup({ id, name })) continue;
|
|
268
|
+
const name = (ref?.name ?? "").trim() || (names[0] ?? "\uBBF8\uC9C0\uC815");
|
|
269
|
+
if (isUnassignedGroup({ id, name }, vocab.unassignedIds, names)) continue;
|
|
232
270
|
groupsById.set(id, { id, name, parent_id: ref?.parent_id ?? null });
|
|
233
271
|
}
|
|
234
272
|
return Array.from(groupsById.values());
|
|
235
273
|
}
|
|
236
|
-
function buildModel(groups, employees, positionRanks) {
|
|
237
|
-
const
|
|
274
|
+
function buildModel(groups, employees, positionRanks, vocab = DEFAULT_VOCAB) {
|
|
275
|
+
const names = unassignedNamesOf(vocab);
|
|
276
|
+
const visibleGroups = groups.filter(
|
|
277
|
+
(group) => !isUnassignedGroup(group, vocab.unassignedIds, names)
|
|
278
|
+
);
|
|
238
279
|
const groupsById = new Map(visibleGroups.map((group) => [group.id, group]));
|
|
239
280
|
const employeesByGroupId = /* @__PURE__ */ new Map();
|
|
240
281
|
for (const employee of employees) {
|
|
@@ -255,7 +296,7 @@ function buildModel(groups, employees, positionRanks) {
|
|
|
255
296
|
(items) => items.sort((a, b) => a.name.localeCompare(b.name, "ko"))
|
|
256
297
|
);
|
|
257
298
|
employeesByGroupId.forEach(
|
|
258
|
-
(items) => items.sort((a, b) => compareMembers(a, b, positionRanks))
|
|
299
|
+
(items) => items.sort((a, b) => compareMembers(a, b, positionRanks, vocab.dutyOrder, vocab.gradeOrder))
|
|
259
300
|
);
|
|
260
301
|
return {
|
|
261
302
|
childrenByParent,
|
|
@@ -275,22 +316,18 @@ function groupEmployees(groupId, model, excludedIds) {
|
|
|
275
316
|
(employee) => !excludedIds.has(employee.id)
|
|
276
317
|
);
|
|
277
318
|
}
|
|
278
|
-
function
|
|
279
|
-
return employees.filter((employee) => {
|
|
280
|
-
const title = `${employee.grade ?? ""} ${employee.job_title ?? ""}`;
|
|
281
|
-
return /회장|대표|CEO|사장/.test(title);
|
|
282
|
-
}).sort((a, b) => leadershipRank(a) - leadershipRank(b)).slice(0, 3);
|
|
283
|
-
}
|
|
284
|
-
function leadershipRank(employee) {
|
|
319
|
+
function leadershipRankOf(employee, leadership) {
|
|
285
320
|
const title = `${employee.grade ?? ""} ${employee.job_title ?? ""}`;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return 9;
|
|
321
|
+
for (let index = 0; index < leadership.length; index += 1) {
|
|
322
|
+
if (leadership[index].some((name) => title.includes(name))) return index;
|
|
323
|
+
}
|
|
324
|
+
return -1;
|
|
291
325
|
}
|
|
292
|
-
function
|
|
293
|
-
|
|
326
|
+
function leadershipEmployees(employees, leadership = LEADERSHIP_MATCH) {
|
|
327
|
+
return employees.map((employee) => ({ employee, rank: leadershipRankOf(employee, leadership) })).filter((entry) => entry.rank >= 0).sort((a, b) => a.rank - b.rank).slice(0, 3).map((entry) => entry.employee);
|
|
328
|
+
}
|
|
329
|
+
function buildCanvasLayout(model, employees, leadershipGroups) {
|
|
330
|
+
const leadership = leadershipEmployees(employees, leadershipGroups);
|
|
294
331
|
const leadershipIds = new Set(leadership.map((employee) => employee.id));
|
|
295
332
|
const topGroup = model.visibleRoots.length === 1 ? model.visibleRoots[0] : null;
|
|
296
333
|
const topChildren = topGroup ? model.childrenByParent.get(topGroup.id) ?? [] : [];
|
|
@@ -645,17 +682,6 @@ function connectorPath(connector) {
|
|
|
645
682
|
`V ${connector.toY}`
|
|
646
683
|
].join(" ");
|
|
647
684
|
}
|
|
648
|
-
function clamp(value, min, max) {
|
|
649
|
-
return Math.min(max, Math.max(min, value));
|
|
650
|
-
}
|
|
651
|
-
function applyZoom(current, nextScale, focal) {
|
|
652
|
-
const scale = clamp(nextScale, MIN_ZOOM, MAX_ZOOM);
|
|
653
|
-
return {
|
|
654
|
-
scale,
|
|
655
|
-
x: focal.x - (focal.x - current.x) / current.scale * scale,
|
|
656
|
-
y: focal.y - (focal.y - current.y) / current.scale * scale
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
685
|
function EmployeeAvatar({ employee, featured }) {
|
|
660
686
|
const size = featured ? 40 : 32;
|
|
661
687
|
if (employee.image) {
|
|
@@ -877,92 +903,31 @@ function CanvasEmployeeNode({
|
|
|
877
903
|
function OrganizationCanvas({
|
|
878
904
|
model,
|
|
879
905
|
employees,
|
|
906
|
+
leadership,
|
|
880
907
|
selectedGroupId,
|
|
881
908
|
onSelect,
|
|
882
909
|
onOpenCard,
|
|
883
910
|
height
|
|
884
911
|
}) {
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
912
|
+
const {
|
|
913
|
+
viewportRef,
|
|
914
|
+
view,
|
|
915
|
+
setView,
|
|
916
|
+
dragging,
|
|
917
|
+
isFullscreen,
|
|
918
|
+
viewportCenter,
|
|
919
|
+
zoomAt,
|
|
920
|
+
toggleFullscreen,
|
|
921
|
+
pointerHandlers
|
|
922
|
+
} = usePanZoomCanvas({ stopSelector: "[data-org-card]", initialView: DEFAULT_VIEW });
|
|
923
|
+
const layout = useMemo(
|
|
924
|
+
() => buildCanvasLayout(model, employees, leadership),
|
|
925
|
+
[model, employees, leadership]
|
|
926
|
+
);
|
|
898
927
|
useEffect(() => {
|
|
899
928
|
setView(DEFAULT_VIEW);
|
|
900
|
-
}, [layout.width, layout.height]);
|
|
901
|
-
|
|
902
|
-
const viewport = viewportRef.current;
|
|
903
|
-
if (!viewport) return;
|
|
904
|
-
const onWheel = (event) => {
|
|
905
|
-
event.preventDefault();
|
|
906
|
-
const rect = viewport.getBoundingClientRect();
|
|
907
|
-
const focal = { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
908
|
-
setView(
|
|
909
|
-
(current) => applyZoom(current, current.scale * (event.deltaY > 0 ? 0.9 : 1.1), focal)
|
|
910
|
-
);
|
|
911
|
-
};
|
|
912
|
-
viewport.addEventListener("wheel", onWheel, { passive: false });
|
|
913
|
-
return () => viewport.removeEventListener("wheel", onWheel);
|
|
914
|
-
}, []);
|
|
915
|
-
const viewportCenter = useCallback(() => {
|
|
916
|
-
const rect = viewportRef.current?.getBoundingClientRect();
|
|
917
|
-
if (!rect) return { x: 0, y: 0 };
|
|
918
|
-
return { x: rect.width / 2, y: rect.height / 2 };
|
|
919
|
-
}, []);
|
|
920
|
-
const zoomStep = (delta) => {
|
|
921
|
-
const focal = viewportCenter();
|
|
922
|
-
setView((current) => applyZoom(current, current.scale + delta, focal));
|
|
923
|
-
};
|
|
924
|
-
const handlePointerDown = (event) => {
|
|
925
|
-
const target = event.target;
|
|
926
|
-
if (target.closest("[data-org-card]")) return;
|
|
927
|
-
dragRef.current = {
|
|
928
|
-
pointerId: event.pointerId,
|
|
929
|
-
startX: event.clientX,
|
|
930
|
-
startY: event.clientY,
|
|
931
|
-
originX: view.x,
|
|
932
|
-
originY: view.y
|
|
933
|
-
};
|
|
934
|
-
setDragging(true);
|
|
935
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
936
|
-
};
|
|
937
|
-
const handlePointerMove = (event) => {
|
|
938
|
-
const drag = dragRef.current;
|
|
939
|
-
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
940
|
-
setView((current) => ({
|
|
941
|
-
...current,
|
|
942
|
-
x: drag.originX + event.clientX - drag.startX,
|
|
943
|
-
y: drag.originY + event.clientY - drag.startY
|
|
944
|
-
}));
|
|
945
|
-
};
|
|
946
|
-
const handlePointerUp = (event) => {
|
|
947
|
-
if (dragRef.current?.pointerId !== event.pointerId) return;
|
|
948
|
-
dragRef.current = null;
|
|
949
|
-
setDragging(false);
|
|
950
|
-
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
951
|
-
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
952
|
-
}
|
|
953
|
-
};
|
|
954
|
-
const toggleFullscreen = async () => {
|
|
955
|
-
const viewport = viewportRef.current;
|
|
956
|
-
if (!viewport) return;
|
|
957
|
-
try {
|
|
958
|
-
if (document.fullscreenElement === viewport) {
|
|
959
|
-
await document.exitFullscreen();
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
await viewport.requestFullscreen();
|
|
963
|
-
} catch {
|
|
964
|
-
}
|
|
965
|
-
};
|
|
929
|
+
}, [layout.width, layout.height, setView]);
|
|
930
|
+
const zoomStep = (delta) => zoomAt(view.scale + delta, viewportCenter());
|
|
966
931
|
return /* @__PURE__ */ jsxs(
|
|
967
932
|
"div",
|
|
968
933
|
{
|
|
@@ -978,10 +943,7 @@ function OrganizationCanvas({
|
|
|
978
943
|
cursor: dragging ? "grabbing" : "grab",
|
|
979
944
|
touchAction: "none"
|
|
980
945
|
},
|
|
981
|
-
|
|
982
|
-
onPointerMove: handlePointerMove,
|
|
983
|
-
onPointerUp: handlePointerUp,
|
|
984
|
-
onPointerCancel: handlePointerUp,
|
|
946
|
+
...pointerHandlers,
|
|
985
947
|
children: [
|
|
986
948
|
/* @__PURE__ */ jsxs(
|
|
987
949
|
"div",
|
|
@@ -1080,7 +1042,12 @@ function OrgChartBoardImpl({
|
|
|
1080
1042
|
height = "72vh",
|
|
1081
1043
|
employeesEndpoint = "/employees",
|
|
1082
1044
|
departmentsEndpoint = "/departments?include=paths",
|
|
1083
|
-
positionsEndpoint = "/job-positions"
|
|
1045
|
+
positionsEndpoint = "/job-positions",
|
|
1046
|
+
dutyOrder,
|
|
1047
|
+
gradeOrder,
|
|
1048
|
+
leadershipMatch,
|
|
1049
|
+
unassignedGroupIds,
|
|
1050
|
+
unassignedNames
|
|
1084
1051
|
}) {
|
|
1085
1052
|
const adapter = useSduiAdapter();
|
|
1086
1053
|
const api = hostFetchOf(adapter) ?? defaultAdapter.fetch;
|
|
@@ -1090,24 +1057,46 @@ function OrgChartBoardImpl({
|
|
|
1090
1057
|
const [state, setState] = useState("idle");
|
|
1091
1058
|
const [offline, setOffline] = useState(false);
|
|
1092
1059
|
const [selectedGroupId, setSelectedGroupId] = useState("");
|
|
1060
|
+
const vocabKey = JSON.stringify({
|
|
1061
|
+
dutyOrder,
|
|
1062
|
+
gradeOrder,
|
|
1063
|
+
leadershipMatch,
|
|
1064
|
+
unassignedGroupIds,
|
|
1065
|
+
unassignedNames
|
|
1066
|
+
});
|
|
1067
|
+
const vocab = useMemo(
|
|
1068
|
+
() => orgVocabOf(JSON.parse(vocabKey)),
|
|
1069
|
+
[vocabKey]
|
|
1070
|
+
);
|
|
1071
|
+
const apiRef = useRef(api);
|
|
1072
|
+
apiRef.current = api;
|
|
1073
|
+
const vocabRef = useRef(vocab);
|
|
1074
|
+
vocabRef.current = vocab;
|
|
1093
1075
|
const load = useCallback(async () => {
|
|
1076
|
+
const fetchApi = apiRef.current;
|
|
1077
|
+
const currentVocab = vocabRef.current;
|
|
1094
1078
|
setState("loading");
|
|
1095
1079
|
setOffline(false);
|
|
1096
1080
|
try {
|
|
1097
1081
|
const [nextEmployees, fetchedGroups, nextPositions] = await Promise.all([
|
|
1098
|
-
fetchAllPages(
|
|
1082
|
+
fetchAllPages(fetchApi, employeesEndpoint, pickEmployees),
|
|
1099
1083
|
// 부서 조회가 죽어도 조직도는 떠야 한다 — 사원 데이터에서 합성한다.
|
|
1100
|
-
fetchAllPages(
|
|
1084
|
+
fetchAllPages(fetchApi, departmentsEndpoint, pickGroups).catch(
|
|
1101
1085
|
() => []
|
|
1102
1086
|
),
|
|
1103
1087
|
// 직위 마스터는 정렬 보조라 못 불러와도 조직도는 떠야 한다.
|
|
1104
|
-
fetchAllPages(
|
|
1088
|
+
fetchAllPages(fetchApi, positionsEndpoint, pickPositions).catch(
|
|
1105
1089
|
() => []
|
|
1106
1090
|
)
|
|
1107
1091
|
]);
|
|
1108
|
-
let nextGroups = fetchedGroups.length > 0 ? fetchedGroups : groupsFromEmployees(nextEmployees);
|
|
1109
|
-
nextGroups = mergeEmployeeGroups(nextGroups, nextEmployees);
|
|
1110
|
-
const model2 = buildModel(
|
|
1092
|
+
let nextGroups = fetchedGroups.length > 0 ? fetchedGroups : groupsFromEmployees(nextEmployees, currentVocab);
|
|
1093
|
+
nextGroups = mergeEmployeeGroups(nextGroups, nextEmployees, currentVocab);
|
|
1094
|
+
const model2 = buildModel(
|
|
1095
|
+
nextGroups,
|
|
1096
|
+
nextEmployees,
|
|
1097
|
+
jobPositionRankMap(nextPositions),
|
|
1098
|
+
currentVocab
|
|
1099
|
+
);
|
|
1111
1100
|
const firstGroupId = model2.visibleRoots[0]?.id ?? (nextEmployees[0] ? employeeGroupId(nextEmployees[0]) : "");
|
|
1112
1101
|
setEmployees(nextEmployees);
|
|
1113
1102
|
setGroups(nextGroups);
|
|
@@ -1118,17 +1107,25 @@ function OrgChartBoardImpl({
|
|
|
1118
1107
|
setOffline(error?.status === 503);
|
|
1119
1108
|
setState("error");
|
|
1120
1109
|
}
|
|
1121
|
-
}, []);
|
|
1110
|
+
}, [employeesEndpoint, departmentsEndpoint, positionsEndpoint]);
|
|
1122
1111
|
useEffect(() => {
|
|
1123
1112
|
void load();
|
|
1124
1113
|
}, [load]);
|
|
1125
1114
|
const model = useMemo(
|
|
1126
|
-
() => buildModel(groups, employees, jobPositionRankMap(positions)),
|
|
1127
|
-
[groups, employees, positions]
|
|
1115
|
+
() => buildModel(groups, employees, jobPositionRankMap(positions), vocab),
|
|
1116
|
+
[groups, employees, positions, vocab]
|
|
1128
1117
|
);
|
|
1129
1118
|
const openCard = useCallback(
|
|
1130
1119
|
(employee) => {
|
|
1131
|
-
onMemberClick
|
|
1120
|
+
if (!onMemberClick) {
|
|
1121
|
+
warnOnce(
|
|
1122
|
+
"orgchartboard:member-click",
|
|
1123
|
+
"[sdui] OrgChartBoard: onMemberClick\uC774 \uC5C6\uC5B4 \uC0AC\uC6D0 \uCE74\uB4DC \uD074\uB9AD\uC744 \uBB34\uC2DC\uD569\uB2C8\uB2E4 \u2014 setState(fromEvent)\uB85C \uD589\uC744 \uBC1B\uC544 navigate\uB85C \uC774\uC73C\uC138\uC694",
|
|
1124
|
+
"warn"
|
|
1125
|
+
);
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
onMemberClick(employee);
|
|
1132
1129
|
},
|
|
1133
1130
|
[onMemberClick]
|
|
1134
1131
|
);
|
|
@@ -1175,6 +1172,7 @@ function OrgChartBoardImpl({
|
|
|
1175
1172
|
{
|
|
1176
1173
|
model,
|
|
1177
1174
|
employees,
|
|
1175
|
+
leadership: vocab.leadership,
|
|
1178
1176
|
selectedGroupId,
|
|
1179
1177
|
onSelect: setSelectedGroupId,
|
|
1180
1178
|
onOpenCard: openCard,
|
|
@@ -1192,7 +1190,7 @@ function OrgChartBoardImpl({
|
|
|
1192
1190
|
overflow: "hidden"
|
|
1193
1191
|
},
|
|
1194
1192
|
children: [
|
|
1195
|
-
/* @__PURE__ */ jsx("style", { children: OCB_CSS }),
|
|
1193
|
+
/* @__PURE__ */ jsx("style", { href: "erp-ocb", precedence: "medium", children: OCB_CSS }),
|
|
1196
1194
|
/* @__PURE__ */ jsxs(
|
|
1197
1195
|
"div",
|
|
1198
1196
|
{
|
|
@@ -1239,4 +1237,4 @@ function OrgChartBoardImpl({
|
|
|
1239
1237
|
}
|
|
1240
1238
|
var OrgChartBoard = boxed(OrgChartBoardImpl, "OrgChartBoard");
|
|
1241
1239
|
|
|
1242
|
-
export { OrgChartBoard };
|
|
1240
|
+
export { OrgChartBoard, buildModel, compareMembers, isUnassignedGroup, leadershipEmployees, orgVocabOf, pickEmployees, pickGroups, pickPositions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OverlayLayer } from './chunk-XQPTSEJC.js';
|
|
2
|
-
import { Dialog, warnOnce } from './chunk-
|
|
2
|
+
import { Dialog, warnOnce } from './chunk-RNOUXUBO.js';
|
|
3
3
|
import { createContext, useContext, useMemo } from 'react';
|
|
4
4
|
import { jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ImageViewer } from './chunk-
|
|
2
|
-
import { boxed } from './chunk-
|
|
1
|
+
import { ImageViewer } from './chunk-SAPBDJJQ.js';
|
|
2
|
+
import { boxed } from './chunk-5WW4MBRO.js';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DateRangePicker } from './chunk-
|
|
1
|
+
import { DateRangePicker } from './chunk-WSLT32Q4.js';
|
|
2
2
|
import { useOverlayLayer } from './chunk-XQPTSEJC.js';
|
|
3
|
-
import { Input, Button, IconButton, Tag, Field, Checkbox } from './chunk-
|
|
3
|
+
import { Input, Button, IconButton, Tag, Field, Checkbox } from './chunk-RNOUXUBO.js';
|
|
4
4
|
import { useRef, useEffect, useState, useMemo } from 'react';
|
|
5
5
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -29,20 +29,20 @@ function Popover({
|
|
|
29
29
|
}, [open]);
|
|
30
30
|
useOverlayLayer(open, () => closeRef.current(), hostRef);
|
|
31
31
|
return (
|
|
32
|
-
// 트리거와 패널을 함께 감싸는 기준 상자 — .
|
|
32
|
+
// 트리거와 패널을 함께 감싸는 기준 상자 — .wp-popover-host의 position:relative가
|
|
33
33
|
// 패널 absolute의 기준이 된다
|
|
34
|
-
/* @__PURE__ */ jsxs("div", { ref: hostRef, className: "erp-popover-host", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { ref: hostRef, className: "wp-popover-host erp-popover-host", children: [
|
|
35
35
|
trigger,
|
|
36
36
|
open ? (
|
|
37
|
-
// 기본은 오른쪽 기준(.
|
|
37
|
+
// 기본은 오른쪽 기준(.wp-popover), --left가 붙으면 왼쪽 기준으로 뒤집힌다
|
|
38
38
|
/* @__PURE__ */ jsxs(
|
|
39
39
|
"div",
|
|
40
40
|
{
|
|
41
|
-
className: alignLeft ? "erp-popover erp-popover--left" : "erp-popover",
|
|
41
|
+
className: alignLeft ? "wp-popover wp-popover--left erp-popover erp-popover--left" : "wp-popover erp-popover",
|
|
42
42
|
style: width ? { width } : void 0,
|
|
43
43
|
children: [
|
|
44
|
-
/* @__PURE__ */ jsx("div", { className: "erp-popover__body", children }),
|
|
45
|
-
footer ? /* @__PURE__ */ jsx("div", { className: "erp-popover__foot", children: footer }) : null
|
|
44
|
+
/* @__PURE__ */ jsx("div", { className: "wp-popover__body erp-popover__body", children }),
|
|
45
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "wp-popover__foot erp-popover__foot", children: footer }) : null
|
|
46
46
|
]
|
|
47
47
|
}
|
|
48
48
|
)
|