@things-factory/worklist 10.1.259 → 10.1.260
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/chip-counts.d.ts +13 -0
- package/dist-client/chip-counts.js +11 -0
- package/dist-client/chip-counts.js.map +1 -1
- package/dist-client/chip-filters.d.ts +29 -0
- package/dist-client/chip-filters.js +17 -1
- package/dist-client/chip-filters.js.map +1 -1
- package/dist-client/pages/approval-progress/approval-progress-page.d.ts +0 -4
- package/dist-client/pages/approval-progress/approval-progress-page.js +37 -31
- package/dist-client/pages/approval-progress/approval-progress-page.js.map +1 -1
- package/dist-client/pages/todo/approval-pending-list-page.d.ts +2 -3
- package/dist-client/pages/todo/approval-pending-list-page.js +33 -47
- package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
- package/dist-client/pages/todo/draft-list-page.js +13 -10
- package/dist-client/pages/todo/draft-list-page.js.map +1 -1
- package/dist-client/pages/todo/todo-list-page.d.ts +0 -3
- package/dist-client/pages/todo/todo-list-page.js +30 -42
- package/dist-client/pages/todo/todo-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/activity-installation/activity-installation-controller.js +1 -0
- package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
- package/dist-server/controllers/activity-installation/installable-to-activity.d.ts +10 -0
- package/dist-server/controllers/activity-installation/installable-to-activity.js +22 -1
- package/dist-server/controllers/activity-installation/installable-to-activity.js.map +1 -1
- package/dist-server/service/approval-progress/approval-progress-query.js +4 -0
- package/dist-server/service/approval-progress/approval-progress-query.js.map +1 -1
- package/dist-server/service/approval-progress/approval-progress-rule.d.ts +4 -0
- package/dist-server/service/approval-progress/approval-progress-rule.js +8 -0
- package/dist-server/service/approval-progress/approval-progress-rule.js.map +1 -1
- package/dist-server/service/approval-progress/approval-progress-type.d.ts +1 -0
- package/dist-server/service/approval-progress/approval-progress-type.js +4 -0
- package/dist-server/service/approval-progress/approval-progress-type.js.map +1 -1
- package/dist-server/service/index.d.ts +3 -3
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
- package/translations/en.json +3 -2
- package/translations/es.json +3 -2
- package/translations/ja.json +3 -2
- package/translations/ko.json +3 -2
- package/translations/ms.json +3 -2
- package/translations/zh.json +3 -2
|
@@ -43,6 +43,7 @@ async function installActivity(name, domain, options = {}) {
|
|
|
43
43
|
return await repository.save({
|
|
44
44
|
...(existing ?? {}),
|
|
45
45
|
...(0, installable_to_activity_js_1.activityRowFrom)(template),
|
|
46
|
+
...(0, installable_to_activity_js_1.activityDefaultsFrom)(template, existing),
|
|
46
47
|
state: activity_js_1.ActivityStatus.Released,
|
|
47
48
|
domain,
|
|
48
49
|
creator: existing ? existing.creator : user,
|
package/dist-server/controllers/activity-installation/activity-installation-controller.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-installation-controller.js","sourceRoot":"","sources":["../../../server/controllers/activity-installation/activity-installation-controller.ts"],"names":[],"mappings":";;;AA8BA,
|
|
1
|
+
{"version":3,"file":"activity-installation-controller.js","sourceRoot":"","sources":["../../../server/controllers/activity-installation/activity-installation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\n\nimport { Domain, getRepository } from '@things-factory/shell'\n\nimport { Activity, ActivityStatus } from '../../service/activity/activity.js'\nimport { InstallableActivity } from '../../service/installable-activity/installable-activity.js'\nimport { ActivityReadiness } from '../../service/installable-activity/activity-readiness.js'\nimport { assertDoorSlugIsFree, assertNotAlreadyInstalled, assertNotDeclaredIntended } from './registry-conflict.js'\nimport { doorSlug } from '../../service/activity/decision-key-declaration.js'\nimport { activityDefaultsFrom, activityRowFrom } from './installable-to-activity.js'\n\n/**\n * 등록된 양식을 **도메인에 실제로 세운다.**\n *\n * ── 왜 함수로 내놓나 ───────────────────────────────────────────────────────\n * 앞서는 이 일이 화면 뮤테이션 안에만 있었다. 그래서 양식을 세우는 길이 **사람이 화면에서 누르는 것\n * 하나뿐**이었고, 새로 배포하거나 도메인을 하나 더 만들 때마다 그 클릭을 기억해야 했다. 기억하지\n * 못하면 그 기능이 오류 보고 없이 없다.\n *\n * 앱이 「내 기능이 서려면 이 양식이 있어야 한다」를 아는 경우가 있다. 그런 앱은 기동할 때 스스로\n * 세울 수 있어야 한다. 언제 세울지는 앱이 정하고, 세우는 방법은 여기가 한 벌만 갖는다.\n *\n * ── 있는 것을 덮되 결재선은 건드리지 않는다 ────────────────────────────────\n * 이미 있으면 양식의 선언(모델 · 보는 화면 · 시작 방식)으로 덮는다. 버전이 오르면 그 값이 따라와야\n * 하기 때문이다.\n *\n * 그런데 **결재선은 양식의 것이 아니라 그 현장의 것**이다. 누가 결재하는지는 공장이 정한다. 그래서\n * 양식에 결재선 선언이 없으면 이미 있는 결재선이 그대로 남는다 — 버전을 올릴 때마다 결재자가 지워지면\n * 그 뒤로 상신이 곧 완료가 된다.\n */\nexport async function installActivity(\n name: string,\n domain: Domain,\n options: { manager?: EntityManager; user?: any } = {}\n): Promise<Activity> {\n const template = ActivityInstallations.get(name)\n\n if (!template) {\n /*\n * 없는 이름을 세울 수는 없다. 조용히 넘기면 부르는 쪽은 세운 줄 알고, 그 기능은 없는 채로 선다.\n */\n throw new Error(\n `installActivity: there is no installable activity named \"${name}\". ` +\n `known: ${ActivityInstallations.list()\n .map(one => one.name)\n .join(', ')}`\n )\n }\n\n const { manager, user } = options\n const repository = getRepository(Activity, manager)\n\n const existing = await repository.findOneBy({ domain: { id: domain.id }, name })\n\n return await repository.save({\n ...(existing ?? {}),\n ...activityRowFrom(template),\n ...activityDefaultsFrom(template, existing),\n state: ActivityStatus.Released,\n domain,\n creator: existing ? (existing as any).creator : user,\n updater: user\n } as Activity)\n}\n\n/**\n * Work a module has identified as a person's decision and **has not built.**\n *\n * Deliberately not an InstallableActivity. A template with no callback can be installed and\n * issued, and then someone approves a request and nothing happens — on the twin side that means a\n * person presses approve and no equipment moves. So these live in their own registry: the catalog\n * reads them, `installActivity` cannot reach them.\n *\n * They belong on the screen because the catalog is the plan of record. The question \"what is left\"\n * should be answered where people look, not in one person's head.\n */\nexport type IntendedActivity = {\n /** What the activity's `name` will be once it exists. */\n key: string\n /** What the catalog shows. The activity's own name is usually not a sentence a person reads. */\n label: string\n category?: string\n /** What this work is, for the person who will receive it. Draft wording is fine. */\n guide?: string[]\n readiness: ActivityReadiness\n}\n\nexport class ActivityInstallations {\n static templates: { [name: string]: InstallableActivity } = {}\n\n /** Keyed separately from `templates`, so nothing here can be installed by mistake. */\n static intended: { [key: string]: IntendedActivity } = {}\n\n static installActivityTemplate(template: InstallableActivity) {\n assertNotDeclaredIntended(template.name, ActivityInstallations.intended)\n assertDoorSlugIsFree(template.name, doorSlug, ActivityInstallations.templates)\n\n ActivityInstallations.templates[template.name] = template\n }\n\n /**\n * Declare work that should reach someone's worklist and does not yet.\n *\n * A module calls this for each item it has identified. When the real thing is built, delete the\n * call and register the template instead — the catalog row moves from 예정 to 동작 확인됨 on its\n * own.\n */\n static declareIntendedActivity(intended: IntendedActivity) {\n assertNotAlreadyInstalled(intended.key, ActivityInstallations.templates)\n\n ActivityInstallations.intended[intended.key] = intended\n }\n\n static get(name: string): InstallableActivity {\n return ActivityInstallations.templates[name]\n }\n\n static list(): InstallableActivity[] {\n return Object.values(ActivityInstallations.templates)\n }\n\n static listIntended(): IntendedActivity[] {\n return Object.values(ActivityInstallations.intended)\n }\n\n /**\n * 액티비티인스턴스의 변화가 발생했을 때, 호출되는 콜백함수\n * @param name 액티비티인스턴스가 속한 액티비티명\n * @param activityInstance 해당 액티비티인스턴스\n * @param activityThreads 액티비티인스턴스의 변화를 일으킨 원인이 되는 액티비티쓰레드들\n * @param context 서비스 컨텍스트 : domain, user, translation, ..\n * @returns\n */\n static async callback(name: string, activityInstance: any, activityThreads: any[], context: ResolverContext) {\n const installableActivity = ActivityInstallations.templates[name]\n if (!installableActivity) {\n return\n }\n\n const { callback } = installableActivity\n\n callback && (await callback(activityInstance, { causedBy: activityThreads }, context))\n }\n}\n"]}
|
|
@@ -39,6 +39,16 @@ type TemplateFields = {
|
|
|
39
39
|
[field: string]: unknown;
|
|
40
40
|
};
|
|
41
41
|
export declare const ACTIVITY_ROW_FIELDS: readonly ["name", "label", "description", "activityType", "priority", "startingType", "multiple", "model", "decisionKeys", "uiType", "uiSource", "viewType", "viewSource", "reportType", "reportSource", "thumbnail"];
|
|
42
|
+
/**
|
|
43
|
+
* The template fields that only seed a row: the template's value is the default, and once the row has one it is the
|
|
44
|
+
* domain's - the activity screen edits it, and installing again at every boot does not take it back.
|
|
45
|
+
*
|
|
46
|
+
* standardTime how long the work may take; an instance's due is its issue plus this (issue.ts). Never copied
|
|
47
|
+
* before, so every installed approval had no due (the user, 2026-11-08: 「각 결재에 기한이 없군」).
|
|
48
|
+
*/
|
|
49
|
+
export declare const ACTIVITY_DEFAULT_FIELDS: readonly ["standardTime"];
|
|
50
|
+
/** The defaults of a template the row does not have yet. */
|
|
51
|
+
export declare function activityDefaultsFrom(template: object | undefined, existing: object | null | undefined): TemplateFields;
|
|
42
52
|
/**
|
|
43
53
|
* The part of a template that is stored on the Activity row.
|
|
44
54
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ACTIVITY_ROW_FIELDS = void 0;
|
|
3
|
+
exports.ACTIVITY_DEFAULT_FIELDS = exports.ACTIVITY_ROW_FIELDS = void 0;
|
|
4
|
+
exports.activityDefaultsFrom = activityDefaultsFrom;
|
|
4
5
|
exports.activityRowFrom = activityRowFrom;
|
|
5
6
|
exports.ACTIVITY_ROW_FIELDS = [
|
|
6
7
|
'name',
|
|
@@ -20,6 +21,26 @@ exports.ACTIVITY_ROW_FIELDS = [
|
|
|
20
21
|
'reportSource',
|
|
21
22
|
'thumbnail'
|
|
22
23
|
];
|
|
24
|
+
/**
|
|
25
|
+
* The template fields that only seed a row: the template's value is the default, and once the row has one it is the
|
|
26
|
+
* domain's - the activity screen edits it, and installing again at every boot does not take it back.
|
|
27
|
+
*
|
|
28
|
+
* standardTime how long the work may take; an instance's due is its issue plus this (issue.ts). Never copied
|
|
29
|
+
* before, so every installed approval had no due (the user, 2026-11-08: 「각 결재에 기한이 없군」).
|
|
30
|
+
*/
|
|
31
|
+
exports.ACTIVITY_DEFAULT_FIELDS = ['standardTime'];
|
|
32
|
+
/** The defaults of a template the row does not have yet. */
|
|
33
|
+
function activityDefaultsFrom(template, existing) {
|
|
34
|
+
const fields = (template ?? {});
|
|
35
|
+
const row = (existing ?? {});
|
|
36
|
+
const defaults = {};
|
|
37
|
+
for (const field of exports.ACTIVITY_DEFAULT_FIELDS) {
|
|
38
|
+
if ((row[field] === undefined || row[field] === null) && fields[field] !== undefined) {
|
|
39
|
+
defaults[field] = fields[field];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return defaults;
|
|
43
|
+
}
|
|
23
44
|
/**
|
|
24
45
|
* The part of a template that is stored on the Activity row.
|
|
25
46
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installable-to-activity.js","sourceRoot":"","sources":["../../../server/controllers/activity-installation/installable-to-activity.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"installable-to-activity.js","sourceRoot":"","sources":["../../../server/controllers/activity-installation/installable-to-activity.ts"],"names":[],"mappings":";;;AAmEA,oDAYC;AAoCD,0CAaC;AA1FY,QAAA,mBAAmB,GAAG;IACjC,MAAM;IACN,OAAO;IACP,aAAa;IACb,cAAc;IACd,UAAU;IACV,cAAc;IACd,UAAU;IACV,OAAO;IACP,cAAc;IACd,QAAQ;IACR,UAAU;IACV,UAAU;IACV,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,WAAW;CACH,CAAA;AAEV;;;;;;GAMG;AACU,QAAA,uBAAuB,GAAG,CAAC,cAAc,CAAU,CAAA;AAEhE,4DAA4D;AAC5D,SAAgB,oBAAoB,CAAC,QAA4B,EAAE,QAAmC;IACpG,MAAM,MAAM,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAmB,CAAA;IACjD,MAAM,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAmB,CAAA;IAC9C,MAAM,QAAQ,GAAmB,EAAE,CAAA;IAEnC,KAAK,MAAM,KAAK,IAAI,+BAAuB,EAAE,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;YACrF,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAgB,eAAe,CAAC,QAA4B;IAC1D,MAAM,MAAM,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAmB,CAAA;IACjD,MAAM,GAAG,GAAmB,EAAE,CAAA;IAE9B,KAAK,MAAM,KAAK,IAAI,2BAAmB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAE3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAA;QACpB,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/**\n * The template fields that belong on the Activity row, named one by one.\n *\n * ── Why not spread the template ───────────────────────────────────────────\n * installActivity used `{ ...(template as any) }`. A template field with no column on Activity was\n * dropped by the save, which reported success — and `as any` meant the types said nothing about it.\n * Nine fields were being handed over with no home: activity, approvalSteps, callback, category,\n * guide, label, provider, readiness, release.\n *\n * `label` was the one that hurt. It is the display name a person reads, and it reached exactly one\n * screen — the catalog, which reads the template registry directly — while every screen reading the\n * row showed the instance name instead. decisionKeys only worked because a column happened to be\n * added for it in the same change; the next field would have been left to the same luck.\n *\n * Naming the fields buys three things: a new template field has to be wired here on purpose, the\n * eight that stay behind are recorded as catalog-only rather than lost, and the two `as any` casts\n * go away. (2026-09-10, architect's ruling)\n *\n * ── What stays in the template registry, and why ──────────────────────────\n * activity the installed row itself, attached by the catalog query. Writing it back would\n * be a row pointing at itself\n * approvalSteps counted per domain by the catalog query from the line that is actually set up\n * callback a function\n * category how the catalog groups it\n * guide what the work is, for the catalog's reader\n * provider which module registered it\n * readiness how far along the registering module says it is\n * release which version registered it\n *\n * Each of those is answered by the registry, which is loaded in every process that serves the\n * catalog. Copying them to the row would make a second copy that goes stale on the next release.\n *\n * ── The template shape is spelled out, not imported ───────────────────────\n * InstallableActivity carries type-graphql decorators, and the test runner strips types without\n * reading them, so importing it takes the whole test file down. That happened three times in one\n * day — to search-key-declaration, to decision-key-declaration, and here.\n */\ntype TemplateFields = { [field: string]: unknown }\nexport const ACTIVITY_ROW_FIELDS = [\n 'name',\n 'label',\n 'description',\n 'activityType',\n 'priority',\n 'startingType',\n 'multiple',\n 'model',\n 'decisionKeys',\n 'uiType',\n 'uiSource',\n 'viewType',\n 'viewSource',\n 'reportType',\n 'reportSource',\n 'thumbnail'\n] as const\n\n/**\n * The template fields that only seed a row: the template's value is the default, and once the row has one it is the\n * domain's - the activity screen edits it, and installing again at every boot does not take it back.\n *\n * standardTime how long the work may take; an instance's due is its issue plus this (issue.ts). Never copied\n * before, so every installed approval had no due (the user, 2026-11-08: 「각 결재에 기한이 없군」).\n */\nexport const ACTIVITY_DEFAULT_FIELDS = ['standardTime'] as const\n\n/** The defaults of a template the row does not have yet. */\nexport function activityDefaultsFrom(template: object | undefined, existing: object | null | undefined): TemplateFields {\n const fields = (template ?? {}) as TemplateFields\n const row = (existing ?? {}) as TemplateFields\n const defaults: TemplateFields = {}\n\n for (const field of ACTIVITY_DEFAULT_FIELDS) {\n if ((row[field] === undefined || row[field] === null) && fields[field] !== undefined) {\n defaults[field] = fields[field]\n }\n }\n\n return defaults\n}\n\n/**\n * The part of a template that is stored on the Activity row.\n *\n * A field the template left undefined is not copied, so installing again does not blank a value\n * somebody edited on the row — `save` with an explicit undefined writes null. That protection is\n * real: the activity list screen lets a domain edit viewType and viewSource on the row, and\n * installActivity runs at every boot. A field the template set to null is copied, because null is\n * how a template says the value is gone.\n *\n * ── So leaving a field out is not the same as clearing it ─────────────────\n * A template that stops providing something has to say so, because silence means \"keep whatever the\n * row has\":\n *\n * viewSource: undefined the template says nothing — the row keeps its value\n * viewSource: null the template says there is none — the row is cleared\n *\n * plant hit this: they removed two viewSource declarations, the rows kept pointing at elements that\n * no longer existed, and approvers met a screen that could not load. (2026-09-11)\n *\n * ── Why null and not an empty string ──────────────────────────────────────\n * The rule was first written as `viewSource: ''`, and for a string field that does clear it. But\n * five of the sixteen fields carried here are not strings — priority is a number, multiple and\n * activityType and startingType are enums, model and decisionKeys are json — and none of them has\n * an empty string. `priority: ''` puts a non-number in an integer column; `decisionKeys: ''` puts a\n * string where the screen expects an array and every declared slot disappears with no error. A rule\n * that only holds for two thirds of the list is the kind that gets applied to the other third.\n *\n * null is the one signal that reads the same on all sixteen, and it says \"there is none\" rather\n * than naming a value that happens to be falsy. It needs nothing here: the copy below asks only\n * whether the template said anything, so null crosses over and the save writes NULL.\n *\n * An empty string still clears a string field — it is a value, and it lands in the column. It is\n * simply not the rule. (2026-09-16, answering the architect)\n */\nexport function activityRowFrom(template: object | undefined): TemplateFields {\n const fields = (template ?? {}) as TemplateFields\n const row: TemplateFields = {}\n\n for (const field of ACTIVITY_ROW_FIELDS) {\n const value = fields[field]\n\n if (value !== undefined) {\n row[field] = value\n }\n }\n\n return row\n}\n"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ApprovalProgressQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
5
6
|
const type_graphql_1 = require("type-graphql");
|
|
6
7
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
8
|
const organization_1 = require("@things-factory/organization");
|
|
@@ -88,6 +89,8 @@ let ApprovalProgressQuery = class ApprovalProgressQuery {
|
|
|
88
89
|
const instance = line.approvals[0].activityThread.activityInstance;
|
|
89
90
|
const { names, roleName } = await (0, waiting_on_js_1.namesWaitedOn)((0, shell_1.getRepository)(activity_approval_js_1.ActivityApproval).manager, line.progress.waiting);
|
|
90
91
|
const employee = employeeOf.get(requesterOf(line.approvals));
|
|
92
|
+
const deciderIds = [...new Set(line.progress.decided.map(row => row.terminatorId || row.approverId).filter(Boolean))];
|
|
93
|
+
const deciders = deciderIds.length ? await (0, shell_1.getRepository)(auth_base_1.User).find({ where: { id: (0, typeorm_1.In)(deciderIds) } }) : [];
|
|
91
94
|
items.push({
|
|
92
95
|
id: line.id,
|
|
93
96
|
activityName: line.activityName,
|
|
@@ -100,6 +103,7 @@ let ApprovalProgressQuery = class ApprovalProgressQuery {
|
|
|
100
103
|
step: line.progress.step,
|
|
101
104
|
steps: line.progress.steps,
|
|
102
105
|
waitingOn: names,
|
|
106
|
+
decidedBy: deciders.map(one => one.name),
|
|
103
107
|
waitingRole: roleName,
|
|
104
108
|
waitingSince: line.progress.waitingSince,
|
|
105
109
|
dueAt: instance.dueAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-progress-query.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Query, Resolver } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Employee } from '@things-factory/organization'\nimport { getRepository, Pagination } from '@things-factory/shell'\n\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { activityTKey } from '../activity/decision-key-declaration.js'\nimport {\n APPROVAL_PROGRESS_STATES,\n countsOf,\n inProgressOrder,\n passes,\n progressOf,\n ProgressLine\n} from './approval-progress-rule.js'\nimport { ApprovalProgress, ApprovalProgressFilter, ApprovalProgressList } from './approval-progress-type.js'\nimport { namesWaitedOn } from './waiting-on.js'\n\n/**\n * 결재 현황 — the domain's every approval case and where it stands, whatever its kind (ADR-0183).\n *\n * Read by whoever reads every case (`activity-instance` query, the rule `assert-may-read.ts` names): a line shows\n * the headline and the requester of a case the reader may already open.\n *\n * A case is one activity instance with a deciding approval row. Its state, step and waiting are read from the rows\n * by `progressOf`; the filter and the counts run on those lines, so a count says what the list would show.\n */\n@Resolver()\nexport class ApprovalProgressQuery {\n @Directive('@privilege(category: \"activity-instance\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ApprovalProgressList, { description: 'The approvals of this domain, every kind, and where each stands.' })\n async approvalProgress(\n @Arg('filter', type => ApprovalProgressFilter, { nullable: true }) filter: ApprovalProgressFilter,\n @Arg('pagination', type => Pagination, { nullable: true }) pagination: Pagination,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalProgressList> {\n const { domain } = context.state\n filter = filter || {}\n\n const rows = await getRepository(ActivityApproval)\n .createQueryBuilder('ap')\n .innerJoinAndSelect('ap.activityThread', 'at')\n .innerJoinAndSelect('at.activityInstance', 'ai')\n .leftJoinAndSelect('ai.activity', 'act')\n .where('ap.domain = :domainId', { domainId: domain.id })\n .getMany()\n\n const cases = new Map<string, ActivityApproval[]>()\n for (const row of rows) {\n const id = row.activityThread.activityInstance.id\n cases.set(id, [...(cases.get(id) || []), row])\n }\n\n const requesterOf = (approvals: ActivityApproval[]) => {\n const thread = approvals[0].activityThread\n return thread.assigneeId || thread.activityInstance.creatorId\n }\n\n const requesterIds = [...new Set([...cases.values()].map(requesterOf).filter(Boolean))]\n const employees = requesterIds.length\n ? await getRepository(Employee)\n .createQueryBuilder('e')\n .leftJoinAndSelect('e.user', 'u')\n .leftJoinAndSelect('e.department', 'd')\n .where('e.domain = :domainId', { domainId: domain.id })\n .andWhere('u.id IN (:...requesterIds)', { requesterIds })\n .getMany()\n : []\n const employeeOf = new Map(employees.map(one => [one.user?.id, one]))\n const users = requesterIds.length\n ? await getRepository(User).createQueryBuilder('u').where('u.id IN (:...requesterIds)', { requesterIds }).getMany()\n : []\n const userName = new Map(users.map(one => [one.id, one.name]))\n\n const lines: (ProgressLine & { id: string; approvals: ActivityApproval[] })[] = []\n for (const [id, approvals] of cases) {\n /* A case seated only for references is not an approval. */\n if (!approvals.some(row => row.participation !== 'reference')) continue\n\n const instance = approvals[0].activityThread.activityInstance\n const requesterId = requesterOf(approvals)\n const employee = employeeOf.get(requesterId)\n\n lines.push({\n id,\n approvals,\n activityName: instance.activity?.name ?? '',\n headline: instance.name ?? '',\n requesterName: employee?.name || userName.get(requesterId),\n departmentId: employee?.department?.id,\n progress: progressOf({\n instanceState: instance.state,\n dueAt: instance.dueAt,\n approvalLine: instance.approvalLine as any,\n approvals\n })\n })\n }\n\n const passing = lines.filter(line => passes(line, filter)).sort(inProgressOrder)\n const { states, overdue } = countsOf(lines, filter)\n\n const limit = pagination?.limit || 50\n const page = pagination?.page || 1\n const pageLines = passing.slice((page - 1) * limit, page * limit)\n\n const items: ApprovalProgress[] = []\n for (const line of pageLines) {\n const instance = line.approvals[0].activityThread.activityInstance\n const { names, roleName } = await namesWaitedOn(getRepository(ActivityApproval).manager, line.progress.waiting)\n const employee = employeeOf.get(requesterOf(line.approvals))\n\n items.push({\n id: line.id,\n activityName: line.activityName,\n activityLabel: instance.activity?.label || line.activityName,\n activityLabelTKey: line.activityName ? activityTKey(line.activityName, 'label') : undefined,\n headline: line.headline,\n requesterName: line.requesterName,\n departmentName: employee?.department?.name,\n state: line.progress.state,\n step: line.progress.step,\n steps: line.progress.steps,\n waitingOn: names,\n waitingRole: roleName,\n waitingSince: line.progress.waitingSince,\n dueAt: instance.dueAt,\n overdue: line.progress.overdue,\n raisedAt: line.progress.raisedAt,\n endedAt: line.progress.endedAt\n })\n }\n\n /* The kinds that have a case here - what the kind filter offers. */\n const kinds = new Map<string, { name: string; label: string; labelTKey: string }>()\n for (const line of lines) {\n const activity = line.approvals[0].activityThread.activityInstance.activity\n if (line.activityName && !kinds.has(line.activityName))\n kinds.set(line.activityName, { name: line.activityName, label: activity?.label || line.activityName, labelTKey: activityTKey(line.activityName, 'label') })\n }\n\n return {\n items,\n kinds: [...kinds.values()].sort((a, b) => a.label.localeCompare(b.label)),\n total: passing.length,\n counts: APPROVAL_PROGRESS_STATES.map(state => ({ state, count: states[state] })),\n overdue\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-progress-query.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Arg, Ctx, Directive, Query, Resolver } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Employee } from '@things-factory/organization'\nimport { getRepository, Pagination } from '@things-factory/shell'\n\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { activityTKey } from '../activity/decision-key-declaration.js'\nimport {\n APPROVAL_PROGRESS_STATES,\n countsOf,\n inProgressOrder,\n passes,\n progressOf,\n ProgressLine\n} from './approval-progress-rule.js'\nimport { ApprovalProgress, ApprovalProgressFilter, ApprovalProgressList } from './approval-progress-type.js'\nimport { namesWaitedOn } from './waiting-on.js'\n\n/**\n * 결재 현황 — the domain's every approval case and where it stands, whatever its kind (ADR-0183).\n *\n * Read by whoever reads every case (`activity-instance` query, the rule `assert-may-read.ts` names): a line shows\n * the headline and the requester of a case the reader may already open.\n *\n * A case is one activity instance with a deciding approval row. Its state, step and waiting are read from the rows\n * by `progressOf`; the filter and the counts run on those lines, so a count says what the list would show.\n */\n@Resolver()\nexport class ApprovalProgressQuery {\n @Directive('@privilege(category: \"activity-instance\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ApprovalProgressList, { description: 'The approvals of this domain, every kind, and where each stands.' })\n async approvalProgress(\n @Arg('filter', type => ApprovalProgressFilter, { nullable: true }) filter: ApprovalProgressFilter,\n @Arg('pagination', type => Pagination, { nullable: true }) pagination: Pagination,\n @Ctx() context: ResolverContext\n ): Promise<ApprovalProgressList> {\n const { domain } = context.state\n filter = filter || {}\n\n const rows = await getRepository(ActivityApproval)\n .createQueryBuilder('ap')\n .innerJoinAndSelect('ap.activityThread', 'at')\n .innerJoinAndSelect('at.activityInstance', 'ai')\n .leftJoinAndSelect('ai.activity', 'act')\n .where('ap.domain = :domainId', { domainId: domain.id })\n .getMany()\n\n const cases = new Map<string, ActivityApproval[]>()\n for (const row of rows) {\n const id = row.activityThread.activityInstance.id\n cases.set(id, [...(cases.get(id) || []), row])\n }\n\n const requesterOf = (approvals: ActivityApproval[]) => {\n const thread = approvals[0].activityThread\n return thread.assigneeId || thread.activityInstance.creatorId\n }\n\n const requesterIds = [...new Set([...cases.values()].map(requesterOf).filter(Boolean))]\n const employees = requesterIds.length\n ? await getRepository(Employee)\n .createQueryBuilder('e')\n .leftJoinAndSelect('e.user', 'u')\n .leftJoinAndSelect('e.department', 'd')\n .where('e.domain = :domainId', { domainId: domain.id })\n .andWhere('u.id IN (:...requesterIds)', { requesterIds })\n .getMany()\n : []\n const employeeOf = new Map(employees.map(one => [one.user?.id, one]))\n const users = requesterIds.length\n ? await getRepository(User).createQueryBuilder('u').where('u.id IN (:...requesterIds)', { requesterIds }).getMany()\n : []\n const userName = new Map(users.map(one => [one.id, one.name]))\n\n const lines: (ProgressLine & { id: string; approvals: ActivityApproval[] })[] = []\n for (const [id, approvals] of cases) {\n /* A case seated only for references is not an approval. */\n if (!approvals.some(row => row.participation !== 'reference')) continue\n\n const instance = approvals[0].activityThread.activityInstance\n const requesterId = requesterOf(approvals)\n const employee = employeeOf.get(requesterId)\n\n lines.push({\n id,\n approvals,\n activityName: instance.activity?.name ?? '',\n headline: instance.name ?? '',\n requesterName: employee?.name || userName.get(requesterId),\n departmentId: employee?.department?.id,\n progress: progressOf({\n instanceState: instance.state,\n dueAt: instance.dueAt,\n approvalLine: instance.approvalLine as any,\n approvals\n })\n })\n }\n\n const passing = lines.filter(line => passes(line, filter)).sort(inProgressOrder)\n const { states, overdue } = countsOf(lines, filter)\n\n const limit = pagination?.limit || 50\n const page = pagination?.page || 1\n const pageLines = passing.slice((page - 1) * limit, page * limit)\n\n const items: ApprovalProgress[] = []\n for (const line of pageLines) {\n const instance = line.approvals[0].activityThread.activityInstance\n const { names, roleName } = await namesWaitedOn(getRepository(ActivityApproval).manager, line.progress.waiting)\n const employee = employeeOf.get(requesterOf(line.approvals))\n const deciderIds = [...new Set(line.progress.decided.map(row => row.terminatorId || row.approverId).filter(Boolean))] as string[]\n const deciders = deciderIds.length ? await getRepository(User).find({ where: { id: In(deciderIds) } }) : []\n\n items.push({\n id: line.id,\n activityName: line.activityName,\n activityLabel: instance.activity?.label || line.activityName,\n activityLabelTKey: line.activityName ? activityTKey(line.activityName, 'label') : undefined,\n headline: line.headline,\n requesterName: line.requesterName,\n departmentName: employee?.department?.name,\n state: line.progress.state,\n step: line.progress.step,\n steps: line.progress.steps,\n waitingOn: names,\n decidedBy: deciders.map(one => one.name),\n waitingRole: roleName,\n waitingSince: line.progress.waitingSince,\n dueAt: instance.dueAt,\n overdue: line.progress.overdue,\n raisedAt: line.progress.raisedAt,\n endedAt: line.progress.endedAt\n })\n }\n\n /* The kinds that have a case here - what the kind filter offers. */\n const kinds = new Map<string, { name: string; label: string; labelTKey: string }>()\n for (const line of lines) {\n const activity = line.approvals[0].activityThread.activityInstance.activity\n if (line.activityName && !kinds.has(line.activityName))\n kinds.set(line.activityName, { name: line.activityName, label: activity?.label || line.activityName, labelTKey: activityTKey(line.activityName, 'label') })\n }\n\n return {\n items,\n kinds: [...kinds.values()].sort((a, b) => a.label.localeCompare(b.label)),\n total: passing.length,\n counts: APPROVAL_PROGRESS_STATES.map(state => ({ state, count: states[state] })),\n overdue\n }\n }\n}\n"]}
|
|
@@ -9,6 +9,8 @@ export interface ProgressApprovalRow {
|
|
|
9
9
|
terminatedAt?: Date | null;
|
|
10
10
|
approverId?: string | null;
|
|
11
11
|
approverRoleId?: string | null;
|
|
12
|
+
/** Who judged the row - the person, also when the seat was a role's. */
|
|
13
|
+
terminatorId?: string | null;
|
|
12
14
|
}
|
|
13
15
|
export interface ProgressFacts {
|
|
14
16
|
instanceState?: string | null;
|
|
@@ -26,6 +28,8 @@ export interface Progress {
|
|
|
26
28
|
steps: number;
|
|
27
29
|
/** The rows of the step waited on now — whom it waits on. */
|
|
28
30
|
waiting: ProgressApprovalRow[];
|
|
31
|
+
/** The rows that decided it - the last approval of an approved case, the rejection of a rejected one. */
|
|
32
|
+
decided: ProgressApprovalRow[];
|
|
29
33
|
/** Since when the step waited on now has waited — its row is made when the step before it is approved. */
|
|
30
34
|
waitingSince?: Date;
|
|
31
35
|
/** When it was first put up for approval. */
|
|
@@ -45,11 +45,19 @@ function progressOf(facts, now = new Date()) {
|
|
|
45
45
|
const step = state === 'PENDING' ? (0, approval_step_js_1.currentStepOf)(approvals) : undefined;
|
|
46
46
|
const waiting = state === 'PENDING' ? (0, approval_step_js_1.currentStepRows)(approvals) : [];
|
|
47
47
|
const dueAt = timeOf(facts.dueAt);
|
|
48
|
+
const approved = thisRound.filter(row => row.judgment === 'approved');
|
|
49
|
+
const lastOrder = Math.max(0, ...approved.map(row => Number(row.order) || 0));
|
|
50
|
+
const decided = state === 'APPROVED'
|
|
51
|
+
? approved.filter(row => (Number(row.order) || 0) === lastOrder)
|
|
52
|
+
: state === 'REJECTED'
|
|
53
|
+
? thisRound.filter(row => row.judgment === 'rejected')
|
|
54
|
+
: [];
|
|
48
55
|
return {
|
|
49
56
|
state,
|
|
50
57
|
step: step ? (orders.indexOf(step.order) + 1 || step.order) : undefined,
|
|
51
58
|
steps: orders.length,
|
|
52
59
|
waiting,
|
|
60
|
+
decided,
|
|
53
61
|
waitingSince: earliest(waiting.map(row => row.createdAt)),
|
|
54
62
|
raisedAt: earliest(approvals.filter(deciding).map(row => row.createdAt)),
|
|
55
63
|
endedAt: state === 'PENDING' ? undefined : latest(thisRound.map(row => row.terminatedAt)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-progress-rule.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-rule.ts"],"names":[],"mappings":"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","sourcesContent":["import { currentStepOf, currentStepRows, latestRound } from '../../../shared/approval-step.js'\n\n/*\n * 결재 현황의 규칙 — 결재 한 건의 줄 하나를 결재 행에서 읽는다(ADR-0183 결정 1). DB 도 화면도 가져오지 않는다:\n * 질의가 행을 모아 넘기고, 시험이 같은 함수를 부른다.\n */\n\nexport type ApprovalProgressState = 'PENDING' | 'APPROVED' | 'REJECTED' | 'ABORTED'\n\nexport const APPROVAL_PROGRESS_STATES: readonly ApprovalProgressState[] = ['PENDING', 'APPROVED', 'REJECTED', 'ABORTED']\n\nexport interface ProgressApprovalRow {\n round?: number | null\n order?: number | null\n judgment?: string | null\n participation?: string | null\n createdAt?: Date | null\n terminatedAt?: Date | null\n approverId?: string | null\n approverRoleId?: string | null\n}\n\nexport interface ProgressFacts {\n instanceState?: string | null\n dueAt?: Date | null\n approvalLine?: { participation?: string }[] | null\n approvals: ProgressApprovalRow[]\n}\n\nexport interface Progress {\n state: ApprovalProgressState\n /** The step waited on now, counted among the deciding steps (references skipped) — 1 for the first approver. */\n step?: number\n /** How many deciding steps the line has. */\n steps: number\n /** The rows of the step waited on now — whom it waits on. */\n waiting: ProgressApprovalRow[]\n /** Since when the step waited on now has waited — its row is made when the step before it is approved. */\n waitingSince?: Date\n /** When it was first put up for approval. */\n raisedAt?: Date\n /** When it ended, for what is no longer waiting. */\n endedAt?: Date\n overdue: boolean\n}\n\nconst deciding = (row: ProgressApprovalRow) => row.participation !== 'reference'\nconst timeOf = (value?: Date | null) => (value ? new Date(value).getTime() : undefined)\nconst earliest = (values: (Date | null | undefined)[]) => {\n const times = values.map(timeOf).filter((one): one is number => one !== undefined)\n return times.length ? new Date(Math.min(...times)) : undefined\n}\nconst latest = (values: (Date | null | undefined)[]) => {\n const times = values.map(timeOf).filter((one): one is number => one !== undefined)\n return times.length ? new Date(Math.max(...times)) : undefined\n}\n\n/** The orders of the deciding steps of the line — a reference takes a place in the line and is not a step. */\nfunction decidingOrders(facts: ProgressFacts): number[] {\n const line = facts.approvalLine || []\n if (line.length) {\n return line.map((item, index) => (item?.participation === 'reference' ? 0 : index + 1)).filter(Boolean)\n }\n\n /* A case with no line kept on it: the orders its deciding rows carry. */\n return [...new Set(facts.approvals.filter(deciding).map(row => Number(row.order) || 0))].sort((a, b) => a - b)\n}\n\nexport function progressOf(facts: ProgressFacts, now: Date = new Date()): Progress {\n const approvals = facts.approvals || []\n const round = latestRound(approvals)\n const thisRound = approvals.filter(row => (Number(row.round) || 0) === round && deciding(row))\n const orders = decidingOrders(facts)\n\n /*\n * 반려가 중단보다 먼저다. Office 의 문은 반려되면 업무를 닫는다(`rejectionIsFinal`) — 그 건은 aborted 이고\n * 그 차수에 rejected 가 남는다. 중단을 먼저 읽으면 반려된 결재가 「중단」으로 보인다.\n */\n const state: ApprovalProgressState = thisRound.some(row => row.judgment === 'rejected')\n ? 'REJECTED'\n : facts.instanceState === 'aborted'\n ? 'ABORTED'\n : currentStepOf(approvals)\n ? 'PENDING'\n : 'APPROVED'\n\n const step = state === 'PENDING' ? currentStepOf(approvals) : undefined\n const waiting = state === 'PENDING' ? currentStepRows(approvals) : []\n const dueAt = timeOf(facts.dueAt)\n\n return {\n state,\n step: step ? (orders.indexOf(step.order) + 1 || step.order) : undefined,\n steps: orders.length,\n waiting,\n waitingSince: earliest(waiting.map(row => row.createdAt)),\n raisedAt: earliest(approvals.filter(deciding).map(row => row.createdAt)),\n endedAt: state === 'PENDING' ? undefined : latest(thisRound.map(row => row.terminatedAt)),\n overdue: state === 'PENDING' && dueAt !== undefined && dueAt < now.getTime()\n }\n}\n\nexport interface ProgressFilter {\n activityNames?: string[] | null\n states?: string[] | null\n departmentIds?: string[] | null\n /** The first day raised, inclusive. */\n from?: Date | null\n /** The last moment raised, exclusive. */\n to?: Date | null\n overdueOnly?: boolean | null\n search?: string | null\n}\n\nexport interface ProgressLine {\n activityName: string\n headline: string\n requesterName?: string\n departmentId?: string\n progress: Progress\n}\n\n/** Whether a line passes the filter. `ignore` leaves out the conditions a count is taken across. */\nexport function passes(line: ProgressLine, filter: ProgressFilter, ignore: { state?: boolean; overdue?: boolean } = {}): boolean {\n const { progress } = line\n if (filter.activityNames?.length && !filter.activityNames.includes(line.activityName)) return false\n if (!ignore.state && filter.states?.length && !filter.states.includes(progress.state)) return false\n if (filter.departmentIds?.length && !filter.departmentIds.includes(line.departmentId ?? '')) return false\n const raised = timeOf(progress.raisedAt)\n if (filter.from && (raised === undefined || raised < new Date(filter.from).getTime())) return false\n if (filter.to && (raised === undefined || raised >= new Date(filter.to).getTime())) return false\n if (!ignore.overdue && filter.overdueOnly && !progress.overdue) return false\n const search = filter.search?.trim().toLowerCase()\n if (search && ![line.headline, line.requesterName ?? ''].some(text => text.toLowerCase().includes(search))) return false\n return true\n}\n\n/** What waits stands first, the longest waiting at the top; what ended follows, the latest first. */\nexport function inProgressOrder(a: ProgressLine, b: ProgressLine): number {\n const pendingA = a.progress.state === 'PENDING'\n const pendingB = b.progress.state === 'PENDING'\n if (pendingA !== pendingB) return pendingA ? -1 : 1\n if (pendingA) return (timeOf(a.progress.waitingSince) ?? 0) - (timeOf(b.progress.waitingSince) ?? 0)\n return (timeOf(b.progress.endedAt ?? b.progress.raisedAt) ?? 0) - (timeOf(a.progress.endedAt ?? a.progress.raisedAt) ?? 0)\n}\n\n/** How many lines stand in each state, and how many are overdue — under the filter's other conditions. */\nexport function countsOf(lines: ProgressLine[], filter: ProgressFilter): { states: Record<ApprovalProgressState, number>; overdue: number } {\n const states = Object.fromEntries(APPROVAL_PROGRESS_STATES.map(state => [state, 0])) as Record<ApprovalProgressState, number>\n let overdue = 0\n for (const line of lines) {\n if (passes(line, filter, { state: true, overdue: true })) states[line.progress.state]++\n if (passes(line, filter, { overdue: true }) && line.progress.overdue) overdue++\n }\n return { states, overdue }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-progress-rule.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-rule.ts"],"names":[],"mappings":"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","sourcesContent":["import { currentStepOf, currentStepRows, latestRound } from '../../../shared/approval-step.js'\n\n/*\n * 결재 현황의 규칙 — 결재 한 건의 줄 하나를 결재 행에서 읽는다(ADR-0183 결정 1). DB 도 화면도 가져오지 않는다:\n * 질의가 행을 모아 넘기고, 시험이 같은 함수를 부른다.\n */\n\nexport type ApprovalProgressState = 'PENDING' | 'APPROVED' | 'REJECTED' | 'ABORTED'\n\nexport const APPROVAL_PROGRESS_STATES: readonly ApprovalProgressState[] = ['PENDING', 'APPROVED', 'REJECTED', 'ABORTED']\n\nexport interface ProgressApprovalRow {\n round?: number | null\n order?: number | null\n judgment?: string | null\n participation?: string | null\n createdAt?: Date | null\n terminatedAt?: Date | null\n approverId?: string | null\n approverRoleId?: string | null\n /** Who judged the row - the person, also when the seat was a role's. */\n terminatorId?: string | null\n}\n\nexport interface ProgressFacts {\n instanceState?: string | null\n dueAt?: Date | null\n approvalLine?: { participation?: string }[] | null\n approvals: ProgressApprovalRow[]\n}\n\nexport interface Progress {\n state: ApprovalProgressState\n /** The step waited on now, counted among the deciding steps (references skipped) — 1 for the first approver. */\n step?: number\n /** How many deciding steps the line has. */\n steps: number\n /** The rows of the step waited on now — whom it waits on. */\n waiting: ProgressApprovalRow[]\n /** The rows that decided it - the last approval of an approved case, the rejection of a rejected one. */\n decided: ProgressApprovalRow[]\n /** Since when the step waited on now has waited — its row is made when the step before it is approved. */\n waitingSince?: Date\n /** When it was first put up for approval. */\n raisedAt?: Date\n /** When it ended, for what is no longer waiting. */\n endedAt?: Date\n overdue: boolean\n}\n\nconst deciding = (row: ProgressApprovalRow) => row.participation !== 'reference'\nconst timeOf = (value?: Date | null) => (value ? new Date(value).getTime() : undefined)\nconst earliest = (values: (Date | null | undefined)[]) => {\n const times = values.map(timeOf).filter((one): one is number => one !== undefined)\n return times.length ? new Date(Math.min(...times)) : undefined\n}\nconst latest = (values: (Date | null | undefined)[]) => {\n const times = values.map(timeOf).filter((one): one is number => one !== undefined)\n return times.length ? new Date(Math.max(...times)) : undefined\n}\n\n/** The orders of the deciding steps of the line — a reference takes a place in the line and is not a step. */\nfunction decidingOrders(facts: ProgressFacts): number[] {\n const line = facts.approvalLine || []\n if (line.length) {\n return line.map((item, index) => (item?.participation === 'reference' ? 0 : index + 1)).filter(Boolean)\n }\n\n /* A case with no line kept on it: the orders its deciding rows carry. */\n return [...new Set(facts.approvals.filter(deciding).map(row => Number(row.order) || 0))].sort((a, b) => a - b)\n}\n\nexport function progressOf(facts: ProgressFacts, now: Date = new Date()): Progress {\n const approvals = facts.approvals || []\n const round = latestRound(approvals)\n const thisRound = approvals.filter(row => (Number(row.round) || 0) === round && deciding(row))\n const orders = decidingOrders(facts)\n\n /*\n * 반려가 중단보다 먼저다. Office 의 문은 반려되면 업무를 닫는다(`rejectionIsFinal`) — 그 건은 aborted 이고\n * 그 차수에 rejected 가 남는다. 중단을 먼저 읽으면 반려된 결재가 「중단」으로 보인다.\n */\n const state: ApprovalProgressState = thisRound.some(row => row.judgment === 'rejected')\n ? 'REJECTED'\n : facts.instanceState === 'aborted'\n ? 'ABORTED'\n : currentStepOf(approvals)\n ? 'PENDING'\n : 'APPROVED'\n\n const step = state === 'PENDING' ? currentStepOf(approvals) : undefined\n const waiting = state === 'PENDING' ? currentStepRows(approvals) : []\n const dueAt = timeOf(facts.dueAt)\n const approved = thisRound.filter(row => row.judgment === 'approved')\n const lastOrder = Math.max(0, ...approved.map(row => Number(row.order) || 0))\n const decided =\n state === 'APPROVED'\n ? approved.filter(row => (Number(row.order) || 0) === lastOrder)\n : state === 'REJECTED'\n ? thisRound.filter(row => row.judgment === 'rejected')\n : []\n\n return {\n state,\n step: step ? (orders.indexOf(step.order) + 1 || step.order) : undefined,\n steps: orders.length,\n waiting,\n decided,\n waitingSince: earliest(waiting.map(row => row.createdAt)),\n raisedAt: earliest(approvals.filter(deciding).map(row => row.createdAt)),\n endedAt: state === 'PENDING' ? undefined : latest(thisRound.map(row => row.terminatedAt)),\n overdue: state === 'PENDING' && dueAt !== undefined && dueAt < now.getTime()\n }\n}\n\nexport interface ProgressFilter {\n activityNames?: string[] | null\n states?: string[] | null\n departmentIds?: string[] | null\n /** The first day raised, inclusive. */\n from?: Date | null\n /** The last moment raised, exclusive. */\n to?: Date | null\n overdueOnly?: boolean | null\n search?: string | null\n}\n\nexport interface ProgressLine {\n activityName: string\n headline: string\n requesterName?: string\n departmentId?: string\n progress: Progress\n}\n\n/** Whether a line passes the filter. `ignore` leaves out the conditions a count is taken across. */\nexport function passes(line: ProgressLine, filter: ProgressFilter, ignore: { state?: boolean; overdue?: boolean } = {}): boolean {\n const { progress } = line\n if (filter.activityNames?.length && !filter.activityNames.includes(line.activityName)) return false\n if (!ignore.state && filter.states?.length && !filter.states.includes(progress.state)) return false\n if (filter.departmentIds?.length && !filter.departmentIds.includes(line.departmentId ?? '')) return false\n const raised = timeOf(progress.raisedAt)\n if (filter.from && (raised === undefined || raised < new Date(filter.from).getTime())) return false\n if (filter.to && (raised === undefined || raised >= new Date(filter.to).getTime())) return false\n if (!ignore.overdue && filter.overdueOnly && !progress.overdue) return false\n const search = filter.search?.trim().toLowerCase()\n if (search && ![line.headline, line.requesterName ?? ''].some(text => text.toLowerCase().includes(search))) return false\n return true\n}\n\n/** What waits stands first, the longest waiting at the top; what ended follows, the latest first. */\nexport function inProgressOrder(a: ProgressLine, b: ProgressLine): number {\n const pendingA = a.progress.state === 'PENDING'\n const pendingB = b.progress.state === 'PENDING'\n if (pendingA !== pendingB) return pendingA ? -1 : 1\n if (pendingA) return (timeOf(a.progress.waitingSince) ?? 0) - (timeOf(b.progress.waitingSince) ?? 0)\n return (timeOf(b.progress.endedAt ?? b.progress.raisedAt) ?? 0) - (timeOf(a.progress.endedAt ?? a.progress.raisedAt) ?? 0)\n}\n\n/** How many lines stand in each state, and how many are overdue — under the filter's other conditions. */\nexport function countsOf(lines: ProgressLine[], filter: ProgressFilter): { states: Record<ApprovalProgressState, number>; overdue: number } {\n const states = Object.fromEntries(APPROVAL_PROGRESS_STATES.map(state => [state, 0])) as Record<ApprovalProgressState, number>\n let overdue = 0\n for (const line of lines) {\n if (passes(line, filter, { state: true, overdue: true })) states[line.progress.state]++\n if (passes(line, filter, { overdue: true }) && line.progress.overdue) overdue++\n }\n return { states, overdue }\n}\n"]}
|
|
@@ -84,6 +84,10 @@ tslib_1.__decorate([
|
|
|
84
84
|
(0, type_graphql_1.Field)(type => [String], { description: 'Whom the step waited on now waits on - people, and a role as its holders.' }),
|
|
85
85
|
tslib_1.__metadata("design:type", Array)
|
|
86
86
|
], ApprovalProgress.prototype, "waitingOn", void 0);
|
|
87
|
+
tslib_1.__decorate([
|
|
88
|
+
(0, type_graphql_1.Field)(type => [String], { description: 'Who decided it - the last approver of an approved case, who rejected a rejected one.' }),
|
|
89
|
+
tslib_1.__metadata("design:type", Array)
|
|
90
|
+
], ApprovalProgress.prototype, "decidedBy", void 0);
|
|
87
91
|
tslib_1.__decorate([
|
|
88
92
|
(0, type_graphql_1.Field)({ nullable: true, description: 'The role the step waited on now is seated by, if any.' }),
|
|
89
93
|
tslib_1.__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-progress-type.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-type.ts"],"names":[],"mappings":";;;;AAAA,+CAAoE;AAG7D,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;CAqBlC,CAAA;AArBY,wDAAsB;AAEjC;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;6DACjG;AAGxB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC;;sDAC9F;AAGjB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;6DAChF;AAGxB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,iCAAiC,EAAE,CAAC;sCACnE,IAAI;oDAAA;AAGX;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;sCAChE,IAAI;kDAAA;AAGT;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;;2DAC9D;AAGrB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;;sDACxE;iCApBJ,sBAAsB;IADlC,IAAA,wBAAS,EAAC,EAAE,WAAW,EAAE,sEAAsE,EAAE,CAAC;GACtF,sBAAsB,CAqBlC;AAGM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;
|
|
1
|
+
{"version":3,"file":"approval-progress-type.js","sourceRoot":"","sources":["../../../server/service/approval-progress/approval-progress-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'\n\n@InputType({ description: 'What the approval progress list shows - every condition is optional.' })\nexport class ApprovalProgressFilter {\n @Field(type => [String], { nullable: true, description: 'The kinds - activity names (an office door is its activity).' })\n activityNames?: string[]\n\n @Field(type => [String], { nullable: true, description: 'The states - PENDING, APPROVED, REJECTED, ABORTED.' })\n states?: string[]\n\n @Field(type => [String], { nullable: true, description: \"The requester's departments (organization).\" })\n departmentIds?: string[]\n\n @Field({ nullable: true, description: 'Raised on or after this moment.' })\n from?: Date\n\n @Field({ nullable: true, description: 'Raised before this moment.' })\n to?: Date\n\n @Field({ nullable: true, description: 'Only what still waits past its due time.' })\n overdueOnly?: boolean\n\n @Field({ nullable: true, description: 'Words in the headline or the requester name.' })\n search?: string\n}\n\n@ObjectType({ description: 'One approval case and where it stands.' })\nexport class ApprovalProgress {\n @Field(type => ID, { description: 'The activity instance.' })\n id: string\n\n @Field({ description: 'The kind - the activity name.' })\n activityName: string\n\n @Field({ nullable: true, description: 'The kind as a person reads it - the activity label.' })\n activityLabel?: string\n\n @Field({ nullable: true, description: 'The i18n key the kind label is translated from.' })\n activityLabelTKey?: string\n\n @Field({ description: 'What the approver reads first - the instance name.' })\n headline: string\n\n @Field({ nullable: true, description: 'Who put it up for approval.' })\n requesterName?: string\n\n @Field({ nullable: true, description: \"The requester's department now.\" })\n departmentName?: string\n\n @Field({ description: 'PENDING, APPROVED, REJECTED or ABORTED.' })\n state: string\n\n @Field(type => Int, { nullable: true, description: 'The deciding step waited on now, from 1.' })\n step?: number\n\n @Field(type => Int, { description: 'How many deciding steps the line has.' })\n steps: number\n\n @Field(type => [String], { description: 'Whom the step waited on now waits on - people, and a role as its holders.' })\n waitingOn: string[]\n\n @Field(type => [String], { description: 'Who decided it - the last approver of an approved case, who rejected a rejected one.' })\n decidedBy: string[]\n\n @Field({ nullable: true, description: 'The role the step waited on now is seated by, if any.' })\n waitingRole?: string\n\n @Field({ nullable: true, description: 'Since when the step waited on now has waited.' })\n waitingSince?: Date\n\n @Field({ nullable: true, description: 'When it is due.' })\n dueAt?: Date\n\n @Field({ description: 'Still waiting past its due time.' })\n overdue: boolean\n\n @Field({ nullable: true, description: 'When it was first put up for approval.' })\n raisedAt?: Date\n\n @Field({ nullable: true, description: 'When it ended.' })\n endedAt?: Date\n}\n\n@ObjectType({ description: 'How many approvals stand in one state.' })\nexport class ApprovalProgressStateCount {\n @Field({ description: 'The state.' })\n state: string\n\n @Field(type => Int, { description: 'How many, under the other conditions.' })\n count: number\n}\n\n@ObjectType({ description: 'A kind of approval that has a case in this domain.' })\nexport class ApprovalProgressKind {\n @Field({ description: 'The activity name.' })\n name: string\n\n @Field({ description: 'The activity label.' })\n label: string\n\n @Field({ description: 'The i18n key the label is translated from.' })\n labelTKey: string\n}\n\n@ObjectType({ description: 'The approvals of a domain and where each stands.' })\nexport class ApprovalProgressList {\n @Field(type => [ApprovalProgress], { description: 'The page asked for.' })\n items: ApprovalProgress[]\n\n @Field(type => [ApprovalProgressKind], { description: 'The kinds with a case here, whatever the filter.' })\n kinds: ApprovalProgressKind[]\n\n @Field(type => Int, { description: 'How many pass the filter.' })\n total: number\n\n @Field(type => [ApprovalProgressStateCount], { description: 'How many stand in each state, under the other conditions.' })\n counts: ApprovalProgressStateCount[]\n\n @Field(type => Int, { description: 'How many still wait past their due time, under the other conditions.' })\n overdue: number\n}\n"]}
|
|
@@ -17,8 +17,8 @@ export * from './work-door/work-door-journal.js';
|
|
|
17
17
|
export * from './work-door/work-door-journal-service.js';
|
|
18
18
|
export * from './work-door/work-door-service.js';
|
|
19
19
|
export { waitingOn } from './approval-progress/waiting-on.js';
|
|
20
|
-
export declare const entities: (typeof import("./activity
|
|
21
|
-
export declare const subscribers: (typeof import("./activity-
|
|
20
|
+
export declare const entities: (typeof import("./activity/activity.js").Activity | typeof import("./activity-approval/activity-approval.js").ActivityApproval | typeof import("./activity-thread/activity-thread.js").ActivityThread | typeof import("./activity-instance/activity-instance.js").ActivityInstance | typeof import("./installable-activity/installable-activity.js").InstallableActivity | typeof import("./activity-template/activity-template.js").ActivityTemplate | typeof import("./activity-summary/activity-summary.js").ActivitySummary | typeof import("./activity/activity-history.js").ActivityHistory | typeof import("./activity-instance/activity-instance-history.js").ActivityInstanceHistory | typeof import("./activity-template/activity-template-history.js").ActivityTemplateHistory | typeof import("./activity-thread/activity-thread-history.js").ActivityThreadHistory | typeof import("./work-door/work-door-not-used.js").WorkDoorNotUsed | typeof import("./work-door/work-door-journal.js").WorkDoorJournal)[];
|
|
21
|
+
export declare const subscribers: (typeof import("./activity-approval/event-subscriber.js").ActivityApprovalSubscriber | typeof import("./activity/event-subscriber.js").ActivityHistoryEntitySubscriber | typeof import("./activity/declaration-guard-subscriber.js").ActivityDeclarationGuardSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceHistoryEntitySubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadSubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadHistoryEntitySubscriber)[];
|
|
22
22
|
export declare const schema: {
|
|
23
|
-
resolverClasses: (typeof import("./activity-
|
|
23
|
+
resolverClasses: (typeof import("./activity-stats/activity-stats-query.js").ActivityStatsQuery | typeof import("./activity-approval/activity-approval-query.js").ActivityApprovalQuery | typeof import("./activity-approval/activity-approval-mutation.js").ActivityApprovalMutation | typeof import("./activity-approval/activity-approval-subscription.js").ActivityApprovalSubscription | typeof import("./activity/activity-mutation.js").ActivityMutation | typeof import("./activity/activity-query.js").ActivityQuery | typeof import("./activity-instance/activity-instance-mutation.js").ActivityInstanceMutation | typeof import("./activity-instance/activity-instance-query.js").ActivityInstanceQuery | typeof import("./activity-instance/activity-instance-subscription.js").ActivityInstanceSubscription | typeof import("./activity-template/activity-template-mutation.js").ActivityTemplateMutation | typeof import("./activity-template/activity-template-query.js").ActivityTemplateQuery | typeof import("./activity-thread/activity-thread-mutation.js").ActivityThreadMutation | typeof import("./activity-thread/activity-thread-query.js").ActivityThreadQuery | typeof import("./activity-thread/activity-thread-history-query.js").ActivityThreadHistoryQuery | typeof import("./activity-thread/activity-thread-subscription.js").ActivityThreadSubscription | typeof import("./installable-activity/installable-activity-query.js").InstallableActivityQuery | typeof import("./installable-activity/installable-activity-mutation.js").InstallableActivityMutation | typeof import("./activity-summary/activity-summary-query.js").ActivitySummaryQuery | typeof import("./activity-summary/person-open-work.js").PersonOpenWorkQuery | typeof import("./work-door/work-door-resolver.js").WorkDoorResolver | typeof import("./approval-progress/approval-progress-query.js").ApprovalProgressQuery)[];
|
|
24
24
|
};
|