@wowyuarm/dsh-agent-team 0.1.14-alpha.2 → 0.1.15
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 +6 -4
- package/README.zh.md +6 -4
- package/cordis.patch.yml +3 -1
- package/package.json +51 -46
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -2
- package/packages/agent-team/core-skills/member-memory-manager/SKILL.md +30 -0
- package/packages/agent-team/lib/context-continuity-host.js +90 -0
- package/packages/agent-team/lib/context-projection.js +266 -489
- package/packages/agent-team/lib/context-source.js +4 -72
- package/packages/agent-team/lib/human-avatar.js +61 -0
- package/packages/agent-team/lib/human-profile.js +157 -0
- package/packages/agent-team/lib/human-update-check.js +119 -0
- package/packages/agent-team/lib/index.js +464 -254
- package/packages/agent-team/lib/ledger.js +120 -15
- package/packages/agent-team/lib/member-context.js +6 -3
- package/packages/agent-team/lib/member-runtime.js +1 -1
- package/packages/agent-team/lib/pressure-policy.js +6 -1
- package/packages/agent-team/lib/typert.host.js +489 -33
- package/packages/agent-team/lib/typert.remote-client.d.ts +15 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +250 -28
- package/packages/agent-team/lib/types/context-continuity-host.d.ts +84 -0
- package/packages/agent-team/lib/types/context-continuity-host.d.ts.map +1 -0
- package/packages/agent-team/lib/types/context-projection.d.ts +130 -185
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-source.d.ts +4 -35
- package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
- package/packages/agent-team/lib/types/human-avatar.d.ts +29 -0
- package/packages/agent-team/lib/types/human-avatar.d.ts.map +1 -0
- package/packages/agent-team/lib/types/human-profile.d.ts +116 -0
- package/packages/agent-team/lib/types/human-profile.d.ts.map +1 -0
- package/packages/agent-team/lib/types/human-update-check.d.ts +73 -0
- package/packages/agent-team/lib/types/human-update-check.d.ts.map +1 -0
- package/packages/agent-team/lib/types/index.d.ts +153 -41
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +31 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/pressure-policy.d.ts +6 -0
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +17 -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 +81 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/client-agent-team/README.md +1 -1
- package/packages/client-agent-team/README.zh.md +1 -1
- package/packages/client-agent-team/lib/client.js +1545 -303
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts +15 -0
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.js +115 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +6 -2
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +22 -1
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +25 -2
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +6 -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 +67 -29
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +2 -2
- 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 +12 -5
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +4 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +22 -7
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +11 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +66 -5
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +18 -3
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +213 -67
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +5 -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 +52 -26
- package/packages/client-agent-team/lib/types/client/avatar-image.d.ts +21 -0
- package/packages/client-agent-team/lib/types/client/avatar-image.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/avatar-image.js +9 -0
- package/packages/client-agent-team/lib/types/client/human-identity.d.ts +90 -0
- package/packages/client-agent-team/lib/types/client/human-identity.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/human-identity.js +96 -0
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +76 -4
- package/packages/client-agent-team/lib/types/client/locales.d.ts +72 -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 +78 -2
- package/packages/client-agent-team/lib/types/client/refs.d.ts +71 -0
- package/packages/client-agent-team/lib/types/client/refs.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/refs.js +181 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +9 -3
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +57 -9
- 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 +85 -17
- 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/context-tools.js +20 -6
- package/packages/tool-agent-team/lib/index.js +2 -2
- package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
- package/packages/agent-team/lib/context-management.js +0 -371
- package/packages/agent-team/lib/types/context-management.d.ts +0 -154
- package/packages/agent-team/lib/types/context-management.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +0 -31
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/task-refs.js +0 -99
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
import { type TeamHumanIdentityFace } from './human-identity.ts';
|
|
3
|
+
export interface HumanSettingsSectionInjected {
|
|
4
|
+
/** The shared Human identity projection: profile facts plus post-write refresh. */
|
|
5
|
+
identity: TeamHumanIdentityFace;
|
|
6
|
+
/** Persist one renamed display name; the failure message when the Host refuses it. */
|
|
7
|
+
saveName: (name: string) => Promise<string | undefined>;
|
|
8
|
+
/** Upload one image file, persist its reference; the failure message when it does not stick. */
|
|
9
|
+
uploadAvatar: (file: File) => Promise<string | undefined>;
|
|
10
|
+
/** Clear the avatar; the identity falls back to the initial. */
|
|
11
|
+
removeAvatar: () => Promise<string | undefined>;
|
|
12
|
+
}
|
|
13
|
+
export type HumanSettingsSectionProps = PropsRuntime<'settings.section'> & PropsLocale<'team'> & HumanSettingsSectionInjected;
|
|
14
|
+
export declare function HumanSettingsSection(props: HumanSettingsSectionProps): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=HumanSettingsSection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HumanSettingsSection.d.ts","sourceRoot":"","sources":["../../../src/client/HumanSettingsSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAiBlF,MAAM,WAAW,4BAA4B;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACvD,gGAAgG;IAChG,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,gEAAgE;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,yBAAyB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAChC,WAAW,CAAC,MAAM,CAAC,GACnB,4BAA4B,CAAA;AAsBhC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,+BAiKpE"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { Button, Input } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
+
import { useHumanIdentity } from "./human-identity.js";
|
|
5
|
+
import { useAvatarImage } from "./avatar-image.js";
|
|
6
|
+
import css from './human-settings.module.css';
|
|
7
|
+
/**
|
|
8
|
+
* The Human's own settings page: display name, avatar, and the version
|
|
9
|
+
* footnote.
|
|
10
|
+
*
|
|
11
|
+
* The page owns no durable fact and no copy of one. Name, avatar, and version
|
|
12
|
+
* all arrive from the shared identity projection, so a save here moves the
|
|
13
|
+
* message rows and member refs at the same moment; a failed write keeps the
|
|
14
|
+
* typed name in the field and reports the Host's own reason.
|
|
15
|
+
*/
|
|
16
|
+
/** Host-side avatar ceiling (`ATTACHMENT_MAX_BYTES`): the settings page refuses larger files before the round trip. */
|
|
17
|
+
const AVATAR_MAX_BYTES = 10 * 1024 * 1024;
|
|
18
|
+
/**
|
|
19
|
+
* Run one durable write and reduce every failure to the message the page
|
|
20
|
+
* reports. A rejected Remote call (a dropped carrier, a refused write) is a
|
|
21
|
+
* failure like any other: without this the field would sit on "saving" forever
|
|
22
|
+
* and report nothing.
|
|
23
|
+
*/
|
|
24
|
+
async function failureOf(action) {
|
|
25
|
+
try {
|
|
26
|
+
return await action();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return error instanceof Error ? error.message : String(error);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** First visible character of a display name, or the neutral `H` before one is known. */
|
|
33
|
+
function avatarInitial(name) {
|
|
34
|
+
const trimmed = (name ?? '').replace(/^@/, '').trim();
|
|
35
|
+
return trimmed === '' ? 'H' : trimmed.slice(0, 1).toUpperCase();
|
|
36
|
+
}
|
|
37
|
+
export function HumanSettingsSection(props) {
|
|
38
|
+
const { t, identity } = props;
|
|
39
|
+
const profile = useHumanIdentity(identity);
|
|
40
|
+
// Undefined means "follow the Host value": the field re-syncs whenever the
|
|
41
|
+
// profile changes underneath, without a background read clobbering a name
|
|
42
|
+
// the reader is still editing.
|
|
43
|
+
const [draft, setDraft] = useState(undefined);
|
|
44
|
+
const [saving, setSaving] = useState(false);
|
|
45
|
+
const [uploading, setUploading] = useState(false);
|
|
46
|
+
const [notice, setNotice] = useState(null);
|
|
47
|
+
const filePicker = useRef(null);
|
|
48
|
+
const name = draft ?? profile.name ?? '';
|
|
49
|
+
const dirty = draft !== undefined && draft.trim() !== (profile.name ?? '');
|
|
50
|
+
const emptyName = draft !== undefined && draft.trim() === '';
|
|
51
|
+
const hasAvatar = profile.avatarRef !== undefined;
|
|
52
|
+
// The circle answers to decoded bytes, not to a stored reference: the Host
|
|
53
|
+
// accepts any `image/…` payload, so a file this browser cannot read has to
|
|
54
|
+
// fall back to the initial exactly as a removed one does.
|
|
55
|
+
const avatar = useAvatarImage(profile.avatarUrl);
|
|
56
|
+
const submitName = async () => {
|
|
57
|
+
if (!dirty || emptyName || saving)
|
|
58
|
+
return;
|
|
59
|
+
setSaving(true);
|
|
60
|
+
setNotice(null);
|
|
61
|
+
const failure = await failureOf(() => props.saveName(name.trim()));
|
|
62
|
+
setSaving(false);
|
|
63
|
+
if (failure !== undefined) {
|
|
64
|
+
setNotice(t('humanSettingsNameFailed', { message: failure }));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setDraft(undefined);
|
|
68
|
+
};
|
|
69
|
+
const pickAvatar = async (file) => {
|
|
70
|
+
if (file === undefined)
|
|
71
|
+
return;
|
|
72
|
+
setNotice(null);
|
|
73
|
+
if (!file.type.startsWith('image/')) {
|
|
74
|
+
setNotice(t('humanSettingsAvatarNotImage'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (file.size > AVATAR_MAX_BYTES) {
|
|
78
|
+
setNotice(t('humanSettingsAvatarTooLarge'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
setUploading(true);
|
|
82
|
+
const failure = await failureOf(() => props.uploadAvatar(file));
|
|
83
|
+
setUploading(false);
|
|
84
|
+
if (failure !== undefined)
|
|
85
|
+
setNotice(t('humanSettingsAvatarFailed', { message: failure }));
|
|
86
|
+
};
|
|
87
|
+
const removeAvatar = async () => {
|
|
88
|
+
setNotice(null);
|
|
89
|
+
const failure = await failureOf(() => props.removeAvatar());
|
|
90
|
+
if (failure !== undefined)
|
|
91
|
+
setNotice(t('humanSettingsAvatarFailed', { message: failure }));
|
|
92
|
+
};
|
|
93
|
+
// The page says what it is before it says what happened: the settings nav
|
|
94
|
+
// lists it beside the Harness's own pages, so the title alone leaves "whose
|
|
95
|
+
// profile is this, and where does it apply?" unanswered — and every state,
|
|
96
|
+
// including a failed read, has to answer it.
|
|
97
|
+
const pageHeader = _jsxs(_Fragment, { children: [_jsx("h2", { className: css.heading, children: t('humanSettingsTitle') }), _jsx("p", { className: css.intro, children: t('humanSettingsIntro') })] });
|
|
98
|
+
if (profile.status === 'loading' && profile.name === undefined) {
|
|
99
|
+
return _jsxs("div", { className: css.section, children: [pageHeader, _jsx("p", { className: css.state, role: "status", children: t('humanSettingsLoading') })] });
|
|
100
|
+
}
|
|
101
|
+
if (profile.name === undefined) {
|
|
102
|
+
return _jsxs("div", { className: css.section, children: [pageHeader, _jsx("p", { className: css.state, role: "alert", children: t('humanSettingsUnavailable', { message: profile.error ?? '' }) }), _jsx("div", { className: css.stateAction, children: _jsx(Button, { variant: "outline", onClick: () => { void identity.refresh(); }, children: t('retry') }) })] });
|
|
103
|
+
}
|
|
104
|
+
return (_jsxs("div", { className: css.section, children: [pageHeader, _jsxs("div", { className: css.rows, children: [_jsxs("div", { className: css.row, children: [_jsxs("div", { className: css.rowText, children: [_jsx("div", { className: css.title, children: t('humanSettingsName') }), _jsx("div", { className: css.desc, children: t('humanSettingsNameHint') })] }), _jsxs("form", { className: css.controls, onSubmit: (event) => {
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
void submitName();
|
|
107
|
+
}, children: [_jsx(Input, { className: css.nameInput, "aria-label": t('humanSettingsName'), "aria-invalid": emptyName || undefined, value: name, disabled: saving, onChange: (event) => { setDraft(event.target.value); } }), _jsx(Button, { type: "submit", variant: "primary", disabled: saving || !dirty || emptyName, children: saving ? t('humanSettingsSaving') : t('humanSettingsSave') })] })] }), _jsxs("div", { className: css.row, children: [_jsxs("div", { className: css.rowText, children: [_jsx("div", { className: css.title, children: t('humanSettingsAvatar') }), _jsx("div", { className: css.desc, children: t('humanSettingsAvatarHint') })] }), _jsxs("div", { className: css.controls, children: [avatar.src === undefined
|
|
108
|
+
? _jsx("span", { className: `${css.identity} ${css.identityFallback}`, "data-avatar": "initial", "aria-hidden": "true", children: avatarInitial(profile.name) })
|
|
109
|
+
: _jsx("img", { className: `${css.identity} ${css.identityImage}`, "data-avatar": "image", src: avatar.src, alt: "", onError: avatar.failed }), _jsx("input", { ref: filePicker, type: "file", accept: "image/*", tabIndex: -1, "aria-hidden": "true", hidden: true, onChange: (event) => {
|
|
110
|
+
void pickAvatar(event.target.files?.[0]);
|
|
111
|
+
event.target.value = '';
|
|
112
|
+
} }), _jsx(Button, { variant: "outline", disabled: uploading, onClick: () => { filePicker.current?.click(); }, children: uploading ? t('humanSettingsUploading') : hasAvatar ? t('humanSettingsReplace') : t('humanSettingsUpload') }), hasAvatar && _jsx(Button, { disabled: uploading, onClick: () => { void removeAvatar(); }, children: t('humanSettingsRemoveAvatar') })] })] })] }), _jsxs("div", { className: css.footnote, children: [_jsx("span", { children: t('humanSettingsVersion', { version: profile.version ?? '' }) }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("a", { className: css.link, href: profile.repoUrl ?? '', target: "_blank", rel: "noreferrer", children: "GitHub" }), profile.updateAvailable && profile.latestVersion !== undefined
|
|
113
|
+
? _jsx("a", { className: css.link, href: `${profile.repoUrl ?? ''}/releases`, target: "_blank", rel: "noreferrer", children: t('humanSettingsUpdateAvailable', { version: profile.latestVersion }) })
|
|
114
|
+
: null] }), emptyName && _jsx("p", { className: css.notice, children: t('humanSettingsNameEmpty') }), notice === null ? null : _jsx("p", { className: css.notice, role: "alert", children: notice })] }));
|
|
115
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAclD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACjD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;IAC3D,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAA;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IACjE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC1F,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"TeamAgentsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAgentsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,2BAA2B,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAclD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAA;IAC/D,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACjD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IACvD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IACzD,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;IAC3D,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACnD,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAA;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IACjE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC1F,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC;AAED,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BA+O9P"}
|
|
@@ -9,7 +9,7 @@ import { mintRequestId } from "./requests.js";
|
|
|
9
9
|
import { diagnosticText, restartOffered } from "./TeamPresenceDot.js";
|
|
10
10
|
import { TeamRowMenu } from "./TeamRowMenu.js";
|
|
11
11
|
import { TeamSidebarSection } from "./TeamSidebarSection.js";
|
|
12
|
-
import { AgentEditorDialog, ModelPickerField, sameModel } from "./TeamMemberEditor.js";
|
|
12
|
+
import { AgentEditorDialog, ModelPickerField, sameModel, warmModelCatalog } from "./TeamMemberEditor.js";
|
|
13
13
|
import { TeamAgentImport } from "./TeamAgentImport.js";
|
|
14
14
|
import createCss from './create.module.css';
|
|
15
15
|
import css from './sidebar.module.css';
|
|
@@ -112,6 +112,10 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
|
|
|
112
112
|
setLoading(false);
|
|
113
113
|
}, [loadMembers, workspaceId, followRollover]);
|
|
114
114
|
useEffect(() => { void refresh(); }, [refresh]);
|
|
115
|
+
// Warm the Host model catalog while the roster loads, so the create and
|
|
116
|
+
// edit pickers open with rows instead of paying the first read on open.
|
|
117
|
+
// Mount-scoped (not per refresh): presence wakes must not refetch it.
|
|
118
|
+
useEffect(() => { warmModelCatalog(loadModels); }, [loadModels]);
|
|
115
119
|
useEffect(() => subscribeChanges({ kind: 'workspace', workspaceId }, update => {
|
|
116
120
|
if (update.type === 'failed') {
|
|
117
121
|
setError(update.message);
|
|
@@ -144,7 +148,7 @@ export function TeamAgentsPanel({ workspaceId, loadMembers, subscribeChanges, ad
|
|
|
144
148
|
try {
|
|
145
149
|
const result = await addMember(request);
|
|
146
150
|
if (result.ok) {
|
|
147
|
-
const committed = { ...result.value.status, workspaceIds:
|
|
151
|
+
const committed = { ...result.value.status, workspaceIds: result.value.workspaceIds };
|
|
148
152
|
setMembers(current => {
|
|
149
153
|
const retained = current.filter(status => status.member.memberId !== committed.member.memberId);
|
|
150
154
|
return committed.member.state === 'inactive' || committed.member.state === 'archived' ? retained : [...retained, committed];
|
|
@@ -5,14 +5,35 @@ export interface TeamAvatarOwner {
|
|
|
5
5
|
/** Public handle, or the raw Member id when the roster no longer names them. */
|
|
6
6
|
readonly name: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* The reader's own identity, as the Client's one Human projection holds it.
|
|
10
|
+
*
|
|
11
|
+
* The stack draws every owner from the shared Member language — hue plus
|
|
12
|
+
* initial — which is the whole identity an Agent has. The Human is the one
|
|
13
|
+
* Member with a picture, so that one chip draws the picture and falls back to
|
|
14
|
+
* this name's initial, exactly as the timeline already does.
|
|
15
|
+
*/
|
|
16
|
+
export interface TeamAvatarHuman {
|
|
17
|
+
readonly memberId: AgentTeamMemberId;
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly avatarUrl?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Owners as a seat names them: the Client's Human identity outranks the name
|
|
23
|
+
* the Host projected for that actor, so a rename moves label and initial
|
|
24
|
+
* together in every seat that draws the stack.
|
|
25
|
+
*/
|
|
26
|
+
export declare function namedAvatarOwners(owners: readonly TeamAvatarOwner[], human: TeamAvatarHuman | undefined): readonly TeamAvatarOwner[];
|
|
8
27
|
/**
|
|
9
28
|
* The compact "who is on this work" stack: overlapping 18px Member circles in
|
|
10
29
|
* the shared identity language, capped at three plus a `+N` chip. The circles
|
|
11
30
|
* are presentational, so the stack is one `role="img"` whose label carries the
|
|
12
31
|
* whole roster — three anonymous initials would read as noise.
|
|
13
32
|
*/
|
|
14
|
-
export declare function TeamAvatarStack({ owners, label }: {
|
|
33
|
+
export declare function TeamAvatarStack({ owners, label, human }: {
|
|
15
34
|
readonly owners: readonly TeamAvatarOwner[];
|
|
16
35
|
readonly label: string;
|
|
36
|
+
/** The reader's own identity; one owner matching it draws the Human's picture. */
|
|
37
|
+
readonly human?: TeamAvatarHuman | undefined;
|
|
17
38
|
}): import("react").JSX.Element | null;
|
|
18
39
|
//# sourceMappingURL=TeamAvatarStack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamAvatarStack.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAvatarStack.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"TeamAvatarStack.d.ts","sourceRoot":"","sources":["../../../src/client/TeamAvatarStack.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAQvE,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,SAAS,eAAe,EAAE,CAGpI;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IACxD,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;CAC7C,sCAQA"}
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useAvatarImage } from "./avatar-image.js";
|
|
2
3
|
import { memberHue } from "./team-formatters.js";
|
|
3
4
|
import css from './avatar-stack.module.css';
|
|
4
5
|
/** Distinct owners past this count collapse into one `+N` chip. */
|
|
5
6
|
const MAX_VISIBLE = 3;
|
|
7
|
+
/**
|
|
8
|
+
* Owners as a seat names them: the Client's Human identity outranks the name
|
|
9
|
+
* the Host projected for that actor, so a rename moves label and initial
|
|
10
|
+
* together in every seat that draws the stack.
|
|
11
|
+
*/
|
|
12
|
+
export function namedAvatarOwners(owners, human) {
|
|
13
|
+
if (human === undefined)
|
|
14
|
+
return owners;
|
|
15
|
+
return owners.map(owner => owner.memberId === human.memberId ? { memberId: owner.memberId, name: human.name } : owner);
|
|
16
|
+
}
|
|
6
17
|
/**
|
|
7
18
|
* The compact "who is on this work" stack: overlapping 18px Member circles in
|
|
8
19
|
* the shared identity language, capped at three plus a `+N` chip. The circles
|
|
9
20
|
* are presentational, so the stack is one `role="img"` whose label carries the
|
|
10
21
|
* whole roster — three anonymous initials would read as noise.
|
|
11
22
|
*/
|
|
12
|
-
export function TeamAvatarStack({ owners, label }) {
|
|
23
|
+
export function TeamAvatarStack({ owners, label, human }) {
|
|
13
24
|
if (owners.length === 0)
|
|
14
25
|
return null;
|
|
15
26
|
const shown = owners.slice(0, MAX_VISIBLE);
|
|
16
27
|
const overflow = owners.length - shown.length;
|
|
17
|
-
return _jsxs("span", { className: css.stack, role: "img", "aria-label": label, children: [shown.map(owner => _jsx(
|
|
28
|
+
return _jsxs("span", { className: css.stack, role: "img", "aria-label": label, children: [shown.map(owner => _jsx(OwnerAvatar, { owner: owner, human: human }, owner.memberId)), overflow > 0 && _jsx("span", { className: css.overflow, children: `+${overflow}` })] });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* One circle. Only an owner the seat identifies as the Human consults an image
|
|
32
|
+
* at all, and those bytes keep the initial whenever they do not decode — the
|
|
33
|
+
* same promise, and the same hook, the timeline avatar makes.
|
|
34
|
+
*/
|
|
35
|
+
function OwnerAvatar({ owner, human }) {
|
|
36
|
+
const image = useAvatarImage(human !== undefined && owner.memberId === human.memberId ? human.avatarUrl : undefined);
|
|
37
|
+
const hue = { '--team-avatar-hue': memberHue(owner.memberId) };
|
|
38
|
+
if (image.src === undefined)
|
|
39
|
+
return _jsx("span", { className: css.avatar, style: hue, children: initial(owner.name) });
|
|
40
|
+
return _jsx("img", { className: css.avatarImage, style: hue, src: image.src, alt: "", "aria-hidden": "true", onError: image.failed });
|
|
18
41
|
}
|
|
19
42
|
/** First visible character of a handle — and of a raw Member id when that is all there is. */
|
|
20
43
|
function initial(name) {
|
|
@@ -5,6 +5,9 @@ import type { TeamDraftStore } from './drafts.ts';
|
|
|
5
5
|
interface TeamChannelPageProps {
|
|
6
6
|
readonly workspaceId: WorkspaceId;
|
|
7
7
|
readonly channelRef: AgentTeamChannelRef;
|
|
8
|
+
/** The Human's own display name and avatar, from the shared identity projection. */
|
|
9
|
+
readonly humanName: string;
|
|
10
|
+
readonly humanAvatarUrl?: string | undefined;
|
|
8
11
|
readonly loadChannels: TeamConversationProps['loadChannels'];
|
|
9
12
|
readonly subscribeChanges: TeamConversationProps['subscribeChanges'];
|
|
10
13
|
readonly loadMembers: TeamConversationProps['loadMembers'];
|
|
@@ -19,9 +22,11 @@ interface TeamChannelPageProps {
|
|
|
19
22
|
readonly selectThread: TeamConversationProps['selectThread'];
|
|
20
23
|
readonly selectChannel: TeamConversationProps['selectChannel'];
|
|
21
24
|
readonly resolveTaskRefs: TeamConversationProps['resolveTaskRefs'];
|
|
25
|
+
readonly resolveThreadRefs: TeamConversationProps['resolveThreadRefs'];
|
|
26
|
+
readonly openMemberSession: TeamConversationProps['openMemberSession'];
|
|
22
27
|
readonly backToChannels: TeamConversationProps['backToChannels'];
|
|
23
28
|
readonly t: TeamConversationProps['t'];
|
|
24
29
|
}
|
|
25
|
-
export declare function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }: TeamChannelPageProps): import("react").JSX.Element;
|
|
30
|
+
export declare function TeamChannelPage({ workspaceId, channelRef, humanName, humanAvatarUrl, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, resolveThreadRefs, openMemberSession, t }: TeamChannelPageProps): import("react").JSX.Element;
|
|
26
31
|
export {};
|
|
27
32
|
//# sourceMappingURL=TeamChannelPage.d.ts.map
|
|
@@ -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;AAEvD,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;AAEvD,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAA;AAmB/D,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,oFAAoF;IACpF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,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,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,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,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAA;IACtE,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,gBAAgB,CAAC,CAAA;IAChE,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AAkDD,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BA4Y/V"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment, useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Button, IconChevronLeftOutlineRegular, IconChevronRightOutlineRegular, Modal } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { mintRequestId, uploadComposerFiles } from "./requests.js";
|
|
5
5
|
import { TeamComposer } from "./TeamComposer.js";
|
|
6
6
|
import { TeamMemberRow } from "./TeamMemberRow.js";
|
|
7
7
|
import { TeamMessage } from "./TeamMessage.js";
|
|
8
|
-
import { TeamAvatarStack } from "./TeamAvatarStack.js";
|
|
8
|
+
import { namedAvatarOwners, TeamAvatarStack } from "./TeamAvatarStack.js";
|
|
9
9
|
import { TeamCountBadge } from "./TeamCountBadge.js";
|
|
10
10
|
import { TeamRunDivider } from "./TeamRunDivider.js";
|
|
11
11
|
import { claimersLabel, formatAbsoluteTime, formatInboxTime, formatTaskStatus, taskStatusDot, mentionNamesOf } from "./team-formatters.js";
|
|
12
12
|
import { TeamStateDot } from "./TeamStateDot.js";
|
|
13
13
|
import { useChannelMembership } from "./team-membership.js";
|
|
14
14
|
import { useTimelineScroll } from "./timeline-scroll.js";
|
|
15
|
-
import { hostTaskRefLookup, jumpToTaskThread } from "./
|
|
15
|
+
import { hostTaskRefLookup, jumpToTaskThread } from "./refs.js";
|
|
16
|
+
import { hostThreadRefLookup, jumpToThread } from "./refs.js";
|
|
17
|
+
import { rosterChannelName, rosterMember } from "./refs.js";
|
|
16
18
|
import { chunkRunsWithDays, isRunGap } from "./team-separators.js";
|
|
17
19
|
import channelCss from './channel.module.css';
|
|
18
20
|
import css from './conversation.module.css';
|
|
@@ -44,11 +46,24 @@ function followUpAt(item) {
|
|
|
44
46
|
const lastActivityAt = item.lastActivityAt;
|
|
45
47
|
return lastActivityAt === undefined || lastActivityAt === item.message.occurredAt ? undefined : lastActivityAt;
|
|
46
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* What the door prints about follow-up activity, or nothing. A resolved Task
|
|
51
|
+
* stops printing it: the status word beside the door already says nothing is
|
|
52
|
+
* moving, and the instant it would print is the moment it resolved — repeated
|
|
53
|
+
* on every finished row. The precise instant stays on the control's title, one
|
|
54
|
+
* hover away. A taskless Thread never resolves, so a discussion keeps the
|
|
55
|
+
* recency that is the whole of its state line: it wears no status word, dot, or
|
|
56
|
+
* owner stack.
|
|
57
|
+
*/
|
|
58
|
+
function printedActivityAt(item) {
|
|
59
|
+
const status = item.task?.status;
|
|
60
|
+
return status === 'done' || status === 'closed' ? undefined : followUpAt(item);
|
|
61
|
+
}
|
|
47
62
|
/** Host unread per Thread, keyed for the feed's rows: zero unread is the absence of a badge, not a row. */
|
|
48
63
|
function unreadCounts(inbox) {
|
|
49
64
|
return new Map(inbox.items.filter(item => item.unreadCount > 0).map(item => [item.thread.threadRef, item.unreadCount]));
|
|
50
65
|
}
|
|
51
|
-
export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, t }) {
|
|
66
|
+
export function TeamChannelPage({ workspaceId, channelRef, humanName, humanAvatarUrl, loadChannels, subscribeChanges, loadMembers, loadInbox, drafts, putAttachment, getAttachment, sendMessage, joinChannel, removeChannelMember, selectThread, selectChannel, backToChannels, resolveTaskRefs, resolveThreadRefs, openMemberSession, t }) {
|
|
52
67
|
const [view, setView] = useState();
|
|
53
68
|
const [members, setMembers] = useState([]);
|
|
54
69
|
const [unreadByThread, setUnreadByThread] = useState(new Map());
|
|
@@ -76,8 +91,10 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
76
91
|
const refreshSequenceRef = useRef(0);
|
|
77
92
|
const channelLastItem = view?.items[view.items.length - 1];
|
|
78
93
|
// Branded-ref navigation for message bodies: channel refs hop directly,
|
|
79
|
-
// task refs resolve against this Channel's loaded timeline and
|
|
80
|
-
//
|
|
94
|
+
// task and thread refs resolve against this Channel's loaded timeline and
|
|
95
|
+
// fall back to the Host resolver, which also accepts abbreviated spellings.
|
|
96
|
+
// Unresolvable refs never become links (see TeamMessage), so this path only
|
|
97
|
+
// fires for refs the Host already confirmed.
|
|
81
98
|
const openRef = (ref) => {
|
|
82
99
|
if (ref.startsWith('channel:')) {
|
|
83
100
|
if (ref !== channelRef)
|
|
@@ -90,18 +107,9 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
90
107
|
selectThread(match.thread.threadRef, channelRef, match.task?.taskRef, match.taskNumber);
|
|
91
108
|
return;
|
|
92
109
|
}
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
if (!result.ok)
|
|
97
|
-
return;
|
|
98
|
-
const target = result.value.items[0];
|
|
99
|
-
if (target !== undefined) {
|
|
100
|
-
const targetChannel = result.value.channels.find(channel => channel.channelRef === target.message.channelRef);
|
|
101
|
-
if (targetChannel !== undefined)
|
|
102
|
-
selectThread(target.thread.threadRef, targetChannel.channelRef, target.task?.taskRef, target.taskNumber);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
110
|
+
// Not in the loaded timeline (or cited by abbreviation): resolve through
|
|
111
|
+
// the Host and jump to the Thread's home Channel.
|
|
112
|
+
jumpToThread(resolveThreadRefs, workspaceId, ref, selectThread);
|
|
105
113
|
return;
|
|
106
114
|
}
|
|
107
115
|
if (ref.startsWith('task:')) {
|
|
@@ -116,6 +124,33 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
116
124
|
}
|
|
117
125
|
};
|
|
118
126
|
const lookupTaskRefs = hostTaskRefLookup(resolveTaskRefs, workspaceId);
|
|
127
|
+
const lookupThreadRefs = hostThreadRefLookup(resolveThreadRefs, workspaceId);
|
|
128
|
+
// Roster chips resolve synchronously from loaded data: channel names from
|
|
129
|
+
// the loaded feed windows, member facts from the member list. Anything
|
|
130
|
+
// outside stays plain text — the same rule unresolvable refs follow. The
|
|
131
|
+
// lookups key on roster content, not array identity: every refresh hands
|
|
132
|
+
// over fresh arrays, and the memoized rows must survive change bursts that
|
|
133
|
+
// leave the roster itself untouched.
|
|
134
|
+
const rosterKey = useMemo(() => [
|
|
135
|
+
(view?.channels ?? []).map(channel => `${channel.channelRef}=${channel.name}=${channel.state}`).join(','),
|
|
136
|
+
members.map(status => `${status.member.memberId}=${status.member.handle}=${status.member.sessionId}=${status.availability}`).join(','),
|
|
137
|
+
view?.humanMemberId ?? '',
|
|
138
|
+
].join(';'), [view, members]);
|
|
139
|
+
const channelNameOf = useMemo(() => {
|
|
140
|
+
const channels = view?.channels ?? [];
|
|
141
|
+
return (ref) => rosterChannelName(channels, ref);
|
|
142
|
+
}, [rosterKey]);
|
|
143
|
+
const memberOf = useMemo(() => {
|
|
144
|
+
const humanMemberId = view?.humanMemberId;
|
|
145
|
+
return (ref) => rosterMember(members, humanMemberId, humanName, ref);
|
|
146
|
+
}, [rosterKey, humanName]);
|
|
147
|
+
// The Thread entry row's owner stack speaks the same grammar as the Inbox
|
|
148
|
+
// row's, Human included: the Host names which actor is the reader, the
|
|
149
|
+
// Client's identity projection says what that actor looks like.
|
|
150
|
+
const humanMemberId = view?.humanMemberId;
|
|
151
|
+
const humanIdentity = humanMemberId === undefined
|
|
152
|
+
? undefined
|
|
153
|
+
: { memberId: humanMemberId, name: humanName, ...(humanAvatarUrl === undefined ? {} : { avatarUrl: humanAvatarUrl }) };
|
|
119
154
|
const timeline = useTimelineScroll(`${view?.items.length ?? 0}:${channelLastItem?.message.messageRef ?? ''}`);
|
|
120
155
|
const channel = view?.channels.find(item => item.channelRef === channelRef);
|
|
121
156
|
const channelMemberIds = new Set(view?.members.filter(item => item.channelRef === channelRef).map(item => item.memberId) ?? []);
|
|
@@ -364,7 +399,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
364
399
|
: _jsx("div", { className: css.messageRun, children: block.items.map((item, index) => {
|
|
365
400
|
const senderStatus = members.find(member => member.member.memberId === item.message.sender);
|
|
366
401
|
const human = item.message.sender === view.humanMemberId;
|
|
367
|
-
const sender = human ?
|
|
402
|
+
const sender = human ? humanName : senderStatus?.member.handle ?? item.message.sender;
|
|
368
403
|
const turnGap = isRunGap(index > 0 ? block.items[index - 1].message.occurredAt : undefined, item.message.occurredAt);
|
|
369
404
|
const task = item.task;
|
|
370
405
|
// The entry's own line is the gate under the body, and its state
|
|
@@ -373,7 +408,7 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
373
408
|
// of it — the Thread page owns that surface.
|
|
374
409
|
const unread = unreadByThread.get(item.thread.threadRef) ?? 0;
|
|
375
410
|
// A turn divider already labels the gapped entry; its row stays chrome-free.
|
|
376
|
-
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsx(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, handleByMember), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: item.message.topLevel && _jsx(ThreadEntryRow, { item: item, owners: item.claimOwners, unread: unread, t: t, onOpen: () => { selectThread(item.thread.threadRef, channelRef, task?.taskRef, item.taskNumber); } }) })] }, item.message.messageRef);
|
|
411
|
+
return _jsxs(Fragment, { children: [turnGap && _jsx(TeamRunDivider, { occurredAt: item.message.occurredAt }), _jsx(TeamMessage, { senderName: sender, memberId: item.message.sender, human: human, ...(humanAvatarUrl === undefined ? {} : { avatarUrl: humanAvatarUrl }), body: item.message.body, attachments: item.message.attachments, loadAttachment: getAttachment, t: t, occurredAt: item.message.occurredAt, mentionNames: mentionNamesOf(item.mentions, handleByMember, humanName), onOpenRef: openRef, onResolveTaskRefs: lookupTaskRefs, onResolveThreadRefs: lookupThreadRefs, channelNameOf: channelNameOf, memberOf: memberOf, onOpenMemberSession: openMemberSession, grouped: index > 0, showGroupedTime: item.message.topLevel === true && !turnGap, ...(senderStatus === undefined ? {} : { senderTitle: senderStatus.member.description }), children: item.message.topLevel && _jsx(ThreadEntryRow, { item: item, owners: item.claimOwners, unread: unread, human: humanIdentity, t: t, onOpen: () => { selectThread(item.thread.threadRef, channelRef, task?.taskRef, item.taskNumber); } }) })] }, item.message.messageRef);
|
|
377
412
|
}) }, `run-${block.items[0].message.messageRef}`))] }) }), channel !== undefined ? _jsx(TeamComposer, { members: channelMembers, drafts: drafts, draftKey: draftKey, pending: pending, ...(statusMessage === undefined ? {} : { confirmation: statusMessage }), ...(error === undefined ? {} : { error }), onEdit: clearSendState, onSubmit: () => { void send(); }, pendingFiles: pendingFiles, onFilesChange: setPendingFiles, asTask: asTask, onAsTaskChange: setAsTask, t: t }, draftKey) : _jsx("div", {})] });
|
|
378
413
|
}
|
|
379
414
|
/**
|
|
@@ -385,27 +420,30 @@ export function TeamChannelPage({ workspaceId, channelRef, loadChannels, subscri
|
|
|
385
420
|
* carried nothing else. The unread capsule is the only member a taskless
|
|
386
421
|
* discussion can carry: it needs no Task.
|
|
387
422
|
*/
|
|
388
|
-
function ThreadStateCluster({ task, owners, unread, t }) {
|
|
423
|
+
function ThreadStateCluster({ task, owners, unread, human, t }) {
|
|
389
424
|
if (task === undefined && unread === 0)
|
|
390
425
|
return null;
|
|
391
|
-
|
|
426
|
+
const namedOwners = namedAvatarOwners(owners, human);
|
|
427
|
+
return _jsxs("span", { className: css.stateCluster, children: [task !== undefined && _jsx(TeamAvatarStack, { owners: namedOwners, label: claimersLabel(namedOwners, t), human: human }), task !== undefined && _jsx(TeamStateDot, { size: 8, state: taskStatusDot(task.status) }), task !== undefined && _jsx("span", { className: css.statusWord, children: formatTaskStatus(task.status, t) }), _jsx(TeamCountBadge, { count: unread })] });
|
|
392
428
|
}
|
|
393
429
|
/**
|
|
394
430
|
* The gate under one top-level Message: the single row that opens its Thread,
|
|
395
431
|
* and the one line that says what stands there. State leads it, then what the
|
|
396
432
|
* entry is: a Task entry keeps its number so the status word never floats free
|
|
397
|
-
* of the Task it describes, follow-up activity adds when the work last moved
|
|
398
|
-
* and an unanswered Thread says only 回复.
|
|
399
|
-
* 今天/昨天 form with the precise local time on
|
|
400
|
-
* unread Thread says so in the control's label
|
|
433
|
+
* of the Task it describes, follow-up activity adds when the work last moved —
|
|
434
|
+
* while the work is still unfinished — and an unanswered Thread says only 回复.
|
|
435
|
+
* The instant uses the Inbox's own 今天/昨天 form with the precise local time on
|
|
436
|
+
* the control's title, and an unread Thread says so in the control's label
|
|
437
|
+
* rather than only in pixels.
|
|
401
438
|
*/
|
|
402
|
-
function ThreadEntryRow({ item, owners, unread, t, onOpen }) {
|
|
439
|
+
function ThreadEntryRow({ item, owners, unread, human, t, onOpen }) {
|
|
403
440
|
const taskNumber = item.taskNumber;
|
|
404
441
|
const followUp = followUpAt(item);
|
|
442
|
+
const printedActivity = printedActivityAt(item);
|
|
405
443
|
const label = taskNumber !== undefined
|
|
406
444
|
? t('taskLabel', { number: taskNumber })
|
|
407
445
|
: followUp === undefined ? t('replyAction') : t('threadLabel');
|
|
408
|
-
const text =
|
|
446
|
+
const text = printedActivity === undefined ? label : `${label} · ${t('recentActivity', { time: formatInboxTime(printedActivity, t) })}`;
|
|
409
447
|
const openLabel = taskNumber === undefined
|
|
410
448
|
? unread > 0 ? t('openThreadUnread', { count: unread }) : t('openThread')
|
|
411
449
|
: unread > 0 ? t('openTaskUnread', { number: taskNumber, count: unread }) : t('openTask', { number: taskNumber });
|
|
@@ -413,5 +451,5 @@ function ThreadEntryRow({ item, owners, unread, t, onOpen }) {
|
|
|
413
451
|
// owner stack keeps its own accessible name — a labeled button prunes its
|
|
414
452
|
// descendants from the accessibility tree — and so the control's name says
|
|
415
453
|
// exactly what clicking it does.
|
|
416
|
-
return _jsxs("span", { className: css.entryLine, "data-thread-entry": "", children: [_jsx(ThreadStateCluster, { task: item.task, owners: owners, unread: unread, t: t }), _jsxs("button", { type: "button", className: css.entryRow, "aria-label": openLabel, ...(followUp === undefined ? {} : { title: formatAbsoluteTime(followUp) }), onClick: onOpen, children: [_jsx("span", { children: text }), _jsx("span", { className: css.entryArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutlineRegular, { size: 12 }) })] })] });
|
|
454
|
+
return _jsxs("span", { className: css.entryLine, "data-thread-entry": "", children: [_jsx(ThreadStateCluster, { task: item.task, owners: owners, unread: unread, human: human, t: t }), _jsxs("button", { type: "button", className: css.entryRow, "aria-label": openLabel, ...(followUp === undefined ? {} : { title: formatAbsoluteTime(followUp) }), onClick: onOpen, children: [_jsx("span", { children: text }), _jsx("span", { className: css.entryArrow, "aria-hidden": "true", children: _jsx(IconChevronRightOutlineRegular, { size: 12 }) })] })] });
|
|
417
455
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { IconChecklistOutlineMedium, IconPaperclipOutlineMedium, IconSendOutlineRegular, Tooltip, useAnchoredMaxHeight, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
4
|
import { TeamPresenceDot } from "./TeamPresenceDot.js";
|
|
5
5
|
import { allMentionMembers, containsAllMention, containsMention, mentionedMemberIds } from "./team-formatters.js";
|
|
6
6
|
import css from './composer.module.css';
|
|
@@ -259,7 +259,7 @@ export function TeamComposer({ members, followerMemberIds, drafts, draftKey, pen
|
|
|
259
259
|
if (chosen.length > 0 && pendingFiles !== undefined)
|
|
260
260
|
onFilesChange([...pendingFiles, ...chosen]);
|
|
261
261
|
event.target.value = '';
|
|
262
|
-
} }), _jsx(Tooltip, { label: t('attachFiles'), side: "top", delayMs: 500, children: _jsx("button", { type: "button", className: css.attachButton, "aria-label": t('attachFiles'), disabled: pending, onClick: () => { fileInputRef.current?.click(); }, children: _jsx(
|
|
262
|
+
} }), _jsx(Tooltip, { label: t('attachFiles'), side: "top", delayMs: 500, children: _jsx("button", { type: "button", className: css.attachButton, "aria-label": t('attachFiles'), disabled: pending, onClick: () => { fileInputRef.current?.click(); }, children: _jsx(IconPaperclipOutlineMedium, { size: 14 }) }) })] })), onAsTaskChange !== undefined && (_jsxs("button", { type: "button", className: asTask === true ? `${css.asTaskPill} ${css.asTaskPillOn}` : css.asTaskPill, "aria-label": t('asTask'), "aria-pressed": asTask === true, title: t('asTask'), disabled: pending, onClick: () => { onAsTaskChange(asTask !== true); }, children: [_jsx(IconChecklistOutlineMedium, { size: 14 }), _jsx("span", { className: css.asTaskLabel, children: t('asTask') })] })), _jsx("button", { type: "submit", className: css.sendButton, "aria-label": pending ? t('sendingMessage') : t('sendMessage'), disabled: pending || draft.trim() === '', onMouseDown: event => {
|
|
263
263
|
// Keep the composer focused when the send control is clicked.
|
|
264
264
|
event.preventDefault();
|
|
265
265
|
inputRef.current?.focus({ preventScroll: true });
|
|
@@ -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, threadObservations, subscribeChanges, loadMembers, loadInbox, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, selectWorkspace, backToWorkspace, backToChannels, resolveTaskRefs }: TeamConversationProps): import("react").JSX.Element;
|
|
2
|
+
export declare function TeamConversation({ t, useWorkspaces, navigation, drafts, humanIdentity, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, loadInbox, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, selectWorkspace, backToWorkspace, backToChannels, resolveTaskRefs, resolveThreadRefs, openMemberSession }: 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;
|
|
1
|
+
{"version":3,"file":"TeamConversation.d.ts","sourceRoot":"","sources":["../../../src/client/TeamConversation.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAOvD,wBAAgB,gBAAgB,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,EAAE,qBAAqB,+BAgC9c"}
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useSyncExternalStore } from 'react';
|
|
3
|
+
import { useHumanIdentity } from "./human-identity.js";
|
|
3
4
|
import { TeamChannelPage } from "./TeamChannelPage.js";
|
|
4
5
|
import { TeamInboxPage } from "./TeamInboxPage.js";
|
|
5
6
|
import { TeamThreadPage } from "./TeamThreadPage.js";
|
|
6
7
|
import css from './conversation.module.css';
|
|
7
|
-
export function TeamConversation({ t, useWorkspaces, navigation, drafts, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, loadInbox, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, selectWorkspace, backToWorkspace, backToChannels, resolveTaskRefs }) {
|
|
8
|
+
export function TeamConversation({ t, useWorkspaces, navigation, drafts, humanIdentity, putAttachment, getAttachment, loadChannels, readThread, loadThreadHistory, threadObservations, subscribeChanges, loadMembers, loadInbox, sendMessage, joinChannel, removeChannelMember, reply, changeTask, promoteThread, selectThread, selectChannel, selectWorkspace, backToWorkspace, backToChannels, resolveTaskRefs, resolveThreadRefs, openMemberSession }) {
|
|
8
9
|
const navigationState = useSyncExternalStore(navigation.subscribe, navigation.getSnapshot, navigation.getSnapshot);
|
|
10
|
+
// Every seat names and draws the Human from this one projection: the
|
|
11
|
+
// localized fallback stands only until the first profile read lands.
|
|
12
|
+
const identity = useHumanIdentity(humanIdentity);
|
|
13
|
+
const humanName = identity.name ?? t('human');
|
|
9
14
|
const workspaces = useWorkspaces(state => state.items);
|
|
10
15
|
const current = workspaces.find(workspace => workspace.workspaceId === navigationState.workspaceId);
|
|
11
16
|
if (navigationState.inbox === true) {
|
|
12
17
|
// The Inbox page is global: it merges every visible Workspace and needs no
|
|
13
18
|
// selected Workspace. Selecting Inbox clears the Channel/Thread faces, so
|
|
14
|
-
// this face owns the seat while the flag stands.
|
|
15
|
-
|
|
19
|
+
// this face owns the seat while the flag stands. The Human identity rides
|
|
20
|
+
// along for the same reason it rides on the other two faces: a row that
|
|
21
|
+
// names or draws the reader must draw the one identity every seat draws.
|
|
22
|
+
return _jsx(TeamInboxPage, { useWorkspaces: useWorkspaces, loadInbox: loadInbox, subscribeChanges: subscribeChanges, selectWorkspace: selectWorkspace, selectThread: selectThread, humanName: humanName, ...(identity.avatarUrl === undefined ? {} : { humanAvatarUrl: identity.avatarUrl }), t: t }, "inbox");
|
|
16
23
|
}
|
|
17
24
|
if (current !== undefined && navigationState.threadRef !== undefined) {
|
|
18
|
-
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);
|
|
25
|
+
return _jsx(TeamThreadPage, { humanName: humanName, ...(identity.avatarUrl === undefined ? {} : { humanAvatarUrl: identity.avatarUrl }), workspaceId: current.workspaceId, putAttachment: putAttachment, threadRef: navigationState.threadRef, backToWorkspace: backToWorkspace, selectChannel: selectChannel, selectThread: selectThread, resolveTaskRefs: resolveTaskRefs, resolveThreadRefs: resolveThreadRefs, openMemberSession: openMemberSession, ...(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);
|
|
19
26
|
}
|
|
20
27
|
if (current !== undefined && navigationState.channelRef !== undefined) {
|
|
21
|
-
return _jsx(TeamChannelPage, { workspaceId: current.workspaceId, channelRef: navigationState.channelRef, drafts: drafts, putAttachment: putAttachment, getAttachment: getAttachment, loadChannels: loadChannels, subscribeChanges: subscribeChanges, loadMembers: loadMembers, loadInbox: loadInbox, sendMessage: sendMessage, joinChannel: joinChannel, removeChannelMember: removeChannelMember, selectThread: selectThread, selectChannel: selectChannel, backToChannels: backToChannels, resolveTaskRefs: resolveTaskRefs, t: t }, navigationState.channelRef);
|
|
28
|
+
return _jsx(TeamChannelPage, { humanName: humanName, ...(identity.avatarUrl === undefined ? {} : { humanAvatarUrl: identity.avatarUrl }), workspaceId: current.workspaceId, channelRef: navigationState.channelRef, drafts: drafts, putAttachment: putAttachment, getAttachment: getAttachment, loadChannels: loadChannels, subscribeChanges: subscribeChanges, loadMembers: loadMembers, loadInbox: loadInbox, sendMessage: sendMessage, joinChannel: joinChannel, removeChannelMember: removeChannelMember, selectThread: selectThread, selectChannel: selectChannel, backToChannels: backToChannels, resolveTaskRefs: resolveTaskRefs, resolveThreadRefs: resolveThreadRefs, openMemberSession: openMemberSession, t: t }, navigationState.channelRef);
|
|
22
29
|
}
|
|
23
30
|
const welcome = current === undefined
|
|
24
31
|
? { eyebrow: t('teamMode'), title: t('team'), body: t('empty') }
|
|
@@ -6,6 +6,9 @@ interface TeamInboxPageProps {
|
|
|
6
6
|
readonly subscribeChanges: TeamConversationProps['subscribeChanges'];
|
|
7
7
|
readonly selectWorkspace: TeamConversationProps['selectWorkspace'];
|
|
8
8
|
readonly selectThread: TeamConversationProps['selectThread'];
|
|
9
|
+
/** The Human's display name, from the Client's one identity projection. */
|
|
10
|
+
readonly humanName: string;
|
|
11
|
+
readonly humanAvatarUrl?: string | undefined;
|
|
9
12
|
readonly t: TeamConversationProps['t'];
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
@@ -20,6 +23,6 @@ interface TeamInboxPageProps {
|
|
|
20
23
|
* holding unread is only ever in the queue: the Host already excludes it from
|
|
21
24
|
* the tail, and this page never re-derives that judgement.
|
|
22
25
|
*/
|
|
23
|
-
export declare function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, t }: TeamInboxPageProps): import("react").JSX.Element;
|
|
26
|
+
export declare function TeamInboxPage({ useWorkspaces, loadInbox, subscribeChanges, selectWorkspace, selectThread, humanName, humanAvatarUrl, t }: TeamInboxPageProps): import("react").JSX.Element;
|
|
24
27
|
export {};
|
|
25
28
|
//# sourceMappingURL=TeamInboxPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAavD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,kBAAkB,+
|
|
1
|
+
{"version":3,"file":"TeamInboxPage.d.ts","sourceRoot":"","sources":["../../../src/client/TeamInboxPage.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAavD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAC9D,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACtD,mGAAmG;IACnG,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;IACpE,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAA;CACvC;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,EAAE,EAAE,kBAAkB,+BAqH5J"}
|