@agentaily/design-system 0.5.0 → 0.7.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.
@@ -0,0 +1,271 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { HelpSteps } from "./HelpSteps.js";
4
+ import { Icon } from "../utilities/Icon.js";
5
+ import { SecretField } from "../inputs/SecretField.js";
6
+ import { StatusPill } from "../display/StatusPill.js";
7
+ import { TestRow } from "./TestRow.js";
8
+ const AX_FEISHUCARD_CSS = `
9
+ .s-detect { display: flex; flex-direction: column; gap: 9px; padding: 13px 14px; border: 1px solid var(--border-default);
10
+ border-radius: var(--radius-2); background: var(--surface-page); }
11
+ .s-detect__row { display: flex; align-items: center; gap: 10px; }
12
+ .s-detect__k { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label); text-transform: uppercase;
13
+ color: var(--text-faint); width: 84px; flex: none; }
14
+ .s-detect__v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); word-break: break-all; flex: 1; }
15
+ .s-detect__ok { color: var(--ok); display: flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10px;
16
+ letter-spacing: var(--tracking-label); text-transform: uppercase; flex: none; }
17
+ .s-map { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }
18
+ .s-map th { text-align: left; font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label);
19
+ text-transform: uppercase; color: var(--text-faint); font-weight: 500; padding: 0 0 8px; }
20
+ .s-map td { padding: 7px 0; border-top: 1px solid var(--border-default); color: var(--text-body); vertical-align: middle; }
21
+ .s-map__from { color: var(--text-muted); }
22
+ .s-map__arrow { width: 36px; color: var(--text-faint); }
23
+ .s-map__col { font-family: var(--font-mono); }
24
+ .s-map__tag { font-family: var(--font-mono); font-size: 9px; letter-spacing: var(--tracking-label); text-transform: uppercase;
25
+ color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; margin-left: 7px; }
26
+ .s-sub { display: flex; align-items: center; gap: 8px; }
27
+ .s-sub__line { flex: 1; height: 1px; background: var(--border-default); }
28
+ `;
29
+ const AX_CONNCARD_CSS_FS = `
30
+ .s-card { position: relative; background: var(--surface-card); border: 1px solid var(--border-default);
31
+ border-radius: var(--radius-3); overflow: hidden; transition: border-color var(--dur-2) var(--ease-out); }
32
+ .s-card.is-ok { border-color: rgba(62, 207, 142, 0.4); }
33
+ .s-card.is-error { border-color: rgba(229, 72, 77, 0.4); }
34
+ .s-card__head { padding: 20px 24px 18px; }
35
+ .s-card__toprow { display: flex; align-items: center; gap: 11px; margin-bottom: 15px; }
36
+ .s-card__icon { flex: none; width: 30px; height: 30px; border-radius: var(--radius-2);
37
+ border: 1px solid var(--border-strong); background: var(--surface-raised); color: var(--text-body);
38
+ display: flex; align-items: center; justify-content: center; }
39
+ .s-card__eyebrow { color: var(--text-faint); }
40
+ .s-card__status { margin-left: auto; flex: none; }
41
+ .s-card__title { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 500;
42
+ letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--text-body); margin: 0; }
43
+ .s-card__desc { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); margin: 9px 0 0; max-width: 58ch; }
44
+ .s-card__body { padding: 4px 24px 22px; display: flex; flex-direction: column; gap: 18px; }
45
+ .s-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
46
+ @media (max-width: 560px) { .s-row2 { grid-template-columns: 1fr; } }
47
+ .s-lock { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); }
48
+ .s-lock svg { flex: none; margin-top: 1px; color: var(--text-muted); }
49
+ .s-lock strong { color: var(--text-muted); font-weight: 500; }
50
+ `;
51
+ function fs_injectCss(id, css) {
52
+ if (typeof document === "undefined" || document.getElementById(id)) return;
53
+ const s = document.createElement("style");
54
+ s.id = id;
55
+ s.textContent = css;
56
+ document.head.appendChild(s);
57
+ }
58
+ fs_injectCss("ax-conncard-css", AX_CONNCARD_CSS_FS);
59
+ fs_injectCss("ax-feishucard-css", AX_FEISHUCARD_CSS);
60
+ function parseFeishuLink(url) {
61
+ if (!url) return null;
62
+ const tokenM = url.match(/\/base\/([A-Za-z0-9]+)/) || url.match(/[?&]app_token=([A-Za-z0-9]+)/);
63
+ const tableM = url.match(/[?&]table=([A-Za-z0-9]+)/);
64
+ if (!tokenM) return null;
65
+ return { token: tokenM[1], table: tableM ? tableM[1] : "" };
66
+ }
67
+ const FS_DEFAULT_FIELD_MAP = [
68
+ { from: "姓名", to: "姓名", tag: null },
69
+ { from: "手机号", to: "手机号", tag: null },
70
+ { from: "邮箱", to: "邮箱", tag: null },
71
+ { from: "报名场次", to: "场次", tag: "单选" },
72
+ { from: "备注", to: "备注", tag: null },
73
+ { from: null, to: "提交时间", tag: "自动" },
74
+ { from: null, to: "来源链接", tag: "自动" }
75
+ ];
76
+ const FS_DEFAULT_HELP = {
77
+ title: "如何获取飞书应用凭证?",
78
+ steps: [
79
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
80
+ "打开飞书开放平台 ",
81
+ /* @__PURE__ */ jsx("code", { children: "open.feishu.cn" }),
82
+ ",创建一个「企业自建应用」。"
83
+ ] }),
84
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
85
+ "在「凭证与基础信息」中复制 ",
86
+ /* @__PURE__ */ jsx("code", { children: "App ID" }),
87
+ " 与 ",
88
+ /* @__PURE__ */ jsx("code", { children: "App Secret" }),
89
+ "。"
90
+ ] }),
91
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
92
+ "到「权限管理」开通多维表格读写权限 ",
93
+ /* @__PURE__ */ jsx("code", { children: "bitable:app" }),
94
+ ",并发布版本。"
95
+ ] }),
96
+ /* @__PURE__ */ jsxs(React.Fragment, { children: [
97
+ "在目标多维表格里,把这个应用添加为",
98
+ /* @__PURE__ */ jsx("strong", { children: "可编辑协作者" }),
99
+ "。"
100
+ ] }),
101
+ /* @__PURE__ */ jsx(React.Fragment, { children: "复制该多维表格的分享链接,粘贴到上方「多维表格链接」。" })
102
+ ],
103
+ link: { href: "https://open.feishu.cn", label: "打开飞书开放平台" }
104
+ };
105
+ function FeishuCard({
106
+ appId = "",
107
+ onAppIdChange,
108
+ secret = "",
109
+ onSecretChange,
110
+ link = "",
111
+ onLinkChange,
112
+ status = "idle",
113
+ result,
114
+ onTest,
115
+ masked = false,
116
+ appIdError,
117
+ secretError,
118
+ linkError,
119
+ fieldMap = FS_DEFAULT_FIELD_MAP,
120
+ showMapping,
121
+ help,
122
+ canTest,
123
+ idleHint = "填写凭证与链接后测试写入权限"
124
+ }) {
125
+ const parsed = parseFeishuLink(link);
126
+ const maskedNow = masked && !(secret || "").trim();
127
+ const testDisabled = canTest !== void 0 ? !canTest : !(appId || "").trim() || !(secret || "").trim() && !masked || !parsed;
128
+ const showMap = showMapping !== void 0 ? showMapping : status === "ok";
129
+ const help_ = help || FS_DEFAULT_HELP;
130
+ return /* @__PURE__ */ jsxs(
131
+ "section",
132
+ {
133
+ className: "s-card" + (status === "ok" ? " is-ok" : status === "error" ? " is-error" : ""),
134
+ children: [
135
+ /* @__PURE__ */ jsxs("div", { className: "s-card__head", children: [
136
+ /* @__PURE__ */ jsxs("div", { className: "s-card__toprow", children: [
137
+ /* @__PURE__ */ jsx("div", { className: "s-card__icon", children: /* @__PURE__ */ jsx(Icon, { name: "table", size: 16 }) }),
138
+ /* @__PURE__ */ jsx("span", { className: "ax-label s-card__eyebrow", children: "数据写入 · FEISHU BITABLE" }),
139
+ /* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status }) })
140
+ ] }),
141
+ /* @__PURE__ */ jsx("h2", { className: "s-card__title", children: "飞书多维表格" }),
142
+ /* @__PURE__ */ jsx("p", { className: "s-card__desc", children: "每次提交后,数据自动写入指定多维表格的一行。需要一个飞书自建应用的凭证,以及目标表格的链接。" })
143
+ ] }),
144
+ /* @__PURE__ */ jsxs("div", { className: "s-card__body", children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "s-row2", children: [
146
+ /* @__PURE__ */ jsxs("div", { children: [
147
+ /* @__PURE__ */ jsx("label", { className: "s-field__label ax-label", children: "App ID" }),
148
+ /* @__PURE__ */ jsx(
149
+ "input",
150
+ {
151
+ className: "ax-input ax-input--mono" + (appIdError ? " ax-input--error" : ""),
152
+ type: "text",
153
+ value: appId,
154
+ spellCheck: "false",
155
+ placeholder: "cli_xxxxxxxxxxxx",
156
+ onChange: (e) => onAppIdChange && onAppIdChange(e.target.value)
157
+ }
158
+ ),
159
+ appIdError ? /* @__PURE__ */ jsx("p", { className: "s-field__hint s-field__hint--err", children: appIdError }) : /* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "应用标识,可公开。" })
160
+ ] }),
161
+ /* @__PURE__ */ jsx(
162
+ SecretField,
163
+ {
164
+ label: "App Secret",
165
+ value: secret,
166
+ onChange: onSecretChange,
167
+ placeholder: maskedNow ? "已保存 ········ · 留空则保持不变" : "••••••••••••••••",
168
+ hint: maskedNow ? "已存密钥 · 留空表示不修改" : "应用密钥,加密存储。",
169
+ error: secretError
170
+ }
171
+ )
172
+ ] }),
173
+ /* @__PURE__ */ jsxs("div", { children: [
174
+ /* @__PURE__ */ jsx("label", { className: "s-field__label ax-label", children: "多维表格链接" }),
175
+ /* @__PURE__ */ jsx(
176
+ "input",
177
+ {
178
+ className: "ax-input" + (linkError ? " ax-input--error" : ""),
179
+ type: "text",
180
+ value: link,
181
+ spellCheck: "false",
182
+ placeholder: "https://your-team.feishu.cn/base/bascn…?table=tbl…",
183
+ onChange: (e) => onLinkChange && onLinkChange(e.target.value)
184
+ }
185
+ ),
186
+ linkError ? /* @__PURE__ */ jsx("p", { className: "s-field__hint s-field__hint--err", children: linkError }) : /* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "在多维表格右上角「分享」中复制链接粘贴即可,App Token 与数据表会自动识别。" })
187
+ ] }),
188
+ parsed ? /* @__PURE__ */ jsxs("div", { className: "s-detect", children: [
189
+ /* @__PURE__ */ jsxs("div", { className: "s-detect__row", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "s-detect__k", children: "App Token" }),
191
+ /* @__PURE__ */ jsx("span", { className: "s-detect__v", children: parsed.token }),
192
+ /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", children: [
193
+ /* @__PURE__ */ jsx(Icon, { name: "check", size: 12 }),
194
+ "已识别"
195
+ ] })
196
+ ] }),
197
+ /* @__PURE__ */ jsxs("div", { className: "s-detect__row", children: [
198
+ /* @__PURE__ */ jsx("span", { className: "s-detect__k", children: "数据表" }),
199
+ /* @__PURE__ */ jsx("span", { className: "s-detect__v", children: parsed.table || "—" }),
200
+ parsed.table ? /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", children: [
201
+ /* @__PURE__ */ jsx(Icon, { name: "check", size: 12 }),
202
+ "已识别"
203
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "s-detect__ok", style: { color: "var(--warn)" }, children: [
204
+ /* @__PURE__ */ jsx(Icon, { name: "warn", size: 12 }),
205
+ "缺失"
206
+ ] })
207
+ ] })
208
+ ] }) : null,
209
+ /* @__PURE__ */ jsxs("div", { className: "s-lock", children: [
210
+ /* @__PURE__ */ jsx(Icon, { name: "shield", size: 14 }),
211
+ /* @__PURE__ */ jsxs("span", { children: [
212
+ /* @__PURE__ */ jsx("strong", { children: "凭证加密存储" }),
213
+ ",仅服务端用于写入数据。用户",
214
+ /* @__PURE__ */ jsx("strong", { children: "无法接触你的飞书凭证或表格权限。" })
215
+ ] })
216
+ ] }),
217
+ showMap ? /* @__PURE__ */ jsxs("div", { children: [
218
+ /* @__PURE__ */ jsxs("div", { className: "s-sub", style: { marginBottom: 12 }, children: [
219
+ /* @__PURE__ */ jsx("span", { className: "ax-label", children: "字段映射 · 自动" }),
220
+ /* @__PURE__ */ jsx("span", { className: "s-sub__line" })
221
+ ] }),
222
+ /* @__PURE__ */ jsxs("table", { className: "s-map", children: [
223
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
224
+ /* @__PURE__ */ jsx("th", { children: "字段" }),
225
+ /* @__PURE__ */ jsx("th", { className: "s-map__arrow" }),
226
+ /* @__PURE__ */ jsx("th", { children: "表格列" })
227
+ ] }) }),
228
+ /* @__PURE__ */ jsx("tbody", { children: fieldMap.map((m, i) => /* @__PURE__ */ jsxs("tr", { children: [
229
+ /* @__PURE__ */ jsx("td", { className: "s-map__from", children: m.from || /* @__PURE__ */ jsx("span", { style: { color: "var(--text-faint)" }, children: "—" }) }),
230
+ /* @__PURE__ */ jsx("td", { className: "s-map__arrow", children: /* @__PURE__ */ jsx(Icon, { name: "arrow", size: 14 }) }),
231
+ /* @__PURE__ */ jsxs("td", { children: [
232
+ /* @__PURE__ */ jsx("span", { className: "s-map__col", children: m.to }),
233
+ m.tag ? /* @__PURE__ */ jsx("span", { className: "s-map__tag", children: m.tag }) : null
234
+ ] })
235
+ ] }, i)) })
236
+ ] })
237
+ ] }) : null,
238
+ /* @__PURE__ */ jsx(FeishuHelpSlot, { help: help_ })
239
+ ] }),
240
+ /* @__PURE__ */ jsx(
241
+ TestRow,
242
+ {
243
+ status,
244
+ result,
245
+ onTest,
246
+ disabled: testDisabled,
247
+ idleHint
248
+ }
249
+ )
250
+ ]
251
+ }
252
+ );
253
+ }
254
+ function FeishuHelpSlot({ help }) {
255
+ if (!help) return null;
256
+ if (React.isValidElement(help)) return help;
257
+ return /* @__PURE__ */ jsx(
258
+ HelpSteps,
259
+ {
260
+ title: help.title,
261
+ steps: help.steps,
262
+ link: help.link,
263
+ defaultOpen: help.defaultOpen
264
+ }
265
+ );
266
+ }
267
+ export {
268
+ FeishuCard,
269
+ parseFeishuLink
270
+ };
271
+ //# sourceMappingURL=FeishuCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeishuCard.js","sources":["../../../src/components/settings/FeishuCard.jsx"],"sourcesContent":["import React from \"react\";\nimport { HelpSteps } from \"./HelpSteps.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\nimport { SecretField } from \"../inputs/SecretField.jsx\";\nimport { StatusPill } from \"../display/StatusPill.jsx\";\nimport { TestRow } from \"./TestRow.jsx\";\n\n// FeishuCard — a PURE-DISPLAY connection card for a Feishu (Lark) Bitable data\n// sink. Props in (appId / secret / link, status, result, masked, errors,\n// fieldMap, help…), events out (onAppIdChange / onSecretChange / onLinkChange /\n// onTest). Zero state, zero localStorage, zero save bar, zero gating — the\n// caller owns all of that. The only thing it derives locally is the App\n// Token / table read-out parsed from the share link (pure display). Composes\n// SecretField / StatusPill / TestRow / HelpSteps.\nconst AX_FEISHUCARD_CSS = `\n.s-detect { display: flex; flex-direction: column; gap: 9px; padding: 13px 14px; border: 1px solid var(--border-default);\n border-radius: var(--radius-2); background: var(--surface-page); }\n.s-detect__row { display: flex; align-items: center; gap: 10px; }\n.s-detect__k { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint); width: 84px; flex: none; }\n.s-detect__v { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); word-break: break-all; flex: 1; }\n.s-detect__ok { color: var(--ok); display: flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10px;\n letter-spacing: var(--tracking-label); text-transform: uppercase; flex: none; }\n.s-map { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }\n.s-map th { text-align: left; font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-label);\n text-transform: uppercase; color: var(--text-faint); font-weight: 500; padding: 0 0 8px; }\n.s-map td { padding: 7px 0; border-top: 1px solid var(--border-default); color: var(--text-body); vertical-align: middle; }\n.s-map__from { color: var(--text-muted); }\n.s-map__arrow { width: 36px; color: var(--text-faint); }\n.s-map__col { font-family: var(--font-mono); }\n.s-map__tag { font-family: var(--font-mono); font-size: 9px; letter-spacing: var(--tracking-label); text-transform: uppercase;\n color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 2px 5px; margin-left: 7px; }\n.s-sub { display: flex; align-items: center; gap: 8px; }\n.s-sub__line { flex: 1; height: 1px; background: var(--border-default); }\n`;\n\n// Shared connection-card shell, mirrored from DeepSeekCard so this card renders\n// correctly when mounted on its own. Guarded by a single id — first writer wins.\nconst AX_CONNCARD_CSS_FS = `\n.s-card { position: relative; background: var(--surface-card); border: 1px solid var(--border-default);\n border-radius: var(--radius-3); overflow: hidden; transition: border-color var(--dur-2) var(--ease-out); }\n.s-card.is-ok { border-color: rgba(62, 207, 142, 0.4); }\n.s-card.is-error { border-color: rgba(229, 72, 77, 0.4); }\n.s-card__head { padding: 20px 24px 18px; }\n.s-card__toprow { display: flex; align-items: center; gap: 11px; margin-bottom: 15px; }\n.s-card__icon { flex: none; width: 30px; height: 30px; border-radius: var(--radius-2);\n border: 1px solid var(--border-strong); background: var(--surface-raised); color: var(--text-body);\n display: flex; align-items: center; justify-content: center; }\n.s-card__eyebrow { color: var(--text-faint); }\n.s-card__status { margin-left: auto; flex: none; }\n.s-card__title { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 500;\n letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); color: var(--text-body); margin: 0; }\n.s-card__desc { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); margin: 9px 0 0; max-width: 58ch; }\n.s-card__body { padding: 4px 24px 22px; display: flex; flex-direction: column; gap: 18px; }\n.s-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n@media (max-width: 560px) { .s-row2 { grid-template-columns: 1fr; } }\n.s-lock { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-xs); color: var(--text-faint); line-height: var(--leading-snug); }\n.s-lock svg { flex: none; margin-top: 1px; color: var(--text-muted); }\n.s-lock strong { color: var(--text-muted); font-weight: 500; }\n`;\n\nfunction fs_injectCss(id, css) {\n if (typeof document === \"undefined\" || document.getElementById(id)) return;\n const s = document.createElement(\"style\");\n s.id = id;\n s.textContent = css;\n document.head.appendChild(s);\n}\nfs_injectCss(\"ax-conncard-css\", AX_CONNCARD_CSS_FS);\nfs_injectCss(\"ax-feishucard-css\", AX_FEISHUCARD_CSS);\n\n// Parse the App Token + data-table id out of a Bitable share URL — pure display.\nexport function parseFeishuLink(url) {\n if (!url) return null;\n const tokenM = url.match(/\\/base\\/([A-Za-z0-9]+)/) || url.match(/[?&]app_token=([A-Za-z0-9]+)/);\n const tableM = url.match(/[?&]table=([A-Za-z0-9]+)/);\n if (!tokenM) return null;\n return { token: tokenM[1], table: tableM ? tableM[1] : \"\" };\n}\n\nconst FS_DEFAULT_FIELD_MAP = [\n { from: \"姓名\", to: \"姓名\", tag: null },\n { from: \"手机号\", to: \"手机号\", tag: null },\n { from: \"邮箱\", to: \"邮箱\", tag: null },\n { from: \"报名场次\", to: \"场次\", tag: \"单选\" },\n { from: \"备注\", to: \"备注\", tag: null },\n { from: null, to: \"提交时间\", tag: \"自动\" },\n { from: null, to: \"来源链接\", tag: \"自动\" },\n];\n\nconst FS_DEFAULT_HELP = {\n title: \"如何获取飞书应用凭证?\",\n steps: [\n <React.Fragment>\n 打开飞书开放平台 <code>open.feishu.cn</code>,创建一个「企业自建应用」。\n </React.Fragment>,\n <React.Fragment>\n 在「凭证与基础信息」中复制 <code>App ID</code> 与 <code>App Secret</code>。\n </React.Fragment>,\n <React.Fragment>\n 到「权限管理」开通多维表格读写权限 <code>bitable:app</code>,并发布版本。\n </React.Fragment>,\n <React.Fragment>\n 在目标多维表格里,把这个应用添加为<strong>可编辑协作者</strong>。\n </React.Fragment>,\n <React.Fragment>复制该多维表格的分享链接,粘贴到上方「多维表格链接」。</React.Fragment>,\n ],\n link: { href: \"https://open.feishu.cn\", label: \"打开飞书开放平台\" },\n};\n\nexport function FeishuCard({\n appId = \"\",\n onAppIdChange,\n secret = \"\",\n onSecretChange,\n link = \"\",\n onLinkChange,\n status = \"idle\",\n result,\n onTest,\n masked = false,\n appIdError,\n secretError,\n linkError,\n fieldMap = FS_DEFAULT_FIELD_MAP,\n showMapping,\n help,\n canTest,\n idleHint = \"填写凭证与链接后测试写入权限\",\n}) {\n const parsed = parseFeishuLink(link);\n // Masked echo is derived from props (no state): stored secret + empty field →\n // masked placeholder, still counts as \"present\" for the Test button.\n const maskedNow = masked && !(secret || \"\").trim();\n const testDisabled =\n canTest !== undefined\n ? !canTest\n : !(appId || \"\").trim() || (!(secret || \"\").trim() && !masked) || !parsed;\n const showMap = showMapping !== undefined ? showMapping : status === \"ok\";\n const help_ = help || FS_DEFAULT_HELP;\n\n return (\n <section\n className={\"s-card\" + (status === \"ok\" ? \" is-ok\" : status === \"error\" ? \" is-error\" : \"\")}\n >\n <div className=\"s-card__head\">\n <div className=\"s-card__toprow\">\n <div className=\"s-card__icon\">\n <Icon name=\"table\" size={16} />\n </div>\n <span className=\"ax-label s-card__eyebrow\">数据写入 · FEISHU BITABLE</span>\n <span className=\"s-card__status\">\n <StatusPill status={status} />\n </span>\n </div>\n <h2 className=\"s-card__title\">飞书多维表格</h2>\n <p className=\"s-card__desc\">\n 每次提交后,数据自动写入指定多维表格的一行。需要一个飞书自建应用的凭证,以及目标表格的链接。\n </p>\n </div>\n\n <div className=\"s-card__body\">\n <div className=\"s-row2\">\n <div>\n <label className=\"s-field__label ax-label\">App ID</label>\n <input\n className={\"ax-input ax-input--mono\" + (appIdError ? \" ax-input--error\" : \"\")}\n type=\"text\"\n value={appId}\n spellCheck=\"false\"\n placeholder=\"cli_xxxxxxxxxxxx\"\n onChange={(e) => onAppIdChange && onAppIdChange(e.target.value)}\n />\n {appIdError ? (\n <p className=\"s-field__hint s-field__hint--err\">{appIdError}</p>\n ) : (\n <p className=\"s-field__hint\">应用标识,可公开。</p>\n )}\n </div>\n <SecretField\n label=\"App Secret\"\n value={secret}\n onChange={onSecretChange}\n placeholder={maskedNow ? \"已保存 ········ · 留空则保持不变\" : \"••••••••••••••••\"}\n hint={maskedNow ? \"已存密钥 · 留空表示不修改\" : \"应用密钥,加密存储。\"}\n error={secretError}\n />\n </div>\n\n <div>\n <label className=\"s-field__label ax-label\">多维表格链接</label>\n <input\n className={\"ax-input\" + (linkError ? \" ax-input--error\" : \"\")}\n type=\"text\"\n value={link}\n spellCheck=\"false\"\n placeholder=\"https://your-team.feishu.cn/base/bascn…?table=tbl…\"\n onChange={(e) => onLinkChange && onLinkChange(e.target.value)}\n />\n {linkError ? (\n <p className=\"s-field__hint s-field__hint--err\">{linkError}</p>\n ) : (\n <p className=\"s-field__hint\">\n 在多维表格右上角「分享」中复制链接粘贴即可,App Token 与数据表会自动识别。\n </p>\n )}\n </div>\n\n {parsed ? (\n <div className=\"s-detect\">\n <div className=\"s-detect__row\">\n <span className=\"s-detect__k\">App Token</span>\n <span className=\"s-detect__v\">{parsed.token}</span>\n <span className=\"s-detect__ok\">\n <Icon name=\"check\" size={12} />\n 已识别\n </span>\n </div>\n <div className=\"s-detect__row\">\n <span className=\"s-detect__k\">数据表</span>\n <span className=\"s-detect__v\">{parsed.table || \"—\"}</span>\n {parsed.table ? (\n <span className=\"s-detect__ok\">\n <Icon name=\"check\" size={12} />\n 已识别\n </span>\n ) : (\n <span className=\"s-detect__ok\" style={{ color: \"var(--warn)\" }}>\n <Icon name=\"warn\" size={12} />\n 缺失\n </span>\n )}\n </div>\n </div>\n ) : null}\n\n <div className=\"s-lock\">\n <Icon name=\"shield\" size={14} />\n <span>\n <strong>凭证加密存储</strong>,仅服务端用于写入数据。用户\n <strong>无法接触你的飞书凭证或表格权限。</strong>\n </span>\n </div>\n\n {showMap ? (\n <div>\n <div className=\"s-sub\" style={{ marginBottom: 12 }}>\n <span className=\"ax-label\">字段映射 · 自动</span>\n <span className=\"s-sub__line\"></span>\n </div>\n <table className=\"s-map\">\n <thead>\n <tr>\n <th>字段</th>\n <th className=\"s-map__arrow\"></th>\n <th>表格列</th>\n </tr>\n </thead>\n <tbody>\n {fieldMap.map((m, i) => (\n <tr key={i}>\n <td className=\"s-map__from\">\n {m.from || <span style={{ color: \"var(--text-faint)\" }}>—</span>}\n </td>\n <td className=\"s-map__arrow\">\n <Icon name=\"arrow\" size={14} />\n </td>\n <td>\n <span className=\"s-map__col\">{m.to}</span>\n {m.tag ? <span className=\"s-map__tag\">{m.tag}</span> : null}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : null}\n\n <FeishuHelpSlot help={help_} />\n </div>\n\n <TestRow\n status={status}\n result={result}\n onTest={onTest}\n disabled={testDisabled}\n idleHint={idleHint}\n />\n </section>\n );\n}\n\nfunction FeishuHelpSlot({ help }) {\n if (!help) return null;\n if (React.isValidElement(help)) return help;\n return (\n <HelpSteps\n title={help.title}\n steps={help.steps}\n link={help.link}\n defaultOpen={help.defaultOpen}\n />\n );\n}\n"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ export interface BrandMarkProps {
8
8
  size?: number;
9
9
  /** Render the "agentaily" wordmark after the mark. @default false */
10
10
  wordmark?: boolean;
11
- /** Show the blinking block cursor after the wordmark. @default true */
11
+ /** Show the block cursor after the wordmark. Off by default in lockups; opt in for the liveness motif. @default false */
12
12
  cursor?: boolean;
13
13
  /** Animate the cursor (blink). Set false for a solid, static cursor. @default true */
14
14
  blink?: boolean;
@@ -19,7 +19,7 @@ if (typeof document !== "undefined" && !document.getElementById("ax-brandmark-cs
19
19
  function BrandMark({
20
20
  size = 20,
21
21
  wordmark = false,
22
- cursor = true,
22
+ cursor = false,
23
23
  blink = true,
24
24
  className = "",
25
25
  ...rest
@@ -1 +1 @@
1
- {"version":3,"file":"BrandMark.js","sources":["../../../src/components/utilities/BrandMark.jsx"],"sourcesContent":["import React from \"react\";\n\n// BrandMark — the agentaily mark (cursor block inside corner ticks) and optional\n// typed wordmark. Monochrome, drawn in currentColor so it inverts with the theme.\n// Used in auth modals, settings headers, top bars. Never recolor with a hue.\nconst AX_BRANDMARK_CSS = `\n.ax-brandmark { display: inline-flex; align-items: center; gap: 9px; color: var(--text-body); }\n.ax-brandmark__mark { display: inline-flex; flex: none; }\n.ax-brandmark__word {\n font-family: var(--font-mono); font-weight: var(--weight-medium);\n letter-spacing: -0.02em; color: var(--text-body);\n display: inline-flex; align-items: baseline; line-height: 1;\n}\n.ax-brandmark__word .ax-cursor { margin-left: 1px; width: 0.42em; height: 0.92em; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-brandmark-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-brandmark-css\";\n s.textContent = AX_BRANDMARK_CSS;\n document.head.appendChild(s);\n}\n\nexport function BrandMark({\n size = 20,\n wordmark = false,\n cursor = true,\n blink = true,\n className = \"\",\n ...rest\n}) {\n const stroke = Math.max(2, Math.round((size / 32) * 2.4 * 10) / 10);\n return (\n <span className={[\"ax-brandmark\", className].filter(Boolean).join(\" \")} {...rest}>\n <span className=\"ax-brandmark__mark\" aria-hidden=\"true\">\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M2 10 V2 H10\" stroke=\"currentColor\" strokeWidth={stroke} />\n <path d=\"M22 30 H30 V22\" stroke=\"currentColor\" strokeWidth={stroke} />\n <rect x=\"12\" y=\"9\" width=\"8\" height=\"14\" fill=\"currentColor\" />\n </svg>\n </span>\n {wordmark ? (\n <span className=\"ax-brandmark__word\" style={{ fontSize: Math.round(size * 0.75) }}>\n agentaily\n {cursor ? (\n <i className=\"ax-cursor\" style={blink ? undefined : { animation: \"none\" }}></i>\n ) : null}\n </span>\n ) : null}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAKA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU;AAAA,EACxB,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,GAAG;AACL,GAAG;AACD,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAO,OAAO,KAAM,MAAM,EAAE,IAAI,EAAE;AAClE,SACE,qBAAC,QAAA,EAAK,WAAW,CAAC,gBAAgB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MAC1E,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,WAAU,sBAAqB,eAAY,QAC/C,UAAA,qBAAC,OAAA,EAAI,OAAO,MAAM,QAAQ,MAAM,SAAQ,aAAY,MAAK,QACvD,UAAA;AAAA,MAAA,oBAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAa,QAAQ;AAAA,0BACjE,QAAA,EAAK,GAAE,kBAAiB,QAAO,gBAAe,aAAa,QAAQ;AAAA,MACpE,oBAAC,QAAA,EAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,MAAK,MAAK,eAAA,CAAe;AAAA,IAAA,EAAA,CAC/D,EAAA,CACF;AAAA,IACC,WACC,qBAAC,QAAA,EAAK,WAAU,sBAAqB,OAAO,EAAE,UAAU,KAAK,MAAM,OAAO,IAAI,KAAK,UAAA;AAAA,MAAA;AAAA,MAEhF,SACC,oBAAC,KAAA,EAAE,WAAU,aAAY,OAAO,QAAQ,SAAY,EAAE,WAAW,OAAA,EAAO,CAAG,IACzE;AAAA,IAAA,EAAA,CACN,IACE;AAAA,EAAA,GACN;AAEJ;"}
1
+ {"version":3,"file":"BrandMark.js","sources":["../../../src/components/utilities/BrandMark.jsx"],"sourcesContent":["import React from \"react\";\n\n// BrandMark — the agentaily mark (cursor block inside corner ticks) and optional\n// typed wordmark. Monochrome, drawn in currentColor so it inverts with the theme.\n// Used in auth modals, settings headers, top bars. Never recolor with a hue.\nconst AX_BRANDMARK_CSS = `\n.ax-brandmark { display: inline-flex; align-items: center; gap: 9px; color: var(--text-body); }\n.ax-brandmark__mark { display: inline-flex; flex: none; }\n.ax-brandmark__word {\n font-family: var(--font-mono); font-weight: var(--weight-medium);\n letter-spacing: -0.02em; color: var(--text-body);\n display: inline-flex; align-items: baseline; line-height: 1;\n}\n.ax-brandmark__word .ax-cursor { margin-left: 1px; width: 0.42em; height: 0.92em; }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-brandmark-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-brandmark-css\";\n s.textContent = AX_BRANDMARK_CSS;\n document.head.appendChild(s);\n}\n\nexport function BrandMark({\n size = 20,\n wordmark = false,\n cursor = false,\n blink = true,\n className = \"\",\n ...rest\n}) {\n const stroke = Math.max(2, Math.round((size / 32) * 2.4 * 10) / 10);\n return (\n <span className={[\"ax-brandmark\", className].filter(Boolean).join(\" \")} {...rest}>\n <span className=\"ax-brandmark__mark\" aria-hidden=\"true\">\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M2 10 V2 H10\" stroke=\"currentColor\" strokeWidth={stroke} />\n <path d=\"M22 30 H30 V22\" stroke=\"currentColor\" strokeWidth={stroke} />\n <rect x=\"12\" y=\"9\" width=\"8\" height=\"14\" fill=\"currentColor\" />\n </svg>\n </span>\n {wordmark ? (\n <span className=\"ax-brandmark__word\" style={{ fontSize: Math.round(size * 0.75) }}>\n agentaily\n {cursor ? (\n <i className=\"ax-cursor\" style={blink ? undefined : { animation: \"none\" }}></i>\n ) : null}\n </span>\n ) : null}\n </span>\n );\n}\n"],"names":[],"mappings":";;AAKA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU;AAAA,EACxB,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,GAAG;AACL,GAAG;AACD,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAO,OAAO,KAAM,MAAM,EAAE,IAAI,EAAE;AAClE,SACE,qBAAC,QAAA,EAAK,WAAW,CAAC,gBAAgB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,MAC1E,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,WAAU,sBAAqB,eAAY,QAC/C,UAAA,qBAAC,OAAA,EAAI,OAAO,MAAM,QAAQ,MAAM,SAAQ,aAAY,MAAK,QACvD,UAAA;AAAA,MAAA,oBAAC,UAAK,GAAE,gBAAe,QAAO,gBAAe,aAAa,QAAQ;AAAA,0BACjE,QAAA,EAAK,GAAE,kBAAiB,QAAO,gBAAe,aAAa,QAAQ;AAAA,MACpE,oBAAC,QAAA,EAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,MAAK,MAAK,eAAA,CAAe;AAAA,IAAA,EAAA,CAC/D,EAAA,CACF;AAAA,IACC,WACC,qBAAC,QAAA,EAAK,WAAU,sBAAqB,OAAO,EAAE,UAAU,KAAK,MAAM,OAAO,IAAI,KAAK,UAAA;AAAA,MAAA;AAAA,MAEhF,SACC,oBAAC,KAAA,EAAE,WAAU,aAAY,OAAO,QAAQ,SAAY,EAAE,WAAW,OAAA,EAAO,CAAG,IACzE;AAAA,IAAA,EAAA,CACN,IACE;AAAA,EAAA,GACN;AAEJ;"}
package/dist/index.d.ts CHANGED
@@ -30,6 +30,7 @@ export * from "./components/buttons/IconButton";
30
30
  export * from "./components/chat/CodeBlock";
31
31
  export * from "./components/chat/Composer";
32
32
  export * from "./components/chat/ConversationThread";
33
+ export * from "./components/chat/Markdown";
33
34
  export * from "./components/chat/Message";
34
35
 
35
36
  // code
@@ -121,8 +122,9 @@ export * from "./components/overlay/Sheet";
121
122
  export * from "./components/review/MarkupLayer";
122
123
 
123
124
  // settings
125
+ export * from "./components/settings/DeepSeekCard";
126
+ export * from "./components/settings/FeishuCard";
124
127
  export * from "./components/settings/HelpSteps";
125
- export * from "./components/settings/IntegrationSettings";
126
128
  export * from "./components/settings/TestRow";
127
129
 
128
130
  // utilities
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { IconButton } from "./components/buttons/IconButton.js";
21
21
  import { CodeBlock } from "./components/chat/CodeBlock.js";
22
22
  import { Composer } from "./components/chat/Composer.js";
23
23
  import { ConversationThread } from "./components/chat/ConversationThread.js";
24
+ import { Markdown } from "./components/chat/Markdown.js";
24
25
  import { Message } from "./components/chat/Message.js";
25
26
  import { Agent } from "./components/code/Agent.js";
26
27
  import { Artifact } from "./components/code/Artifact.js";
@@ -96,8 +97,9 @@ import { NavigationMenu } from "./components/overlay/NavigationMenu.js";
96
97
  import { Popover } from "./components/overlay/Popover.js";
97
98
  import { Sheet } from "./components/overlay/Sheet.js";
98
99
  import { MarkupLayer } from "./components/review/MarkupLayer.js";
100
+ import { DeepSeekCard } from "./components/settings/DeepSeekCard.js";
101
+ import { FeishuCard, parseFeishuLink } from "./components/settings/FeishuCard.js";
99
102
  import { HelpSteps } from "./components/settings/HelpSteps.js";
100
- import { IntegrationSettings } from "./components/settings/IntegrationSettings.js";
101
103
  import { TestRow } from "./components/settings/TestRow.js";
102
104
  import { BrandMark } from "./components/utilities/BrandMark.js";
103
105
  import { Icon } from "./components/utilities/Icon.js";
@@ -153,6 +155,7 @@ export {
153
155
  ConversationThread,
154
156
  DataTable,
155
157
  DatePicker,
158
+ DeepSeekCard,
156
159
  DesignerShell,
157
160
  Dialog,
158
161
  DocsLayout,
@@ -160,6 +163,7 @@ export {
160
163
  Edge,
161
164
  Empty,
162
165
  EnvironmentVariables,
166
+ FeishuCard,
163
167
  Field,
164
168
  FieldGroup,
165
169
  FileTree,
@@ -174,12 +178,12 @@ export {
174
178
  Input,
175
179
  InputGroup,
176
180
  InputOTP,
177
- IntegrationSettings,
178
181
  Item,
179
182
  JSXPreview,
180
183
  Kbd,
181
184
  Label,
182
185
  LineChart,
186
+ Markdown,
183
187
  MarkupLayer,
184
188
  Menubar,
185
189
  Message,
@@ -240,6 +244,7 @@ export {
240
244
  Transcription,
241
245
  Typography,
242
246
  VoiceSelector,
243
- WebPreview
247
+ WebPreview,
248
+ parseFeishuLink
244
249
  };
245
250
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agentaily/design-system",
3
- "version": "0.5.0",
4
- "description": "Agentaily design system — light-first monochrome React component library (113 components) + Storybook.",
3
+ "version": "0.7.0",
4
+ "description": "Agentaily design system — light-first monochrome React component library (115 components) + Storybook.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "author": "Agentaily",
@@ -1,84 +0,0 @@
1
- /**
2
- * Fullscreen integration modal: connect a DeepSeek key (conversation engine) and
3
- * a Feishu Bitable (data sink). Reports a 0/2 readiness state and gates Save until
4
- * both connect. Composes SecretField, StatusPill, TestRow, HelpSteps. The monthly
5
- * usage-cap block is opt-in.
6
- *
7
- * Two storage modes:
8
- * - **Uncontrolled (default):** self-persists the whole config to localStorage —
9
- * the legacy behavior, unchanged when none of the seam props below are passed.
10
- * - **Controlled / backend-wired:** pass `value` + `onChange` to hold the config
11
- * yourself (no localStorage writes), `onSave`/`onTest` to reach a real backend,
12
- * `readiness` to reflect server-known connection state, and `masked` so stored
13
- * secrets echo masked and are never re-submitted.
14
- */
15
- export interface IntegrationConfig {
16
- /** DeepSeek API key. Empty when masked + untouched (caller keeps the stored one). */
17
- dsKey: string;
18
- /** Conversation model id, e.g. "deepseek-chat" | "deepseek-reasoner". */
19
- dsModel: string;
20
- /** Monthly usage-cap toggle. */
21
- capOn: boolean;
22
- /** Monthly cap amount (digits-only string). */
23
- cap: string;
24
- /** DeepSeek connection status. */
25
- dsStatus: "idle" | "testing" | "ok" | "error";
26
- /** DeepSeek test result line. */
27
- dsResult: string;
28
- /** Feishu app id (public). */
29
- appId: string;
30
- /** Feishu app secret. Empty when masked + untouched. */
31
- secret: string;
32
- /** Feishu Bitable share URL (app_token + table auto-parsed). */
33
- link: string;
34
- /** Feishu connection status. */
35
- fsStatus: "idle" | "testing" | "ok" | "error";
36
- /** Feishu test result line. */
37
- fsResult: string;
38
- /** Whether the last config was saved. */
39
- saved: boolean;
40
- }
41
- export interface IntegrationSettingsProps {
42
- /** Close handler (Esc + the × button + overlay). */
43
- onClose?: () => void;
44
- /** Show the DeepSeek monthly usage-cap warning + toggle. @default true */
45
- showUsageCap?: boolean;
46
- /** localStorage key for the persisted config (uncontrolled mode only). @default "agentaily.integrations.v1" */
47
- storageKey?: string;
48
- /**
49
- * Controlled config. When provided, this is the source of truth — the modal
50
- * stops reading/writing localStorage and every edit flows out via `onChange`.
51
- * Omit for the self-persisting default.
52
- */
53
- value?: IntegrationConfig;
54
- /** Fires with the next full config on every edit/test (controlled mode). */
55
- onChange?: (next: IntegrationConfig) => void;
56
- /**
57
- * Persist handler. Receives the current config (masked secrets stay empty —
58
- * treat empty as "keep the stored one"). Return a Promise: Save is disabled and
59
- * spins while it's pending, marks saved on resolve, and stays dirty on reject.
60
- * When omitted, Save just flips the in-component saved state.
61
- */
62
- onSave?: (value: IntegrationConfig) => void | Promise<void>;
63
- /**
64
- * Connection probe. `which` is "deepseek" | "feishu"; return
65
- * `Promise<{ ok, message }>` to drive that card's StatusPill + TestRow. When
66
- * omitted, a built-in mock probe runs (validates key shape / link parsing).
67
- */
68
- onTest?: (which: "deepseek" | "feishu") => Promise<{ ok: boolean; message?: string }>;
69
- /**
70
- * External readiness override. When set, these flags (not the in-app test
71
- * status) decide the 0/2 rail, Save gating, and the green pills — e.g. show
72
- * "connected" for credentials already verified server-side. Live testing/error
73
- * transitions still surface on the pill.
74
- */
75
- readiness?: { deepseek?: boolean; feishu?: boolean };
76
- /**
77
- * Masked-echo flags for already-stored secrets. When `deepseek`/`feishu` is
78
- * true and the field is untouched, it renders a masked placeholder, keeps its
79
- * value empty, and still counts as "present" for testing — so the mask is never
80
- * sent back as a new value. Typing overrides the mask for that field.
81
- */
82
- masked?: { deepseek?: boolean; feishu?: boolean };
83
- }
84
- export declare function IntegrationSettings(props: IntegrationSettingsProps): JSX.Element;