@wowyuarm/dsh-agent-team 0.1.11 → 0.1.12
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/README.md +4 -4
- package/README.zh.md +4 -4
- package/package.json +3 -2
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -2
- package/packages/agent-team/lib/context-projection.js +5 -1
- package/packages/agent-team/lib/index.js +11 -44
- package/packages/agent-team/lib/ledger.js +251 -142
- package/packages/agent-team/lib/member-runtime.js +47 -9
- package/packages/agent-team/lib/mentions.js +56 -0
- package/packages/agent-team/lib/spec.js +1 -0
- package/packages/agent-team/lib/typert.host.js +80 -31
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +71 -26
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +1 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +75 -17
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
- package/packages/agent-team/lib/types/mentions.d.ts +34 -0
- package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +0 -18
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +57 -15
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +48 -8
- package/packages/client-agent-team/lib/client.js +1366 -909
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +125 -13
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +10 -3
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +11 -17
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +1 -1
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +9 -5
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +82 -14
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +6 -2
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +28 -10
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +3 -4
- package/packages/client-agent-team/lib/types/client/locales.d.ts +36 -16
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +36 -16
- package/packages/client-agent-team/lib/types/client/slots.d.ts +0 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts +7 -1
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.js +62 -31
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +38 -5
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +54 -7
- package/packages/tool-agent-team/README.md +2 -2
- package/packages/tool-agent-team/README.zh.md +2 -2
- package/packages/tool-agent-team/lib/index.js +29 -16
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/progress-nudge.js +0 -328
- package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { formatAbsoluteTime, formatInboxTime } from "./team-formatters.js";
|
|
5
|
+
import { TeamAvatarStack } from "./TeamAvatarStack.js";
|
|
6
|
+
import { TeamCountBadge } from "./TeamCountBadge.js";
|
|
5
7
|
import css from './conversation.module.css';
|
|
6
8
|
import inboxCss from './inbox.module.css';
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* How many 「最近活跃」 rows the merged page may show. The Host bounds each
|
|
11
|
+
* Workspace's own slice; this is the single bound across every Workspace on
|
|
12
|
+
* screen, so the section stays the same size no matter how many are open — and
|
|
13
|
+
* it stays a way back into work rather than a second queue, which is why it is
|
|
14
|
+
* shorter than the queue the reader is actually being asked to work through.
|
|
15
|
+
*/
|
|
16
|
+
const RECENT_ROWS_LIMIT = 5;
|
|
17
|
+
/**
|
|
18
|
+
* Queue order: newest unread first, one total order across Workspaces. Each
|
|
9
19
|
* Workspace slice arrives in the Host's own order (that order is the Host's
|
|
10
20
|
* truncation policy); the merged display order is decided here, where the
|
|
11
21
|
* merge happens, and the ledger sequence breaks ties so the queue never
|
|
@@ -18,16 +28,21 @@ function compareInboxRows(left, right) {
|
|
|
18
28
|
return byTime !== 0 ? byTime : right.item.newestSequence - left.item.newestSequence;
|
|
19
29
|
}
|
|
20
30
|
/**
|
|
21
|
-
* The Human
|
|
22
|
-
*
|
|
23
|
-
*
|
|
31
|
+
* The Human Inbox: one Inbox call per visible Workspace, rendering the Host's
|
|
32
|
+
* two slices — the unread queue (「需要我」, mentions counted inside it rather
|
|
33
|
+
* than alone) and the 「最近活跃」 tail of Threads the reader took part in.
|
|
34
|
+
* Both merge across every Workspace into one recency-ordered list, newest
|
|
35
|
+
* first, since a queue is read by recency rather than by Workspace.
|
|
24
36
|
* Opening the page never acknowledges anything — only a durable Thread read
|
|
25
|
-
* consumes a mention marker, so rows and the badge
|
|
26
|
-
* opened through the existing auto-ack path.
|
|
37
|
+
* advances the watermark and consumes a mention marker, so rows and the badge
|
|
38
|
+
* drop after the Thread is opened through the existing auto-ack path. A Thread
|
|
39
|
+
* holding unread is only ever in the queue: the Host already excludes it from
|
|
40
|
+
* the tail, and this page never re-derives that judgement.
|
|
27
41
|
*/
|
|
28
42
|
export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }) {
|
|
29
43
|
const workspaces = useWorkspaces(state => state.items);
|
|
30
44
|
const [rows, setRows] = useState();
|
|
45
|
+
const [recentRows, setRecentRows] = useState([]);
|
|
31
46
|
const [loading, setLoading] = useState(true);
|
|
32
47
|
const [error, setError] = useState();
|
|
33
48
|
// Only the first refresh owns the loading surface; later wakes refresh the
|
|
@@ -37,15 +52,19 @@ export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, sele
|
|
|
37
52
|
if (!loadedRef.current)
|
|
38
53
|
setLoading(true);
|
|
39
54
|
const results = await Promise.all(workspaces.map(async (workspace) => {
|
|
40
|
-
const result = await loadInbox({ workspaceId: workspace.workspaceId,
|
|
55
|
+
const result = await loadInbox({ workspaceId: workspace.workspaceId, limit: 100 });
|
|
41
56
|
return result.ok
|
|
42
|
-
? { ok: true, workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, items: result.value.items }
|
|
57
|
+
? { ok: true, workspaceId: workspace.workspaceId, workspaceTitle: workspace.title, items: result.value.items, recent: result.value.recent }
|
|
43
58
|
: { ok: false, message: result.error.message };
|
|
44
59
|
}));
|
|
45
60
|
const failure = results.find(result => !result.ok);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
61
|
+
const asRows = (items, workspaceId, workspaceTitle) => items.map(item => ({ workspaceId, workspaceTitle, item }));
|
|
62
|
+
setRows(results.flatMap(result => result.ok ? asRows(result.items, result.workspaceId, result.workspaceTitle) : []).sort(compareInboxRows));
|
|
63
|
+
// The tail is one global bound rather than one per Workspace: the reader was
|
|
64
|
+
// promised ten Threads to step back into, and every Workspace's slice is
|
|
65
|
+
// already capped on its own, so the merged list is trimmed here.
|
|
66
|
+
setRecentRows(results.flatMap(result => result.ok ? asRows(result.recent, result.workspaceId, result.workspaceTitle) : [])
|
|
67
|
+
.sort(compareInboxRows).slice(0, RECENT_ROWS_LIMIT));
|
|
49
68
|
setError(failure?.ok === false ? failure.message : undefined);
|
|
50
69
|
loadedRef.current = true;
|
|
51
70
|
setLoading(false);
|
|
@@ -65,7 +84,56 @@ export function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, sele
|
|
|
65
84
|
// The page rides the shared conversation seat: the same header band, 880px
|
|
66
85
|
// reading column, responsive gutters, and scrollbar gutter as Channel and
|
|
67
86
|
// Thread, so switching surfaces does not shift the content column.
|
|
68
|
-
|
|
87
|
+
const totalUnread = rows?.reduce((sum, row) => sum + row.item.unreadCount, 0) ?? 0;
|
|
88
|
+
const totalMentions = rows?.reduce((sum, row) => sum + row.item.directCount, 0) ?? 0;
|
|
89
|
+
// A row names its Workspace only while the rows on screen span more than one.
|
|
90
|
+
// With a single Workspace in the list the segment is a constant printed down
|
|
91
|
+
// every row, which spends the row's most readable position on something that
|
|
92
|
+
// never varies; the moment a second Workspace reaches the list it comes back,
|
|
93
|
+
// because two rows then have to be tellable apart. This reads the rows rather
|
|
94
|
+
// than the open Workspaces: a Workspace holding nothing to show here is not a
|
|
95
|
+
// reason to keep printing the name of the one that is.
|
|
96
|
+
const shownWorkspaces = new Set();
|
|
97
|
+
for (const row of rows ?? [])
|
|
98
|
+
shownWorkspaces.add(row.workspaceTitle);
|
|
99
|
+
for (const row of recentRows)
|
|
100
|
+
shownWorkspaces.add(row.workspaceTitle);
|
|
101
|
+
const showWorkspace = shownWorkspaces.size > 1;
|
|
102
|
+
return _jsxs("main", { className: css.surface, "data-team-inbox": true, children: [_jsx("div", { className: css.surfaceHeader, children: _jsx("header", { className: css.headerRow, children: _jsxs("div", { className: css.headerCopy, children: [_jsx("h1", { children: t('inboxTitle') }), rows !== undefined && rows.length > 0 && _jsxs("p", { className: inboxCss.headerMeta, children: [_jsx("span", { children: t('inboxHeaderThreads', { count: rows.length }) }), _jsx("span", { className: inboxCss.headerUnread, children: t('inboxHeaderUnread', { count: totalUnread }) }), totalMentions > 0 && _jsx("span", { children: t('inboxHeaderMentions', { count: totalMentions }) })] })] }) }) }), _jsx("div", { className: css.timeline, children: _jsxs("div", { className: css.timelineContent, children: [loading && rows === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingInbox')] }) }), !loading && rows === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void refresh(); }, children: t('retry') })] }), rows !== undefined && (rows.length === 0 && recentRows.length === 0
|
|
69
103
|
? _jsx("div", { className: css.emptySurface, children: _jsxs("div", { className: css.emptyState, children: [_jsx("strong", { children: t('inboxEmptyTitle') }), _jsx("span", { children: t('inboxEmptyHint') })] }) })
|
|
70
|
-
:
|
|
104
|
+
: _jsxs(_Fragment, { children: [rows.length > 0 && _jsxs("section", { className: inboxCss.section, children: [_jsxs("h2", { className: inboxCss.sectionTitle, children: [t('inboxSectionNeedsMe'), _jsx("span", { className: inboxCss.sectionCount, children: rows.length })] }), _jsx("div", { className: inboxCss.list, children: rows.map(row => _jsx(InboxQueueRow, { row: row, t: t, showWorkspace: showWorkspace, onOpen: () => { open(row); } }, `${row.workspaceId} ${row.item.thread.threadRef}`)) })] }), recentRows.length > 0 && _jsxs("section", { className: inboxCss.section, children: [_jsxs("h2", { className: inboxCss.sectionTitle, children: [t('inboxSectionRecent'), _jsx("span", { className: inboxCss.sectionCount, children: recentRows.length })] }), _jsx("div", { className: inboxCss.list, children: recentRows.map(row => _jsx(InboxQueueRow, { row: row, t: t, showWorkspace: showWorkspace, onOpen: () => { open(row); } }, `${row.workspaceId} ${row.item.thread.threadRef}`)) })] })] })), rows !== undefined && error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] }) })] });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* One queue row, shaped like the shipped two-line result row: who is on this
|
|
108
|
+
* Thread leads in the gutter, the identity line answers which Thread this is,
|
|
109
|
+
* how much is waiting, and when it last moved, and the gist sits under it on the
|
|
110
|
+
* same column as evidence for that identity rather than as the row's subject.
|
|
111
|
+
*
|
|
112
|
+
* The gutter carries the one thing every row has — who is on the work, or who
|
|
113
|
+
* moved a Thread nobody has claimed — so a Thread that merely arrived and one
|
|
114
|
+
* that named the reader open on the same edge instead of the quieter one opening
|
|
115
|
+
* on a slot reserved for a count it does not hold. It is the grammar the Channel
|
|
116
|
+
* feed's Thread entry row already speaks, where the people on the work lead the
|
|
117
|
+
* row.
|
|
118
|
+
*
|
|
119
|
+
* Before the queue admitted every unread Thread, each row was a mention and the
|
|
120
|
+
* rows were interchangeable; now that named and ambient unread share one list,
|
|
121
|
+
* the row has to carry that difference itself. The count closes the identity
|
|
122
|
+
* line and only its ink changes — the shared capsule fill for a row that names
|
|
123
|
+
* the reader, a hairline for one that merely moved. The two numbers behind that
|
|
124
|
+
* ink (unread, mentions) reach assistive tech through the capsule's own name,
|
|
125
|
+
* because a second visible count beside the first would cost the row the one
|
|
126
|
+
* thing it needs to stay scannable.
|
|
127
|
+
*/
|
|
128
|
+
function InboxQueueRow({ row, t, showWorkspace, onOpen }) {
|
|
129
|
+
const { item } = row;
|
|
130
|
+
const actor = item.newestActor;
|
|
131
|
+
const owners = item.claimOwners;
|
|
132
|
+
const named = item.directCount > 0;
|
|
133
|
+
const countLabel = named
|
|
134
|
+
? t('inboxRowUnreadMentions', { count: item.unreadCount, mentions: item.directCount })
|
|
135
|
+
: t('inboxRowUnread', { count: item.unreadCount });
|
|
136
|
+
return _jsxs("button", { type: "button", className: inboxCss.row, "data-named": named || undefined, onClick: onOpen, children: [_jsx("span", { className: inboxCss.rowActor, children: owners.length > 0
|
|
137
|
+
? _jsx(TeamAvatarStack, { owners: owners, label: t('claimers', { names: owners.map(owner => `@${owner.name}`).join(', ') }) })
|
|
138
|
+
: _jsx(TeamAvatarStack, { owners: [actor], label: t('inboxRowActor', { name: `@${actor.name}` }) }) }), _jsxs("span", { className: inboxCss.rowLine, children: [_jsxs("span", { className: inboxCss.rowCrumb, children: [showWorkspace && _jsx("span", { className: inboxCss.rowWorkspace, children: row.workspaceTitle }), showWorkspace && ' / ', _jsxs("span", { className: inboxCss.rowChannel, children: ["#", item.channelName] }), ' ', item.taskNumber !== undefined && _jsx("span", { className: inboxCss.rowTask, children: t('taskLabel', { number: item.taskNumber }) })] }), _jsx(TeamCountBadge, { count: item.unreadCount, tone: named ? 'solid' : 'hairline', label: countLabel }), _jsx("time", { className: inboxCss.rowTime, dateTime: item.newestOccurredAt, title: formatAbsoluteTime(item.newestOccurredAt), children: formatInboxTime(item.newestOccurredAt, t) })] }), _jsx("span", { className: inboxCss.rowPreview, children: item.previewText })] });
|
|
71
139
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AgentTeamClientMemberStatus } from '@wowyuarm/dsh-agent-team/types';
|
|
2
|
+
import type { TeamSidebarProps } from './slots.ts';
|
|
3
|
+
/** One membership action: what it says and which Member it acts on. */
|
|
4
|
+
export interface TeamMemberAction {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly onSelect: () => void;
|
|
7
|
+
readonly disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The one place a Member's identity is drawn: the presence-bearing avatar plus
|
|
11
|
+
* the handle over its description. Read-only rosters, the rosters with a
|
|
12
|
+
* membership action, and the sidebar Agent list all render this, so identity,
|
|
13
|
+
* tone and truncation cannot drift between surfaces that show the same person.
|
|
14
|
+
*
|
|
15
|
+
* A fragment, not a row: each surface owns its own row element, hit target and
|
|
16
|
+
* grid, and places this identity in that grid's first two tracks. The handle
|
|
17
|
+
* spelling is the surface's call — rosters address Members the way the
|
|
18
|
+
* composer does (`@handle`), the sidebar names them as the directory does.
|
|
19
|
+
*/
|
|
20
|
+
export declare function TeamMemberIdentity({ status, name, className, t }: {
|
|
21
|
+
readonly status: AgentTeamClientMemberStatus;
|
|
22
|
+
/** Handle spelling for this surface; defaults to the mention form. */
|
|
23
|
+
readonly name?: string | undefined;
|
|
24
|
+
/** Surface-local copy hook (sidebar line heights, dialog density). */
|
|
25
|
+
readonly className?: string | undefined;
|
|
26
|
+
readonly t: TeamSidebarProps['t'];
|
|
27
|
+
}): import("react").JSX.Element;
|
|
28
|
+
/**
|
|
29
|
+
* The one roster row: identity, an optional membership action, and the row's
|
|
30
|
+
* own failure line. The action is the row's only chrome, so the eye lands on
|
|
31
|
+
* the handle first and on the action second. A read-only roster omits it and
|
|
32
|
+
* the trailing track collapses, handing its width back to the description.
|
|
33
|
+
*/
|
|
34
|
+
export declare function TeamMemberRow({ status, action, error, className, t }: {
|
|
35
|
+
readonly status: AgentTeamClientMemberStatus;
|
|
36
|
+
readonly action?: TeamMemberAction | undefined;
|
|
37
|
+
/** Transport failure for this row's last mutation, announced in place. */
|
|
38
|
+
readonly error?: string | undefined;
|
|
39
|
+
/** Surface-local hook (dialog, sidebar, footer) for its own row rules. */
|
|
40
|
+
readonly className?: string | undefined;
|
|
41
|
+
readonly t: TeamSidebarProps['t'];
|
|
42
|
+
}): import("react").JSX.Element;
|
|
43
|
+
//# sourceMappingURL=TeamMemberRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamMemberRow.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAIlD,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;IACjE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,sEAAsE;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BAQA;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;IACrE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC9C,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BAMA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { TeamMemberAvatar } from "./TeamMemberAvatar.js";
|
|
4
|
+
import css from './member-row.module.css';
|
|
5
|
+
/**
|
|
6
|
+
* The one place a Member's identity is drawn: the presence-bearing avatar plus
|
|
7
|
+
* the handle over its description. Read-only rosters, the rosters with a
|
|
8
|
+
* membership action, and the sidebar Agent list all render this, so identity,
|
|
9
|
+
* tone and truncation cannot drift between surfaces that show the same person.
|
|
10
|
+
*
|
|
11
|
+
* A fragment, not a row: each surface owns its own row element, hit target and
|
|
12
|
+
* grid, and places this identity in that grid's first two tracks. The handle
|
|
13
|
+
* spelling is the surface's call — rosters address Members the way the
|
|
14
|
+
* composer does (`@handle`), the sidebar names them as the directory does.
|
|
15
|
+
*/
|
|
16
|
+
export function TeamMemberIdentity({ status, name, className, t }) {
|
|
17
|
+
return _jsxs(_Fragment, { children: [_jsx(TeamMemberAvatar, { status: status, t: t }), _jsxs("span", { className: className === undefined ? css.copy : `${css.copy} ${className}`, children: [_jsx("strong", { children: name ?? `@${status.member.handle.replace(/^@/, '')}` }), _jsx("small", { children: status.member.description })] })] });
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The one roster row: identity, an optional membership action, and the row's
|
|
21
|
+
* own failure line. The action is the row's only chrome, so the eye lands on
|
|
22
|
+
* the handle first and on the action second. A read-only roster omits it and
|
|
23
|
+
* the trailing track collapses, handing its width back to the description.
|
|
24
|
+
*/
|
|
25
|
+
export function TeamMemberRow({ status, action, error, className, t }) {
|
|
26
|
+
return _jsxs("div", { className: className === undefined ? css.row : `${css.row} ${className}`, "data-team-member-row": true, children: [_jsx(TeamMemberIdentity, { status: status, t: t }), action !== undefined && _jsx(Button, { size: "sm", variant: "outline", className: css.action, disabled: action.disabled === true, onClick: action.onSelect, children: action.label }), error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error })] });
|
|
27
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type TeamMembersActionProps = Pick<
|
|
1
|
+
import type { TeamSettingsProps } from './slots.ts';
|
|
2
|
+
type TeamMembersActionProps = Pick<TeamSettingsProps, 'wide' | 'loadMemberGroups' | 't'>;
|
|
3
3
|
export declare function TeamMembersAction({ wide, loadMemberGroups, t }: TeamMembersActionProps): import("react").JSX.Element;
|
|
4
4
|
export {};
|
|
5
5
|
//# sourceMappingURL=TeamMembersAction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMembersAction.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMembersAction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"TeamMembersAction.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMembersAction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAKnD,KAAK,sBAAsB,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,kBAAkB,GAAG,GAAG,CAAC,CAAA;AAExF,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,sBAAsB,+BAkDtF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { IconUserOutline16, Modal, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
-
import {
|
|
4
|
+
import { TeamMemberRow } from "./TeamMemberRow.js";
|
|
5
5
|
import membersCss from './members.module.css';
|
|
6
6
|
import css from './team.module.css';
|
|
7
7
|
export function TeamMembersAction({ wide, loadMemberGroups, t }) {
|
|
@@ -28,5 +28,5 @@ export function TeamMembersAction({ wide, loadMemberGroups, t }) {
|
|
|
28
28
|
setPanelOpen(false);
|
|
29
29
|
queueMicrotask(() => { triggerRef.current?.focus(); });
|
|
30
30
|
};
|
|
31
|
-
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { label: t('members'), delayMs: 500, disabled: wide, children: _jsxs("button", { ref: triggerRef, type: "button", className: wide ? css.settingsAction : `${css.settingsAction} ${css.rail}`, "aria-label": t('members'), "aria-haspopup": "dialog", onClick: openMembers, children: [_jsx(IconUserOutline16, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: t('members') })] }) }), _jsx(Modal, { open: panelOpen, onClose: closeMembers, title: t('members'), closeLabel: t('close'), contentClassName: membersCss.body, children: _jsxs("div", { ref: contentRef, className: membersCss.content, tabIndex: -1, children: [loading && _jsx("p", { className: membersCss.state, role: "status", children: t('loadingAgents') }), !loading && groups.length === 0 && error === undefined && _jsx("p", { className: membersCss.state, children: t('emptyAgents') }), !loading && groups.map(group => (_jsxs("section", { className: membersCss.group, "aria-labelledby": `team-members-${group.workspaceId}`, children: [_jsx("h3", { id: `team-members-${group.workspaceId}`, children: group.workspaceTitle }), group.members.map(status =>
|
|
31
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { label: t('members'), delayMs: 500, disabled: wide, children: _jsxs("button", { ref: triggerRef, type: "button", className: wide ? css.settingsAction : `${css.settingsAction} ${css.rail}`, "aria-label": t('members'), "aria-haspopup": "dialog", onClick: openMembers, children: [_jsx(IconUserOutline16, { size: wide ? 16 : 18 }), wide && _jsx("span", { children: t('members') })] }) }), _jsx(Modal, { open: panelOpen, onClose: closeMembers, title: t('members'), closeLabel: t('close'), contentClassName: membersCss.body, children: _jsxs("div", { ref: contentRef, className: membersCss.content, tabIndex: -1, children: [loading && _jsx("p", { className: membersCss.state, role: "status", children: t('loadingAgents') }), !loading && groups.length === 0 && error === undefined && _jsx("p", { className: membersCss.state, children: t('emptyAgents') }), !loading && groups.map(group => (_jsxs("section", { className: membersCss.group, "aria-labelledby": `team-members-${group.workspaceId}`, children: [_jsx("h3", { id: `team-members-${group.workspaceId}`, children: group.workspaceTitle }), group.members.map(status => _jsx(TeamMemberRow, { status: status, className: membersCss.member, t: t }, status.member.memberId))] }, group.workspaceId))), error !== undefined && _jsx("p", { className: membersCss.error, role: "alert", children: error })] }) })] }));
|
|
32
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAe/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IACxE,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+
|
|
1
|
+
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EAInB,gBAAgB,EAGhB,kBAAkB,EAEnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAe/D,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAA;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IACxE,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAA;IACxD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAuvBxD"}
|
|
@@ -5,7 +5,7 @@ import { TeamComposer } from "./TeamComposer.js";
|
|
|
5
5
|
import { diagnosticText, TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
6
6
|
import { TeamMessage } from "./TeamMessage.js";
|
|
7
7
|
import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
8
|
-
import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf, taskStatusDot } from "./team-formatters.js";
|
|
8
|
+
import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf, mentionedMemberIds, taskStatusDot } from "./team-formatters.js";
|
|
9
9
|
import { TeamStateDot } from "./TeamStateDot.js";
|
|
10
10
|
import { mintRequestId, uploadComposerFiles } from "./requests.js";
|
|
11
11
|
import { ScopeCoverage } from "./scope-coverage.js";
|
|
@@ -659,8 +659,12 @@ export function TeamThreadPage(props) {
|
|
|
659
659
|
}
|
|
660
660
|
if (result.value.kind === 'committed') {
|
|
661
661
|
const committed = result.value;
|
|
662
|
+
// The optimistic row chips what the Host is about to report: a
|
|
663
|
+
// hand-typed `@Handle` delivers exactly like a picked recipient, and the
|
|
664
|
+
// committed facts replace this row as soon as they arrive.
|
|
665
|
+
const optimisticMentions = [...new Set([...recipients, ...mentionedMemberIds(draft, channelMembers)])].sort();
|
|
662
666
|
setCurrentFacts(current => {
|
|
663
|
-
const merged = mergeFacts(current, [{ kind: 'message', sequence: committed.message.sequence, message: committed.message, mentions:
|
|
667
|
+
const merged = mergeFacts(current, [{ kind: 'message', sequence: committed.message.sequence, message: committed.message, mentions: optimisticMentions, occurredAt: committed.receipt.occurredAt }]);
|
|
664
668
|
currentFactsRef.current = merged;
|
|
665
669
|
return merged;
|
|
666
670
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamWorkspaceBrowser.d.ts","sourceRoot":"","sources":["../../../src/client/TeamWorkspaceBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAyBlD,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,+BAoHtY"}
|
|
@@ -7,6 +7,17 @@ import { useSidebarSectionOpen, setSidebarSectionOpen } from "./sidebar-sections
|
|
|
7
7
|
import { TeamAgentsPanel } from "./TeamAgentsPanel.js";
|
|
8
8
|
import { TeamChannelsPanel } from "./TeamChannelsPanel.js";
|
|
9
9
|
import css from './sidebar.module.css';
|
|
10
|
+
/**
|
|
11
|
+
* The Inbox entry's icon with its unread mark. The quantity left this surface
|
|
12
|
+
* and lives in the control's accessible name: the sidebar answers whether
|
|
13
|
+
* anything is waiting at a glance, and the number — which moves on every fact —
|
|
14
|
+
* is what a reader asks for on purpose. The mark hangs off the icon rather than
|
|
15
|
+
* off the control, so the wide card and the 36px rail button put the same dot
|
|
16
|
+
* on the same corner of the same glyph.
|
|
17
|
+
*/
|
|
18
|
+
function InboxMark({ unread }) {
|
|
19
|
+
return _jsxs("span", { className: css.inboxMark, children: [_jsx(IconQueueOutline14, { size: 16 }), unread > 0 && _jsx("span", { className: css.inboxDot, "data-team-inbox-dot": true, "aria-hidden": "true" })] });
|
|
20
|
+
}
|
|
10
21
|
export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWorkspace, selectChannel, selectInbox, t, useWorkspaces, loadMembers, loadInbox, subscribeChanges, subscribeReads, addMember, loadChannels, createChannel, updateChannel, archiveChannel, updateMember, recoverMember, archiveMember, joinChannel, removeChannelMember, loadModels, openMemberSession }) {
|
|
11
22
|
const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
|
|
12
23
|
const workspaces = useWorkspaces(state => state.items);
|
|
@@ -17,26 +28,33 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
|
|
|
17
28
|
// one is set, the selected Agent card while a Member Session view is open,
|
|
18
29
|
// otherwise the browsed Workspace's overview. The selected row keeps its
|
|
19
30
|
// quiet folder tint (data-selected) in every case. The mention-Inbox card
|
|
20
|
-
// takes the marker while the Inbox page stands
|
|
31
|
+
// takes the marker while the Inbox page stands, and stands down while the
|
|
32
|
+
// embedded Member Session covers that page: the Inbox stays the remembered
|
|
33
|
+
// face underneath — closing the overlay returns to it, marker included —
|
|
34
|
+
// but the card is not a second current page while an Agent holds the seat.
|
|
21
35
|
const overviewIsCurrent = navigationState.channelRef === undefined && navigationState.memberSessionId === undefined && navigationState.inbox !== true;
|
|
22
|
-
const inboxIsCurrent = navigationState.inbox === true;
|
|
36
|
+
const inboxIsCurrent = navigationState.inbox === true && navigationState.memberSessionId === undefined;
|
|
23
37
|
const [creatingAgents, setCreatingAgents] = useState([]);
|
|
24
38
|
// Rail icons request expansion and name the section to reveal once wide.
|
|
25
39
|
const [pendingSection, setPendingSection] = useState();
|
|
26
40
|
const channelsRef = useRef(null);
|
|
27
41
|
const agentsRef = useRef(null);
|
|
28
42
|
const workspacesOpen = useSidebarSectionOpen(undefined, 'workspaces');
|
|
29
|
-
// The cross-Workspace
|
|
30
|
-
// Team sidebar stands; every wake re-pulls each Workspace's
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
43
|
+
// The cross-Workspace Inbox badge: one scope-less subscription while the
|
|
44
|
+
// Team sidebar stands; every wake re-pulls each Workspace's unread total
|
|
45
|
+
// (limit 1 — totals cover every row, never the list). Same-burst wakes
|
|
46
|
+
// coalesce behind a short debounce; the number is whatever the Host's whole
|
|
47
|
+
// unread slice returns, mentions included rather than alone.
|
|
34
48
|
const [inboxTotal, setInboxTotal] = useState(0);
|
|
49
|
+
// One name for both entries: what the control is, and how much waits behind
|
|
50
|
+
// it. The rail repeats it as its hover hint, which is the only place a reader
|
|
51
|
+
// still meets the quantity without opening the page.
|
|
52
|
+
const inboxLabel = inboxTotal > 0 ? t('inboxTitleWithCount', { count: inboxTotal }) : t('inboxTitle');
|
|
35
53
|
useEffect(() => {
|
|
36
54
|
let disposed = false;
|
|
37
55
|
let scheduled;
|
|
38
56
|
const refresh = async () => {
|
|
39
|
-
const results = await Promise.all(workspaces.map(workspace => loadInbox({ workspaceId: workspace.workspaceId,
|
|
57
|
+
const results = await Promise.all(workspaces.map(workspace => loadInbox({ workspaceId: workspace.workspaceId, limit: 1 })));
|
|
40
58
|
if (disposed)
|
|
41
59
|
return;
|
|
42
60
|
setInboxTotal(results.reduce((sum, result) => result.ok ? sum + result.value.totalUnreadCount : sum, 0));
|
|
@@ -80,7 +98,7 @@ export function TeamWorkspaceBrowser({ wide, expandSidebar, navigation, selectWo
|
|
|
80
98
|
queueMicrotask(() => { node?.querySelector('button')?.focus(); });
|
|
81
99
|
}, [wide, pendingSection]);
|
|
82
100
|
if (!wide) {
|
|
83
|
-
return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label:
|
|
101
|
+
return _jsxs("nav", { className: css.railWorkspace, "aria-label": t('workspaceSections'), children: [_jsx(Tooltip, { label: inboxLabel, side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: () => { selectInbox(); expandSidebar(); }, children: _jsx(InboxMark, { unread: inboxTotal }) }) }), _jsx(Tooltip, { label: t('channels'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('channels'), onClick: () => { setPendingSection('channels'); expandSidebar(); }, children: _jsx(IconListPenOutline16, { size: 16 }) }) }), _jsx(Tooltip, { label: t('agents'), side: "right", children: _jsx("button", { type: "button", className: css.railButton, "aria-label": t('agents'), onClick: () => { setPendingSection('agents'); expandSidebar(); }, children: _jsx(IconAgentPresetOutline16, { size: 16 }) }) })] });
|
|
84
102
|
}
|
|
85
|
-
return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label":
|
|
103
|
+
return _jsxs("section", { className: css.workspaceBrowser, "aria-label": t('workspaces'), children: [_jsxs("button", { type: "button", className: css.inboxCard, "aria-label": inboxLabel, "aria-current": inboxIsCurrent ? 'page' : undefined, onClick: selectInbox, children: [_jsx(InboxMark, { unread: inboxTotal }), _jsx("span", { className: css.inboxCardLabel, children: t('inboxTitle') })] }), _jsx(TeamSidebarSection, { title: t('workspaces'), open: workspacesOpen, onToggle: open => { setSidebarSectionOpen(undefined, 'workspaces', open); }, children: _jsxs("div", { className: css.workspaceList, children: [workspaces.map(workspace => _jsx(TeamWorkspaceRow, { workspaceId: workspace.workspaceId, title: workspace.title, path: workspace.path, selected: workspace.workspaceId === selectedId, current: workspace.workspaceId === selectedId && overviewIsCurrent, onSelect: selectWorkspace }, workspace.workspaceId)), workspaces.length === 0 && _jsx("p", { className: css.emptyState, children: t('empty') })] }) }), selectedId !== undefined && _jsxs("div", { className: css.workspaceSection, children: [_jsx("div", { ref: channelsRef, children: _jsx(TeamChannelsPanel, { workspaceId: selectedId, loadMembers: loadMembers, loadChannels: loadChannels, subscribeChanges: subscribeChanges, createChannel: createChannel, updateChannel: updateChannel, archiveChannel: archiveChannel, joinChannel: joinChannel, removeChannelMember: removeChannelMember, creatingAgents: creatingAgents.filter(request => request.workspaceId === selectedId), ...(navigationState.memberSessionId !== undefined || navigationState.channelRef === undefined ? {} : { selectedChannelRef: navigationState.channelRef }), selectChannel: selectChannel, t: t }, selectedId) }), _jsx("div", { ref: agentsRef, children: _jsx(TeamAgentsPanel, { workspaceId: selectedId, loadMembers: loadMembers, subscribeChanges: subscribeChanges, addMember: addMember, updateMember: updateMember, recoverMember: recoverMember, archiveMember: archiveMember, loadModels: loadModels, ...(navigationState.memberSessionId === undefined ? {} : { memberSessionId: navigationState.memberSessionId }), openMemberSession: openMemberSession, onCreatingChange: (request, creating) => { setCreatingAgents(current => creating ? [...current.filter(item => item.requestId !== request.requestId), request] : current.filter(item => item.requestId !== request.requestId)); }, t: t }, selectedId) })] })] });
|
|
86
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAoCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AA6LD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import agentTeamRemote from '
|
|
1
|
+
import agentTeamRemote from '@wowyuarm/dsh-agent-team/remote';
|
|
2
2
|
import { TeamNavigation } from "./navigation.js";
|
|
3
3
|
import { TeamChangeStream, TeamReadStream } from "./team-changes.js";
|
|
4
4
|
import { TeamDraftStore } from "./drafts.js";
|
|
5
5
|
import { TeamFooterAction } from "./TeamFooterAction.js";
|
|
6
|
-
import {
|
|
6
|
+
import { TeamMembersAction } from "./TeamMembersAction.js";
|
|
7
7
|
import { TeamConversation } from "./TeamConversation.js";
|
|
8
8
|
import { TeamWorkspaceBrowser } from "./TeamWorkspaceBrowser.js";
|
|
9
9
|
import { en, zh } from "./locales.js";
|
|
@@ -183,12 +183,11 @@ function applyUi(ctx) {
|
|
|
183
183
|
navigation.actions().exitMemberSession();
|
|
184
184
|
navigation.actions().leaveTeam();
|
|
185
185
|
},
|
|
186
|
-
loadMemberGroups,
|
|
187
186
|
}),
|
|
188
187
|
}, TeamFooterAction));
|
|
189
188
|
registerModeShadow(ctx, navigation, changes, reads, drafts, 'sidebar.workspaces', TeamWorkspaceBrowser);
|
|
190
189
|
registerModeShadow(ctx, navigation, changes, reads, drafts, 'main', TeamConversation, undefined, 'conversation');
|
|
191
|
-
registerModeShadow(ctx, navigation, changes, reads, drafts, 'sidebar.settings',
|
|
190
|
+
registerModeShadow(ctx, navigation, changes, reads, drafts, 'sidebar.settings', TeamMembersAction, () => ({ loadMemberGroups }));
|
|
192
191
|
}
|
|
193
192
|
export async function apply(ctx) {
|
|
194
193
|
const disposeRemote = await ctx.remote.$mount(agentTeamRemote);
|
|
@@ -27,14 +27,20 @@ export declare const zh: {
|
|
|
27
27
|
readonly statusError: "错误";
|
|
28
28
|
readonly statusUnavailable: "不可用";
|
|
29
29
|
readonly addChannel: "新建频道";
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
32
|
-
readonly loadingInbox: "
|
|
33
|
-
readonly inboxEmptyTitle: "
|
|
34
|
-
readonly inboxEmptyHint: "
|
|
35
|
-
readonly inboxTimeToday: "今天";
|
|
30
|
+
readonly inboxTitle: "收件箱";
|
|
31
|
+
readonly inboxTitleWithCount: "收件箱,{count} 条未读";
|
|
32
|
+
readonly loadingInbox: "正在加载收件箱…";
|
|
33
|
+
readonly inboxEmptyTitle: "收件箱是空的";
|
|
34
|
+
readonly inboxEmptyHint: "你参与的 Thread 有新活动、或有人提到你时,会出现在这里";
|
|
36
35
|
readonly inboxTimeYesterday: "昨天";
|
|
37
|
-
readonly
|
|
36
|
+
readonly inboxHeaderThreads: "{count} 个 Thread";
|
|
37
|
+
readonly inboxHeaderUnread: "{count} 条未读";
|
|
38
|
+
readonly inboxHeaderMentions: "{count} 条提及";
|
|
39
|
+
readonly inboxRowUnread: "{count} 条未读";
|
|
40
|
+
readonly inboxRowUnreadMentions: "{count} 条未读,其中 {mentions} 条提及";
|
|
41
|
+
readonly inboxRowActor: "最新来自 {name}";
|
|
42
|
+
readonly inboxSectionNeedsMe: "需要我";
|
|
43
|
+
readonly inboxSectionRecent: "最近活跃";
|
|
38
44
|
readonly channelName: "名称";
|
|
39
45
|
readonly channelDescription: "说明";
|
|
40
46
|
readonly initialMembers: "初始成员";
|
|
@@ -100,12 +106,16 @@ export declare const zh: {
|
|
|
100
106
|
readonly taskStatusInReview: "待验收";
|
|
101
107
|
readonly taskStatusDone: "已完成";
|
|
102
108
|
readonly taskStatusClosed: "已关闭";
|
|
103
|
-
readonly taskMessageCount: "{count} 条消息";
|
|
104
109
|
readonly taskLabel: "Task #{number}";
|
|
105
110
|
readonly taskPending: "Task …";
|
|
106
111
|
readonly openTask: "打开 Task #{number}";
|
|
107
112
|
readonly openThread: "打开讨论";
|
|
113
|
+
readonly openTaskUnread: "打开 Task #{number}({count} 条新动态)";
|
|
114
|
+
readonly openThreadUnread: "打开讨论({count} 条新动态)";
|
|
108
115
|
readonly threadLabel: "讨论";
|
|
116
|
+
readonly recentActivity: "最近活动 {time}";
|
|
117
|
+
readonly replyAction: "回复";
|
|
118
|
+
readonly claimers: "由 {names} 处理";
|
|
109
119
|
readonly asTask: "作为任务";
|
|
110
120
|
readonly promoteToTask: "转为 Task";
|
|
111
121
|
readonly promotingTask: "正在转为 Task…";
|
|
@@ -184,14 +194,20 @@ export declare const en: {
|
|
|
184
194
|
readonly statusError: "Error";
|
|
185
195
|
readonly statusUnavailable: "Unavailable";
|
|
186
196
|
readonly addChannel: "New Channel";
|
|
187
|
-
readonly
|
|
188
|
-
readonly
|
|
189
|
-
readonly loadingInbox: "Loading
|
|
190
|
-
readonly inboxEmptyTitle: "
|
|
191
|
-
readonly inboxEmptyHint: "
|
|
192
|
-
readonly inboxTimeToday: "Today";
|
|
197
|
+
readonly inboxTitle: "Inbox";
|
|
198
|
+
readonly inboxTitleWithCount: "Inbox, {count} unread";
|
|
199
|
+
readonly loadingInbox: "Loading Inbox…";
|
|
200
|
+
readonly inboxEmptyTitle: "Your Inbox is empty";
|
|
201
|
+
readonly inboxEmptyHint: "Threads you take part in appear here when they have new activity or mention you";
|
|
193
202
|
readonly inboxTimeYesterday: "Yesterday";
|
|
194
|
-
readonly
|
|
203
|
+
readonly inboxHeaderThreads: "{count} Thread(s)";
|
|
204
|
+
readonly inboxHeaderUnread: "{count} unread";
|
|
205
|
+
readonly inboxHeaderMentions: "{count} mention(s)";
|
|
206
|
+
readonly inboxRowUnread: "{count} unread";
|
|
207
|
+
readonly inboxRowUnreadMentions: "{count} unread, {mentions} mention(s)";
|
|
208
|
+
readonly inboxRowActor: "Latest from {name}";
|
|
209
|
+
readonly inboxSectionNeedsMe: "Needs me";
|
|
210
|
+
readonly inboxSectionRecent: "Recently active";
|
|
195
211
|
readonly channelName: "Name";
|
|
196
212
|
readonly channelDescription: "Description";
|
|
197
213
|
readonly initialMembers: "Initial members";
|
|
@@ -257,12 +273,16 @@ export declare const en: {
|
|
|
257
273
|
readonly taskStatusInReview: "In review";
|
|
258
274
|
readonly taskStatusDone: "Done";
|
|
259
275
|
readonly taskStatusClosed: "Closed";
|
|
260
|
-
readonly taskMessageCount: "{count} messages";
|
|
261
276
|
readonly taskLabel: "Task #{number}";
|
|
262
277
|
readonly taskPending: "Task …";
|
|
263
278
|
readonly openTask: "Open Task #{number}";
|
|
264
279
|
readonly openThread: "Open thread";
|
|
280
|
+
readonly openTaskUnread: "Open Task #{number} ({count} new updates)";
|
|
281
|
+
readonly openThreadUnread: "Open thread ({count} new updates)";
|
|
265
282
|
readonly threadLabel: "Thread";
|
|
283
|
+
readonly recentActivity: "Last activity {time}";
|
|
284
|
+
readonly replyAction: "Reply";
|
|
285
|
+
readonly claimers: "Handled by {names}";
|
|
266
286
|
readonly asTask: "As task";
|
|
267
287
|
readonly promoteToTask: "Convert to Task";
|
|
268
288
|
readonly promotingTask: "Converting to Task…";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
|