@rudderhq/server 0.2.7-canary.2 → 0.2.7-canary.20
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/bundled-plugins/plugin-linear/dist/worker.js +22 -0
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +26 -1
- package/dist/config.js.map +1 -1
- package/dist/database-backup-scheduler.d.ts +37 -0
- package/dist/database-backup-scheduler.d.ts.map +1 -0
- package/dist/database-backup-scheduler.js +50 -0
- package/dist/database-backup-scheduler.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -10
- package/dist/index.js.map +1 -1
- package/dist/routes/calendar.js +1 -1
- package/dist/routes/calendar.js.map +1 -1
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +129 -3
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/sidebar-badges.d.ts.map +1 -1
- package/dist/routes/sidebar-badges.js +12 -25
- package/dist/routes/sidebar-badges.js.map +1 -1
- package/dist/services/automation-chat-output.d.ts.map +1 -1
- package/dist/services/automation-chat-output.js +1 -11
- package/dist/services/automation-chat-output.js.map +1 -1
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +12 -40
- package/dist/services/automations.js.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +1 -1
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +27 -3
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chats.d.ts +25 -0
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.js +45 -0
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts.map +1 -1
- package/dist/services/costs.js +163 -44
- package/dist/services/costs.js.map +1 -1
- package/dist/services/messenger.d.ts +2 -16
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +261 -50
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/orgs.d.ts.map +1 -1
- package/dist/services/orgs.js +2 -1
- package/dist/services/orgs.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.js +53 -2
- package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.js +79 -9
- package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -1
- package/dist/services/sidebar-badges.d.ts +20 -6
- package/dist/services/sidebar-badges.d.ts.map +1 -1
- package/dist/services/sidebar-badges.js +172 -34
- package/dist/services/sidebar-badges.js.map +1 -1
- package/package.json +13 -13
- package/ui-dist/assets/{_basePickBy-Dt5BZkFR.js → _basePickBy-Z-nVVgZf.js} +1 -1
- package/ui-dist/assets/{_baseUniq-BV6xkV-q.js → _baseUniq-Dh-6NL8P.js} +1 -1
- package/ui-dist/assets/{arc-BavI3Cpg.js → arc-Dx0oQadP.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-D084Ft-t.js → architectureDiagram-2XIMDMQ5-CWuo8Dj6.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-B11F-ZeY.js → blockDiagram-WCTKOSBZ-CbcNpbB_.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-CU79tVS8.js → c4Diagram-IC4MRINW-Dsqi1Fq9.js} +1 -1
- package/ui-dist/assets/channel-C0eHQJ77.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-Bg9R5H9K.js → chunk-4BX2VUAB-CRY-15XU.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-Jn5G2tt5.js → chunk-55IACEB6-duEUUC1_.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-JXfQE2rg.js → chunk-FMBD7UC4-DIXiuDXe.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-BAeArUQT.js → chunk-JSJVCQXG-CBw9Zve6.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-CrZqiCTV.js → chunk-KX2RTZJC-Cbcp4AQs.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-BqWqHlDy.js → chunk-NQ4KR5QH-C7bmgFmt.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-BqwOeAXJ.js → chunk-QZHKN3VN-DX9ha7sr.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-CnekGXD1.js → chunk-WL4C6EOR-Ds_jtgg-.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-BYwRa3N4.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-BYwRa3N4.js +1 -0
- package/ui-dist/assets/clone-BoMzR_MV.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-Bb0oormu.js → cose-bilkent-S5V4N54A-BTZXqhQM.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-Di0mSC7I.js → dagre-KLK3FWXG-DoagFvkM.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-BmboA6j9.js → diagram-E7M64L7V-CB3LSeL7.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-kZhtKkiD.js → diagram-IFDJBPK2-DYl5A0v_.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-XW7Rz4Bf.js → diagram-P4PSJMXO-B75eqyOE.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-BNczf0Sk.js → erDiagram-INFDFZHY-DQr-k6Ob.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-Ch_czQvO.js → flowDiagram-PKNHOUZH-Ocns_Qv9.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-C1URfdUK.js → ganttDiagram-A5KZAMGK-BjE__MFt.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-CcxWHXyd.js → gitGraphDiagram-K3NZZRJ6-C2kH5giJ.js} +1 -1
- package/ui-dist/assets/{graph-V1OMZqHH.js → graph-DCiMHpHb.js} +1 -1
- package/ui-dist/assets/{index-D_kInGws.js → index-BC5uZF8E.js} +1 -1
- package/ui-dist/assets/{index-D6HKN84d.js → index-BFfolhzq.js} +1 -1
- package/ui-dist/assets/{index-ryg6l2z9.js → index-BI02BXrX.js} +1 -1
- package/ui-dist/assets/{index-DzAtWBqd.js → index-BM2f3uhO.js} +1 -1
- package/ui-dist/assets/{index-DB47pZF6.js → index-BRhp1mgy.js} +1 -1
- package/ui-dist/assets/{index-CL_6t72P.js → index-BRjIyHuE.js} +1 -1
- package/ui-dist/assets/{index-TVEu67wj.js → index-BfivROpG.js} +1 -1
- package/ui-dist/assets/{index-S47mKW1y.js → index-Bqp_LUjM.js} +1 -1
- package/ui-dist/assets/{index-BeN23vsN.js → index-C6S5PhGB.js} +1 -1
- package/ui-dist/assets/{index-C09tSW5o.js → index-C8YCz15P.js} +1 -1
- package/ui-dist/assets/index-CEnH7dl6.css +1 -0
- package/ui-dist/assets/{index-BB4cyXDK.js → index-CGZps8RJ.js} +1 -1
- package/ui-dist/assets/{index-QBpzNJ_D.js → index-CL6ddeTd.js} +1 -1
- package/ui-dist/assets/{index-Cdz1D2gL.js → index-ClUvF5DZ.js} +1 -1
- package/ui-dist/assets/{index-CECy-vrC.js → index-CwWteDDT.js} +1 -1
- package/ui-dist/assets/{index-D5aBaXzj.js → index-D4FPw6Z-.js} +1 -1
- package/ui-dist/assets/{index-DYEitDv9.js → index-DE8Or43O.js} +1 -1
- package/ui-dist/assets/{index-DkmRKRUV.js → index-DTEf2nnT.js} +1 -1
- package/ui-dist/assets/{index-BlRJUkpp.js → index-DYK0Hv0u.js} +1 -1
- package/ui-dist/assets/{index-DdJ5VFjZ.js → index-DqZcHxj3.js} +1 -1
- package/ui-dist/assets/{index-BV8o7Fq3.js → index-FeiA9wfj.js} +1 -1
- package/ui-dist/assets/{index-CVEsvjFN.js → index-SOxEvpVg.js} +1 -1
- package/ui-dist/assets/{index-DY84bnqq.js → index-jnmcBz-Q.js} +1 -1
- package/ui-dist/assets/index-tihUm8g4.js +1528 -0
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-iClsiP3Z.js → infoDiagram-LFFYTUFH-EYWd-pp8.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-BttLWbR-.js → ishikawaDiagram-PHBUUO56-CXBLaizm.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-DtuvfDLZ.js → journeyDiagram-4ABVD52K-AZ1urW_B.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-DInRSYDg.js → kanban-definition-K7BYSVSG-C0wbmei0.js} +1 -1
- package/ui-dist/assets/{layout-_3fh9W3_.js → layout-D1zBnRfr.js} +1 -1
- package/ui-dist/assets/{linear-BPKSoGxr.js → linear-DotDRzvv.js} +1 -1
- package/ui-dist/assets/{mermaid.core-4SnxubJe.js → mermaid.core-CkITwr03.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-YRQLILUH-CEFlhL8P.js → mindmap-definition-YRQLILUH-Dfd2b6xG.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-B52KJjTW.js → pieDiagram-SKSYHLDU-C9UKudln.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-CM8WWsTV.js → quadrantDiagram-337W2JSQ-bOy85C9o.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-CqLV4dlq.js → requirementDiagram-Z7DCOOCP-NJgBrRFH.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-BWciQ_Qk.js → sankeyDiagram-WA2Y5GQK-CjKs8Ww5.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-DqPHsdhr.js → sequenceDiagram-2WXFIKYE-BeBTWv23.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-BFd1hpKm.js → stateDiagram-RAJIS63D-BpGOOwbe.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-Cpt3cnOp.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-CVDJHxkz.js → timeline-definition-YZTLITO2-XKaBljll.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-BSISEEpV.js → treemap-KZPCXAKY-kWJ2O44d.js} +1 -1
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-BkeCtczy.js → vennDiagram-LZ73GAT5-BUqICYfS.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-CcXKs2fL.js → xychartDiagram-JWTSCODW-C7kF7s-X.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/channel-DMQmi8-S.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-CMV-ujRZ.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CMV-ujRZ.js +0 -1
- package/ui-dist/assets/clone-BWKwW-sv.js +0 -1
- package/ui-dist/assets/index-B137l9Mb.js +0 -1511
- package/ui-dist/assets/index-CpjJLMdb.css +0 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-By51CxHn.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Db } from "@rudderhq/db";
|
|
2
|
-
import { type MessengerApprovalThreadItem, type MessengerBudgetThreadItem, type MessengerHeartbeatRunThreadItem, type MessengerIssueThreadItem, type MessengerJoinRequestThreadItem, type MessengerSystemThreadKind, type MessengerThreadSummary } from "@rudderhq/shared";
|
|
2
|
+
import { type MessengerApprovalThreadItem, type MessengerBudgetThreadItem, type MessengerHeartbeatRunThreadItem, type MessengerIssueThreadItem, type MessengerJoinRequestThreadItem, type MessengerSystemThreadKind, type MessengerThreadDetail, type MessengerThreadSummary } from "@rudderhq/shared";
|
|
3
3
|
import { chatService } from "./chats.js";
|
|
4
4
|
type ThreadReadState = {
|
|
5
5
|
lastReadAt: Date;
|
|
@@ -14,21 +14,7 @@ export declare function messengerService(db: Db): {
|
|
|
14
14
|
} | null>;
|
|
15
15
|
getIssuesThread: (orgId: string, userId: string) => Promise<{
|
|
16
16
|
summary: MessengerThreadSummary;
|
|
17
|
-
detail:
|
|
18
|
-
threadKey: string;
|
|
19
|
-
kind: "issues";
|
|
20
|
-
title: string;
|
|
21
|
-
subtitle: string;
|
|
22
|
-
preview: string | null;
|
|
23
|
-
latestActivityAt: Date | null;
|
|
24
|
-
lastReadAt: Date | null;
|
|
25
|
-
unreadCount: number;
|
|
26
|
-
needsAttention: boolean;
|
|
27
|
-
isPinned: false;
|
|
28
|
-
href: string;
|
|
29
|
-
description: string;
|
|
30
|
-
items: MessengerIssueThreadItem[];
|
|
31
|
-
};
|
|
17
|
+
detail: MessengerThreadDetail<MessengerIssueThreadItem>;
|
|
32
18
|
}>;
|
|
33
19
|
getApprovalsThread: (orgId: string, userId: string) => Promise<{
|
|
34
20
|
summary: MessengerThreadSummary;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messenger.d.ts","sourceRoot":"","sources":["../../src/services/messenger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAcvC,OAAO,EASL,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAE9B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,
|
|
1
|
+
{"version":3,"file":"messenger.d.ts","sourceRoot":"","sources":["../../src/services/messenger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAcvC,OAAO,EASL,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAE9B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAE9B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA8BzC,KAAK,eAAe,GAAG;IACrB,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAgIF,KAAK,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAK/F,KAAK,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAqiBlG,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE;iCA2rBK,MAAM,UAAU,MAAM;oCA0DnB,MAAM,UAAU,MAAM;sBAKjC,mBAAmB;kBAC3B,cAAc,EAAE;;6BA3BJ,MAAM,UAAU,MAAM;;;;gCAInB,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;6BAIzB,MAAM,UAAU,MAAM,cAAc,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAuB9D,MAAM,UAAU,MAAM,aAAa,MAAM;;;;;;;;;4BAQzC,MAAM,UAAU,MAAM,aAAa,MAAM;2BAAzC,MAAM,UAAU,MAAM,aAAa,MAAM;EA+C/E"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, desc, eq, inArray, isNull, or } from "drizzle-orm";
|
|
1
|
+
import { and, desc, eq, gt, inArray, isNull, or, sql } from "drizzle-orm";
|
|
2
2
|
import { activityLog, approvalComments, approvals, agents, authUsers, heartbeatRuns, issueComments, issues, joinRequests, messengerThreadUserStates, } from "@rudderhq/db";
|
|
3
3
|
import { formatMessengerPreview, formatMessengerTitle, } from "@rudderhq/shared";
|
|
4
4
|
import { issueService } from "./issues.js";
|
|
@@ -496,6 +496,10 @@ async function loadThreadStates(db, orgId, userId, threadKeys) {
|
|
|
496
496
|
.where(and(eq(messengerThreadUserStates.orgId, orgId), eq(messengerThreadUserStates.userId, userId), inArray(messengerThreadUserStates.threadKey, threadKeys)));
|
|
497
497
|
return new Map(rows.map((row) => [row.threadKey, row]));
|
|
498
498
|
}
|
|
499
|
+
async function lastReadAtForThread(db, orgId, userId, threadKey, threadStates) {
|
|
500
|
+
const states = threadStates ?? loadThreadStates(db, orgId, userId, [threadKey]);
|
|
501
|
+
return (await states).get(threadKey)?.lastReadAt ?? null;
|
|
502
|
+
}
|
|
499
503
|
export function messengerService(db) {
|
|
500
504
|
const issuesSvc = issueService(db);
|
|
501
505
|
const chatsSvc = chatService(db);
|
|
@@ -538,30 +542,45 @@ export function messengerService(db) {
|
|
|
538
542
|
}
|
|
539
543
|
return Array.from(universe.values());
|
|
540
544
|
}
|
|
541
|
-
async function
|
|
545
|
+
async function loadIssueData(orgId, userId, threadStates, options) {
|
|
546
|
+
const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "issues", threadStates);
|
|
542
547
|
const issuesUniverse = await loadIssueUniverse(orgId, userId);
|
|
543
548
|
const issueIds = issuesUniverse.map((row) => row.id);
|
|
544
|
-
const
|
|
545
|
-
const lastReadAt = threadStates.get("issues")?.lastReadAt ?? null;
|
|
549
|
+
const lastReadAt = await lastReadAtPromise;
|
|
546
550
|
const [commentRows, activityRows] = await Promise.all([
|
|
547
551
|
issueIds.length === 0
|
|
548
552
|
? Promise.resolve([])
|
|
549
|
-
:
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
553
|
+
: options.includeDetail
|
|
554
|
+
? db
|
|
555
|
+
.select({
|
|
556
|
+
id: issueComments.id,
|
|
557
|
+
issueId: issueComments.issueId,
|
|
558
|
+
body: issueComments.body,
|
|
559
|
+
authorAgentId: issueComments.authorAgentId,
|
|
560
|
+
authorUserId: issueComments.authorUserId,
|
|
561
|
+
authorAgentName: agents.name,
|
|
562
|
+
authorUserName: authUsers.name,
|
|
563
|
+
createdAt: issueComments.createdAt,
|
|
564
|
+
})
|
|
565
|
+
.from(issueComments)
|
|
566
|
+
.leftJoin(agents, eq(issueComments.authorAgentId, agents.id))
|
|
567
|
+
.leftJoin(authUsers, eq(issueComments.authorUserId, authUsers.id))
|
|
568
|
+
.where(and(eq(issueComments.orgId, orgId), inArray(issueComments.issueId, issueIds)))
|
|
569
|
+
.orderBy(desc(issueComments.createdAt))
|
|
570
|
+
: db
|
|
571
|
+
.select({
|
|
572
|
+
id: issueComments.id,
|
|
573
|
+
issueId: issueComments.issueId,
|
|
574
|
+
body: issueComments.body,
|
|
575
|
+
authorAgentId: issueComments.authorAgentId,
|
|
576
|
+
authorUserId: issueComments.authorUserId,
|
|
577
|
+
authorAgentName: sql `null`,
|
|
578
|
+
authorUserName: sql `null`,
|
|
579
|
+
createdAt: issueComments.createdAt,
|
|
580
|
+
})
|
|
581
|
+
.from(issueComments)
|
|
582
|
+
.where(and(eq(issueComments.orgId, orgId), inArray(issueComments.issueId, issueIds), sql `(${issueComments.authorUserId} is null or ${issueComments.authorUserId} <> ${userId})`))
|
|
583
|
+
.orderBy(desc(issueComments.createdAt)),
|
|
565
584
|
issueIds.length === 0
|
|
566
585
|
? Promise.resolve([])
|
|
567
586
|
: db
|
|
@@ -582,7 +601,7 @@ export function messengerService(db) {
|
|
|
582
601
|
const latestCommentByIssue = new Map();
|
|
583
602
|
const latestExternalCommentByIssue = new Map();
|
|
584
603
|
for (const row of commentRows) {
|
|
585
|
-
if (!latestCommentByIssue.has(row.issueId)) {
|
|
604
|
+
if (options.includeDetail && !latestCommentByIssue.has(row.issueId)) {
|
|
586
605
|
latestCommentByIssue.set(row.issueId, row);
|
|
587
606
|
}
|
|
588
607
|
if (!isSelfAuthoredComment(row, userId) && !latestExternalCommentByIssue.has(row.issueId)) {
|
|
@@ -648,20 +667,26 @@ export function messengerService(db) {
|
|
|
648
667
|
: null;
|
|
649
668
|
const summaryPreview = attentionActivityAt ? issueThreadPreview(issue, attentionPreview) : null;
|
|
650
669
|
return {
|
|
651
|
-
|
|
670
|
+
issue,
|
|
671
|
+
item: options.includeDetail
|
|
672
|
+
? issueCard(issue, userId, issue.followed, latestPreview, latestActivityAt ?? issue.updatedAt, latestSourceIsComment ? latestVisibleComment : null, statusChangeActivity)
|
|
673
|
+
: null,
|
|
652
674
|
attentionActivityAt,
|
|
653
675
|
attentionPreview: summaryPreview,
|
|
654
676
|
};
|
|
655
677
|
});
|
|
656
|
-
const unsortedItems = unsortedEntries.map((entry) => entry.item);
|
|
657
678
|
const latestFirstEntries = [...unsortedEntries].sort((a, b) => {
|
|
658
679
|
const aTime = a.attentionActivityAt?.getTime() ?? Number.NEGATIVE_INFINITY;
|
|
659
680
|
const bTime = b.attentionActivityAt?.getTime() ?? Number.NEGATIVE_INFINITY;
|
|
660
681
|
if (aTime !== bTime)
|
|
661
682
|
return bTime - aTime;
|
|
662
|
-
return a.
|
|
683
|
+
return issueDisplayLabel(a.issue).localeCompare(issueDisplayLabel(b.issue));
|
|
663
684
|
});
|
|
664
|
-
const chronologicalItems =
|
|
685
|
+
const chronologicalItems = options.includeDetail
|
|
686
|
+
? unsortedEntries
|
|
687
|
+
.flatMap((entry) => entry.item ? [entry.item] : [])
|
|
688
|
+
.sort(compareChronologicalActivity)
|
|
689
|
+
: [];
|
|
665
690
|
const latestAttentionEntry = latestFirstEntries.find((entry) => entry.attentionActivityAt);
|
|
666
691
|
const latestActivityAt = latestAttentionEntry?.attentionActivityAt ?? null;
|
|
667
692
|
const unreadCount = unsortedEntries.filter((entry) => {
|
|
@@ -672,9 +697,12 @@ export function messengerService(db) {
|
|
|
672
697
|
return true;
|
|
673
698
|
return itemActivity.getTime() > lastReadAt.getTime();
|
|
674
699
|
}).length;
|
|
675
|
-
|
|
700
|
+
const data = {
|
|
676
701
|
summary: issueSummary(issuesUniverse.length, latestActivityAt, unreadCount, lastReadAt, latestAttentionEntry?.attentionPreview ?? null),
|
|
677
|
-
|
|
702
|
+
itemCount: issuesUniverse.length,
|
|
703
|
+
};
|
|
704
|
+
if (options.includeDetail) {
|
|
705
|
+
data.detail = {
|
|
678
706
|
threadKey: "issues",
|
|
679
707
|
kind: "issues",
|
|
680
708
|
title: "Issues",
|
|
@@ -688,12 +716,22 @@ export function messengerService(db) {
|
|
|
688
716
|
href: "/messenger/issues",
|
|
689
717
|
description: "Followed issues, issues I created, issues assigned to me, and issues ready for my review",
|
|
690
718
|
items: chronologicalItems,
|
|
691
|
-
}
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
return data;
|
|
722
|
+
}
|
|
723
|
+
async function loadIssueSummaryData(orgId, userId, threadStates) {
|
|
724
|
+
const data = await loadIssueData(orgId, userId, threadStates, { includeDetail: true });
|
|
725
|
+
return {
|
|
726
|
+
summary: data.summary,
|
|
727
|
+
detail: data.detail,
|
|
692
728
|
};
|
|
693
729
|
}
|
|
694
|
-
async function
|
|
695
|
-
|
|
696
|
-
|
|
730
|
+
async function loadIssueThreadSummaryData(orgId, userId, threadStates) {
|
|
731
|
+
return loadIssueData(orgId, userId, threadStates, { includeDetail: false });
|
|
732
|
+
}
|
|
733
|
+
async function loadApprovalSummaryData(orgId, userId, threadStates) {
|
|
734
|
+
const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "approvals", threadStates);
|
|
697
735
|
const [approvalRows, latestComments] = await Promise.all([
|
|
698
736
|
db
|
|
699
737
|
.select()
|
|
@@ -711,6 +749,7 @@ export function messengerService(db) {
|
|
|
711
749
|
.where(eq(approvals.orgId, orgId))
|
|
712
750
|
.orderBy(desc(approvalComments.createdAt)),
|
|
713
751
|
]);
|
|
752
|
+
const lastReadAt = await lastReadAtPromise;
|
|
714
753
|
const latestCommentByApproval = new Map();
|
|
715
754
|
for (const row of latestComments) {
|
|
716
755
|
if (!latestCommentByApproval.has(row.approvalId)) {
|
|
@@ -754,9 +793,95 @@ export function messengerService(db) {
|
|
|
754
793
|
},
|
|
755
794
|
};
|
|
756
795
|
}
|
|
757
|
-
async function
|
|
758
|
-
const
|
|
759
|
-
const
|
|
796
|
+
async function loadApprovalThreadSummaryData(orgId, userId, threadStates) {
|
|
797
|
+
const lastReadAt = await lastReadAtForThread(db, orgId, userId, "approvals", threadStates);
|
|
798
|
+
const approvalPredicate = eq(approvals.orgId, orgId);
|
|
799
|
+
const pendingApprovalPredicate = and(eq(approvals.orgId, orgId), eq(approvals.status, "pending"));
|
|
800
|
+
const [summaryRows, latestApprovalRows, latestCommentRows, unreadRows] = await Promise.all([
|
|
801
|
+
db
|
|
802
|
+
.select({
|
|
803
|
+
itemCount: sql `count(*)::int`,
|
|
804
|
+
})
|
|
805
|
+
.from(approvals)
|
|
806
|
+
.where(approvalPredicate),
|
|
807
|
+
db
|
|
808
|
+
.select()
|
|
809
|
+
.from(approvals)
|
|
810
|
+
.where(approvalPredicate)
|
|
811
|
+
.orderBy(desc(approvals.updatedAt), desc(approvals.createdAt))
|
|
812
|
+
.limit(1),
|
|
813
|
+
db
|
|
814
|
+
.execute(sql `
|
|
815
|
+
select
|
|
816
|
+
latest_comment.approval_id as "approvalId",
|
|
817
|
+
latest_comment.body as "body",
|
|
818
|
+
latest_comment.created_at as "createdAt"
|
|
819
|
+
from ${approvals}
|
|
820
|
+
inner join lateral (
|
|
821
|
+
select
|
|
822
|
+
${approvalComments.approvalId},
|
|
823
|
+
${approvalComments.body},
|
|
824
|
+
${approvalComments.createdAt}
|
|
825
|
+
from ${approvalComments}
|
|
826
|
+
where ${approvalComments.orgId} = ${orgId}
|
|
827
|
+
and ${approvalComments.approvalId} = ${approvals.id}
|
|
828
|
+
order by ${approvalComments.createdAt} desc
|
|
829
|
+
limit 1
|
|
830
|
+
) latest_comment on true
|
|
831
|
+
where ${approvals.orgId} = ${orgId}
|
|
832
|
+
order by latest_comment.created_at desc
|
|
833
|
+
limit 1
|
|
834
|
+
`),
|
|
835
|
+
db
|
|
836
|
+
.select({
|
|
837
|
+
unreadCount: sql `count(*)::int`,
|
|
838
|
+
})
|
|
839
|
+
.from(approvals)
|
|
840
|
+
.where(lastReadAt ? and(pendingApprovalPredicate, gt(approvals.updatedAt, lastReadAt)) : pendingApprovalPredicate),
|
|
841
|
+
]);
|
|
842
|
+
const latestApproval = (latestApprovalRows[0] ?? null);
|
|
843
|
+
const latestApprovalCommentRows = latestApproval
|
|
844
|
+
? await db
|
|
845
|
+
.select({
|
|
846
|
+
approvalId: approvalComments.approvalId,
|
|
847
|
+
body: approvalComments.body,
|
|
848
|
+
createdAt: approvalComments.createdAt,
|
|
849
|
+
})
|
|
850
|
+
.from(approvalComments)
|
|
851
|
+
.where(eq(approvalComments.approvalId, latestApproval.id))
|
|
852
|
+
.orderBy(desc(approvalComments.createdAt))
|
|
853
|
+
.limit(1)
|
|
854
|
+
: [];
|
|
855
|
+
const latestCommentRow = (latestCommentRows[0] ?? null);
|
|
856
|
+
const latestCommentApprovalRows = latestCommentRow
|
|
857
|
+
? await db
|
|
858
|
+
.select()
|
|
859
|
+
.from(approvals)
|
|
860
|
+
.where(and(eq(approvals.id, latestCommentRow.approvalId), approvalPredicate))
|
|
861
|
+
.limit(1)
|
|
862
|
+
: [];
|
|
863
|
+
const candidateItems = [];
|
|
864
|
+
if (latestApproval) {
|
|
865
|
+
const latestComment = (latestApprovalCommentRows[0] ?? null);
|
|
866
|
+
const latestActivityAt = maxDate(latestApproval.updatedAt, latestComment?.createdAt) ?? latestApproval.updatedAt;
|
|
867
|
+
candidateItems.push(approvalCard(latestApproval, latestComment, userId, latestActivityAt));
|
|
868
|
+
}
|
|
869
|
+
if (latestCommentRow) {
|
|
870
|
+
const approval = (latestCommentApprovalRows[0] ?? null);
|
|
871
|
+
if (approval) {
|
|
872
|
+
const latestActivityAt = maxDate(approval.updatedAt, latestCommentRow.createdAt) ?? approval.updatedAt;
|
|
873
|
+
candidateItems.push(approvalCard(approval, latestCommentRow, userId, latestActivityAt));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
const latestItem = candidateItems.sort(compareLatestActivity)[0] ?? null;
|
|
877
|
+
const itemCount = Number(summaryRows[0]?.itemCount ?? 0);
|
|
878
|
+
return {
|
|
879
|
+
itemCount,
|
|
880
|
+
summary: approvalSummary(itemCount, latestItem?.latestActivityAt ?? null, Number(unreadRows[0]?.unreadCount ?? 0), lastReadAt, latestItem?.preview ?? null),
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
async function loadFailedRunData(orgId, userId, threadStates) {
|
|
884
|
+
const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "failed-runs", threadStates);
|
|
760
885
|
const [runRows, agentRows] = await Promise.all([
|
|
761
886
|
db
|
|
762
887
|
.select({
|
|
@@ -782,6 +907,7 @@ export function messengerService(db) {
|
|
|
782
907
|
.from(agents)
|
|
783
908
|
.where(eq(agents.orgId, orgId)),
|
|
784
909
|
]);
|
|
910
|
+
const lastReadAt = await lastReadAtPromise;
|
|
785
911
|
const agentNames = new Map(agentRows.map((row) => [row.id, row.name]));
|
|
786
912
|
const items = runRows.map((run) => failedRunCard(run, agentNames.get(run.agentId) ?? null));
|
|
787
913
|
const latestFirstItems = [...items].sort(compareLatestActivity);
|
|
@@ -807,10 +933,49 @@ export function messengerService(db) {
|
|
|
807
933
|
},
|
|
808
934
|
};
|
|
809
935
|
}
|
|
810
|
-
async function
|
|
811
|
-
const
|
|
812
|
-
const
|
|
936
|
+
async function loadFailedRunSummaryData(orgId, userId, threadStates) {
|
|
937
|
+
const lastReadAt = await lastReadAtForThread(db, orgId, userId, "failed-runs", threadStates);
|
|
938
|
+
const latestActivitySql = sql `max(coalesce(${heartbeatRuns.updatedAt}, ${heartbeatRuns.createdAt}))`;
|
|
939
|
+
const failedRunPredicate = and(eq(heartbeatRuns.orgId, orgId), eq(heartbeatRuns.status, "failed"));
|
|
940
|
+
const [summaryRows, latestRows, unreadRows] = await Promise.all([
|
|
941
|
+
db
|
|
942
|
+
.select({
|
|
943
|
+
itemCount: sql `count(*)::int`,
|
|
944
|
+
latestActivityAt: latestActivitySql,
|
|
945
|
+
})
|
|
946
|
+
.from(heartbeatRuns)
|
|
947
|
+
.where(failedRunPredicate),
|
|
948
|
+
db
|
|
949
|
+
.select({
|
|
950
|
+
error: heartbeatRuns.error,
|
|
951
|
+
stderrExcerpt: heartbeatRuns.stderrExcerpt,
|
|
952
|
+
})
|
|
953
|
+
.from(heartbeatRuns)
|
|
954
|
+
.where(failedRunPredicate)
|
|
955
|
+
.orderBy(desc(heartbeatRuns.updatedAt), desc(heartbeatRuns.createdAt))
|
|
956
|
+
.limit(1),
|
|
957
|
+
lastReadAt
|
|
958
|
+
? db
|
|
959
|
+
.select({
|
|
960
|
+
unreadCount: sql `count(*)::int`,
|
|
961
|
+
})
|
|
962
|
+
.from(heartbeatRuns)
|
|
963
|
+
.where(and(failedRunPredicate, gt(heartbeatRuns.updatedAt, lastReadAt)))
|
|
964
|
+
: Promise.resolve([]),
|
|
965
|
+
]);
|
|
966
|
+
const summaryRow = summaryRows[0];
|
|
967
|
+
const latestRun = latestRows[0] ?? null;
|
|
968
|
+
const itemCount = Number(summaryRow?.itemCount ?? 0);
|
|
969
|
+
const unreadCount = lastReadAt ? Number(unreadRows[0]?.unreadCount ?? 0) : itemCount;
|
|
970
|
+
return {
|
|
971
|
+
itemCount,
|
|
972
|
+
summary: systemSummary("failed-runs", "Failed runs", itemCount, normalizeDate(summaryRow?.latestActivityAt ?? null), unreadCount, lastReadAt, "No failed runs yet", truncate(latestRun?.error) ?? truncate(latestRun?.stderrExcerpt)),
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
async function loadBudgetAlertData(orgId, userId, threadStates) {
|
|
976
|
+
const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "budget-alerts", threadStates);
|
|
813
977
|
const incidents = ((await budgetsSvc.overview(orgId)).activeIncidents ?? []);
|
|
978
|
+
const lastReadAt = await lastReadAtPromise;
|
|
814
979
|
const items = incidents.map((incident) => budgetCard(incident));
|
|
815
980
|
const latestActivityAt = items[0]?.latestActivityAt ?? null;
|
|
816
981
|
const unreadCount = systemUnreadCountSince(incidents, lastReadAt);
|
|
@@ -833,14 +998,14 @@ export function messengerService(db) {
|
|
|
833
998
|
},
|
|
834
999
|
};
|
|
835
1000
|
}
|
|
836
|
-
async function loadJoinRequestData(orgId, userId) {
|
|
837
|
-
const
|
|
838
|
-
const lastReadAt = threadStates.get("join-requests")?.lastReadAt ?? null;
|
|
1001
|
+
async function loadJoinRequestData(orgId, userId, threadStates) {
|
|
1002
|
+
const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "join-requests", threadStates);
|
|
839
1003
|
const rows = (await db
|
|
840
1004
|
.select()
|
|
841
1005
|
.from(joinRequests)
|
|
842
1006
|
.where(and(eq(joinRequests.orgId, orgId), eq(joinRequests.status, "pending_approval")))
|
|
843
1007
|
.orderBy(desc(joinRequests.updatedAt), desc(joinRequests.createdAt)));
|
|
1008
|
+
const lastReadAt = await lastReadAtPromise;
|
|
844
1009
|
const items = rows.map((row) => joinRequestCard(row));
|
|
845
1010
|
const latestActivityAt = items[0]?.latestActivityAt ?? null;
|
|
846
1011
|
const unreadCount = systemUnreadCountSince(rows, lastReadAt);
|
|
@@ -863,25 +1028,71 @@ export function messengerService(db) {
|
|
|
863
1028
|
},
|
|
864
1029
|
};
|
|
865
1030
|
}
|
|
1031
|
+
async function loadJoinRequestSummaryData(orgId, userId, threadStates) {
|
|
1032
|
+
const lastReadAt = await lastReadAtForThread(db, orgId, userId, "join-requests", threadStates);
|
|
1033
|
+
const latestActivitySql = sql `max(coalesce(${joinRequests.updatedAt}, ${joinRequests.createdAt}))`;
|
|
1034
|
+
const joinRequestPredicate = and(eq(joinRequests.orgId, orgId), eq(joinRequests.status, "pending_approval"));
|
|
1035
|
+
const [summaryRows, latestRows, unreadRows] = await Promise.all([
|
|
1036
|
+
db
|
|
1037
|
+
.select({
|
|
1038
|
+
itemCount: sql `count(*)::int`,
|
|
1039
|
+
latestActivityAt: latestActivitySql,
|
|
1040
|
+
})
|
|
1041
|
+
.from(joinRequests)
|
|
1042
|
+
.where(joinRequestPredicate),
|
|
1043
|
+
db
|
|
1044
|
+
.select({
|
|
1045
|
+
capabilities: joinRequests.capabilities,
|
|
1046
|
+
requestEmailSnapshot: joinRequests.requestEmailSnapshot,
|
|
1047
|
+
})
|
|
1048
|
+
.from(joinRequests)
|
|
1049
|
+
.where(joinRequestPredicate)
|
|
1050
|
+
.orderBy(desc(joinRequests.updatedAt), desc(joinRequests.createdAt))
|
|
1051
|
+
.limit(1),
|
|
1052
|
+
lastReadAt
|
|
1053
|
+
? db
|
|
1054
|
+
.select({
|
|
1055
|
+
unreadCount: sql `count(*)::int`,
|
|
1056
|
+
})
|
|
1057
|
+
.from(joinRequests)
|
|
1058
|
+
.where(and(joinRequestPredicate, gt(joinRequests.updatedAt, lastReadAt)))
|
|
1059
|
+
: Promise.resolve([]),
|
|
1060
|
+
]);
|
|
1061
|
+
const summaryRow = summaryRows[0];
|
|
1062
|
+
const latestRequest = latestRows[0] ?? null;
|
|
1063
|
+
const itemCount = Number(summaryRow?.itemCount ?? 0);
|
|
1064
|
+
const unreadCount = lastReadAt ? Number(unreadRows[0]?.unreadCount ?? 0) : itemCount;
|
|
1065
|
+
return {
|
|
1066
|
+
itemCount,
|
|
1067
|
+
summary: systemSummary("join-requests", "Join requests", itemCount, normalizeDate(summaryRow?.latestActivityAt ?? null), unreadCount, lastReadAt, "No pending join requests", latestRequest?.capabilities ?? latestRequest?.requestEmailSnapshot ?? null),
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
866
1070
|
async function listThreadSummaries(orgId, userId) {
|
|
1071
|
+
const syntheticThreadStates = loadThreadStates(db, orgId, userId, [
|
|
1072
|
+
"issues",
|
|
1073
|
+
"approvals",
|
|
1074
|
+
"failed-runs",
|
|
1075
|
+
"budget-alerts",
|
|
1076
|
+
"join-requests",
|
|
1077
|
+
]);
|
|
867
1078
|
const [chats, issueData, approvalData, failedRunData, budgetData, joinRequestData] = await Promise.all([
|
|
868
|
-
chatsSvc.
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
loadBudgetAlertData(orgId, userId),
|
|
873
|
-
|
|
1079
|
+
chatsSvc.listSummaries(orgId, { status: "active" }, userId),
|
|
1080
|
+
loadIssueThreadSummaryData(orgId, userId, syntheticThreadStates),
|
|
1081
|
+
loadApprovalThreadSummaryData(orgId, userId, syntheticThreadStates),
|
|
1082
|
+
loadFailedRunSummaryData(orgId, userId, syntheticThreadStates),
|
|
1083
|
+
loadBudgetAlertData(orgId, userId, syntheticThreadStates),
|
|
1084
|
+
loadJoinRequestSummaryData(orgId, userId, syntheticThreadStates),
|
|
874
1085
|
]);
|
|
875
1086
|
const syntheticSummaries = [];
|
|
876
|
-
if (issueData.
|
|
1087
|
+
if (issueData.itemCount > 0)
|
|
877
1088
|
syntheticSummaries.push(issueData.summary);
|
|
878
|
-
if (approvalData.
|
|
1089
|
+
if (approvalData.itemCount > 0)
|
|
879
1090
|
syntheticSummaries.push(approvalData.summary);
|
|
880
|
-
if (failedRunData.
|
|
1091
|
+
if (failedRunData.itemCount > 0)
|
|
881
1092
|
syntheticSummaries.push(failedRunData.summary);
|
|
882
1093
|
if (budgetData.detail.items.length > 0)
|
|
883
1094
|
syntheticSummaries.push(budgetData.summary);
|
|
884
|
-
if (joinRequestData.
|
|
1095
|
+
if (joinRequestData.itemCount > 0)
|
|
885
1096
|
syntheticSummaries.push(joinRequestData.summary);
|
|
886
1097
|
const threadSummaries = [
|
|
887
1098
|
...chats.map(chatSummary),
|