feat(admin): publish provider drafts into pack repo
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
- `tksea-portal/admin/providers.html`
|
||||
- `https://sub.tksea.top/portal/admin/providers.html`
|
||||
- 用现有 CRM API 做 pack/provider 浏览、preview-import、import,以及 provider manifest 草稿生成
|
||||
- 当前也可直接调用服务端 `provider_drafts` API,把 manifest 草稿持久化到 CRM SQLite,并支持更新 / 删除
|
||||
- 当前也可直接调用服务端 `provider_drafts` API,把 manifest 草稿持久化到 CRM SQLite,并支持更新 / 删除 / 发布到 pack 仓库
|
||||
- `tksea-portal/admin/batch-import.html`
|
||||
- `https://sub.tksea.top/portal/admin/batch-import.html`
|
||||
- 结构化入口地址,当前跳转到 legacy `admin-batch-import.html`
|
||||
|
||||
@@ -292,8 +292,8 @@
|
||||
<h2>新增模型 / 供应商目录</h2>
|
||||
<p>
|
||||
这页负责浏览已安装 pack、选择 provider、调用 <code>preview-import</code> /
|
||||
<code>import</code>,同时提供 provider manifest 草稿生成器。当前版本不直接在浏览器里写入 pack 仓库,
|
||||
但已经把“新增模型”的准备动作收进同一条操作链。
|
||||
<code>import</code>,同时提供 provider manifest 草稿生成与发布。当前版本已经支持先保存草稿,再经由 CRM
|
||||
服务端写入 pack/provider 文件并自动提交到仓库。
|
||||
</p>
|
||||
<div class="cta-row">
|
||||
<a class="cta primary" href="/portal/admin/providers.html">打开供应商页</a>
|
||||
@@ -302,7 +302,7 @@
|
||||
<ul class="list">
|
||||
<li>
|
||||
<strong>适用动作</strong>
|
||||
查看 pack 与 provider、输入 keys 做 preview/import、生成 provider 草稿 JSON。
|
||||
查看 pack 与 provider、输入 keys 做 preview/import、生成 provider 草稿,并一键发布到仓库。
|
||||
</li>
|
||||
<li>
|
||||
<strong>默认 API Base</strong>
|
||||
@@ -342,8 +342,8 @@
|
||||
</article>
|
||||
<article class="status-card status-note">
|
||||
<div class="metric-label">当前边界</div>
|
||||
<strong>浏览器不直接写 pack 仓库</strong>
|
||||
<p>新增 provider 模板的最终落盘仍通过仓库提交完成,页面当前先覆盖目录、草稿与导入操作。</p>
|
||||
<strong>浏览器提交到 CRM,再由 CRM 写仓库</strong>
|
||||
<p>页面不会直接拼 Git 命令;所有写 pack/provider 与提交仓库的动作,都统一走 CRM 服务端的发布接口。</p>
|
||||
</article>
|
||||
<article class="status-card status-caution">
|
||||
<div class="metric-label">安全前提</div>
|
||||
|
||||
@@ -371,12 +371,12 @@
|
||||
<p class="hero-copy">
|
||||
这页把“新增模型供应商”和“导入供应商帐号”的前置动作收口在一起。当前版本会先列出
|
||||
pack 里已经存在的 provider,允许直接做 <code>preview-import</code> 与 <code>import</code>。
|
||||
如果你要新增 provider 模板,本页也会生成一份 manifest 草稿,方便再落回仓库提交。
|
||||
如果你要新增 provider 模板,本页也支持把草稿保存到 CRM,再一键发布成 pack/provider 文件并自动提交到仓库。
|
||||
</p>
|
||||
<ul class="hero-points">
|
||||
<li>默认 API Base:<code>/portal-admin-api</code></li>
|
||||
<li>支持同域 Bearer admin token</li>
|
||||
<li>支持 provider manifest 草稿生成</li>
|
||||
<li>支持 provider 草稿发布到 pack 仓库</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
@@ -499,8 +499,8 @@
|
||||
<article class="card panel" id="manifest-draft">
|
||||
<h2>Provider Manifest 草稿</h2>
|
||||
<p class="panel-desc">
|
||||
这部分不会直接写仓库,只生成一个可复制的 JSON 草稿,解决“新增模型页面完全缺失”的问题。
|
||||
真正落盘仍通过 pack 仓库提交完成。
|
||||
这部分既能生成与保存 provider 草稿,也能从已保存草稿一键发布到 pack/provider 文件并提交到仓库。
|
||||
页面本身不直接拼 Git 命令,所有写仓库动作都经由 CRM 服务端完成。
|
||||
</p>
|
||||
|
||||
<div class="field-grid two">
|
||||
@@ -530,10 +530,16 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label>发布 Commit Message
|
||||
<input id="draft-commit-message" type="text" placeholder="feat(pack): publish provider draft openai-zhongzhuan">
|
||||
<span class="hint">留空时会按 provider_id 自动生成标准 commit message。</span>
|
||||
</label>
|
||||
|
||||
<div class="actions">
|
||||
<button class="secondary" id="generate-draft-btn">生成草稿</button>
|
||||
<button class="primary" id="save-draft-btn">保存到服务端</button>
|
||||
<button class="secondary" id="update-draft-btn">更新草稿</button>
|
||||
<button class="primary" id="publish-draft-btn">发布到仓库</button>
|
||||
<button class="ghost" id="delete-draft-btn">删除草稿</button>
|
||||
<button class="ghost" id="copy-draft-btn">复制 JSON</button>
|
||||
<button class="ghost" id="refresh-drafts-btn">刷新草稿列表</button>
|
||||
@@ -615,6 +621,7 @@
|
||||
const draftSmokeModelInput = document.getElementById("draft-smoke-model");
|
||||
const draftBaseURLInput = document.getElementById("draft-base-url");
|
||||
const draftModelsInput = document.getElementById("draft-models");
|
||||
const draftCommitMessageInput = document.getElementById("draft-commit-message");
|
||||
|
||||
function defaultApiBase() {
|
||||
return `${window.location.origin}/portal-admin-api`;
|
||||
@@ -688,6 +695,7 @@
|
||||
draftSmokeModel: draftSmokeModelInput.value.trim(),
|
||||
draftBaseURL: draftBaseURLInput.value.trim(),
|
||||
draftModels: draftModelsInput.value.trim(),
|
||||
draftCommitMessage: draftCommitMessageInput.value.trim(),
|
||||
}));
|
||||
syncMetrics();
|
||||
setStatus(catalogStatus, "本地配置已保存。", "success");
|
||||
@@ -720,6 +728,7 @@
|
||||
draftSmokeModelInput.value = payload.draftSmokeModel || "";
|
||||
draftBaseURLInput.value = payload.draftBaseURL || "";
|
||||
draftModelsInput.value = payload.draftModels || "";
|
||||
draftCommitMessageInput.value = payload.draftCommitMessage || "";
|
||||
} catch (error) {
|
||||
apiBaseInput.value = defaultApiBase();
|
||||
}
|
||||
@@ -816,6 +825,9 @@
|
||||
draftSmokeModelInput.value = draft.smoke_test_model || "";
|
||||
draftBaseURLInput.value = draft.base_url || "";
|
||||
draftModelsInput.value = Array.isArray(draft.supported_models) ? draft.supported_models.join(",") : "";
|
||||
if (!draftCommitMessageInput.value.trim()) {
|
||||
draftCommitMessageInput.value = `feat(pack): publish provider draft ${draft.provider_id || ""}`.trim();
|
||||
}
|
||||
}
|
||||
|
||||
function clearDraftFormSelection() {
|
||||
@@ -1144,6 +1156,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function publishDraftToRepo() {
|
||||
const button = document.getElementById("publish-draft-btn");
|
||||
button.disabled = true;
|
||||
try {
|
||||
if (!state.currentDraftID) {
|
||||
throw new Error("请先从服务端草稿列表选择一条草稿");
|
||||
}
|
||||
const result = await requestJSON(`/api/provider-drafts/${encodeURIComponent(state.currentDraftID)}/publish`, {
|
||||
method: "POST",
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify({
|
||||
commit_message: draftCommitMessageInput.value.trim(),
|
||||
}),
|
||||
});
|
||||
importResult.textContent = JSON.stringify(result.publish || result, null, 2);
|
||||
setStatus(
|
||||
draftStatus,
|
||||
`已发布到仓库:${result.publish?.provider_path || "-"} · ${result.publish?.pack_version_before || "-"} -> ${result.publish?.pack_version_after || "-"} · ${result.publish?.commit_sha || "-"}`,
|
||||
"success",
|
||||
);
|
||||
} catch (error) {
|
||||
setStatus(draftStatus, `发布失败:${error.message}`, "danger");
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHTML(value) {
|
||||
return String(value)
|
||||
.replaceAll("&", "&")
|
||||
@@ -1160,6 +1199,7 @@
|
||||
document.getElementById("generate-draft-btn").addEventListener("click", generateDraft);
|
||||
document.getElementById("save-draft-btn").addEventListener("click", saveDraftToServer);
|
||||
document.getElementById("update-draft-btn").addEventListener("click", updateDraftOnServer);
|
||||
document.getElementById("publish-draft-btn").addEventListener("click", publishDraftToRepo);
|
||||
document.getElementById("delete-draft-btn").addEventListener("click", deleteDraftOnServer);
|
||||
document.getElementById("copy-draft-btn").addEventListener("click", copyDraft);
|
||||
document.getElementById("refresh-drafts-btn").addEventListener("click", loadServerDrafts);
|
||||
|
||||
Reference in New Issue
Block a user