@things-factory/organization 10.1.34 → 10.1.38
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/component/approval-line-items-editor-popup.d.ts +1 -0
- package/dist-client/component/approval-line-items-editor-popup.js +6 -8
- package/dist-client/component/approval-line-items-editor-popup.js.map +1 -1
- package/dist-client/component/approval-line-items-editor.d.ts +3 -0
- package/dist-client/component/approval-line-items-editor.js +31 -3
- package/dist-client/component/approval-line-items-editor.js.map +1 -1
- package/dist-client/component/approval-line-selector.d.ts +1 -0
- package/dist-client/component/approval-line-selector.js +6 -8
- package/dist-client/component/approval-line-selector.js.map +1 -1
- package/dist-client/component/assignees-editor-popup.d.ts +1 -0
- package/dist-client/component/assignees-editor-popup.js +6 -8
- package/dist-client/component/assignees-editor-popup.js.map +1 -1
- package/dist-client/component/copy-from.d.ts +13 -0
- package/dist-client/component/copy-from.js +16 -0
- package/dist-client/component/copy-from.js.map +1 -0
- package/dist-client/component/department-selector.d.ts +1 -0
- package/dist-client/component/department-selector.js +6 -8
- package/dist-client/component/department-selector.js.map +1 -1
- package/dist-client/component/popup-actions-row.test.d.ts +1 -0
- package/dist-client/component/popup-actions-row.test.js +42 -0
- package/dist-client/component/popup-actions-row.test.js.map +1 -0
- package/dist-client/component/recipients-editor-popup.d.ts +1 -0
- package/dist-client/component/recipients-editor-popup.js +6 -8
- package/dist-client/component/recipients-editor-popup.js.map +1 -1
- package/dist-client/grist-editor/grist-renderer-approval-line.d.ts +10 -0
- package/dist-client/grist-editor/grist-renderer-approval-line.js +27 -5
- package/dist-client/grist-editor/grist-renderer-approval-line.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types/approval-line.d.ts +23 -0
- package/dist-client/types/approval-line.js +9 -0
- package/dist-client/types/approval-line.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/tests/approval-line-mark.test.ts +68 -0
- package/tests/copy-from.test.ts +17 -0
- package/translations/en.json +3 -1
- package/translations/ja.json +5 -3
- package/translations/ko.json +5 -3
- package/translations/ms.json +3 -1
- package/translations/zh.json +5 -3
|
@@ -56,6 +56,29 @@ export declare function storedParticipation(item?: {
|
|
|
56
56
|
export declare function isApprovalStep(item?: {
|
|
57
57
|
participation?: ApprovalParticipation | string | null;
|
|
58
58
|
}): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* 결재선 한 줄을 화면이 어떻게 표시할지 — **셋이 같은 답을 쓰라고 한 자리에 둔다.**
|
|
61
|
+
*
|
|
62
|
+
* 「이 업무에 결재자가 있나」를 화면 셋이 각각 셌다. 업무정의 리스트의 사람 표는 결재선이 **비었는지**만
|
|
63
|
+
* 보고 답해서, 참조만 있는 줄도 사람 아이콘을 그렸다. BatchRelease 가 그랬다 — 두 줄 다 「참조에만
|
|
64
|
+
* 씁니다」인데 목록에는 결재자가 있는 것으로 보였다(2026-09-22, 수석 아키텍트가 화면에서 확인).
|
|
65
|
+
*
|
|
66
|
+
* 참조만 있는 결재선으로 규제를 걸면 **건은 올라가고 아무도 못 내린다.** 참조는 의견을 낼 뿐 판정하지
|
|
67
|
+
* 않기 때문이다.
|
|
68
|
+
*
|
|
69
|
+
* ── 네 갈래로 가른다 ──────────────────────────────────────────────────────
|
|
70
|
+
* 「참조만」을 「아예 없음」과 같이 그리면 고칠 사람이 무엇을 해야 하는지 모른다. 한쪽은 결재선을
|
|
71
|
+
* 만들어야 하고, 다른 쪽은 이미 있는 줄에 결재자를 더해야 한다.
|
|
72
|
+
*
|
|
73
|
+
* none 줄이 없다
|
|
74
|
+
* reference-only 줄은 있는데 결재 단계가 0 이다 — 아무도 못 내린다
|
|
75
|
+
* one 결재자 한 단계
|
|
76
|
+
* many 결재자 여러 단계
|
|
77
|
+
*/
|
|
78
|
+
export type ApprovalLineMark = 'none' | 'reference-only' | 'one' | 'many';
|
|
79
|
+
export declare function approvalLineMark(line?: {
|
|
80
|
+
participation?: ApprovalParticipation | string | null;
|
|
81
|
+
}[] | null): ApprovalLineMark;
|
|
59
82
|
export declare class ApprovalLineItem {
|
|
60
83
|
type?: OrgMemberTargetType;
|
|
61
84
|
value?: string;
|
|
@@ -70,6 +70,15 @@ export function storedParticipation(item) {
|
|
|
70
70
|
export function isApprovalStep(item) {
|
|
71
71
|
return !!item && !isReferenceStep(item);
|
|
72
72
|
}
|
|
73
|
+
export function approvalLineMark(line) {
|
|
74
|
+
if (!Array.isArray(line) || !line.length) {
|
|
75
|
+
return 'none';
|
|
76
|
+
}
|
|
77
|
+
const steps = line.filter(isApprovalStep).length;
|
|
78
|
+
if (!steps)
|
|
79
|
+
return 'reference-only';
|
|
80
|
+
return steps === 1 ? 'one' : 'many';
|
|
81
|
+
}
|
|
73
82
|
export class ApprovalLineItem {
|
|
74
83
|
}
|
|
75
84
|
export class ApprovalLine {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-line.js","sourceRoot":"","sources":["../../client/types/approval-line.ts"],"names":[],"mappings":"AAMA,MAAM,CAAN,IAAY,qBAGX;AAHD,WAAY,qBAAqB;IAC/B,8CAAqB,CAAA;IACrB,0CAAiB,CAAA;AACnB,CAAC,EAHW,qBAAqB,KAArB,qBAAqB,QAGhC;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC/B,wCAAwC;IACxC,8CAAqB,CAAA;IACrB,8CAA8C;IAC9C,gDAAuB,CAAA;AACzB,CAAC,EALW,qBAAqB,KAArB,qBAAqB,QAKhC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAAgE;IAC9F,MAAM,KAAK,GAAG,IAAI,EAAE,aAAa,CAAA;IAEjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,qBAAqB,CAAC,SAAS,CAAA;AAC7F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAEnC;IACC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;AAC5E,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,cAAc,CAAC,IAAgE;IAC7F,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,OAAO,gBAAgB;CAoB5B;AAED,MAAM,OAAO,YAAY;CAkCxB","sourcesContent":["import { Domain, User, Role } from '@operato/shell'\n\nimport { Employee } from './employee'\nimport { Department } from './department'\nimport { OrgMemberTarget, OrgMemberTargetType } from './org-member'\n\nexport enum ApprovalLineOwnerType {\n Employee = 'Employee',\n Common = 'Common'\n}\n\n/**\n * 결재선에 어떤 자격으로 서는가.\n *\n * 서버는 소문자를 쓴다(`approval-line-item.ts` 의 `ApprovalParticipation`).\n */\nexport enum ApprovalParticipation {\n /** 결정한다. 이 사람이 승인하거나 반려해야 다음으로 넘어간다. */\n Approval = 'approval',\n /** 알기만 한다. 의견은 낼 수 있고 안 내도 되며, 결재를 막지 않는다. */\n Reference = 'reference'\n}\n\n/**\n * Is this step a reference rather than an approval?\n *\n * Ask it here, never inline. \"This is an approval\" is written two ways on stored rows — `'approval'`\n * on recent ones and nothing at all on rows created before the column existed (5 of the 8 in 내\n * 결재함 today). Both are approvals, and asking in the negative is what makes them behave alike.\n *\n * The danger is the opposite question. `participation === 'approval'` looks equivalent and drops\n * every older row — no error, just a list that is quietly shorter. Four places in this package had\n * each written the check by hand, three of them against the raw string rather than the enum, so a\n * single one of them turning the question around would have gone unnoticed.\n *\n * The server settled this the same way and says why in\n * worklist/server/controllers/activity-approval/approval-line.ts: one place to decide, or the rule\n * grows a second copy that nobody updates.\n */\nexport function isReferenceStep(item?: { participation?: ApprovalParticipation | string | null }): boolean {\n const value = item?.participation\n\n /*\n * The same fact arrives spelled two ways, and neither side is wrong.\n *\n * The column holds `reference`, and everything server-side compares against that. GraphQL does\n * not: type-graphql's registerEnumType exposes an enum by its **key**, so the API answers\n * `Reference`. A screen reading `approvalLines { model { participation } }` therefore receives\n * `Reference` and was comparing it to `reference` — false every time.\n *\n * That is why 「표준 3단 결재」 showed its reference step as an approver: no 참조 marker on the\n * list, no quiet styling, and 알림 시점 left editable on a row that is not a reference at all.\n * Four hand-written copies of this check hid it; one place to ask makes it a one-line fix.\n *\n * Both spellings are accepted here, at the boundary, rather than by teaching every caller about\n * the API's casing.\n */\n return typeof value === 'string' && value.toLowerCase() === ApprovalParticipation.Reference\n}\n\n/**\n * The spelling this step should be stored and edited under.\n *\n * isReferenceStep answers the question; this answers with a value, for the places that cannot ask a\n * function. A `<select>` matches its options by string equality, so an option list of `''` and\n * `'reference'` silently selects neither when the API hands back `Reference` — the row then reads\n * as an approver, and the next edit to that row writes the approver spelling back. A reference step\n * turns into an approval with no error and nothing on screen to notice.\n *\n * Approval canonicalises to undefined rather than `'approval'`: rows created before the column\n * existed have nothing there, and empty has to keep meaning approval for those to behave. See\n * ApprovalLineItem.participation.\n */\nexport function storedParticipation(item?: {\n participation?: ApprovalParticipation | string | null\n}): ApprovalParticipation | undefined {\n return isReferenceStep(item) ? ApprovalParticipation.Reference : undefined\n}\n\n/** Is this step one that has to approve before the request moves on? See isReferenceStep. */\nexport function isApprovalStep(item?: { participation?: ApprovalParticipation | string | null }): boolean {\n return !!item && !isReferenceStep(item)\n}\n\nexport class ApprovalLineItem {\n type?: OrgMemberTargetType\n value?: string\n approver?: OrgMemberTarget\n\n /**\n * **비어 있으면 결재다.**\n *\n * 지금 도는 결재선에는 이 칸이 없다. 그 항목들이 전부 결재자로 읽혀야 거동이 안 바뀐다.\n */\n participation?: ApprovalParticipation\n\n /**\n * 참조에게 언제 알리나 — 몇 번째 결재가 끝났을 때. 비면 상신 즉시.\n *\n * 배열 자리로 시점을 표현하지 않는다. 참조 항목의 자리는 뜻이 없고 결재 차례를 소비하지 않는다.\n * 편집기가 항목을 목록 끝에 붙이므로, 자리로 하면 기본값이 「마지막 결재 뒤」가 되어 의견 낼 기회가\n * 아예 없는 쪽이 기본이 된다.\n */\n notifyAfter?: number\n}\n\nexport class ApprovalLine {\n readonly id?: string\n\n domain?: Domain\n\n domainId?: string\n\n name?: string\n\n description?: string\n\n model?: ApprovalLineItem[]\n\n ownerType?: ApprovalLineOwnerType\n\n ownerValue?: string\n\n ownerEmployee?: Employee\n\n ownerDepartment?: Department\n\n ownerRole?: Role\n\n createdAt?: Date\n\n updatedAt?: Date\n\n creator?: User\n\n creatorId?: string\n\n updater?: User\n\n updaterId?: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-line.js","sourceRoot":"","sources":["../../client/types/approval-line.ts"],"names":[],"mappings":"AAMA,MAAM,CAAN,IAAY,qBAGX;AAHD,WAAY,qBAAqB;IAC/B,8CAAqB,CAAA;IACrB,0CAAiB,CAAA;AACnB,CAAC,EAHW,qBAAqB,KAArB,qBAAqB,QAGhC;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC/B,wCAAwC;IACxC,8CAAqB,CAAA;IACrB,8CAA8C;IAC9C,gDAAuB,CAAA;AACzB,CAAC,EALW,qBAAqB,KAArB,qBAAqB,QAKhC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAAgE;IAC9F,MAAM,KAAK,GAAG,IAAI,EAAE,aAAa,CAAA;IAEjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,qBAAqB,CAAC,SAAS,CAAA;AAC7F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAEnC;IACC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;AAC5E,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,cAAc,CAAC,IAAgE;IAC7F,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AAuBD,MAAM,UAAU,gBAAgB,CAAC,IAAyE;IACxG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACzC,OAAO,MAAM,CAAA;IACf,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAA;IAEhD,IAAI,CAAC,KAAK;QAAE,OAAO,gBAAgB,CAAA;IACnC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAA;AACrC,CAAC;AAED,MAAM,OAAO,gBAAgB;CAoB5B;AAED,MAAM,OAAO,YAAY;CAkCxB","sourcesContent":["import { Domain, User, Role } from '@operato/shell'\n\nimport { Employee } from './employee'\nimport { Department } from './department'\nimport { OrgMemberTarget, OrgMemberTargetType } from './org-member'\n\nexport enum ApprovalLineOwnerType {\n Employee = 'Employee',\n Common = 'Common'\n}\n\n/**\n * 결재선에 어떤 자격으로 서는가.\n *\n * 서버는 소문자를 쓴다(`approval-line-item.ts` 의 `ApprovalParticipation`).\n */\nexport enum ApprovalParticipation {\n /** 결정한다. 이 사람이 승인하거나 반려해야 다음으로 넘어간다. */\n Approval = 'approval',\n /** 알기만 한다. 의견은 낼 수 있고 안 내도 되며, 결재를 막지 않는다. */\n Reference = 'reference'\n}\n\n/**\n * Is this step a reference rather than an approval?\n *\n * Ask it here, never inline. \"This is an approval\" is written two ways on stored rows — `'approval'`\n * on recent ones and nothing at all on rows created before the column existed (5 of the 8 in 내\n * 결재함 today). Both are approvals, and asking in the negative is what makes them behave alike.\n *\n * The danger is the opposite question. `participation === 'approval'` looks equivalent and drops\n * every older row — no error, just a list that is quietly shorter. Four places in this package had\n * each written the check by hand, three of them against the raw string rather than the enum, so a\n * single one of them turning the question around would have gone unnoticed.\n *\n * The server settled this the same way and says why in\n * worklist/server/controllers/activity-approval/approval-line.ts: one place to decide, or the rule\n * grows a second copy that nobody updates.\n */\nexport function isReferenceStep(item?: { participation?: ApprovalParticipation | string | null }): boolean {\n const value = item?.participation\n\n /*\n * The same fact arrives spelled two ways, and neither side is wrong.\n *\n * The column holds `reference`, and everything server-side compares against that. GraphQL does\n * not: type-graphql's registerEnumType exposes an enum by its **key**, so the API answers\n * `Reference`. A screen reading `approvalLines { model { participation } }` therefore receives\n * `Reference` and was comparing it to `reference` — false every time.\n *\n * That is why 「표준 3단 결재」 showed its reference step as an approver: no 참조 marker on the\n * list, no quiet styling, and 알림 시점 left editable on a row that is not a reference at all.\n * Four hand-written copies of this check hid it; one place to ask makes it a one-line fix.\n *\n * Both spellings are accepted here, at the boundary, rather than by teaching every caller about\n * the API's casing.\n */\n return typeof value === 'string' && value.toLowerCase() === ApprovalParticipation.Reference\n}\n\n/**\n * The spelling this step should be stored and edited under.\n *\n * isReferenceStep answers the question; this answers with a value, for the places that cannot ask a\n * function. A `<select>` matches its options by string equality, so an option list of `''` and\n * `'reference'` silently selects neither when the API hands back `Reference` — the row then reads\n * as an approver, and the next edit to that row writes the approver spelling back. A reference step\n * turns into an approval with no error and nothing on screen to notice.\n *\n * Approval canonicalises to undefined rather than `'approval'`: rows created before the column\n * existed have nothing there, and empty has to keep meaning approval for those to behave. See\n * ApprovalLineItem.participation.\n */\nexport function storedParticipation(item?: {\n participation?: ApprovalParticipation | string | null\n}): ApprovalParticipation | undefined {\n return isReferenceStep(item) ? ApprovalParticipation.Reference : undefined\n}\n\n/** Is this step one that has to approve before the request moves on? See isReferenceStep. */\nexport function isApprovalStep(item?: { participation?: ApprovalParticipation | string | null }): boolean {\n return !!item && !isReferenceStep(item)\n}\n\n/**\n * 결재선 한 줄을 화면이 어떻게 표시할지 — **셋이 같은 답을 쓰라고 한 자리에 둔다.**\n *\n * 「이 업무에 결재자가 있나」를 화면 셋이 각각 셌다. 업무정의 리스트의 사람 표는 결재선이 **비었는지**만\n * 보고 답해서, 참조만 있는 줄도 사람 아이콘을 그렸다. BatchRelease 가 그랬다 — 두 줄 다 「참조에만\n * 씁니다」인데 목록에는 결재자가 있는 것으로 보였다(2026-09-22, 수석 아키텍트가 화면에서 확인).\n *\n * 참조만 있는 결재선으로 규제를 걸면 **건은 올라가고 아무도 못 내린다.** 참조는 의견을 낼 뿐 판정하지\n * 않기 때문이다.\n *\n * ── 네 갈래로 가른다 ──────────────────────────────────────────────────────\n * 「참조만」을 「아예 없음」과 같이 그리면 고칠 사람이 무엇을 해야 하는지 모른다. 한쪽은 결재선을\n * 만들어야 하고, 다른 쪽은 이미 있는 줄에 결재자를 더해야 한다.\n *\n * none 줄이 없다\n * reference-only 줄은 있는데 결재 단계가 0 이다 — 아무도 못 내린다\n * one 결재자 한 단계\n * many 결재자 여러 단계\n */\nexport type ApprovalLineMark = 'none' | 'reference-only' | 'one' | 'many'\n\nexport function approvalLineMark(line?: { participation?: ApprovalParticipation | string | null }[] | null): ApprovalLineMark {\n if (!Array.isArray(line) || !line.length) {\n return 'none'\n }\n\n const steps = line.filter(isApprovalStep).length\n\n if (!steps) return 'reference-only'\n return steps === 1 ? 'one' : 'many'\n}\n\nexport class ApprovalLineItem {\n type?: OrgMemberTargetType\n value?: string\n approver?: OrgMemberTarget\n\n /**\n * **비어 있으면 결재다.**\n *\n * 지금 도는 결재선에는 이 칸이 없다. 그 항목들이 전부 결재자로 읽혀야 거동이 안 바뀐다.\n */\n participation?: ApprovalParticipation\n\n /**\n * 참조에게 언제 알리나 — 몇 번째 결재가 끝났을 때. 비면 상신 즉시.\n *\n * 배열 자리로 시점을 표현하지 않는다. 참조 항목의 자리는 뜻이 없고 결재 차례를 소비하지 않는다.\n * 편집기가 항목을 목록 끝에 붙이므로, 자리로 하면 기본값이 「마지막 결재 뒤」가 되어 의견 낼 기회가\n * 아예 없는 쪽이 기본이 된다.\n */\n notifyAfter?: number\n}\n\nexport class ApprovalLine {\n readonly id?: string\n\n domain?: Domain\n\n domainId?: string\n\n name?: string\n\n description?: string\n\n model?: ApprovalLineItem[]\n\n ownerType?: ApprovalLineOwnerType\n\n ownerValue?: string\n\n ownerEmployee?: Employee\n\n ownerDepartment?: Department\n\n ownerRole?: Role\n\n createdAt?: Date\n\n updatedAt?: Date\n\n creator?: User\n\n creatorId?: string\n\n updater?: User\n\n updaterId?: string\n}\n"]}
|