From 199d0259cd8924beeac185ac72b38243f3957d79 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 14 Apr 2026 09:10:41 +0200 Subject: [PATCH] feat: add "+ App" shortcut button to sidebar Applications header Adds a subtle "+ App" button in the sidebar section header for quick app creation without navigating to the Deployments tab first. Only visible to OPERATOR and ADMIN roles. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/src/components/LayoutShell.module.css | 28 +++++++++++++ ui/src/components/LayoutShell.tsx | 50 +++++++++++++++--------- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/ui/src/components/LayoutShell.module.css b/ui/src/components/LayoutShell.module.css index 2c09aa76..4f89366e 100644 --- a/ui/src/components/LayoutShell.module.css +++ b/ui/src/components/LayoutShell.module.css @@ -43,6 +43,34 @@ opacity: 0.6; } +.appSectionWrap { + position: relative; +} + +.addAppBtn { + position: absolute; + top: 6px; + right: 6px; + z-index: 1; + display: flex; + align-items: center; + gap: 2px; + background: none; + border: none; + padding: 2px 6px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; + color: var(--sidebar-muted); + cursor: pointer; + transition: color 0.12s, background 0.12s; +} + +.addAppBtn:hover { + color: var(--amber); + background: rgba(255, 255, 255, 0.06); +} + .mainContent { flex: 1; display: flex; diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 270e1609..fce8c9f2 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -21,7 +21,7 @@ import { } from '@cameleer/design-system'; import type { SearchResult, SidebarTreeNode, DropdownItem, ButtonGroupItem, ExchangeStatus } from '@cameleer/design-system'; import sidebarLogo from '@cameleer/design-system/assets/cameleer3-logo.svg'; -import { Box, Settings, FileText, ChevronRight, Square, Pause, Star, X, User } from 'lucide-react'; +import { Box, Settings, FileText, ChevronRight, Square, Pause, Star, X, User, Plus } from 'lucide-react'; import { AboutMeDialog } from './AboutMeDialog'; import css from './LayoutShell.module.css'; import { useQueryClient } from '@tanstack/react-query'; @@ -31,7 +31,7 @@ import { useSearchExecutions, useAttributeKeys } from '../api/queries/executions import { useUsers, useGroups, useRoles } from '../api/queries/admin/rbac'; import { useEnvironments } from '../api/queries/admin/environments'; import type { UserDetail, GroupDetail, RoleDetail } from '../api/queries/admin/rbac'; -import { useAuthStore, useIsAdmin } from '../auth/auth-store'; +import { useAuthStore, useIsAdmin, useCanControl } from '../auth/auth-store'; import { useEnvironmentStore } from '../api/environment-store'; import { useState, useMemo, useCallback, useEffect, useRef, createElement } from 'react'; import type { ReactNode } from 'react'; @@ -296,6 +296,7 @@ function LayoutContent() { // --- Role checks ---------------------------------------------------- const isAdmin = useIsAdmin(); + const canControl = useCanControl(); // --- Environment filtering ----------------------------------------- const selectedEnv = useEnvironmentStore((s) => s.environment); @@ -692,23 +693,34 @@ function LayoutContent() { /> {/* Applications section */} - - - +
+ {canControl && ( + + )} + + + +
{/* Starred section — only when there are starred items */} {starredItems.length > 0 && (