feat: move Apps from admin to main tab bar with container config
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m20s
CI / docker (push) Successful in 1m8s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Failing after 2m16s

- Apps tab visible to OPERATOR+ (hidden for VIEWER), scoped by
  sidebar app selection and environment filter
- List view: DataTable with name, environment, updated, created columns
- Detail view: deployments across all envs, version upload with
  per-env deploy target, container config form (resources, ports,
  custom env vars) with explicit Save
- Memory reserve field disabled for non-production environments
  with info hint
- Admin sidebar sorted alphabetically, Applications entry removed
- Old admin AppsPage deleted

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-08 16:23:30 +02:00
parent 875062e59a
commit de4ca10fa5
9 changed files with 726 additions and 417 deletions

View File

@@ -1,9 +1,11 @@
import { useMemo } from 'react';
import { Tabs } from '@cameleer/design-system';
import type { TabKey, Scope } from '../hooks/useScope';
import { TabKpis } from './TabKpis';
import { useCanControl } from '../auth/auth-store';
import styles from './ContentTabs.module.css';
const TABS = [
const BASE_TABS = [
{ label: 'Exchanges', value: 'exchanges' },
{ label: 'Dashboard', value: 'dashboard' },
{ label: 'Runtime', value: 'runtime' },
@@ -18,10 +20,16 @@ interface ContentTabsProps {
}
export function ContentTabs({ active, onChange, scope }: ContentTabsProps) {
const canControl = useCanControl();
const tabs = useMemo(() => {
if (!canControl) return BASE_TABS;
return [...BASE_TABS, { label: 'Apps', value: 'apps' }];
}, [canControl]);
return (
<div className={styles.wrapper}>
<Tabs
tabs={TABS}
tabs={tabs}
active={active}
onChange={(v) => onChange(v as TabKey)}
/>

View File

@@ -94,16 +94,15 @@ export function buildAppTreeNodes(
}
/**
* Admin tree — static nodes.
* Admin tree — static nodes, alphabetically sorted.
*/
export function buildAdminTreeNodes(): SidebarTreeNode[] {
return [
{ id: 'admin:environments', label: 'Environments', path: '/admin/environments' },
{ id: 'admin:apps', label: 'Applications', path: '/admin/apps' },
{ id: 'admin:rbac', label: 'Users & Roles', path: '/admin/rbac' },
{ id: 'admin:audit', label: 'Audit Log', path: '/admin/audit' },
{ id: 'admin:oidc', label: 'OIDC', path: '/admin/oidc' },
{ id: 'admin:database', label: 'Database', path: '/admin/database' },
{ id: 'admin:clickhouse', label: 'ClickHouse', path: '/admin/clickhouse' },
{ id: 'admin:database', label: 'Database', path: '/admin/database' },
{ id: 'admin:environments', label: 'Environments', path: '/admin/environments' },
{ id: 'admin:oidc', label: 'OIDC', path: '/admin/oidc' },
{ id: 'admin:rbac', label: 'Users & Roles', path: '/admin/rbac' },
];
}