feat: add image_make controls to admin

This commit is contained in:
john
2026-07-19 18:34:55 +08:00
parent 75b7c07a4d
commit 790c5794e9
4 changed files with 104 additions and 2 deletions
+43 -2
View File
@@ -12,6 +12,7 @@ type PluginDraft = {
provider: string;
llmProviderKeyId: string;
llmModel: string;
purposes: Record<string, boolean>;
};
function draftFromPlugin(plugin: AssetPluginConfig): PluginDraft {
@@ -20,6 +21,7 @@ function draftFromPlugin(plugin: AssetPluginConfig): PluginDraft {
provider: plugin.provider ?? '',
llmProviderKeyId: plugin.llmProviderKeyId ?? '',
llmModel: plugin.llmModel ?? '',
purposes: { ...(plugin.purposes ?? {}) },
};
}
@@ -61,6 +63,16 @@ export function AssetGatewayPage() {
setDrafts((current) => ({ ...current, [pluginId]: { ...current[pluginId], ...patch } }));
};
const updatePurpose = (pluginId: string, purposeId: string, enabled: boolean) => {
setDrafts((current) => ({
...current,
[pluginId]: {
...current[pluginId],
purposes: { ...(current[pluginId]?.purposes ?? {}), [purposeId]: enabled },
},
}));
};
const saveGlobal = async (enabled: boolean) => {
setBusy('global'); setMessage(null); setError(null);
try {
@@ -81,6 +93,7 @@ export function AssetGatewayPage() {
provider: draft.provider || null,
llmProviderKeyId: draft.llmProviderKeyId || null,
llmModel: draft.llmModel || null,
purposes: draft.purposes,
});
setConfig(result.config);
setDrafts(Object.fromEntries(result.config.plugins.map((item) => [item.pluginId, draftFromPlugin(item)])));
@@ -126,11 +139,21 @@ export function AssetGatewayPage() {
</label>
</div>
<div className="asset-plugin-fields">
<label> Provider<select value={draft.provider} onChange={(event) => updateDraft(plugin.pluginId, { provider: event.target.value })} disabled={!draft.enabled}>
<label> Provider<select value={draft.provider} onChange={(event) => {
const provider = event.target.value;
updateDraft(plugin.pluginId, {
provider,
...(provider === 'image_make' ? { llmProviderKeyId: '', llmModel: '' } : {}),
});
}} disabled={!draft.enabled}>
<option value=""> Provider</option>
{plugin.providers.map((provider) => <option key={provider} value={provider}>{provider}</option>)}
</select></label>
{plugin.supportsLlm ? <>
{plugin.pluginId === 'asset-generate' && draft.provider === 'image_make' ? (
<div className="asset-image-make-note">
image_make
</div>
) : plugin.supportsLlm ? <>
<label> LLM<select value={draft.llmProviderKeyId} onChange={(event) => updateDraft(plugin.pluginId, { llmProviderKeyId: event.target.value, llmModel: '' })} disabled={!draft.enabled}>
<option value="">使 LLM</option>
{activeKeys.map((key) => <option key={key.id} value={key.id}>{key.name}</option>)}
@@ -140,6 +163,24 @@ export function AssetGatewayPage() {
{selectedKey?.models.map((model) => <option key={model} value={model}>{model}</option>)}
</select></label>
</> : <div className="asset-no-llm"> · LLM</div>}
{plugin.pluginId === 'asset-generate' && plugin.purposeCatalog?.length ? (
<fieldset className="asset-purpose-fieldset" disabled={!draft.enabled || draft.provider !== 'image_make'}>
<legend>image_make </legend>
<div className="asset-purpose-grid">
{plugin.purposeCatalog.map((purpose) => (
<label key={purpose.id}>
<input
type="checkbox"
checked={Boolean(draft.purposes[purpose.id])}
onChange={(event) => updatePurpose(plugin.pluginId, purpose.id, event.target.checked)}
/>
<span>{purpose.label}<small>{purpose.presetId}</small></span>
</label>
))}
</div>
<p> MindSpace </p>
</fieldset>
) : null}
</div>
<div className="asset-plugin-footer"><span className={`asset-status ${draft.enabled ? 'is-on' : ''}`}>{draft.enabled ? '待保存为启用' : '默认安全关闭'}</span><button type="button" className="send-btn" disabled={busy === plugin.pluginId} onClick={() => void savePlugin(plugin)}>{busy === plugin.pluginId ? '保存中…' : '保存配置'}</button></div>
</section>;
+1
View File
@@ -307,6 +307,7 @@ export async function updateAssetPluginConfig(
provider?: string | null;
llmProviderKeyId?: string | null;
llmModel?: string | null;
purposes?: Record<string, boolean>;
},
): Promise<{ ok: boolean; config: AssetGatewayConfig }> {
return portalFetch(`/admin-api/asset-gateway/plugins/${encodeURIComponent(pluginId)}`, {
+54
View File
@@ -1080,6 +1080,60 @@ body,
min-width: 0;
}
.asset-image-make-note,
.asset-no-llm {
padding: 9px 10px;
border-radius: var(--radius-sm);
background: rgba(132, 110, 255, .1);
color: var(--color-text-muted);
font-size: 11px;
line-height: 1.5;
}
.asset-purpose-fieldset {
min-width: 0;
margin: 2px 0 0;
padding: 10px;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
}
.asset-purpose-fieldset legend {
padding: 0 5px;
color: var(--color-text-muted);
font-size: 11px;
}
.asset-purpose-fieldset > p {
margin: 8px 0 0;
color: var(--color-text-muted);
font-size: 10px;
line-height: 1.45;
}
.asset-purpose-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 7px;
}
.asset-purpose-grid label {
display: flex;
align-items: flex-start;
gap: 7px;
padding: 7px;
border-radius: var(--radius-xs);
background: rgba(255, 255, 255, .035);
}
.asset-purpose-grid small {
display: block;
margin-top: 2px;
color: var(--color-text-muted);
font-size: 9px;
word-break: break-all;
}
.asset-plugin-footer {
display: flex;
align-items: center;
+6
View File
@@ -208,6 +208,12 @@ export type AssetPluginConfig = {
llmProviderId: string | null;
llmModel: string | null;
updatedAt: number | null;
purposes?: Record<string, boolean>;
purposeCatalog?: Array<{
id: string;
label: string;
presetId: string;
}>;
};
export type AssetGatewayConfig = {