@agentaily/design-system 0.3.0 → 0.5.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/DESIGN.md +3 -3
- package/README.md +2 -2
- package/dist/components/auth/SignInPage.d.ts +42 -4
- package/dist/components/auth/SignInPage.js +84 -40
- package/dist/components/auth/SignInPage.js.map +1 -1
- package/dist/components/settings/IntegrationSettings.d.ts +73 -4
- package/dist/components/settings/IntegrationSettings.js +199 -141
- package/dist/components/settings/IntegrationSettings.js.map +1 -1
- package/dist/components/utilities/RotatingTagline.d.ts +30 -0
- package/dist/components/utilities/RotatingTagline.js +90 -0
- package/dist/components/utilities/RotatingTagline.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
3
3
|
import { Alert } from "../feedback/Alert.js";
|
|
4
4
|
import { Badge } from "../display/Badge.js";
|
|
5
5
|
import { BrandMark } from "../utilities/BrandMark.js";
|
|
@@ -9,6 +9,7 @@ import { Icon } from "../utilities/Icon.js";
|
|
|
9
9
|
import { IconButton } from "../buttons/IconButton.js";
|
|
10
10
|
import { SecretField } from "../inputs/SecretField.js";
|
|
11
11
|
import { Select } from "../inputs/Select.js";
|
|
12
|
+
import { Spinner } from "../feedback/Spinner.js";
|
|
12
13
|
import { StatusPill } from "../display/StatusPill.js";
|
|
13
14
|
import { Switch } from "../inputs/Switch.js";
|
|
14
15
|
import { TestRow } from "./TestRow.js";
|
|
@@ -129,7 +130,49 @@ const S_FIELD_MAP = [
|
|
|
129
130
|
{ from: null, to: "提交时间", tag: "自动" },
|
|
130
131
|
{ from: null, to: "来源链接", tag: "自动" }
|
|
131
132
|
];
|
|
132
|
-
|
|
133
|
+
const S_DEFAULTS = {
|
|
134
|
+
dsKey: "",
|
|
135
|
+
dsModel: "deepseek-chat",
|
|
136
|
+
capOn: false,
|
|
137
|
+
cap: "200",
|
|
138
|
+
dsStatus: "idle",
|
|
139
|
+
dsResult: "",
|
|
140
|
+
appId: "",
|
|
141
|
+
secret: "",
|
|
142
|
+
link: "",
|
|
143
|
+
fsStatus: "idle",
|
|
144
|
+
fsResult: "",
|
|
145
|
+
saved: false
|
|
146
|
+
};
|
|
147
|
+
function s_normalize(raw) {
|
|
148
|
+
const r = raw || {};
|
|
149
|
+
return {
|
|
150
|
+
dsKey: r.dsKey || "",
|
|
151
|
+
dsModel: r.dsModel || "deepseek-chat",
|
|
152
|
+
capOn: !!r.capOn,
|
|
153
|
+
cap: r.cap || "200",
|
|
154
|
+
dsStatus: r.dsStatus === "ok" ? "ok" : "idle",
|
|
155
|
+
dsResult: r.dsResult || "",
|
|
156
|
+
appId: r.appId || "",
|
|
157
|
+
secret: r.secret || "",
|
|
158
|
+
link: r.link || "",
|
|
159
|
+
fsStatus: r.fsStatus === "ok" ? "ok" : "idle",
|
|
160
|
+
fsResult: r.fsResult || "",
|
|
161
|
+
saved: !!r.saved
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function IntegrationSettings({
|
|
165
|
+
onClose,
|
|
166
|
+
showUsageCap = true,
|
|
167
|
+
storageKey = S_LS_KEY,
|
|
168
|
+
value,
|
|
169
|
+
onChange,
|
|
170
|
+
onSave,
|
|
171
|
+
onTest,
|
|
172
|
+
readiness,
|
|
173
|
+
masked
|
|
174
|
+
}) {
|
|
175
|
+
const controlled = value !== void 0;
|
|
133
176
|
const load = () => {
|
|
134
177
|
try {
|
|
135
178
|
return JSON.parse(localStorage.getItem(storageKey)) || {};
|
|
@@ -137,20 +180,33 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
137
180
|
return {};
|
|
138
181
|
}
|
|
139
182
|
};
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
183
|
+
const [localCfg, setLocalCfg] = useState(() => controlled ? S_DEFAULTS : s_normalize(load()));
|
|
184
|
+
const cfg = controlled ? { ...S_DEFAULTS, ...value } : localCfg;
|
|
185
|
+
const {
|
|
186
|
+
dsKey,
|
|
187
|
+
dsModel,
|
|
188
|
+
capOn,
|
|
189
|
+
cap,
|
|
190
|
+
dsStatus,
|
|
191
|
+
dsResult,
|
|
192
|
+
appId,
|
|
193
|
+
secret,
|
|
194
|
+
link,
|
|
195
|
+
fsStatus,
|
|
196
|
+
fsResult,
|
|
197
|
+
saved
|
|
198
|
+
} = cfg;
|
|
199
|
+
const cfgRef = useRef(cfg);
|
|
200
|
+
cfgRef.current = cfg;
|
|
201
|
+
const update = (partial) => {
|
|
202
|
+
if (controlled) {
|
|
203
|
+
if (onChange) onChange({ ...cfgRef.current, ...partial });
|
|
204
|
+
} else setLocalCfg((c) => ({ ...c, ...partial }));
|
|
205
|
+
};
|
|
152
206
|
const [dirty, setDirty] = useState(false);
|
|
153
|
-
const [
|
|
207
|
+
const [saving, setSaving] = useState(false);
|
|
208
|
+
const [dsKeyEdited, setDsKeyEdited] = useState(false);
|
|
209
|
+
const [secretEdited, setSecretEdited] = useState(false);
|
|
154
210
|
useEffect(() => {
|
|
155
211
|
const onKey = (e) => {
|
|
156
212
|
if (e.key === "Escape") onClose && onClose();
|
|
@@ -158,124 +214,130 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
158
214
|
window.addEventListener("keydown", onKey);
|
|
159
215
|
return () => window.removeEventListener("keydown", onKey);
|
|
160
216
|
}, [onClose]);
|
|
161
|
-
const parsed = s_parseFeishu(link);
|
|
162
|
-
const dsConnected = dsStatus === "ok";
|
|
163
|
-
const fsConnected = fsStatus === "ok";
|
|
164
|
-
const readyCount = (dsConnected ? 1 : 0) + (fsConnected ? 1 : 0);
|
|
165
|
-
const allReady = dsConnected && fsConnected;
|
|
166
217
|
useEffect(() => {
|
|
167
|
-
|
|
168
|
-
dsKey,
|
|
169
|
-
dsModel,
|
|
170
|
-
capOn,
|
|
171
|
-
cap,
|
|
172
|
-
dsStatus,
|
|
173
|
-
dsResult,
|
|
174
|
-
appId,
|
|
175
|
-
secret,
|
|
176
|
-
link,
|
|
177
|
-
fsStatus,
|
|
178
|
-
fsResult,
|
|
179
|
-
saved
|
|
180
|
-
};
|
|
218
|
+
if (controlled) return;
|
|
181
219
|
try {
|
|
182
|
-
localStorage.setItem(storageKey, JSON.stringify(
|
|
220
|
+
localStorage.setItem(storageKey, JSON.stringify(localCfg));
|
|
183
221
|
} catch (e) {
|
|
184
222
|
}
|
|
185
|
-
}, [
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
saved,
|
|
198
|
-
storageKey
|
|
199
|
-
]);
|
|
200
|
-
const touch = () => {
|
|
223
|
+
}, [controlled, localCfg, storageKey]);
|
|
224
|
+
const parsed = s_parseFeishu(link);
|
|
225
|
+
const dsConnected = readiness ? !!readiness.deepseek : dsStatus === "ok";
|
|
226
|
+
const fsConnected = readiness ? !!readiness.feishu : fsStatus === "ok";
|
|
227
|
+
const dsPill = dsStatus === "testing" || dsStatus === "error" ? dsStatus : dsConnected ? "ok" : "idle";
|
|
228
|
+
const fsPill = fsStatus === "testing" || fsStatus === "error" ? fsStatus : fsConnected ? "ok" : "idle";
|
|
229
|
+
const readyCount = (dsConnected ? 1 : 0) + (fsConnected ? 1 : 0);
|
|
230
|
+
const allReady = dsConnected && fsConnected;
|
|
231
|
+
const maskedDs = !!(masked && masked.deepseek) && !dsKeyEdited;
|
|
232
|
+
const maskedFs = !!(masked && masked.feishu) && !secretEdited;
|
|
233
|
+
const setCfg = (partial) => {
|
|
234
|
+
update({ ...partial, saved: false });
|
|
201
235
|
setDirty(true);
|
|
202
|
-
setSaved(false);
|
|
203
236
|
};
|
|
204
|
-
const editDs = (
|
|
205
|
-
|
|
206
|
-
if (dsStatus !== "idle") {
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
const editDs = (key) => (v) => {
|
|
238
|
+
const patch = { [key]: v, saved: false };
|
|
239
|
+
if (cfgRef.current.dsStatus !== "idle") {
|
|
240
|
+
patch.dsStatus = "idle";
|
|
241
|
+
patch.dsResult = "";
|
|
209
242
|
}
|
|
210
|
-
|
|
243
|
+
update(patch);
|
|
244
|
+
setDirty(true);
|
|
211
245
|
};
|
|
212
|
-
const editFs = (
|
|
213
|
-
|
|
214
|
-
if (fsStatus !== "idle") {
|
|
215
|
-
|
|
216
|
-
|
|
246
|
+
const editFs = (key) => (v) => {
|
|
247
|
+
const patch = { [key]: v, saved: false };
|
|
248
|
+
if (cfgRef.current.fsStatus !== "idle") {
|
|
249
|
+
patch.fsStatus = "idle";
|
|
250
|
+
patch.fsResult = "";
|
|
217
251
|
}
|
|
218
|
-
|
|
252
|
+
update(patch);
|
|
253
|
+
setDirty(true);
|
|
219
254
|
};
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
255
|
+
const editDsKey = (v) => {
|
|
256
|
+
if (!dsKeyEdited) setDsKeyEdited(true);
|
|
257
|
+
editDs("dsKey")(v);
|
|
258
|
+
};
|
|
259
|
+
const editSecret = (v) => {
|
|
260
|
+
if (!secretEdited) setSecretEdited(true);
|
|
261
|
+
editFs("secret")(v);
|
|
262
|
+
};
|
|
263
|
+
const setTest = (which, status, result, finalize) => {
|
|
264
|
+
const patch = which === "deepseek" ? { dsStatus: status, dsResult: result } : { fsStatus: status, fsResult: result };
|
|
265
|
+
if (finalize) patch.saved = false;
|
|
266
|
+
update(patch);
|
|
267
|
+
if (finalize) setDirty(true);
|
|
268
|
+
};
|
|
269
|
+
const builtinTest = async (which) => {
|
|
270
|
+
if (which === "deepseek") {
|
|
271
|
+
setTest("deepseek", "testing", "", false);
|
|
272
|
+
await s_sleep(1300);
|
|
273
|
+
const k = cfgRef.current.dsKey.trim();
|
|
274
|
+
if (k.startsWith("sk-") && k.length >= 20)
|
|
275
|
+
setTest("deepseek", "ok", `连接正常 · 延迟 0.4s · ${cfgRef.current.dsModel}`, true);
|
|
276
|
+
else
|
|
277
|
+
setTest(
|
|
278
|
+
"deepseek",
|
|
279
|
+
"error",
|
|
280
|
+
k ? "密钥无效或额度不足,请核对后重试" : "请先填写 API Key",
|
|
281
|
+
true
|
|
282
|
+
);
|
|
228
283
|
} else {
|
|
229
|
-
|
|
230
|
-
|
|
284
|
+
setTest("feishu", "testing", "", false);
|
|
285
|
+
await s_sleep(1500);
|
|
286
|
+
const c = cfgRef.current;
|
|
287
|
+
const p = s_parseFeishu(c.link);
|
|
288
|
+
if (!c.appId.trim() || !c.secret.trim())
|
|
289
|
+
return setTest("feishu", "error", "缺少 App ID 或 App Secret", true);
|
|
290
|
+
if (!p) return setTest("feishu", "error", "无法识别多维表格链接,请粘贴完整 URL", true);
|
|
291
|
+
if (!p.table) return setTest("feishu", "error", "链接缺少数据表 (table) 参数", true);
|
|
292
|
+
setTest("feishu", "ok", "已连接 ·「报名登记表」· 检测到 6 个字段", true);
|
|
231
293
|
}
|
|
232
|
-
touch();
|
|
233
294
|
};
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
295
|
+
const runTest = async (which) => {
|
|
296
|
+
if (onTest) {
|
|
297
|
+
setTest(which, "testing", "", false);
|
|
298
|
+
try {
|
|
299
|
+
const res = await onTest(which);
|
|
300
|
+
const ok = !!(res && res.ok);
|
|
301
|
+
setTest(
|
|
302
|
+
which,
|
|
303
|
+
ok ? "ok" : "error",
|
|
304
|
+
res && res.message || (ok ? "连接正常" : "连接失败"),
|
|
305
|
+
true
|
|
306
|
+
);
|
|
307
|
+
} catch (e) {
|
|
308
|
+
setTest(which, "error", e && e.message || "测试失败", true);
|
|
309
|
+
}
|
|
242
310
|
return;
|
|
243
311
|
}
|
|
244
|
-
|
|
245
|
-
setFsStatus("error");
|
|
246
|
-
setFsResult("无法识别多维表格链接,请粘贴完整 URL");
|
|
247
|
-
touch();
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
if (!parsed.table) {
|
|
251
|
-
setFsStatus("error");
|
|
252
|
-
setFsResult("链接缺少数据表 (table) 参数");
|
|
253
|
-
touch();
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
setFsStatus("ok");
|
|
257
|
-
setFsResult("已连接 ·「报名登记表」· 检测到 6 个字段");
|
|
258
|
-
touch();
|
|
312
|
+
builtinTest(which);
|
|
259
313
|
};
|
|
260
|
-
const
|
|
261
|
-
setSaved(true);
|
|
314
|
+
const afterSaved = () => {
|
|
262
315
|
setDirty(false);
|
|
316
|
+
setDsKeyEdited(false);
|
|
317
|
+
setSecretEdited(false);
|
|
318
|
+
};
|
|
319
|
+
const doSave = async () => {
|
|
320
|
+
if (onSave) {
|
|
321
|
+
setSaving(true);
|
|
322
|
+
try {
|
|
323
|
+
await onSave(cfgRef.current);
|
|
324
|
+
update({ saved: true });
|
|
325
|
+
afterSaved();
|
|
326
|
+
} catch (e) {
|
|
327
|
+
} finally {
|
|
328
|
+
setSaving(false);
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
update({ saved: true });
|
|
332
|
+
afterSaved();
|
|
333
|
+
}
|
|
263
334
|
};
|
|
264
335
|
const onDiscard = () => {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
setDsModel(b.dsModel || "deepseek-chat");
|
|
268
|
-
setCapOn(!!b.capOn);
|
|
269
|
-
setCap(b.cap || "200");
|
|
270
|
-
setDsStatus(b.dsStatus === "ok" ? "ok" : "idle");
|
|
271
|
-
setDsResult(b.dsResult || "");
|
|
272
|
-
setAppId(b.appId || "");
|
|
273
|
-
setSecret(b.secret || "");
|
|
274
|
-
setLink(b.link || "");
|
|
275
|
-
setFsStatus(b.fsStatus === "ok" ? "ok" : "idle");
|
|
276
|
-
setFsResult(b.fsResult || "");
|
|
277
|
-
setSaved(!!b.saved);
|
|
336
|
+
setDsKeyEdited(false);
|
|
337
|
+
setSecretEdited(false);
|
|
278
338
|
setDirty(false);
|
|
339
|
+
if (controlled) return;
|
|
340
|
+
setLocalCfg(s_normalize(load()));
|
|
279
341
|
};
|
|
280
342
|
return /* @__PURE__ */ jsx("div", { className: "s-overlay", role: "dialog", "aria-modal": "true", "aria-label": "集成设置", children: /* @__PURE__ */ jsxs("div", { className: "s-modal", children: [
|
|
281
343
|
/* @__PURE__ */ jsxs("header", { className: "s-modal__bar", children: [
|
|
@@ -318,13 +380,13 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
318
380
|
/* @__PURE__ */ jsxs(
|
|
319
381
|
"section",
|
|
320
382
|
{
|
|
321
|
-
className: "s-card" + (
|
|
383
|
+
className: "s-card" + (dsPill === "ok" ? " is-ok" : dsPill === "error" ? " is-error" : ""),
|
|
322
384
|
children: [
|
|
323
385
|
/* @__PURE__ */ jsxs("div", { className: "s-card__head", children: [
|
|
324
386
|
/* @__PURE__ */ jsxs("div", { className: "s-card__toprow", children: [
|
|
325
387
|
/* @__PURE__ */ jsx("div", { className: "s-card__icon", children: /* @__PURE__ */ jsx(Icon, { name: "key", size: 16 }) }),
|
|
326
388
|
/* @__PURE__ */ jsx("span", { className: "ax-label s-card__eyebrow", children: "对话引擎 · LLM" }),
|
|
327
|
-
/* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status:
|
|
389
|
+
/* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status: dsPill }) })
|
|
328
390
|
] }),
|
|
329
391
|
/* @__PURE__ */ jsx("h2", { className: "s-card__title", children: "DeepSeek" }),
|
|
330
392
|
/* @__PURE__ */ jsx("p", { className: "s-card__desc", children: "驱动对话式交互。用户发送的每一条消息,都通过这把密钥调用 DeepSeek 补全。" })
|
|
@@ -335,9 +397,10 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
335
397
|
{
|
|
336
398
|
label: "API KEY",
|
|
337
399
|
value: dsKey,
|
|
338
|
-
onChange:
|
|
339
|
-
placeholder: "sk-xxxxxxxxxxxxxxxxxxxxxxxx",
|
|
340
|
-
|
|
400
|
+
onChange: editDsKey,
|
|
401
|
+
placeholder: maskedDs ? "已保存 ········ · 留空则保持不变" : "sk-xxxxxxxxxxxxxxxxxxxxxxxx",
|
|
402
|
+
hint: maskedDs ? "已存密钥 · 留空表示不修改,输入新值即覆盖" : void 0,
|
|
403
|
+
error: !maskedDs && dsStatus === "error" && !dsKey.trim() ? "此项必填" : void 0
|
|
341
404
|
}
|
|
342
405
|
),
|
|
343
406
|
/* @__PURE__ */ jsxs("div", { className: "s-lock", children: [
|
|
@@ -354,7 +417,7 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
354
417
|
Select,
|
|
355
418
|
{
|
|
356
419
|
value: dsModel,
|
|
357
|
-
onChange: (e) => editDs(
|
|
420
|
+
onChange: (e) => editDs("dsModel")(e.target.value),
|
|
358
421
|
options: [
|
|
359
422
|
{ value: "deepseek-chat", label: "deepseek-chat · 通用 · 快" },
|
|
360
423
|
{ value: "deepseek-reasoner", label: "deepseek-reasoner · 深度推理" }
|
|
@@ -378,10 +441,7 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
378
441
|
{
|
|
379
442
|
label: "启用每月用量上限",
|
|
380
443
|
checked: capOn,
|
|
381
|
-
onChange: (e) => {
|
|
382
|
-
setCapOn(e.target.checked);
|
|
383
|
-
touch();
|
|
384
|
-
}
|
|
444
|
+
onChange: (e) => setCfg({ capOn: e.target.checked })
|
|
385
445
|
}
|
|
386
446
|
),
|
|
387
447
|
/* @__PURE__ */ jsxs("div", { className: "s-cap__field", style: { display: capOn ? "flex" : "none" }, children: [
|
|
@@ -392,10 +452,7 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
392
452
|
type: "text",
|
|
393
453
|
inputMode: "numeric",
|
|
394
454
|
value: cap,
|
|
395
|
-
onChange: (e) => {
|
|
396
|
-
setCap(e.target.value.replace(/[^0-9]/g, ""));
|
|
397
|
-
touch();
|
|
398
|
-
},
|
|
455
|
+
onChange: (e) => setCfg({ cap: e.target.value.replace(/[^0-9]/g, "") }),
|
|
399
456
|
"aria-label": "每月上限(元)"
|
|
400
457
|
}
|
|
401
458
|
),
|
|
@@ -433,8 +490,8 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
433
490
|
{
|
|
434
491
|
status: dsStatus,
|
|
435
492
|
result: dsResult,
|
|
436
|
-
onTest:
|
|
437
|
-
disabled: !dsKey.trim(),
|
|
493
|
+
onTest: () => runTest("deepseek"),
|
|
494
|
+
disabled: !dsKey.trim() && !maskedDs,
|
|
438
495
|
idleHint: "填写密钥后测试连通性"
|
|
439
496
|
}
|
|
440
497
|
)
|
|
@@ -444,13 +501,13 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
444
501
|
/* @__PURE__ */ jsxs(
|
|
445
502
|
"section",
|
|
446
503
|
{
|
|
447
|
-
className: "s-card" + (
|
|
504
|
+
className: "s-card" + (fsPill === "ok" ? " is-ok" : fsPill === "error" ? " is-error" : ""),
|
|
448
505
|
children: [
|
|
449
506
|
/* @__PURE__ */ jsxs("div", { className: "s-card__head", children: [
|
|
450
507
|
/* @__PURE__ */ jsxs("div", { className: "s-card__toprow", children: [
|
|
451
508
|
/* @__PURE__ */ jsx("div", { className: "s-card__icon", children: /* @__PURE__ */ jsx(Icon, { name: "table", size: 16 }) }),
|
|
452
509
|
/* @__PURE__ */ jsx("span", { className: "ax-label s-card__eyebrow", children: "数据写入 · FEISHU BITABLE" }),
|
|
453
|
-
/* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status:
|
|
510
|
+
/* @__PURE__ */ jsx("span", { className: "s-card__status", children: /* @__PURE__ */ jsx(StatusPill, { status: fsPill }) })
|
|
454
511
|
] }),
|
|
455
512
|
/* @__PURE__ */ jsx("h2", { className: "s-card__title", children: "飞书多维表格" }),
|
|
456
513
|
/* @__PURE__ */ jsx("p", { className: "s-card__desc", children: "每次提交后,数据自动写入指定多维表格的一行。需要一个飞书自建应用的凭证,以及目标表格的链接。" })
|
|
@@ -467,7 +524,7 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
467
524
|
value: appId,
|
|
468
525
|
spellCheck: "false",
|
|
469
526
|
placeholder: "cli_xxxxxxxxxxxx",
|
|
470
|
-
onChange: (e) => editFs(
|
|
527
|
+
onChange: (e) => editFs("appId")(e.target.value)
|
|
471
528
|
}
|
|
472
529
|
),
|
|
473
530
|
/* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "应用标识,可公开。" })
|
|
@@ -477,9 +534,9 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
477
534
|
{
|
|
478
535
|
label: "App Secret",
|
|
479
536
|
value: secret,
|
|
480
|
-
onChange:
|
|
481
|
-
placeholder: "••••••••••••••••",
|
|
482
|
-
hint: "应用密钥,加密存储。"
|
|
537
|
+
onChange: editSecret,
|
|
538
|
+
placeholder: maskedFs ? "已保存 ········ · 留空则保持不变" : "••••••••••••••••",
|
|
539
|
+
hint: maskedFs ? "已存密钥 · 留空表示不修改" : "应用密钥,加密存储。"
|
|
483
540
|
}
|
|
484
541
|
)
|
|
485
542
|
] }),
|
|
@@ -493,7 +550,7 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
493
550
|
value: link,
|
|
494
551
|
spellCheck: "false",
|
|
495
552
|
placeholder: "https://your-team.feishu.cn/base/bascn…?table=tbl…",
|
|
496
|
-
onChange: (e) => editFs(
|
|
553
|
+
onChange: (e) => editFs("link")(e.target.value)
|
|
497
554
|
}
|
|
498
555
|
),
|
|
499
556
|
/* @__PURE__ */ jsx("p", { className: "s-field__hint", children: "在多维表格右上角「分享」中复制链接粘贴即可,App Token 与数据表会自动识别。" })
|
|
@@ -586,8 +643,8 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
586
643
|
{
|
|
587
644
|
status: fsStatus,
|
|
588
645
|
result: fsResult,
|
|
589
|
-
onTest:
|
|
590
|
-
disabled: !appId.trim() || !secret.trim() || !parsed,
|
|
646
|
+
onTest: () => runTest("feishu"),
|
|
647
|
+
disabled: !appId.trim() || !secret.trim() && !maskedFs || !parsed,
|
|
591
648
|
idleHint: "填写凭证与链接后测试写入权限"
|
|
592
649
|
}
|
|
593
650
|
)
|
|
@@ -614,9 +671,10 @@ function IntegrationSettings({ onClose, showUsageCap = true, storageKey = S_LS_K
|
|
|
614
671
|
{
|
|
615
672
|
variant: "primary",
|
|
616
673
|
size: "md",
|
|
617
|
-
icon: /* @__PURE__ */ jsx(Icon, { name: "save", size: 14 }),
|
|
618
|
-
disabled: !allReady || !dirty,
|
|
619
|
-
|
|
674
|
+
icon: saving ? /* @__PURE__ */ jsx(Spinner, { size: "sm" }) : /* @__PURE__ */ jsx(Icon, { name: "save", size: 14 }),
|
|
675
|
+
disabled: !allReady || !dirty || saving,
|
|
676
|
+
"aria-busy": saving || void 0,
|
|
677
|
+
onClick: doSave,
|
|
620
678
|
children: "保存配置"
|
|
621
679
|
}
|
|
622
680
|
)
|