feat(web): place workspace controls in sidebar

This commit is contained in:
dadachann
2026-07-25 16:26:13 +08:00
parent 9ea1a81048
commit 7c64cd9d51
5 changed files with 99 additions and 12 deletions
@@ -1915,6 +1915,10 @@ export default function HomeSidebar({
</SidebarMenu>
</SidebarHeader>
<div className="px-2 group-data-[collapsible=icon]:px-0">
<WorkspaceSwitcher className="w-full group-data-[collapsible=icon]:min-w-0 group-data-[collapsible=icon]:px-2" />
</div>
{/* Navigation items grouped by section */}
<div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
<SidebarContent ref={navigationContentRef} className="min-h-0 pb-8">
@@ -1970,11 +1974,6 @@ export default function HomeSidebar({
{/* Footer */}
<SidebarFooter>
{currentWorkspace?.workspace.source === 'cloud_projection' && (
<div className="px-2 group-data-[collapsible=icon]:px-0">
<WorkspaceSwitcher className="w-full group-data-[collapsible=icon]:min-w-0 group-data-[collapsible=icon]:px-2" />
</div>
)}
{/* Models entry */}
<SidebarMenu>
<SidebarMenuItem>
@@ -1,5 +1,12 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Copy, Loader2, Trash2, UserPlus, Users } from 'lucide-react';
import {
Copy,
ExternalLink,
Loader2,
Trash2,
UserPlus,
Users,
} from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
@@ -27,12 +34,11 @@ import type {
WorkspaceMembership,
WorkspaceRole,
} from '@/app/infra/entities/workspace';
import { backendClient } from '@/app/infra/http';
import { backendClient, systemInfo } from '@/app/infra/http';
import {
PanelBody,
PanelToolbar,
} from '@/app/home/components/settings-dialog/panel-layout';
import WorkspaceSwitcher from './WorkspaceSwitcher';
interface WorkspaceSettingsPanelProps {
active: boolean;
@@ -77,6 +83,13 @@ export default function WorkspaceSettingsPanel({
!isCloudProjection && permissions.has('member.remove');
const canTransferOwner =
!isCloudProjection && permissions.has('owner.transfer');
const canManageCloudMembers =
isCloudProjection &&
(workspaceInfo?.membership.role === 'owner' ||
workspaceInfo?.membership.role === 'admin');
const cloudMembersURL = workspaceInfo
? `${systemInfo.cloud_service_url.replace(/\/$/, '')}/cloud?workspace=${encodeURIComponent(workspaceInfo.workspace.uuid)}#workspace-members`
: '';
const loadWorkspace = useCallback(async () => {
setLoading(true);
@@ -203,12 +216,20 @@ export default function WorkspaceSettingsPanel({
)}
</p>
</div>
<WorkspaceSwitcher className="ml-auto" />
{workspaceInfo && (
<Badge variant="secondary">
{t(`workspace.roles.${workspaceInfo.membership.role}`)}
</Badge>
)}
{canManageCloudMembers && (
<Button asChild size="sm" variant="outline">
<a href={cloudMembersURL} target="_blank" rel="noopener noreferrer">
<UserPlus />
{t('workspace.inviteMember')}
<ExternalLink className="size-3.5" />
</a>
</Button>
)}
</PanelToolbar>
<PanelBody className="space-y-6">
@@ -40,7 +40,7 @@ export default function WorkspaceSwitcher({
const workspaces = useWorkspaceBootstrap();
const isCloud = currentWorkspace?.workspace.source === 'cloud_projection';
if (!currentWorkspace || (!isCloud && workspaces.length <= 1)) return null;
if (!currentWorkspace) return null;
const cloudPortalUrl = `${systemInfo.cloud_service_url.replace(/\/$/, '')}/cloud?workspace=${encodeURIComponent(currentWorkspace.workspace.uuid)}`;
-2
View File
@@ -43,7 +43,6 @@ import {
PluginInstallProgressDialog,
} from '@/app/home/plugins/components/plugin-install-task';
import { setDocumentTitle } from '@/hooks/useDocumentTitle';
import WorkspaceSwitcher from '@/app/home/components/workspace-settings/WorkspaceSwitcher';
// Routes that belong to the "Extensions" section
const EXTENSIONS_ROUTES = [
@@ -265,7 +264,6 @@ function HomeLayoutInner({ children }: { children: React.ReactNode }) {
)}
</BreadcrumbList>
</Breadcrumb>
<WorkspaceSwitcher className="ml-auto w-44" />
</div>
</header>