@wowyuarm/dsh-agent-team 0.1.7 → 0.1.8
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/package.json +1 -1
- package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +2 -0
- package/packages/agent-team/lib/index.js +58 -0
- package/packages/agent-team/lib/ledger.js +135 -12
- package/packages/agent-team/lib/member-context.js +1 -1
- package/packages/agent-team/lib/progress-nudge.js +320 -0
- package/packages/agent-team/lib/typert.host.js +27 -26
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +26 -25
- package/packages/agent-team/lib/types/index.d.ts +8 -0
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +27 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/progress-nudge.d.ts +136 -0
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/entities.d.ts +18 -0
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +2 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +2 -2
- package/packages/client-agent-team/lib/client.js +406 -512
- package/packages/client-agent-team/lib/client.js.map +1 -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 +3 -7
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +37 -27
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.js +3 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +5 -0
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +4 -6
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts +14 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.js +15 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +41 -16
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +2 -67
- package/packages/client-agent-team/lib/types/client/locales.d.ts +0 -2
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +0 -2
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +1 -2
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +7 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.js +25 -3
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +11 -10
- 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 +14 -11
- package/packages/tool-agent-team/lib/index.js +9 -9
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +0 -12
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +0 -13
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +0 -20
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/member-session-input.js +0 -110
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAIvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamChannelPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamChannelPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,mBAAmB,EAE7D,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAIvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAe/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,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,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAmBD,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BA8UnR"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
|
-
import { Button, IconChevronLeftOutline14, IconChevronRightOutline14, Modal
|
|
3
|
+
import { Button, IconChevronLeftOutline14, IconChevronRightOutline14, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { bytesToBase64 } from "./attachment-preview.js";
|
|
5
5
|
import { mintRequestId } from "./requests.js";
|
|
6
6
|
import { TeamComposer } from "./TeamComposer.js";
|
|
@@ -8,6 +8,7 @@ import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
|
8
8
|
import { TeamMessage } from "./TeamMessage.js";
|
|
9
9
|
import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
10
10
|
import { formatTaskStatus, taskStatusDot, mentionNamesOf } from "./team-formatters.js";
|
|
11
|
+
import { TeamStateDot } from "./TeamStateDot.js";
|
|
11
12
|
import { useChannelMembership } from "./team-membership.js";
|
|
12
13
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
13
14
|
import { hostTaskRefLookup, jumpToTaskThread } from "./task-refs.js";
|
|
@@ -304,11 +305,6 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
304
305
|
const sender = human ? t('human') : senderStatus?.member.handle ?? item.message.sender;
|
|
305
306
|
const turnGap = isRunGap(index > 0 ? block.items[index - 1].message.occurredAt : undefined, item.message.occurredAt);
|
|
306
307
|
// A turn divider already labels the gapped entry; its row stays chrome-free.
|
|
307
|
-
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsxs(TeamMessage, { senderName: sender, memberId: item.message.sender, human: human, body: item.message.body, attachments: item.message.attachments, loadAttachment: getAttachment, t: t, occurredAt: item.message.occurredAt, mentionNames: mentionNamesOf(item.mentions, mentionHandlesMap), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: [item.message.topLevel && item.task !== undefined && item.taskNumber !== undefined && _jsxs("button", { type: "button", className: channelCss.taskFooter, "aria-label": t('openTask', { number: item.taskNumber }), onClick: () => { selectThread(item.thread.threadRef, channelRef, item.task?.taskRef, item.taskNumber); }, children: [_jsx("span", { className: channelCss.taskDot, children: (() => {
|
|
308
|
-
const dot = taskStatusDot(item.task.status);
|
|
309
|
-
return dot === 'ongoing' || dot === 'warning' || dot === 'done'
|
|
310
|
-
? _jsx(StateDot, { size: 8, state: dot })
|
|
311
|
-
: _jsx("span", { className: channelCss.taskDotQuiet, "data-variant": dot });
|
|
312
|
-
})() }), _jsx("span", { className: channelCss.taskNumber, children: t('taskLabel', { number: item.taskNumber }) }), _jsx("span", { className: channelCss.taskStatus, children: formatTaskStatus(item.task.status, t) }), _jsx("span", { className: channelCss.taskCount, children: t('taskMessageCount', { count: item.messageCount }) }), _jsx("span", { className: channelCss.taskArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutline14, { size: 12 }) })] }), item.message.topLevel && item.task === undefined && _jsxs("button", { type: "button", className: channelCss.taskFooter, "aria-label": t('openThread'), onClick: () => { selectThread(item.thread.threadRef, channelRef); }, children: [_jsx("span", { className: channelCss.taskNumber, children: t('threadLabel') }), _jsx("span", { className: channelCss.taskCount, children: t('taskMessageCount', { count: item.messageCount }) }), _jsx("span", { className: channelCss.taskArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutline14, { size: 12 }) })] })] })] }, item.message.messageRef);
|
|
308
|
+
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsxs(TeamMessage, { senderName: sender, memberId: item.message.sender, human: human, body: item.message.body, attachments: item.message.attachments, loadAttachment: getAttachment, t: t, occurredAt: item.message.occurredAt, mentionNames: mentionNamesOf(item.mentions, mentionHandlesMap), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: [item.message.topLevel && item.task !== undefined && item.taskNumber !== undefined && _jsxs("button", { type: "button", className: channelCss.taskFooter, "aria-label": t('openTask', { number: item.taskNumber }), onClick: () => { selectThread(item.thread.threadRef, channelRef, item.task?.taskRef, item.taskNumber); }, children: [_jsx("span", { className: channelCss.taskDot, children: _jsx(TeamStateDot, { size: 8, state: taskStatusDot(item.task.status) }) }), _jsx("span", { className: channelCss.taskNumber, children: t('taskLabel', { number: item.taskNumber }) }), _jsx("span", { className: channelCss.taskStatus, children: formatTaskStatus(item.task.status, t) }), _jsx("span", { className: channelCss.taskCount, children: t('taskMessageCount', { count: item.messageCount }) }), _jsx("span", { className: channelCss.taskArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutline14, { size: 12 }) })] }), item.message.topLevel && item.task === undefined && _jsxs("button", { type: "button", className: channelCss.taskFooter, "aria-label": t('openThread'), onClick: () => { selectThread(item.thread.threadRef, channelRef); }, children: [_jsx("span", { className: channelCss.taskNumber, children: t('threadLabel') }), _jsx("span", { className: channelCss.taskCount, children: t('taskMessageCount', { count: item.messageCount }) }), _jsx("span", { className: channelCss.taskArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutline14, { size: 12 }) })] })] })] }, item.message.messageRef);
|
|
313
309
|
}) }, `run-${block.items[0].message.messageRef}`))] }) }), channel !== undefined ? _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setStatusMessage(undefined); }, onSubmit: () => { void send(); }, pendingFiles: pendingFiles, onFilesChange: setPendingFiles, asTask: asTask, onAsTaskChange: setAsTask, t: t }, draftKey) : _jsx("div", {})] });
|
|
314
310
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { AgentTeamClientMemberStatus, AgentTeamMemberId } from '@wowyuarm/dsh-agent-team/types';
|
|
2
2
|
import type { TeamConversationProps } from './slots.ts';
|
|
3
|
-
export declare function TeamComposer({ members, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }: {
|
|
3
|
+
export declare function TeamComposer({ members, followerMemberIds, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }: {
|
|
4
4
|
readonly members: readonly AgentTeamClientMemberStatus[];
|
|
5
|
+
/** Current Thread followers; the Thread surface passes them so they rank above other candidates. */
|
|
6
|
+
readonly followerMemberIds?: ReadonlySet<AgentTeamMemberId>;
|
|
5
7
|
readonly recipients: ReadonlySet<AgentTeamMemberId>;
|
|
6
8
|
readonly draft: string;
|
|
7
9
|
readonly pending: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamComposer.d.ts","sourceRoot":"","sources":["../../../src/client/TeamComposer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAqEvD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE;IAC9N,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAA;IACxD,oGAAoG;IACpG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAC3D,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,IAAI,EAAE,CAAA;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI,CAAA;IACzD,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACnD,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC,+BA6SA"}
|
|
@@ -31,6 +31,12 @@ function mentionCandidates(members, query) {
|
|
|
31
31
|
&& status.member.state !== 'archived'
|
|
32
32
|
&& status.member.handle.toLocaleLowerCase().startsWith(normalized));
|
|
33
33
|
}
|
|
34
|
+
/** Thread followers rank first: mentioning them delivers directly, while a non-follower enters the two-send invite flow. */
|
|
35
|
+
function rankMentionCandidates(candidates, followers) {
|
|
36
|
+
if (followers === undefined || followers.size === 0)
|
|
37
|
+
return candidates;
|
|
38
|
+
return [...candidates].sort((left, right) => Number(followers.has(right.member.memberId)) - Number(followers.has(left.member.memberId)));
|
|
39
|
+
}
|
|
34
40
|
/** Every member a manual handle pick could reach: the @all expansion snapshot. */
|
|
35
41
|
function allMentionMembers(members) {
|
|
36
42
|
return members.filter(status => status.presence !== 'unavailable' && status.member.state !== 'inactive' && status.member.state !== 'archived');
|
|
@@ -50,22 +56,24 @@ function draftPreviewUrl(file) {
|
|
|
50
56
|
}
|
|
51
57
|
return url;
|
|
52
58
|
}
|
|
53
|
-
export function TeamComposer({ members, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
|
|
59
|
+
export function TeamComposer({ members, followerMemberIds, recipients, draft, pending, confirmation, error, onDraftChange, onRecipientsChange, onSubmit, placeholder, pendingFiles, onFilesChange, asTask, onAsTaskChange, t }) {
|
|
54
60
|
const inputRef = useRef(null);
|
|
55
61
|
const fileInputRef = useRef(null);
|
|
56
62
|
const rootRef = useRef(null);
|
|
57
63
|
const menuRef = useRef(null);
|
|
64
|
+
const activeOptionRef = useRef(null);
|
|
58
65
|
const composingRef = useRef(false);
|
|
59
66
|
const [mention, setMention] = useState();
|
|
60
67
|
const [highlight, setHighlight] = useState(0);
|
|
61
68
|
// @all is a composer-layer expansion of the same eligibility filter a
|
|
62
69
|
// handle pick uses; the fixed row stays on top of the matching members.
|
|
63
|
-
const memberCandidates = mention === undefined ? [] : mentionCandidates(members, mention.query);
|
|
70
|
+
const memberCandidates = mention === undefined ? [] : rankMentionCandidates(mentionCandidates(members, mention.query), followerMemberIds);
|
|
64
71
|
const options = mention !== undefined && 'all'.startsWith(mention.query.toLocaleLowerCase())
|
|
65
72
|
? [{ kind: 'all' }, ...memberCandidates.map(status => ({ kind: 'member', status }))]
|
|
66
73
|
: memberCandidates.map(status => ({ kind: 'member', status }));
|
|
67
74
|
const menuOpen = mention !== undefined && options.length > 0;
|
|
68
75
|
const activeOption = options[highlight];
|
|
76
|
+
const activeOptionKey = activeOption === undefined ? undefined : activeOption.kind === 'all' ? 'all' : activeOption.status.member.memberId;
|
|
69
77
|
const allCount = allMentionMembers(members).length;
|
|
70
78
|
const listId = 'team-mention-suggestions';
|
|
71
79
|
const menuMaxHeight = useAnchoredMaxHeight(menuRef, 320, menuOpen ? draft : null);
|
|
@@ -85,6 +93,14 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
85
93
|
}
|
|
86
94
|
setHighlight(current => Math.min(current, options.length - 1));
|
|
87
95
|
}, [mention, options.length]);
|
|
96
|
+
// The anchored height cap keeps long rosters scrollable; without this the
|
|
97
|
+
// keyboard-highlighted row can stay hidden below the fold.
|
|
98
|
+
useLayoutEffect(() => {
|
|
99
|
+
if (!menuOpen)
|
|
100
|
+
return;
|
|
101
|
+
// Optional call: jsdom renders the menu without a layout engine.
|
|
102
|
+
activeOptionRef.current?.scrollIntoView?.({ block: 'nearest' });
|
|
103
|
+
}, [menuOpen, highlight, activeOptionKey]);
|
|
88
104
|
// Match the resident DSH composer without stealing a later user choice: Team
|
|
89
105
|
// data can load after navigation, so a dialog or another control may already
|
|
90
106
|
// own focus by the time this composer appears.
|
|
@@ -135,6 +151,21 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
135
151
|
pruneRecipients(nextDraft);
|
|
136
152
|
updateMention(nextDraft, event.target.selectionStart ?? nextDraft.length);
|
|
137
153
|
};
|
|
154
|
+
// Both pick kinds share the same commit path: swap the text in, add the
|
|
155
|
+
// recipients, close the menu, and restore the caret after focus.
|
|
156
|
+
const commitMention = (nextDraft, nextCaret, nextRecipients) => {
|
|
157
|
+
onDraftChange(nextDraft);
|
|
158
|
+
onRecipientsChange(nextRecipients);
|
|
159
|
+
setMention(undefined);
|
|
160
|
+
setHighlight(0);
|
|
161
|
+
requestAnimationFrame(() => {
|
|
162
|
+
const input = inputRef.current;
|
|
163
|
+
if (input === null)
|
|
164
|
+
return;
|
|
165
|
+
input.focus({ preventScroll: true });
|
|
166
|
+
input.setSelectionRange(nextCaret, nextCaret);
|
|
167
|
+
});
|
|
168
|
+
};
|
|
138
169
|
const selectOption = (option) => {
|
|
139
170
|
if (mention === undefined)
|
|
140
171
|
return;
|
|
@@ -146,35 +177,14 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
146
177
|
const nextRecipients = new Set(recipients);
|
|
147
178
|
for (const status of allMentionMembers(members))
|
|
148
179
|
nextRecipients.add(status.member.memberId);
|
|
149
|
-
|
|
150
|
-
onRecipientsChange(nextRecipients);
|
|
151
|
-
setMention(undefined);
|
|
152
|
-
setHighlight(0);
|
|
153
|
-
requestAnimationFrame(() => {
|
|
154
|
-
const input = inputRef.current;
|
|
155
|
-
if (input === null)
|
|
156
|
-
return;
|
|
157
|
-
input.focus({ preventScroll: true });
|
|
158
|
-
input.setSelectionRange(nextCaret, nextCaret);
|
|
159
|
-
});
|
|
180
|
+
commitMention(nextDraft, nextCaret, nextRecipients);
|
|
160
181
|
return;
|
|
161
182
|
}
|
|
162
183
|
const member = option.status;
|
|
163
184
|
const inserted = `@${member.member.handle} `;
|
|
164
185
|
const nextDraft = `${draft.slice(0, mention.start)}${inserted}${draft.slice(mention.end)}`;
|
|
165
186
|
const nextCaret = mention.start + inserted.length;
|
|
166
|
-
|
|
167
|
-
onDraftChange(nextDraft);
|
|
168
|
-
onRecipientsChange(nextRecipients);
|
|
169
|
-
setMention(undefined);
|
|
170
|
-
setHighlight(0);
|
|
171
|
-
requestAnimationFrame(() => {
|
|
172
|
-
const input = inputRef.current;
|
|
173
|
-
if (input === null)
|
|
174
|
-
return;
|
|
175
|
-
input.focus({ preventScroll: true });
|
|
176
|
-
input.setSelectionRange(nextCaret, nextCaret);
|
|
177
|
-
});
|
|
187
|
+
commitMention(nextDraft, nextCaret, new Set(recipients).add(member.member.memberId));
|
|
178
188
|
};
|
|
179
189
|
// Pasted files (screenshots, copies) join the same chips the "+" picker
|
|
180
190
|
// fills; only a paste that carries files is intercepted, so plain text
|
|
@@ -234,8 +244,8 @@ export function TeamComposer({ members, recipients, draft, pending, confirmation
|
|
|
234
244
|
const optionId = option.kind === 'all' ? `${listId}-all` : `${listId}-${option.status.member.memberId}`;
|
|
235
245
|
const selected = index === highlight;
|
|
236
246
|
return option.kind === 'all'
|
|
237
|
-
? _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx("span", { className: css.mentionAllDot, "aria-hidden": "true" }), _jsx("span", { className: css.mentionName, children: "@all" }), _jsx("span", { className: css.mentionDescription, children: t('mentionAll', { count: allCount }) })] }, "all")
|
|
238
|
-
: _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx(TeamPresenceDot, { status: option.status, t: t }), _jsxs("span", { className: css.mentionName, children: ["@", option.status.member.handle] }), _jsx("span", { className: css.mentionDescription, children: option.status.member.description })] }, option.status.member.memberId);
|
|
247
|
+
? _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, ref: selected ? activeOptionRef : undefined, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx("span", { className: css.mentionAllDot, "aria-hidden": "true" }), _jsx("span", { className: css.mentionName, children: "@all" }), _jsx("span", { className: css.mentionDescription, children: t('mentionAll', { count: allCount }) })] }, "all")
|
|
248
|
+
: _jsxs("button", { id: optionId, type: "button", role: "option", "aria-selected": selected, className: css.mentionOption, ref: selected ? activeOptionRef : undefined, onMouseDown: event => { event.preventDefault(); }, onClick: () => { selectOption(option); }, children: [_jsx(TeamPresenceDot, { status: option.status, t: t }), _jsxs("span", { className: css.mentionName, children: ["@", option.status.member.handle] }), _jsx("span", { className: css.mentionDescription, children: option.status.member.description })] }, option.status.member.memberId);
|
|
239
249
|
}) }), _jsx("textarea", { ref: inputRef, "aria-label": t('messageDraft'), "aria-autocomplete": "list", "aria-controls": menuOpen ? listId : undefined, "aria-activedescendant": menuOpen && activeOption !== undefined ? activeOption.kind === 'all' ? `${listId}-all` : `${listId}-${activeOption.status.member.memberId}` : undefined, "aria-expanded": menuOpen, value: draft, readOnly: pending, placeholder: placeholder ?? t('messagePlaceholder'), rows: 1, onChange: onChange, onPaste: onPaste, onKeyDown: onKeyDown, onSelect: event => { updateMention(event.currentTarget.value, event.currentTarget.selectionStart ?? event.currentTarget.value.length); }, onCompositionStart: () => { composingRef.current = true; }, onCompositionEnd: () => { setTimeout(() => { composingRef.current = false; }, 10); } })] }), recipients.size > 0 && _jsx("p", { className: css.notifyRow, "data-team-notify": true, children: t('composerNotify', { ids: [...recipients].sort().map(memberId => `@${members.find(candidate => candidate.member.memberId === memberId)?.member.handle ?? memberId}`).join(', ') }) }), onFilesChange !== undefined && pendingFiles !== undefined && pendingFiles.length > 0 && (_jsx("ul", { className: css.fileChips, "aria-label": t('attachFiles'), children: pendingFiles.map((file, index) => {
|
|
240
250
|
const previewUrl = draftPreviewUrl(file);
|
|
241
251
|
return _jsxs("li", { className: `${css.fileChip} ${previewUrl !== undefined ? css.imageChip : ''}`, children: [previewUrl !== undefined && _jsx("img", { src: previewUrl, alt: "", className: css.imageChipPreview }), _jsxs("span", { className: css.fileChipName, title: file.name, children: [file.name, _jsx("span", { className: css.fileChipSize, children: formatByteSize(file.size) })] }), _jsx("button", { type: "button", className: css.fileChipRemove, "aria-label": t('removeFile', { name: file.name }), disabled: pending, onClick: () => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TeamConversationProps } from './slots.ts';
|
|
2
|
-
export declare function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }: TeamConversationProps): import("react").JSX.Element;
|
|
2
|
+
export declare function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }: TeamConversationProps): import("react").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=TeamConversation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamConversation.d.ts","sourceRoot":"","sources":["../../../src/client/TeamConversation.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAKvD,wBAAgB,gBAAgB,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,EAAE,qBAAqB,+
|
|
1
|
+
{"version":3,"file":"TeamConversation.d.ts","sourceRoot":"","sources":["../../../src/client/TeamConversation.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAKvD,wBAAgB,gBAAgB,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,EAAE,qBAAqB,+BAoB7X"}
|
|
@@ -3,12 +3,12 @@ import { useSyncExternalStore } from 'react';
|
|
|
3
3
|
import { TeamChannelPage } from "./TeamChannelPage.js";
|
|
4
4
|
import { TeamThreadPage } from "./TeamThreadPage.js";
|
|
5
5
|
import css from './conversation.module.css';
|
|
6
|
-
export function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }) {
|
|
6
|
+
export function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, backToWorkspace, backToChannels, resolveTaskRefs }) {
|
|
7
7
|
const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
|
|
8
8
|
const workspaces = useWorkspaces(state => state.items);
|
|
9
9
|
const current = workspaces.find(workspace => workspace.workspaceId === navigationState.workspaceId);
|
|
10
10
|
if (current !== undefined && navigationState.threadRef !== undefined) {
|
|
11
|
-
return _jsx(TeamThreadPage, { workspaceId: current.workspaceId, putAttachment: putAttachment, threadRef: navigationState.threadRef, backToWorkspace: backToWorkspace, selectChannel: selectChannel, selectThread: selectThread, resolveTaskRefs: resolveTaskRefs, ...(navigationState.channelRef === undefined ? {} : { channelRef: navigationState.channelRef }), ...(navigationState.taskRef === undefined ? {} : { taskRef: navigationState.taskRef }), ...(navigationState.taskNumber === undefined ? {} : { taskNumber: navigationState.taskNumber }), drafts: drafts, getAttachment: getAttachment, readThread: readThread, loadChannels: loadChannels, loadThreadHistory: loadThreadHistory, subscribeChanges: subscribeChanges, loadMembers: loadMembers, reply: reply, changeTask: changeTask, promoteThread: promoteThread, t: t }, navigationState.threadRef);
|
|
11
|
+
return _jsx(TeamThreadPage, { workspaceId: current.workspaceId, putAttachment: putAttachment, threadRef: navigationState.threadRef, backToWorkspace: backToWorkspace, selectChannel: selectChannel, selectThread: selectThread, resolveTaskRefs: resolveTaskRefs, ...(navigationState.channelRef === undefined ? {} : { channelRef: navigationState.channelRef }), ...(navigationState.taskRef === undefined ? {} : { taskRef: navigationState.taskRef }), ...(navigationState.taskNumber === undefined ? {} : { taskNumber: navigationState.taskNumber }), drafts: drafts, getAttachment: getAttachment, readThread: readThread, loadChannels: loadChannels, loadThreadHistory: loadThreadHistory, threadObservations: threadObservations, subscribeChanges: subscribeChanges, loadMembers: loadMembers, reply: reply, changeTask: changeTask, promoteThread: promoteThread, t: t }, navigationState.threadRef);
|
|
12
12
|
}
|
|
13
13
|
if (current !== undefined && navigationState.channelRef !== undefined) {
|
|
14
14
|
return _jsx(TeamChannelPage, { workspaceId: current.workspaceId, channelRef: navigationState.channelRef, drafts: drafts, putAttachment: putAttachment, getAttachment: getAttachment, loadChannels: loadChannels, subscribeChanges: subscribeChanges, loadMembers: loadMembers, sendMessage: sendMessage, joinChannel: joinChannel, removeChannelMember: removeChannelMember, selectThread: selectThread, selectChannel: selectChannel, backToChannels: backToChannels, resolveTaskRefs: resolveTaskRefs, t: t }, navigationState.channelRef);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMemberAvatar.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberAvatar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamMemberAvatar.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberAvatar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAMlD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC9C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BAkBA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
3
|
import { memberHue } from "./team-formatters.js";
|
|
4
4
|
import { presenceDotState, presenceLabel } from "./TeamPresenceDot.js";
|
|
5
|
+
import { TeamStateDot } from "./TeamStateDot.js";
|
|
5
6
|
import css from './sidebar.module.css';
|
|
6
7
|
/**
|
|
7
8
|
* Sidebar Member avatar reusing the conversation identity language: the
|
|
@@ -11,5 +12,5 @@ import css from './sidebar.module.css';
|
|
|
11
12
|
export function TeamMemberAvatar({ status, t }) {
|
|
12
13
|
const label = presenceLabel(status, t);
|
|
13
14
|
const state = presenceDotState(status.presence);
|
|
14
|
-
return (_jsx(Tooltip, { label: label, delayMs: 300, children: _jsxs("span", { className: css.agentAvatar, style: { '--team-avatar-hue': memberHue(status.member.memberId) }, role: "img", "aria-label": label, children: [status.member.handle.replace('@', '').slice(0, 1).toUpperCase(), _jsx("span", { className: css.agentAvatarBadge, "aria-hidden": "true", children:
|
|
15
|
+
return (_jsx(Tooltip, { label: label, delayMs: 300, children: _jsxs("span", { className: css.agentAvatar, style: { '--team-avatar-hue': memberHue(status.member.memberId) }, role: "img", "aria-label": label, children: [status.member.handle.replace('@', '').slice(0, 1).toUpperCase(), _jsx("span", { className: css.agentAvatarBadge, "aria-hidden": "true", children: _jsx(TeamStateDot, { state: state }) })] }) }));
|
|
15
16
|
}
|
|
@@ -218,6 +218,11 @@ function renderRefs(text, onOpenRef, taskLabel, refLabel) {
|
|
|
218
218
|
if (segment.ref === undefined)
|
|
219
219
|
return _jsx(Fragment, { children: segment.text }, index);
|
|
220
220
|
const resolved = cachedResolvedTaskRef(segment.ref);
|
|
221
|
+
// Task refs link only once the Host confirms them; abbreviated or unknown
|
|
222
|
+
// refs stay plain text so prose never misfires as a link. Channel and
|
|
223
|
+
// Thread refs have no resolver and link at the authored position.
|
|
224
|
+
if (segment.ref.startsWith('task:') && resolved === undefined)
|
|
225
|
+
return _jsx(Fragment, { children: segment.text }, index);
|
|
221
226
|
const label = resolved !== undefined && segment.ref.startsWith('task:') ? taskLabel(resolved.taskNumber) : refLabel(segment.ref);
|
|
222
227
|
return _jsx("button", { type: "button", className: css.refLink, title: segment.ref, onClick: () => { onOpenRef(segment.ref); }, children: label }, index);
|
|
223
228
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { StateDotState } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
2
1
|
import type { AgentTeamClientMemberStatus } from '@wowyuarm/dsh-agent-team/types';
|
|
3
2
|
import type { TeamSidebarProps } from './slots.ts';
|
|
3
|
+
import type { TeamStateDotState } from './TeamStateDot.tsx';
|
|
4
4
|
export declare function presenceLabel(status: AgentTeamClientMemberStatus, t: TeamSidebarProps['t']): string;
|
|
5
5
|
/** Shared presence → indicator mapping for dots and avatar badges. */
|
|
6
|
-
export declare function presenceDotState(presence: AgentTeamClientMemberStatus['presence']):
|
|
6
|
+
export declare function presenceDotState(presence: AgentTeamClientMemberStatus['presence']): TeamStateDotState;
|
|
7
7
|
export declare function TeamPresenceDot({ status, t }: {
|
|
8
8
|
readonly status: AgentTeamClientMemberStatus;
|
|
9
9
|
readonly t: TeamSidebarProps['t'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { TeamStateDot } from "./TeamStateDot.js";
|
|
3
4
|
import css from './presence.module.css';
|
|
4
5
|
export function presenceLabel(status, t) {
|
|
5
6
|
const label = status.presence === 'available' ? t('statusAvailable')
|
|
@@ -9,12 +10,9 @@ export function presenceLabel(status, t) {
|
|
|
9
10
|
}
|
|
10
11
|
/** Shared presence → indicator mapping for dots and avatar badges. */
|
|
11
12
|
export function presenceDotState(presence) {
|
|
12
|
-
return presence === 'available' ? 'done' : presence === 'working' ? 'ongoing' : presence === 'error' ? 'error' : '
|
|
13
|
+
return presence === 'available' ? 'done' : presence === 'working' ? 'ongoing' : presence === 'error' ? 'error' : 'quiet';
|
|
13
14
|
}
|
|
14
15
|
export function TeamPresenceDot({ status, t }) {
|
|
15
16
|
const label = presenceLabel(status, t);
|
|
16
|
-
|
|
17
|
-
return (_jsx(Tooltip, { label: label, delayMs: 300, children: _jsx("span", { className: css.target, role: "img", "aria-label": label, children: state === 'gray'
|
|
18
|
-
? _jsx("span", { className: css.unavailableDot, "aria-hidden": "true" })
|
|
19
|
-
: _jsx(StateDot, { state: state }) }) }));
|
|
17
|
+
return (_jsx(Tooltip, { label: label, delayMs: 300, children: _jsx("span", { className: css.target, role: "img", "aria-label": label, children: _jsx(TeamStateDot, { state: presenceDotState(status.presence) }) }) }));
|
|
20
18
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StateDotState } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
2
|
+
/** The Team status dot language: the DSH four-color states plus the two quiet statuses StateDot has no slot for. */
|
|
3
|
+
export type TeamStateDotState = StateDotState | 'todo' | 'quiet';
|
|
4
|
+
/**
|
|
5
|
+
* Render the one shared Team status indicator. Native StateDot states pass
|
|
6
|
+
* through; the quiet statuses mirror StateDot geometry locally so every
|
|
7
|
+
* surface renders the same shape — todo a hollow ring (not started), quiet a
|
|
8
|
+
* solid tertiary dot with the same 10% halo (closed, unavailable).
|
|
9
|
+
*/
|
|
10
|
+
export declare function TeamStateDot({ state, size }: {
|
|
11
|
+
readonly state: TeamStateDotState;
|
|
12
|
+
readonly size?: number | undefined;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=TeamStateDot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamStateDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamStateDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAG1E,oHAAoH;AACpH,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAA;AAEhE;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;IACjD,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC,+BAKA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { StateDot } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import css from './state-dot.module.css';
|
|
4
|
+
/**
|
|
5
|
+
* Render the one shared Team status indicator. Native StateDot states pass
|
|
6
|
+
* through; the quiet statuses mirror StateDot geometry locally so every
|
|
7
|
+
* surface renders the same shape — todo a hollow ring (not started), quiet a
|
|
8
|
+
* solid tertiary dot with the same 10% halo (closed, unavailable).
|
|
9
|
+
*/
|
|
10
|
+
export function TeamStateDot({ state, size = 10 }) {
|
|
11
|
+
if (state === 'todo' || state === 'quiet') {
|
|
12
|
+
return _jsx("span", { className: css.quiet, "data-variant": state, style: { width: size, height: size }, "aria-hidden": "true" });
|
|
13
|
+
}
|
|
14
|
+
return _jsx(StateDot, { state: state, size: size });
|
|
15
|
+
}
|
|
@@ -12,6 +12,7 @@ interface TeamThreadPageProps {
|
|
|
12
12
|
readonly loadChannels: TeamConversationProps['loadChannels'];
|
|
13
13
|
readonly readThread: TeamConversationProps['readThread'];
|
|
14
14
|
readonly loadThreadHistory: TeamConversationProps['loadThreadHistory'];
|
|
15
|
+
readonly threadObservations: TeamConversationProps['threadObservations'];
|
|
15
16
|
readonly subscribeChanges: TeamConversationProps['subscribeChanges'];
|
|
16
17
|
readonly loadMembers: TeamConversationProps['loadMembers'];
|
|
17
18
|
readonly drafts: TeamDraftStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,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;
|
|
1
|
+
{"version":3,"file":"TeamThreadPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamThreadPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,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;AA8BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,+BAgsBxD"}
|
|
@@ -5,7 +5,8 @@ import { TeamComposer } from "./TeamComposer.js";
|
|
|
5
5
|
import { 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 } from "./team-formatters.js";
|
|
8
|
+
import { formatActivity, formatClaimState, formatTaskStatus, formatTaskTitle, mentionNamesOf, taskStatusDot } from "./team-formatters.js";
|
|
9
|
+
import { TeamStateDot } from "./TeamStateDot.js";
|
|
9
10
|
import { mintRequestId } from "./requests.js";
|
|
10
11
|
import { daySeparatorLabel, isRunGap, timelineDayKey } from "./team-separators.js";
|
|
11
12
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
@@ -33,11 +34,14 @@ function readMeta(facts) {
|
|
|
33
34
|
return new Map(facts.map(fact => [factKey(fact.fact), fact]));
|
|
34
35
|
}
|
|
35
36
|
export function TeamThreadPage(props) {
|
|
36
|
-
const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, promoteThread, t, } = props;
|
|
37
|
+
const { workspaceId, channelRef, taskRef, threadRef, taskNumber, backToWorkspace, selectChannel, selectThread, resolveTaskRefs, putAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, drafts, getAttachment, reply, changeTask, promoteThread, t, } = props;
|
|
37
38
|
const threadRequest = { threadRef, ...(taskRef === undefined ? {} : { taskRef }) };
|
|
38
39
|
const [projection, setProjection] = useState();
|
|
39
40
|
const [channelView, setChannelView] = useState();
|
|
40
41
|
const [members, setMembers] = useState([]);
|
|
42
|
+
// Current Thread followers; the composer ranks them first because a mention
|
|
43
|
+
// to a follower delivers directly instead of entering the invite detour.
|
|
44
|
+
const [followerIds, setFollowerIds] = useState(() => new Set());
|
|
41
45
|
const [currentFacts, setCurrentFacts] = useState([]);
|
|
42
46
|
const [olderFacts, setOlderFacts] = useState([]);
|
|
43
47
|
const [readFacts, setReadFacts] = useState([]);
|
|
@@ -196,29 +200,37 @@ export function TeamThreadPage(props) {
|
|
|
196
200
|
// Every arrival while the Thread is open is acknowledged durably: the
|
|
197
201
|
// timeline renders it either way, and the Human has no manual read
|
|
198
202
|
// action anymore. The count only feeds the pure jump hint for a reader
|
|
199
|
-
// away from the
|
|
203
|
+
// away from the tail; a bottom-pinned reader already sees the arrivals.
|
|
200
204
|
if (!timeline.isPinned())
|
|
201
205
|
setNewFactsCount(current => current + additions.length);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// The durable acknowledgment did not happen (it failed, a newer read
|
|
206
|
-
// superseded it, or the page unmounted); the count keeps the jump hint
|
|
207
|
-
// visible unless that newer read now owns the tail.
|
|
208
|
-
if (!mountedRef.current || sequenceRef.current !== priorSequence + 1)
|
|
209
|
-
return;
|
|
210
|
-
setNewFactsCount(current => current + additions.length);
|
|
206
|
+
// The acknowledgment outcome does not change what is on screen: a
|
|
207
|
+
// failed read surfaces through the error surface, not through the count.
|
|
208
|
+
await readCurrent(true);
|
|
211
209
|
}
|
|
212
210
|
catch {
|
|
213
211
|
// A passive refresh is an invalidation convenience; the next explicit action rereads Host state.
|
|
214
212
|
}
|
|
215
213
|
};
|
|
214
|
+
// Follower ranking is an enhancement, not a page fact: a failed observation
|
|
215
|
+
// read leaves the roster order in place instead of surfacing an error.
|
|
216
|
+
const refreshFollowers = async () => {
|
|
217
|
+
try {
|
|
218
|
+
const result = await threadObservations({ workspaceId, ...threadRequest });
|
|
219
|
+
if (!mountedRef.current || !result.ok)
|
|
220
|
+
return;
|
|
221
|
+
setFollowerIds(new Set(result.value.followers));
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// The next thread-scope wake retries; ranking falls back to roster order.
|
|
225
|
+
}
|
|
226
|
+
};
|
|
216
227
|
useEffect(() => {
|
|
217
228
|
mountedRef.current = true;
|
|
218
229
|
projectionRef.current = undefined;
|
|
219
230
|
setProjection(undefined);
|
|
220
231
|
setChannelView(undefined);
|
|
221
232
|
setMembers([]);
|
|
233
|
+
setFollowerIds(new Set());
|
|
222
234
|
setCurrentFacts([]);
|
|
223
235
|
currentFactsRef.current = [];
|
|
224
236
|
setOlderFacts([]);
|
|
@@ -235,9 +247,10 @@ export function TeamThreadPage(props) {
|
|
|
235
247
|
void (async () => {
|
|
236
248
|
// One parallel round covers the whole first paint. The durable read no
|
|
237
249
|
// longer wakes any change scope, so no second wave follows it.
|
|
238
|
-
const [read, history] = await Promise.all([
|
|
250
|
+
const [read, history, observations] = await Promise.all([
|
|
239
251
|
readThread({ requestId: readRequestIdRef.current, workspaceId, ...threadRequest }),
|
|
240
252
|
loadThreadHistory({ workspaceId, ...threadRequest, limit: 20 }).catch(() => undefined),
|
|
253
|
+
threadObservations({ workspaceId, ...threadRequest }).catch(() => undefined),
|
|
241
254
|
]);
|
|
242
255
|
if (!mountedRef.current || sequence !== sequenceRef.current)
|
|
243
256
|
return;
|
|
@@ -259,6 +272,8 @@ export function TeamThreadPage(props) {
|
|
|
259
272
|
setHistoryCursor(history.value.cursor);
|
|
260
273
|
setHistoryHasMore(history.value.hasMore);
|
|
261
274
|
}
|
|
275
|
+
if (observations !== undefined && observations.ok)
|
|
276
|
+
setFollowerIds(new Set(observations.value.followers));
|
|
262
277
|
setError(undefined);
|
|
263
278
|
setLoading(false);
|
|
264
279
|
await drainUnread();
|
|
@@ -273,6 +288,8 @@ export function TeamThreadPage(props) {
|
|
|
273
288
|
return;
|
|
274
289
|
}
|
|
275
290
|
void refreshPassiveFacts();
|
|
291
|
+
// Attention changes wake this scope too; keep the mention ranking current.
|
|
292
|
+
void refreshFollowers();
|
|
276
293
|
}),
|
|
277
294
|
subscribeChanges({ kind: 'workspace', workspaceId }, update => {
|
|
278
295
|
if (!mountedRef.current)
|
|
@@ -298,6 +315,14 @@ export function TeamThreadPage(props) {
|
|
|
298
315
|
if (newFactsCount > 0 && timeline.isPinned())
|
|
299
316
|
setNewFactsCount(0);
|
|
300
317
|
}, [newFactsCount, currentFacts, olderFacts, timeline]);
|
|
318
|
+
// The hint answers "where is the tail?"; the moment the reader is back
|
|
319
|
+
// within the follow margin — by the jump click or their own scroll — it
|
|
320
|
+
// must go away even when no render follows that position change.
|
|
321
|
+
const handleTimelineScroll = () => {
|
|
322
|
+
timeline.onScroll();
|
|
323
|
+
if (timeline.isPinned())
|
|
324
|
+
setNewFactsCount(0);
|
|
325
|
+
};
|
|
301
326
|
const loadOlder = async () => {
|
|
302
327
|
if (historyHasMore === false && historyCursor === undefined)
|
|
303
328
|
return;
|
|
@@ -614,7 +639,7 @@ export function TeamThreadPage(props) {
|
|
|
614
639
|
// Threads are always entered through a Channel page, so a Channel origin
|
|
615
640
|
// returns to its timeline; a Thread restored without one returns further.
|
|
616
641
|
const backLabel = channelRef === undefined ? t('backToWorkspace') : t('backToChannel');
|
|
617
|
-
return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined &&
|
|
642
|
+
return _jsxs("main", { className: css.surface, "data-team-thread": threadRef, children: [_jsxs("div", { className: css.surfaceHeader, children: [_jsx("div", { className: css.backRow, children: _jsx(Button, { size: "sm", icon: _jsx(IconChevronLeftOutline14, {}), onClick: backToWorkspace, children: backLabel }) }), _jsxs("header", { className: css.headerRow, children: [_jsxs("div", { className: css.headerCopy, children: [_jsxs("div", { className: threadCss.titleLine, children: [_jsx("h1", { children: task === undefined ? t('threadLabel') : t('taskLabel', { number: resolvedTaskNumber ?? '…' }) }), task !== undefined && _jsxs(Pill, { children: [_jsx(TeamStateDot, { size: 8, state: taskStatusDot(task.status) }), formatTaskStatus(task.status, t)] })] }), taskTitle !== undefined && taskTitle !== '' && _jsx("p", { className: threadCss.taskTitle, title: taskTitle, children: taskTitle })] }), task === undefined && thread !== undefined && _jsx("div", { className: css.headerActions, children: _jsx(Button, { size: "sm", variant: "primary", disabled: pending, onClick: () => { void convertToTask(); }, children: mutating === 'promote' ? t('promotingTask') : t('promoteToTask') }) }), task !== undefined && thread !== undefined && task.resolution !== 'closed' && _jsxs("div", { className: css.headerActions, children: [(() => {
|
|
618
643
|
const activeClaims = projection?.claims.filter(claim => claim.taskRef === task.taskRef && claim.state === 'active') ?? [];
|
|
619
644
|
const earlyAccept = task.resolution === 'open' && task.status === 'in_progress' && activeClaims.length > 0;
|
|
620
645
|
// todo Tasks accept directly: the work finished outside the
|
|
@@ -637,7 +662,7 @@ export function TeamThreadPage(props) {
|
|
|
637
662
|
})(), task !== undefined && thread !== undefined && _jsx("section", { className: threadCss.workSection, "aria-label": t('claims'), children: _jsx(DisclosureRow, { expandOnRowClick: true, expandable: true, open: claimsOpen, onToggle: () => { setClaimsOpen(current => !current); }, icon: _jsx(IconChecklistOutline14, { size: 14 }), title: `${t('claims')} · ${taskClaims.length}`, children: _jsxs("div", { className: threadCss.claimList, children: [taskClaims.length === 0 && _jsx("p", { className: threadCss.emptyClaims, children: t('noClaims') }), taskClaims.map(claim => {
|
|
638
663
|
const ownerStatus = members.find(status => status.member.memberId === claim.owner);
|
|
639
664
|
return _jsxs("article", { className: threadCss.claimRow, children: [ownerStatus === undefined ? _jsx("span", {}) : _jsx(TeamPresenceDot, { status: ownerStatus, t: t }), _jsx("strong", { className: threadCss.claimOwner, children: memberName(claim.owner) }), _jsx("span", { className: threadCss.claimDirection, children: claim.direction }), _jsx("small", { className: threadCss.claimState, children: formatClaimState(claim.state, t) })] }, claim.claimRef);
|
|
640
|
-
})] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll:
|
|
665
|
+
})] }) }) })] }), _jsx("section", { ref: timeline.ref, onScroll: handleTimelineScroll, className: css.timeline, "aria-label": t('timelineLabel'), children: _jsxs("div", { className: css.timelineContent, children: [loading && projection === undefined && error === undefined && _jsx("div", { className: css.emptySurface, children: _jsxs("p", { className: css.loadingState, children: [_jsx("span", { className: css.loadingMark, "aria-hidden": "true" }), t('loadingThread')] }) }), projection === undefined && error !== undefined && _jsxs("div", { className: css.errorState, role: "alert", children: [_jsx("span", { children: error }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { void readCurrent(); }, children: t('retry') })] }), olderFacts.length > 0 && _jsxs("section", { className: threadCss.historySection, "aria-label": t('olderHistory'), children: [_jsx("h2", { children: t('olderHistory') }), renderFactBlocks(olderFacts, undefined)] }), historyHasMore && _jsx("div", { className: css.timelineAction, children: _jsx(Button, { size: "sm", onClick: () => { void loadOlder(); }, children: t('loadOlder') }) }), currentFactsWithAnchor.length > 0 && _jsx("section", { className: threadCss.publicSection, children: renderFactBlocks(currentFactsWithAnchor, unreadBoundary) }), autoReadExhausted && _jsxs("div", { className: css.timelineAction, role: "alert", children: [_jsx("span", { children: t('autoReadIncomplete') }), _jsx(Button, { size: "sm", onClick: () => { setAutoReadExhausted(false); void drainUnread(); }, disabled: loading, children: t('retry') })] }), newFactsCount > 0 && _jsx("div", { className: threadCss.newUpdates, role: "status", children: _jsx("button", { type: "button", className: threadCss.newUpdatesJump, onClick: () => { setNewFactsCount(0); timeline.scrollToBottom(); }, children: t('newUpdatesJump', { count: newFactsCount }) }) })] }) }), projection !== undefined && thread !== undefined ? (task?.resolution === 'closed'
|
|
641
666
|
? _jsxs("div", { className: threadCss.closedBar, "data-team-closed": true, children: [error !== undefined && _jsx("p", { className: css.error, role: "alert", children: error }), _jsxs("div", { className: threadCss.closedNotice, children: [_jsx("span", { children: t('taskClosedNotice') }), _jsx(Button, { size: "sm", variant: "outline", disabled: pending, onClick: () => { void mutateTask('reopen'); }, children: t('reopenTask') })] })] })
|
|
642
|
-
: _jsx(TeamComposer, { members: channelMembers, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, placeholder: t('replyPlaceholder'), pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
|
|
667
|
+
: _jsx(TeamComposer, { members: channelMembers, followerMemberIds: followerIds, recipients: recipients, draft: draft, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onDraftChange: next => { drafts.writeDraft(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onRecipientsChange: next => { drafts.writeRecipients(draftKey, next); setConfirmation(undefined); setReplyRequestId(undefined); setStatusMessage(undefined); }, onSubmit: () => { void sendReply(); }, placeholder: t('replyPlaceholder'), pendingFiles: pendingFiles, onFilesChange: setPendingFiles, t: t }, draftKey)) : _jsx("div", {})] });
|
|
643
668
|
}
|
|
@@ -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;AAoCnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,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;AAyJD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
|