@dsh-plus/image-studio 0.1.22 → 0.1.23
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 +616 -437
- package/package.json +2 -2
- package/src/client/card.tsx +145 -474
- package/src/client/draft.ts +128 -0
- package/src/client/preset-sections.tsx +321 -0
- package/src/client/styles.ts +9 -0
package/lib/client.js
CHANGED
|
@@ -277,9 +277,72 @@ window.__ModuleLoader__.load({
|
|
|
277
277
|
kind: "idle",
|
|
278
278
|
text: ""
|
|
279
279
|
};
|
|
280
|
+
/** 状态行 + 动作按钮(两种形态共用,类名随形态切换度量)。 */
|
|
281
|
+
function CardFoot(props) {
|
|
282
|
+
const p = props.prefix;
|
|
283
|
+
const section = props.variant === "section";
|
|
284
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
285
|
+
className: section ? `${p}-sectionFooter` : `${p}-footer`,
|
|
286
|
+
children: [props.status !== void 0 && props.status.kind !== "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
287
|
+
className: `${p}-status${props.status.kind === "error" ? ` ${p}-statusError` : ""}`,
|
|
288
|
+
role: "status",
|
|
289
|
+
children: props.status.text
|
|
290
|
+
}) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
291
|
+
type: "button",
|
|
292
|
+
className: `${p}-btn ${action.variant === "primary" ? `${p}-btnPrimary` : `${p}-btnGhost`}`,
|
|
293
|
+
disabled: action.disabled === true,
|
|
294
|
+
onClick: action.onClick,
|
|
295
|
+
children: action.label
|
|
296
|
+
}, action.key))]
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
/** 只读提示 + 字段区 + 页脚(两种形态共用)。 */
|
|
300
|
+
function CardBody(props) {
|
|
301
|
+
const p = props.prefix;
|
|
302
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
303
|
+
props.readOnlyNotice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
304
|
+
className: `${p}-readOnly`,
|
|
305
|
+
role: "status",
|
|
306
|
+
children: props.readOnlyNotice
|
|
307
|
+
}) : null,
|
|
308
|
+
props.children,
|
|
309
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardFoot, { ...props })
|
|
310
|
+
] });
|
|
311
|
+
}
|
|
280
312
|
function CardChrome(props) {
|
|
281
313
|
const p = props.prefix;
|
|
282
314
|
const badge = props.statusBadge;
|
|
315
|
+
if (props.variant === "section") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
316
|
+
className: `${p}-section`,
|
|
317
|
+
"aria-label": props.title,
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
320
|
+
className: `${p}-sectionHead`,
|
|
321
|
+
children: [
|
|
322
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
323
|
+
className: `${p}-sectionTitle`,
|
|
324
|
+
children: props.title
|
|
325
|
+
}),
|
|
326
|
+
badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
327
|
+
className: `${p}-sectionBadge ${badge.on ? `${p}-statusOn` : `${p}-statusOff`}`,
|
|
328
|
+
children: badge.text
|
|
329
|
+
}) : null,
|
|
330
|
+
props.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
331
|
+
className: `${p}-pending`,
|
|
332
|
+
children: props.dirtyLabel
|
|
333
|
+
}) : null
|
|
334
|
+
]
|
|
335
|
+
}),
|
|
336
|
+
props.description === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
337
|
+
className: `${p}-sectionDesc`,
|
|
338
|
+
children: props.description
|
|
339
|
+
}),
|
|
340
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
341
|
+
className: `${p}-sectionBody`,
|
|
342
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, { ...props })
|
|
343
|
+
})
|
|
344
|
+
]
|
|
345
|
+
});
|
|
283
346
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
284
347
|
className: `${p}-card${props.open ? ` ${p}-cardOpen` : ""}`,
|
|
285
348
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -309,38 +372,44 @@ window.__ModuleLoader__.load({
|
|
|
309
372
|
}) : null,
|
|
310
373
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
|
|
311
374
|
]
|
|
312
|
-
}), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
375
|
+
}), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
313
376
|
className: `${p}-body`,
|
|
314
|
-
children:
|
|
315
|
-
props.readOnlyNotice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
316
|
-
className: `${p}-readOnly`,
|
|
317
|
-
role: "status",
|
|
318
|
-
children: props.readOnlyNotice
|
|
319
|
-
}) : null,
|
|
320
|
-
props.children,
|
|
321
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
322
|
-
className: `${p}-footer`,
|
|
323
|
-
children: [props.status !== void 0 && props.status.kind !== "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
324
|
-
className: `${p}-status${props.status.kind === "error" ? ` ${p}-statusError` : ""}`,
|
|
325
|
-
role: "status",
|
|
326
|
-
children: props.status.text
|
|
327
|
-
}) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
328
|
-
type: "button",
|
|
329
|
-
className: `${p}-btn ${action.variant === "primary" ? `${p}-btnPrimary` : `${p}-btnGhost`}`,
|
|
330
|
-
disabled: action.disabled === true,
|
|
331
|
-
onClick: action.onClick,
|
|
332
|
-
children: action.label
|
|
333
|
-
}, action.key))]
|
|
334
|
-
})
|
|
335
|
-
]
|
|
377
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, { ...props })
|
|
336
378
|
}) : null]
|
|
337
379
|
});
|
|
338
380
|
}
|
|
381
|
+
/** 取值未到达时的占位:与 CardChrome 同形态,避免宿主页里闪一次卡片外壳。 */
|
|
382
|
+
function CardLoading(props) {
|
|
383
|
+
if (props.variant === "section") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
384
|
+
className: `${props.prefix}-section`,
|
|
385
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
386
|
+
className: `${props.prefix}-readOnly`,
|
|
387
|
+
role: "status",
|
|
388
|
+
children: props.text
|
|
389
|
+
})
|
|
390
|
+
});
|
|
391
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
392
|
+
className: `${props.prefix}-card`,
|
|
393
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
394
|
+
className: `${props.prefix}-readOnly`,
|
|
395
|
+
role: "status",
|
|
396
|
+
children: props.text
|
|
397
|
+
})
|
|
398
|
+
});
|
|
399
|
+
}
|
|
339
400
|
//#endregion
|
|
340
401
|
//#region ../shared/src/client/config-slots.ts
|
|
341
402
|
/** dsh-plus 聚合 bundle 的包名(各插件 row 均经其补丁层插入 profile)。 */
|
|
342
403
|
const DSH_PLUS_BUNDLE = "@dsh-plus/bundle-main";
|
|
343
404
|
/**
|
|
405
|
+
* 视图 → 外壳形态:插件页 page 视图渲染在官方页面容器内(宿主已画标题、图标、
|
|
406
|
+
* 面包屑与页面级内边距),再套卡片会形成卡片套卡片并压缩移动端可用宽度,
|
|
407
|
+
* 故用无边框分节;summary 与 legacy 槽位保持卡片形态。
|
|
408
|
+
*/
|
|
409
|
+
function cardVariantFor(view) {
|
|
410
|
+
return view === "page" ? "section" : "card";
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
344
413
|
* 把一张配置卡片同时注册进 legacy 与新版三个槽位。
|
|
345
414
|
* 任一槽位在当前 dsh 版本未声明时对应 inject 挂起等待,版本不命中即 no-op。
|
|
346
415
|
*/
|
|
@@ -366,6 +435,17 @@ window.__ModuleLoader__.load({
|
|
|
366
435
|
}, reg.component));
|
|
367
436
|
}
|
|
368
437
|
//#endregion
|
|
438
|
+
//#region ../shared/src/client/draft.ts
|
|
439
|
+
/**
|
|
440
|
+
* 单命名空间 staged 草稿(简单配置卡片共用):读 scope 快照、播种草稿、
|
|
441
|
+
* 脏判定、保存(revision fencing + 重新装载)与状态行。
|
|
442
|
+
*
|
|
443
|
+
* 语义与官方 staged 表单一致:Host 更新不覆盖在途编辑,只有保存才写回;
|
|
444
|
+
* 保存成功后按 Host 解析值重置草稿。`from`/`patch` 参与 effect 与 useMemo
|
|
445
|
+
* 依赖,必须是模块级稳定函数(不要内联箭头函数)。
|
|
446
|
+
* @module @dsh-plus/shared/client/draft
|
|
447
|
+
*/
|
|
448
|
+
//#endregion
|
|
369
449
|
//#region ../shared/src/client/fetch.ts
|
|
370
450
|
async function parse(res, guard) {
|
|
371
451
|
const body = await res.json();
|
|
@@ -520,6 +600,9 @@ window.__ModuleLoader__.load({
|
|
|
520
600
|
* - 窄屏 input/textarea 16px(防 iOS 聚焦缩放)、可点目标 ≥44px;
|
|
521
601
|
* - footer 按钮等宽换行、状态文字独占一行;
|
|
522
602
|
* - 展开态 body 底部 sticky 保存栏(长表单滚动中始终可达)。
|
|
603
|
+
* - 分节形态(-section,插件页 page 视图内嵌宿主页面):无边框/背景、横向零
|
|
604
|
+
* 内边距,页脚不 sticky——官方插件页已提供页面级内边距,再叠一层卡片会
|
|
605
|
+
* 缩窄移动端可用宽度(卡片套卡片)。
|
|
523
606
|
* 沿用官方 data-plugin / data-plugin-css 约定(HMR 据此卸载),不覆盖上游选择器。
|
|
524
607
|
* @module @dsh-plus/shared/client/styles
|
|
525
608
|
*/
|
|
@@ -566,6 +649,15 @@ window.__ModuleLoader__.load({
|
|
|
566
649
|
.${prefix}-checkRow input:checked::after{left:16px;background:var(--dsw-alias-bg-base)}
|
|
567
650
|
.${prefix}-checkRow input:disabled{opacity:.4;cursor:default}
|
|
568
651
|
.${prefix}-checkRow input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
652
|
+
/* 宿主内嵌分节形态(插件页 page 视图):官方设置页同构——无边框/背景,
|
|
653
|
+
横向零内边距(宽度交给宿主页面容器),小节标题 13px/600,页脚非 sticky。 */
|
|
654
|
+
.${prefix}-section{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;padding:16px 0;display:flex}
|
|
655
|
+
.${prefix}-sectionHead{align-items:center;gap:8px;min-width:0;display:flex}
|
|
656
|
+
.${prefix}-sectionTitle{min-width:0;color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
657
|
+
.${prefix}-sectionBadge{white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
658
|
+
.${prefix}-sectionDesc{color:var(--dsw-alias-label-tertiary);margin:4px 0 0;font-size:12px;line-height:1.5}
|
|
659
|
+
.${prefix}-sectionBody{flex-direction:column;min-width:0;display:flex}
|
|
660
|
+
.${prefix}-sectionFooter{align-items:center;gap:8px;padding-top:16px;display:flex;flex-wrap:wrap}
|
|
569
661
|
.${prefix}-groupLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;padding:12px 0 2px;margin:0}
|
|
570
662
|
.${prefix}-readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}
|
|
571
663
|
.${prefix}-warn{color:var(--dsw-alias-label-error);margin:12px 0 0;font-size:12px;line-height:1.5}
|
|
@@ -587,6 +679,8 @@ window.__ModuleLoader__.load({
|
|
|
587
679
|
.${prefix}-status{flex-basis:100%;flex:none}
|
|
588
680
|
.${prefix}-btn{min-height:44px;flex:1;min-width:96px}
|
|
589
681
|
.${prefix}-statusBadge{display:none}
|
|
682
|
+
.${prefix}-sectionBadge{display:inline-block}
|
|
683
|
+
.${prefix}-sectionFooter{position:static}
|
|
590
684
|
}
|
|
591
685
|
@media (pointer:coarse){
|
|
592
686
|
.${prefix}-btn{min-height:44px}
|
|
@@ -624,6 +718,90 @@ ${extra}
|
|
|
624
718
|
*/
|
|
625
719
|
const SETTINGS_NS = "dsh-plus-image-studio";
|
|
626
720
|
//#endregion
|
|
721
|
+
//#region src/client/api.ts
|
|
722
|
+
/**
|
|
723
|
+
* 数据端点通道(前端预留):同源 fetch 封装,类型与 dto.ts 对齐。
|
|
724
|
+
* 本次仅交付通道层,不交付调用它的界面。
|
|
725
|
+
* @module image-studio/client/api
|
|
726
|
+
*/
|
|
727
|
+
const BASE = "/dsh-plus/image-studio";
|
|
728
|
+
/** 提交生图任务。 */
|
|
729
|
+
function generate(request) {
|
|
730
|
+
return postJson(`${BASE}/generate`, request);
|
|
731
|
+
}
|
|
732
|
+
/** 批量任务轮询。 */
|
|
733
|
+
function fetchTasks() {
|
|
734
|
+
return getJson(`${BASE}/tasks`);
|
|
735
|
+
}
|
|
736
|
+
/** 取消任务。 */
|
|
737
|
+
function cancelTask(taskId) {
|
|
738
|
+
return postJson(`${BASE}/tasks/${taskId}/cancel`);
|
|
739
|
+
}
|
|
740
|
+
/** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
|
|
741
|
+
function isGalleryList(value) {
|
|
742
|
+
if (typeof value !== "object" || value === null) return false;
|
|
743
|
+
return Array.isArray(value.items);
|
|
744
|
+
}
|
|
745
|
+
/** 画廊列表。 */
|
|
746
|
+
function fetchGallery() {
|
|
747
|
+
return getJson(`${BASE}/gallery`, isGalleryList);
|
|
748
|
+
}
|
|
749
|
+
/** 删除画廊条目。 */
|
|
750
|
+
function deleteGalleryItem(itemId) {
|
|
751
|
+
return fetch(`${BASE}/gallery/${itemId}`, {
|
|
752
|
+
method: "DELETE",
|
|
753
|
+
credentials: "same-origin"
|
|
754
|
+
}).then((res) => res.json());
|
|
755
|
+
}
|
|
756
|
+
/** 图片 URL(<img src> 直连,非 fetch)。 */
|
|
757
|
+
function imageUrl(imageId) {
|
|
758
|
+
return `${BASE}/images/${imageId}`;
|
|
759
|
+
}
|
|
760
|
+
/** 上传原图 URL(缩略图直连,非 fetch)。 */
|
|
761
|
+
function uploadImageUrl(uploadId) {
|
|
762
|
+
return `${BASE}/uploads/${uploadId}`;
|
|
763
|
+
}
|
|
764
|
+
/** 上传本地图片:raw body 流(query 携带原文件名,仅展示用)。 */
|
|
765
|
+
async function uploadImage(file) {
|
|
766
|
+
const query = new URLSearchParams({ name: file.name });
|
|
767
|
+
const res = await fetch(`${BASE}/uploads?${query.toString()}`, {
|
|
768
|
+
method: "POST",
|
|
769
|
+
credentials: "same-origin",
|
|
770
|
+
headers: { "content-type": "application/octet-stream" },
|
|
771
|
+
body: file
|
|
772
|
+
});
|
|
773
|
+
const body = await res.json();
|
|
774
|
+
if (!res.ok) throw new Error(body.message ?? body.error ?? `HTTP ${res.status}`);
|
|
775
|
+
return body;
|
|
776
|
+
}
|
|
777
|
+
/** 上传列表(最新在后;界面自行倒序)。 */
|
|
778
|
+
async function fetchUploads() {
|
|
779
|
+
return getJson(`${BASE}/uploads`);
|
|
780
|
+
}
|
|
781
|
+
/** 凭据状态(describe,永不回传值)。 */
|
|
782
|
+
function fetchCredentialStatus(refName) {
|
|
783
|
+
return getJson(`${BASE}/credentials/${refName}`);
|
|
784
|
+
}
|
|
785
|
+
/** 设置凭据值。 */
|
|
786
|
+
function setCredential(refName, value) {
|
|
787
|
+
return postJson(`${BASE}/credentials/${refName}`, { value });
|
|
788
|
+
}
|
|
789
|
+
/** 删除凭据。 */
|
|
790
|
+
function unsetCredential(refName) {
|
|
791
|
+
return fetch(`${BASE}/credentials/${refName}`, {
|
|
792
|
+
method: "DELETE",
|
|
793
|
+
credentials: "same-origin"
|
|
794
|
+
}).then((res) => res.json());
|
|
795
|
+
}
|
|
796
|
+
/** 协议 registry + 参数目录。 */
|
|
797
|
+
function fetchProviders() {
|
|
798
|
+
return getJson(`${BASE}/providers`);
|
|
799
|
+
}
|
|
800
|
+
/** 预设只读快照(读写走官方 settings RPC)。 */
|
|
801
|
+
function fetchPresets() {
|
|
802
|
+
return getJson(`${BASE}/presets`);
|
|
803
|
+
}
|
|
804
|
+
//#endregion
|
|
627
805
|
//#region src/credentials.ts
|
|
628
806
|
/**
|
|
629
807
|
* 凭据引用名派生与校验:提供商预设 id → IMAGE_STUDIO_PRESET_<ID>。
|
|
@@ -938,100 +1116,7 @@ ${extra}
|
|
|
938
1116
|
return out;
|
|
939
1117
|
}
|
|
940
1118
|
//#endregion
|
|
941
|
-
//#region src/client/
|
|
942
|
-
/**
|
|
943
|
-
* 数据端点通道(前端预留):同源 fetch 封装,类型与 dto.ts 对齐。
|
|
944
|
-
* 本次仅交付通道层,不交付调用它的界面。
|
|
945
|
-
* @module image-studio/client/api
|
|
946
|
-
*/
|
|
947
|
-
const BASE = "/dsh-plus/image-studio";
|
|
948
|
-
/** 提交生图任务。 */
|
|
949
|
-
function generate(request) {
|
|
950
|
-
return postJson(`${BASE}/generate`, request);
|
|
951
|
-
}
|
|
952
|
-
/** 批量任务轮询。 */
|
|
953
|
-
function fetchTasks() {
|
|
954
|
-
return getJson(`${BASE}/tasks`);
|
|
955
|
-
}
|
|
956
|
-
/** 取消任务。 */
|
|
957
|
-
function cancelTask(taskId) {
|
|
958
|
-
return postJson(`${BASE}/tasks/${taskId}/cancel`);
|
|
959
|
-
}
|
|
960
|
-
/** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
|
|
961
|
-
function isGalleryList(value) {
|
|
962
|
-
if (typeof value !== "object" || value === null) return false;
|
|
963
|
-
return Array.isArray(value.items);
|
|
964
|
-
}
|
|
965
|
-
/** 画廊列表。 */
|
|
966
|
-
function fetchGallery() {
|
|
967
|
-
return getJson(`${BASE}/gallery`, isGalleryList);
|
|
968
|
-
}
|
|
969
|
-
/** 删除画廊条目。 */
|
|
970
|
-
function deleteGalleryItem(itemId) {
|
|
971
|
-
return fetch(`${BASE}/gallery/${itemId}`, {
|
|
972
|
-
method: "DELETE",
|
|
973
|
-
credentials: "same-origin"
|
|
974
|
-
}).then((res) => res.json());
|
|
975
|
-
}
|
|
976
|
-
/** 图片 URL(<img src> 直连,非 fetch)。 */
|
|
977
|
-
function imageUrl(imageId) {
|
|
978
|
-
return `${BASE}/images/${imageId}`;
|
|
979
|
-
}
|
|
980
|
-
/** 上传原图 URL(缩略图直连,非 fetch)。 */
|
|
981
|
-
function uploadImageUrl(uploadId) {
|
|
982
|
-
return `${BASE}/uploads/${uploadId}`;
|
|
983
|
-
}
|
|
984
|
-
/** 上传本地图片:raw body 流(query 携带原文件名,仅展示用)。 */
|
|
985
|
-
async function uploadImage(file) {
|
|
986
|
-
const query = new URLSearchParams({ name: file.name });
|
|
987
|
-
const res = await fetch(`${BASE}/uploads?${query.toString()}`, {
|
|
988
|
-
method: "POST",
|
|
989
|
-
credentials: "same-origin",
|
|
990
|
-
headers: { "content-type": "application/octet-stream" },
|
|
991
|
-
body: file
|
|
992
|
-
});
|
|
993
|
-
const body = await res.json();
|
|
994
|
-
if (!res.ok) throw new Error(body.message ?? body.error ?? `HTTP ${res.status}`);
|
|
995
|
-
return body;
|
|
996
|
-
}
|
|
997
|
-
/** 上传列表(最新在后;界面自行倒序)。 */
|
|
998
|
-
async function fetchUploads() {
|
|
999
|
-
return getJson(`${BASE}/uploads`);
|
|
1000
|
-
}
|
|
1001
|
-
/** 凭据状态(describe,永不回传值)。 */
|
|
1002
|
-
function fetchCredentialStatus(refName) {
|
|
1003
|
-
return getJson(`${BASE}/credentials/${refName}`);
|
|
1004
|
-
}
|
|
1005
|
-
/** 设置凭据值。 */
|
|
1006
|
-
function setCredential(refName, value) {
|
|
1007
|
-
return postJson(`${BASE}/credentials/${refName}`, { value });
|
|
1008
|
-
}
|
|
1009
|
-
/** 删除凭据。 */
|
|
1010
|
-
function unsetCredential(refName) {
|
|
1011
|
-
return fetch(`${BASE}/credentials/${refName}`, {
|
|
1012
|
-
method: "DELETE",
|
|
1013
|
-
credentials: "same-origin"
|
|
1014
|
-
}).then((res) => res.json());
|
|
1015
|
-
}
|
|
1016
|
-
/** 协议 registry + 参数目录。 */
|
|
1017
|
-
function fetchProviders() {
|
|
1018
|
-
return getJson(`${BASE}/providers`);
|
|
1019
|
-
}
|
|
1020
|
-
/** 预设只读快照(读写走官方 settings RPC)。 */
|
|
1021
|
-
function fetchPresets() {
|
|
1022
|
-
return getJson(`${BASE}/presets`);
|
|
1023
|
-
}
|
|
1024
|
-
//#endregion
|
|
1025
|
-
//#region src/client/card.tsx
|
|
1026
|
-
/**
|
|
1027
|
-
* 配置卡片(injectPluginConfigCard 三槽位,legacy key = settings 命名空间,
|
|
1028
|
-
* 0.1.6-alpha.2 起为插件页 row/bundle config,view 分发 summary/page):
|
|
1029
|
-
* 三组预设(提供商/参数/提示词)+ 高级项(并发/超时/代理/画廊上限)的
|
|
1030
|
-
* staged draft 编辑;提供商预设逐条附 API Key 管理(凭据端点,值不回显)。
|
|
1031
|
-
* JSON 字段(extraHeaders/paramSpecs)以文本镜像编辑,保存时解析 +
|
|
1032
|
-
* validateParamSpecs 本地校验,非法即拦在保存前。
|
|
1033
|
-
* @module image-studio/client/card
|
|
1034
|
-
*/
|
|
1119
|
+
//#region src/client/draft.ts
|
|
1035
1120
|
/** 配置值 → 编辑草稿。 */
|
|
1036
1121
|
function draftOf(value) {
|
|
1037
1122
|
return {
|
|
@@ -1103,6 +1188,41 @@ ${extra}
|
|
|
1103
1188
|
uploadTtlHours: Math.max(1, Math.floor(Number(draft.uploadTtlHours) || 24))
|
|
1104
1189
|
};
|
|
1105
1190
|
}
|
|
1191
|
+
/** 空提供商预设(新增行用;协议取目录首项)。 */
|
|
1192
|
+
function emptyProviderDraft(protocol) {
|
|
1193
|
+
return {
|
|
1194
|
+
id: "",
|
|
1195
|
+
name: "",
|
|
1196
|
+
protocol,
|
|
1197
|
+
baseUrl: "",
|
|
1198
|
+
model: "",
|
|
1199
|
+
extraHeadersText: "{}"
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
/** 空参数预设(新增行用;id 由时间戳生成,行序即身份)。 */
|
|
1203
|
+
function emptyParamDraft() {
|
|
1204
|
+
return {
|
|
1205
|
+
id: `param-${Date.now().toString(36)}`,
|
|
1206
|
+
name: "",
|
|
1207
|
+
endpoint: "generation",
|
|
1208
|
+
specsText: "{}"
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
/** 空提示词预设(新增行用)。 */
|
|
1212
|
+
function emptyPromptDraft() {
|
|
1213
|
+
return {
|
|
1214
|
+
id: `prompt-${Date.now().toString(36)}`,
|
|
1215
|
+
name: "",
|
|
1216
|
+
text: ""
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
//#endregion
|
|
1220
|
+
//#region src/client/preset-sections.tsx
|
|
1221
|
+
/**
|
|
1222
|
+
* 配置卡片的三组预设编辑区:提供商(含逐条 API Key 管理)、提示词、参数。
|
|
1223
|
+
* 从 card.tsx 拆出,避免单组件过长;草稿类型与纯转换在 ./draft.ts。
|
|
1224
|
+
* @module image-studio/client/preset-sections
|
|
1225
|
+
*/
|
|
1106
1226
|
/** 单个提供商预设的 API Key 行(describe 徽标 + 设置/删除,值不回显)。 */
|
|
1107
1227
|
function CredentialRow(props) {
|
|
1108
1228
|
const { t, presetId, disabled } = props;
|
|
@@ -1160,6 +1280,334 @@ ${extra}
|
|
|
1160
1280
|
]
|
|
1161
1281
|
});
|
|
1162
1282
|
}
|
|
1283
|
+
function ProviderPresetSection(props) {
|
|
1284
|
+
const { t, draft, disabled, protocols, onPatch, onPatchProvider } = props;
|
|
1285
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1286
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1287
|
+
className: "imsc-groupTitle",
|
|
1288
|
+
children: t("card.providers")
|
|
1289
|
+
}),
|
|
1290
|
+
draft.providers.map((provider, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1291
|
+
className: "imsc-presetBox",
|
|
1292
|
+
children: [
|
|
1293
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1294
|
+
className: "imsc-presetHead",
|
|
1295
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1296
|
+
className: "imsc-presetName",
|
|
1297
|
+
children: provider.name || provider.id || "—"
|
|
1298
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1299
|
+
type: "button",
|
|
1300
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1301
|
+
disabled,
|
|
1302
|
+
onClick: () => onPatch({ providers: draft.providers.filter((_, i) => i !== index) }),
|
|
1303
|
+
children: t("common.delete")
|
|
1304
|
+
})]
|
|
1305
|
+
}),
|
|
1306
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1307
|
+
className: "imsc-grid2",
|
|
1308
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1309
|
+
prefix: "imsc",
|
|
1310
|
+
id: `imsc-pid-${index}`,
|
|
1311
|
+
label: t("card.field.id"),
|
|
1312
|
+
hint: t("card.idHint"),
|
|
1313
|
+
value: provider.id,
|
|
1314
|
+
invalid: provider.id !== "" && !isValidPresetId(provider.id),
|
|
1315
|
+
invalidLabel: t("card.idInvalid"),
|
|
1316
|
+
disabled,
|
|
1317
|
+
onEdit: (v) => onPatchProvider(index, { id: v })
|
|
1318
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1319
|
+
prefix: "imsc",
|
|
1320
|
+
id: `imsc-pname-${index}`,
|
|
1321
|
+
label: t("card.field.name"),
|
|
1322
|
+
value: provider.name,
|
|
1323
|
+
disabled,
|
|
1324
|
+
onEdit: (v) => onPatchProvider(index, { name: v })
|
|
1325
|
+
})]
|
|
1326
|
+
}),
|
|
1327
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1328
|
+
className: "imsc-grid2",
|
|
1329
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1330
|
+
className: "imsc-field",
|
|
1331
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1332
|
+
className: "imsc-head",
|
|
1333
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1334
|
+
className: "imsc-label",
|
|
1335
|
+
htmlFor: `imsc-pproto-${index}`,
|
|
1336
|
+
children: t("card.field.protocol")
|
|
1337
|
+
})
|
|
1338
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
1339
|
+
id: `imsc-pproto-${index}`,
|
|
1340
|
+
className: "imsc-select",
|
|
1341
|
+
value: provider.protocol,
|
|
1342
|
+
disabled,
|
|
1343
|
+
onChange: (event) => onPatchProvider(index, { protocol: event.target.value }),
|
|
1344
|
+
children: (protocols.length > 0 ? protocols : [{
|
|
1345
|
+
id: provider.protocol,
|
|
1346
|
+
label: provider.protocol
|
|
1347
|
+
}]).map((protocol) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1348
|
+
value: protocol.id,
|
|
1349
|
+
children: protocol.label
|
|
1350
|
+
}, protocol.id))
|
|
1351
|
+
})]
|
|
1352
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1353
|
+
prefix: "imsc",
|
|
1354
|
+
id: `imsc-pmodel-${index}`,
|
|
1355
|
+
label: t("card.field.model"),
|
|
1356
|
+
value: provider.model,
|
|
1357
|
+
disabled,
|
|
1358
|
+
onEdit: (v) => onPatchProvider(index, { model: v })
|
|
1359
|
+
})]
|
|
1360
|
+
}),
|
|
1361
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1362
|
+
prefix: "imsc",
|
|
1363
|
+
id: `imsc-purl-${index}`,
|
|
1364
|
+
label: t("card.field.baseUrl"),
|
|
1365
|
+
value: provider.baseUrl,
|
|
1366
|
+
disabled,
|
|
1367
|
+
onEdit: (v) => onPatchProvider(index, { baseUrl: v })
|
|
1368
|
+
}),
|
|
1369
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1370
|
+
className: "imsc-field",
|
|
1371
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1372
|
+
className: "imsc-head",
|
|
1373
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1374
|
+
className: "imsc-label",
|
|
1375
|
+
htmlFor: `imsc-pheaders-${index}`,
|
|
1376
|
+
children: t("card.field.extraHeaders")
|
|
1377
|
+
})
|
|
1378
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1379
|
+
id: `imsc-pheaders-${index}`,
|
|
1380
|
+
className: "imsc-textarea",
|
|
1381
|
+
value: provider.extraHeadersText,
|
|
1382
|
+
disabled,
|
|
1383
|
+
onChange: (event) => onPatchProvider(index, { extraHeadersText: event.target.value })
|
|
1384
|
+
})]
|
|
1385
|
+
}),
|
|
1386
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CredentialRow, {
|
|
1387
|
+
t,
|
|
1388
|
+
presetId: provider.id,
|
|
1389
|
+
disabled
|
|
1390
|
+
})
|
|
1391
|
+
]
|
|
1392
|
+
}, `provider-${index}`)),
|
|
1393
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1394
|
+
type: "button",
|
|
1395
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1396
|
+
disabled,
|
|
1397
|
+
onClick: () => onPatch({ providers: [...draft.providers, emptyProviderDraft(protocols[0]?.id ?? "openai-images")] }),
|
|
1398
|
+
children: [
|
|
1399
|
+
t("card.add"),
|
|
1400
|
+
" · ",
|
|
1401
|
+
t("card.providers")
|
|
1402
|
+
]
|
|
1403
|
+
})
|
|
1404
|
+
] });
|
|
1405
|
+
}
|
|
1406
|
+
function PromptPresetSection(props) {
|
|
1407
|
+
const { t, draft, disabled, onPatch, onPatchPrompt } = props;
|
|
1408
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1409
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1410
|
+
className: "imsc-groupTitle",
|
|
1411
|
+
children: t("card.prompts")
|
|
1412
|
+
}),
|
|
1413
|
+
draft.prompts.map((prompt, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1414
|
+
className: "imsc-presetBox",
|
|
1415
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1416
|
+
className: "imsc-presetHead",
|
|
1417
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1418
|
+
className: "imsc-input",
|
|
1419
|
+
"aria-label": t("card.field.name"),
|
|
1420
|
+
value: prompt.name,
|
|
1421
|
+
disabled,
|
|
1422
|
+
onChange: (event) => onPatchPrompt(index, { name: event.target.value })
|
|
1423
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1424
|
+
type: "button",
|
|
1425
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1426
|
+
disabled,
|
|
1427
|
+
onClick: () => onPatch({ prompts: draft.prompts.filter((_, i) => i !== index) }),
|
|
1428
|
+
children: t("common.delete")
|
|
1429
|
+
})]
|
|
1430
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1431
|
+
className: "imsc-textarea",
|
|
1432
|
+
"aria-label": t("card.field.text"),
|
|
1433
|
+
value: prompt.text,
|
|
1434
|
+
disabled,
|
|
1435
|
+
onChange: (event) => onPatchPrompt(index, { text: event.target.value })
|
|
1436
|
+
})]
|
|
1437
|
+
}, `prompt-${index}`)),
|
|
1438
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1439
|
+
type: "button",
|
|
1440
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1441
|
+
disabled,
|
|
1442
|
+
onClick: () => onPatch({ prompts: [...draft.prompts, emptyPromptDraft()] }),
|
|
1443
|
+
children: [
|
|
1444
|
+
t("card.add"),
|
|
1445
|
+
" · ",
|
|
1446
|
+
t("card.prompts")
|
|
1447
|
+
]
|
|
1448
|
+
})
|
|
1449
|
+
] });
|
|
1450
|
+
}
|
|
1451
|
+
function ParamPresetSection(props) {
|
|
1452
|
+
const { t, draft, disabled, onPatch, onPatchParam } = props;
|
|
1453
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1454
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1455
|
+
className: "imsc-groupTitle",
|
|
1456
|
+
children: t("card.params")
|
|
1457
|
+
}),
|
|
1458
|
+
draft.params.map((param, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1459
|
+
className: "imsc-presetBox",
|
|
1460
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1461
|
+
className: "imsc-presetHead",
|
|
1462
|
+
children: [
|
|
1463
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1464
|
+
className: "imsc-input",
|
|
1465
|
+
"aria-label": t("card.field.name"),
|
|
1466
|
+
value: param.name,
|
|
1467
|
+
disabled,
|
|
1468
|
+
onChange: (event) => onPatchParam(index, { name: event.target.value })
|
|
1469
|
+
}),
|
|
1470
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1471
|
+
className: "imsc-select",
|
|
1472
|
+
"aria-label": t("card.field.endpoint"),
|
|
1473
|
+
value: param.endpoint,
|
|
1474
|
+
disabled,
|
|
1475
|
+
onChange: (event) => onPatchParam(index, { endpoint: event.target.value }),
|
|
1476
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1477
|
+
value: "generation",
|
|
1478
|
+
children: t("tab.generation")
|
|
1479
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1480
|
+
value: "edit",
|
|
1481
|
+
children: t("tab.edit")
|
|
1482
|
+
})]
|
|
1483
|
+
}),
|
|
1484
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1485
|
+
type: "button",
|
|
1486
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1487
|
+
disabled,
|
|
1488
|
+
onClick: () => onPatch({ params: draft.params.filter((_, i) => i !== index) }),
|
|
1489
|
+
children: t("common.delete")
|
|
1490
|
+
})
|
|
1491
|
+
]
|
|
1492
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1493
|
+
className: "imsc-textarea",
|
|
1494
|
+
"aria-label": t("card.field.paramSpecs"),
|
|
1495
|
+
placeholder: "{ \"size\": { \"enabled\": true, \"value\": \"1024x1024\" } }",
|
|
1496
|
+
value: param.specsText,
|
|
1497
|
+
disabled,
|
|
1498
|
+
onChange: (event) => onPatchParam(index, { specsText: event.target.value })
|
|
1499
|
+
})]
|
|
1500
|
+
}, `param-${index}`)),
|
|
1501
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1502
|
+
type: "button",
|
|
1503
|
+
className: "imsc-btn imsc-btnGhost",
|
|
1504
|
+
disabled,
|
|
1505
|
+
onClick: () => onPatch({ params: [...draft.params, emptyParamDraft()] }),
|
|
1506
|
+
children: [
|
|
1507
|
+
t("card.add"),
|
|
1508
|
+
" · ",
|
|
1509
|
+
t("card.params")
|
|
1510
|
+
]
|
|
1511
|
+
})
|
|
1512
|
+
] });
|
|
1513
|
+
}
|
|
1514
|
+
//#endregion
|
|
1515
|
+
//#region src/client/card.tsx
|
|
1516
|
+
/**
|
|
1517
|
+
* 配置卡片(injectPluginConfigCard 三槽位,legacy key = settings 命名空间,
|
|
1518
|
+
* 0.1.6-alpha.2 起为插件页 row/bundle config,view 分发 summary/page):
|
|
1519
|
+
* 三组预设(提供商/参数/提示词)+ 高级项(并发/超时/代理/画廊上限)的
|
|
1520
|
+
* staged draft 编辑;提供商预设逐条附 API Key 管理(凭据端点,值不回显)。
|
|
1521
|
+
* JSON 字段(extraHeaders/paramSpecs)以文本镜像编辑,保存时解析 +
|
|
1522
|
+
* validateParamSpecs 本地校验,非法即拦在保存前。
|
|
1523
|
+
* 草稿类型与纯转换在 ./draft.ts,三组预设编辑区在 ./preset-sections.tsx。
|
|
1524
|
+
* @module image-studio/client/card
|
|
1525
|
+
*/
|
|
1526
|
+
/** 协议目录(服务端 /providers):驱动提供商预设的协议下拉。 */
|
|
1527
|
+
function useProtocols() {
|
|
1528
|
+
const [protocols, setProtocols] = (0, react.useState)([]);
|
|
1529
|
+
(0, react.useEffect)(() => {
|
|
1530
|
+
fetchProviders().then((res) => setProtocols(res.protocols.map((p) => ({
|
|
1531
|
+
id: p.id,
|
|
1532
|
+
label: p.label
|
|
1533
|
+
})))).catch(() => {});
|
|
1534
|
+
}, []);
|
|
1535
|
+
return protocols;
|
|
1536
|
+
}
|
|
1537
|
+
/** 卡片动作:放弃(回到 Host 值并重置基线)与保存。 */
|
|
1538
|
+
function cardActions(options) {
|
|
1539
|
+
const { t } = options;
|
|
1540
|
+
return [{
|
|
1541
|
+
key: "discard",
|
|
1542
|
+
label: t("card.discard"),
|
|
1543
|
+
disabled: !options.dirty || options.saving,
|
|
1544
|
+
onClick: options.onDiscard
|
|
1545
|
+
}, {
|
|
1546
|
+
key: "save",
|
|
1547
|
+
label: t(options.saving ? "common.saving" : "card.save"),
|
|
1548
|
+
variant: "primary",
|
|
1549
|
+
disabled: !options.dirty || options.saving || options.disabled,
|
|
1550
|
+
onClick: options.onSave
|
|
1551
|
+
}];
|
|
1552
|
+
}
|
|
1553
|
+
/** 高级项:并发 / 超时 / 代理 / 画廊上限 / 上传保留时长。 */
|
|
1554
|
+
function AdvancedFields(props) {
|
|
1555
|
+
const { t, draft, disabled, onPatch } = props;
|
|
1556
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1558
|
+
className: "imsc-groupTitle",
|
|
1559
|
+
children: t("card.advanced")
|
|
1560
|
+
}),
|
|
1561
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1562
|
+
className: "imsc-grid2",
|
|
1563
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1564
|
+
prefix: "imsc",
|
|
1565
|
+
id: "imsc-conc",
|
|
1566
|
+
label: t("card.maxConcurrent"),
|
|
1567
|
+
numeric: true,
|
|
1568
|
+
value: draft.maxConcurrent,
|
|
1569
|
+
disabled,
|
|
1570
|
+
onEdit: (v) => onPatch({ maxConcurrent: v })
|
|
1571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1572
|
+
prefix: "imsc",
|
|
1573
|
+
id: "imsc-timeout",
|
|
1574
|
+
label: t("card.requestTimeoutMs"),
|
|
1575
|
+
numeric: true,
|
|
1576
|
+
value: draft.requestTimeoutMs,
|
|
1577
|
+
disabled,
|
|
1578
|
+
onEdit: (v) => onPatch({ requestTimeoutMs: v })
|
|
1579
|
+
})]
|
|
1580
|
+
}),
|
|
1581
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1582
|
+
className: "imsc-grid2",
|
|
1583
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1584
|
+
prefix: "imsc",
|
|
1585
|
+
id: "imsc-proxy",
|
|
1586
|
+
label: t("card.proxy"),
|
|
1587
|
+
value: draft.proxy,
|
|
1588
|
+
disabled,
|
|
1589
|
+
onEdit: (v) => onPatch({ proxy: v })
|
|
1590
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1591
|
+
prefix: "imsc",
|
|
1592
|
+
id: "imsc-gmax",
|
|
1593
|
+
label: t("card.galleryMaxItems"),
|
|
1594
|
+
numeric: true,
|
|
1595
|
+
value: draft.galleryMaxItems,
|
|
1596
|
+
disabled,
|
|
1597
|
+
onEdit: (v) => onPatch({ galleryMaxItems: v })
|
|
1598
|
+
})]
|
|
1599
|
+
}),
|
|
1600
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1601
|
+
prefix: "imsc",
|
|
1602
|
+
id: "imsc-upload-ttl",
|
|
1603
|
+
label: t("card.uploadTtlHours"),
|
|
1604
|
+
numeric: true,
|
|
1605
|
+
value: draft.uploadTtlHours,
|
|
1606
|
+
disabled,
|
|
1607
|
+
onEdit: (v) => onPatch({ uploadTtlHours: v })
|
|
1608
|
+
})
|
|
1609
|
+
] });
|
|
1610
|
+
}
|
|
1163
1611
|
function StudioConfigCard(props) {
|
|
1164
1612
|
const { t, scope, api } = props;
|
|
1165
1613
|
const snapshot = (0, react.useSyncExternalStore)((listener) => scope.subscribe(listener), () => scope.getSnapshot());
|
|
@@ -1169,13 +1617,7 @@ ${extra}
|
|
|
1169
1617
|
const [baseline, setBaseline] = (0, react.useState)("");
|
|
1170
1618
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
1171
1619
|
const [status, setStatus] = (0, react.useState)(IDLE_STATUS);
|
|
1172
|
-
const
|
|
1173
|
-
(0, react.useEffect)(() => {
|
|
1174
|
-
fetchProviders().then((res) => setProtocols(res.protocols.map((p) => ({
|
|
1175
|
-
id: p.id,
|
|
1176
|
-
label: p.label
|
|
1177
|
-
})))).catch(() => {});
|
|
1178
|
-
}, []);
|
|
1620
|
+
const protocols = useProtocols();
|
|
1179
1621
|
(0, react.useEffect)(() => {
|
|
1180
1622
|
if (value === void 0 || draft !== null) return;
|
|
1181
1623
|
const initial = draftOf(value);
|
|
@@ -1184,12 +1626,11 @@ ${extra}
|
|
|
1184
1626
|
}, [value, draft]);
|
|
1185
1627
|
const dirty = (0, react.useMemo)(() => draft !== null && JSON.stringify(draft) !== baseline, [draft, baseline]);
|
|
1186
1628
|
if (props.view === "summary") return t("card.summary");
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
})
|
|
1629
|
+
const variant = cardVariantFor(props.view);
|
|
1630
|
+
if (value === void 0 || draft === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardLoading, {
|
|
1631
|
+
prefix: "imsc",
|
|
1632
|
+
variant,
|
|
1633
|
+
text: t("common.loading")
|
|
1193
1634
|
});
|
|
1194
1635
|
const disabled = !snapshot.writable;
|
|
1195
1636
|
const onSave = () => {
|
|
@@ -1224,24 +1665,32 @@ ${extra}
|
|
|
1224
1665
|
});
|
|
1225
1666
|
setStatus(IDLE_STATUS);
|
|
1226
1667
|
};
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1668
|
+
const sectionProps = {
|
|
1669
|
+
t,
|
|
1670
|
+
draft,
|
|
1671
|
+
disabled,
|
|
1672
|
+
protocols,
|
|
1673
|
+
onPatch: patch,
|
|
1674
|
+
onPatchProvider: (index, next) => patch({ providers: draft.providers.map((p, i) => i === index ? {
|
|
1675
|
+
...p,
|
|
1676
|
+
...next
|
|
1677
|
+
} : p) }),
|
|
1678
|
+
onPatchParam: (index, next) => patch({ params: draft.params.map((p, i) => i === index ? {
|
|
1679
|
+
...p,
|
|
1680
|
+
...next
|
|
1681
|
+
} : p) }),
|
|
1682
|
+
onPatchPrompt: (index, next) => patch({ prompts: draft.prompts.map((p, i) => i === index ? {
|
|
1683
|
+
...p,
|
|
1684
|
+
...next
|
|
1685
|
+
} : p) })
|
|
1686
|
+
};
|
|
1239
1687
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CardChrome, {
|
|
1240
1688
|
prefix: "imsc",
|
|
1241
1689
|
title: t("card.title"),
|
|
1242
1690
|
description: t("card.description"),
|
|
1243
1691
|
open,
|
|
1244
1692
|
onToggle: setOpen,
|
|
1693
|
+
variant,
|
|
1245
1694
|
statusBadge: {
|
|
1246
1695
|
text: draft.providers.length > 0 ? t("card.badgeOn").replace("{n}", String(draft.providers.length)) : t("card.badgeOff"),
|
|
1247
1696
|
on: draft.providers.length > 0
|
|
@@ -1250,307 +1699,28 @@ ${extra}
|
|
|
1250
1699
|
dirtyLabel: t("common.unsaved"),
|
|
1251
1700
|
readOnlyNotice: disabled ? t("card.readOnly") : void 0,
|
|
1252
1701
|
status,
|
|
1253
|
-
actions:
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1702
|
+
actions: cardActions({
|
|
1703
|
+
t,
|
|
1704
|
+
dirty,
|
|
1705
|
+
saving,
|
|
1706
|
+
disabled,
|
|
1707
|
+
onDiscard: () => {
|
|
1258
1708
|
const restored = draftOf(value);
|
|
1259
1709
|
setDraft(restored);
|
|
1260
1710
|
setBaseline(JSON.stringify(restored));
|
|
1261
1711
|
setStatus(IDLE_STATUS);
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
label: t(saving ? "common.saving" : "card.save"),
|
|
1266
|
-
variant: "primary",
|
|
1267
|
-
disabled: !dirty || saving || disabled,
|
|
1268
|
-
onClick: onSave
|
|
1269
|
-
}],
|
|
1712
|
+
},
|
|
1713
|
+
onSave
|
|
1714
|
+
}),
|
|
1270
1715
|
children: [
|
|
1271
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
children: [
|
|
1278
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1279
|
-
className: "imsc-presetHead",
|
|
1280
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1281
|
-
className: "imsc-presetName",
|
|
1282
|
-
children: provider.name || provider.id || "—"
|
|
1283
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1284
|
-
type: "button",
|
|
1285
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1286
|
-
disabled,
|
|
1287
|
-
onClick: () => patch({ providers: draft.providers.filter((_, i) => i !== index) }),
|
|
1288
|
-
children: t("common.delete")
|
|
1289
|
-
})]
|
|
1290
|
-
}),
|
|
1291
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1292
|
-
className: "imsc-grid2",
|
|
1293
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1294
|
-
prefix: "imsc",
|
|
1295
|
-
id: `imsc-pid-${index}`,
|
|
1296
|
-
label: t("card.field.id"),
|
|
1297
|
-
hint: t("card.idHint"),
|
|
1298
|
-
value: provider.id,
|
|
1299
|
-
invalid: provider.id !== "" && !isValidPresetId(provider.id),
|
|
1300
|
-
invalidLabel: t("card.idInvalid"),
|
|
1301
|
-
disabled,
|
|
1302
|
-
onEdit: (v) => patchProvider(index, { id: v })
|
|
1303
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1304
|
-
prefix: "imsc",
|
|
1305
|
-
id: `imsc-pname-${index}`,
|
|
1306
|
-
label: t("card.field.name"),
|
|
1307
|
-
value: provider.name,
|
|
1308
|
-
disabled,
|
|
1309
|
-
onEdit: (v) => patchProvider(index, { name: v })
|
|
1310
|
-
})]
|
|
1311
|
-
}),
|
|
1312
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1313
|
-
className: "imsc-grid2",
|
|
1314
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1315
|
-
className: "imsc-field",
|
|
1316
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1317
|
-
className: "imsc-head",
|
|
1318
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1319
|
-
className: "imsc-label",
|
|
1320
|
-
htmlFor: `imsc-pproto-${index}`,
|
|
1321
|
-
children: t("card.field.protocol")
|
|
1322
|
-
})
|
|
1323
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
1324
|
-
id: `imsc-pproto-${index}`,
|
|
1325
|
-
className: "imsc-select",
|
|
1326
|
-
value: provider.protocol,
|
|
1327
|
-
disabled,
|
|
1328
|
-
onChange: (event) => patchProvider(index, { protocol: event.target.value }),
|
|
1329
|
-
children: (protocols.length > 0 ? protocols : [{
|
|
1330
|
-
id: provider.protocol,
|
|
1331
|
-
label: provider.protocol
|
|
1332
|
-
}]).map((protocol) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1333
|
-
value: protocol.id,
|
|
1334
|
-
children: protocol.label
|
|
1335
|
-
}, protocol.id))
|
|
1336
|
-
})]
|
|
1337
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1338
|
-
prefix: "imsc",
|
|
1339
|
-
id: `imsc-pmodel-${index}`,
|
|
1340
|
-
label: t("card.field.model"),
|
|
1341
|
-
value: provider.model,
|
|
1342
|
-
disabled,
|
|
1343
|
-
onEdit: (v) => patchProvider(index, { model: v })
|
|
1344
|
-
})]
|
|
1345
|
-
}),
|
|
1346
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1347
|
-
prefix: "imsc",
|
|
1348
|
-
id: `imsc-purl-${index}`,
|
|
1349
|
-
label: t("card.field.baseUrl"),
|
|
1350
|
-
value: provider.baseUrl,
|
|
1351
|
-
disabled,
|
|
1352
|
-
onEdit: (v) => patchProvider(index, { baseUrl: v })
|
|
1353
|
-
}),
|
|
1354
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1355
|
-
className: "imsc-field",
|
|
1356
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1357
|
-
className: "imsc-head",
|
|
1358
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1359
|
-
className: "imsc-label",
|
|
1360
|
-
htmlFor: `imsc-pheaders-${index}`,
|
|
1361
|
-
children: t("card.field.extraHeaders")
|
|
1362
|
-
})
|
|
1363
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1364
|
-
id: `imsc-pheaders-${index}`,
|
|
1365
|
-
className: "imsc-textarea",
|
|
1366
|
-
value: provider.extraHeadersText,
|
|
1367
|
-
disabled,
|
|
1368
|
-
onChange: (event) => patchProvider(index, { extraHeadersText: event.target.value })
|
|
1369
|
-
})]
|
|
1370
|
-
}),
|
|
1371
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CredentialRow, {
|
|
1372
|
-
t,
|
|
1373
|
-
presetId: provider.id,
|
|
1374
|
-
disabled
|
|
1375
|
-
})
|
|
1376
|
-
]
|
|
1377
|
-
}, `provider-${index}`)),
|
|
1378
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1379
|
-
type: "button",
|
|
1380
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1381
|
-
disabled,
|
|
1382
|
-
onClick: () => patch({ providers: [...draft.providers, {
|
|
1383
|
-
id: "",
|
|
1384
|
-
name: "",
|
|
1385
|
-
protocol: protocols[0]?.id ?? "openai-images",
|
|
1386
|
-
baseUrl: "",
|
|
1387
|
-
model: "",
|
|
1388
|
-
extraHeadersText: "{}"
|
|
1389
|
-
}] }),
|
|
1390
|
-
children: [
|
|
1391
|
-
t("card.add"),
|
|
1392
|
-
" · ",
|
|
1393
|
-
t("card.providers")
|
|
1394
|
-
]
|
|
1395
|
-
}),
|
|
1396
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1397
|
-
className: "imsc-groupTitle",
|
|
1398
|
-
children: t("card.prompts")
|
|
1399
|
-
}),
|
|
1400
|
-
draft.prompts.map((prompt, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1401
|
-
className: "imsc-presetBox",
|
|
1402
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1403
|
-
className: "imsc-presetHead",
|
|
1404
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1405
|
-
className: "imsc-input",
|
|
1406
|
-
"aria-label": t("card.field.name"),
|
|
1407
|
-
value: prompt.name,
|
|
1408
|
-
disabled,
|
|
1409
|
-
onChange: (event) => patchPrompt(index, { name: event.target.value })
|
|
1410
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1411
|
-
type: "button",
|
|
1412
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1413
|
-
disabled,
|
|
1414
|
-
onClick: () => patch({ prompts: draft.prompts.filter((_, i) => i !== index) }),
|
|
1415
|
-
children: t("common.delete")
|
|
1416
|
-
})]
|
|
1417
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1418
|
-
className: "imsc-textarea",
|
|
1419
|
-
"aria-label": t("card.field.text"),
|
|
1420
|
-
value: prompt.text,
|
|
1421
|
-
disabled,
|
|
1422
|
-
onChange: (event) => patchPrompt(index, { text: event.target.value })
|
|
1423
|
-
})]
|
|
1424
|
-
}, `prompt-${index}`)),
|
|
1425
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1426
|
-
type: "button",
|
|
1427
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1428
|
-
disabled,
|
|
1429
|
-
onClick: () => patch({ prompts: [...draft.prompts, {
|
|
1430
|
-
id: `prompt-${Date.now().toString(36)}`,
|
|
1431
|
-
name: "",
|
|
1432
|
-
text: ""
|
|
1433
|
-
}] }),
|
|
1434
|
-
children: [
|
|
1435
|
-
t("card.add"),
|
|
1436
|
-
" · ",
|
|
1437
|
-
t("card.prompts")
|
|
1438
|
-
]
|
|
1439
|
-
}),
|
|
1440
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1441
|
-
className: "imsc-groupTitle",
|
|
1442
|
-
children: t("card.params")
|
|
1443
|
-
}),
|
|
1444
|
-
draft.params.map((param, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1445
|
-
className: "imsc-presetBox",
|
|
1446
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1447
|
-
className: "imsc-presetHead",
|
|
1448
|
-
children: [
|
|
1449
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1450
|
-
className: "imsc-input",
|
|
1451
|
-
"aria-label": t("card.field.name"),
|
|
1452
|
-
value: param.name,
|
|
1453
|
-
disabled,
|
|
1454
|
-
onChange: (event) => patchParam(index, { name: event.target.value })
|
|
1455
|
-
}),
|
|
1456
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1457
|
-
className: "imsc-select",
|
|
1458
|
-
"aria-label": t("card.field.endpoint"),
|
|
1459
|
-
value: param.endpoint,
|
|
1460
|
-
disabled,
|
|
1461
|
-
onChange: (event) => patchParam(index, { endpoint: event.target.value }),
|
|
1462
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1463
|
-
value: "generation",
|
|
1464
|
-
children: t("tab.generation")
|
|
1465
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1466
|
-
value: "edit",
|
|
1467
|
-
children: t("tab.edit")
|
|
1468
|
-
})]
|
|
1469
|
-
}),
|
|
1470
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1471
|
-
type: "button",
|
|
1472
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1473
|
-
disabled,
|
|
1474
|
-
onClick: () => patch({ params: draft.params.filter((_, i) => i !== index) }),
|
|
1475
|
-
children: t("common.delete")
|
|
1476
|
-
})
|
|
1477
|
-
]
|
|
1478
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1479
|
-
className: "imsc-textarea",
|
|
1480
|
-
"aria-label": t("card.field.paramSpecs"),
|
|
1481
|
-
placeholder: "{ \"size\": { \"enabled\": true, \"value\": \"1024x1024\" } }",
|
|
1482
|
-
value: param.specsText,
|
|
1483
|
-
disabled,
|
|
1484
|
-
onChange: (event) => patchParam(index, { specsText: event.target.value })
|
|
1485
|
-
})]
|
|
1486
|
-
}, `param-${index}`)),
|
|
1487
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1488
|
-
type: "button",
|
|
1489
|
-
className: "imsc-btn imsc-btnGhost",
|
|
1490
|
-
disabled,
|
|
1491
|
-
onClick: () => patch({ params: [...draft.params, {
|
|
1492
|
-
id: `param-${Date.now().toString(36)}`,
|
|
1493
|
-
name: "",
|
|
1494
|
-
endpoint: "generation",
|
|
1495
|
-
specsText: "{}"
|
|
1496
|
-
}] }),
|
|
1497
|
-
children: [
|
|
1498
|
-
t("card.add"),
|
|
1499
|
-
" · ",
|
|
1500
|
-
t("card.params")
|
|
1501
|
-
]
|
|
1502
|
-
}),
|
|
1503
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1504
|
-
className: "imsc-groupTitle",
|
|
1505
|
-
children: t("card.advanced")
|
|
1506
|
-
}),
|
|
1507
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1508
|
-
className: "imsc-grid2",
|
|
1509
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1510
|
-
prefix: "imsc",
|
|
1511
|
-
id: "imsc-conc",
|
|
1512
|
-
label: t("card.maxConcurrent"),
|
|
1513
|
-
numeric: true,
|
|
1514
|
-
value: draft.maxConcurrent,
|
|
1515
|
-
disabled,
|
|
1516
|
-
onEdit: (v) => patch({ maxConcurrent: v })
|
|
1517
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1518
|
-
prefix: "imsc",
|
|
1519
|
-
id: "imsc-timeout",
|
|
1520
|
-
label: t("card.requestTimeoutMs"),
|
|
1521
|
-
numeric: true,
|
|
1522
|
-
value: draft.requestTimeoutMs,
|
|
1523
|
-
disabled,
|
|
1524
|
-
onEdit: (v) => patch({ requestTimeoutMs: v })
|
|
1525
|
-
})]
|
|
1526
|
-
}),
|
|
1527
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1528
|
-
className: "imsc-grid2",
|
|
1529
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1530
|
-
prefix: "imsc",
|
|
1531
|
-
id: "imsc-proxy",
|
|
1532
|
-
label: t("card.proxy"),
|
|
1533
|
-
value: draft.proxy,
|
|
1534
|
-
disabled,
|
|
1535
|
-
onEdit: (v) => patch({ proxy: v })
|
|
1536
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1537
|
-
prefix: "imsc",
|
|
1538
|
-
id: "imsc-gmax",
|
|
1539
|
-
label: t("card.galleryMaxItems"),
|
|
1540
|
-
numeric: true,
|
|
1541
|
-
value: draft.galleryMaxItems,
|
|
1542
|
-
disabled,
|
|
1543
|
-
onEdit: (v) => patch({ galleryMaxItems: v })
|
|
1544
|
-
})]
|
|
1545
|
-
}),
|
|
1546
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
|
|
1547
|
-
prefix: "imsc",
|
|
1548
|
-
id: "imsc-upload-ttl",
|
|
1549
|
-
label: t("card.uploadTtlHours"),
|
|
1550
|
-
numeric: true,
|
|
1551
|
-
value: draft.uploadTtlHours,
|
|
1716
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderPresetSection, { ...sectionProps }),
|
|
1717
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PromptPresetSection, { ...sectionProps }),
|
|
1718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParamPresetSection, { ...sectionProps }),
|
|
1719
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AdvancedFields, {
|
|
1720
|
+
t,
|
|
1721
|
+
draft,
|
|
1552
1722
|
disabled,
|
|
1553
|
-
|
|
1723
|
+
onPatch: patch
|
|
1554
1724
|
})
|
|
1555
1725
|
]
|
|
1556
1726
|
});
|
|
@@ -4026,6 +4196,14 @@ ${extra}
|
|
|
4026
4196
|
}
|
|
4027
4197
|
.imsc-credRow { display: flex; align-items: center; gap: 8px; }
|
|
4028
4198
|
.imsc-credRow .imsc-input { flex: 1; min-width: 0; }
|
|
4199
|
+
/* 分节形态(插件页 page 视图,无边框分节):预设块改为分隔线分组,去掉第二层内边距 */
|
|
4200
|
+
.imsc-section .imsc-presetBox {
|
|
4201
|
+
border: 0;
|
|
4202
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
4203
|
+
border-radius: 0;
|
|
4204
|
+
padding: 10px 0 2px;
|
|
4205
|
+
margin-bottom: 0;
|
|
4206
|
+
}
|
|
4029
4207
|
|
|
4030
4208
|
/* ── 移动端(≤767px,与 ui-mobile-fit 同断点)── */
|
|
4031
4209
|
@media (max-width: 767px) {
|
|
@@ -4059,6 +4237,7 @@ ${extra}
|
|
|
4059
4237
|
.ims-btn { min-height: 40px; }
|
|
4060
4238
|
.ims-btnSmall { min-height: 32px; }
|
|
4061
4239
|
.imsc-grid2 { grid-template-columns: 1fr; }
|
|
4240
|
+
.imsc-section .imsc-presetBox { padding: 10px 0 2px; }
|
|
4062
4241
|
}
|
|
4063
4242
|
`;
|
|
4064
4243
|
/** 注入面板 + 入口 + 卡片附加样式(重复调用幂等:已存在则跳过)。 */
|