@things-factory/worklist 10.1.44 → 10.1.47
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/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/activity-approval-ribon.d.ts +1 -1
- package/dist-client/components/activity-approval-ribon.js +2 -2
- package/dist-client/components/activity-approval-ribon.js.map +1 -1
- package/dist-client/components/activity-fields.d.ts +7 -0
- package/dist-client/components/activity-fields.js +8 -0
- package/dist-client/components/activity-fields.js.map +1 -1
- package/dist-client/components/activity-instance-ribon.d.ts +1 -1
- package/dist-client/components/activity-instance-ribon.js +2 -2
- package/dist-client/components/activity-instance-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-ribon.d.ts +1 -1
- package/dist-client/components/activity-thread-ribon.js +2 -2
- package/dist-client/components/activity-thread-ribon.js.map +1 -1
- package/dist-client/components/activity-thread-timeline.js +3 -4
- package/dist-client/components/activity-thread-timeline.js.map +1 -1
- package/dist-client/components/state-ribon.d.ts +9 -1
- package/dist-client/components/state-ribon.js +43 -34
- package/dist-client/components/state-ribon.js.map +1 -1
- package/dist-client/entity360/person-open-work-section.d.ts +23 -0
- package/dist-client/entity360/person-open-work-section.js +79 -0
- package/dist-client/entity360/person-open-work-section.js.map +1 -0
- package/dist-client/pages/activity-approval/activity-approval-page.js +2 -2
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-catalog/activity-detail-page.js +2 -2
- package/dist-client/pages/activity-catalog/activity-detail-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.js +19 -40
- package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.js +2 -2
- package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +2 -2
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view.js +2 -2
- package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/templates/activity-approval-context-template.js +6 -5
- package/dist-client/templates/activity-approval-context-template.js.map +1 -1
- package/dist-client/templates/activity-thread-context-template.js +3 -2
- package/dist-client/templates/activity-thread-context-template.js.map +1 -1
- package/dist-client/tsconfig.chk.tsbuildinfo +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/activity-summary/activity-summary-query.js +6 -53
- package/dist-server/service/activity-summary/activity-summary-query.js.map +1 -1
- package/dist-server/service/activity-summary/index.d.ts +2 -1
- package/dist-server/service/activity-summary/index.js +2 -1
- package/dist-server/service/activity-summary/index.js.map +1 -1
- package/dist-server/service/activity-summary/open-work.d.ts +5 -0
- package/dist-server/service/activity-summary/open-work.js +63 -0
- package/dist-server/service/activity-summary/open-work.js.map +1 -0
- package/dist-server/service/activity-summary/person-open-work.d.ts +17 -0
- package/dist-server/service/activity-summary/person-open-work.js +68 -0
- package/dist-server/service/activity-summary/person-open-work.js.map +1 -0
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -10
- package/tests/person-open-work.test.ts +91 -0
- package/translations/en.json +3 -11
- package/translations/ja.json +3 -11
- package/translations/ko.json +3 -11
- package/translations/ms.json +3 -11
- package/translations/zh.json +3 -11
|
@@ -2,55 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ActivitySummaryQuery = 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_summary_js_1 = require("./activity-summary.js");
|
|
10
|
-
const activity_thread_js_1 = require("../activity-thread/activity-thread.js");
|
|
11
|
-
const activity_approval_js_1 = require("../activity-approval/activity-approval.js");
|
|
12
|
-
const my_pending_approvals_js_1 = require("../activity-approval/my-pending-approvals.js");
|
|
13
9
|
const activity_instance_js_1 = require("../activity-instance/activity-instance.js");
|
|
10
|
+
const open_work_js_1 = require("./open-work.js");
|
|
14
11
|
let ActivitySummaryQuery = class ActivitySummaryQuery {
|
|
15
12
|
async activitySummary(context) {
|
|
16
13
|
return {};
|
|
17
14
|
}
|
|
18
15
|
async numberOfToDos(activitySummary, context) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
relations: ['roles']
|
|
23
|
-
});
|
|
24
|
-
const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id);
|
|
25
|
-
const excludedStatuses = [activity_thread_js_1.ActivityThreadStatus.Unassigned, activity_thread_js_1.ActivityThreadStatus.Ended, activity_thread_js_1.ActivityThreadStatus.Aborted];
|
|
26
|
-
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
27
|
-
repository: (0, shell_1.getRepository)(activity_thread_js_1.ActivityThread),
|
|
28
|
-
params: {},
|
|
29
|
-
domain,
|
|
30
|
-
alias: 'at'
|
|
31
|
-
})
|
|
32
|
-
.innerJoinAndSelect('at.activityInstance', 'ai')
|
|
33
|
-
.andWhere(new typeorm_1.Brackets(qb => {
|
|
34
|
-
qb.where('at.state NOT IN (:...excludedStatuses)', { excludedStatuses }).andWhere('at.assignee = :userId', {
|
|
35
|
-
userId: user.id
|
|
36
|
-
});
|
|
37
|
-
if (roles.length > 0) {
|
|
38
|
-
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
39
|
-
subQb
|
|
40
|
-
.where('ai.assigneeRole IN (:...roles)', { roles })
|
|
41
|
-
.andWhere(`at.state = '${activity_thread_js_1.ActivityThreadStatus.Unassigned}'`);
|
|
42
|
-
}));
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
return await queryBuilder.getCount();
|
|
16
|
+
const { domain, user } = context.state;
|
|
17
|
+
/* The rule lives in `open-work.ts`, shared with the person 360 - one answer to one question. */
|
|
18
|
+
return await (0, open_work_js_1.toDosOf)(domain, user.id);
|
|
46
19
|
}
|
|
47
20
|
async numberOfApprovalPendings(activitySummary, context) {
|
|
48
|
-
|
|
49
|
-
user = await (0, shell_1.getRepository)(auth_base_1.User).findOne({
|
|
50
|
-
where: { id: user.id },
|
|
51
|
-
relations: ['roles']
|
|
52
|
-
});
|
|
53
|
-
const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id);
|
|
21
|
+
const { domain, user } = context.state;
|
|
54
22
|
/*
|
|
55
23
|
* The badge asks the same question the inbox does, through the same clause.
|
|
56
24
|
*
|
|
@@ -75,22 +43,7 @@ let ActivitySummaryQuery = class ActivitySummaryQuery {
|
|
|
75
43
|
* inbox list and the calendar already share one clause for this; the badge is the third reader
|
|
76
44
|
* and now asks through it too. `myPendingApprovalsWhere` carries why each part is there.
|
|
77
45
|
*/
|
|
78
|
-
|
|
79
|
-
repository: (0, shell_1.getRepository)(activity_approval_js_1.ActivityApproval),
|
|
80
|
-
params: {},
|
|
81
|
-
domain,
|
|
82
|
-
alias: 'ap'
|
|
83
|
-
})
|
|
84
|
-
/*
|
|
85
|
-
* Counting rows needs no columns, so this query joined nothing while the other two readers
|
|
86
|
-
* joined for their own reasons. The clause is what decides: it is about to read the instance
|
|
87
|
-
* to answer whether the person judging raised it, and an unjoined caller throws rather than
|
|
88
|
-
* counting wrong. Joining here keeps the three readers answering the same question.
|
|
89
|
-
*/
|
|
90
|
-
.leftJoin('ap.activityThread', 'at')
|
|
91
|
-
.leftJoin('at.activityInstance', 'ai')
|
|
92
|
-
.andWhere((0, my_pending_approvals_js_1.myPendingApprovalsWhere)({ userId: user.id, roles }));
|
|
93
|
-
return await queryBuilder.getCount();
|
|
46
|
+
return await (0, open_work_js_1.pendingApprovalsOf)(domain, user.id);
|
|
94
47
|
}
|
|
95
48
|
async numberOfPicks(activitySummary, context) {
|
|
96
49
|
var { domain, user } = context.state;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-summary-query.js","sourceRoot":"","sources":["../../../server/service/activity-summary/activity-summary-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivitySummary } from './activity-summary.js'\nimport { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\nimport { ActivityInstance, ActivityInstanceStatus } from '../activity-instance/activity-instance.js'\n\n@Resolver(ActivitySummary)\nexport class ActivitySummaryQuery {\n @Query(returns => ActivitySummary!, { nullable: true, description: 'To fetch a Activity Summary' })\n async activitySummary(@Ctx() context: ResolverContext): Promise<ActivitySummary> {\n return {}\n }\n\n @FieldResolver(type => Number)\n async numberOfToDos(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n\n const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)\n\n const excludedStatuses = [ActivityThreadStatus.Unassigned, ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n params: {},\n domain,\n alias: 'at'\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 return await queryBuilder.getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfApprovalPendings(\n @Root() activitySummary: ActivitySummary,\n @Ctx() context: ResolverContext\n ): Promise<number> {\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 /*\n * The badge asks the same question the inbox does, through the same clause.\n *\n * ── What the badge was counting ───────────────────────────────────────\n * It had its own copy of \"not finished yet\", written as NOT IN four judgments, and that copy\n * had drifted three ways from the list it labels:\n *\n * closed a reference seat the case closed when it ended\n * aborted an approval closed because the thread was aborted\n * reference a seat that comments and never decides\n *\n * TERMINATED_JUDGMENTS holds six; this named four. So every ended thread and every case a\n * reference had been on kept adding to the number, and a role-held row had no judgment test at\n * all — once closed with nobody having pressed, `approver` stays empty and it would have been\n * counted forever, for everyone holding that role.\n *\n * The badge therefore read higher than the inbox it points at. Opening it showed fewer, or\n * nothing: a number that sends someone to an empty screen teaches them to stop believing it.\n *\n * ── Why the clause is borrowed rather than fixed here ─────────────────\n * Naming the six here would make the count right today and drift again at the seventh. The\n * inbox list and the calendar already share one clause for this; the badge is the third reader\n * and now asks through it too. `myPendingApprovalsWhere` carries why each part is there.\n */\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(ActivityApproval),\n params: {},\n domain,\n alias: 'ap'\n })\n /*\n * Counting rows needs no columns, so this query joined nothing while the other two readers\n * joined for their own reasons. The clause is what decides: it is about to read the instance\n * to answer whether the person judging raised it, and an unjoined caller throws rather than\n * counting wrong. Joining here keeps the three readers answering the same question.\n */\n .leftJoin('ap.activityThread', 'at')\n .leftJoin('at.activityInstance', 'ai')\n .andWhere(myPendingApprovalsWhere({ userId: user.id, roles }))\n\n return await queryBuilder.getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfPicks(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* \n activity-instance 중에서 아직 created 상태이면서, \n activity-instance의 assigneeRole 이 지정되지 않았거나,\n assigneeRole이 지정되었으면 그 Role에 내가 해당된 경우이면서,\n 나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는\n activity-instance 리스트를 모두 가져오는 쿼리이다.\n */\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 if (!roles.length) {\n return 0\n }\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .leftJoinAndSelect('ai.activityThreads', 'threads', 'threads.assignee = :user', { user: user.id })\n .andWhere('ai.state IN (:...status)', {\n status: [ActivityInstanceStatus.Issued, ActivityInstanceStatus.Unassigned]\n })\n .andWhere('ai.assigneeRole IN (:...roles)', { roles })\n .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */\n .getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfDrafts(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* 생성자가 자신이면서, 아직 Draft 상태인 activity-instance 리스트만 반환 */\n const status = [ActivityInstanceStatus.Draft]\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .andWhere('ai.state IN (:...status)', { status })\n .andWhere('ai.creator = :user', { user: user.id })\n .getCount()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-summary-query.js","sourceRoot":"","sources":["../../../server/service/activity-summary/activity-summary-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivitySummary } from './activity-summary.js'\nimport { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\nimport { ActivityInstance, ActivityInstanceStatus } from '../activity-instance/activity-instance.js'\nimport { pendingApprovalsOf, toDosOf } from './open-work.js'\n\n@Resolver(ActivitySummary)\nexport class ActivitySummaryQuery {\n @Query(returns => ActivitySummary!, { nullable: true, description: 'To fetch a Activity Summary' })\n async activitySummary(@Ctx() context: ResolverContext): Promise<ActivitySummary> {\n return {}\n }\n\n @FieldResolver(type => Number)\n async numberOfToDos(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, user } = context.state\n\n /* The rule lives in `open-work.ts`, shared with the person 360 - one answer to one question. */\n return await toDosOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfApprovalPendings(\n @Root() activitySummary: ActivitySummary,\n @Ctx() context: ResolverContext\n ): Promise<number> {\n const { domain, user } = context.state\n\n /*\n * The badge asks the same question the inbox does, through the same clause.\n *\n * ── What the badge was counting ───────────────────────────────────────\n * It had its own copy of \"not finished yet\", written as NOT IN four judgments, and that copy\n * had drifted three ways from the list it labels:\n *\n * closed a reference seat the case closed when it ended\n * aborted an approval closed because the thread was aborted\n * reference a seat that comments and never decides\n *\n * TERMINATED_JUDGMENTS holds six; this named four. So every ended thread and every case a\n * reference had been on kept adding to the number, and a role-held row had no judgment test at\n * all — once closed with nobody having pressed, `approver` stays empty and it would have been\n * counted forever, for everyone holding that role.\n *\n * The badge therefore read higher than the inbox it points at. Opening it showed fewer, or\n * nothing: a number that sends someone to an empty screen teaches them to stop believing it.\n *\n * ── Why the clause is borrowed rather than fixed here ─────────────────\n * Naming the six here would make the count right today and drift again at the seventh. The\n * inbox list and the calendar already share one clause for this; the badge is the third reader\n * and now asks through it too. `myPendingApprovalsWhere` carries why each part is there.\n */\n return await pendingApprovalsOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfPicks(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* \n activity-instance 중에서 아직 created 상태이면서, \n activity-instance의 assigneeRole 이 지정되지 않았거나,\n assigneeRole이 지정되었으면 그 Role에 내가 해당된 경우이면서,\n 나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는\n activity-instance 리스트를 모두 가져오는 쿼리이다.\n */\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 if (!roles.length) {\n return 0\n }\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .leftJoinAndSelect('ai.activityThreads', 'threads', 'threads.assignee = :user', { user: user.id })\n .andWhere('ai.state IN (:...status)', {\n status: [ActivityInstanceStatus.Issued, ActivityInstanceStatus.Unassigned]\n })\n .andWhere('ai.assigneeRole IN (:...roles)', { roles })\n .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */\n .getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfDrafts(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* 생성자가 자신이면서, 아직 Draft 상태인 activity-instance 리스트만 반환 */\n const status = [ActivityInstanceStatus.Draft]\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .andWhere('ai.state IN (:...status)', { status })\n .andWhere('ai.creator = :user', { user: user.id })\n .getCount()\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ActivitySummary } from "./activity-summary.js";
|
|
2
2
|
import { ActivitySummaryQuery } from "./activity-summary-query.js";
|
|
3
|
+
import { PersonOpenWorkQuery } from "./person-open-work.js";
|
|
3
4
|
export declare const entities: (typeof ActivitySummary)[];
|
|
4
|
-
export declare const resolvers: (typeof ActivitySummaryQuery)[];
|
|
5
|
+
export declare const resolvers: (typeof ActivitySummaryQuery | typeof PersonOpenWorkQuery)[];
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolvers = exports.entities = void 0;
|
|
4
4
|
const activity_summary_js_1 = require("./activity-summary.js");
|
|
5
5
|
const activity_summary_query_js_1 = require("./activity-summary-query.js");
|
|
6
|
+
const person_open_work_js_1 = require("./person-open-work.js");
|
|
6
7
|
exports.entities = [activity_summary_js_1.ActivitySummary];
|
|
7
|
-
exports.resolvers = [activity_summary_query_js_1.ActivitySummaryQuery];
|
|
8
|
+
exports.resolvers = [activity_summary_query_js_1.ActivitySummaryQuery, person_open_work_js_1.PersonOpenWorkQuery];
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/activity-summary/index.ts"],"names":[],"mappings":";;;AAAA,+DAAuD;AACvD,2EAAkE;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/activity-summary/index.ts"],"names":[],"mappings":";;;AAAA,+DAAuD;AACvD,2EAAkE;AAClE,+DAA2D;AAE9C,QAAA,QAAQ,GAAG,CAAC,qCAAe,CAAC,CAAA;AAC5B,QAAA,SAAS,GAAG,CAAC,gDAAoB,EAAE,yCAAmB,CAAC,CAAA","sourcesContent":["import { ActivitySummary } from \"./activity-summary.js\"\nimport { ActivitySummaryQuery } from \"./activity-summary-query.js\"\nimport { PersonOpenWorkQuery } from \"./person-open-work.js\"\n\nexport const entities = [ActivitySummary]\nexport const resolvers = [ActivitySummaryQuery, PersonOpenWorkQuery]\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */
|
|
3
|
+
export declare function toDosOf(domain: Domain, userId: string): Promise<number>;
|
|
4
|
+
/** Approvals waiting on the person - through the inbox's own clause. */
|
|
5
|
+
export declare function pendingApprovalsOf(domain: Domain, userId: string): Promise<number>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toDosOf = toDosOf;
|
|
4
|
+
exports.pendingApprovalsOf = pendingApprovalsOf;
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const activity_thread_js_1 = require("../activity-thread/activity-thread.js");
|
|
9
|
+
const activity_approval_js_1 = require("../activity-approval/activity-approval.js");
|
|
10
|
+
const my_pending_approvals_js_1 = require("../activity-approval/my-pending-approvals.js");
|
|
11
|
+
/**
|
|
12
|
+
* What a person has on their plate in one domain - the same questions the rail's badges ask.
|
|
13
|
+
*
|
|
14
|
+
* The badges asked them only of whoever is signed in, with the rule written inline. The person 360
|
|
15
|
+
* asks them of someone else (ADR-0067, the person 360 ruling), so the rule lives here once and both
|
|
16
|
+
* readers call it - a second copy would drift the way the approval count once did
|
|
17
|
+
* (`activity-summary-query.ts` records how).
|
|
18
|
+
*/
|
|
19
|
+
/** The roles a person holds in this domain - an approval or a thread held by role reaches them through these. */
|
|
20
|
+
async function rolesIn(domain, userId) {
|
|
21
|
+
const user = await (0, shell_1.getRepository)(auth_base_1.User).findOne({ where: { id: userId }, relations: ['roles'] });
|
|
22
|
+
return (user?.roles || []).filter(role => role.domainId === domain.id).map(role => role.id);
|
|
23
|
+
}
|
|
24
|
+
/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */
|
|
25
|
+
async function toDosOf(domain, userId) {
|
|
26
|
+
const roles = await rolesIn(domain, userId);
|
|
27
|
+
const excludedStatuses = [activity_thread_js_1.ActivityThreadStatus.Unassigned, activity_thread_js_1.ActivityThreadStatus.Ended, activity_thread_js_1.ActivityThreadStatus.Aborted];
|
|
28
|
+
return await (0, shell_1.getQueryBuilderFromListParams)({
|
|
29
|
+
repository: (0, shell_1.getRepository)(activity_thread_js_1.ActivityThread),
|
|
30
|
+
params: {},
|
|
31
|
+
domain,
|
|
32
|
+
alias: 'at'
|
|
33
|
+
})
|
|
34
|
+
.innerJoinAndSelect('at.activityInstance', 'ai')
|
|
35
|
+
.andWhere(new typeorm_1.Brackets(qb => {
|
|
36
|
+
qb.where('at.state NOT IN (:...excludedStatuses)', { excludedStatuses }).andWhere('at.assignee = :userId', {
|
|
37
|
+
userId
|
|
38
|
+
});
|
|
39
|
+
if (roles.length > 0) {
|
|
40
|
+
qb.orWhere(new typeorm_1.Brackets(subQb => {
|
|
41
|
+
subQb
|
|
42
|
+
.where('ai.assigneeRole IN (:...roles)', { roles })
|
|
43
|
+
.andWhere(`at.state = '${activity_thread_js_1.ActivityThreadStatus.Unassigned}'`);
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
}))
|
|
47
|
+
.getCount();
|
|
48
|
+
}
|
|
49
|
+
/** Approvals waiting on the person - through the inbox's own clause. */
|
|
50
|
+
async function pendingApprovalsOf(domain, userId) {
|
|
51
|
+
const roles = await rolesIn(domain, userId);
|
|
52
|
+
return await (0, shell_1.getQueryBuilderFromListParams)({
|
|
53
|
+
repository: (0, shell_1.getRepository)(activity_approval_js_1.ActivityApproval),
|
|
54
|
+
params: {},
|
|
55
|
+
domain,
|
|
56
|
+
alias: 'ap'
|
|
57
|
+
})
|
|
58
|
+
.leftJoin('ap.activityThread', 'at')
|
|
59
|
+
.leftJoin('at.activityInstance', 'ai')
|
|
60
|
+
.andWhere((0, my_pending_approvals_js_1.myPendingApprovalsWhere)({ userId, roles }))
|
|
61
|
+
.getCount();
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=open-work.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-work.js","sourceRoot":"","sources":["../../../server/service/activity-summary/open-work.ts"],"names":[],"mappings":";;AAyBA,0BA6BC;AAGD,gDAaC;AAtED,qCAAkC;AAElC,yDAAgD;AAChD,iDAA4F;AAE5F,8EAA4F;AAC5F,oFAA4E;AAC5E,0FAAsF;AAEtF;;;;;;;GAOG;AAEH,iHAAiH;AACjH,KAAK,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IACnD,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC/F,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC7F,CAAC;AAED,oGAAoG;AAC7F,KAAK,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IAC1D,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,MAAM,gBAAgB,GAAG,CAAC,yCAAoB,CAAC,UAAU,EAAE,yCAAoB,CAAC,KAAK,EAAE,yCAAoB,CAAC,OAAO,CAAC,CAAA;IAEpH,OAAO,MAAM,IAAA,qCAA6B,EAAC;QACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,mCAAc,CAAC;QACzC,MAAM,EAAE,EAAE;QACV,MAAM;QACN,KAAK,EAAE,IAAI;KACZ,CAAC;SACC,kBAAkB,CAAC,qBAAqB,EAAE,IAAI,CAAC;SAC/C,QAAQ,CACP,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QAChB,EAAE,CAAC,KAAK,CAAC,wCAAwC,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,uBAAuB,EAAE;YACzG,MAAM;SACP,CAAC,CAAA;QAEF,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,eAAe,yCAAoB,CAAC,UAAU,GAAG,CAAC,CAAA;YAChE,CAAC,CAAC,CACH,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CACH;SACA,QAAQ,EAAE,CAAA;AACf,CAAC;AAED,wEAAwE;AACjE,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,MAAc;IACrE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE3C,OAAO,MAAM,IAAA,qCAA6B,EAAC;QACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,uCAAgB,CAAC;QAC3C,MAAM,EAAE,EAAE;QACV,MAAM;QACN,KAAK,EAAE,IAAI;KACZ,CAAC;SACC,QAAQ,CAAC,mBAAmB,EAAE,IAAI,CAAC;SACnC,QAAQ,CAAC,qBAAqB,EAAE,IAAI,CAAC;SACrC,QAAQ,CAAC,IAAA,iDAAuB,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;SACpD,QAAQ,EAAE,CAAA;AACf,CAAC","sourcesContent":["import { Brackets } from 'typeorm'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\n\n/**\n * What a person has on their plate in one domain - the same questions the rail's badges ask.\n *\n * The badges asked them only of whoever is signed in, with the rule written inline. The person 360\n * asks them of someone else (ADR-0067, the person 360 ruling), so the rule lives here once and both\n * readers call it - a second copy would drift the way the approval count once did\n * (`activity-summary-query.ts` records how).\n */\n\n/** The roles a person holds in this domain - an approval or a thread held by role reaches them through these. */\nasync function rolesIn(domain: Domain, userId: string): Promise<string[]> {\n const user = await getRepository(User).findOne({ where: { id: userId }, relations: ['roles'] })\n return (user?.roles || []).filter(role => role.domainId === domain.id).map(role => role.id)\n}\n\n/** Threads assigned to the person and not finished, plus unassigned ones their role may pick up. */\nexport async function toDosOf(domain: Domain, userId: string): Promise<number> {\n const roles = await rolesIn(domain, userId)\n const excludedStatuses = [ActivityThreadStatus.Unassigned, ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityThread),\n params: {},\n domain,\n alias: 'at'\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\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 .getCount()\n}\n\n/** Approvals waiting on the person - through the inbox's own clause. */\nexport async function pendingApprovalsOf(domain: Domain, userId: string): Promise<number> {\n const roles = await rolesIn(domain, userId)\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityApproval),\n params: {},\n domain,\n alias: 'ap'\n })\n .leftJoin('ap.activityThread', 'at')\n .leftJoin('at.activityInstance', 'ai')\n .andWhere(myPendingApprovalsWhere({ userId, roles }))\n .getCount()\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class PersonOpenWork {
|
|
2
|
+
toDos: number;
|
|
3
|
+
approvalsPending: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The "work they hold" section of the person 360 (ADR-0067, the person 360 ruling).
|
|
7
|
+
*
|
|
8
|
+
* **Counts only.** ADR-0091 opens a case only to the people on it; a count opens no case, so a
|
|
9
|
+
* colleague in the same domain may see it. The cases themselves stay behind the inbox's own doors.
|
|
10
|
+
* The count answers the same question the person's own badges do (`open-work.ts`).
|
|
11
|
+
*
|
|
12
|
+
* **Only inside this domain.** A person who is not a member here gets no answer (null) - counts do
|
|
13
|
+
* not cross domains, and "not a member" is not "zero".
|
|
14
|
+
*/
|
|
15
|
+
export declare class PersonOpenWorkQuery {
|
|
16
|
+
personOpenWork(userId: string, context: ResolverContext): Promise<PersonOpenWork | null>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PersonOpenWorkQuery = exports.PersonOpenWork = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const open_work_js_1 = require("./open-work.js");
|
|
9
|
+
let PersonOpenWork = class PersonOpenWork {
|
|
10
|
+
};
|
|
11
|
+
exports.PersonOpenWork = PersonOpenWork;
|
|
12
|
+
tslib_1.__decorate([
|
|
13
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, {
|
|
14
|
+
description: 'Threads assigned to the person and not finished, plus unassigned ones their role may pick up.'
|
|
15
|
+
}),
|
|
16
|
+
tslib_1.__metadata("design:type", Number)
|
|
17
|
+
], PersonOpenWork.prototype, "toDos", void 0);
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Approvals waiting on the person.' }),
|
|
20
|
+
tslib_1.__metadata("design:type", Number)
|
|
21
|
+
], PersonOpenWork.prototype, "approvalsPending", void 0);
|
|
22
|
+
exports.PersonOpenWork = PersonOpenWork = tslib_1.__decorate([
|
|
23
|
+
(0, type_graphql_1.ObjectType)({ description: 'How much work a person holds in this domain - counts only, never the cases.' })
|
|
24
|
+
], PersonOpenWork);
|
|
25
|
+
/**
|
|
26
|
+
* The "work they hold" section of the person 360 (ADR-0067, the person 360 ruling).
|
|
27
|
+
*
|
|
28
|
+
* **Counts only.** ADR-0091 opens a case only to the people on it; a count opens no case, so a
|
|
29
|
+
* colleague in the same domain may see it. The cases themselves stay behind the inbox's own doors.
|
|
30
|
+
* The count answers the same question the person's own badges do (`open-work.ts`).
|
|
31
|
+
*
|
|
32
|
+
* **Only inside this domain.** A person who is not a member here gets no answer (null) - counts do
|
|
33
|
+
* not cross domains, and "not a member" is not "zero".
|
|
34
|
+
*/
|
|
35
|
+
let PersonOpenWorkQuery = class PersonOpenWorkQuery {
|
|
36
|
+
async personOpenWork(userId, context) {
|
|
37
|
+
const { domain } = context.state;
|
|
38
|
+
const member = await (0, shell_1.getRepository)(auth_base_1.User)
|
|
39
|
+
.createQueryBuilder('USER')
|
|
40
|
+
.innerJoin('USER.domains', 'DOMAIN')
|
|
41
|
+
.where('USER.id = :userId', { userId })
|
|
42
|
+
.andWhere('DOMAIN.id = :domainId', { domainId: domain.id })
|
|
43
|
+
.getCount();
|
|
44
|
+
if (!member)
|
|
45
|
+
return null;
|
|
46
|
+
return {
|
|
47
|
+
toDos: await (0, open_work_js_1.toDosOf)(domain, userId),
|
|
48
|
+
approvalsPending: await (0, open_work_js_1.pendingApprovalsOf)(domain, userId)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.PersonOpenWorkQuery = PersonOpenWorkQuery;
|
|
53
|
+
tslib_1.__decorate([
|
|
54
|
+
(0, type_graphql_1.Directive)('@privilege(category: "activity-instance", privilege: "query", domainOwnerGranted: true)'),
|
|
55
|
+
(0, type_graphql_1.Query)(returns => PersonOpenWork, {
|
|
56
|
+
nullable: true,
|
|
57
|
+
description: 'How much work a person holds in this domain - counts only. Null when the person is not a member here.'
|
|
58
|
+
}),
|
|
59
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('userId')),
|
|
60
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
61
|
+
tslib_1.__metadata("design:type", Function),
|
|
62
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
63
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
64
|
+
], PersonOpenWorkQuery.prototype, "personOpenWork", null);
|
|
65
|
+
exports.PersonOpenWorkQuery = PersonOpenWorkQuery = tslib_1.__decorate([
|
|
66
|
+
(0, type_graphql_1.Resolver)()
|
|
67
|
+
], PersonOpenWorkQuery);
|
|
68
|
+
//# sourceMappingURL=person-open-work.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"person-open-work.js","sourceRoot":"","sources":["../../../server/service/activity-summary/person-open-work.ts"],"names":[],"mappings":";;;;AAAA,+CAA2F;AAE3F,yDAAgD;AAChD,iDAAqD;AAErD,iDAA4D;AAGrD,IAAM,cAAc,GAApB,MAAM,cAAc;CAQ1B,CAAA;AARY,wCAAc;AAIzB;IAHC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE;QAClB,WAAW,EAAE,+FAA+F;KAC7G,CAAC;;6CACW;AAGb;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC;;wDAChD;yBAPb,cAAc;IAD1B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,6EAA6E,EAAE,CAAC;GAC9F,cAAc,CAQ1B;AAED;;;;;;;;;GASG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAMxB,AAAN,KAAK,CAAC,cAAc,CAAgB,MAAc,EAAS,OAAwB;QACjF,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC;aACrC,kBAAkB,CAAC,MAAM,CAAC;aAC1B,SAAS,CAAC,cAAc,EAAE,QAAQ,CAAC;aACnC,KAAK,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,CAAC;aACtC,QAAQ,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;aAC1D,QAAQ,EAAE,CAAA;QAEb,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAExB,OAAO;YACL,KAAK,EAAE,MAAM,IAAA,sBAAO,EAAC,MAAM,EAAE,MAAM,CAAC;YACpC,gBAAgB,EAAE,MAAM,IAAA,iCAAkB,EAAC,MAAM,EAAE,MAAM,CAAC;SAC3D,CAAA;IACH,CAAC;CACF,CAAA;AAvBY,kDAAmB;AAMxB;IALL,IAAA,wBAAS,EAAC,yFAAyF,CAAC;IACpG,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,cAAc,EAAE;QAChC,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,uGAAuG;KACrH,CAAC;IACoB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,CAAC,CAAA;IAAkB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;yDAgBzD;8BAtBU,mBAAmB;IAD/B,IAAA,uBAAQ,GAAE;GACE,mBAAmB,CAuB/B","sourcesContent":["import { Arg, Ctx, Directive, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { pendingApprovalsOf, toDosOf } from './open-work.js'\n\n@ObjectType({ description: 'How much work a person holds in this domain - counts only, never the cases.' })\nexport class PersonOpenWork {\n @Field(type => Int, {\n description: 'Threads assigned to the person and not finished, plus unassigned ones their role may pick up.'\n })\n toDos: number\n\n @Field(type => Int, { description: 'Approvals waiting on the person.' })\n approvalsPending: number\n}\n\n/**\n * The \"work they hold\" section of the person 360 (ADR-0067, the person 360 ruling).\n *\n * **Counts only.** ADR-0091 opens a case only to the people on it; a count opens no case, so a\n * colleague in the same domain may see it. The cases themselves stay behind the inbox's own doors.\n * The count answers the same question the person's own badges do (`open-work.ts`).\n *\n * **Only inside this domain.** A person who is not a member here gets no answer (null) - counts do\n * not cross domains, and \"not a member\" is not \"zero\".\n */\n@Resolver()\nexport class PersonOpenWorkQuery {\n @Directive('@privilege(category: \"activity-instance\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => PersonOpenWork, {\n nullable: true,\n description: 'How much work a person holds in this domain - counts only. Null when the person is not a member here.'\n })\n async personOpenWork(@Arg('userId') userId: string, @Ctx() context: ResolverContext): Promise<PersonOpenWork | null> {\n const { domain } = context.state\n\n const member = await getRepository(User)\n .createQueryBuilder('USER')\n .innerJoin('USER.domains', 'DOMAIN')\n .where('USER.id = :userId', { userId })\n .andWhere('DOMAIN.id = :domainId', { domainId: domain.id })\n .getCount()\n\n if (!member) return null\n\n return {\n toDos: await toDosOf(domain, userId),\n approvalsPending: await pendingApprovalsOf(domain, userId)\n }\n }\n}\n"]}
|
|
@@ -16,8 +16,8 @@ export * from './work-door/work-door-not-used.js';
|
|
|
16
16
|
export * from './work-door/work-door-journal.js';
|
|
17
17
|
export * from './work-door/work-door-journal-service.js';
|
|
18
18
|
export * from './work-door/work-door-service.js';
|
|
19
|
-
export declare const entities: (typeof import("./activity/activity.js").Activity | typeof import("./activity-approval/activity-approval.js").ActivityApproval | typeof import("./activity-thread/activity-thread.js").ActivityThread | typeof import("./activity-instance/activity-instance.js").ActivityInstance | typeof import("./installable-activity/installable-activity.js").InstallableActivity | typeof import("./activity-template/activity-template.js").ActivityTemplate | typeof import("./activity/activity-
|
|
19
|
+
export declare const entities: (typeof import("./activity/activity.js").Activity | typeof import("./activity-approval/activity-approval.js").ActivityApproval | typeof import("./activity-thread/activity-thread.js").ActivityThread | typeof import("./activity-instance/activity-instance.js").ActivityInstance | typeof import("./installable-activity/installable-activity.js").InstallableActivity | typeof import("./activity-template/activity-template.js").ActivityTemplate | typeof import("./activity-summary/activity-summary.js").ActivitySummary | typeof import("./activity/activity-history.js").ActivityHistory | typeof import("./activity-instance/activity-instance-history.js").ActivityInstanceHistory | typeof import("./activity-template/activity-template-history.js").ActivityTemplateHistory | typeof import("./activity-thread/activity-thread-history.js").ActivityThreadHistory | typeof import("./work-door/work-door-not-used.js").WorkDoorNotUsed | typeof import("./work-door/work-door-journal.js").WorkDoorJournal)[];
|
|
20
20
|
export declare const subscribers: (typeof import("./activity-approval/event-subscriber.js").ActivityApprovalSubscriber | typeof import("./activity/event-subscriber.js").ActivityHistoryEntitySubscriber | typeof import("./activity/declaration-guard-subscriber.js").ActivityDeclarationGuardSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceSubscriber | typeof import("./activity-instance/event-subscriber.js").ActivityInstanceHistoryEntitySubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadSubscriber | typeof import("./activity-thread/event-subscriber.js").ActivityThreadHistoryEntitySubscriber)[];
|
|
21
21
|
export declare const schema: {
|
|
22
|
-
resolverClasses: (typeof import("./activity-stats/activity-stats-query.js").ActivityStatsQuery | typeof import("./activity-approval/activity-approval-query.js").ActivityApprovalQuery | typeof import("./activity-approval/activity-approval-mutation.js").ActivityApprovalMutation | typeof import("./activity-approval/activity-approval-subscription.js").ActivityApprovalSubscription | typeof import("./activity/activity-mutation.js").ActivityMutation | typeof import("./activity/activity-query.js").ActivityQuery | typeof import("./activity-instance/activity-instance-mutation.js").ActivityInstanceMutation | typeof import("./activity-instance/activity-instance-query.js").ActivityInstanceQuery | typeof import("./activity-instance/activity-instance-subscription.js").ActivityInstanceSubscription | typeof import("./activity-template/activity-template-mutation.js").ActivityTemplateMutation | typeof import("./activity-template/activity-template-query.js").ActivityTemplateQuery | typeof import("./activity-thread/activity-thread-mutation.js").ActivityThreadMutation | typeof import("./activity-thread/activity-thread-query.js").ActivityThreadQuery | typeof import("./activity-thread/activity-thread-history-query.js").ActivityThreadHistoryQuery | typeof import("./activity-thread/activity-thread-subscription.js").ActivityThreadSubscription | typeof import("./installable-activity/installable-activity-query.js").InstallableActivityQuery | typeof import("./installable-activity/installable-activity-mutation.js").InstallableActivityMutation | typeof import("./activity-summary/activity-summary-query.js").ActivitySummaryQuery | typeof import("./work-door/work-door-resolver.js").WorkDoorResolver)[];
|
|
22
|
+
resolverClasses: (typeof import("./activity-stats/activity-stats-query.js").ActivityStatsQuery | typeof import("./activity-approval/activity-approval-query.js").ActivityApprovalQuery | typeof import("./activity-approval/activity-approval-mutation.js").ActivityApprovalMutation | typeof import("./activity-approval/activity-approval-subscription.js").ActivityApprovalSubscription | typeof import("./activity/activity-mutation.js").ActivityMutation | typeof import("./activity/activity-query.js").ActivityQuery | typeof import("./activity-instance/activity-instance-mutation.js").ActivityInstanceMutation | typeof import("./activity-instance/activity-instance-query.js").ActivityInstanceQuery | typeof import("./activity-instance/activity-instance-subscription.js").ActivityInstanceSubscription | typeof import("./activity-template/activity-template-mutation.js").ActivityTemplateMutation | typeof import("./activity-template/activity-template-query.js").ActivityTemplateQuery | typeof import("./activity-thread/activity-thread-mutation.js").ActivityThreadMutation | typeof import("./activity-thread/activity-thread-query.js").ActivityThreadQuery | typeof import("./activity-thread/activity-thread-history-query.js").ActivityThreadHistoryQuery | typeof import("./activity-thread/activity-thread-subscription.js").ActivityThreadSubscription | typeof import("./installable-activity/installable-activity-query.js").InstallableActivityQuery | typeof import("./installable-activity/installable-activity-mutation.js").InstallableActivityMutation | typeof import("./activity-summary/activity-summary-query.js").ActivitySummaryQuery | typeof import("./activity-summary/person-open-work.js").PersonOpenWorkQuery | typeof import("./work-door/work-door-resolver.js").WorkDoorResolver)[];
|
|
23
23
|
};
|