@xmanrui/dsh-im 4.3.0 → 4.4.0
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/lib/client.js +951 -626
- package/lib/index.js +233 -233
- package/package.json +1 -1
- package/plugin-src/client/access-policy-settings.js +351 -0
- package/plugin-src/client/channel-card-meta.js +2 -1
- package/plugin-src/client/channels/dingtalk/api.js +5 -0
- package/plugin-src/client/channels/dingtalk/index.js +1 -0
- package/plugin-src/client/channels/feishu/api.js +5 -0
- package/plugin-src/client/channels/feishu/index.js +1 -0
- package/plugin-src/client/channels/qq/api.js +5 -0
- package/plugin-src/client/channels/qq/index.js +1 -0
- package/plugin-src/client/channels/shared/token-api.js +5 -0
- package/plugin-src/client/channels/shared/token-channel.js +1 -0
- package/plugin-src/client/channels/telegram/api.js +2 -17
- package/plugin-src/client/channels/telegram/index.js +0 -112
- package/plugin-src/client/channels/telegram/styles.js +0 -28
- package/plugin-src/client/channels/wecom/api.js +5 -0
- package/plugin-src/client/channels/wecom/index.js +1 -0
- package/plugin-src/client/channels/weixin/api.js +5 -0
- package/plugin-src/client/channels/weixin/index.js +1 -0
- package/plugin-src/client/channels/whatsapp/api.js +4 -10
- package/plugin-src/client/channels/whatsapp/index.js +1 -125
- package/plugin-src/client/channels/whatsapp/styles.js +0 -25
- package/plugin-src/client/delivery-settings.js +61 -9
- package/plugin-src/client/i18n.js +56 -1
- package/plugin-src/client/index.js +1 -0
- package/plugin-src/client/styles.js +50 -4
- package/plugin-src/host/channels/dingtalk/production.mjs +12 -1
- package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
- package/plugin-src/host/channels/feishu/production.mjs +39 -1
- package/plugin-src/host/channels/feishu/rpc.mjs +19 -2
- package/plugin-src/host/channels/qq/production.mjs +12 -1
- package/plugin-src/host/channels/qq/rpc.mjs +11 -0
- package/plugin-src/host/channels/shared/access-policy-production.mjs +137 -0
- package/plugin-src/host/channels/shared/access-policy-rpc.mjs +17 -0
- package/plugin-src/host/channels/shared/production.mjs +15 -1
- package/plugin-src/host/channels/shared/rpc.mjs +9 -0
- package/plugin-src/host/channels/slack/production.mjs +12 -1
- package/plugin-src/host/channels/slack/rpc.mjs +10 -0
- package/plugin-src/host/channels/telegram/rpc.mjs +2 -49
- package/plugin-src/host/channels/wecom/production.mjs +12 -1
- package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
- package/plugin-src/host/channels/weixin/production.mjs +12 -1
- package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
- package/plugin-src/host/channels/whatsapp/production.mjs +16 -2
- package/plugin-src/host/channels/whatsapp/rpc.mjs +10 -15
- package/src/channels/dingtalk/dingtalk-bridge.mjs +61 -9
- package/src/channels/dingtalk/dingtalk-runtime.mjs +4 -0
- package/src/channels/discord/discord-runtime.mjs +29 -1
- package/src/channels/feishu/bridge.mjs +188 -80
- package/src/channels/feishu/feishu-runtime.mjs +4 -0
- package/src/channels/qq/qq-bridge.mjs +59 -17
- package/src/channels/qq/qq-runtime.mjs +20 -2
- package/src/channels/shared/access-policy.mjs +210 -0
- package/src/channels/shared/bot-workspace-store.mjs +176 -33
- package/src/channels/shared/command-permission.mjs +32 -0
- package/src/channels/shared/compact-command.mjs +5 -2
- package/src/channels/shared/i18n-en/shared-c.mjs +2 -0
- package/src/channels/shared/inbound-access.mjs +43 -0
- package/src/channels/shared/text-harness-bridge.mjs +47 -4
- package/src/channels/shared/workspace-command.mjs +10 -1
- package/src/channels/slack/slack-runtime.mjs +4 -0
- package/src/channels/telegram/telegram-runtime.mjs +5 -13
- package/src/channels/wecom/wecom-bridge.mjs +51 -4
- package/src/channels/wecom/wecom-runtime.mjs +4 -0
- package/src/channels/weixin/weixin-bridge.mjs +59 -16
- package/src/channels/weixin/weixin-runtime.mjs +4 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +42 -20
|
@@ -4,34 +4,6 @@ const CSS = String.raw`
|
|
|
4
4
|
.dtg-page { --ddt-accent: #229ed9; --ddt-accent-deep: #1687bd; --ddt-accent-wash: #eaf7fd; }
|
|
5
5
|
.dtg-avatar { color: #fff; background: #229ed9; }
|
|
6
6
|
.dtg-avatar svg { display: block; }
|
|
7
|
-
.dtg-access { min-width: 0; width: 100%; max-width: 100%; display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
-
.dtg-accessHeading { position: relative; min-width: 0; max-width: 100%; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; }
|
|
9
|
-
.dtg-accessHeading > strong { min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
|
|
10
|
-
.dtg-accessStatus { min-width: 0; max-width: 100%; flex: 0 1 auto; display: inline-flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }
|
|
11
|
-
.dtg-accessBadge { min-width: 0; max-width: 100%; flex: 0 1 auto; padding: 3px 8px; border-radius: 999px; color: #1687bd; background: #eaf7fd; font-size: 11px; font-weight: 700; overflow-wrap: anywhere; text-align: center; }
|
|
12
|
-
.dtg-accessBadge[data-mode="private-allowlist"] { color: #a15c00; background: #fff3d6; }
|
|
13
|
-
.dtg-accessHelp { position: static; display: inline-flex; flex: none; }
|
|
14
|
-
.dtg-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #229ed9 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1687bd; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
|
|
15
|
-
.dtg-accessHelpButton:hover { border-color: #229ed9; color: #1178a8; background: #eaf7fd; }
|
|
16
|
-
.dtg-accessHelpButton:focus-visible { outline: none; border-color: #229ed9; box-shadow: 0 0 0 3px color-mix(in srgb, #229ed9 18%, transparent); }
|
|
17
|
-
.dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: min(300px, 100%); max-width: 100%; display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
18
|
-
.dtg-accessTooltipItem { display: grid; gap: 2px; }
|
|
19
|
-
.dtg-accessTooltipItem + .dtg-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
|
|
20
|
-
.dtg-accessTooltipItem strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 17px; font-weight: 700; }
|
|
21
|
-
.dtg-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; font-weight: 400; }
|
|
22
|
-
.dtg-accessHelp:hover .dtg-accessTooltip, .dtg-accessHelp:focus-within .dtg-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
23
|
-
.dtg-accessField { min-width: 0; max-width: 100%; display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
24
|
-
.dtg-accessField select, .dtg-accessField textarea { min-width: 0; width: 100%; max-width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
25
|
-
.dtg-accessField select { height: 34px; padding: 0 9px; }
|
|
26
|
-
.dtg-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
27
|
-
.dtg-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
|
|
28
|
-
.dtg-accessField > span, .dtg-accessField small { overflow-wrap: anywhere; }
|
|
29
|
-
.dtg-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
|
|
30
|
-
.dtg-accessWarning, .dtg-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
|
|
31
|
-
.dtg-accessWarning { color: #a15c00; }
|
|
32
|
-
.dtg-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
|
|
33
|
-
.dtg-accessActions { min-width: 0; max-width: 100%; display: flex; justify-content: flex-end; flex-wrap: wrap; }
|
|
34
|
-
.dtg-accessActions .ddt-button { max-width: 100%; white-space: normal; }
|
|
35
7
|
`;
|
|
36
8
|
|
|
37
9
|
export function installTelegramStyles() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WECOM_RPC_CHANNEL = '/wecom';
|
|
@@ -15,6 +16,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|
|
15
16
|
setWorkspace: 'bot.workspace.set',
|
|
16
17
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
17
18
|
setContextEnhancement: 'bot.context-enhancement.set',
|
|
19
|
+
setAccessPolicy: 'bot.access-policy.set',
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
const PROVISION_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting', 'connected', 'failed', 'cancelled']);
|
|
@@ -99,6 +101,9 @@ function normalizeBot(value) {
|
|
|
99
101
|
workspace: text(value.workspace, '', 4_096),
|
|
100
102
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
101
103
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
104
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
105
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
106
|
+
: {}),
|
|
102
107
|
bot: {
|
|
103
108
|
name: text(value.bot?.name, '企业微信机器人', 100),
|
|
104
109
|
appIdMasked: text(value.bot?.appIdMasked, '应用标识已安全保存', 140),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WEIXIN_RPC_CHANNEL = '/weixin';
|
|
@@ -14,6 +15,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
14
15
|
setWorkspace: 'bot.workspace.set',
|
|
15
16
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
16
17
|
setContextEnhancement: 'bot.context-enhancement.set',
|
|
18
|
+
setAccessPolicy: 'bot.access-policy.set',
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
const ACCOUNT_STATES = new Set(['connected', 'connecting', 'offline', 'error']);
|
|
@@ -124,6 +126,9 @@ function normalizeBot(value) {
|
|
|
124
126
|
workspace: string(value.workspace).slice(0, 4_096),
|
|
125
127
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
126
128
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
129
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
130
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
131
|
+
: {}),
|
|
127
132
|
bot: {
|
|
128
133
|
name: string(value.bot.name, '微信机器人'),
|
|
129
134
|
accountIdMasked: string(value.bot.accountIdMasked, '已安全保存'),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WHATSAPP_RPC_CHANNEL = '/whatsapp';
|
|
@@ -91,16 +92,9 @@ function normalizeBot(value) {
|
|
|
91
92
|
workspace: text(value.workspace, '', 4_096),
|
|
92
93
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
93
94
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
94
|
-
accessPolicy
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
) ? value.accessPolicy.accessMode : 'self-only',
|
|
98
|
-
allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers)
|
|
99
|
-
? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => (
|
|
100
|
-
typeof entry === 'string' && /^[1-9]\d{4,14}$/.test(entry)
|
|
101
|
-
)))]
|
|
102
|
-
: [],
|
|
103
|
-
},
|
|
95
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
96
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
97
|
+
: {}),
|
|
104
98
|
bot: {
|
|
105
99
|
name: text(value.bot?.name, 'WhatsApp机器人', 100),
|
|
106
100
|
idMasked: text(value.bot?.idMasked, 'WhatsApp账号', 140),
|
|
@@ -31,119 +31,6 @@ import { installWhatsappStyles } from './styles.js';
|
|
|
31
31
|
|
|
32
32
|
const ACTIVE_STATES = new Set(['pending', 'connecting']);
|
|
33
33
|
|
|
34
|
-
function accessPolicyFor(account) {
|
|
35
|
-
const accessMode = ['self-only', 'private-allowlist', 'open'].includes(
|
|
36
|
-
account?.accessPolicy?.accessMode,
|
|
37
|
-
) ? account.accessPolicy.accessMode : 'self-only';
|
|
38
|
-
return {
|
|
39
|
-
accessMode,
|
|
40
|
-
allowedNumbers: Array.isArray(account?.accessPolicy?.allowedNumbers)
|
|
41
|
-
? account.accessPolicy.allowedNumbers : [],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function allowedNumbersFromText(value) {
|
|
46
|
-
const entries = value.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
|
|
47
|
-
const normalized = entries.map((entry) => entry.replace(/^\+/, ''));
|
|
48
|
-
if (normalized.some((entry) => !/^[1-9]\d{4,14}$/.test(entry))) {
|
|
49
|
-
throw new TypeError('电话号码必须包含国家或地区代码,每行一个。');
|
|
50
|
-
}
|
|
51
|
-
return [...new Set(normalized)];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function WhatsappAccessSettings({ account, busy = false, onSave }) {
|
|
55
|
-
const policy = accessPolicyFor(account);
|
|
56
|
-
const sourceNumbers = policy.allowedNumbers.join('\n');
|
|
57
|
-
const helpId = React.useId();
|
|
58
|
-
const [accessMode, setAccessMode] = React.useState(policy.accessMode);
|
|
59
|
-
const [allowedNumbers, setAllowedNumbers] = React.useState(sourceNumbers);
|
|
60
|
-
const [error, setError] = React.useState(null);
|
|
61
|
-
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
setAccessMode(policy.accessMode);
|
|
64
|
-
setAllowedNumbers(sourceNumbers);
|
|
65
|
-
setError(null);
|
|
66
|
-
}, [policy.accessMode, sourceNumbers]);
|
|
67
|
-
|
|
68
|
-
const save = async (event) => {
|
|
69
|
-
event.preventDefault();
|
|
70
|
-
setError(null);
|
|
71
|
-
try {
|
|
72
|
-
const normalized = allowedNumbersFromText(allowedNumbers);
|
|
73
|
-
if (typeof onSave !== 'function') throw new Error('WhatsApp 访问设置暂不可用。');
|
|
74
|
-
await onSave({ accessMode, allowedNumbers: normalized });
|
|
75
|
-
} catch (caught) {
|
|
76
|
-
setError(caught?.message ?? 'WhatsApp 访问设置保存失败。');
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const allowlistEnabled = accessMode === 'private-allowlist';
|
|
81
|
-
const labels = {
|
|
82
|
-
'self-only': '仅自己模式',
|
|
83
|
-
'private-allowlist': '指定联系人模式',
|
|
84
|
-
open: '开放响应模式',
|
|
85
|
-
};
|
|
86
|
-
return h('form', { className: 'dwa-access', onSubmit: save },
|
|
87
|
-
h('div', { className: 'dwa-accessHeading' },
|
|
88
|
-
h('strong', null, '访问设置'),
|
|
89
|
-
h('span', { className: 'dwa-accessStatus' },
|
|
90
|
-
h('span', { className: 'dwa-accessBadge', 'data-mode': policy.accessMode },
|
|
91
|
-
['已生效:', labels[policy.accessMode]]),
|
|
92
|
-
h('span', { className: 'dwa-accessHelp' },
|
|
93
|
-
h('button', {
|
|
94
|
-
type: 'button',
|
|
95
|
-
className: 'dwa-accessHelpButton',
|
|
96
|
-
'aria-label': '查看 WhatsApp 访问模式说明',
|
|
97
|
-
'aria-describedby': helpId,
|
|
98
|
-
}, h('span', { 'aria-hidden': 'true' }, '?')),
|
|
99
|
-
h('span', { id: helpId, className: 'dwa-accessTooltip', role: 'tooltip' },
|
|
100
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
101
|
-
h('strong', null, '仅自己模式'),
|
|
102
|
-
h('span', null, '只响应已绑定 WhatsApp 账号的自聊消息。')),
|
|
103
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
104
|
-
h('strong', null, '指定联系人模式'),
|
|
105
|
-
h('span', null, '响应自聊和白名单联系人的私聊,忽略群聊。')),
|
|
106
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
107
|
-
h('strong', null, '开放响应模式'),
|
|
108
|
-
h('span', null, '响应所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员的提及或回复。')))))),
|
|
109
|
-
h('label', { className: 'dwa-accessField' },
|
|
110
|
-
h('span', null, '模式'),
|
|
111
|
-
h('select', {
|
|
112
|
-
value: accessMode,
|
|
113
|
-
disabled: busy,
|
|
114
|
-
'aria-label': 'WhatsApp 访问模式',
|
|
115
|
-
onChange: (event) => { setAccessMode(event.target.value); setError(null); },
|
|
116
|
-
},
|
|
117
|
-
h('option', { value: 'self-only' }, '仅自己模式(默认)'),
|
|
118
|
-
h('option', { value: 'private-allowlist' }, '指定联系人模式'),
|
|
119
|
-
h('option', { value: 'open' }, '开放响应模式'))),
|
|
120
|
-
allowlistEnabled
|
|
121
|
-
? h('label', { className: 'dwa-accessField' },
|
|
122
|
-
h('span', null, '允许私聊的 WhatsApp 电话号码'),
|
|
123
|
-
h('textarea', {
|
|
124
|
-
value: allowedNumbers,
|
|
125
|
-
disabled: busy,
|
|
126
|
-
rows: 3,
|
|
127
|
-
placeholder: '每行一个含国家或地区代码的号码',
|
|
128
|
-
'aria-label': '允许私聊的 WhatsApp 电话号码',
|
|
129
|
-
onChange: (event) => { setAllowedNumbers(event.target.value); setError(null); },
|
|
130
|
-
}),
|
|
131
|
-
h('small', null, '可以包含开头的 +,保存时会自动移除。'))
|
|
132
|
-
: null,
|
|
133
|
-
allowlistEnabled && allowedNumbers.trim() === ''
|
|
134
|
-
? h('p', { className: 'dwa-accessWarning', role: 'status' },
|
|
135
|
-
'白名单为空;保存后将只接受自聊消息。')
|
|
136
|
-
: null,
|
|
137
|
-
error ? h('p', { className: 'dwa-accessError', role: 'alert' }, error) : null,
|
|
138
|
-
h('div', { className: 'dwa-accessActions' },
|
|
139
|
-
h('button', {
|
|
140
|
-
type: 'submit',
|
|
141
|
-
className: 'ddt-button',
|
|
142
|
-
'data-kind': 'secondary',
|
|
143
|
-
disabled: busy,
|
|
144
|
-
}, busy ? '正在保存…' : '保存访问设置')));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
34
|
const Button = React.forwardRef(function Button(
|
|
148
35
|
{ children, kind = 'secondary', className = '', ...props },
|
|
149
36
|
ref,
|
|
@@ -300,7 +187,6 @@ export function WhatsappAccountCard({
|
|
|
300
187
|
onWorkspaceSave,
|
|
301
188
|
onAgentPresetSave,
|
|
302
189
|
onContextEnhancementSave,
|
|
303
|
-
onAccessPolicySave,
|
|
304
190
|
onRequestRemove,
|
|
305
191
|
onConfirmRemove,
|
|
306
192
|
onCancelRemove,
|
|
@@ -333,6 +219,7 @@ export function WhatsappAccountCard({
|
|
|
333
219
|
botId: account.botId,
|
|
334
220
|
botName: account.bot.name,
|
|
335
221
|
connected: account.connected,
|
|
222
|
+
accessPolicy: account.accessPolicy,
|
|
336
223
|
}))),
|
|
337
224
|
h(WorkspaceEditor, {
|
|
338
225
|
workspace: account.workspace,
|
|
@@ -349,11 +236,6 @@ export function WhatsappAccountCard({
|
|
|
349
236
|
disabled: Boolean(busy),
|
|
350
237
|
onSave: onContextEnhancementSave,
|
|
351
238
|
}),
|
|
352
|
-
h(WhatsappAccessSettings, {
|
|
353
|
-
account,
|
|
354
|
-
busy: Boolean(busy),
|
|
355
|
-
onSave: onAccessPolicySave,
|
|
356
|
-
}),
|
|
357
239
|
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
|
358
240
|
h('div', { className: 'dim-cardFooterLayout' },
|
|
359
241
|
h('div', { className: 'ddt-actions dim-cardActions' },
|
|
@@ -617,12 +499,6 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
617
499
|
WHATSAPP_ENDPOINTS.setContextEnhancement,
|
|
618
500
|
{ botId: account.botId, config },
|
|
619
501
|
),
|
|
620
|
-
onAccessPolicySave: (accessPolicy) => botAction(
|
|
621
|
-
account,
|
|
622
|
-
'access',
|
|
623
|
-
WHATSAPP_ENDPOINTS.setAccessPolicy,
|
|
624
|
-
{ botId: account.botId, ...accessPolicy },
|
|
625
|
-
),
|
|
626
502
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
627
503
|
onCancelRemove: () => setRemoveTarget(null),
|
|
628
504
|
onConfirmRemove: async () => {
|
|
@@ -4,31 +4,6 @@ const CSS = String.raw`
|
|
|
4
4
|
.dwa-page { --ddt-accent: #25d366; --ddt-accent-deep: #128c7e; --ddt-accent-wash: #eafbf0; }
|
|
5
5
|
.dwa-avatar { color: #fff; background: #25d366; }
|
|
6
6
|
.dwa-avatar svg { display: block; }
|
|
7
|
-
.dwa-access { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
-
.dwa-accessHeading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
9
|
-
.dwa-accessHeading > strong { font-size: 13px; }
|
|
10
|
-
.dwa-accessStatus { min-width: 0; display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }
|
|
11
|
-
.dwa-accessBadge { flex: none; padding: 3px 8px; border-radius: 999px; color: #08785f; background: #eafbf0; font-size: 11px; font-weight: 700; }
|
|
12
|
-
.dwa-accessBadge[data-mode="private-allowlist"] { color: #0f6f8f; background: #eaf7fd; }
|
|
13
|
-
.dwa-accessBadge[data-mode="open"] { color: #a15c00; background: #fff3d6; }
|
|
14
|
-
.dwa-accessHelp { position: relative; display: inline-flex; flex: none; }
|
|
15
|
-
.dwa-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #25d366 34%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #128c7e; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; }
|
|
16
|
-
.dwa-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: 270px; max-width: min(290px, calc(100vw - 48px)); display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
17
|
-
.dwa-accessTooltipItem { display: grid; gap: 2px; }
|
|
18
|
-
.dwa-accessTooltipItem + .dwa-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
|
|
19
|
-
.dwa-accessTooltipItem strong { font-size: 12px; line-height: 17px; }
|
|
20
|
-
.dwa-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
|
|
21
|
-
.dwa-accessHelp:hover .dwa-accessTooltip, .dwa-accessHelp:focus-within .dwa-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
22
|
-
.dwa-accessField { display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
23
|
-
.dwa-accessField select, .dwa-accessField textarea { width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
24
|
-
.dwa-accessField select { height: 34px; padding: 0 9px; }
|
|
25
|
-
.dwa-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
26
|
-
.dwa-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
|
|
27
|
-
.dwa-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
|
|
28
|
-
.dwa-accessWarning, .dwa-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
|
|
29
|
-
.dwa-accessWarning { color: #a15c00; }
|
|
30
|
-
.dwa-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
|
|
31
|
-
.dwa-accessActions { display: flex; justify-content: flex-end; }
|
|
32
7
|
`;
|
|
33
8
|
|
|
34
9
|
export function installWhatsappStyles() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { AccessPolicySettingsPage } from './access-policy-settings.js';
|
|
3
4
|
import { h, isEnglish, localizeText } from './i18n.js';
|
|
4
5
|
|
|
5
6
|
export const DELIVERY_RPC_CHANNEL = '/dsh-im-delivery';
|
|
@@ -18,6 +19,11 @@ export const DELIVERY_ENDPOINTS = Object.freeze({
|
|
|
18
19
|
test: 'target.test',
|
|
19
20
|
});
|
|
20
21
|
|
|
22
|
+
export const BOT_SETTINGS_TABS = Object.freeze([
|
|
23
|
+
Object.freeze({ id: 'delivery', label: '投递设置' }),
|
|
24
|
+
Object.freeze({ id: 'access', label: '访问设置' }),
|
|
25
|
+
]);
|
|
26
|
+
|
|
21
27
|
const CHANNEL_DEFINITIONS = Object.freeze({
|
|
22
28
|
weixin: {
|
|
23
29
|
label: '微信',
|
|
@@ -532,8 +538,15 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
|
|
|
532
538
|
: null);
|
|
533
539
|
}
|
|
534
540
|
|
|
535
|
-
export function DeliveryTargetSettingsPage({
|
|
541
|
+
export function DeliveryTargetSettingsPage({
|
|
542
|
+
channel,
|
|
543
|
+
account,
|
|
544
|
+
rpcCall,
|
|
545
|
+
accessRpcCall,
|
|
546
|
+
onBack,
|
|
547
|
+
}) {
|
|
536
548
|
const definition = CHANNEL_DEFINITIONS[channel];
|
|
549
|
+
const [activeTabId, setActiveTabId] = React.useState(BOT_SETTINGS_TABS[0].id);
|
|
537
550
|
const [phase, setPhase] = React.useState('loading');
|
|
538
551
|
const [targets, setTargets] = React.useState([]);
|
|
539
552
|
const [suggestionPhase, setSuggestionPhase] = React.useState('idle');
|
|
@@ -543,8 +556,13 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
543
556
|
const [editor, setEditor] = React.useState(null);
|
|
544
557
|
const [saving, setSaving] = React.useState(false);
|
|
545
558
|
const [botCopyState, setBotCopyState] = React.useState(null);
|
|
559
|
+
const [accessPolicy, setAccessPolicy] = React.useState(account.accessPolicy);
|
|
546
560
|
const mounted = React.useRef(true);
|
|
547
561
|
|
|
562
|
+
React.useEffect(() => {
|
|
563
|
+
setAccessPolicy(account.accessPolicy);
|
|
564
|
+
}, [account.botId, account.accessPolicy]);
|
|
565
|
+
|
|
548
566
|
const invoke = React.useCallback(async (endpoint, payload = {}, signal) => {
|
|
549
567
|
if (typeof rpcCall !== 'function') throw new Error('投递目标设置暂不可用。');
|
|
550
568
|
return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
|
|
@@ -654,13 +672,51 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
654
672
|
}
|
|
655
673
|
};
|
|
656
674
|
|
|
675
|
+
const activeTab = BOT_SETTINGS_TABS.find((tab) => tab.id === activeTabId)
|
|
676
|
+
?? BOT_SETTINGS_TABS[0];
|
|
677
|
+
const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
|
|
678
|
+
const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
|
|
679
|
+
|
|
657
680
|
return h('section', {
|
|
658
681
|
className: 'dim-deliveryPage',
|
|
659
682
|
'aria-label': `${account.botName || definition.label}机器人设置`,
|
|
660
683
|
},
|
|
661
684
|
h('header', { className: 'dim-deliveryHeader' },
|
|
662
|
-
h(DeliveryButton, { className: 'dim-deliveryBack', onClick: onBack }, '← 返回机器人列表'),
|
|
663
|
-
|
|
685
|
+
h(DeliveryButton, { className: 'dim-deliveryBack', onClick: onBack }, '← 返回机器人列表')),
|
|
686
|
+
h('div', { className: 'dim-botSettingsTabsBar' },
|
|
687
|
+
h('nav', {
|
|
688
|
+
className: 'dim-botSettingsTabs',
|
|
689
|
+
role: 'tablist',
|
|
690
|
+
'aria-label': '机器人设置页签',
|
|
691
|
+
}, BOT_SETTINGS_TABS.map((tab) => h('button', {
|
|
692
|
+
key: tab.id,
|
|
693
|
+
id: `dim-bot-settings-${tab.id}-tab`,
|
|
694
|
+
type: 'button',
|
|
695
|
+
role: 'tab',
|
|
696
|
+
className: 'dim-botSettingsTab',
|
|
697
|
+
'aria-selected': tab.id === activeTab.id,
|
|
698
|
+
'aria-controls': `dim-bot-settings-${tab.id}-panel`,
|
|
699
|
+
tabIndex: tab.id === activeTab.id ? 0 : -1,
|
|
700
|
+
onClick: () => setActiveTabId(tab.id),
|
|
701
|
+
}, tab.label)))),
|
|
702
|
+
h('div', {
|
|
703
|
+
id: activePanelId,
|
|
704
|
+
className: 'dim-botSettingsTabPanel',
|
|
705
|
+
role: 'tabpanel',
|
|
706
|
+
'aria-labelledby': activeTabDomId,
|
|
707
|
+
},
|
|
708
|
+
activeTab.id === 'access'
|
|
709
|
+
? h(AccessPolicySettingsPage, {
|
|
710
|
+
channel,
|
|
711
|
+
account: { ...account, accessPolicy },
|
|
712
|
+
rpcCall: accessRpcCall,
|
|
713
|
+
onSaved: setAccessPolicy,
|
|
714
|
+
})
|
|
715
|
+
: h(React.Fragment, null,
|
|
716
|
+
h('section', { className: 'dim-deliveryIdentity', 'aria-labelledby': 'dim-delivery-bot-title' },
|
|
717
|
+
h('div', { className: 'dim-deliveryIdentityHeading' },
|
|
718
|
+
h('h2', { id: 'dim-delivery-bot-title', className: 'dim-deliveryBotName' },
|
|
719
|
+
account.botName || '机器人设置'),
|
|
664
720
|
h('a', {
|
|
665
721
|
className: 'dim-deliveryDocsLink',
|
|
666
722
|
href: isEnglish() ? DELIVERY_DOCS_URL.en : DELIVERY_DOCS_URL.zh,
|
|
@@ -669,11 +725,7 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
669
725
|
'aria-label': '打开主动投递使用文档',
|
|
670
726
|
},
|
|
671
727
|
h('span', null, '使用文档'),
|
|
672
|
-
h('span', { 'aria-hidden': 'true' }, '↗')))
|
|
673
|
-
h('section', { className: 'dim-deliveryIdentity', 'aria-labelledby': 'dim-delivery-bot-title' },
|
|
674
|
-
h('div', null,
|
|
675
|
-
h('h2', { id: 'dim-delivery-bot-title', className: 'dim-deliveryBotName' },
|
|
676
|
-
account.botName || '机器人设置')),
|
|
728
|
+
h('span', { 'aria-hidden': 'true' }, '↗'))),
|
|
677
729
|
h('div', { className: 'dim-deliveryBotId' },
|
|
678
730
|
h('span', null, 'Bot ID'),
|
|
679
731
|
h('code', { title: account.botId }, account.botId),
|
|
@@ -745,5 +797,5 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
745
797
|
rpcCall: invoke,
|
|
746
798
|
onChanged: () => loadTargets({ silent: true }),
|
|
747
799
|
onEdit: () => setEditor({ mode: 'edit', target, source: 'edit' }),
|
|
748
|
-
})))));
|
|
800
|
+
})))))));
|
|
749
801
|
}
|
|
@@ -7,6 +7,62 @@ const EN = Object.freeze({
|
|
|
7
7
|
'IM机器人': 'IM bots',
|
|
8
8
|
'IM机器人设置': 'IM bot settings',
|
|
9
9
|
'更多机器人设置': 'More bot settings',
|
|
10
|
+
'机器人设置': 'Bot settings',
|
|
11
|
+
'机器人设置页签': 'Bot settings tabs',
|
|
12
|
+
'投递设置': 'Delivery settings',
|
|
13
|
+
'访问设置': 'Access settings',
|
|
14
|
+
'查看访问权限说明': 'View access permission details',
|
|
15
|
+
'允许所有用户': 'Allow all users',
|
|
16
|
+
'仅白名单用户': 'Allowlisted users only',
|
|
17
|
+
'默认命令权限': 'Default command permission',
|
|
18
|
+
'命令权限': 'Command permission',
|
|
19
|
+
'可以执行命令': 'Can run commands',
|
|
20
|
+
'不可以执行命令': 'Cannot run commands',
|
|
21
|
+
'白名单用户': 'Allowlisted users',
|
|
22
|
+
'查看白名单说明': 'View allowlist details',
|
|
23
|
+
'命令权限例外': 'Command permission exceptions',
|
|
24
|
+
'当前没有白名单用户,保存后普通用户将无法使用机器人。': 'There are currently no allowlisted users. After saving, regular users will not be able to use the bot.',
|
|
25
|
+
'新增用户': 'Add user',
|
|
26
|
+
'尚未添加用户': 'No users added',
|
|
27
|
+
'当前渠道不支持群聊': 'Group chat is not supported by this channel',
|
|
28
|
+
'原所有者或扫码接入者始终可以访问并执行命令;以下设置仅约束其他用户。': 'The original owner or QR-code operator can always access the bot and run commands; the settings below apply only to other users.',
|
|
29
|
+
'此区域无需配置,保存私聊设置时会保留现有群聊策略。': 'No setup is needed here. Saving direct-message settings keeps the existing group policy.',
|
|
30
|
+
'访问设置已保存。': 'Access settings saved.',
|
|
31
|
+
'访问设置暂不可用。': 'Access settings are currently unavailable.',
|
|
32
|
+
'访问设置保存失败,请稍后重试。': 'Could not save access settings. Try again later.',
|
|
33
|
+
'服务没有返回已保存的访问策略,请刷新后重试。': 'The service did not return the saved access policy. Refresh and try again.',
|
|
34
|
+
'访问策略尚未就绪,请返回机器人列表刷新后重试。': 'The access policy is not ready. Return to the bot list, refresh, and try again.',
|
|
35
|
+
'当前渠道暂不支持访问设置。': 'Access settings are not supported by this channel yet.',
|
|
36
|
+
'用户标识无效。': 'The user ID is invalid.',
|
|
37
|
+
'用户标识必须是字符串。': 'The user ID must be a string.',
|
|
38
|
+
'用户标识不能为空、包含控制字符或超过 256 个字符。': 'The user ID cannot be empty, contain control characters, or exceed 256 characters.',
|
|
39
|
+
'用户条目必须包含用户标识和命令权限。': 'Each user entry must include a user ID and command permission.',
|
|
40
|
+
'命令权限必须是布尔值。': 'Command permission must be a boolean.',
|
|
41
|
+
'访问模式只能是 open 或 allowlist。': 'Access mode must be open or allowlist.',
|
|
42
|
+
'开放模式设置必须完整。': 'Open-mode settings must be complete.',
|
|
43
|
+
'开放模式默认命令权限必须是布尔值。': 'The open-mode default command permission must be a boolean.',
|
|
44
|
+
'开放模式命令权限覆盖用户必须是数组。': 'Open-mode command permission overrides must be an array.',
|
|
45
|
+
'开放模式命令权限覆盖用户不能包含重复的用户标识。': 'Open-mode command permission overrides cannot contain duplicate user IDs.',
|
|
46
|
+
'白名单模式设置必须完整。': 'Allowlist-mode settings must be complete.',
|
|
47
|
+
'白名单模式用户必须是数组。': 'Allowlist-mode users must be an array.',
|
|
48
|
+
'白名单模式用户不能包含重复的用户标识。': 'Allowlist-mode users cannot contain duplicate user IDs.',
|
|
49
|
+
'访问场景设置必须同时包含模式、开放模式设置和白名单模式设置。': 'Each access context must include its mode, open-mode settings, and allowlist-mode settings.',
|
|
50
|
+
'请同时提交完整的私聊和群聊访问设置。': 'Submit complete direct-message and group access settings together.',
|
|
51
|
+
'填写微信用户 ID': 'Enter a WeChat user ID',
|
|
52
|
+
'飞书 Open ID': 'Feishu Open ID',
|
|
53
|
+
'群成员 Open ID': 'Group member Open ID',
|
|
54
|
+
'钉钉用户 ID': 'DingTalk user ID',
|
|
55
|
+
'填写 senderStaffId 或 senderId': 'Enter senderStaffId or senderId',
|
|
56
|
+
'群成员用户 ID': 'Group member user ID',
|
|
57
|
+
'企业微信用户 ID': 'WeCom user ID',
|
|
58
|
+
'填写 userid': 'Enter userid',
|
|
59
|
+
'填写 member_openid': 'Enter member_openid',
|
|
60
|
+
'QQ User Open ID': 'QQ User Open ID',
|
|
61
|
+
'群成员 User ID': 'Group member User ID',
|
|
62
|
+
'填写数字 User ID': 'Enter a numeric user ID',
|
|
63
|
+
'WhatsApp 电话号码或 JID': 'WhatsApp phone number or JID',
|
|
64
|
+
'群成员电话号码或 JID': 'Group member phone number or JID',
|
|
65
|
+
'8613800000000 或完整 JID': '8613800000000 or a full JID',
|
|
10
66
|
'IM 渠道': 'IM channels',
|
|
11
67
|
'让 DeepSeek Harness 触手可及': 'Connecting DeepSeek Harness',
|
|
12
68
|
'当前版本': 'Current version',
|
|
@@ -521,7 +577,6 @@ const EN = Object.freeze({
|
|
|
521
577
|
'先通过 @BotFather 获取 Bot Token,再在这里完成接入。': 'Get a Bot Token from @BotFather, then connect it here.',
|
|
522
578
|
'填写 @BotFather 生成的 Bot Token': 'Enter the Bot Token from @BotFather',
|
|
523
579
|
'访问模式': 'Access mode',
|
|
524
|
-
'访问设置': 'Access settings',
|
|
525
580
|
'Telegram 访问模式': 'Telegram access mode',
|
|
526
581
|
'查看 Telegram 访问模式说明': 'View Telegram access mode details',
|
|
527
582
|
'群聊全部忽略,私聊仅允许白名单用户。': 'All group messages are ignored; only allowlisted users may send DMs.',
|
|
@@ -294,6 +294,7 @@ export function IMSettingsTab({
|
|
|
294
294
|
channel: active.id,
|
|
295
295
|
account: deliverySettings,
|
|
296
296
|
rpcCall: rpcCalls.deliveryRpcCall,
|
|
297
|
+
accessRpcCall: rpcCalls[`${active.id}RpcCall`],
|
|
297
298
|
onBack: () => setDeliverySettings(null),
|
|
298
299
|
})
|
|
299
300
|
: active.id === 'weixin'
|
|
@@ -369,9 +369,18 @@ const CSS = String.raw`
|
|
|
369
369
|
.dim-botSettingsButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
370
370
|
.dim-botSettingsTooltip { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: max-content; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
371
371
|
.dim-botSettingsAction:hover .dim-botSettingsTooltip, .dim-botSettingsAction:focus-within .dim-botSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
372
|
-
.dim-deliveryPage { min-width: 0; display: grid;
|
|
372
|
+
.dim-deliveryPage { min-width: 0; display: grid; }
|
|
373
373
|
.dim-deliveryHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
|
|
374
|
-
.dim-
|
|
374
|
+
.dim-botSettingsTabsBar { min-width: 0; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
|
|
375
|
+
.dim-botSettingsTabs { min-width: 0; display: flex; align-items: flex-end; gap: 24px; overflow-x: auto; scrollbar-width: none; }
|
|
376
|
+
.dim-botSettingsTabs::-webkit-scrollbar { display: none; }
|
|
377
|
+
.dim-botSettingsTab { position: relative; min-height: 38px; flex: none; display: inline-flex; align-items: center; justify-content: center; padding: 6px 2px 9px; border: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 13px; line-height: 20px; font-weight: 560; white-space: nowrap; cursor: pointer; transition: color .15s ease; }
|
|
378
|
+
.dim-botSettingsTab::after { content: ''; position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: transparent; transform: scaleX(.45); transition: background .15s ease, transform .15s ease; }
|
|
379
|
+
.dim-botSettingsTab:hover:not([aria-selected="true"]) { color: var(--dsw-alias-label-primary, #1f2329); }
|
|
380
|
+
.dim-botSettingsTab[aria-selected="true"] { color: var(--dsw-alias-state-business-primary, #3370ff); font-weight: 650; }
|
|
381
|
+
.dim-botSettingsTab[aria-selected="true"]::after { background: var(--dsw-alias-state-business-primary, #3370ff); transform: scaleX(1); }
|
|
382
|
+
.dim-botSettingsTab:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: -2px; border-radius: 5px; }
|
|
383
|
+
.dim-botSettingsTabPanel { min-width: 0; display: grid; gap: 14px; padding-top: 14px; }
|
|
375
384
|
.dim-deliveryDocsLink { min-height: 30px; flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 5px 8px; border-radius: 7px; color: var(--dsw-alias-state-business-primary, #3370ff); font-size: 12px; line-height: 18px; text-decoration: none; white-space: nowrap; }
|
|
376
385
|
.dim-deliveryDocsLink:hover { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, transparent); }
|
|
377
386
|
.dim-deliveryDocsLink:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
@@ -383,6 +392,7 @@ const CSS = String.raw`
|
|
|
383
392
|
.dim-deliveryButton[data-kind="danger"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
384
393
|
.dim-deliveryBack { flex: none; border-color: transparent; background: transparent; }
|
|
385
394
|
.dim-deliveryIdentity, .dim-deliveryTargets { min-width: 0; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
|
|
395
|
+
.dim-deliveryIdentityHeading { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
386
396
|
.dim-deliveryBotName, .dim-deliverySectionHeading h3 { min-width: 0; overflow: hidden; margin: 0; font-size: 15px; line-height: 22px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
|
|
387
397
|
.dim-deliveryIdentity > div:first-child p, .dim-deliverySectionHeading p { margin: 2px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; }
|
|
388
398
|
.dim-deliveryBotId { min-width: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; align-items: center; gap: 10px; margin-top: 12px; padding: 10px 12px; border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
@@ -425,6 +435,38 @@ const CSS = String.raw`
|
|
|
425
435
|
.dim-targetField input[readonly] { color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
426
436
|
.dim-targetFormError { margin: 10px 0 0; font-size: 12px; line-height: 18px; }
|
|
427
437
|
.dim-targetFormActions { display: flex; justify-content: flex-end; gap: 7px; margin-top: 12px; }
|
|
438
|
+
.dim-accessPage { min-width: 0; display: grid; gap: 14px; }
|
|
439
|
+
.dim-accessScene { position: relative; min-width: 0; margin: 0; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
|
|
440
|
+
.dim-accessScene > legend { padding: 0 6px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; line-height: 22px; font-weight: 650; }
|
|
441
|
+
.dim-accessLegendContent { display: inline-flex; align-items: center; gap: 6px; }
|
|
442
|
+
.dim-panel .dim-accessLegendHelp { position: static; }
|
|
443
|
+
.dim-accessLegendHelp .dim-channelTooltip { top: 20px; right: auto; left: 16px; width: min(320px, calc(100% - 32px)); max-width: none; }
|
|
444
|
+
.dim-accessControls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
445
|
+
.dim-accessControls[data-mode="allowlist"] { grid-template-columns: minmax(0, 1fr); }
|
|
446
|
+
.dim-accessField { min-width: 0; display: grid; align-content: start; gap: 5px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
|
|
447
|
+
.dim-accessField input, .dim-accessField select { width: 100%; min-width: 0; height: 36px; padding: 0 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; }
|
|
448
|
+
.dim-accessField input:focus, .dim-accessField select:focus { outline: 2px solid color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 28%, transparent); border-color: var(--dsw-alias-state-business-primary, #3370ff); }
|
|
449
|
+
.dim-accessUsers { min-width: 0; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
|
|
450
|
+
.dim-accessUsersHeading { position: relative; min-width: 0; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
451
|
+
.dim-accessUsersHeading > div { min-width: 0; }
|
|
452
|
+
.dim-accessUsersTitle { display: inline-flex; align-items: center; gap: 6px; }
|
|
453
|
+
.dim-accessUsersHeading strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; line-height: 20px; font-weight: 620; }
|
|
454
|
+
.dim-accessUsersHeading p { margin: 2px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
|
|
455
|
+
.dim-panel .dim-accessUsersHelp { position: static; }
|
|
456
|
+
.dim-accessUsersHelp .dim-channelTooltip { top: calc(100% + 7px); right: auto; left: 0; width: min(320px, 100%); max-width: none; }
|
|
457
|
+
.dim-accessAddUser { width: 32px; height: 32px; min-height: 32px; flex: 0 0 32px; padding: 0; font-size: 20px; line-height: 1; }
|
|
458
|
+
.dim-accessUsersEmpty { margin-top: 10px; padding: 15px 12px; border: 1px dashed var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; line-height: 18px; text-align: center; }
|
|
459
|
+
.dim-accessUserList { display: grid; gap: 9px; margin: 10px 0 0; padding: 0; list-style: none; }
|
|
460
|
+
.dim-accessUserRow { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(145px, 180px) max-content; align-items: end; gap: 10px; padding: 11px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
461
|
+
.dim-accessDeleteUser { margin-bottom: 1px; }
|
|
462
|
+
.dim-accessUnsupported { padding: 18px 14px; border: 1px dashed var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); text-align: center; }
|
|
463
|
+
.dim-accessUnsupported strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; line-height: 20px; }
|
|
464
|
+
.dim-accessUnsupported p { margin: 4px 0 0; font-size: 12px; line-height: 18px; }
|
|
465
|
+
.dim-accessState { padding: 11px 13px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 24%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 9px; color: var(--dsw-alias-state-warn-primary, #d97706); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 7%, var(--dsw-alias-bg-layer-1, #fff)); font-size: 12px; line-height: 18px; }
|
|
466
|
+
.dim-accessFeedback { margin: 0; padding: 10px 12px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font-size: 12px; line-height: 18px; }
|
|
467
|
+
.dim-accessFeedback[data-tone="success"] { color: var(--dsw-alias-state-success-primary, #20a162); }
|
|
468
|
+
.dim-accessFeedback[data-tone="error"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
469
|
+
.dim-accessActions { display: flex; justify-content: flex-end; }
|
|
428
470
|
.dim-panel .dim-botCard .dim-cardFooter { margin-top: 0; }
|
|
429
471
|
.dim-panel .ddt-headingCopy { display: none; }
|
|
430
472
|
.dim-panel .ddt-qrFrame, .dim-panel .ddt-countdown { width: min(270px, 100%); }
|
|
@@ -448,6 +490,9 @@ const CSS = String.raw`
|
|
|
448
490
|
.dim-targetActions { justify-content: flex-start; }
|
|
449
491
|
.dim-targetFormGrid { grid-template-columns: minmax(0, 1fr); }
|
|
450
492
|
.dim-targetSuggestionHeading { align-items: stretch; flex-direction: column; }
|
|
493
|
+
.dim-accessControls { grid-template-columns: minmax(0, 1fr); }
|
|
494
|
+
.dim-accessUserRow { grid-template-columns: minmax(0, 1fr); }
|
|
495
|
+
.dim-accessDeleteUser { justify-self: start; }
|
|
451
496
|
}
|
|
452
497
|
@media (max-width: 840px) {
|
|
453
498
|
.dim-title { align-items: flex-start; }
|
|
@@ -471,11 +516,12 @@ const CSS = String.raw`
|
|
|
471
516
|
.dim-rail { grid-template-columns: minmax(0, 1fr); }
|
|
472
517
|
.dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; }
|
|
473
518
|
.dim-loopbackRecoveryAction { width: 100%; }
|
|
474
|
-
.dim-
|
|
475
|
-
.dim-
|
|
519
|
+
.dim-deliverySectionHeading { align-items: stretch; flex-direction: column; }
|
|
520
|
+
.dim-botSettingsTabs { gap: 18px; }
|
|
476
521
|
.dim-deliveryBotId { grid-template-columns: minmax(0, 1fr) max-content; }
|
|
477
522
|
.dim-deliveryBotId > span { grid-column: 1 / -1; }
|
|
478
523
|
.dim-targetActions .dim-deliveryButton { flex: 1 1 auto; }
|
|
524
|
+
.dim-accessActions .dim-deliveryButton { width: 100%; }
|
|
479
525
|
.dim-directoryPickerBackdrop { padding: 10px; }
|
|
480
526
|
.dim-directoryPicker { height: calc(100vh - 20px); min-height: 0; border-radius: 14px; }
|
|
481
527
|
.dim-directoryPickerHeader { padding: 18px 17px 14px; }
|