|
|
@@ -14,7 +14,6 @@
|
|
|
|
|
|
import { useState } from 'react'
|
|
|
import type { ReactNode } from 'react'
|
|
|
-import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
|
import { Button, IconPlusOutline16, Modal } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
import type { InjectFace, PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
|
|
|
// Type-only: pulls this package's SlotMap merge (the two Models child slots).
|
|
|
@@ -22,6 +21,7 @@ import type {} from './slot-contract.ts'
|
|
|
import { CustomProviderCard } from './CustomProviderCard.tsx'
|
|
|
import { deriveKeyRef, protocolChoices, providerUsable } from './store.ts'
|
|
|
import type { ModelsSettingsStore, ProviderRow } from './store.ts'
|
|
|
+import type { ModelsOperations } from './operations.ts'
|
|
|
import type { SettingsSchemaOperations } from './schema-operations.ts'
|
|
|
import { ProviderEditor, type ProviderEditorProps } from './ProviderEditor.tsx'
|
|
|
import type { en } from './locales.ts'
|
|
|
@@ -35,8 +35,8 @@ export interface ModelsSectionInjected {
|
|
|
/** Page snapshot bound by the UI renderer as useSnapshot. */
|
|
|
snapshot: ModelsSettingsStore['store']
|
|
|
}
|
|
|
- /** The page plugin's context, whose Remote namespaces the editors write through. */
|
|
|
- ctx: ClientContext
|
|
|
+ /** The Host operations the section and its cards invoke. */
|
|
|
+ operations: ModelsOperations
|
|
|
/** Settings schema and immutable path callbacks. */
|
|
|
schema: SettingsSchemaOperations
|
|
|
/** Section copy. */
|
|
|
@@ -81,7 +81,7 @@ interface EditorTarget extends ProviderIdentity {
|
|
|
/** Values that vary around the shared provider-editor rendering. */
|
|
|
interface ProviderEditorRenderProps extends Pick<
|
|
|
ProviderEditorProps,
|
|
|
- 'namespace' | 'schema' | 'ctx' | 't' | 'readOnly' | 'onClose'
|
|
|
+ 'namespace' | 'schema' | 'operations' | 't' | 'readOnly' | 'onClose'
|
|
|
> {
|
|
|
target: EditorTarget
|
|
|
}
|
|
|
@@ -105,26 +105,26 @@ function renderProviderEditor({ target, ...props }: ProviderEditorRenderProps):
|
|
|
* and the whole operation safely retryable; both unsets are idempotent.
|
|
|
* The settings removal names the profile rather than rebuilding its whole
|
|
|
* namespace from a partial view.
|
|
|
- * @param ctx - the page plugin's context, carrying the settings and credential Remote namespaces.
|
|
|
+ * @param operations - the page's Host operations.
|
|
|
* @param controller - the page store to refresh.
|
|
|
* @param target - the provider's settings address and optional managed credential.
|
|
|
* @returns the failure message, or undefined once the write and reload landed.
|
|
|
*/
|
|
|
export async function removeProviderProfile(
|
|
|
- ctx: ClientContext,
|
|
|
+ operations: ModelsOperations,
|
|
|
controller: ModelsSettingsStore,
|
|
|
target: { settingsNs: string; settingsPath: readonly string[]; credentialRef?: string },
|
|
|
): Promise<string | undefined> {
|
|
|
if (target.credentialRef !== undefined) {
|
|
|
- const credential = await ctx.remote.credentials.unset(target.credentialRef)
|
|
|
- if (!credential.ok) return credential.error.message
|
|
|
+ const credential = await operations.removeCredential(target.credentialRef)
|
|
|
+ if (credential !== undefined) return credential
|
|
|
}
|
|
|
- const response = await ctx.remote.settings.mutate(
|
|
|
+ const written = await operations.writeSettings(
|
|
|
target.settingsNs,
|
|
|
[{ op: 'unset', path: [...target.settingsPath] }],
|
|
|
undefined,
|
|
|
)
|
|
|
- if (!response.ok) return response.error.message
|
|
|
+ if (written.kind !== 'written') return written.message
|
|
|
await controller.load()
|
|
|
return undefined
|
|
|
}
|
|
|
@@ -193,16 +193,16 @@ export function providerCopy(template: string, target: ProviderIdentity): string
|
|
|
* @returns the section, or null while the shell has not injected yet.
|
|
|
*/
|
|
|
export function ModelsSection(props: ModelsSectionProps): ReactNode {
|
|
|
- const { controller, useSnapshot, ctx, schema, t, renderSlot } = props
|
|
|
+ const { controller, useSnapshot, operations, schema, t, renderSlot } = props
|
|
|
if (
|
|
|
- controller === undefined || useSnapshot === undefined || ctx === undefined
|
|
|
+ controller === undefined || useSnapshot === undefined || operations === undefined
|
|
|
|| schema === undefined || t === undefined
|
|
|
) return null
|
|
|
- return <Loaded injected={{ controller, useSnapshot, ctx, schema, t }} renderSlot={renderSlot} />
|
|
|
+ return <Loaded injected={{ controller, useSnapshot, operations, schema, t }} renderSlot={renderSlot} />
|
|
|
}
|
|
|
|
|
|
function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderSlot: ModelsRenderSlot }): ReactNode {
|
|
|
- const { controller, ctx, schema, t } = injected
|
|
|
+ const { controller, operations, schema, t } = injected
|
|
|
const state = injected.useSnapshot(snapshot => snapshot)
|
|
|
const [editing, setEditing] = useState<EditorTarget | undefined>(undefined)
|
|
|
const [adding, setAdding] = useState(false)
|
|
|
@@ -250,7 +250,7 @@ function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderS
|
|
|
if (deleteTarget === undefined || deleting) return
|
|
|
setDeleting(true)
|
|
|
setDeleteFailure(undefined)
|
|
|
- void removeProviderProfile(ctx, controller, deleteTarget)
|
|
|
+ void removeProviderProfile(operations, controller, deleteTarget)
|
|
|
.then((failure) => {
|
|
|
if (failure !== undefined) {
|
|
|
setDeleteFailure(failure)
|
|
|
@@ -331,7 +331,7 @@ function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderS
|
|
|
target,
|
|
|
namespace,
|
|
|
schema,
|
|
|
- ctx,
|
|
|
+ operations,
|
|
|
t,
|
|
|
readOnly: !state.writable,
|
|
|
onClose: (changed) => { closeSetup(changed, target) },
|
|
|
@@ -426,7 +426,7 @@ function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderS
|
|
|
target,
|
|
|
namespace,
|
|
|
schema,
|
|
|
- ctx,
|
|
|
+ operations,
|
|
|
t,
|
|
|
readOnly: !state.writable,
|
|
|
onClose: (changed) => { closeEditor(changed, target) },
|
|
|
@@ -466,7 +466,7 @@ function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderS
|
|
|
namespace={addNamespace}
|
|
|
schema={schema}
|
|
|
settingsPath={addTarget.settingsPath}
|
|
|
- ctx={ctx}
|
|
|
+ operations={operations}
|
|
|
t={t}
|
|
|
readOnly={!state.writable}
|
|
|
onClose={(changed) => { closeEditor(changed, addTarget) }}
|
|
|
@@ -488,7 +488,7 @@ function Loaded({ injected, renderSlot }: { injected: ModelsSectionFace; renderS
|
|
|
protocols={protocols}
|
|
|
/* v8 ignore next -- the card only opens from a button disabled without this namespace */
|
|
|
revision={state.namespaces.get('llm-pi-ai')?.revision ?? 0}
|
|
|
- ctx={ctx}
|
|
|
+ operations={operations}
|
|
|
t={t}
|
|
|
readOnly={!state.writable}
|
|
|
onClose={(changed) => {
|