@things-factory/worklist 10.0.19 → 10.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/activity-cells.d.ts +21 -0
- package/dist-client/activity-cells.js +117 -0
- package/dist-client/activity-cells.js.map +1 -0
- package/dist-client/activity-summary-generator.js +57 -11
- package/dist-client/activity-summary-generator.js.map +1 -1
- package/dist-client/approval-progress.d.ts +18 -0
- package/dist-client/approval-progress.js +31 -0
- package/dist-client/approval-progress.js.map +1 -0
- package/dist-client/bootstrap.js +6 -11
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/chip-filters.d.ts +53 -0
- package/dist-client/chip-filters.js +60 -0
- package/dist-client/chip-filters.js.map +1 -0
- package/dist-client/components/activity-approval-ribon.d.ts +19 -0
- package/dist-client/components/activity-approval-ribon.js +50 -126
- package/dist-client/components/activity-approval-ribon.js.map +1 -1
- package/dist-client/components/activity-fields.d.ts +50 -0
- package/dist-client/components/activity-fields.js +393 -0
- package/dist-client/components/activity-fields.js.map +1 -0
- package/dist-client/components/activity-instance-ribon.d.ts +19 -0
- package/dist-client/components/activity-instance-ribon.js +55 -122
- package/dist-client/components/activity-instance-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-ribon.d.ts +25 -0
- package/dist-client/components/activity-thread-ribon.js +64 -121
- package/dist-client/components/activity-thread-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-timeline.d.ts +14 -2
- package/dist-client/components/activity-thread-timeline.js +234 -104
- package/dist-client/components/activity-thread-timeline.js.map +1 -1
- package/dist-client/components/state-ribon.d.ts +40 -0
- package/dist-client/components/state-ribon.js +200 -0
- package/dist-client/components/state-ribon.js.map +1 -0
- package/dist-client/due.d.ts +16 -0
- package/dist-client/due.js +78 -0
- package/dist-client/due.js.map +1 -0
- package/dist-client/pages/activity/activity-list-page.js +4 -6
- package/dist-client/pages/activity/activity-list-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-list-page.js +2 -1
- package/dist-client/pages/activity-approval/activity-approval-list-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-page.d.ts +52 -5
- package/dist-client/pages/activity-approval/activity-approval-page.js +265 -118
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-list-page.d.ts +0 -1
- package/dist-client/pages/activity-instance/activity-instance-list-page.js +8 -24
- package/dist-client/pages/activity-instance/activity-instance-list-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-start-page.d.ts +1 -0
- package/dist-client/pages/activity-instance/activity-instance-start-page.js +7 -0
- package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.js +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
- package/dist-client/pages/activity-stats/activity-stats-list-page.js +2 -1
- package/dist-client/pages/activity-stats/activity-stats-list-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.d.ts +30 -4
- package/dist-client/pages/activity-thread/activity-thread-page.js +142 -66
- package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +17 -6
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +118 -65
- 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 +24 -7
- package/dist-client/pages/activity-thread/activity-thread-view.js +84 -308
- package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +1 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.js +13 -9
- package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
- package/dist-client/pages/todo/approval-done-list-page.d.ts +1 -0
- package/dist-client/pages/todo/approval-done-list-page.js +111 -58
- package/dist-client/pages/todo/approval-done-list-page.js.map +1 -1
- package/dist-client/pages/todo/approval-pending-list-page.d.ts +32 -1
- package/dist-client/pages/todo/approval-pending-list-page.js +485 -130
- package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
- package/dist-client/pages/todo/done-list-calendar-page.d.ts +2 -0
- package/dist-client/pages/todo/done-list-calendar-page.js +213 -29
- package/dist-client/pages/todo/done-list-calendar-page.js.map +1 -1
- package/dist-client/pages/todo/done-list-page.d.ts +1 -0
- package/dist-client/pages/todo/done-list-page.js +126 -62
- package/dist-client/pages/todo/done-list-page.js.map +1 -1
- package/dist-client/pages/todo/draft-list-page.d.ts +1 -0
- package/dist-client/pages/todo/draft-list-page.js +82 -34
- package/dist-client/pages/todo/draft-list-page.js.map +1 -1
- package/dist-client/pages/todo/pickable-list-page.js +6 -10
- package/dist-client/pages/todo/pickable-list-page.js.map +1 -1
- package/dist-client/pages/todo/todo-list-page.d.ts +1 -1
- package/dist-client/pages/todo/todo-list-page.js +102 -78
- package/dist-client/pages/todo/todo-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +0 -6
- package/dist-client/route.js.map +1 -1
- package/dist-client/templates/activity-approval-context-template.js +60 -138
- package/dist-client/templates/activity-approval-context-template.js.map +1 -1
- package/dist-client/templates/activity-instance-context-template.js +13 -172
- package/dist-client/templates/activity-instance-context-template.js.map +1 -1
- package/dist-client/templates/activity-thread-context-template.js +39 -131
- package/dist-client/templates/activity-thread-context-template.js.map +1 -1
- package/dist-client/templates/context-panel.d.ts +26 -0
- package/dist-client/templates/context-panel.js +182 -0
- package/dist-client/templates/context-panel.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/when.d.ts +4 -0
- package/dist-client/when.js +72 -0
- package/dist-client/when.js.map +1 -0
- package/dist-server/controllers/activity-approval/_abort.js +2 -1
- package/dist-server/controllers/activity-approval/_abort.js.map +1 -1
- package/dist-server/controllers/activity-approval/approval-line.d.ts +106 -0
- package/dist-server/controllers/activity-approval/approval-line.js +151 -0
- package/dist-server/controllers/activity-approval/approval-line.js.map +1 -0
- package/dist-server/controllers/activity-approval/approve.js +61 -51
- package/dist-server/controllers/activity-approval/approve.js.map +1 -1
- package/dist-server/controllers/activity-approval/claim.d.ts +42 -0
- package/dist-server/controllers/activity-approval/claim.js +77 -0
- package/dist-server/controllers/activity-approval/claim.js.map +1 -0
- package/dist-server/controllers/activity-approval/create-approval.d.ts +41 -0
- package/dist-server/controllers/activity-approval/create-approval.js +78 -0
- package/dist-server/controllers/activity-approval/create-approval.js.map +1 -0
- package/dist-server/controllers/activity-approval/delegate.d.ts +16 -0
- package/dist-server/controllers/activity-approval/delegate.js +43 -7
- package/dist-server/controllers/activity-approval/delegate.js.map +1 -1
- package/dist-server/controllers/activity-approval/opinion.d.ts +10 -0
- package/dist-server/controllers/activity-approval/opinion.js +43 -0
- package/dist-server/controllers/activity-approval/opinion.js.map +1 -0
- package/dist-server/controllers/activity-approval/reject.js +21 -1
- package/dist-server/controllers/activity-approval/reject.js.map +1 -1
- package/dist-server/controllers/activity-approval/save.js +26 -2
- package/dist-server/controllers/activity-approval/save.js.map +1 -1
- package/dist-server/controllers/activity-installation/activity-installation-controller.d.ts +26 -0
- package/dist-server/controllers/activity-installation/activity-installation-controller.js +45 -0
- package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
- package/dist-server/controllers/activity-instance/approval-expectation.d.ts +34 -0
- package/dist-server/controllers/activity-instance/approval-expectation.js +18 -0
- package/dist-server/controllers/activity-instance/approval-expectation.js.map +1 -0
- package/dist-server/controllers/activity-instance/issue.js +32 -0
- package/dist-server/controllers/activity-instance/issue.js.map +1 -1
- package/dist-server/controllers/activity-thread/restart.js +17 -1
- package/dist-server/controllers/activity-thread/restart.js.map +1 -1
- package/dist-server/controllers/activity-thread/submit.js +23 -43
- package/dist-server/controllers/activity-thread/submit.js.map +1 -1
- package/dist-server/controllers/common.js +46 -0
- package/dist-server/controllers/common.js.map +1 -1
- package/dist-server/controllers/index.d.ts +1 -0
- package/dist-server/controllers/index.js +8 -0
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/service/activity/activity-mutation.js +25 -5
- package/dist-server/service/activity/activity-mutation.js.map +1 -1
- package/dist-server/service/activity/activity-type.d.ts +14 -0
- package/dist-server/service/activity/activity-type.js +8 -0
- package/dist-server/service/activity/activity-type.js.map +1 -1
- package/dist-server/service/activity/activity.d.ts +18 -0
- package/dist-server/service/activity/activity.js +5 -0
- package/dist-server/service/activity/activity.js.map +1 -1
- package/dist-server/service/activity-approval/activity-approval-mutation.js +3 -2
- package/dist-server/service/activity-approval/activity-approval-mutation.js.map +1 -1
- package/dist-server/service/activity-approval/activity-approval-query.d.ts +19 -1
- package/dist-server/service/activity-approval/activity-approval-query.js +186 -56
- package/dist-server/service/activity-approval/activity-approval-query.js.map +1 -1
- package/dist-server/service/activity-approval/activity-approval.d.ts +29 -1
- package/dist-server/service/activity-approval/activity-approval.js +19 -0
- package/dist-server/service/activity-approval/activity-approval.js.map +1 -1
- package/dist-server/service/activity-approval/my-pending-approvals.d.ts +21 -0
- package/dist-server/service/activity-approval/my-pending-approvals.js +40 -0
- package/dist-server/service/activity-approval/my-pending-approvals.js.map +1 -0
- package/dist-server/service/activity-instance/activity-instance-type.d.ts +20 -0
- package/dist-server/service/activity-instance/activity-instance-type.js +11 -0
- package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
- package/dist-server/service/activity-instance/activity-instance.d.ts +6 -0
- package/dist-server/service/activity-instance/activity-instance.js +5 -0
- package/dist-server/service/activity-instance/activity-instance.js.map +1 -1
- package/dist-server/service/activity-stats/activity-stats-query.d.ts +5 -0
- package/dist-server/service/activity-stats/activity-stats-query.js +149 -11
- package/dist-server/service/activity-stats/activity-stats-query.js.map +1 -1
- package/dist-server/service/activity-stats/activity-stats-type.d.ts +19 -6
- package/dist-server/service/activity-stats/activity-stats-type.js +37 -10
- package/dist-server/service/activity-stats/activity-stats-type.js.map +1 -1
- package/dist-server/service/activity-stats/event-placement.d.ts +55 -0
- package/dist-server/service/activity-stats/event-placement.js +82 -0
- package/dist-server/service/activity-stats/event-placement.js.map +1 -0
- package/dist-server/service/activity-thread/activity-thread-query.js +48 -24
- package/dist-server/service/activity-thread/activity-thread-query.js.map +1 -1
- package/dist-server/service/activity-thread/my-open-threads.d.ts +15 -0
- package/dist-server/service/activity-thread/my-open-threads.js +40 -0
- package/dist-server/service/activity-thread/my-open-threads.js.map +1 -0
- package/dist-server/service/activity-thread/todo-order.d.ts +49 -0
- package/dist-server/service/activity-thread/todo-order.js +70 -0
- package/dist-server/service/activity-thread/todo-order.js.map +1 -0
- package/dist-server/service/installable-activity/installable-activity-mutation.d.ts +6 -0
- package/dist-server/service/installable-activity/installable-activity-mutation.js +7 -24
- package/dist-server/service/installable-activity/installable-activity-mutation.js.map +1 -1
- package/dist-server/service/nulls-last.d.ts +30 -0
- package/dist-server/service/nulls-last.js +37 -0
- package/dist-server/service/nulls-last.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/dataset/activity-instance-search-page.ko.md +5 -0
- package/helps/dataset/activity-instance-search-page.md +13 -0
- package/helps/worklist/activity-approval.ko.md +5 -0
- package/helps/worklist/activity-approval.md +14 -0
- package/helps/worklist/activity-bank-page.ko.md +5 -0
- package/helps/worklist/activity-bank-page.md +13 -0
- package/helps/worklist/activity-reporter-list.ko.md +5 -0
- package/helps/worklist/activity-reporter-list.md +13 -0
- package/helps/worklist/activity-store.ko.md +5 -0
- package/helps/worklist/activity-store.md +13 -0
- package/helps/worklist/activity-template.ko.md +5 -0
- package/helps/worklist/activity-template.md +13 -0
- package/helps/worklist/installable-activity.ko.md +5 -0
- package/helps/worklist/installable-activity.md +13 -0
- package/package.json +13 -12
- package/things-factory.config.js +0 -5
- package/translations/en.json +129 -51
- package/translations/ja.json +130 -52
- package/translations/ko.json +82 -4
- package/translations/ms.json +129 -51
- package/translations/zh.json +132 -54
- package/dist-client/pages/dashboard/dashboard-home.d.ts +0 -1
- package/dist-client/pages/dashboard/dashboard-home.js +0 -22
- package/dist-client/pages/dashboard/dashboard-home.js.map +0 -1
- package/dist-client/pages/worklist-home.d.ts +0 -1
- package/dist-client/pages/worklist-home.js +0 -17
- package/dist-client/pages/worklist-home.js.map +0 -1
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ActivityEvent = exports.ActivityEventStatus = void 0;
|
|
3
|
+
exports.ActivityEvent = exports.ActivityEventStatus = exports.ActivityEventDateBasis = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const event_placement_js_1 = require("./event-placement.js");
|
|
7
|
+
var event_placement_js_2 = require("./event-placement.js");
|
|
8
|
+
Object.defineProperty(exports, "ActivityEventDateBasis", { enumerable: true, get: function () { return event_placement_js_2.ActivityEventDateBasis; } });
|
|
9
|
+
/**
|
|
10
|
+
* How a finished item reads on the calendar.
|
|
11
|
+
*
|
|
12
|
+
* `Aborted` is not decoration. A thread that was given up on ends in the same query as one that was
|
|
13
|
+
* completed, and without a value of its own it was reported as `Done` — the calendar drew a
|
|
14
|
+
* checkmark on work nobody finished.
|
|
15
|
+
*/
|
|
16
|
+
/*
|
|
17
|
+
* A const map, not a TS `enum`.
|
|
18
|
+
*
|
|
19
|
+
* The placement rules beside this file are pure and belong under test, and this package's test
|
|
20
|
+
* runner is node's own strip-only TypeScript — which refuses `enum` outright
|
|
21
|
+
* (ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX). One `enum` in a file makes every module that imports it
|
|
22
|
+
* untestable there, however pure it is. registerEnumType takes a plain object, so nothing is lost
|
|
23
|
+
* at the schema boundary and the list stays the single source with the type derived from it.
|
|
24
|
+
*/
|
|
25
|
+
exports.ActivityEventStatus = {
|
|
26
|
+
Done: 'done',
|
|
27
|
+
Aborted: 'aborted',
|
|
28
|
+
Pending: 'pending',
|
|
29
|
+
Approved: 'approved',
|
|
30
|
+
Rejected: 'rejected'
|
|
31
|
+
};
|
|
32
|
+
(0, type_graphql_1.registerEnumType)(exports.ActivityEventStatus, {
|
|
14
33
|
name: 'ActivityEventStatus',
|
|
15
34
|
description: 'state enumeration of a Activity Event'
|
|
16
35
|
});
|
|
36
|
+
(0, type_graphql_1.registerEnumType)(event_placement_js_1.ActivityEventDateBasis, {
|
|
37
|
+
name: 'ActivityEventDateBasis',
|
|
38
|
+
description: 'what the date of an Activity Event means'
|
|
39
|
+
});
|
|
17
40
|
let ActivityEvent = class ActivityEvent {
|
|
18
41
|
};
|
|
19
42
|
exports.ActivityEvent = ActivityEvent;
|
|
@@ -34,9 +57,13 @@ tslib_1.__decorate([
|
|
|
34
57
|
tslib_1.__metadata("design:type", Number)
|
|
35
58
|
], ActivityEvent.prototype, "priority", void 0);
|
|
36
59
|
tslib_1.__decorate([
|
|
37
|
-
(0, type_graphql_1.Field)({ nullable: true }),
|
|
60
|
+
(0, type_graphql_1.Field)(type => exports.ActivityEventStatus, { nullable: true }),
|
|
38
61
|
tslib_1.__metadata("design:type", String)
|
|
39
62
|
], ActivityEvent.prototype, "state", void 0);
|
|
63
|
+
tslib_1.__decorate([
|
|
64
|
+
(0, type_graphql_1.Field)(type => event_placement_js_1.ActivityEventDateBasis, { nullable: true }),
|
|
65
|
+
tslib_1.__metadata("design:type", String)
|
|
66
|
+
], ActivityEvent.prototype, "basis", void 0);
|
|
40
67
|
tslib_1.__decorate([
|
|
41
68
|
(0, type_graphql_1.Field)({ nullable: true }),
|
|
42
69
|
tslib_1.__metadata("design:type", Date)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-stats-type.js","sourceRoot":"","sources":["../../../server/service/activity-stats/activity-stats-type.ts"],"names":[],"mappings":";;;;AAAA,+CAA2E;AAE3E,
|
|
1
|
+
{"version":3,"file":"activity-stats-type.js","sourceRoot":"","sources":["../../../server/service/activity-stats/activity-stats-type.ts"],"names":[],"mappings":";;;;AAAA,+CAA2E;AAE3E,6DAA6D;AAE7D,2DAA6D;AAApD,4HAAA,sBAAsB,OAAA;AAG/B;;;;;;GAMG;AACH;;;;;;;;GAQG;AACU,QAAA,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;CACZ,CAAA;AAIV,IAAA,+BAAgB,EAAC,2BAAmB,EAAE;IACpC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,uCAAuC;CACrD,CAAC,CAAA;AAEF,IAAA,+BAAgB,EAAC,2CAAsB,EAAE;IACvC,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EAAE,0CAA0C;CACxD,CAAC,CAAA;AAGK,IAAM,aAAa,GAAnB,MAAM,aAAa;CA4BzB,CAAA;AA5BY,sCAAa;AAExB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;yCACf;AAGX;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2CACb;AAGb;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2CACb;AAGb;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CACT;AAUjB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,2BAAmB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CAC5B;AAG3B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,2CAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CAC5B;AAG9B;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACnB,IAAI;2CAAA;wBA3BA,aAAa;IADzB,IAAA,yBAAU,GAAE;GACA,aAAa,CA4BzB","sourcesContent":["import { ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'\n\nimport { ActivityEventDateBasis } from './event-placement.js'\n\nexport { ActivityEventDateBasis } from './event-placement.js'\nexport type { ActivityEventDateBasis as ActivityEventDateBasisType } from './event-placement.js'\n\n/**\n * How a finished item reads on the calendar.\n *\n * `Aborted` is not decoration. A thread that was given up on ends in the same query as one that was\n * completed, and without a value of its own it was reported as `Done` — the calendar drew a\n * checkmark on work nobody finished.\n */\n/*\n * A const map, not a TS `enum`.\n *\n * The placement rules beside this file are pure and belong under test, and this package's test\n * runner is node's own strip-only TypeScript — which refuses `enum` outright\n * (ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX). One `enum` in a file makes every module that imports it\n * untestable there, however pure it is. registerEnumType takes a plain object, so nothing is lost\n * at the schema boundary and the list stays the single source with the type derived from it.\n */\nexport const ActivityEventStatus = {\n Done: 'done',\n Aborted: 'aborted',\n Pending: 'pending',\n Approved: 'approved',\n Rejected: 'rejected'\n} as const\n\nexport type ActivityEventStatus = (typeof ActivityEventStatus)[keyof typeof ActivityEventStatus]\n\nregisterEnumType(ActivityEventStatus, {\n name: 'ActivityEventStatus',\n description: 'state enumeration of a Activity Event'\n})\n\nregisterEnumType(ActivityEventDateBasis, {\n name: 'ActivityEventDateBasis',\n description: 'what the date of an Activity Event means'\n})\n\n@ObjectType()\nexport class ActivityEvent {\n @Field({ nullable: true })\n id?: string\n\n @Field({ nullable: true })\n name?: string\n\n @Field({ nullable: true })\n type?: string\n\n @Field({ nullable: true })\n priority?: number\n\n /*\n * Declared explicitly, which changes what crosses the wire: registerEnumType publishes an enum\n * by its **key**, so this now answers `Pending` rather than `pending`. Without the explicit type\n * reflection sees String and the raw value goes out — that inconsistency is worth removing while\n * this type has exactly one consumer (done-list-calendar-page), and that consumer already folds\n * case on both enum fields.\n */\n @Field(type => ActivityEventStatus, { nullable: true })\n state?: ActivityEventStatus\n\n @Field(type => ActivityEventDateBasis, { nullable: true })\n basis?: ActivityEventDateBasis\n\n @Field({ nullable: true })\n date?: Date\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **What the event's date means.** Not decoration — the reader acts on it.
|
|
3
|
+
*
|
|
4
|
+
* A finished item sits on the day it ended. An unfinished one sits on its deadline when it has
|
|
5
|
+
* one, and otherwise on the day it landed on this person. Those are two different sentences on the
|
|
6
|
+
* same square: "due by the 12th" and "arrived on the 12th". Drawn alike, an approver reads a
|
|
7
|
+
* deadline as an arrival and lets it pass, or reads an arrival as a deadline and reshuffles a week
|
|
8
|
+
* for nothing.
|
|
9
|
+
*
|
|
10
|
+
* It lives here, beside the rule that assigns it, rather than in activity-stats-type.ts where it
|
|
11
|
+
* is published to the schema. That file carries decorators, and this package's tests run on node's
|
|
12
|
+
* strip-only TypeScript, which parses neither decorators nor `enum` — a pure rule that imports
|
|
13
|
+
* either one cannot be tested at all. The vocabulary belongs with the rule; the type file imports
|
|
14
|
+
* it to register it.
|
|
15
|
+
*
|
|
16
|
+
* A const map rather than a TS `enum`, for the same reason. registerEnumType takes a plain object,
|
|
17
|
+
* so the schema is unaffected.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ActivityEventDateBasis: {
|
|
20
|
+
/** 이 날까지 해야 한다. */
|
|
21
|
+
readonly Due: "due";
|
|
22
|
+
/** 이 날 내 앞에 왔다 — 기한이 없어서 그 자리를 쓴다. */
|
|
23
|
+
readonly HandedOver: "handed-over";
|
|
24
|
+
/** 이 날 끝났다. */
|
|
25
|
+
readonly Terminated: "terminated";
|
|
26
|
+
};
|
|
27
|
+
export type ActivityEventDateBasis = (typeof ActivityEventDateBasis)[keyof typeof ActivityEventDateBasis];
|
|
28
|
+
/**
|
|
29
|
+
* Which day an unfinished item sits on, and what that day means.
|
|
30
|
+
*
|
|
31
|
+
* Its deadline when it has one — the only value that says when the work has to happen. Otherwise
|
|
32
|
+
* the day it landed on this person, which is honest as a position and keeps deadline-less items
|
|
33
|
+
* from vanishing from the calendar altogether.
|
|
34
|
+
*
|
|
35
|
+
* The two are different sentences on the same square — "due by the 12th" and "arrived on the 12th"
|
|
36
|
+
* — so the basis travels with the date. A screen cannot recover it later; by then both are just a
|
|
37
|
+
* date. See ActivityEventDateBasis.
|
|
38
|
+
*/
|
|
39
|
+
export declare function placeOf(dueAt?: Date, handedOverAt?: Date): {
|
|
40
|
+
date?: Date;
|
|
41
|
+
basis?: ActivityEventDateBasis;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Does this land inside the window the calendar asked for?
|
|
45
|
+
*
|
|
46
|
+
* Finished items filter in SQL on one column. Unfinished ones carry a per-row coordinate
|
|
47
|
+
* (deadline, else handover), and expressing that in SQL means standing up a COALESCE that behaves
|
|
48
|
+
* identically on all five drivers this framework supports. One calendar page is six weeks of one
|
|
49
|
+
* person's work, so it reads and then filters.
|
|
50
|
+
*
|
|
51
|
+
* Half-open: `from` counts, `to` does not. The caller passes the day after the last cell as `to`,
|
|
52
|
+
* so an item at exactly midnight on that boundary belongs to the next page, not this one — and
|
|
53
|
+
* counting both ends would draw it on two.
|
|
54
|
+
*/
|
|
55
|
+
export declare function withinPeriod(date: Date | undefined, from: string, to: string): boolean;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActivityEventDateBasis = void 0;
|
|
4
|
+
exports.placeOf = placeOf;
|
|
5
|
+
exports.withinPeriod = withinPeriod;
|
|
6
|
+
/**
|
|
7
|
+
* **What the event's date means.** Not decoration — the reader acts on it.
|
|
8
|
+
*
|
|
9
|
+
* A finished item sits on the day it ended. An unfinished one sits on its deadline when it has
|
|
10
|
+
* one, and otherwise on the day it landed on this person. Those are two different sentences on the
|
|
11
|
+
* same square: "due by the 12th" and "arrived on the 12th". Drawn alike, an approver reads a
|
|
12
|
+
* deadline as an arrival and lets it pass, or reads an arrival as a deadline and reshuffles a week
|
|
13
|
+
* for nothing.
|
|
14
|
+
*
|
|
15
|
+
* It lives here, beside the rule that assigns it, rather than in activity-stats-type.ts where it
|
|
16
|
+
* is published to the schema. That file carries decorators, and this package's tests run on node's
|
|
17
|
+
* strip-only TypeScript, which parses neither decorators nor `enum` — a pure rule that imports
|
|
18
|
+
* either one cannot be tested at all. The vocabulary belongs with the rule; the type file imports
|
|
19
|
+
* it to register it.
|
|
20
|
+
*
|
|
21
|
+
* A const map rather than a TS `enum`, for the same reason. registerEnumType takes a plain object,
|
|
22
|
+
* so the schema is unaffected.
|
|
23
|
+
*/
|
|
24
|
+
exports.ActivityEventDateBasis = {
|
|
25
|
+
/** 이 날까지 해야 한다. */
|
|
26
|
+
Due: 'due',
|
|
27
|
+
/** 이 날 내 앞에 왔다 — 기한이 없어서 그 자리를 쓴다. */
|
|
28
|
+
HandedOver: 'handed-over',
|
|
29
|
+
/** 이 날 끝났다. */
|
|
30
|
+
Terminated: 'terminated'
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Which day an unfinished item sits on, and what that day means.
|
|
34
|
+
*
|
|
35
|
+
* Its deadline when it has one — the only value that says when the work has to happen. Otherwise
|
|
36
|
+
* the day it landed on this person, which is honest as a position and keeps deadline-less items
|
|
37
|
+
* from vanishing from the calendar altogether.
|
|
38
|
+
*
|
|
39
|
+
* The two are different sentences on the same square — "due by the 12th" and "arrived on the 12th"
|
|
40
|
+
* — so the basis travels with the date. A screen cannot recover it later; by then both are just a
|
|
41
|
+
* date. See ActivityEventDateBasis.
|
|
42
|
+
*/
|
|
43
|
+
function placeOf(dueAt, handedOverAt) {
|
|
44
|
+
if (dueAt) {
|
|
45
|
+
return { date: dueAt, basis: exports.ActivityEventDateBasis.Due };
|
|
46
|
+
}
|
|
47
|
+
if (handedOverAt) {
|
|
48
|
+
return { date: handedOverAt, basis: exports.ActivityEventDateBasis.HandedOver };
|
|
49
|
+
}
|
|
50
|
+
/*
|
|
51
|
+
* Neither date. Nothing is drawn.
|
|
52
|
+
*
|
|
53
|
+
* The tempting fallback is today, or the day the row was created — and both would place the item
|
|
54
|
+
* somewhere it does not belong, which is a fact the calendar made up. A row with no deadline and
|
|
55
|
+
* no handover has no position, and saying nothing is the only honest answer available.
|
|
56
|
+
*/
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Does this land inside the window the calendar asked for?
|
|
61
|
+
*
|
|
62
|
+
* Finished items filter in SQL on one column. Unfinished ones carry a per-row coordinate
|
|
63
|
+
* (deadline, else handover), and expressing that in SQL means standing up a COALESCE that behaves
|
|
64
|
+
* identically on all five drivers this framework supports. One calendar page is six weeks of one
|
|
65
|
+
* person's work, so it reads and then filters.
|
|
66
|
+
*
|
|
67
|
+
* Half-open: `from` counts, `to` does not. The caller passes the day after the last cell as `to`,
|
|
68
|
+
* so an item at exactly midnight on that boundary belongs to the next page, not this one — and
|
|
69
|
+
* counting both ends would draw it on two.
|
|
70
|
+
*/
|
|
71
|
+
function withinPeriod(date, from, to) {
|
|
72
|
+
if (!date) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const at = new Date(date).getTime();
|
|
76
|
+
/* An unreadable date is not a date. Drawing it as one would put a row on 1970-01-01. */
|
|
77
|
+
if (!Number.isFinite(at)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return at >= new Date(from).getTime() && at < new Date(to).getTime();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=event-placement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-placement.js","sourceRoot":"","sources":["../../../server/service/activity-stats/event-placement.ts"],"names":[],"mappings":";;;AAwCA,0BAiBC;AAcD,oCAaC;AApFD;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,sBAAsB,GAAG;IACpC,mBAAmB;IACnB,GAAG,EAAE,KAAK;IACV,sCAAsC;IACtC,UAAU,EAAE,aAAa;IACzB,eAAe;IACf,UAAU,EAAE,YAAY;CAChB,CAAA;AAIV;;;;;;;;;;GAUG;AACH,SAAgB,OAAO,CAAC,KAAY,EAAE,YAAmB;IACvD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,8BAAsB,CAAC,GAAG,EAAE,CAAA;IAC3D,CAAC;IAED,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,8BAAsB,CAAC,UAAU,EAAE,CAAA;IACzE,CAAC;IAED;;;;;;OAMG;IACH,OAAO,EAAE,CAAA;AACX,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,YAAY,CAAC,IAAsB,EAAE,IAAY,EAAE,EAAU;IAC3E,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAA;IAEnC,wFAAwF;IACxF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;AACtE,CAAC","sourcesContent":["/**\n * **What the event's date means.** Not decoration — the reader acts on it.\n *\n * A finished item sits on the day it ended. An unfinished one sits on its deadline when it has\n * one, and otherwise on the day it landed on this person. Those are two different sentences on the\n * same square: \"due by the 12th\" and \"arrived on the 12th\". Drawn alike, an approver reads a\n * deadline as an arrival and lets it pass, or reads an arrival as a deadline and reshuffles a week\n * for nothing.\n *\n * It lives here, beside the rule that assigns it, rather than in activity-stats-type.ts where it\n * is published to the schema. That file carries decorators, and this package's tests run on node's\n * strip-only TypeScript, which parses neither decorators nor `enum` — a pure rule that imports\n * either one cannot be tested at all. The vocabulary belongs with the rule; the type file imports\n * it to register it.\n *\n * A const map rather than a TS `enum`, for the same reason. registerEnumType takes a plain object,\n * so the schema is unaffected.\n */\nexport const ActivityEventDateBasis = {\n /** 이 날까지 해야 한다. */\n Due: 'due',\n /** 이 날 내 앞에 왔다 — 기한이 없어서 그 자리를 쓴다. */\n HandedOver: 'handed-over',\n /** 이 날 끝났다. */\n Terminated: 'terminated'\n} as const\n\nexport type ActivityEventDateBasis = (typeof ActivityEventDateBasis)[keyof typeof ActivityEventDateBasis]\n\n/**\n * Which day an unfinished item sits on, and what that day means.\n *\n * Its deadline when it has one — the only value that says when the work has to happen. Otherwise\n * the day it landed on this person, which is honest as a position and keeps deadline-less items\n * from vanishing from the calendar altogether.\n *\n * The two are different sentences on the same square — \"due by the 12th\" and \"arrived on the 12th\"\n * — so the basis travels with the date. A screen cannot recover it later; by then both are just a\n * date. See ActivityEventDateBasis.\n */\nexport function placeOf(dueAt?: Date, handedOverAt?: Date): { date?: Date; basis?: ActivityEventDateBasis } {\n if (dueAt) {\n return { date: dueAt, basis: ActivityEventDateBasis.Due }\n }\n\n if (handedOverAt) {\n return { date: handedOverAt, basis: ActivityEventDateBasis.HandedOver }\n }\n\n /*\n * Neither date. Nothing is drawn.\n *\n * The tempting fallback is today, or the day the row was created — and both would place the item\n * somewhere it does not belong, which is a fact the calendar made up. A row with no deadline and\n * no handover has no position, and saying nothing is the only honest answer available.\n */\n return {}\n}\n\n/**\n * Does this land inside the window the calendar asked for?\n *\n * Finished items filter in SQL on one column. Unfinished ones carry a per-row coordinate\n * (deadline, else handover), and expressing that in SQL means standing up a COALESCE that behaves\n * identically on all five drivers this framework supports. One calendar page is six weeks of one\n * person's work, so it reads and then filters.\n *\n * Half-open: `from` counts, `to` does not. The caller passes the day after the last cell as `to`,\n * so an item at exactly midnight on that boundary belongs to the next page, not this one — and\n * counting both ends would draw it on two.\n */\nexport function withinPeriod(date: Date | undefined, from: string, to: string): boolean {\n if (!date) {\n return false\n }\n\n const at = new Date(date).getTime()\n\n /* An unreadable date is not a date. Drawing it as one would put a row on 1970-01-01. */\n if (!Number.isFinite(at)) {\n return false\n }\n\n return at >= new Date(from).getTime() && at < new Date(to).getTime()\n}\n"]}
|
|
@@ -2,15 +2,57 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ActivityThreadQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const typeorm_1 = require("typeorm");
|
|
6
5
|
const type_graphql_1 = require("type-graphql");
|
|
7
6
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
7
|
const shell_1 = require("@things-factory/shell");
|
|
9
8
|
const activity_instance_js_1 = require("../activity-instance/activity-instance.js");
|
|
10
9
|
const activity_thread_js_1 = require("./activity-thread.js");
|
|
10
|
+
const my_open_threads_js_1 = require("./my-open-threads.js");
|
|
11
11
|
const activity_approval_js_1 = require("../activity-approval/activity-approval.js");
|
|
12
12
|
const activity_thread_type_js_1 = require("./activity-thread-type.js");
|
|
13
13
|
const activity_thread_history_js_1 = require("./activity-thread-history.js");
|
|
14
|
+
const todo_order_js_1 = require("./todo-order.js");
|
|
15
|
+
/**
|
|
16
|
+
* 「할 일」 목록의 정렬 — **기한이 없는 것은 뒤로 간다.**
|
|
17
|
+
*
|
|
18
|
+
* ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────
|
|
19
|
+
* 화면의 기본 정렬은 `dueAt` 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에
|
|
20
|
+
* 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.
|
|
21
|
+
*
|
|
22
|
+
* NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저, postgres 는
|
|
23
|
+
* 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.
|
|
24
|
+
*
|
|
25
|
+
* ── 왜 NULLS LAST 를 쓰지 않나 ─────────────────────────────────────────────
|
|
26
|
+
* `ORDER BY ... NULLS LAST` 는 postgres · oracle 문법이다. mysql · mssql 에서는 구문 오류가 난다.
|
|
27
|
+
* 이 프레임워크는 다섯 드라이버를 다 지켜야 한다.
|
|
28
|
+
*
|
|
29
|
+
* `CASE WHEN ... IS NULL THEN 1 ELSE 0 END` 는 표준 SQL 이고 다섯 곳에서 다 돈다. 컬럼 이름은
|
|
30
|
+
* 손으로 적지 않고 TypeORM 의 메타데이터에서 꺼낸다 — 이 프로젝트의 명명 규칙이 snake_case 라
|
|
31
|
+
* `dueAt` 은 실제로 `due_at` 이다(shell 의 NamingStrategy).
|
|
32
|
+
*
|
|
33
|
+
* ── 공용 함수를 고치지 않는다 ──────────────────────────────────────────────
|
|
34
|
+
* `getQueryBuilderFromListParams` 는 136개 꾸러미가 함께 쓴다. 정렬은 이 목록의 사정이므로
|
|
35
|
+
* 여기서 맡는다 — 그 함수에는 정렬을 넘기지 않고(빈 배열) 아래에서 직접 건다.
|
|
36
|
+
*/
|
|
37
|
+
function applyTodoSortings(queryBuilder, sortings) {
|
|
38
|
+
const terms = (0, todo_order_js_1.todoOrderTerms)(sortings, name => {
|
|
39
|
+
const alias = todo_order_js_1.TODO_INSTANCE_SORTS.has(name) ? 'ai' : 'at';
|
|
40
|
+
const metadata = (0, shell_1.getRepository)(alias === 'ai' ? activity_instance_js_1.ActivityInstance : activity_thread_js_1.ActivityThread).metadata;
|
|
41
|
+
const column = metadata.findColumnWithPropertyName(name);
|
|
42
|
+
if (!column) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const escape = (part) => queryBuilder.connection.driver.escape(part);
|
|
46
|
+
return `${escape(alias)}.${escape(column.databaseName)}`;
|
|
47
|
+
});
|
|
48
|
+
terms.forEach(({ expression, direction, select }, index) => {
|
|
49
|
+
/* 식은 select 에 이름 붙여 올린다 — orderBy 는 식을 못 받는다(todo-order 머리말). */
|
|
50
|
+
if (select) {
|
|
51
|
+
queryBuilder.addSelect(select, expression);
|
|
52
|
+
}
|
|
53
|
+
index === 0 ? queryBuilder.orderBy(expression, direction) : queryBuilder.addOrderBy(expression, direction);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
14
56
|
let ActivityThreadQuery = class ActivityThreadQuery {
|
|
15
57
|
async activityThread(id, context) {
|
|
16
58
|
const { domain } = context.state;
|
|
@@ -36,19 +78,10 @@ let ActivityThreadQuery = class ActivityThreadQuery {
|
|
|
36
78
|
relations: ['roles']
|
|
37
79
|
});
|
|
38
80
|
const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id);
|
|
39
|
-
const excludedStatuses = [
|
|
40
|
-
// ActivityThreadStatus.Assigned,
|
|
41
|
-
// ActivityThreadStatus.Started,
|
|
42
|
-
// ActivityThreadStatus.Submitted,
|
|
43
|
-
// ActivityThreadStatus.Escalated,
|
|
44
|
-
// ActivityThreadStatus.Rejected,
|
|
45
|
-
activity_thread_js_1.ActivityThreadStatus.Unassigned,
|
|
46
|
-
activity_thread_js_1.ActivityThreadStatus.Ended,
|
|
47
|
-
activity_thread_js_1.ActivityThreadStatus.Aborted
|
|
48
|
-
];
|
|
49
81
|
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
50
82
|
repository: (0, shell_1.getRepository)(activity_thread_js_1.ActivityThread),
|
|
51
|
-
|
|
83
|
+
/* 정렬은 아래에서 직접 건다(applyTodoSortings 머리말) — 여기에 넘기면 NULL 자리를 못 정한다. */
|
|
84
|
+
params: { ...params, sortings: [] },
|
|
52
85
|
domain,
|
|
53
86
|
alias: 'at',
|
|
54
87
|
searchables: ['name', 'description'],
|
|
@@ -59,18 +92,9 @@ let ActivityThreadQuery = class ActivityThreadQuery {
|
|
|
59
92
|
}
|
|
60
93
|
})
|
|
61
94
|
.innerJoinAndSelect('at.activityInstance', 'ai')
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
66
|
-
if (roles.length > 0) {
|
|
67
|
-
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
68
|
-
subQb
|
|
69
|
-
.where('ai.assigneeRole IN (:...roles)', { roles })
|
|
70
|
-
.andWhere(`at.state = '${activity_thread_js_1.ActivityThreadStatus.Unassigned}'`);
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
}));
|
|
95
|
+
/* 「내 앞에 있는 일」의 정의는 한 자리에 있다 — 달력도 같은 것을 읽는다. */
|
|
96
|
+
.andWhere((0, my_open_threads_js_1.myOpenThreadsWhere)({ userId: user.id, roles }));
|
|
97
|
+
applyTodoSortings(queryBuilder, params.sortings || []);
|
|
74
98
|
const [items, total] = await queryBuilder.getManyAndCount();
|
|
75
99
|
return { items, total };
|
|
76
100
|
}
|
|
@@ -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, 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 { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { ActivityThreadList } from './activity-thread-type.js'\nimport { ActivityThreadHistory } from './activity-thread-history.js'\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 return await getRepository(ActivityThread).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\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 excludedStatuses = [\n // ActivityThreadStatus.Assigned,\n // ActivityThreadStatus.Started,\n // ActivityThreadStatus.Submitted,\n // ActivityThreadStatus.Escalated,\n // ActivityThreadStatus.Rejected,\n ActivityThreadStatus.Unassigned,\n ActivityThreadStatus.Ended,\n ActivityThreadStatus.Aborted\n ]\n\n const queryBuilder = 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(\n new Brackets(qb => {\n qb.where('at.state NOT IN (:...excludedStatuses)', { excludedStatuses }).andWhere('at.assignee = :userId', {\n userId: user.id\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 = '${ActivityThreadStatus.Unassigned}'`)\n })\n )\n }\n })\n )\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, 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 { 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 return await getRepository(ActivityThread).findOne({\n where: { domain: { id: domain.id }, id }\n })\n }\n\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"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Brackets } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* The work that is on my plate — one definition, two readers.
|
|
4
|
+
*
|
|
5
|
+
* 할 일 목록 asks this, and so does the calendar. Written twice they drift: a new state, or a new
|
|
6
|
+
* way of being assigned, lands in one and not the other, and the calendar quietly shows a
|
|
7
|
+
* different week than the list it sits beside. Nothing errors.
|
|
8
|
+
*
|
|
9
|
+
* Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
|
|
10
|
+
* reads assigneeRole off the instance.
|
|
11
|
+
*/
|
|
12
|
+
export declare function myOpenThreadsWhere({ userId, roles }: {
|
|
13
|
+
userId: string;
|
|
14
|
+
roles: string[];
|
|
15
|
+
}): Brackets;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.myOpenThreadsWhere = myOpenThreadsWhere;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
const activity_thread_js_1 = require("./activity-thread.js");
|
|
6
|
+
/**
|
|
7
|
+
* Thread states that are **not** work waiting on someone.
|
|
8
|
+
*
|
|
9
|
+
* Unassigned belongs here for the person branch only — a thread nobody holds is not on my plate
|
|
10
|
+
* until I claim it, and the role branch below is what surfaces it to the people who could.
|
|
11
|
+
*/
|
|
12
|
+
const CLOSED_OR_UNCLAIMED = [
|
|
13
|
+
activity_thread_js_1.ActivityThreadStatus.Unassigned,
|
|
14
|
+
activity_thread_js_1.ActivityThreadStatus.Ended,
|
|
15
|
+
activity_thread_js_1.ActivityThreadStatus.Aborted
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* The work that is on my plate — one definition, two readers.
|
|
19
|
+
*
|
|
20
|
+
* 할 일 목록 asks this, and so does the calendar. Written twice they drift: a new state, or a new
|
|
21
|
+
* way of being assigned, lands in one and not the other, and the calendar quietly shows a
|
|
22
|
+
* different week than the list it sits beside. Nothing errors.
|
|
23
|
+
*
|
|
24
|
+
* Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
|
|
25
|
+
* reads assigneeRole off the instance.
|
|
26
|
+
*/
|
|
27
|
+
function myOpenThreadsWhere({ userId, roles }) {
|
|
28
|
+
return new typeorm_1.Brackets(qb => {
|
|
29
|
+
qb.where('at.state NOT IN (:...closedOrUnclaimed)', { closedOrUnclaimed: CLOSED_OR_UNCLAIMED }).andWhere('at.assignee = :userId', { userId });
|
|
30
|
+
/* 역할로 걸린 것은 아직 임자가 없다 — 그 역할을 가진 사람 모두의 할 일이다. */
|
|
31
|
+
if (roles.length > 0) {
|
|
32
|
+
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
33
|
+
subQb
|
|
34
|
+
.where('ai.assigneeRole IN (:...roles)', { roles })
|
|
35
|
+
.andWhere('at.state = :unassigned', { unassigned: activity_thread_js_1.ActivityThreadStatus.Unassigned });
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=my-open-threads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"my-open-threads.js","sourceRoot":"","sources":["../../../server/service/activity-thread/my-open-threads.ts"],"names":[],"mappings":";;AA0BA,gDAkBC;AA5CD,qCAAkC;AAElC,6DAA2D;AAE3D;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG;IAC1B,yCAAoB,CAAC,UAAU;IAC/B,yCAAoB,CAAC,KAAK;IAC1B,yCAAoB,CAAC,OAAO;CAC7B,CAAA;AAED;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAuC;IACvF,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,yCAAyC,EAAE,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAC,CAAC,QAAQ,CACtG,uBAAuB,EACvB,EAAE,MAAM,EAAE,CACX,CAAA;QAED,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","sourcesContent":["import { Brackets } from 'typeorm'\n\nimport { ActivityThreadStatus } from './activity-thread.js'\n\n/**\n * Thread states that are **not** work waiting on someone.\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 CLOSED_OR_UNCLAIMED = [\n ActivityThreadStatus.Unassigned,\n ActivityThreadStatus.Ended,\n ActivityThreadStatus.Aborted\n]\n\n/**\n * The work that is on my plate — one definition, two readers.\n *\n * 할 일 목록 asks this, and so does the calendar. Written twice they drift: a new state, or a new\n * way of being assigned, lands in one and not the other, and the calendar quietly shows a\n * different week than the list it sits beside. 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 (:...closedOrUnclaimed)', { closedOrUnclaimed: CLOSED_OR_UNCLAIMED }).andWhere(\n '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"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「할 일」 목록의 정렬 규칙 — **기한이 없는 것은 뒤로 간다.**
|
|
3
|
+
*
|
|
4
|
+
* ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────
|
|
5
|
+
* 화면의 기본 정렬은 dueAt 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에
|
|
6
|
+
* 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.
|
|
7
|
+
*
|
|
8
|
+
* NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저,
|
|
9
|
+
* postgres 는 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.
|
|
10
|
+
*
|
|
11
|
+
* ── 왜 NULLS LAST 를 쓰지 않나 ─────────────────────────────────────────────
|
|
12
|
+
* ORDER BY ... NULLS LAST 는 postgres · oracle 문법이다. mysql · mssql 에서는 구문 오류가 난다.
|
|
13
|
+
* 이 프레임워크는 다섯 드라이버를 다 지켜야 한다.
|
|
14
|
+
*
|
|
15
|
+
* CASE WHEN ... IS NULL THEN 1 ELSE 0 END 는 표준 SQL 이고 다섯 곳에서 다 돈다.
|
|
16
|
+
*
|
|
17
|
+
* TypeORM 의 세 번째 인자(nulls)도 쓸 수 없다 — SelectQueryBuilder 가 드라이버를 보지 않고
|
|
18
|
+
* 「ASC NULLS LAST」를 그대로 붙인다(1331행).
|
|
19
|
+
*
|
|
20
|
+
* ── 식은 select 로 올려서 정렬한다 ─────────────────────────────────────────
|
|
21
|
+
* orderBy 에 식을 그대로 주면 TypeORM 이 **첫 점을 alias 로 읽는다.** 실측 오류:
|
|
22
|
+
* 「"CASE WHEN "at"" alias was not found」. 그래서 식을 select 에 이름 붙여 올리고, 정렬은 그
|
|
23
|
+
* 이름으로 건다 — 점이 없으므로 TypeORM 이 이름 그대로 통과시킨다.
|
|
24
|
+
*
|
|
25
|
+
* ── 여기에 SQL 을 적지 않는다 ──────────────────────────────────────────────
|
|
26
|
+
* 컬럼 이름은 부르는 쪽이 TypeORM 메타데이터에서 꺼내 넘긴다(fieldOf). 이 파일이 이름을 지어내면
|
|
27
|
+
* 명명 규칙이 바뀔 때 조용히 틀린다 — 이 프로젝트는 snake_case 라 dueAt 이 실제로는 due_at 이다.
|
|
28
|
+
*/
|
|
29
|
+
/** 업무 인스턴스(ai) 쪽 컬럼으로 정렬하는 이름들. 나머지는 스레드(at) 쪽이다. */
|
|
30
|
+
export declare const TODO_INSTANCE_SORTS: Set<string>;
|
|
31
|
+
/** 값이 없으면 뒤로 보낼 컬럼. 기한이 없는 일은 「언제까지」를 묻는 정렬에서 맨 뒤가 맞다. */
|
|
32
|
+
export declare const TODO_NULLS_LAST: Set<string>;
|
|
33
|
+
export type OrderTerm = {
|
|
34
|
+
expression: string;
|
|
35
|
+
direction: 'ASC' | 'DESC';
|
|
36
|
+
/** 이 항목이 select 에 올려야 하는 식. 있으면 부르는 쪽이 addSelect 한다. */
|
|
37
|
+
select?: string;
|
|
38
|
+
};
|
|
39
|
+
export { NULL_RANK_ALIAS } from '../nulls-last.js';
|
|
40
|
+
/**
|
|
41
|
+
* 정렬 요청을 ORDER BY 항목들로 바꾼다.
|
|
42
|
+
*
|
|
43
|
+
* `fieldOf` 는 컬럼 이름을 따옴표까지 붙여 돌려준다. 못 찾으면 undefined 를 주고, 그때는 값 없는
|
|
44
|
+
* 것을 뒤로 보내는 항목을 만들지 않는다 — 지어낸 이름으로 SQL 을 세우지 않는다.
|
|
45
|
+
*/
|
|
46
|
+
export declare function todoOrderTerms(sortings: {
|
|
47
|
+
name: string;
|
|
48
|
+
desc?: boolean;
|
|
49
|
+
}[], fieldOf: (name: string) => string | undefined): OrderTerm[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 「할 일」 목록의 정렬 규칙 — **기한이 없는 것은 뒤로 간다.**
|
|
4
|
+
*
|
|
5
|
+
* ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────
|
|
6
|
+
* 화면의 기본 정렬은 dueAt 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에
|
|
7
|
+
* 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.
|
|
8
|
+
*
|
|
9
|
+
* NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저,
|
|
10
|
+
* postgres 는 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.
|
|
11
|
+
*
|
|
12
|
+
* ── 왜 NULLS LAST 를 쓰지 않나 ─────────────────────────────────────────────
|
|
13
|
+
* ORDER BY ... NULLS LAST 는 postgres · oracle 문법이다. mysql · mssql 에서는 구문 오류가 난다.
|
|
14
|
+
* 이 프레임워크는 다섯 드라이버를 다 지켜야 한다.
|
|
15
|
+
*
|
|
16
|
+
* CASE WHEN ... IS NULL THEN 1 ELSE 0 END 는 표준 SQL 이고 다섯 곳에서 다 돈다.
|
|
17
|
+
*
|
|
18
|
+
* TypeORM 의 세 번째 인자(nulls)도 쓸 수 없다 — SelectQueryBuilder 가 드라이버를 보지 않고
|
|
19
|
+
* 「ASC NULLS LAST」를 그대로 붙인다(1331행).
|
|
20
|
+
*
|
|
21
|
+
* ── 식은 select 로 올려서 정렬한다 ─────────────────────────────────────────
|
|
22
|
+
* orderBy 에 식을 그대로 주면 TypeORM 이 **첫 점을 alias 로 읽는다.** 실측 오류:
|
|
23
|
+
* 「"CASE WHEN "at"" alias was not found」. 그래서 식을 select 에 이름 붙여 올리고, 정렬은 그
|
|
24
|
+
* 이름으로 건다 — 점이 없으므로 TypeORM 이 이름 그대로 통과시킨다.
|
|
25
|
+
*
|
|
26
|
+
* ── 여기에 SQL 을 적지 않는다 ──────────────────────────────────────────────
|
|
27
|
+
* 컬럼 이름은 부르는 쪽이 TypeORM 메타데이터에서 꺼내 넘긴다(fieldOf). 이 파일이 이름을 지어내면
|
|
28
|
+
* 명명 규칙이 바뀔 때 조용히 틀린다 — 이 프로젝트는 snake_case 라 dueAt 이 실제로는 due_at 이다.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.NULL_RANK_ALIAS = exports.TODO_NULLS_LAST = exports.TODO_INSTANCE_SORTS = void 0;
|
|
32
|
+
exports.todoOrderTerms = todoOrderTerms;
|
|
33
|
+
const nulls_last_js_1 = require("../nulls-last.js");
|
|
34
|
+
/** 업무 인스턴스(ai) 쪽 컬럼으로 정렬하는 이름들. 나머지는 스레드(at) 쪽이다. */
|
|
35
|
+
exports.TODO_INSTANCE_SORTS = new Set(['name', 'description', 'priority', 'creator', 'createdAt']);
|
|
36
|
+
/** 값이 없으면 뒤로 보낼 컬럼. 기한이 없는 일은 「언제까지」를 묻는 정렬에서 맨 뒤가 맞다. */
|
|
37
|
+
exports.TODO_NULLS_LAST = new Set(['dueAt']);
|
|
38
|
+
/* The nulls-last rule lives in one place — 결재함 sorts by 기한 too. */
|
|
39
|
+
var nulls_last_js_2 = require("../nulls-last.js");
|
|
40
|
+
Object.defineProperty(exports, "NULL_RANK_ALIAS", { enumerable: true, get: function () { return nulls_last_js_2.NULL_RANK_ALIAS; } });
|
|
41
|
+
/**
|
|
42
|
+
* 정렬 요청을 ORDER BY 항목들로 바꾼다.
|
|
43
|
+
*
|
|
44
|
+
* `fieldOf` 는 컬럼 이름을 따옴표까지 붙여 돌려준다. 못 찾으면 undefined 를 주고, 그때는 값 없는
|
|
45
|
+
* 것을 뒤로 보내는 항목을 만들지 않는다 — 지어낸 이름으로 SQL 을 세우지 않는다.
|
|
46
|
+
*/
|
|
47
|
+
function todoOrderTerms(sortings, fieldOf) {
|
|
48
|
+
const terms = [];
|
|
49
|
+
for (const sorting of sortings || []) {
|
|
50
|
+
if (!sorting?.name) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const alias = exports.TODO_INSTANCE_SORTS.has(sorting.name) ? 'ai' : 'at';
|
|
54
|
+
const direction = sorting.desc ? 'DESC' : 'ASC';
|
|
55
|
+
if (exports.TODO_NULLS_LAST.has(sorting.name)) {
|
|
56
|
+
const field = fieldOf(sorting.name);
|
|
57
|
+
/* 값이 없는 줄에 1 을 주어 뒤로 보낸다. 오름차순이든 내림차순이든 뒤다. */
|
|
58
|
+
if (field) {
|
|
59
|
+
terms.push({
|
|
60
|
+
expression: nulls_last_js_1.NULL_RANK_ALIAS,
|
|
61
|
+
direction: 'ASC',
|
|
62
|
+
select: (0, nulls_last_js_1.nullsLastSelect)(field)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
terms.push({ expression: `${alias}.${sorting.name}`, direction });
|
|
67
|
+
}
|
|
68
|
+
return terms;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=todo-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-order.js","sourceRoot":"","sources":["../../../server/service/activity-thread/todo-order.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;;AA0BH,wCA+BC;AAvDD,oDAAmE;AAEnE,qDAAqD;AACxC,QAAA,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAA;AAEvG,0DAA0D;AAC7C,QAAA,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;AASjD,mEAAmE;AACnE,kDAAkD;AAAzC,gHAAA,eAAe,OAAA;AAExB;;;;;GAKG;AACH,SAAgB,cAAc,CAC5B,QAA4C,EAC5C,OAA6C;IAE7C,MAAM,KAAK,GAAgB,EAAE,CAAA;IAE7B,KAAK,MAAM,OAAO,IAAI,QAAQ,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;YACnB,SAAQ;QACV,CAAC;QAED,MAAM,KAAK,GAAG,2BAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QACjE,MAAM,SAAS,GAAmB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAA;QAE/D,IAAI,uBAAe,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;YAEnC,+CAA+C;YAC/C,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,IAAI,CAAC;oBACT,UAAU,EAAE,+BAAe;oBAC3B,SAAS,EAAE,KAAK;oBAChB,MAAM,EAAE,IAAA,+BAAe,EAAC,KAAK,CAAC;iBAC/B,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;IACnE,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["/**\n * 「할 일」 목록의 정렬 규칙 — **기한이 없는 것은 뒤로 간다.**\n *\n * ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────\n * 화면의 기본 정렬은 dueAt 오름차순이다. 급한 것부터 보라는 뜻인데, **기한이 없는 것이 맨 위에\n * 왔다.** 실측(sqlite): 9건 중 기한 없는 6건이 먼저 나오고 「3일 지남」 3건이 맨 아래였다.\n *\n * NULL 을 앞에 둘지 뒤에 둘지는 **DB 마다 다르다** — sqlite 는 오름차순에서 NULL 이 먼저,\n * postgres 는 나중이다. 그래서 같은 코드가 개발 환경과 운영 환경에서 다른 순서를 낸다.\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 *\n * TypeORM 의 세 번째 인자(nulls)도 쓸 수 없다 — SelectQueryBuilder 가 드라이버를 보지 않고\n * 「ASC NULLS LAST」를 그대로 붙인다(1331행).\n *\n * ── 식은 select 로 올려서 정렬한다 ─────────────────────────────────────────\n * orderBy 에 식을 그대로 주면 TypeORM 이 **첫 점을 alias 로 읽는다.** 실측 오류:\n * 「\"CASE WHEN \"at\"\" alias was not found」. 그래서 식을 select 에 이름 붙여 올리고, 정렬은 그\n * 이름으로 건다 — 점이 없으므로 TypeORM 이 이름 그대로 통과시킨다.\n *\n * ── 여기에 SQL 을 적지 않는다 ──────────────────────────────────────────────\n * 컬럼 이름은 부르는 쪽이 TypeORM 메타데이터에서 꺼내 넘긴다(fieldOf). 이 파일이 이름을 지어내면\n * 명명 규칙이 바뀔 때 조용히 틀린다 — 이 프로젝트는 snake_case 라 dueAt 이 실제로는 due_at 이다.\n */\n\nimport { NULL_RANK_ALIAS, nullsLastSelect } from '../nulls-last.js'\n\n/** 업무 인스턴스(ai) 쪽 컬럼으로 정렬하는 이름들. 나머지는 스레드(at) 쪽이다. */\nexport const TODO_INSTANCE_SORTS = new Set(['name', 'description', 'priority', 'creator', 'createdAt'])\n\n/** 값이 없으면 뒤로 보낼 컬럼. 기한이 없는 일은 「언제까지」를 묻는 정렬에서 맨 뒤가 맞다. */\nexport const TODO_NULLS_LAST = new Set(['dueAt'])\n\nexport type OrderTerm = {\n expression: string\n direction: 'ASC' | 'DESC'\n /** 이 항목이 select 에 올려야 하는 식. 있으면 부르는 쪽이 addSelect 한다. */\n select?: string\n}\n\n/* The nulls-last rule lives in one place — 결재함 sorts by 기한 too. */\nexport { NULL_RANK_ALIAS } from '../nulls-last.js'\n\n/**\n * 정렬 요청을 ORDER BY 항목들로 바꾼다.\n *\n * `fieldOf` 는 컬럼 이름을 따옴표까지 붙여 돌려준다. 못 찾으면 undefined 를 주고, 그때는 값 없는\n * 것을 뒤로 보내는 항목을 만들지 않는다 — 지어낸 이름으로 SQL 을 세우지 않는다.\n */\nexport function todoOrderTerms(\n sortings: { name: string; desc?: boolean }[],\n fieldOf: (name: string) => string | undefined\n): OrderTerm[] {\n const terms: OrderTerm[] = []\n\n for (const sorting of sortings || []) {\n if (!sorting?.name) {\n continue\n }\n\n const alias = TODO_INSTANCE_SORTS.has(sorting.name) ? 'ai' : 'at'\n const direction: 'ASC' | 'DESC' = sorting.desc ? 'DESC' : 'ASC'\n\n if (TODO_NULLS_LAST.has(sorting.name)) {\n const field = fieldOf(sorting.name)\n\n /* 값이 없는 줄에 1 을 주어 뒤로 보낸다. 오름차순이든 내림차순이든 뒤다. */\n if (field) {\n terms.push({\n expression: NULL_RANK_ALIAS,\n direction: 'ASC',\n select: nullsLastSelect(field)\n })\n }\n }\n\n terms.push({ expression: `${alias}.${sorting.name}`, direction })\n }\n\n return terms\n}\n"]}
|