From a6f946dde8fa3d15a805277dca73766af3ba89f1 Mon Sep 17 00:00:00 2001 From: Nene7ko_ <1604009816@qq.com> Date: Wed, 2 Sep 2026 08:08:02 +0800 Subject: [PATCH 01/33] chore: checkpoint current admin ui --- .gitmodules | 3 + admin-ui/.gitignore | 3 + admin-ui/.smoke/01-tenants-lobby.png | Bin 0 -> 37937 bytes admin-ui/.smoke/02-tenant-settings.png | Bin 0 -> 48426 bytes admin-ui/.smoke/03-apps-lobby.png | Bin 0 -> 41762 bytes admin-ui/.smoke/04-app-detail.png | Bin 0 -> 37459 bytes admin-ui/.smoke/05-draft-editor.png | Bin 0 -> 40435 bytes admin-ui/.smoke/06-backends-lobby.png | Bin 0 -> 45401 bytes admin-ui/.smoke/06-check.png | Bin 0 -> 3695 bytes admin-ui/.smoke/07-backend-detail.png | Bin 0 -> 38432 bytes admin-ui/.smoke/mock-api.mjs | 182 ++ admin-ui/index.html | 12 + admin-ui/package-lock.json | 2334 +++++++++++++++++ admin-ui/package.json | 43 + admin-ui/src/App.tsx | 57 + admin-ui/src/api/client.ts | 236 ++ admin-ui/src/api/types.ts | 221 ++ admin-ui/src/components/AppShell.tsx | 90 + admin-ui/src/components/AuditFields.tsx | 25 + admin-ui/src/components/BindingsEditor.tsx | 99 + admin-ui/src/components/DraftEditor.tsx | 248 ++ admin-ui/src/components/KeyValueEditor.tsx | 54 + admin-ui/src/components/LoadState.tsx | 35 + admin-ui/src/components/ProtocolFields.tsx | 76 + admin-ui/src/components/ReasonDialog.tsx | 92 + admin-ui/src/components/ResourceLobby.tsx | 111 + admin-ui/src/components/StatusActions.tsx | 104 + admin-ui/src/components/StatusTag.tsx | 18 + admin-ui/src/lib/connection.tsx | 75 + admin-ui/src/lib/draftSession.ts | 42 + admin-ui/src/lib/format.ts | 24 + admin-ui/src/lib/mutation.ts | 91 + admin-ui/src/lib/recents.ts | 51 + admin-ui/src/main.tsx | 18 + admin-ui/src/pages/ConnectPage.tsx | 62 + admin-ui/src/pages/TenantsPage.tsx | 74 + admin-ui/src/pages/tenant/AppDetailPage.tsx | 430 +++ admin-ui/src/pages/tenant/AppsPage.tsx | 77 + .../src/pages/tenant/BackendDetailPage.tsx | 188 ++ admin-ui/src/pages/tenant/BackendsPage.tsx | 88 + .../src/pages/tenant/BindingDetailPage.tsx | 195 ++ admin-ui/src/pages/tenant/BindingsPage.tsx | 116 + admin-ui/src/pages/tenant/ModelDetailPage.tsx | 270 ++ admin-ui/src/pages/tenant/ModelsPage.tsx | 107 + admin-ui/src/pages/tenant/TenantLayout.tsx | 84 + admin-ui/src/pages/tenant/TenantOverview.tsx | 232 ++ admin-ui/src/styles/app.less | 103 + admin-ui/src/styles/tdesign.less | 8 + admin-ui/tsconfig.json | 21 + admin-ui/vite.config.ts | 89 + docs/docs/admin-web-ui.md | 242 ++ docs/mkdocs.yml | 1 + third_party/tdesign-react | 1 + 53 files changed, 6732 insertions(+) create mode 100644 .gitmodules create mode 100644 admin-ui/.gitignore create mode 100644 admin-ui/.smoke/01-tenants-lobby.png create mode 100644 admin-ui/.smoke/02-tenant-settings.png create mode 100644 admin-ui/.smoke/03-apps-lobby.png create mode 100644 admin-ui/.smoke/04-app-detail.png create mode 100644 admin-ui/.smoke/05-draft-editor.png create mode 100644 admin-ui/.smoke/06-backends-lobby.png create mode 100644 admin-ui/.smoke/06-check.png create mode 100644 admin-ui/.smoke/07-backend-detail.png create mode 100644 admin-ui/.smoke/mock-api.mjs create mode 100644 admin-ui/index.html create mode 100644 admin-ui/package-lock.json create mode 100644 admin-ui/package.json create mode 100644 admin-ui/src/App.tsx create mode 100644 admin-ui/src/api/client.ts create mode 100644 admin-ui/src/api/types.ts create mode 100644 admin-ui/src/components/AppShell.tsx create mode 100644 admin-ui/src/components/AuditFields.tsx create mode 100644 admin-ui/src/components/BindingsEditor.tsx create mode 100644 admin-ui/src/components/DraftEditor.tsx create mode 100644 admin-ui/src/components/KeyValueEditor.tsx create mode 100644 admin-ui/src/components/LoadState.tsx create mode 100644 admin-ui/src/components/ProtocolFields.tsx create mode 100644 admin-ui/src/components/ReasonDialog.tsx create mode 100644 admin-ui/src/components/ResourceLobby.tsx create mode 100644 admin-ui/src/components/StatusActions.tsx create mode 100644 admin-ui/src/components/StatusTag.tsx create mode 100644 admin-ui/src/lib/connection.tsx create mode 100644 admin-ui/src/lib/draftSession.ts create mode 100644 admin-ui/src/lib/format.ts create mode 100644 admin-ui/src/lib/mutation.ts create mode 100644 admin-ui/src/lib/recents.ts create mode 100644 admin-ui/src/main.tsx create mode 100644 admin-ui/src/pages/ConnectPage.tsx create mode 100644 admin-ui/src/pages/TenantsPage.tsx create mode 100644 admin-ui/src/pages/tenant/AppDetailPage.tsx create mode 100644 admin-ui/src/pages/tenant/AppsPage.tsx create mode 100644 admin-ui/src/pages/tenant/BackendDetailPage.tsx create mode 100644 admin-ui/src/pages/tenant/BackendsPage.tsx create mode 100644 admin-ui/src/pages/tenant/BindingDetailPage.tsx create mode 100644 admin-ui/src/pages/tenant/BindingsPage.tsx create mode 100644 admin-ui/src/pages/tenant/ModelDetailPage.tsx create mode 100644 admin-ui/src/pages/tenant/ModelsPage.tsx create mode 100644 admin-ui/src/pages/tenant/TenantLayout.tsx create mode 100644 admin-ui/src/pages/tenant/TenantOverview.tsx create mode 100644 admin-ui/src/styles/app.less create mode 100644 admin-ui/src/styles/tdesign.less create mode 100644 admin-ui/tsconfig.json create mode 100644 admin-ui/vite.config.ts create mode 100644 docs/docs/admin-web-ui.md create mode 160000 third_party/tdesign-react diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..a3ce8f48 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/tdesign-react"] + path = third_party/tdesign-react + url = https://github.com/Tencent/tdesign-react.git diff --git a/admin-ui/.gitignore b/admin-ui/.gitignore new file mode 100644 index 00000000..e5537bed --- /dev/null +++ b/admin-ui/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +*.local diff --git a/admin-ui/.smoke/01-tenants-lobby.png b/admin-ui/.smoke/01-tenants-lobby.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3fad3629c2242bf8a6a88a8a19315ecd8abf47 GIT binary patch literal 37937 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