Skip to content

Commit 46c69e2

Browse files
committed
feat(enrichment): admin enrichment view + readiness-driven status bar
* `/enrichment` admin view: paginated cache list, refresh / invalidate actions, providers status bar, EnrichmentCard preview * shorthand editor: pick subtype + auto-resolve preview before submit * status bar reads server-computed `ready` / `missingKeys` instead of trying to mirror gating against a sanitized `thirdPartyServiceIntegration` (apiKey was redacted, causing false "缺 apiKey" warnings) * groups providers by `featureGateConfigKey` so TMDB and Bangumi land in separate chips even though both share the `media` category
1 parent af0df1c commit 46c69e2

15 files changed

Lines changed: 1674 additions & 120 deletions

File tree

apps/admin/src/api/enrichment.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type {
2+
EnrichmentListResponse,
3+
EnrichmentProviderMeta,
4+
EnrichmentResult,
5+
} from '~/models/enrichment'
6+
7+
import { request } from '~/utils/request'
8+
9+
const encodeId = (id: string) => encodeURIComponent(id)
10+
11+
export const enrichmentApi = {
12+
resolve: (url: string) =>
13+
request.get<EnrichmentResult>('/enrichment/resolve', {
14+
params: { url },
15+
}),
16+
17+
list: (params: { page?: number; size?: number; onlyFailed?: boolean } = {}) =>
18+
request.get<EnrichmentListResponse>('/enrichment/admin/list', {
19+
params: {
20+
...params,
21+
...(params.onlyFailed ? { onlyFailed: true } : {}),
22+
},
23+
}),
24+
25+
providers: () =>
26+
request.get<EnrichmentProviderMeta[]>('/enrichment/admin/providers'),
27+
28+
refresh: (provider: string, externalId: string) =>
29+
request.post<EnrichmentResult>(
30+
`/enrichment/admin/refresh/${encodeURIComponent(provider)}/${encodeId(externalId)}`,
31+
),
32+
33+
invalidate: (provider: string, externalId: string) =>
34+
request.delete<void>(
35+
`/enrichment/admin/cache/${encodeURIComponent(provider)}/${encodeId(externalId)}`,
36+
),
37+
}

apps/admin/src/api/recently.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,34 @@ import type { RecentlyModel } from '~/models/recently'
22

33
import { request } from '~/utils/request'
44

5+
export type RecentlyType =
6+
| 'text'
7+
| 'link'
8+
| 'book'
9+
| 'media'
10+
| 'music'
11+
| 'github'
12+
| 'academic'
13+
| 'code'
14+
15+
export interface RecentlyCreatePayload {
16+
type?: RecentlyType
17+
content?: string
18+
metadata?: Record<string, unknown>
19+
}
20+
21+
export type RecentlyUpdatePayload = RecentlyCreatePayload
22+
523
export const recentlyApi = {
624
// 获取最近访问列表
725
getAll: () => request.get<RecentlyModel[]>('/recently/all'),
826

927
// 创建速记
10-
create: (data: { content: string }) =>
28+
create: (data: RecentlyCreatePayload) =>
1129
request.post<RecentlyModel>('/recently', { data }),
1230

1331
// 更新速记
14-
update: (id: string, data: { content: string }) =>
32+
update: (id: string, data: RecentlyUpdatePayload) =>
1533
request.put<RecentlyModel>(`/recently/${id}`, { data }),
1634

1735
// 删除最近访问项

apps/admin/src/components/config-form/index.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,21 @@ export const SectionFields = defineComponent({
9999

100100
// Handle nested fields (object type)
101101
if (field.fields && field.fields.length > 0) {
102+
if (field.subsection) {
103+
return (
104+
<Subsection
105+
key={fieldPath}
106+
title={field.subsection.title}
107+
description={field.subsection.description}
108+
>
109+
<SectionFields
110+
fields={field.fields}
111+
formData={formData}
112+
dataKeyPrefix={fieldPath}
113+
/>
114+
</Subsection>
115+
)
116+
}
102117
return (
103118
<SectionFields
104119
fields={field.fields}
@@ -292,3 +307,27 @@ export const FormFieldItem = defineComponent({
292307
}
293308
},
294309
})
310+
311+
const Subsection = defineComponent({
312+
props: {
313+
title: { type: String, required: true },
314+
description: String,
315+
},
316+
setup(props, { slots }) {
317+
return () => (
318+
<div class="border-t border-neutral-100 first:border-t-0 dark:border-neutral-800">
319+
<div class="px-4 pb-2 pt-4">
320+
<div class="text-xs font-semibold uppercase tracking-wide text-neutral-500 dark:text-neutral-400">
321+
{props.title}
322+
</div>
323+
{props.description && (
324+
<p class="mt-1 text-xs text-neutral-400 dark:text-neutral-500">
325+
{props.description}
326+
</p>
327+
)}
328+
</div>
329+
{slots.default?.()}
330+
</div>
331+
)
332+
},
333+
})

apps/admin/src/components/config-form/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export interface FormField {
4040
required?: boolean
4141
ui: UIConfig
4242
fields?: FormField[]
43+
subsection?: {
44+
title: string
45+
description?: string
46+
}
4347
}
4448

4549
export interface FormSection {

0 commit comments

Comments
 (0)