@things-factory/worklist 10.1.269 → 10.1.270
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-instance-ribon.js +3 -2
- package/dist-client/components/activity-instance-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-ribon.js +3 -2
- package/dist-client/components/activity-thread-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-timeline.d.ts +2 -2
- package/dist-client/components/activity-thread-timeline.js +3 -1
- package/dist-client/components/activity-thread-timeline.js.map +1 -1
- package/dist-client/components/decision-content.js +1 -1
- package/dist-client/components/decision-content.js.map +1 -1
- package/dist-client/components/ribon-description.d.ts +13 -0
- package/dist-client/components/ribon-description.js +14 -0
- package/dist-client/components/ribon-description.js.map +1 -0
- package/dist-client/components/source-link.d.ts +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.d.ts +2 -2
- package/dist-client/pages/activity-thread/activity-thread-page.d.ts +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +3 -0
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view.d.ts +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/activity-installation/activity-installation-controller.js +5 -0
- package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
- package/dist-server/controllers/activity-instance/complete.d.ts +6 -1
- package/dist-server/controllers/activity-instance/complete.js +6 -1
- package/dist-server/controllers/activity-instance/complete.js.map +1 -1
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +5 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/activity/finished-case.d.ts +28 -0
- package/dist-server/service/activity/finished-case.js +38 -0
- package/dist-server/service/activity/finished-case.js.map +1 -0
- package/dist-server/service/activity-approval/index.d.ts +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 +2 -1
- package/translations/es.json +2 -1
- package/translations/ja.json +2 -1
- package/translations/ko.json +6 -5
- package/translations/ms.json +2 -1
- package/translations/zh.json +2 -1
|
@@ -7,6 +7,7 @@ const activity_js_1 = require("../../service/activity/activity.js");
|
|
|
7
7
|
const registry_conflict_js_1 = require("./registry-conflict.js");
|
|
8
8
|
const decision_key_declaration_js_1 = require("../../service/activity/decision-key-declaration.js");
|
|
9
9
|
const installable_to_activity_js_1 = require("./installable-to-activity.js");
|
|
10
|
+
const finished_case_js_1 = require("../../service/activity/finished-case.js");
|
|
10
11
|
/**
|
|
11
12
|
* 등록된 양식을 **도메인에 실제로 세운다.**
|
|
12
13
|
*
|
|
@@ -57,6 +58,10 @@ class ActivityInstallations {
|
|
|
57
58
|
static installActivityTemplate(template) {
|
|
58
59
|
(0, registry_conflict_js_1.assertNotDeclaredIntended)(template.name, ActivityInstallations.intended);
|
|
59
60
|
(0, registry_conflict_js_1.assertDoorSlugIsFree)(template.name, decision_key_declaration_js_1.doorSlug, ActivityInstallations.templates);
|
|
61
|
+
/* Said, not refused: activities registered before the rule still install; their module's test holds them to it. */
|
|
62
|
+
const empty = (0, finished_case_js_1.finishedCaseShowsNothing)(template);
|
|
63
|
+
if (empty)
|
|
64
|
+
console.warn(`[worklist] ${empty} (finished-case.ts)`);
|
|
60
65
|
ActivityInstallations.templates[template.name] = template;
|
|
61
66
|
}
|
|
62
67
|
/**
|
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":";;;
|
|
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'\nimport { finishedCaseShowsNothing } from '../../service/activity/finished-case.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 /* Said, not refused: activities registered before the rule still install; their module's test holds them to it. */\n const empty = finishedCaseShowsNothing(template as any)\n if (empty) console.warn(`[worklist] ${empty} (finished-case.ts)`)\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"]}
|
|
@@ -6,8 +6,13 @@ import { ActivityInstance } from '../../service/activity-instance/activity-insta
|
|
|
6
6
|
*
|
|
7
7
|
* For the module that issued the case and judges its work (an application's own to-do); a person ends their own
|
|
8
8
|
* thread through the thread's `end`.
|
|
9
|
+
*
|
|
10
|
+
* `output` is what was done, in the activity's declared output fields - the finished case shows it, as it shows what a
|
|
11
|
+
* person wrote when they end their own thread. A module that closed its to-do with only a reason left the finished
|
|
12
|
+
* screen with nothing to show of how it ended (2026-11-11, 문의 할 일).
|
|
9
13
|
*/
|
|
10
|
-
export declare function complete({ id, reason }: {
|
|
14
|
+
export declare function complete({ id, reason, output }: {
|
|
11
15
|
id: string;
|
|
12
16
|
reason?: string;
|
|
17
|
+
output?: Record<string, any>;
|
|
13
18
|
}, context: ResolverContext): Promise<ActivityInstance>;
|
|
@@ -12,8 +12,12 @@ const common_js_1 = require("../common.js");
|
|
|
12
12
|
*
|
|
13
13
|
* For the module that issued the case and judges its work (an application's own to-do); a person ends their own
|
|
14
14
|
* thread through the thread's `end`.
|
|
15
|
+
*
|
|
16
|
+
* `output` is what was done, in the activity's declared output fields - the finished case shows it, as it shows what a
|
|
17
|
+
* person wrote when they end their own thread. A module that closed its to-do with only a reason left the finished
|
|
18
|
+
* screen with nothing to show of how it ended (2026-11-11, 문의 할 일).
|
|
15
19
|
*/
|
|
16
|
-
async function complete({ id, reason }, context) {
|
|
20
|
+
async function complete({ id, reason, output }, context) {
|
|
17
21
|
const { domain, user, tx } = context.state;
|
|
18
22
|
const repository = tx.getRepository(activity_instance_js_1.ActivityInstance);
|
|
19
23
|
const activityInstance = await repository.findOne({
|
|
@@ -35,6 +39,7 @@ async function complete({ id, reason }, context) {
|
|
|
35
39
|
await threads.save({
|
|
36
40
|
...thread,
|
|
37
41
|
reason,
|
|
42
|
+
...(output ? { output: { ...(thread.output ?? {}), ...output } } : {}),
|
|
38
43
|
state: activity_thread_js_1.ActivityThreadStatus.Ended,
|
|
39
44
|
transaction: 'end',
|
|
40
45
|
startedAt: thread.startedAt ?? now,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../server/controllers/activity-instance/complete.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../server/controllers/activity-instance/complete.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\n\nimport { ActivityThread, ActivityThreadStatus } from '../../service/activity-thread/activity-thread.js'\nimport { ActivityInstance, ActivityInstanceStatus } from '../../service/activity-instance/activity-instance.js'\nimport { evalActivityInstanceState } from '../common.js'\n\n/**\n * Ends a case whose work is done - every thread still open ends as done, then the case ends. The counterpart of\n * `abort` for a to-do the records show finished: a case handed to several people, or to whoever holds a role, is\n * done for all of them when its work is done, and its history says ended, not aborted.\n *\n * For the module that issued the case and judges its work (an application's own to-do); a person ends their own\n * thread through the thread's `end`.\n *\n * `output` is what was done, in the activity's declared output fields - the finished case shows it, as it shows what a\n * person wrote when they end their own thread. A module that closed its to-do with only a reason left the finished\n * screen with nothing to show of how it ended (2026-11-11, 문의 할 일).\n */\nexport async function complete(\n { id, reason, output }: { id: string; reason?: string; output?: Record<string, any> },\n context: ResolverContext\n): Promise<ActivityInstance> {\n const { domain, user, tx } = context.state\n const repository = tx.getRepository(ActivityInstance)\n\n const activityInstance = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['domain', 'activity', 'activityThreads', 'assigneeRoles', 'supervisoryRole', 'updater', 'creator', 'starter', 'terminator']\n })\n\n if (!activityInstance) {\n throw new Error(context.t('error.activity-instance not found', { activityInstance: id }))\n }\n\n if (activityInstance.state == ActivityInstanceStatus.Aborted || activityInstance.state == ActivityInstanceStatus.Ended) {\n throw new Error(context.t(`error.activity-instance is already terminated`, { id, state: activityInstance.state }))\n }\n\n const TERMINATED = [ActivityThreadStatus.Aborted, ActivityThreadStatus.Ended]\n const open = (activityInstance.activityThreads ?? []).filter(thread => !TERMINATED.includes(thread.state))\n const now = new Date()\n if (open.length) {\n const threads = tx.getRepository(ActivityThread)\n for (const thread of await threads.find({ where: { id: In(open.map(one => one.id)) } })) {\n await threads.save({\n ...thread,\n reason,\n ...(output ? { output: { ...(thread.output ?? {}), ...output } } : {}),\n state: ActivityThreadStatus.Ended,\n transaction: 'end',\n startedAt: thread.startedAt ?? now,\n updater: user,\n terminatedAt: now\n })\n }\n }\n\n return await repository.save({\n ...activityInstance,\n activityThreads: undefined,\n reason,\n ...(await evalActivityInstanceState(id, context)),\n startedAt: activityInstance.startedAt ?? now,\n transaction: 'end',\n updater: user,\n terminatedAt: now,\n terminator: user\n } as any)\n}\n"]}
|
package/dist-server/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export * from './controllers/index.js';
|
|
|
3
3
|
export * from './service/index.js';
|
|
4
4
|
export { freezeDecisionSentences, DecisionSentenceMissing } from '../shared/decision-sentences.js';
|
|
5
5
|
export { freezeDecisionSentencesFor } from './service/activity/freeze-decision-sentences-for.js';
|
|
6
|
+
export { assertFinishedCaseShows, finishedCaseShowsNothing, outputFieldsOf } from './service/activity/finished-case.js';
|
|
6
7
|
export type { DecisionSentenceKey, Translate as DecisionSentenceTranslate } from '../shared/decision-sentences.js';
|
package/dist-server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.freezeDecisionSentencesFor = exports.DecisionSentenceMissing = exports.freezeDecisionSentences = void 0;
|
|
3
|
+
exports.outputFieldsOf = exports.finishedCaseShowsNothing = exports.assertFinishedCaseShows = exports.freezeDecisionSentencesFor = exports.DecisionSentenceMissing = exports.freezeDecisionSentences = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
require("./routes.js");
|
|
6
6
|
tslib_1.__exportStar(require("./controllers/index.js"), exports);
|
|
@@ -11,6 +11,10 @@ Object.defineProperty(exports, "freezeDecisionSentences", { enumerable: true, ge
|
|
|
11
11
|
Object.defineProperty(exports, "DecisionSentenceMissing", { enumerable: true, get: function () { return decision_sentences_js_1.DecisionSentenceMissing; } });
|
|
12
12
|
var freeze_decision_sentences_for_js_1 = require("./service/activity/freeze-decision-sentences-for.js");
|
|
13
13
|
Object.defineProperty(exports, "freezeDecisionSentencesFor", { enumerable: true, get: function () { return freeze_decision_sentences_for_js_1.freezeDecisionSentencesFor; } });
|
|
14
|
+
var finished_case_js_1 = require("./service/activity/finished-case.js");
|
|
15
|
+
Object.defineProperty(exports, "assertFinishedCaseShows", { enumerable: true, get: function () { return finished_case_js_1.assertFinishedCaseShows; } });
|
|
16
|
+
Object.defineProperty(exports, "finishedCaseShowsNothing", { enumerable: true, get: function () { return finished_case_js_1.finishedCaseShowsNothing; } });
|
|
17
|
+
Object.defineProperty(exports, "outputFieldsOf", { enumerable: true, get: function () { return finished_case_js_1.outputFieldsOf; } });
|
|
14
18
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
15
19
|
const role_tasks_js_1 = require("./role-tasks.js");
|
|
16
20
|
for (const task of role_tasks_js_1.ROLE_TASKS)
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB,iEAAsC;AACtC,6DAAkC;AAElC,sGAAsG;AACtG,yEAAkG;AAAzF,gIAAA,uBAAuB,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AACzD,wGAAgG;AAAvF,8IAAA,0BAA0B,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB,iEAAsC;AACtC,6DAAkC;AAElC,sGAAsG;AACtG,yEAAkG;AAAzF,gIAAA,uBAAuB,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AACzD,wGAAgG;AAAvF,8IAAA,0BAA0B,OAAA;AACnC,wEAAuH;AAA9G,2HAAA,uBAAuB,OAAA;AAAE,4HAAA,wBAAwB,OAAA;AAAE,kHAAA,cAAc,OAAA;AAG1E,yDAA4D;AAC5D,mDAA4C;AAE5C,KAAK,MAAM,IAAI,IAAI,0BAAU;IAAE,IAAA,4BAAgB,EAAC,IAAI,CAAC,CAAA","sourcesContent":["import './routes.js'\n\nexport * from './controllers/index.js'\nexport * from './service/index.js'\n\n/* Freezing an approval's value sentences — the same reading of the input the decision screen uses. */\nexport { freezeDecisionSentences, DecisionSentenceMissing } from '../shared/decision-sentences.js'\nexport { freezeDecisionSentencesFor } from './service/activity/freeze-decision-sentences-for.js'\nexport { assertFinishedCaseShows, finishedCaseShowsNothing, outputFieldsOf } from './service/activity/finished-case.js'\nexport type { DecisionSentenceKey, Translate as DecisionSentenceTranslate } from '../shared/decision-sentences.js'\n\nimport { registerRoleTask } from '@things-factory/auth-base'\nimport { ROLE_TASKS } from './role-tasks.js'\n\nfor (const task of ROLE_TASKS) registerRoleTask(task)\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a finished case of an activity shows anything - what was asked and what was done.
|
|
3
|
+
*
|
|
4
|
+
* The finished screen (activity-thread-view) draws, in order: the activity's own view when it names one (viewType with a
|
|
5
|
+
* viewSource), else the declared decision over the input (decisionKeys), the input fields a person can read, and the
|
|
6
|
+
* output fields what was done was written into. A module's own to-do that kept only a hidden key in its input (an
|
|
7
|
+
* inquiry id, a week), declared no decision and no output, and named no view, finished as an empty screen: the state, the
|
|
8
|
+
* times and nothing of what it was or how it ended (2026-11-11, 문의 할 일 and five more like it).
|
|
9
|
+
*
|
|
10
|
+
* Kept free of imports so the test runner can hold it.
|
|
11
|
+
*/
|
|
12
|
+
type Declared = {
|
|
13
|
+
name?: string;
|
|
14
|
+
viewType?: string;
|
|
15
|
+
viewSource?: string;
|
|
16
|
+
decisionKeys?: unknown[];
|
|
17
|
+
model?: {
|
|
18
|
+
hidden?: boolean;
|
|
19
|
+
inout?: string;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
/** Why a finished case of this activity would show nothing - undefined when it shows something. */
|
|
23
|
+
export declare function finishedCaseShowsNothing(activity: Declared): string | undefined;
|
|
24
|
+
/** For a module's own test: its activities' finished cases show what was asked and what was done. */
|
|
25
|
+
export declare function assertFinishedCaseShows(activity: Declared): void;
|
|
26
|
+
/** The output fields an activity declares - where `complete` writes what was done. */
|
|
27
|
+
export declare function outputFieldsOf(activity: Declared): string[];
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a finished case of an activity shows anything - what was asked and what was done.
|
|
4
|
+
*
|
|
5
|
+
* The finished screen (activity-thread-view) draws, in order: the activity's own view when it names one (viewType with a
|
|
6
|
+
* viewSource), else the declared decision over the input (decisionKeys), the input fields a person can read, and the
|
|
7
|
+
* output fields what was done was written into. A module's own to-do that kept only a hidden key in its input (an
|
|
8
|
+
* inquiry id, a week), declared no decision and no output, and named no view, finished as an empty screen: the state, the
|
|
9
|
+
* times and nothing of what it was or how it ended (2026-11-11, 문의 할 일 and five more like it).
|
|
10
|
+
*
|
|
11
|
+
* Kept free of imports so the test runner can hold it.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.finishedCaseShowsNothing = finishedCaseShowsNothing;
|
|
15
|
+
exports.assertFinishedCaseShows = assertFinishedCaseShows;
|
|
16
|
+
exports.outputFieldsOf = outputFieldsOf;
|
|
17
|
+
const MODULE_VIEWS = ['custom-element', 'template', 'board', 'page', 'external'];
|
|
18
|
+
/** Why a finished case of this activity would show nothing - undefined when it shows something. */
|
|
19
|
+
function finishedCaseShowsNothing(activity) {
|
|
20
|
+
if (activity.viewType && MODULE_VIEWS.includes(activity.viewType) && activity.viewSource)
|
|
21
|
+
return undefined;
|
|
22
|
+
if ((activity.decisionKeys ?? []).length)
|
|
23
|
+
return undefined;
|
|
24
|
+
if ((activity.model ?? []).some(field => !field.hidden && ['in', 'out', 'inout'].includes(String(field.inout))))
|
|
25
|
+
return undefined;
|
|
26
|
+
return `"${activity.name}" finishes as an empty screen: it names no view, declares no decision, and has no visible input or output field`;
|
|
27
|
+
}
|
|
28
|
+
/** For a module's own test: its activities' finished cases show what was asked and what was done. */
|
|
29
|
+
function assertFinishedCaseShows(activity) {
|
|
30
|
+
const empty = finishedCaseShowsNothing(activity);
|
|
31
|
+
if (empty)
|
|
32
|
+
throw new Error(empty);
|
|
33
|
+
}
|
|
34
|
+
/** The output fields an activity declares - where `complete` writes what was done. */
|
|
35
|
+
function outputFieldsOf(activity) {
|
|
36
|
+
return (activity.model ?? []).filter(field => ['out', 'inout'].includes(String(field.inout))).map(field => field.name);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=finished-case.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finished-case.js","sourceRoot":"","sources":["../../../server/service/activity/finished-case.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAaH,4DAMC;AAGD,0DAGC;AAGD,wCAEC;AA5BD,MAAM,YAAY,GAAG,CAAC,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAA;AAUhF,mGAAmG;AACnG,SAAgB,wBAAwB,CAAC,QAAkB;IACzD,IAAI,QAAQ,CAAC,QAAQ,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,UAAU;QAAE,OAAO,SAAS,CAAA;IAC1G,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM;QAAE,OAAO,SAAS,CAAA;IAC1D,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IAEjI,OAAO,IAAI,QAAQ,CAAC,IAAI,iHAAiH,CAAA;AAC3I,CAAC;AAED,qGAAqG;AACrG,SAAgB,uBAAuB,CAAC,QAAkB;IACxD,MAAM,KAAK,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAA;IAChD,IAAI,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAA;AACnC,CAAC;AAED,sFAAsF;AACtF,SAAgB,cAAc,CAAC,QAAkB;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAE,KAAa,CAAC,IAAI,CAAC,CAAA;AACjI,CAAC","sourcesContent":["/**\n * Whether a finished case of an activity shows anything - what was asked and what was done.\n *\n * The finished screen (activity-thread-view) draws, in order: the activity's own view when it names one (viewType with a\n * viewSource), else the declared decision over the input (decisionKeys), the input fields a person can read, and the\n * output fields what was done was written into. A module's own to-do that kept only a hidden key in its input (an\n * inquiry id, a week), declared no decision and no output, and named no view, finished as an empty screen: the state, the\n * times and nothing of what it was or how it ended (2026-11-11, 문의 할 일 and five more like it).\n *\n * Kept free of imports so the test runner can hold it.\n */\n\nconst MODULE_VIEWS = ['custom-element', 'template', 'board', 'page', 'external']\n\ntype Declared = {\n name?: string\n viewType?: string\n viewSource?: string\n decisionKeys?: unknown[]\n model?: { hidden?: boolean; inout?: string }[]\n}\n\n/** Why a finished case of this activity would show nothing - undefined when it shows something. */\nexport function finishedCaseShowsNothing(activity: Declared): string | undefined {\n if (activity.viewType && MODULE_VIEWS.includes(activity.viewType) && activity.viewSource) return undefined\n if ((activity.decisionKeys ?? []).length) return undefined\n if ((activity.model ?? []).some(field => !field.hidden && ['in', 'out', 'inout'].includes(String(field.inout)))) return undefined\n\n return `\"${activity.name}\" finishes as an empty screen: it names no view, declares no decision, and has no visible input or output field`\n}\n\n/** For a module's own test: its activities' finished cases show what was asked and what was done. */\nexport function assertFinishedCaseShows(activity: Declared): void {\n const empty = finishedCaseShowsNothing(activity)\n if (empty) throw new Error(empty)\n}\n\n/** The output fields an activity declares - where `complete` writes what was done. */\nexport function outputFieldsOf(activity: Declared): string[] {\n return (activity.model ?? []).filter(field => ['out', 'inout'].includes(String(field.inout))).map(field => (field as any).name)\n}\n"]}
|
|
@@ -4,5 +4,5 @@ import { ActivityApprovalMutation } from "./activity-approval-mutation.js";
|
|
|
4
4
|
import { ActivityApprovalSubscription } from "./activity-approval-subscription.js";
|
|
5
5
|
import { ActivityApprovalSubscriber } from "./event-subscriber.js";
|
|
6
6
|
export declare const entities: (typeof ActivityApproval)[];
|
|
7
|
-
export declare const resolvers: (typeof
|
|
7
|
+
export declare const resolvers: (typeof ActivityApprovalMutation | typeof ActivityApprovalQuery | typeof ActivityApprovalSubscription)[];
|
|
8
8
|
export declare const subscribers: (typeof ActivityApprovalSubscriber)[];
|
|
@@ -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-approval/event-subscriber.js").ActivityApprovalSubscriber | typeof import("./activity/event-subscriber.js").
|
|
20
|
+
export declare const entities: (typeof import("./activity/activity.js").Activity | typeof import("./activity-instance/activity-instance.js").ActivityInstance | typeof import("./activity-thread/activity-thread.js").ActivityThread | typeof import("./installable-activity/installable-activity.js").InstallableActivity | typeof import("./activity-approval/activity-approval.js").ActivityApproval | typeof import("./activity-instance/activity-instance-history.js").ActivityInstanceHistory | typeof import("./activity-thread/activity-thread-history.js").ActivityThreadHistory | typeof import("./activity/activity-history.js").ActivityHistory | typeof import("./activity-template/activity-template.js").ActivityTemplate | typeof import("./activity-template/activity-template-history.js").ActivityTemplateHistory | 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)[];
|
|
21
|
+
export declare const subscribers: (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-thread/event-subscriber.js").ActivityThreadSubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadHistoryEntitySubscriber | typeof import("./activity/event-subscriber.js").ActivityHistoryEntitySubscriber | typeof import("./activity/declaration-guard-subscriber.js").ActivityDeclarationGuardSubscriber)[];
|
|
22
22
|
export declare const schema: {
|
|
23
|
-
resolverClasses: (typeof import("./activity-approval/activity-approval-
|
|
23
|
+
resolverClasses: (typeof import("./activity-approval/activity-approval-mutation.js").ActivityApprovalMutation | typeof import("./activity-approval/activity-approval-query.js").ActivityApprovalQuery | typeof import("./activity-approval/activity-approval-subscription.js").ActivityApprovalSubscription | 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-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-stats/activity-stats-query.js").ActivityStatsQuery | typeof import("./activity/activity-query.js").ActivityQuery | typeof import("./activity/activity-mutation.js").ActivityMutation | typeof import("./activity-template/activity-template-query.js").ActivityTemplateQuery | typeof import("./activity-template/activity-template-mutation.js").ActivityTemplateMutation | 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
|
};
|