mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 03:03:24 +08:00
Show WhatsApp channel peer next to Agent Preset in session header (4.9.1-ops.20).
Plugins inject conversation.session.header.actions; resolve sessionId back to the bound chat and render nickname/phone or group title. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2718586fda
commit
37742043a9
15 changed files with 852 additions and 326 deletions
319
lib/client.js
319
lib/client.js
|
|
@ -566,12 +566,12 @@ __export(index_exports, {
|
|||
name: () => name
|
||||
});
|
||||
module.exports = __toCommonJS(index_exports);
|
||||
var React24 = __toESM(require("react"), 1);
|
||||
var React25 = __toESM(require("react"), 1);
|
||||
|
||||
// package.json
|
||||
var package_default = {
|
||||
name: "dsh-im-ops",
|
||||
version: "4.9.1-ops.19",
|
||||
version: "4.9.1-ops.20",
|
||||
description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",
|
||||
keywords: [
|
||||
"deepseek-harness",
|
||||
|
|
@ -852,6 +852,7 @@ var EN = Object.freeze({
|
|||
"\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
|
||||
"\u6295\u9012\u8BBE\u7F6E": "Delivery settings",
|
||||
"\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
|
||||
"\u6E20\u9053\u7528\u6237": "Channel user",
|
||||
"\uFF08\u4E0D\u53EF\u7528\uFF09": " (unavailable)",
|
||||
"\u7FA4 Agent Preset": "Group Agent Preset",
|
||||
"\u8DDF\u968F\u5168\u5C40": "Follow global",
|
||||
|
|
@ -11353,7 +11354,8 @@ var WHATSAPP_ENDPOINTS = Object.freeze({
|
|||
setGroupSessionScope: "bot.group-session-scope.set",
|
||||
setWorkspace: "bot.workspace.set",
|
||||
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
||||
setContextEnhancement: "bot.context-enhancement.set"
|
||||
setContextEnhancement: "bot.context-enhancement.set",
|
||||
resolveChannelPeer: "bot.session.channel-peer"
|
||||
});
|
||||
var PROVISION_STATES5 = /* @__PURE__ */ new Set(["starting", "pending", "connecting", "connected", "failed", "cancelled"]);
|
||||
var BOT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
||||
|
|
@ -12113,11 +12115,83 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|||
));
|
||||
}
|
||||
|
||||
// plugin-src/client/channel-peer-label.js
|
||||
var React20 = __toESM(require("react"), 1);
|
||||
var CHANNEL_LABELS = Object.freeze({
|
||||
whatsapp: "WhatsApp",
|
||||
feishu: "\u98DE\u4E66",
|
||||
dingtalk: "\u9489\u9489",
|
||||
wecom: "\u4F01\u4E1A\u5FAE\u4FE1",
|
||||
weixin: "\u5FAE\u4FE1",
|
||||
qq: "QQ",
|
||||
telegram: "Telegram",
|
||||
discord: "Discord",
|
||||
slack: "Slack",
|
||||
office: "AI Office"
|
||||
});
|
||||
function ChannelPeerLabel({ sessionId, resolveChannelPeer }) {
|
||||
const [peer, setPeer] = React20.useState(null);
|
||||
React20.useEffect(() => {
|
||||
if (typeof resolveChannelPeer !== "function" || typeof sessionId !== "string" || !sessionId) {
|
||||
setPeer(null);
|
||||
return void 0;
|
||||
}
|
||||
const controller = new AbortController();
|
||||
let active = true;
|
||||
void (async () => {
|
||||
try {
|
||||
const next = await resolveChannelPeer(sessionId, controller.signal);
|
||||
if (active && !controller.signal.aborted) setPeer(next && typeof next === "object" ? next : null);
|
||||
} catch {
|
||||
if (active && !controller.signal.aborted) setPeer(null);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
active = false;
|
||||
controller.abort();
|
||||
};
|
||||
}, [sessionId, resolveChannelPeer]);
|
||||
if (!peer?.label) return null;
|
||||
const channelName2 = CHANNEL_LABELS[peer.channel] || peer.channel || "IM";
|
||||
const title = peer.kind === "group" ? `${channelName2} \xB7 ${peer.label}` : `${channelName2} \xB7 ${peer.label}`;
|
||||
return h2(
|
||||
"span",
|
||||
{
|
||||
className: "dim-channelPeerLabel",
|
||||
title,
|
||||
"aria-label": localizeText("\u6E20\u9053\u7528\u6237") + ` \xB7 ${title}`
|
||||
},
|
||||
h2("span", { className: "dim-channelPeerChannel", "aria-hidden": "true" }, channelName2),
|
||||
h2("span", { className: "dim-channelPeerText" }, peer.label)
|
||||
);
|
||||
}
|
||||
async function resolveWhatsappChannelPeer(whatsappRpcCall, sessionId, signal) {
|
||||
if (typeof whatsappRpcCall !== "function") return null;
|
||||
const result = await whatsappRpcCall(
|
||||
WHATSAPP_ENDPOINTS.resolveChannelPeer,
|
||||
{ sessionId },
|
||||
signal
|
||||
);
|
||||
const value = unwrapRpcResult9(result);
|
||||
if (!value || typeof value !== "object") return null;
|
||||
const label = typeof value.label === "string" ? value.label.trim() : "";
|
||||
if (!label) return null;
|
||||
return {
|
||||
channel: typeof value.channel === "string" ? value.channel : "whatsapp",
|
||||
botId: typeof value.botId === "string" ? value.botId : "",
|
||||
kind: value.kind === "group" ? "group" : "direct",
|
||||
label,
|
||||
phone: typeof value.phone === "string" ? value.phone : null,
|
||||
pushName: typeof value.pushName === "string" ? value.pushName : null,
|
||||
groupTitle: typeof value.groupTitle === "string" ? value.groupTitle : null
|
||||
};
|
||||
}
|
||||
|
||||
// plugin-src/client/delivery-settings.js
|
||||
var React22 = __toESM(require("react"), 1);
|
||||
var React23 = __toESM(require("react"), 1);
|
||||
|
||||
// plugin-src/client/access-policy-settings.js
|
||||
var React20 = __toESM(require("react"), 1);
|
||||
var React21 = __toESM(require("react"), 1);
|
||||
var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
|
||||
var GROUP_SESSION_SCOPE_ENDPOINT = "bot.group-session-scope.set";
|
||||
var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
|
||||
|
|
@ -12220,8 +12294,8 @@ function ScenePolicyEditor({
|
|||
unsupported = false,
|
||||
onChange
|
||||
}) {
|
||||
const ownerHelpId = React20.useId();
|
||||
const emptyAllowlistHelpId = React20.useId();
|
||||
const ownerHelpId = React21.useId();
|
||||
const emptyAllowlistHelpId = React21.useId();
|
||||
const allowlist = policy.mode === "allowlist";
|
||||
const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
|
||||
const branchKey = allowlist ? "allowlist" : "open";
|
||||
|
|
@ -12273,7 +12347,7 @@ function ScenePolicyEditor({
|
|||
h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
|
||||
h2("p", null, "\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002")
|
||||
) : h2(
|
||||
React20.Fragment,
|
||||
React21.Fragment,
|
||||
null,
|
||||
h2(
|
||||
"div",
|
||||
|
|
@ -12415,18 +12489,18 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
|
||||
const initialKey = JSON.stringify(initialPolicy);
|
||||
const initialScope = normalizeGroupSessionScope(account?.groupSessionScope);
|
||||
const [draft, setDraft] = React20.useState(() => clonePolicy(
|
||||
const [draft, setDraft] = React21.useState(() => clonePolicy(
|
||||
initialPolicy ?? DEFAULT_ACCESS_POLICY
|
||||
));
|
||||
const [groupSessionScope, setGroupSessionScope] = React20.useState(initialScope);
|
||||
const [saving, setSaving] = React20.useState(false);
|
||||
const [feedback, setFeedback] = React20.useState(null);
|
||||
React20.useEffect(() => {
|
||||
const [groupSessionScope, setGroupSessionScope] = React21.useState(initialScope);
|
||||
const [saving, setSaving] = React21.useState(false);
|
||||
const [feedback, setFeedback] = React21.useState(null);
|
||||
React21.useEffect(() => {
|
||||
const next = normalizeAccessPolicy(account?.accessPolicy);
|
||||
setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
|
||||
setGroupSessionScope(normalizeGroupSessionScope(account?.groupSessionScope));
|
||||
}, [account?.botId, initialKey, account?.groupSessionScope]);
|
||||
React20.useEffect(() => {
|
||||
React21.useEffect(() => {
|
||||
setFeedback(null);
|
||||
}, [account?.botId]);
|
||||
if (!definition) {
|
||||
|
|
@ -12579,7 +12653,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
}
|
||||
|
||||
// plugin-src/client/access-grant-settings.js
|
||||
var React21 = __toESM(require("react"), 1);
|
||||
var React22 = __toESM(require("react"), 1);
|
||||
var ACCESS_GRANT_ENDPOINT = "bot.access-grant.set";
|
||||
var ACCESS_PENDING_RESOLVE_ENDPOINT = "bot.access-pending.resolve";
|
||||
var ACCESS_GROUP_TITLES_REFRESH_ENDPOINT = "bot.access-group-titles.refresh";
|
||||
|
|
@ -12671,13 +12745,13 @@ function PhoneTypeahead({
|
|||
disabled,
|
||||
requirePhone = true
|
||||
}) {
|
||||
const [query, setQuery] = React21.useState(value || "");
|
||||
const [open, setOpen] = React21.useState(false);
|
||||
const blurTimer = React21.useRef(null);
|
||||
React21.useEffect(() => {
|
||||
const [query, setQuery] = React22.useState(value || "");
|
||||
const [open, setOpen] = React22.useState(false);
|
||||
const blurTimer = React22.useRef(null);
|
||||
React22.useEffect(() => {
|
||||
setQuery(value || "");
|
||||
}, [value]);
|
||||
React21.useEffect(() => () => {
|
||||
React22.useEffect(() => () => {
|
||||
if (blurTimer.current) window.clearTimeout(blurTimer.current);
|
||||
}, []);
|
||||
const q = query.trim().toLowerCase();
|
||||
|
|
@ -12985,21 +13059,21 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
const initialGrant = normalizeAccessGrant(account?.accessGrant);
|
||||
const initialKey = JSON.stringify(initialGrant);
|
||||
const initialScope = normalizeGroupSessionScope(account?.groupSessionScope);
|
||||
const [draft, setDraft] = React21.useState(() => cloneGrant(initialGrant, ownerPhone));
|
||||
const [groupSessionScope, setGroupSessionScope] = React21.useState(initialScope);
|
||||
const [saving, setSaving] = React21.useState(false);
|
||||
const [feedback, setFeedback] = React21.useState(null);
|
||||
const [newGroupJid, setNewGroupJid] = React21.useState("");
|
||||
const [loadingGrant, setLoadingGrant] = React21.useState(!initialGrant);
|
||||
const contextCatalog = React21.useContext(AgentPresetCatalogContext);
|
||||
const [presetCatalog, setPresetCatalog] = React21.useState(() => normalizeAgentPresetCatalog(
|
||||
const [draft, setDraft] = React22.useState(() => cloneGrant(initialGrant, ownerPhone));
|
||||
const [groupSessionScope, setGroupSessionScope] = React22.useState(initialScope);
|
||||
const [saving, setSaving] = React22.useState(false);
|
||||
const [feedback, setFeedback] = React22.useState(null);
|
||||
const [newGroupJid, setNewGroupJid] = React22.useState("");
|
||||
const [loadingGrant, setLoadingGrant] = React22.useState(!initialGrant);
|
||||
const contextCatalog = React22.useContext(AgentPresetCatalogContext);
|
||||
const [presetCatalog, setPresetCatalog] = React22.useState(() => normalizeAgentPresetCatalog(
|
||||
account?.agentPresetCatalog ?? contextCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
||||
));
|
||||
React21.useEffect(() => {
|
||||
React22.useEffect(() => {
|
||||
setDraft(cloneGrant(normalizeAccessGrant(account?.accessGrant), ownerPhone));
|
||||
setGroupSessionScope(normalizeGroupSessionScope(account?.groupSessionScope));
|
||||
}, [account?.botId, initialKey, account?.groupSessionScope, ownerPhone]);
|
||||
React21.useEffect(() => {
|
||||
React22.useEffect(() => {
|
||||
if (typeof rpcCall !== "function" || !account?.botId) return void 0;
|
||||
let cancelled = false;
|
||||
setLoadingGrant(true);
|
||||
|
|
@ -13053,7 +13127,7 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
};
|
||||
}, [account?.botId, rpcCall, ownerPhone]);
|
||||
const contacts = draft.contacts ?? [];
|
||||
const knownGroupJids = React21.useMemo(() => {
|
||||
const knownGroupJids = React22.useMemo(() => {
|
||||
const set = new Set(Object.keys(draft.groups ?? {}));
|
||||
for (const contact of contacts) {
|
||||
for (const jid of contact.groupJids ?? []) set.add(jid);
|
||||
|
|
@ -13063,7 +13137,7 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
}
|
||||
return [...set].sort();
|
||||
}, [draft.groups, draft.pending, contacts]);
|
||||
const actionableContacts = React21.useMemo(
|
||||
const actionableContacts = React22.useMemo(
|
||||
() => contacts.filter((contact) => contactNeedsGrantAction(contact, draft, knownGroupJids)),
|
||||
[contacts, draft, knownGroupJids]
|
||||
);
|
||||
|
|
@ -13742,13 +13816,13 @@ function TargetForm({
|
|||
}) {
|
||||
const editing = mode === "edit";
|
||||
const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
|
||||
const [targetId, setTargetId] = React22.useState(initialValue?.targetId ?? "");
|
||||
const [name2, setName] = React22.useState(initialValue?.name ?? "");
|
||||
const [kind, setKind] = React22.useState(initialKind);
|
||||
const [route, setRoute] = React22.useState(initialValue?.route ?? {});
|
||||
const [error, setError] = React22.useState(null);
|
||||
const [testing, setTesting] = React22.useState(false);
|
||||
const [testState, setTestState] = React22.useState(null);
|
||||
const [targetId, setTargetId] = React23.useState(initialValue?.targetId ?? "");
|
||||
const [name2, setName] = React23.useState(initialValue?.name ?? "");
|
||||
const [kind, setKind] = React23.useState(initialKind);
|
||||
const [route, setRoute] = React23.useState(initialValue?.route ?? {});
|
||||
const [error, setError] = React23.useState(null);
|
||||
const [testing, setTesting] = React23.useState(false);
|
||||
const [testState, setTestState] = React23.useState(null);
|
||||
const currentTarget = () => {
|
||||
const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field) => {
|
||||
const raw = String(route[field.key] ?? "").trim();
|
||||
|
|
@ -13965,7 +14039,7 @@ function TargetSuggestionPicker({
|
|||
suggestions.map((suggestion, index) => {
|
||||
const identity = routeIdentity(definition, suggestion);
|
||||
const added = configured.has(identity);
|
||||
return React22.createElement("option", {
|
||||
return React23.createElement("option", {
|
||||
key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
|
||||
value: String(index),
|
||||
disabled: added
|
||||
|
|
@ -13982,10 +14056,10 @@ function TargetSuggestionPicker({
|
|||
);
|
||||
}
|
||||
function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
|
||||
const [action, setAction] = React22.useState(null);
|
||||
const [testState, setTestState] = React22.useState(null);
|
||||
const [copyState, setCopyState] = React22.useState(null);
|
||||
const [confirmDelete, setConfirmDelete] = React22.useState(false);
|
||||
const [action, setAction] = React23.useState(null);
|
||||
const [testState, setTestState] = React23.useState(null);
|
||||
const [copyState, setCopyState] = React23.useState(null);
|
||||
const [confirmDelete, setConfirmDelete] = React23.useState(false);
|
||||
const testTarget = async () => {
|
||||
setAction("test");
|
||||
setTestState(null);
|
||||
|
|
@ -14027,7 +14101,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
|
|||
h2(
|
||||
"div",
|
||||
{ className: "dim-targetTitle" },
|
||||
React22.createElement("strong", null, target.name || target.targetId),
|
||||
React23.createElement("strong", null, target.name || target.targetId),
|
||||
h2("span", null, kindLabel(definition, target.kind))
|
||||
),
|
||||
h2("code", null, `targetId: ${target.targetId}`)
|
||||
|
|
@ -14090,28 +14164,28 @@ function DeliveryTargetSettingsPage({
|
|||
onBack
|
||||
}) {
|
||||
const definition = CHANNEL_DEFINITIONS[channel4];
|
||||
const [activeTabId, setActiveTabId] = React22.useState(BOT_SETTINGS_TABS[0].id);
|
||||
const [phase, setPhase] = React22.useState("loading");
|
||||
const [targets, setTargets] = React22.useState([]);
|
||||
const [suggestionPhase, setSuggestionPhase] = React22.useState("idle");
|
||||
const [suggestions, setSuggestions] = React22.useState([]);
|
||||
const [suggestionError, setSuggestionError] = React22.useState(null);
|
||||
const [error, setError] = React22.useState(null);
|
||||
const [editor, setEditor] = React22.useState(null);
|
||||
const [saving, setSaving] = React22.useState(false);
|
||||
const [botCopyState, setBotCopyState] = React22.useState(null);
|
||||
const [accessPolicy, setAccessPolicy] = React22.useState(account.accessPolicy);
|
||||
const [accessGrant, setAccessGrant] = React22.useState(account.accessGrant);
|
||||
const mounted = React22.useRef(true);
|
||||
React22.useEffect(() => {
|
||||
const [activeTabId, setActiveTabId] = React23.useState(BOT_SETTINGS_TABS[0].id);
|
||||
const [phase, setPhase] = React23.useState("loading");
|
||||
const [targets, setTargets] = React23.useState([]);
|
||||
const [suggestionPhase, setSuggestionPhase] = React23.useState("idle");
|
||||
const [suggestions, setSuggestions] = React23.useState([]);
|
||||
const [suggestionError, setSuggestionError] = React23.useState(null);
|
||||
const [error, setError] = React23.useState(null);
|
||||
const [editor, setEditor] = React23.useState(null);
|
||||
const [saving, setSaving] = React23.useState(false);
|
||||
const [botCopyState, setBotCopyState] = React23.useState(null);
|
||||
const [accessPolicy, setAccessPolicy] = React23.useState(account.accessPolicy);
|
||||
const [accessGrant, setAccessGrant] = React23.useState(account.accessGrant);
|
||||
const mounted = React23.useRef(true);
|
||||
React23.useEffect(() => {
|
||||
setAccessPolicy(account.accessPolicy);
|
||||
setAccessGrant(account.accessGrant);
|
||||
}, [account.botId, account.accessPolicy, account.accessGrant]);
|
||||
const invoke = React22.useCallback(async (endpoint, payload = {}, signal) => {
|
||||
const invoke = React23.useCallback(async (endpoint, payload = {}, signal) => {
|
||||
if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
|
||||
return unwrapRpcResult12(await rpcCall(endpoint, payload, signal));
|
||||
}, [rpcCall]);
|
||||
const loadTargets = React22.useCallback(async ({ signal, silent = false } = {}) => {
|
||||
const loadTargets = React23.useCallback(async ({ signal, silent = false } = {}) => {
|
||||
if (!silent) setPhase("loading");
|
||||
setError(null);
|
||||
try {
|
||||
|
|
@ -14125,7 +14199,7 @@ function DeliveryTargetSettingsPage({
|
|||
setPhase("error");
|
||||
}
|
||||
}, [account.botId, invoke]);
|
||||
const loadSuggestions = React22.useCallback(async () => {
|
||||
const loadSuggestions = React23.useCallback(async () => {
|
||||
setSuggestionPhase("loading");
|
||||
setSuggestionError(null);
|
||||
try {
|
||||
|
|
@ -14139,7 +14213,7 @@ function DeliveryTargetSettingsPage({
|
|||
setSuggestionPhase("error");
|
||||
}
|
||||
}, [account.botId, definition, invoke]);
|
||||
React22.useEffect(() => {
|
||||
React23.useEffect(() => {
|
||||
mounted.current = true;
|
||||
const controller = new AbortController();
|
||||
void loadTargets({ signal: controller.signal });
|
||||
|
|
@ -14266,7 +14340,7 @@ function DeliveryTargetSettingsPage({
|
|||
rpcCall: accessRpcCall,
|
||||
onSaved: setAccessPolicy
|
||||
}) : h2(
|
||||
React22.Fragment,
|
||||
React23.Fragment,
|
||||
null,
|
||||
h2(
|
||||
"section",
|
||||
|
|
@ -14970,6 +15044,34 @@ body[data-ds-dark-theme] .dim-page select option, body[data-ds-dark-theme] .dim-
|
|||
.dim-accessGroupTitleRow { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 10px; align-items: end; }
|
||||
.dim-accessNickname { display: block; margin-top: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 15px; font-weight: 560; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dim-accessNicknameEmpty { color: var(--dsw-alias-label-tertiary, #8f959e); font-weight: 400; }
|
||||
.dim-channelPeerLabel {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
max-width: 260px;
|
||||
min-width: 0;
|
||||
height: 22px;
|
||||
padding: 0 8px 0 6px;
|
||||
border-radius: 6px;
|
||||
background: var(--dsw-alias-fill-tsp-secondary, color-mix(in srgb, var(--dsw-alias-label-primary, #1f2329) 6%, transparent));
|
||||
color: var(--dsw-alias-label-secondary, #646a73);
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dim-channelPeerChannel {
|
||||
flex: none;
|
||||
color: var(--dsw-alias-label-tertiary, #8f959e);
|
||||
font-weight: 560;
|
||||
}
|
||||
.dim-channelPeerText {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: 500;
|
||||
color: var(--dsw-alias-label-secondary, #646a73);
|
||||
}
|
||||
.dim-accessUserRow { position: relative; z-index: 0; overflow: visible; }
|
||||
.dim-panel .dim-botCard .dim-cardFooter { margin-top: 0; }
|
||||
.dim-panel .ddt-headingCopy { display: none; }
|
||||
|
|
@ -15052,7 +15154,7 @@ function installImStyles() {
|
|||
}
|
||||
|
||||
// plugin-src/client/update-panel.js
|
||||
var React23 = __toESM(require("react"), 1);
|
||||
var React24 = __toESM(require("react"), 1);
|
||||
var import_react_dom3 = require("react-dom");
|
||||
var import_valid = __toESM(require_valid(), 1);
|
||||
var import_rcompare = __toESM(require_rcompare(), 1);
|
||||
|
|
@ -15142,11 +15244,11 @@ function manualUpdateCommand(snapshot) {
|
|||
return `dsh plugin --profile ${profileArgument} add -w dsh-im-ops@${version}`;
|
||||
}
|
||||
function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
|
||||
const [copyState, setCopyState] = React23.useState("idle");
|
||||
const commandRef = React23.useRef(null);
|
||||
const mounted = React23.useRef(false);
|
||||
const copying = React23.useRef(false);
|
||||
React23.useEffect(() => {
|
||||
const [copyState, setCopyState] = React24.useState("idle");
|
||||
const commandRef = React24.useRef(null);
|
||||
const mounted = React24.useRef(false);
|
||||
const copying = React24.useRef(false);
|
||||
React24.useEffect(() => {
|
||||
mounted.current = true;
|
||||
return () => {
|
||||
mounted.current = false;
|
||||
|
|
@ -15178,7 +15280,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
|
|||
{ className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
|
||||
h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
|
||||
command ? h2(
|
||||
React23.Fragment,
|
||||
React24.Fragment,
|
||||
null,
|
||||
h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
|
||||
h2(
|
||||
|
|
@ -15214,7 +15316,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
|
|||
"aria-hidden": "true",
|
||||
focusable: "false"
|
||||
}, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
|
||||
React23.Fragment,
|
||||
React24.Fragment,
|
||||
null,
|
||||
h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
|
||||
h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
|
||||
|
|
@ -15239,10 +15341,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
|
|||
);
|
||||
}
|
||||
function UpdateDialog({ children, onClose }) {
|
||||
const dialogRef = React23.useRef(null);
|
||||
const titleId = React23.useId();
|
||||
const descriptionId = React23.useId();
|
||||
React23.useEffect(() => {
|
||||
const dialogRef = React24.useRef(null);
|
||||
const titleId = React24.useId();
|
||||
const descriptionId = React24.useId();
|
||||
React24.useEffect(() => {
|
||||
const previous = globalThis.document?.activeElement;
|
||||
dialogRef.current?.focus?.();
|
||||
return () => {
|
||||
|
|
@ -15300,19 +15402,19 @@ function UpdateDialog({ children, onClose }) {
|
|||
return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
|
||||
}
|
||||
function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
||||
const [snapshot, setSnapshot] = React23.useState(null);
|
||||
const [action, setAction] = React23.useState("status");
|
||||
const [error, setError] = React23.useState(null);
|
||||
const [open, setOpen] = React23.useState(false);
|
||||
const [uncertainInstall, setUncertainInstall] = React23.useState(false);
|
||||
const mounted = React23.useRef(false);
|
||||
const busy = React23.useRef(false);
|
||||
const readController = React23.useRef(null);
|
||||
const pollReadController = React23.useRef(null);
|
||||
const installRequest = React23.useRef(null);
|
||||
const onStatusRef = React23.useRef(onStatus);
|
||||
const [snapshot, setSnapshot] = React24.useState(null);
|
||||
const [action, setAction] = React24.useState("status");
|
||||
const [error, setError] = React24.useState(null);
|
||||
const [open, setOpen] = React24.useState(false);
|
||||
const [uncertainInstall, setUncertainInstall] = React24.useState(false);
|
||||
const mounted = React24.useRef(false);
|
||||
const busy = React24.useRef(false);
|
||||
const readController = React24.useRef(null);
|
||||
const pollReadController = React24.useRef(null);
|
||||
const installRequest = React24.useRef(null);
|
||||
const onStatusRef = React24.useRef(onStatus);
|
||||
onStatusRef.current = onStatus;
|
||||
const accept = React23.useCallback((next) => {
|
||||
const accept = React24.useCallback((next) => {
|
||||
setSnapshot(next);
|
||||
onStatusRef.current?.(next);
|
||||
}, []);
|
||||
|
|
@ -15321,7 +15423,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|||
setUncertainInstall(false);
|
||||
accept(next);
|
||||
};
|
||||
const invoke = React23.useCallback(async (endpoint, payload = {}, signal) => {
|
||||
const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
|
||||
if (typeof rpcCall !== "function") {
|
||||
const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
|
||||
unavailable.code = "update-unavailable";
|
||||
|
|
@ -15329,7 +15431,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|||
}
|
||||
return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
|
||||
}, [rpcCall]);
|
||||
React23.useEffect(() => {
|
||||
React24.useEffect(() => {
|
||||
mounted.current = true;
|
||||
busy.current = true;
|
||||
const controller = new AbortController();
|
||||
|
|
@ -15352,7 +15454,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|||
const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
|
||||
const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
|
||||
const shouldPoll = activeJob || uncertainInstall;
|
||||
React23.useEffect(() => {
|
||||
React24.useEffect(() => {
|
||||
if (!shouldPoll) return void 0;
|
||||
let controller;
|
||||
const scheduler = createPollScheduler({
|
||||
|
|
@ -15450,7 +15552,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|||
const manualCommand = manualUpdateCommand(snapshot);
|
||||
const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
|
||||
return h2(
|
||||
React23.Fragment,
|
||||
React24.Fragment,
|
||||
null,
|
||||
h2("button", {
|
||||
type: "button",
|
||||
|
|
@ -15475,13 +15577,13 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|||
h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
|
||||
h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
|
||||
snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
|
||||
React23.Fragment,
|
||||
React24.Fragment,
|
||||
null,
|
||||
h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
|
||||
h2("dd", null, `v${snapshot.installedVersion}`)
|
||||
) : null,
|
||||
targetVersion ? h2(
|
||||
React23.Fragment,
|
||||
React24.Fragment,
|
||||
null,
|
||||
h2("dt", null, "\u76EE\u6807\u7248\u672C"),
|
||||
h2("dd", null, `v${targetVersion}`)
|
||||
|
|
@ -15685,20 +15787,20 @@ function IMSettingsTab({
|
|||
browserLocation = globalThis.location,
|
||||
navigateToRecoveryUrl = replacePageLocation
|
||||
}) {
|
||||
const [selected, setSelected] = React24.useState("weixin");
|
||||
const [loopbackRecovery, setLoopbackRecovery] = React24.useState(null);
|
||||
const [runningVersion, setRunningVersion] = React24.useState(IM_PLUGIN_VERSION);
|
||||
const [deliverySettings, setDeliverySettings] = React24.useState(null);
|
||||
const githubTooltipId = React24.useId();
|
||||
const channelSelectId = React24.useId();
|
||||
const [selected, setSelected] = React25.useState("weixin");
|
||||
const [loopbackRecovery, setLoopbackRecovery] = React25.useState(null);
|
||||
const [runningVersion, setRunningVersion] = React25.useState(IM_PLUGIN_VERSION);
|
||||
const [deliverySettings, setDeliverySettings] = React25.useState(null);
|
||||
const githubTooltipId = React25.useId();
|
||||
const channelSelectId = React25.useId();
|
||||
const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
|
||||
const reportLoopbackRecovery = React24.useCallback((recovery) => {
|
||||
const reportLoopbackRecovery = React25.useCallback((recovery) => {
|
||||
setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
|
||||
}, []);
|
||||
const reportUpdateStatus = React24.useCallback((snapshot) => {
|
||||
const reportUpdateStatus = React25.useCallback((snapshot) => {
|
||||
setRunningVersion(snapshot.runningVersion);
|
||||
}, []);
|
||||
const rpcCalls = React24.useMemo(() => createLoopbackAwareRpcCalls({
|
||||
const rpcCalls = React25.useMemo(() => createLoopbackAwareRpcCalls({
|
||||
dingtalkRpcCall,
|
||||
discordRpcCall,
|
||||
feishuRpcCall,
|
||||
|
|
@ -15730,7 +15832,7 @@ function IMSettingsTab({
|
|||
weixinRpcCall,
|
||||
whatsappRpcCall
|
||||
]);
|
||||
const botSettingsContext = React24.useMemo(() => Object.freeze({
|
||||
const botSettingsContext = React25.useMemo(() => Object.freeze({
|
||||
openBotSettings: setDeliverySettings
|
||||
}), []);
|
||||
return h2(
|
||||
|
|
@ -15881,6 +15983,15 @@ function apply(ctx) {
|
|||
listDirectory: (path, signal) => callWorkspaceDirectoryApi(ctx, "listDirectory", path, signal),
|
||||
pickDirectory: () => callWorkspaceDirectoryApi(ctx, "pickDirectory")
|
||||
});
|
||||
const resolveChannelPeer = (sessionId, signal) => resolveWhatsappChannelPeer(whatsappRpcCall, sessionId, signal);
|
||||
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
||||
name: "conversation.session.header.actions",
|
||||
id: "im-channel-peer",
|
||||
// Immediately after Agent Preset (−10); schedule/jobs follow at 10+.
|
||||
order: 0,
|
||||
locale: IM_LOCALE_NAMESPACE,
|
||||
inject: () => ({ resolveChannelPeer })
|
||||
}, ChannelPeerLabel));
|
||||
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
||||
name: "settings.section",
|
||||
id: "xmanrui-dsh-im",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue