feat(cloud): manage LLM providers in database
Tests / Test passed: 664

This commit is contained in:
2026-07-14 00:31:47 +08:00
parent b613a315ff
commit a166ffd8a4
35 changed files with 2432 additions and 204 deletions
+11 -1
View File
@@ -7,6 +7,7 @@ import {
LogOut,
MonitorSmartphone,
Puzzle,
SlidersHorizontal,
UsersRound,
} from "@lucide/vue";
import {
@@ -14,6 +15,7 @@ import {
getCurrentUser,
logout,
} from "./api";
import { hasScope } from "./permissions";
import type { CloudUser } from "./types";
import LoginScreen from "./views/LoginScreen.vue";
import PasswordChangeScreen from "./views/PasswordChangeScreen.vue";
@@ -21,8 +23,9 @@ import TasksView from "./views/TasksView.vue";
import DevicesView from "./views/DevicesView.vue";
import PluginsView from "./views/PluginsView.vue";
import UsersView from "./views/UsersView.vue";
import LlmProvidersView from "./views/LlmProvidersView.vue";
type ViewId = "tasks" | "devices" | "plugins" | "users";
type ViewId = "tasks" | "devices" | "plugins" | "users" | "providers";
const activeView = ref<ViewId>("tasks");
const currentUser = ref<CloudUser | null>(null);
@@ -49,6 +52,7 @@ const canAdminGovernance = computed(
currentUser.value?.scopes.includes("*") ||
currentUser.value?.scopes.includes("governance:admin")),
);
const canAdminProviders = computed(() => hasScope(currentUser.value, "llm-providers:admin"));
const isAuthenticated = computed(() => currentUser.value !== null);
const currentUserLabel = computed(() =>
currentUser.value ? `${currentUser.value.display_name} (${currentUser.value.role})` : "",
@@ -63,6 +67,9 @@ const navItems = computed<{ id: ViewId; label: string; icon: Component }[]>(() =
if (canAdminUsers.value || canAdminGovernance.value) {
items.push({ id: "users", label: "Users & limits", icon: UsersRound });
}
if (canAdminProviders.value) {
items.push({ id: "providers", label: "LLM providers", icon: SlidersHorizontal });
}
return items;
});
@@ -119,6 +126,8 @@ const activeComponent = computed(() => {
return PluginsView;
case "users":
return UsersView;
case "providers":
return LlmProvidersView;
default:
return TasksView;
}
@@ -155,6 +164,7 @@ const activeComponent = computed(() => {
:can-admin-users="canAdminUsers"
:can-admin-governance="canAdminGovernance"
/>
<LlmProvidersView v-else-if="activeView === 'providers'" :can-admin="canAdminProviders" />
<component v-else :is="activeComponent" :can-submit="canSubmitTasks" />
</main>
</div>