@things-factory/worklist 10.1.167 → 10.1.169
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/components/activity-starter-form.js +2 -0
- package/dist-client/components/activity-starter-form.js.map +1 -1
- package/dist-client/components/decision-content.d.ts +35 -0
- package/dist-client/components/decision-content.js +310 -0
- package/dist-client/components/decision-content.js.map +1 -0
- package/dist-client/components/decision-slots.d.ts +8 -0
- package/dist-client/components/decision-slots.js +17 -0
- package/dist-client/components/decision-slots.js.map +1 -1
- package/dist-client/components/work-box-groups.d.ts +25 -0
- package/dist-client/components/work-box-groups.js +98 -0
- package/dist-client/components/work-box-groups.js.map +1 -0
- package/dist-client/my-work-menus.d.ts +1 -6
- package/dist-client/my-work-menus.js +0 -1
- package/dist-client/my-work-menus.js.map +1 -1
- package/dist-client/pages/activity/activity-list-page.js +1 -0
- package/dist-client/pages/activity/activity-list-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-page.d.ts +2 -52
- package/dist-client/pages/activity-approval/activity-approval-page.js +9 -298
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-catalog/activity-detail-page.js +9 -2
- package/dist-client/pages/activity-catalog/activity-detail-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-start-page.js +3 -0
- package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.d.ts +10 -1
- package/dist-client/pages/activity-instance/activity-instance-view.js +31 -2
- package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.d.ts +6 -2
- package/dist-client/pages/activity-thread/activity-thread-page.js +32 -16
- package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +3 -2
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/activity-thread/thread-sections.d.ts +34 -0
- package/dist-client/pages/activity-thread/thread-sections.js +36 -0
- package/dist-client/pages/activity-thread/thread-sections.js.map +1 -0
- package/dist-client/pages/todo/approval-pending-list-page.d.ts +1 -0
- package/dist-client/pages/todo/approval-pending-list-page.js +10 -77
- package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
- package/dist-client/pages/todo/draft-list-page.d.ts +20 -0
- package/dist-client/pages/todo/draft-list-page.js +103 -5
- package/dist-client/pages/todo/draft-list-page.js.map +1 -1
- package/dist-client/pages/todo/todo-list-page.d.ts +19 -0
- package/dist-client/pages/todo/todo-list-page.js +147 -23
- package/dist-client/pages/todo/todo-list-page.js.map +1 -1
- package/dist-client/pages/todo/work-box.d.ts +36 -0
- package/dist-client/pages/todo/work-box.js +44 -0
- package/dist-client/pages/todo/work-box.js.map +1 -0
- package/dist-client/pages/work-door/work-doors-page.d.ts +1 -15
- package/dist-client/pages/work-door/work-doors-page.js +18 -43
- package/dist-client/pages/work-door/work-doors-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +0 -3
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types/activity.d.ts +2 -0
- package/dist-client/types/activity.js.map +1 -1
- package/dist-server/controllers/activity-approval/create-approval.js +2 -1
- package/dist-server/controllers/activity-approval/create-approval.js.map +1 -1
- package/dist-server/controllers/activity-approval/resolve-judgeable-seats.js +2 -1
- package/dist-server/controllers/activity-approval/resolve-judgeable-seats.js.map +1 -1
- package/dist-server/service/activity-summary/index.d.ts +1 -1
- package/dist-server/service/activity-summary/open-work.d.ts +0 -1
- package/dist-server/service/activity-summary/open-work.js +3 -15
- package/dist-server/service/activity-summary/open-work.js.map +1 -1
- package/dist-server/service/activity-thread/activity-thread-query.d.ts +3 -0
- package/dist-server/service/activity-thread/activity-thread-query.js +24 -5
- package/dist-server/service/activity-thread/activity-thread-query.js.map +1 -1
- package/dist-server/service/activity-thread/index.d.ts +1 -1
- package/dist-server/service/activity-thread/my-open-threads.d.ts +23 -4
- package/dist-server/service/activity-thread/my-open-threads.js +38 -7
- package/dist-server/service/activity-thread/my-open-threads.js.map +1 -1
- package/dist-server/service/index.d.ts +3 -3
- package/dist-server/service/work-door/approval-line-standing.d.ts +14 -0
- package/dist-server/service/work-door/approval-line-standing.js +23 -5
- package/dist-server/service/work-door/approval-line-standing.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/tests/open-doors.test.ts +3 -2
- package/things-factory.config.js +0 -1
- package/translations/en.json +10 -2
- package/translations/es.json +10 -2
- package/translations/ja.json +10 -2
- package/translations/ko.json +10 -2
- package/translations/ms.json +10 -2
- package/translations/zh.json +10 -2
|
@@ -2,6 +2,7 @@ import { Domain, User, Role } from '@operato/shell';
|
|
|
2
2
|
import { ApprovalLineItem, AssigneeItem } from '@things-factory/organization/dist-client';
|
|
3
3
|
import { ActivityModelItem } from './activity-model-type.js';
|
|
4
4
|
import { ActivitySearchKeyItem } from './activity-search-key-item-type.js';
|
|
5
|
+
import type { DecisionKeyDeclaration } from '../components/decision-slots.js';
|
|
5
6
|
export declare enum ActivityStatus {
|
|
6
7
|
Draft = "draft",
|
|
7
8
|
Released = "released",
|
|
@@ -40,6 +41,7 @@ export declare class Activity {
|
|
|
40
41
|
activityType?: ActivityType;
|
|
41
42
|
state?: ActivityStatus;
|
|
42
43
|
searchKeys?: ActivitySearchKeyItem[];
|
|
44
|
+
decisionKeys?: DecisionKeyDeclaration[];
|
|
43
45
|
model?: ActivityModelItem[];
|
|
44
46
|
priority?: number;
|
|
45
47
|
startingType?: ActivityStartingType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../../client/types/activity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../../client/types/activity.ts"],"names":[],"mappings":"AAOA,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,uCAAqB,CAAA;IACrB,2CAAyB,CAAA;AAC3B,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB;AAED,MAAM,CAAN,IAAY,YAWX;AAXD,WAAY,YAAY;IACtB,6BAAa,CAAA;IACb,mCAAmB,CAAA;IACnB,6BAAa,CAAA;IACb,mCAAmB,CAAA;IACnB,6BAAa,CAAA;IACb,iCAAiB,CAAA;IACjB,8CAA8B,CAAA;IAC9B,iCAAiB,CAAA;IACjB,0CAA0B,CAAA;IAC1B,6BAAa,CAAA;AACf,CAAC,EAXW,YAAY,KAAZ,YAAY,QAWvB;AAED,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,yCAAuB,CAAA;IACvB,uCAAqB,CAAA;IACrB,iCAAe,CAAA;IACf,kDAAgC,CAAA;IAChC,+BAAa,CAAA;IACb,uCAAqB,CAAA;AACvB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB;AAED,MAAM,CAAN,IAAY,oBAGX;AAHD,WAAY,oBAAoB;IAC9B,qCAAa,CAAA;IACb,uCAAe,CAAA;AACjB,CAAC,EAHW,oBAAoB,KAApB,oBAAoB,QAG/B;AAED,MAAM,OAAO,QAAQ;IAArB;QAGE,YAAO,GAAY,CAAC,CAAA;QAkBpB,aAAQ,GAAY,CAAC,CAAA;IA2CvB,CAAC;CAAA","sourcesContent":["import { Domain, User, Role } from '@operato/shell'\nimport { ApprovalLineItem, AssigneeItem } from '@things-factory/organization/dist-client'\n\nimport { ActivityModelItem } from './activity-model-type.js'\nimport { ActivitySearchKeyItem } from './activity-search-key-item-type.js'\nimport type { DecisionKeyDeclaration } from '../components/decision-slots.js'\n\nexport enum ActivityStatus {\n Draft = 'draft',\n Released = 'released',\n Deprecated = 'deprecated'\n}\n\nexport enum ActivityType {\n Task = 'task',\n Service = 'service',\n Send = 'send',\n Receive = 'receive',\n User = 'user',\n Manual = 'manual',\n BusinessRule = 'business-rule',\n Script = 'script',\n Subprocess = 'sub-process',\n Call = 'call'\n}\n\nexport enum ActivityUIType {\n Generated = 'generated',\n Template = 'template',\n Board = 'board',\n CustomElement = 'custom-element',\n Page = 'page',\n External = 'external'\n}\n\nexport enum ActivityStartingType {\n post = 'post',\n issue = 'issue'\n}\n\nexport class Activity {\n id?: string\n\n version?: number = 1\n\n domain?: Domain\n\n name?: string\n\n description?: string\n\n activityType?: ActivityType\n\n state?: ActivityStatus\n\n searchKeys?: ActivitySearchKeyItem[]\n\n decisionKeys?: DecisionKeyDeclaration[]\n\n model?: ActivityModelItem[]\n\n priority?: number = 1\n\n startingType?: ActivityStartingType\n\n schedule?: string\n\n timzeone?: string\n\n standardTime?: number\n\n issuerRole?: Role\n\n assigneeRole?: Role\n\n supervisoryRole?: Role\n\n assignees?: AssigneeItem[]\n\n approvalLine?: ApprovalLineItem[]\n\n uiType?: ActivityUIType\n\n uiSource?: string\n\n viewType?: ActivityUIType\n\n viewSource?: string\n\n reportType?: ActivityUIType\n\n reportSource?: string\n\n createdAt?: Date\n\n updatedAt?: Date\n\n client?: User\n\n creator?: User\n\n updater?: User\n\n thumbnail?: string\n}\n"]}
|
|
@@ -16,6 +16,7 @@ const auth_base_1 = require("@things-factory/auth-base");
|
|
|
16
16
|
const organization_1 = require("@things-factory/organization");
|
|
17
17
|
const activity_approval_js_1 = require("../../service/activity-approval/activity-approval.js");
|
|
18
18
|
const common_js_1 = require("../common.js");
|
|
19
|
+
const approval_line_standing_js_1 = require("../../service/work-door/approval-line-standing.js");
|
|
19
20
|
/**
|
|
20
21
|
* 결재선 항목 하나로 행을 만든다.
|
|
21
22
|
*
|
|
@@ -37,7 +38,7 @@ async function createApproval(args, context) {
|
|
|
37
38
|
updater: user
|
|
38
39
|
};
|
|
39
40
|
if (item.type == organization_1.OrgMemberTargetType.Role) {
|
|
40
|
-
const roleId =
|
|
41
|
+
const roleId = (0, approval_line_standing_js_1.seatRoleId)(item);
|
|
41
42
|
if (!roleId) {
|
|
42
43
|
throw new Error(context.t('error.approver role is not set on the approval line', { order }));
|
|
43
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-approval.js","sourceRoot":"","sources":["../../../server/controllers/activity-approval/create-approval.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"create-approval.js","sourceRoot":"","sources":["../../../server/controllers/activity-approval/create-approval.ts"],"names":[],"mappings":";;AA4BA,wCA8CC;AAWD,4CAwBC;AA7GD;;;;;;;;;GASG;AACH,yDAAgD;AAEhD,+DAAkE;AAElE,+FAAiH;AAEjH,4CAA6D;AAC7D,iGAA8E;AAK9E;;;;;GAKG;AACI,KAAK,UAAU,cAAc,CAClC,IAOC,EACD,OAAwB;IAExB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAC1C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAExE,MAAM,IAAI,GAAG;QACX,MAAM;QACN,cAAc;QACd,KAAK,EAAE,cAAc,CAAC,KAAK;QAC3B,KAAK;QACL,QAAQ,EAAE,+CAAwB,CAAC,OAAO;QAC1C,aAAa;QACb,WAAW;QACX,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;KACd,CAAA;IAED,IAAI,IAAI,CAAC,IAAI,IAAI,kCAAmB,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAA,sCAAU,EAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qDAAqD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;QAC9F,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;QAC3E,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,+BAA+B,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QAC/E,CAAC;QAED,OAAO,MAAM,EAAE,CAAC,aAAa,CAAC,uCAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAS,CAAC,CAAA;IACxF,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,0CAA8B,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACpE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gDAAgD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IACzF,CAAC;IAED,OAAO,MAAM,EAAE,CAAC,aAAa,CAAC,uCAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAS,CAAC,CAAA;AACpF,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,gBAAgB,CACpC,IAGC,EACD,OAAwB;IAExB,MAAM,OAAO,GAAuB,EAAE,CAAA;IACtC,MAAM,MAAM,GAAwC,EAAE,CAAA;IAEtD,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CACV,MAAM,cAAc,CAClB,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,EACvG,OAAO,CACR,CACF,CAAA;QACH,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AAC5B,CAAC","sourcesContent":["/*\n * **결재선 한 항목을 실제 행으로 만든다** — 한 자리.\n *\n * ── 왜 뺐나 (2026-09-01) ─────────────────────────────────────────────────\n * 같은 열다섯 줄이 두 파일에 있었다 — `submit.ts`(첫 결재자)와 `approve.ts`(다음 결재자). 역할로 걸린\n * 경우와 사람으로 걸린 경우를 가르고, 못 찾으면 던지고, 행을 만든다.\n *\n * 참조까지 넣으면 **세 벌**이 된다. 그때 한쪽만 고쳐지는 날이 오고, 그러면 어떤 자격의 결재자만\n * 조용히 안 만들어진다 — 오류가 안 나고 결재가 안 걸린다.\n */\nimport { Role } from '@things-factory/auth-base'\nimport type { ApprovalLineItem } from '@things-factory/organization'\nimport { OrgMemberTargetType } from '@things-factory/organization'\n\nimport { ActivityApproval, ActivityApprovalJudgment } from '../../service/activity-approval/activity-approval.js'\nimport type { ActivityThread } from '../../service/activity-thread/activity-thread.js'\nimport { getSystemUserFromOrgMemberItem } from '../common.js'\nimport { seatRoleId } from '../../service/work-door/approval-line-standing.js'\n\n/** 이 항목이 무슨 자격으로 서나 — 행에도 적는다(목록 질의가 참조를 걸러야 한다). */\nexport type Participation = 'approval' | 'reference'\n\n/**\n * 결재선 항목 하나로 행을 만든다.\n *\n * 역할로 걸린 것은 `approverRole` 만 채워지고 `approver` 는 비어 있다 — 그 역할을 가진 사람 여럿이 같은\n * 건을 본다. 처리하는 사람이 정해지는 것은 누른 순간이다(§`approve.ts`).\n */\nexport async function createApproval(\n args: {\n item: ApprovalLineItem\n order: number\n participation: Participation\n activityThread: ActivityThread\n /** 이 행이 왜 생겼나 — `submit` · `escalate` · `notify`. */\n transaction: string\n },\n context: ResolverContext\n): Promise<ActivityApproval> {\n const { domain, user, tx } = context.state\n const { item, order, participation, activityThread, transaction } = args\n\n const base = {\n domain,\n activityThread,\n round: activityThread.round,\n order,\n judgment: ActivityApprovalJudgment.Pending,\n participation,\n transaction,\n creator: user,\n updater: user\n }\n\n if (item.type == OrgMemberTargetType.Role) {\n const roleId = seatRoleId(item)\n if (!roleId) {\n throw new Error(context.t('error.approver role is not set on the approval line', { order }))\n }\n\n const approverRole = await tx.getRepository(Role).findOneBy({ id: roleId })\n if (!approverRole) {\n throw new Error(context.t('error.approver role not found', { role: roleId }))\n }\n\n return await tx.getRepository(ActivityApproval).save({ ...base, approverRole } as any)\n }\n\n const approver = await getSystemUserFromOrgMemberItem(item, context)\n if (!approver) {\n throw new Error(context.t('error.approver is not set on the approval line', { order }))\n }\n\n return await tx.getRepository(ActivityApproval).save({ ...base, approver } as any)\n}\n\n/**\n * 이번에 알려야 할 참조들의 행을 만든다 — **하나가 실패해도 결재를 세우지 않는다.**\n *\n * 참조는 막지 않는 자격이다. 그런데 참조자를 못 찾아 던지면 그 예외가 상신·승인을 통째로 물린다 —\n * 막지 않기로 한 것이 막게 된다.\n *\n * 그래서 실패를 삼키지 않되 **던지지도 않는다.** 못 만든 참조를 이유와 함께 돌려주고, 부르는 쪽이\n * 그것을 기록한다.\n */\nexport async function createReferences(\n args: {\n references: { item: ApprovalLineItem; order: number }[]\n activityThread: ActivityThread\n },\n context: ResolverContext\n): Promise<{ created: ActivityApproval[]; failed: { order: number; reason: string }[] }> {\n const created: ActivityApproval[] = []\n const failed: { order: number; reason: string }[] = []\n\n for (const { item, order } of args.references) {\n try {\n created.push(\n await createApproval(\n { item, order, participation: 'reference', activityThread: args.activityThread, transaction: 'notify' },\n context\n )\n )\n } catch (e: any) {\n failed.push({ order, reason: String(e?.message ?? e) })\n }\n }\n\n return { created, failed }\n}\n"]}
|
|
@@ -5,6 +5,7 @@ const auth_base_1 = require("@things-factory/auth-base");
|
|
|
5
5
|
const organization_1 = require("@things-factory/organization");
|
|
6
6
|
const common_js_1 = require("../common.js");
|
|
7
7
|
const approval_line_js_1 = require("./approval-line.js");
|
|
8
|
+
const approval_line_standing_js_1 = require("../../service/work-door/approval-line-standing.js");
|
|
8
9
|
/**
|
|
9
10
|
* 결재선을 「자리마다 누가 설 수 있나」로 푼다 — **가져오는 일만 한다.**
|
|
10
11
|
*
|
|
@@ -33,7 +34,7 @@ async function resolveJudgeableSeats(approvalLine, context) {
|
|
|
33
34
|
}
|
|
34
35
|
const order = index + 1;
|
|
35
36
|
if (item.type == organization_1.OrgMemberTargetType.Role) {
|
|
36
|
-
const roleId =
|
|
37
|
+
const roleId = (0, approval_line_standing_js_1.seatRoleId)(item);
|
|
37
38
|
const role = roleId && (await tx.getRepository(auth_base_1.Role).findOne({ where: { id: roleId }, relations: ['users'] }));
|
|
38
39
|
seats.push({
|
|
39
40
|
order,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-judgeable-seats.js","sourceRoot":"","sources":["../../../server/controllers/activity-approval/resolve-judgeable-seats.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"resolve-judgeable-seats.js","sourceRoot":"","sources":["../../../server/controllers/activity-approval/resolve-judgeable-seats.ts"],"names":[],"mappings":";;AA2BA,sDA2CC;AAtED,yDAAgD;AAEhD,+DAAkE;AAElE,4CAA6D;AAC7D,yDAAmD;AAEnD,iGAA8E;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACI,KAAK,UAAU,qBAAqB,CACzC,YAAmD,EACnD,OAAwB;IAExB,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAC5B,MAAM,KAAK,GAAoB,EAAE,CAAA;IAEjC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3D,yCAAyC;QACzC,IAAI,CAAC,IAAA,iCAAc,EAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,SAAQ;QACV,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAA;QAEvB,IAAI,IAAI,CAAC,IAAI,IAAI,kCAAmB,CAAC,IAAI,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,IAAA,sCAAU,EAAC,IAAI,CAAC,CAAA;YAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;YAE9G,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK;gBACL,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClD,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI;gBACvC,QAAQ,EAAE,MAAM,IAAI,SAAS;aAC9B,CAAC,CAAA;YAEF,SAAQ;QACV,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAA,0CAA8B,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAEpE,KAAK,CAAC,IAAI,CAAC;YACT,KAAK;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YAC7C,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI;YAC3C,qDAAqD;YACrD,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,SAAS;SACvD,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import { Role } from '@things-factory/auth-base'\nimport type { ApprovalLineItem } from '@things-factory/organization'\nimport { OrgMemberTargetType } from '@things-factory/organization'\n\nimport { getSystemUserFromOrgMemberItem } from '../common.js'\nimport { isApprovalStep } from './approval-line.js'\nimport type { JudgeableSeat } from './own-request.js'\nimport { seatRoleId } from '../../service/work-door/approval-line-standing.js'\n\n/**\n * 결재선을 「자리마다 누가 설 수 있나」로 푼다 — **가져오는 일만 한다.**\n *\n * 판단은 `own-request.ts` 의 `judgeSomeoneElseCanJudge` 가 든다. 이 파일은 DB 를 읽어서 시험이 못\n * 드는 쪽이고, 그래서 여기에는 규칙을 한 줄도 두지 않는다.\n *\n * ── 자리를 푸는 규칙은 `create-approval.ts` 를 그대로 따른다 ──────────────\n * 실제로 행을 만드는 자리가 거기다. 여기서 다르게 풀면 **여기서는 괜찮다고 하고 거기서는 다른 사람을\n * 앉히는** 일이 난다. 그쪽이 가르는 축은 하나다 — `type` 이 `Role` 이면 역할로 걸고, 아니면 사람\n * 하나로 푼다.\n *\n * ⚠ `getSystemUserFromOrgMemberItem` 도 `Role` 을 받아 주는데, 그것은 **그 역할의 첫 사람 하나**를\n * 돌려준다. 실제 거동은 그게 아니라 「그 역할을 가진 사람 누구나」이므로 그 갈래를 먼저 가른다.\n *\n * ── `Myself` 는 올리는 사람이다 ───────────────────────────────────────────\n * 그 자리는 `context.state.user` 로 풀리고, 상신하는 동안 그 사람이 곧 상신자다. 그래서 `Myself` 가\n * 결재 자리에 있으면 **언제나** 자기결재다 — 이 문이 정확히 그것을 잡는다.\n */\nexport async function resolveJudgeableSeats(\n approvalLine: ApprovalLineItem[] | undefined | null,\n context: ResolverContext\n): Promise<JudgeableSeat[]> {\n const { tx } = context.state\n const seats: JudgeableSeat[] = []\n\n for (const [index, item] of (approvalLine || []).entries()) {\n /* 참조는 판정하지 않는다. 자리는 차지하므로 차례는 그대로 센다. */\n if (!isApprovalStep(item)) {\n continue\n }\n\n const order = index + 1\n\n if (item.type == OrgMemberTargetType.Role) {\n const roleId = seatRoleId(item)\n const role = roleId && (await tx.getRepository(Role).findOne({ where: { id: roleId }, relations: ['users'] }))\n\n seats.push({\n order,\n kind: 'role',\n couldJudge: (role?.users || []).map(one => one.id),\n name: role?.name || item.approver?.name,\n pointsAt: roleId || undefined\n })\n\n continue\n }\n\n const approver = await getSystemUserFromOrgMemberItem(item, context)\n\n seats.push({\n order,\n kind: 'person',\n couldJudge: approver?.id ? [approver.id] : [],\n name: approver?.name || item.approver?.name,\n /* 안 풀리는 자리는 이름도 비므로, 결재선에 적힌 값이 관리자가 가진 유일한 실마리다. */\n pointsAt: item.approver?.id || item.value || undefined\n })\n }\n\n return seats\n}\n"]}
|
|
@@ -2,4 +2,4 @@ import { ActivitySummary } from "./activity-summary.js";
|
|
|
2
2
|
import { ActivitySummaryQuery } from "./activity-summary-query.js";
|
|
3
3
|
import { PersonOpenWorkQuery } from "./person-open-work.js";
|
|
4
4
|
export declare const entities: (typeof ActivitySummary)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof PersonOpenWorkQuery | typeof ActivitySummaryQuery)[];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Domain } from '@things-factory/shell';
|
|
2
2
|
/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */
|
|
3
3
|
export declare function toDosOf(domain: Domain, userId: string): Promise<number>;
|
|
4
|
-
/** Approvals waiting on the person - through the inbox's own clause. */
|
|
5
4
|
export declare function pendingApprovalsOf(domain: Domain, userId: string): Promise<number>;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toDosOf = toDosOf;
|
|
4
4
|
exports.pendingApprovalsOf = pendingApprovalsOf;
|
|
5
|
-
const typeorm_1 = require("typeorm");
|
|
6
5
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
6
|
const shell_1 = require("@things-factory/shell");
|
|
8
7
|
const activity_thread_js_1 = require("../activity-thread/activity-thread.js");
|
|
9
8
|
const activity_approval_js_1 = require("../activity-approval/activity-approval.js");
|
|
10
9
|
const my_pending_approvals_js_1 = require("../activity-approval/my-pending-approvals.js");
|
|
10
|
+
const my_open_threads_js_1 = require("../activity-thread/my-open-threads.js");
|
|
11
11
|
/**
|
|
12
12
|
* What a person has on their plate in one domain - the same questions the rail's badges ask.
|
|
13
13
|
*
|
|
@@ -24,7 +24,7 @@ async function rolesIn(domain, userId) {
|
|
|
24
24
|
/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */
|
|
25
25
|
async function toDosOf(domain, userId) {
|
|
26
26
|
const roles = await rolesIn(domain, userId);
|
|
27
|
-
|
|
27
|
+
/* The list's own clause - the badge counts what 할 일 shows, not a copy of its rule. */
|
|
28
28
|
return await (0, shell_1.getQueryBuilderFromListParams)({
|
|
29
29
|
repository: (0, shell_1.getRepository)(activity_thread_js_1.ActivityThread),
|
|
30
30
|
params: {},
|
|
@@ -32,21 +32,9 @@ async function toDosOf(domain, userId) {
|
|
|
32
32
|
alias: 'at'
|
|
33
33
|
})
|
|
34
34
|
.innerJoinAndSelect('at.activityInstance', 'ai')
|
|
35
|
-
.andWhere(
|
|
36
|
-
qb.where('at.state NOT IN (:...excludedStatuses)', { excludedStatuses }).andWhere('at.assignee = :userId', {
|
|
37
|
-
userId
|
|
38
|
-
});
|
|
39
|
-
if (roles.length > 0) {
|
|
40
|
-
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
41
|
-
subQb
|
|
42
|
-
.where('ai.assigneeRole IN (:...roles)', { roles })
|
|
43
|
-
.andWhere(`at.state = '${activity_thread_js_1.ActivityThreadStatus.Unassigned}'`);
|
|
44
|
-
}));
|
|
45
|
-
}
|
|
46
|
-
}))
|
|
35
|
+
.andWhere((0, my_open_threads_js_1.myOpenThreadsWhere)({ userId, roles }))
|
|
47
36
|
.getCount();
|
|
48
37
|
}
|
|
49
|
-
/** Approvals waiting on the person - through the inbox's own clause. */
|
|
50
38
|
async function pendingApprovalsOf(domain, userId) {
|
|
51
39
|
const roles = await rolesIn(domain, userId);
|
|
52
40
|
return await (0, shell_1.getQueryBuilderFromListParams)({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-work.js","sourceRoot":"","sources":["../../../server/service/activity-summary/open-work.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"open-work.js","sourceRoot":"","sources":["../../../server/service/activity-summary/open-work.ts"],"names":[],"mappings":";;AAwBA,0BAaC;AAED,gDAaC;AApDD,yDAAgD;AAChD,iDAA4F;AAE5F,8EAAsE;AACtE,oFAA4E;AAC5E,0FAAsF;AACtF,8EAA0E;AAE1E;;;;;;;GAOG;AAEH,iHAAiH;AACjH,KAAK,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IACnD,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC/F,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC7F,CAAC;AAED,oGAAoG;AAC7F,KAAK,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IAC1D,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE3C,sFAAsF;IACtF,OAAO,MAAM,IAAA,qCAA6B,EAAC;QACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,mCAAc,CAAC;QACzC,MAAM,EAAE,EAAE;QACV,MAAM;QACN,KAAK,EAAE,IAAI;KACZ,CAAC;SACC,kBAAkB,CAAC,qBAAqB,EAAE,IAAI,CAAC;SAC/C,QAAQ,CAAC,IAAA,uCAAkB,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;SAC/C,QAAQ,EAAE,CAAA;AACf,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,MAAc;IACrE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE3C,OAAO,MAAM,IAAA,qCAA6B,EAAC;QACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,uCAAgB,CAAC;QAC3C,MAAM,EAAE,EAAE;QACV,MAAM;QACN,KAAK,EAAE,IAAI;KACZ,CAAC;SACC,QAAQ,CAAC,mBAAmB,EAAE,IAAI,CAAC;SACnC,QAAQ,CAAC,qBAAqB,EAAE,IAAI,CAAC;SACrC,QAAQ,CAAC,IAAA,iDAAuB,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;SACpD,QAAQ,EAAE,CAAA;AACf,CAAC","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivityThread } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\nimport { myOpenThreadsWhere } from '../activity-thread/my-open-threads.js'\n\n/**\n * What a person has on their plate in one domain - the same questions the rail's badges ask.\n *\n * The badges asked them only of whoever is signed in, with the rule written inline. The person 360\n * asks them of someone else (ADR-0067, the person 360 ruling), so the rule lives here once and both\n * readers call it - a second copy would drift the way the approval count once did\n * (`activity-summary-query.ts` records how).\n */\n\n/** The roles a person holds in this domain - an approval or a thread held by role reaches them through these. */\nasync function rolesIn(domain: Domain, userId: string): Promise<string[]> {\n const user = await getRepository(User).findOne({ where: { id: userId }, relations: ['roles'] })\n return (user?.roles || []).filter(role => role.domainId === domain.id).map(role => role.id)\n}\n\n/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */\nexport async function toDosOf(domain: Domain, userId: string): Promise<number> {\n const roles = await rolesIn(domain, userId)\n\n /* The list's own clause - the badge counts what 할 일 shows, not a copy of its rule. */\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n params: {},\n domain,\n alias: 'at'\n })\n .innerJoinAndSelect('at.activityInstance', 'ai')\n .andWhere(myOpenThreadsWhere({ userId, roles }))\n .getCount()\n}\n\nexport async function pendingApprovalsOf(domain: Domain, userId: string): Promise<number> {\n const roles = await rolesIn(domain, userId)\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityApproval),\n params: {},\n domain,\n alias: 'ap'\n })\n .leftJoin('ap.activityThread', 'at')\n .leftJoin('at.activityInstance', 'ai')\n .andWhere(myPendingApprovalsWhere({ userId, roles }))\n .getCount()\n}\n"]}
|
|
@@ -9,7 +9,10 @@ export declare class ActivityThreadQuery {
|
|
|
9
9
|
activityThread(id: string, context: ResolverContext): Promise<ActivityThread>;
|
|
10
10
|
activityThreads(params: ListParam, context: ResolverContext): Promise<ActivityThreadList>;
|
|
11
11
|
todoList(params: ListParam, context: ResolverContext): Promise<ActivityThreadList>;
|
|
12
|
+
submittedList(params: ListParam, context: ResolverContext): Promise<ActivityThreadList>;
|
|
12
13
|
doneList(params: ListParam, context: ResolverContext): Promise<ActivityThreadList>;
|
|
14
|
+
/** 할 일의 「제출한 것」·「완료」 — 내가 올린 것은 상신함이 따라간다(myThreadsOfOthersWhere). */
|
|
15
|
+
private myThreadsOfOthers;
|
|
13
16
|
assignee(activityThread: ActivityThread): Promise<User>;
|
|
14
17
|
activityInstance(activityThread: ActivityThread): Promise<ActivityInstance>;
|
|
15
18
|
activityApprovals(activityThread: ActivityThread, context: ResolverContext): Promise<ActivityApproval[]>;
|
|
@@ -103,9 +103,16 @@ let ActivityThreadQuery = class ActivityThreadQuery {
|
|
|
103
103
|
const [items, total] = await queryBuilder.getManyAndCount();
|
|
104
104
|
return { items, total };
|
|
105
105
|
}
|
|
106
|
+
async submittedList(params, context) {
|
|
107
|
+
const { domain, user } = context.state;
|
|
108
|
+
return await this.myThreadsOfOthers(params, domain, user.id, my_open_threads_js_1.WAITING_ON_OTHERS);
|
|
109
|
+
}
|
|
106
110
|
async doneList(params, context) {
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
const { domain, user } = context.state;
|
|
112
|
+
return await this.myThreadsOfOthers(params, domain, user.id, my_open_threads_js_1.FINISHED);
|
|
113
|
+
}
|
|
114
|
+
/** 할 일의 「제출한 것」·「완료」 — 내가 올린 것은 상신함이 따라간다(myThreadsOfOthersWhere). */
|
|
115
|
+
async myThreadsOfOthers(params, domain, userId, states) {
|
|
109
116
|
const [items, total] = await (0, shell_1.getQueryBuilderFromListParams)({
|
|
110
117
|
repository: (0, shell_1.getRepository)(activity_thread_js_1.ActivityThread),
|
|
111
118
|
params,
|
|
@@ -118,8 +125,8 @@ let ActivityThreadQuery = class ActivityThreadQuery {
|
|
|
118
125
|
priority: { columnName: 'priority', relationColumn: 'activityInstance' }
|
|
119
126
|
}
|
|
120
127
|
})
|
|
121
|
-
.
|
|
122
|
-
.andWhere(
|
|
128
|
+
.innerJoinAndSelect('at.activityInstance', 'ai')
|
|
129
|
+
.andWhere((0, my_open_threads_js_1.myThreadsOfOthersWhere)({ userId, states }))
|
|
123
130
|
.getManyAndCount();
|
|
124
131
|
return { items, total };
|
|
125
132
|
}
|
|
@@ -186,7 +193,19 @@ tslib_1.__decorate([
|
|
|
186
193
|
tslib_1.__metadata("design:returntype", Promise)
|
|
187
194
|
], ActivityThreadQuery.prototype, "todoList", null);
|
|
188
195
|
tslib_1.__decorate([
|
|
189
|
-
(0, type_graphql_1.Query)(returns => activity_thread_type_js_1.ActivityThreadList, {
|
|
196
|
+
(0, type_graphql_1.Query)(returns => activity_thread_type_js_1.ActivityThreadList, {
|
|
197
|
+
description: 'To fetch the tasks(ActivityThreads) I submitted that wait on an approval - of work someone else put up'
|
|
198
|
+
}),
|
|
199
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
200
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
201
|
+
tslib_1.__metadata("design:type", Function),
|
|
202
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
203
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
204
|
+
], ActivityThreadQuery.prototype, "submittedList", null);
|
|
205
|
+
tslib_1.__decorate([
|
|
206
|
+
(0, type_graphql_1.Query)(returns => activity_thread_type_js_1.ActivityThreadList, {
|
|
207
|
+
description: 'To fetch the tasks(ActivityThreads) I finished - of work someone else put up'
|
|
208
|
+
}),
|
|
190
209
|
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
191
210
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
192
211
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-thread-query.js","sourceRoot":"","sources":["../../../server/service/activity-thread/activity-thread-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { ActivityInstance } from '../activity-instance/activity-instance.js'\nimport { ActivityThread, ActivityThreadStatus } from './activity-thread.js'\nimport { myOpenThreadsWhere } from './my-open-threads.js'\nimport { assertMayReadThread } from '../../controllers/activity-read/assert-may-read.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { ActivityThreadList } from './activity-thread-type.js'\nimport { ActivityThreadHistory } from './activity-thread-history.js'\nimport { TODO_INSTANCE_SORTS, todoOrderTerms } from './todo-order.js'\n\n\n/**\n * 「할 일」 목록의 정렬 — **기한이 없는 것은 뒤로 간다.**\n *\n * ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────\n * 화면의 기본 정렬은 `dueAt` 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에\n * 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.\n *\n * NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저, postgres 는\n * 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.\n *\n * ── 왜 NULLS LAST 를 쓰지 않나 ─────────────────────────────────────────────\n * `ORDER BY ... NULLS LAST` 는 postgres · oracle 문법이다. mysql · mssql 에서는 구문 오류가 난다.\n * 이 프레임워크는 다섯 드라이버를 다 지켜야 한다.\n *\n * `CASE WHEN ... IS NULL THEN 1 ELSE 0 END` 는 표준 SQL 이고 다섯 곳에서 다 돈다. 컬럼 이름은\n * 손으로 적지 않고 TypeORM 의 메타데이터에서 꺼낸다 — 이 프로젝트의 명명 규칙이 snake_case 라\n * `dueAt` 은 실제로 `due_at` 이다(shell 의 NamingStrategy).\n *\n * ── 공용 함수를 고치지 않는다 ──────────────────────────────────────────────\n * `getQueryBuilderFromListParams` 는 136개 꾸러미가 함께 쓴다. 정렬은 이 목록의 사정이므로\n * 여기서 맡는다 — 그 함수에는 정렬을 넘기지 않고(빈 배열) 아래에서 직접 건다.\n */\n\nfunction applyTodoSortings(queryBuilder: any, sortings: { name: string; desc?: boolean }[]) {\n const terms = todoOrderTerms(sortings, name => {\n const alias = TODO_INSTANCE_SORTS.has(name) ? 'ai' : 'at'\n const metadata = getRepository(alias === 'ai' ? ActivityInstance : ActivityThread).metadata\n const column = metadata.findColumnWithPropertyName(name)\n\n if (!column) {\n return undefined\n }\n\n const escape = (part: string) => queryBuilder.connection.driver.escape(part)\n\n return `${escape(alias)}.${escape(column.databaseName)}`\n })\n\n terms.forEach(({ expression, direction, select }, index) => {\n /* 식은 select 에 이름 붙여 올린다 — orderBy 는 식을 못 받는다(todo-order 머리말). */\n if (select) {\n queryBuilder.addSelect(select, expression)\n }\n\n index === 0 ? queryBuilder.orderBy(expression, direction) : queryBuilder.addOrderBy(expression, direction)\n })\n}\n\n@Resolver(ActivityThread)\nexport class ActivityThreadQuery {\n @Query(returns => ActivityThread!, { nullable: true, description: 'To fetch a ActivityThread' })\n async activityThread(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ActivityThread> {\n const { domain } = context.state\n\n const thread = await getRepository(ActivityThread).findOne({\n where: { domain: { id: domain.id }, id }\n })\n\n /* 없는 건은 없다고(null). 있는데 못 읽는 건은 이름 붙여 거절한다 — § assert-may-read.ts */\n if (thread) await assertMayReadThread(thread, context)\n\n return thread\n }\n\n @Directive('@privilege(category: \"activity-instance\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ActivityThreadList, { description: 'To fetch multiple ActivityThreads' })\n async activityThreads(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: getRepository(ActivityThread),\n searchables: ['name', 'description']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ActivityThreadList, { description: 'To fetch my own ActivityThreads' })\n async todoList(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n var { domain, user } = context.state\n\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n /* 정렬은 아래에서 직접 건다(applyTodoSortings 머리말) — 여기에 넘기면 NULL 자리를 못 정한다. */\n params: { ...params, sortings: [] },\n domain,\n alias: 'at',\n searchables: ['name', 'description'],\n filtersMap: {\n name: { columnName: 'name', relationColumn: 'activityInstance' },\n description: { columnName: 'description', relationColumn: 'activityInstance' },\n priority: { columnName: 'priority', relationColumn: 'activityInstance' }\n }\n })\n .innerJoinAndSelect('at.activityInstance', 'ai')\n /* 「내 앞에 있는 일」의 정의는 한 자리에 있다 — 달력도 같은 것을 읽는다. */\n .andWhere(myOpenThreadsWhere({ userId: user.id, roles }))\n\n applyTodoSortings(queryBuilder, params.sortings || [])\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ActivityThreadList, { description: 'To fetch the tasks(ActivityThreads) which has done by me' })\n async doneList(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n var { domain, user } = context.state\n\n const status = [ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n const [items, total] = await getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n params,\n domain,\n alias: 'at',\n searchables: ['name', 'description'],\n filtersMap: {\n name: { columnName: 'name', relationColumn: 'activityInstance' },\n description: { columnName: 'description', relationColumn: 'activityInstance' },\n priority: { columnName: 'priority', relationColumn: 'activityInstance' }\n }\n })\n .andWhere('at.state IN (:...status)', { status })\n .andWhere('at.assignee = :user', { user: user.id })\n .getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => User)\n async assignee(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.assigneeId\n ? activityThread.assignee || (await getRepository(User).findOneBy({ id: activityThread.assigneeId }))\n : null\n }\n\n @FieldResolver(type => ActivityInstance)\n async activityInstance(@Root() activityThread: ActivityThread): Promise<ActivityInstance> {\n return await getRepository(ActivityInstance).findOneBy({ id: activityThread.activityInstanceId })\n }\n\n @FieldResolver(type => [ActivityApproval])\n async activityApprovals(\n @Root() activityThread: ActivityThread,\n @Ctx() context: ResolverContext\n ): Promise<ActivityApproval[]> {\n return await getRepository(ActivityApproval).findBy({\n activityThread: { id: activityThread.id }\n })\n }\n\n @FieldResolver(type => [ActivityThreadHistory])\n async activityThreadHistories(\n @Root() activityThread: ActivityThread,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadHistory[]> {\n return await getRepository(ActivityThreadHistory).find({\n where: {\n originalId: activityThread.id\n },\n order: {\n version: 'ASC'\n }\n })\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() activityThread: ActivityThread): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: activityThread.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.updaterId && (await getRepository(User).findOneBy({ id: activityThread.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.creatorId && (await getRepository(User).findOneBy({ id: activityThread.creatorId }))\n }\n\n @FieldResolver(type => User)\n async terminator(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.terminatorId && (await getRepository(User).findOneBy({ id: activityThread.terminatorId }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-thread-query.js","sourceRoot":"","sources":["../../../server/service/activity-thread/activity-thread-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { ActivityInstance } from '../activity-instance/activity-instance.js'\nimport { ActivityThread, ActivityThreadStatus } from './activity-thread.js'\nimport { FINISHED, myOpenThreadsWhere, myThreadsOfOthersWhere, WAITING_ON_OTHERS } from './my-open-threads.js'\nimport { assertMayReadThread } from '../../controllers/activity-read/assert-may-read.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { ActivityThreadList } from './activity-thread-type.js'\nimport { ActivityThreadHistory } from './activity-thread-history.js'\nimport { TODO_INSTANCE_SORTS, todoOrderTerms } from './todo-order.js'\n\n\n/**\n * 「할 일」 목록의 정렬 — **기한이 없는 것은 뒤로 간다.**\n *\n * ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────\n * 화면의 기본 정렬은 `dueAt` 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에\n * 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.\n *\n * NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저, postgres 는\n * 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.\n *\n * ── 왜 NULLS LAST 를 쓰지 않나 ─────────────────────────────────────────────\n * `ORDER BY ... NULLS LAST` 는 postgres · oracle 문법이다. mysql · mssql 에서는 구문 오류가 난다.\n * 이 프레임워크는 다섯 드라이버를 다 지켜야 한다.\n *\n * `CASE WHEN ... IS NULL THEN 1 ELSE 0 END` 는 표준 SQL 이고 다섯 곳에서 다 돈다. 컬럼 이름은\n * 손으로 적지 않고 TypeORM 의 메타데이터에서 꺼낸다 — 이 프로젝트의 명명 규칙이 snake_case 라\n * `dueAt` 은 실제로 `due_at` 이다(shell 의 NamingStrategy).\n *\n * ── 공용 함수를 고치지 않는다 ──────────────────────────────────────────────\n * `getQueryBuilderFromListParams` 는 136개 꾸러미가 함께 쓴다. 정렬은 이 목록의 사정이므로\n * 여기서 맡는다 — 그 함수에는 정렬을 넘기지 않고(빈 배열) 아래에서 직접 건다.\n */\n\nfunction applyTodoSortings(queryBuilder: any, sortings: { name: string; desc?: boolean }[]) {\n const terms = todoOrderTerms(sortings, name => {\n const alias = TODO_INSTANCE_SORTS.has(name) ? 'ai' : 'at'\n const metadata = getRepository(alias === 'ai' ? ActivityInstance : ActivityThread).metadata\n const column = metadata.findColumnWithPropertyName(name)\n\n if (!column) {\n return undefined\n }\n\n const escape = (part: string) => queryBuilder.connection.driver.escape(part)\n\n return `${escape(alias)}.${escape(column.databaseName)}`\n })\n\n terms.forEach(({ expression, direction, select }, index) => {\n /* 식은 select 에 이름 붙여 올린다 — orderBy 는 식을 못 받는다(todo-order 머리말). */\n if (select) {\n queryBuilder.addSelect(select, expression)\n }\n\n index === 0 ? queryBuilder.orderBy(expression, direction) : queryBuilder.addOrderBy(expression, direction)\n })\n}\n\n@Resolver(ActivityThread)\nexport class ActivityThreadQuery {\n @Query(returns => ActivityThread!, { nullable: true, description: 'To fetch a ActivityThread' })\n async activityThread(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ActivityThread> {\n const { domain } = context.state\n\n const thread = await getRepository(ActivityThread).findOne({\n where: { domain: { id: domain.id }, id }\n })\n\n /* 없는 건은 없다고(null). 있는데 못 읽는 건은 이름 붙여 거절한다 — § assert-may-read.ts */\n if (thread) await assertMayReadThread(thread, context)\n\n return thread\n }\n\n @Directive('@privilege(category: \"activity-instance\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ActivityThreadList, { description: 'To fetch multiple ActivityThreads' })\n async activityThreads(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: getRepository(ActivityThread),\n searchables: ['name', 'description']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ActivityThreadList, { description: 'To fetch my own ActivityThreads' })\n async todoList(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n var { domain, user } = context.state\n\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n /* 정렬은 아래에서 직접 건다(applyTodoSortings 머리말) — 여기에 넘기면 NULL 자리를 못 정한다. */\n params: { ...params, sortings: [] },\n domain,\n alias: 'at',\n searchables: ['name', 'description'],\n filtersMap: {\n name: { columnName: 'name', relationColumn: 'activityInstance' },\n description: { columnName: 'description', relationColumn: 'activityInstance' },\n priority: { columnName: 'priority', relationColumn: 'activityInstance' }\n }\n })\n .innerJoinAndSelect('at.activityInstance', 'ai')\n /* 「내 앞에 있는 일」의 정의는 한 자리에 있다 — 달력도 같은 것을 읽는다. */\n .andWhere(myOpenThreadsWhere({ userId: user.id, roles }))\n\n applyTodoSortings(queryBuilder, params.sortings || [])\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Query(returns => ActivityThreadList, {\n description: 'To fetch the tasks(ActivityThreads) I submitted that wait on an approval - of work someone else put up'\n })\n async submittedList(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n const { domain, user } = context.state\n\n return await this.myThreadsOfOthers(params, domain, user.id, WAITING_ON_OTHERS)\n }\n\n @Query(returns => ActivityThreadList, {\n description: 'To fetch the tasks(ActivityThreads) I finished - of work someone else put up'\n })\n async doneList(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadList> {\n const { domain, user } = context.state\n\n return await this.myThreadsOfOthers(params, domain, user.id, FINISHED)\n }\n\n /** 할 일의 「제출한 것」·「완료」 — 내가 올린 것은 상신함이 따라간다(myThreadsOfOthersWhere). */\n private async myThreadsOfOthers(\n params: ListParam,\n domain: Domain,\n userId: string,\n states: ActivityThreadStatus[]\n ): Promise<ActivityThreadList> {\n const [items, total] = await getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n params,\n domain,\n alias: 'at',\n searchables: ['name', 'description'],\n filtersMap: {\n name: { columnName: 'name', relationColumn: 'activityInstance' },\n description: { columnName: 'description', relationColumn: 'activityInstance' },\n priority: { columnName: 'priority', relationColumn: 'activityInstance' }\n }\n })\n .innerJoinAndSelect('at.activityInstance', 'ai')\n .andWhere(myThreadsOfOthersWhere({ userId, states }))\n .getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => User)\n async assignee(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.assigneeId\n ? activityThread.assignee || (await getRepository(User).findOneBy({ id: activityThread.assigneeId }))\n : null\n }\n\n @FieldResolver(type => ActivityInstance)\n async activityInstance(@Root() activityThread: ActivityThread): Promise<ActivityInstance> {\n return await getRepository(ActivityInstance).findOneBy({ id: activityThread.activityInstanceId })\n }\n\n @FieldResolver(type => [ActivityApproval])\n async activityApprovals(\n @Root() activityThread: ActivityThread,\n @Ctx() context: ResolverContext\n ): Promise<ActivityApproval[]> {\n return await getRepository(ActivityApproval).findBy({\n activityThread: { id: activityThread.id }\n })\n }\n\n @FieldResolver(type => [ActivityThreadHistory])\n async activityThreadHistories(\n @Root() activityThread: ActivityThread,\n @Ctx() context: ResolverContext\n ): Promise<ActivityThreadHistory[]> {\n return await getRepository(ActivityThreadHistory).find({\n where: {\n originalId: activityThread.id\n },\n order: {\n version: 'ASC'\n }\n })\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() activityThread: ActivityThread): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: activityThread.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.updaterId && (await getRepository(User).findOneBy({ id: activityThread.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.creatorId && (await getRepository(User).findOneBy({ id: activityThread.creatorId }))\n }\n\n @FieldResolver(type => User)\n async terminator(@Root() activityThread: ActivityThread): Promise<User> {\n return activityThread.terminatorId && (await getRepository(User).findOneBy({ id: activityThread.terminatorId }))\n }\n}\n"]}
|
|
@@ -6,5 +6,5 @@ import { ActivityThreadHistoryQuery } from "./activity-thread-history-query.js";
|
|
|
6
6
|
import { ActivityThreadSubscription } from "./activity-thread-subscription.js";
|
|
7
7
|
import { ActivityThreadHistoryEntitySubscriber, ActivityThreadSubscriber } from "./event-subscriber.js";
|
|
8
8
|
export declare const entities: (typeof ActivityThread | typeof ActivityThreadHistory)[];
|
|
9
|
-
export declare const resolvers: (typeof
|
|
9
|
+
export declare const resolvers: (typeof ActivityThreadQuery | typeof ActivityThreadHistoryQuery | typeof ActivityThreadMutation | typeof ActivityThreadSubscription)[];
|
|
10
10
|
export declare const subscribers: (typeof ActivityThreadSubscriber | typeof ActivityThreadHistoryEntitySubscriber)[];
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Brackets } from 'typeorm';
|
|
2
|
+
import { ActivityThreadStatus } from './activity-thread.js';
|
|
3
|
+
/** A thread I submitted, waiting on someone's judgment. */
|
|
4
|
+
export declare const WAITING_ON_OTHERS: ActivityThreadStatus[];
|
|
5
|
+
/** A thread that is over. */
|
|
6
|
+
export declare const FINISHED: ActivityThreadStatus[];
|
|
2
7
|
/**
|
|
3
|
-
* The work that is on my plate — one definition,
|
|
8
|
+
* The work that is on my plate — one definition, three readers.
|
|
4
9
|
*
|
|
5
|
-
* 할 일 목록 asks this, and so
|
|
6
|
-
* way of being assigned, lands in one and not the other, and the
|
|
7
|
-
* different
|
|
10
|
+
* 할 일 목록 asks this, and so do the calendar and the badge (open-work). Written twice they drift:
|
|
11
|
+
* a new state, or a new way of being assigned, lands in one and not the other, and the badge says
|
|
12
|
+
* a different number than the list it opens. Nothing errors.
|
|
8
13
|
*
|
|
9
14
|
* Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
|
|
10
15
|
* reads assigneeRole off the instance.
|
|
@@ -13,3 +18,17 @@ export declare function myOpenThreadsWhere({ userId, roles }: {
|
|
|
13
18
|
userId: string;
|
|
14
19
|
roles: string[];
|
|
15
20
|
}): Brackets;
|
|
21
|
+
/**
|
|
22
|
+
* My threads in these states, of work **someone else** put up.
|
|
23
|
+
*
|
|
24
|
+
* What I put up myself is followed in 상신함 — the box of what I gave others to do. A post thread
|
|
25
|
+
* is mine only as the vehicle of my request: once submitted it waits on the approvers, and when it
|
|
26
|
+
* ends it is my request that ended. Listing it again under 할 일 put one fact in two boxes. While it
|
|
27
|
+
* is my turn - rejected and back with me - it stays in 할 일, which is myOpenThreadsWhere above.
|
|
28
|
+
*
|
|
29
|
+
* Expects `at` and `ai` joined.
|
|
30
|
+
*/
|
|
31
|
+
export declare function myThreadsOfOthersWhere({ userId, states }: {
|
|
32
|
+
userId: string;
|
|
33
|
+
states: ActivityThreadStatus[];
|
|
34
|
+
}): Brackets;
|
|
@@ -1,32 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FINISHED = exports.WAITING_ON_OTHERS = void 0;
|
|
3
4
|
exports.myOpenThreadsWhere = myOpenThreadsWhere;
|
|
5
|
+
exports.myThreadsOfOthersWhere = myThreadsOfOthersWhere;
|
|
4
6
|
const typeorm_1 = require("typeorm");
|
|
5
7
|
const activity_thread_js_1 = require("./activity-thread.js");
|
|
6
8
|
/**
|
|
7
|
-
* Thread states that are **not**
|
|
9
|
+
* Thread states that are **not** my turn.
|
|
10
|
+
*
|
|
11
|
+
* Submitted and escalated wait on an approver: the thread is still assigned to me, but nothing I do
|
|
12
|
+
* moves it. Counting them made 할 일 say 1 to a person who had just put up an expenditure request
|
|
13
|
+
* and had nothing left to do (2026-10-16). They are the 「제출한 것」 group of the same box.
|
|
8
14
|
*
|
|
9
15
|
* Unassigned belongs here for the person branch only — a thread nobody holds is not on my plate
|
|
10
16
|
* until I claim it, and the role branch below is what surfaces it to the people who could.
|
|
11
17
|
*/
|
|
12
|
-
const
|
|
18
|
+
const NOT_MY_TURN = [
|
|
13
19
|
activity_thread_js_1.ActivityThreadStatus.Unassigned,
|
|
20
|
+
activity_thread_js_1.ActivityThreadStatus.Submitted,
|
|
21
|
+
activity_thread_js_1.ActivityThreadStatus.Escalated,
|
|
14
22
|
activity_thread_js_1.ActivityThreadStatus.Ended,
|
|
15
23
|
activity_thread_js_1.ActivityThreadStatus.Aborted
|
|
16
24
|
];
|
|
25
|
+
/** A thread I submitted, waiting on someone's judgment. */
|
|
26
|
+
exports.WAITING_ON_OTHERS = [activity_thread_js_1.ActivityThreadStatus.Submitted, activity_thread_js_1.ActivityThreadStatus.Escalated];
|
|
27
|
+
/** A thread that is over. */
|
|
28
|
+
exports.FINISHED = [activity_thread_js_1.ActivityThreadStatus.Ended, activity_thread_js_1.ActivityThreadStatus.Aborted];
|
|
17
29
|
/**
|
|
18
|
-
* The work that is on my plate — one definition,
|
|
30
|
+
* The work that is on my plate — one definition, three readers.
|
|
19
31
|
*
|
|
20
|
-
* 할 일 목록 asks this, and so
|
|
21
|
-
* way of being assigned, lands in one and not the other, and the
|
|
22
|
-
* different
|
|
32
|
+
* 할 일 목록 asks this, and so do the calendar and the badge (open-work). Written twice they drift:
|
|
33
|
+
* a new state, or a new way of being assigned, lands in one and not the other, and the badge says
|
|
34
|
+
* a different number than the list it opens. Nothing errors.
|
|
23
35
|
*
|
|
24
36
|
* Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
|
|
25
37
|
* reads assigneeRole off the instance.
|
|
26
38
|
*/
|
|
27
39
|
function myOpenThreadsWhere({ userId, roles }) {
|
|
28
40
|
return new typeorm_1.Brackets(qb => {
|
|
29
|
-
qb.where('at.state NOT IN (:...
|
|
41
|
+
qb.where('at.state NOT IN (:...notMyTurn)', { notMyTurn: NOT_MY_TURN }).andWhere('at.assignee = :userId', {
|
|
42
|
+
userId
|
|
43
|
+
});
|
|
30
44
|
/* 역할로 걸린 것은 아직 임자가 없다 — 그 역할을 가진 사람 모두의 할 일이다. */
|
|
31
45
|
if (roles.length > 0) {
|
|
32
46
|
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
@@ -37,4 +51,21 @@ function myOpenThreadsWhere({ userId, roles }) {
|
|
|
37
51
|
}
|
|
38
52
|
});
|
|
39
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* My threads in these states, of work **someone else** put up.
|
|
56
|
+
*
|
|
57
|
+
* What I put up myself is followed in 상신함 — the box of what I gave others to do. A post thread
|
|
58
|
+
* is mine only as the vehicle of my request: once submitted it waits on the approvers, and when it
|
|
59
|
+
* ends it is my request that ended. Listing it again under 할 일 put one fact in two boxes. While it
|
|
60
|
+
* is my turn - rejected and back with me - it stays in 할 일, which is myOpenThreadsWhere above.
|
|
61
|
+
*
|
|
62
|
+
* Expects `at` and `ai` joined.
|
|
63
|
+
*/
|
|
64
|
+
function myThreadsOfOthersWhere({ userId, states }) {
|
|
65
|
+
return new typeorm_1.Brackets(qb => {
|
|
66
|
+
qb.where('at.assignee = :userId', { userId })
|
|
67
|
+
.andWhere('at.state IN (:...states)', { states })
|
|
68
|
+
.andWhere('(ai.creator IS NULL OR ai.creator != :userId)', { userId });
|
|
69
|
+
});
|
|
70
|
+
}
|
|
40
71
|
//# sourceMappingURL=my-open-threads.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"my-open-threads.js","sourceRoot":"","sources":["../../../server/service/activity-thread/my-open-threads.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"my-open-threads.js","sourceRoot":"","sources":["../../../server/service/activity-thread/my-open-threads.ts"],"names":[],"mappings":";;;AAsCA,gDAiBC;AAYD,wDAMC;AAzED,qCAAkC;AAElC,6DAA2D;AAE3D;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG;IAClB,yCAAoB,CAAC,UAAU;IAC/B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,KAAK;IAC1B,yCAAoB,CAAC,OAAO;CAC7B,CAAA;AAED,2DAA2D;AAC9C,QAAA,iBAAiB,GAAG,CAAC,yCAAoB,CAAC,SAAS,EAAE,yCAAoB,CAAC,SAAS,CAAC,CAAA;AAEjG,6BAA6B;AAChB,QAAA,QAAQ,GAAG,CAAC,yCAAoB,CAAC,KAAK,EAAE,yCAAoB,CAAC,OAAO,CAAC,CAAA;AAElF;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAuC;IACvF,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,uBAAuB,EAAE;YACxG,MAAM;SACP,CAAC,CAAA;QAEF,kDAAkD;QAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,EAAE,CAAC,OAAO,CACR,IAAI,kBAAQ,CAAC,KAAK,CAAC,EAAE;gBACnB,KAAK;qBACF,KAAK,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC;qBAClD,QAAQ,CAAC,wBAAwB,EAAE,EAAE,UAAU,EAAE,yCAAoB,CAAC,UAAU,EAAE,CAAC,CAAA;YACxF,CAAC,CAAC,CACH,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,sBAAsB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAsD;IAC3G,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,CAAC;aAC1C,QAAQ,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,CAAC;aAChD,QAAQ,CAAC,+CAA+C,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { Brackets } from 'typeorm'\n\nimport { ActivityThreadStatus } from './activity-thread.js'\n\n/**\n * Thread states that are **not** my turn.\n *\n * Submitted and escalated wait on an approver: the thread is still assigned to me, but nothing I do\n * moves it. Counting them made 할 일 say 1 to a person who had just put up an expenditure request\n * and had nothing left to do (2026-10-16). They are the 「제출한 것」 group of the same box.\n *\n * Unassigned belongs here for the person branch only — a thread nobody holds is not on my plate\n * until I claim it, and the role branch below is what surfaces it to the people who could.\n */\nconst NOT_MY_TURN = [\n ActivityThreadStatus.Unassigned,\n ActivityThreadStatus.Submitted,\n ActivityThreadStatus.Escalated,\n ActivityThreadStatus.Ended,\n ActivityThreadStatus.Aborted\n]\n\n/** A thread I submitted, waiting on someone's judgment. */\nexport const WAITING_ON_OTHERS = [ActivityThreadStatus.Submitted, ActivityThreadStatus.Escalated]\n\n/** A thread that is over. */\nexport const FINISHED = [ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n/**\n * The work that is on my plate — one definition, three readers.\n *\n * 할 일 목록 asks this, and so do the calendar and the badge (open-work). Written twice they drift:\n * a new state, or a new way of being assigned, lands in one and not the other, and the badge says\n * a different number than the list it opens. Nothing errors.\n *\n * Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch\n * reads assigneeRole off the instance.\n */\nexport function myOpenThreadsWhere({ userId, roles }: { userId: string; roles: string[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.state NOT IN (:...notMyTurn)', { notMyTurn: NOT_MY_TURN }).andWhere('at.assignee = :userId', {\n userId\n })\n\n /* 역할로 걸린 것은 아직 임자가 없다 — 그 역할을 가진 사람 모두의 할 일이다. */\n if (roles.length > 0) {\n qb.orWhere(\n new Brackets(subQb => {\n subQb\n .where('ai.assigneeRole IN (:...roles)', { roles })\n .andWhere('at.state = :unassigned', { unassigned: ActivityThreadStatus.Unassigned })\n })\n )\n }\n })\n}\n\n/**\n * My threads in these states, of work **someone else** put up.\n *\n * What I put up myself is followed in 상신함 — the box of what I gave others to do. A post thread\n * is mine only as the vehicle of my request: once submitted it waits on the approvers, and when it\n * ends it is my request that ended. Listing it again under 할 일 put one fact in two boxes. While it\n * is my turn - rejected and back with me - it stays in 할 일, which is myOpenThreadsWhere above.\n *\n * Expects `at` and `ai` joined.\n */\nexport function myThreadsOfOthersWhere({ userId, states }: { userId: string; states: ActivityThreadStatus[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.assignee = :userId', { userId })\n .andWhere('at.state IN (:...states)', { states })\n .andWhere('(ai.creator IS NULL OR ai.creator != :userId)', { userId })\n })\n}\n"]}
|
|
@@ -16,8 +16,8 @@ export * from './work-door/work-door-not-used.js';
|
|
|
16
16
|
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
|
-
export declare const entities: (typeof import("./activity/activity.js").
|
|
20
|
-
export declare const subscribers: (typeof import("./activity-
|
|
19
|
+
export declare const entities: (typeof import("./activity-thread/activity-thread.js").ActivityThread | typeof import("./activity-thread/activity-thread-history.js").ActivityThreadHistory | typeof import("./activity-approval/activity-approval.js").ActivityApproval | typeof import("./activity/activity.js").Activity | typeof import("./activity/activity-history.js").ActivityHistory | typeof import("./activity-instance/activity-instance.js").ActivityInstance | typeof import("./activity-instance/activity-instance-history.js").ActivityInstanceHistory | typeof import("./activity-template/activity-template.js").ActivityTemplate | typeof import("./activity-template/activity-template-history.js").ActivityTemplateHistory | typeof import("./installable-activity/installable-activity.js").InstallableActivity | typeof import("./activity-summary/activity-summary.js").ActivitySummary | typeof import("./work-door/work-door-not-used.js").WorkDoorNotUsed | typeof import("./work-door/work-door-journal.js").WorkDoorJournal)[];
|
|
20
|
+
export declare const subscribers: (typeof import("./activity-thread/event-subscriber.js").ActivityThreadSubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadHistoryEntitySubscriber | typeof import("./activity-approval/event-subscriber.js").ActivityApprovalSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceHistoryEntitySubscriber | typeof import("./activity/event-subscriber.js").ActivityHistoryEntitySubscriber | typeof import("./activity/declaration-guard-subscriber.js").ActivityDeclarationGuardSubscriber)[];
|
|
21
21
|
export declare const schema: {
|
|
22
|
-
resolverClasses: (typeof import("./activity-
|
|
22
|
+
resolverClasses: (typeof import("./activity-summary/person-open-work.js").PersonOpenWorkQuery | typeof import("./activity-summary/activity-summary-query.js").ActivitySummaryQuery | 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-mutation.js").ActivityThreadMutation | typeof import("./activity-thread/activity-thread-subscription.js").ActivityThreadSubscription | 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-query.js").ActivityQuery | typeof import("./activity/activity-mutation.js").ActivityMutation | typeof import("./activity-instance/activity-instance-query.js").ActivityInstanceQuery | typeof import("./activity-instance/activity-instance-mutation.js").ActivityInstanceMutation | typeof import("./activity-instance/activity-instance-subscription.js").ActivityInstanceSubscription | typeof import("./activity-template/activity-template-query.js").ActivityTemplateQuery | typeof import("./activity-template/activity-template-mutation.js").ActivityTemplateMutation | typeof import("./installable-activity/installable-activity-query.js").InstallableActivityQuery | typeof import("./installable-activity/installable-activity-mutation.js").InstallableActivityMutation | typeof import("./work-door/work-door-resolver.js").WorkDoorResolver)[];
|
|
23
23
|
};
|
|
@@ -58,6 +58,10 @@ export interface ApprovalSeat {
|
|
|
58
58
|
type?: string;
|
|
59
59
|
/** 역할이면 role id, 사람이면 user id. */
|
|
60
60
|
value?: string;
|
|
61
|
+
/** 편집기가 고른 대상. 편집기는 `value` 를 안 쓰고 여기에만 적는다(§`seatRoleId`). */
|
|
62
|
+
approver?: {
|
|
63
|
+
id?: string;
|
|
64
|
+
};
|
|
61
65
|
/** 비어 있으면 결재다(`ApprovalLineItem.participation` 의 규약). */
|
|
62
66
|
participation?: string;
|
|
63
67
|
}
|
|
@@ -87,6 +91,16 @@ export interface ApprovalSeatReader {
|
|
|
87
91
|
/** 지목한 그 사람이 이 공장에 있고 계정이 붙어 있나. */
|
|
88
92
|
personIsHere(personId: string): Promise<boolean>;
|
|
89
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* A seat's role, read the way submission reads it (`create-approval`, `resolve-judgeable-seats`).
|
|
96
|
+
*
|
|
97
|
+
* The approval line editor writes what it picked under `approver` and leaves `value` empty; seeded
|
|
98
|
+
* lines carry both. Reading `value` alone here drew 「결재자 없음」 on the door screen for a line that
|
|
99
|
+
* submits. One function, so the screen and submission cannot read a seat two ways again.
|
|
100
|
+
*/
|
|
101
|
+
export declare function seatRoleId(seat?: ApprovalSeat | null): string | undefined;
|
|
102
|
+
/** A person seat, read the way submission reads it (`getSystemUserFromOrgMemberItem`: approver first). */
|
|
103
|
+
export declare function seatPersonId(seat?: ApprovalSeat | null): string | undefined;
|
|
90
104
|
export declare function judgeApprovalLine(line: ApprovalSeat[] | undefined | null, reader: ApprovalSeatReader): Promise<ApprovalLineStanding>;
|
|
91
105
|
/** 결재선에서 **역할을 지목한 자리**의 id 들 — 부르는 쪽이 미리 읽어 둘 때 쓴다. */
|
|
92
106
|
export declare function rolesNamedIn(line: ApprovalSeat[] | undefined | null): string[];
|