feat(admin-web): add Feishu Application Connection admin page

ADR-0021 pins the organization<->Feishu application binding to 1:1 and
the backend already exposes
  GET    /api/org/:orgSlug/feishu-application-connection
  PUT    /api/org/:orgSlug/feishu-application-connection  (rotate/create)
  DELETE /api/org/:orgSlug/feishu-application-connection  (disable)
backed by FeishuApplicationConnectionService with versioned envelopes
(ADR-0024). The org-admin SPA had no surface for it, so the only
connection type the spec requires was unmanageable from the admin UI.

Add a Feishu page that reads the current connection (status, redacted
app fingerprint, active version, updatedAt), rotates credentials with
appId/appSecret/botOpenId (+ optional verificationToken/encryptKey) as
the backend requires, and disables with confirmation. Add the matching
api client (feishuApplication / rotateFeishuApplication /
disableFeishuApplication), a feishu nav icon and a nav entry.
This commit is contained in:
2026-07-13 23:48:58 +08:00
parent 8d2e0cb2c6
commit 18acc823c3
4 changed files with 223 additions and 4 deletions
+28 -1
View File
@@ -156,6 +156,16 @@ export interface ProviderConnectionRow {
updatedAt: string;
}
export interface FeishuApplicationConnection {
id: string;
appFingerprint: string;
status: 'DRAFT' | 'ACTIVE' | 'DISABLED';
activeVersion: number | null;
keyId: string | null;
createdAt: string;
updatedAt: string;
}
export interface UsageTotals {
runCount: number;
runsWithCost: number;
@@ -259,5 +269,22 @@ export const api = {
put(
`${orgBase(slug)}/provider-connections/${encodeURIComponent(providerId)}`,
body,
) as Promise<ProviderConnectionRow>
) as Promise<ProviderConnectionRow>,
feishuApplication: (slug: string) =>
get(`${orgBase(slug)}/feishu-application-connection`) as Promise<{
connection: FeishuApplicationConnection | null;
}>,
rotateFeishuApplication: (
slug: string,
body: {
appId: string;
appSecret: string;
botOpenId: string;
verificationToken?: string;
encryptKey?: string;
},
) => put(`${orgBase(slug)}/feishu-application-connection`, body) as Promise<FeishuApplicationConnection>,
disableFeishuApplication: (slug: string) =>
del(`${orgBase(slug)}/feishu-application-connection`) as Promise<FeishuApplicationConnection>
};