feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
import { useState, useMemo, useRef, useEffect, useCallback } from 'react';
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
import { useParams, useNavigate, useLocation } from 'react-router';
|
2026-04-08 16:23:30 +02:00
|
|
|
import {
|
|
|
|
|
Badge,
|
|
|
|
|
Button,
|
2026-04-08 17:55:37 +02:00
|
|
|
ConfirmDialog,
|
2026-04-08 16:23:30 +02:00
|
|
|
DataTable,
|
|
|
|
|
Input,
|
|
|
|
|
MonoText,
|
|
|
|
|
SectionHeader,
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
Select,
|
2026-04-08 16:23:30 +02:00
|
|
|
Spinner,
|
2026-04-09 08:00:54 +02:00
|
|
|
StatusDot,
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
Toggle,
|
2026-04-08 16:23:30 +02:00
|
|
|
useToast,
|
|
|
|
|
} from '@cameleer/design-system';
|
|
|
|
|
import type { Column } from '@cameleer/design-system';
|
|
|
|
|
import { useEnvironmentStore } from '../../api/environment-store';
|
|
|
|
|
import { useEnvironments } from '../../api/queries/admin/environments';
|
|
|
|
|
import {
|
|
|
|
|
useAllApps,
|
|
|
|
|
useApps,
|
|
|
|
|
useCreateApp,
|
|
|
|
|
useDeleteApp,
|
|
|
|
|
useAppVersions,
|
|
|
|
|
useUploadJar,
|
|
|
|
|
useDeployments,
|
|
|
|
|
useCreateDeployment,
|
|
|
|
|
useStopDeployment,
|
|
|
|
|
useUpdateContainerConfig,
|
|
|
|
|
} from '../../api/queries/admin/apps';
|
|
|
|
|
import type { App, AppVersion, Deployment } from '../../api/queries/admin/apps';
|
|
|
|
|
import type { Environment } from '../../api/queries/admin/environments';
|
2026-04-08 18:09:12 +02:00
|
|
|
import { useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping } from '../../api/queries/commands';
|
|
|
|
|
import type { ApplicationConfig, TapDefinition } from '../../api/queries/commands';
|
2026-04-08 23:43:14 +02:00
|
|
|
import { useCatalog } from '../../api/queries/catalog';
|
|
|
|
|
import type { CatalogApp, CatalogRoute } from '../../api/queries/catalog';
|
2026-04-08 20:33:41 +02:00
|
|
|
import { DeploymentProgress } from '../../components/DeploymentProgress';
|
2026-04-08 16:23:30 +02:00
|
|
|
import styles from './AppsTab.module.css';
|
|
|
|
|
|
|
|
|
|
function formatBytes(bytes: number): string {
|
|
|
|
|
if (bytes >= 1_048_576) return `${(bytes / 1_048_576).toFixed(1)} MB`;
|
|
|
|
|
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
|
|
|
return `${bytes} B`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function timeAgo(date: string): string {
|
|
|
|
|
const seconds = Math.floor((Date.now() - new Date(date).getTime()) / 1000);
|
|
|
|
|
if (seconds < 60) return `${seconds}s ago`;
|
|
|
|
|
const minutes = Math.floor(seconds / 60);
|
|
|
|
|
if (minutes < 60) return `${minutes}m ago`;
|
|
|
|
|
const hours = Math.floor(minutes / 60);
|
|
|
|
|
if (hours < 24) return `${hours}h ago`;
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
return `${Math.floor(hours / 24)}d ago`;
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const STATUS_COLORS: Record<string, 'success' | 'warning' | 'error' | 'auto' | 'running'> = {
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
RUNNING: 'running', STARTING: 'warning', FAILED: 'error', STOPPED: 'auto',
|
2026-04-08 20:33:41 +02:00
|
|
|
DEGRADED: 'warning', STOPPING: 'auto',
|
2026-04-08 16:23:30 +02:00
|
|
|
};
|
|
|
|
|
|
2026-04-09 08:00:54 +02:00
|
|
|
const DEPLOY_STATUS_DOT: Record<string, string> = {
|
|
|
|
|
RUNNING: 'live', STARTING: 'running', DEGRADED: 'stale',
|
|
|
|
|
STOPPING: 'stale', STOPPED: 'dead', FAILED: 'error',
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-08 17:48:20 +02:00
|
|
|
function slugify(name: string): string {
|
|
|
|
|
return name
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
|
|
|
.replace(/^-+|-+$/g, '')
|
|
|
|
|
.substring(0, 100);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:23:30 +02:00
|
|
|
export default function AppsTab() {
|
|
|
|
|
const { appId } = useParams<{ appId?: string }>();
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const location = useLocation();
|
2026-04-08 16:23:30 +02:00
|
|
|
const selectedEnv = useEnvironmentStore((s) => s.environment);
|
|
|
|
|
const { data: environments = [] } = useEnvironments();
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
if (location.pathname.endsWith('/apps/new')) return <CreateAppView environments={environments} selectedEnv={selectedEnv} />;
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
if (appId) return <AppDetailView appId={appId} environments={environments} selectedEnv={selectedEnv} />;
|
|
|
|
|
return <AppListView selectedEnv={selectedEnv} environments={environments} />;
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
// LIST VIEW
|
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
2026-04-08 16:23:30 +02:00
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
function AppListView({ selectedEnv, environments }: { selectedEnv: string | undefined; environments: Environment[] }) {
|
|
|
|
|
const navigate = useNavigate();
|
2026-04-08 16:23:30 +02:00
|
|
|
const { data: allApps = [], isLoading: allLoading } = useAllApps();
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const envId = useMemo(() => environments.find((e) => e.slug === selectedEnv)?.id, [environments, selectedEnv]);
|
|
|
|
|
const { data: envApps = [], isLoading: envLoading } = useApps(envId);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
|
|
|
|
const apps = selectedEnv ? envApps : allApps;
|
|
|
|
|
const isLoading = selectedEnv ? envLoading : allLoading;
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const envMap = useMemo(() => new Map(environments.map((e) => [e.id, e])), [environments]);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
type AppRow = App & { id: string; envName: string };
|
2026-04-08 16:23:30 +02:00
|
|
|
const rows: AppRow[] = useMemo(
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
() => apps.map((a) => ({ ...a, envName: envMap.get(a.environmentId)?.displayName ?? '?' })),
|
2026-04-08 16:23:30 +02:00
|
|
|
[apps, envMap],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const columns: Column<AppRow>[] = useMemo(() => [
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{ key: 'displayName', header: 'Name', sortable: true,
|
|
|
|
|
render: (_v: unknown, row: AppRow) => (
|
|
|
|
|
<div><div className={styles.cellName}>{row.displayName}</div><div className={styles.cellMeta}>{row.slug}</div></div>
|
2026-04-08 16:23:30 +02:00
|
|
|
),
|
|
|
|
|
},
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
...(!selectedEnv ? [{ key: 'envName', header: 'Environment', sortable: true,
|
|
|
|
|
render: (_v: unknown, row: AppRow) => <Badge label={row.envName} color={'auto' as const} />,
|
2026-04-08 16:23:30 +02:00
|
|
|
}] : []),
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{ key: 'updatedAt', header: 'Updated', sortable: true,
|
|
|
|
|
render: (_v: unknown, row: AppRow) => <span className={styles.cellMeta}>{timeAgo(row.updatedAt)}</span>,
|
2026-04-08 16:23:30 +02:00
|
|
|
},
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{ key: 'createdAt', header: 'Created', sortable: true,
|
|
|
|
|
render: (_v: unknown, row: AppRow) => <span className={styles.cellMeta}>{new Date(row.createdAt).toLocaleDateString()}</span>,
|
2026-04-08 16:23:30 +02:00
|
|
|
},
|
|
|
|
|
], [selectedEnv]);
|
|
|
|
|
|
|
|
|
|
if (isLoading) return <Spinner size="md" />;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles.container}>
|
|
|
|
|
<div className={styles.toolbar}>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<Button size="sm" variant="primary" onClick={() => navigate('/apps/new')}>+ Create App</Button>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
2026-04-08 23:43:14 +02:00
|
|
|
<DataTable columns={columns} data={rows} onRowClick={(row) => navigate(`/apps/${row.slug}`)} />
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 17:48:20 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
// CREATE APP PAGE
|
2026-04-08 17:48:20 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
function CreateAppView({ environments, selectedEnv }: { environments: Environment[]; selectedEnv: string | undefined }) {
|
2026-04-08 17:48:20 +02:00
|
|
|
const { toast } = useToast();
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const navigate = useNavigate();
|
2026-04-08 17:48:20 +02:00
|
|
|
const createApp = useCreateApp();
|
|
|
|
|
const uploadJar = useUploadJar();
|
|
|
|
|
const createDeployment = useCreateDeployment();
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const updateAgentConfig = useUpdateApplicationConfig();
|
|
|
|
|
const updateContainerConfig = useUpdateContainerConfig();
|
|
|
|
|
|
|
|
|
|
const defaultEnvId = useMemo(() => environments.find((e) => e.slug === selectedEnv)?.id ?? (environments.length > 0 ? environments[0].id : ''), [environments, selectedEnv]);
|
2026-04-08 17:48:20 +02:00
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
// Identity
|
2026-04-08 17:48:20 +02:00
|
|
|
const [name, setName] = useState('');
|
|
|
|
|
const [slugEdited, setSlugEdited] = useState(false);
|
|
|
|
|
const [slug, setSlug] = useState('');
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const [envId, setEnvId] = useState(defaultEnvId);
|
2026-04-08 17:48:20 +02:00
|
|
|
const [file, setFile] = useState<File | null>(null);
|
|
|
|
|
const [deploy, setDeploy] = useState(true);
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
|
|
|
|
|
|
|
|
// Monitoring
|
|
|
|
|
const [engineLevel, setEngineLevel] = useState('REGULAR');
|
|
|
|
|
const [payloadCapture, setPayloadCapture] = useState('BOTH');
|
|
|
|
|
const [payloadSize, setPayloadSize] = useState('4');
|
|
|
|
|
const [payloadUnit, setPayloadUnit] = useState('KB');
|
|
|
|
|
const [appLogLevel, setAppLogLevel] = useState('INFO');
|
|
|
|
|
const [agentLogLevel, setAgentLogLevel] = useState('INFO');
|
|
|
|
|
const [metricsEnabled, setMetricsEnabled] = useState(true);
|
|
|
|
|
const [metricsInterval, setMetricsInterval] = useState('60');
|
|
|
|
|
const [samplingRate, setSamplingRate] = useState('1.0');
|
|
|
|
|
const [compressSuccess, setCompressSuccess] = useState(false);
|
|
|
|
|
const [replayEnabled, setReplayEnabled] = useState(true);
|
|
|
|
|
const [routeControlEnabled, setRouteControlEnabled] = useState(true);
|
|
|
|
|
|
|
|
|
|
// Resources
|
|
|
|
|
const env = useMemo(() => environments.find((e) => e.id === envId), [environments, envId]);
|
|
|
|
|
const isProd = env?.production ?? false;
|
|
|
|
|
const defaults = env?.defaultContainerConfig ?? {};
|
|
|
|
|
const [memoryLimit, setMemoryLimit] = useState(String(defaults.memoryLimitMb ?? 512));
|
|
|
|
|
const [memoryReserve, setMemoryReserve] = useState(String(defaults.memoryReserveMb ?? ''));
|
2026-04-09 07:38:23 +02:00
|
|
|
const [cpuRequest, setCpuRequest] = useState(String(defaults.cpuRequest ?? 500));
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const [cpuLimit, setCpuLimit] = useState(String(defaults.cpuLimit ?? ''));
|
|
|
|
|
const [ports, setPorts] = useState<number[]>(Array.isArray(defaults.exposedPorts) ? defaults.exposedPorts as number[] : []);
|
|
|
|
|
const [newPort, setNewPort] = useState('');
|
|
|
|
|
const [envVars, setEnvVars] = useState<{ key: string; value: string }[]>([]);
|
2026-04-08 20:33:41 +02:00
|
|
|
const [appPort, setAppPort] = useState('8080');
|
|
|
|
|
const [replicas, setReplicas] = useState('1');
|
|
|
|
|
const [deployStrategy, setDeployStrategy] = useState('blue-green');
|
|
|
|
|
const [stripPrefix, setStripPrefix] = useState(true);
|
|
|
|
|
const [sslOffloading, setSslOffloading] = useState(true);
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
|
2026-04-09 07:38:23 +02:00
|
|
|
const [configTab, setConfigTab] = useState<'monitoring' | 'resources' | 'variables'>('monitoring');
|
2026-04-08 17:48:20 +02:00
|
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
|
const [step, setStep] = useState('');
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
// Reset resource defaults when environment changes
|
2026-04-08 17:48:20 +02:00
|
|
|
useEffect(() => {
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
const d = environments.find((e) => e.id === envId)?.defaultContainerConfig ?? {};
|
|
|
|
|
setMemoryLimit(String(d.memoryLimitMb ?? 512));
|
|
|
|
|
setMemoryReserve(String(d.memoryReserveMb ?? ''));
|
2026-04-09 07:38:23 +02:00
|
|
|
setCpuRequest(String(d.cpuRequest ?? 500));
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
setCpuLimit(String(d.cpuLimit ?? ''));
|
|
|
|
|
setPorts(Array.isArray(d.exposedPorts) ? d.exposedPorts as number[] : []);
|
|
|
|
|
}, [envId, environments]);
|
2026-04-08 17:48:20 +02:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!slugEdited) setSlug(slugify(name));
|
|
|
|
|
}, [name, slugEdited]);
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
function addPort() {
|
|
|
|
|
const p = parseInt(newPort);
|
|
|
|
|
if (p && !ports.includes(p)) { setPorts([...ports, p]); setNewPort(''); }
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 17:48:20 +02:00
|
|
|
const canSubmit = name.trim() && slug.trim() && envId && file;
|
|
|
|
|
|
|
|
|
|
async function handleSubmit() {
|
|
|
|
|
if (!canSubmit) return;
|
|
|
|
|
setBusy(true);
|
|
|
|
|
try {
|
|
|
|
|
// 1. Create app
|
|
|
|
|
setStep('Creating app...');
|
|
|
|
|
const app = await createApp.mutateAsync({ environmentId: envId, slug: slug.trim(), displayName: name.trim() });
|
|
|
|
|
|
|
|
|
|
// 2. Upload JAR
|
|
|
|
|
setStep('Uploading JAR...');
|
2026-04-08 23:43:14 +02:00
|
|
|
const version = await uploadJar.mutateAsync({ appId: app.slug, file: file! });
|
2026-04-08 17:48:20 +02:00
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
// 3. Save container config
|
|
|
|
|
setStep('Saving configuration...');
|
|
|
|
|
const containerConfig: Record<string, unknown> = {
|
|
|
|
|
memoryLimitMb: memoryLimit ? parseInt(memoryLimit) : null,
|
|
|
|
|
memoryReserveMb: memoryReserve ? parseInt(memoryReserve) : null,
|
2026-04-09 07:38:23 +02:00
|
|
|
cpuRequest: cpuRequest ? parseInt(cpuRequest) : null,
|
|
|
|
|
cpuLimit: cpuLimit ? parseInt(cpuLimit) : null,
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
exposedPorts: ports,
|
|
|
|
|
customEnvVars: Object.fromEntries(envVars.filter((v) => v.key.trim()).map((v) => [v.key, v.value])),
|
2026-04-08 20:33:41 +02:00
|
|
|
appPort: appPort ? parseInt(appPort) : 8080,
|
|
|
|
|
replicas: replicas ? parseInt(replicas) : 1,
|
|
|
|
|
deploymentStrategy: deployStrategy,
|
|
|
|
|
stripPathPrefix: stripPrefix,
|
|
|
|
|
sslOffloading: sslOffloading,
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
};
|
2026-04-08 23:43:14 +02:00
|
|
|
await updateContainerConfig.mutateAsync({ appId: app.slug, config: containerConfig });
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
|
|
|
|
|
// 4. Save agent config (will be pushed to agent on first connect)
|
|
|
|
|
setStep('Saving monitoring config...');
|
|
|
|
|
await updateAgentConfig.mutateAsync({
|
|
|
|
|
application: slug.trim(),
|
|
|
|
|
version: 0,
|
|
|
|
|
engineLevel,
|
|
|
|
|
payloadCaptureMode: payloadCapture,
|
|
|
|
|
applicationLogLevel: appLogLevel,
|
|
|
|
|
agentLogLevel,
|
|
|
|
|
metricsEnabled,
|
|
|
|
|
samplingRate: parseFloat(samplingRate) || 1.0,
|
|
|
|
|
compressSuccess,
|
|
|
|
|
tracedProcessors: {},
|
|
|
|
|
taps: [],
|
|
|
|
|
tapVersion: 0,
|
|
|
|
|
routeRecording: {},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 5. Deploy (if requested)
|
2026-04-08 17:48:20 +02:00
|
|
|
if (deploy) {
|
|
|
|
|
setStep('Starting deployment...');
|
2026-04-08 23:43:14 +02:00
|
|
|
await createDeployment.mutateAsync({ appId: app.slug, appVersionId: version.id, environmentId: envId });
|
2026-04-08 17:48:20 +02:00
|
|
|
}
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
toast({ title: deploy ? 'App created and deployed' : 'App created', description: name.trim(), variant: 'success' });
|
2026-04-08 23:43:14 +02:00
|
|
|
navigate(`/apps/${app.slug}`);
|
2026-04-08 17:48:20 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
toast({ title: 'Failed: ' + step, description: e instanceof Error ? e.message : 'Unknown error', variant: 'error', duration: 86_400_000 });
|
|
|
|
|
} finally {
|
|
|
|
|
setBusy(false);
|
|
|
|
|
setStep('');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<div className={styles.container}>
|
|
|
|
|
<div className={styles.detailHeader}>
|
|
|
|
|
<div>
|
|
|
|
|
<h2 className={styles.detailTitle}>Create Application</h2>
|
|
|
|
|
<div className={styles.detailMeta}>Configure and deploy a new application</div>
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<div className={styles.detailActions}>
|
|
|
|
|
<Button size="sm" variant="ghost" onClick={() => navigate('/apps')} disabled={busy}>Cancel</Button>
|
|
|
|
|
<Button size="sm" variant="primary" onClick={handleSubmit} loading={busy} disabled={!canSubmit || busy}>
|
|
|
|
|
{deploy ? 'Create & Deploy' : 'Create'}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{step && <div className={styles.stepIndicator}>{step}</div>}
|
|
|
|
|
|
|
|
|
|
{/* Identity Section */}
|
|
|
|
|
<SectionHeader>Identity & Artifact</SectionHeader>
|
|
|
|
|
<div className={styles.configGrid}>
|
|
|
|
|
<span className={styles.configLabel}>Application Name</span>
|
|
|
|
|
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Payment Gateway" disabled={busy} />
|
|
|
|
|
|
2026-04-08 18:45:02 +02:00
|
|
|
<span className={styles.configLabel}>External URL</span>
|
|
|
|
|
<MonoText size="sm">/{env?.slug ?? '...'}/{slug || '...'}/</MonoText>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Environment</span>
|
|
|
|
|
<Select value={envId} onChange={(e) => setEnvId(e.target.value)} disabled={busy}
|
|
|
|
|
options={environments.filter((e) => e.enabled).map((e) => ({ value: e.id, label: `${e.displayName} (${e.slug})` }))} />
|
2026-04-08 17:48:20 +02:00
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<span className={styles.configLabel}>Application JAR</span>
|
|
|
|
|
<div className={styles.fileRow}>
|
2026-04-08 21:17:50 +02:00
|
|
|
<input ref={fileInputRef} type="file" accept=".jar"
|
2026-04-08 21:23:05 +02:00
|
|
|
style={{ position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0,0,0,0)', border: 0 }}
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
|
2026-04-08 21:17:50 +02:00
|
|
|
<Button size="sm" variant="secondary" type="button" onClick={() => fileInputRef.current?.click()} disabled={busy}>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
{file ? 'Change file' : 'Select JAR'}
|
|
|
|
|
</Button>
|
|
|
|
|
{file && <span className={styles.fileName}>{file.name} ({formatBytes(file.size)})</span>}
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<span className={styles.configLabel}>Deploy</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={deploy} onChange={() => setDeploy(!deploy)} disabled={busy} />
|
|
|
|
|
<span className={deploy ? styles.toggleEnabled : styles.toggleDisabled}>
|
|
|
|
|
{deploy ? 'Deploy immediately after creation' : 'Create only (deploy later)'}
|
|
|
|
|
</span>
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
</div>
|
2026-04-08 17:48:20 +02:00
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
{/* Config Tabs */}
|
|
|
|
|
<div className={styles.subTabs}>
|
|
|
|
|
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
|
|
|
|
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
2026-04-09 07:38:23 +02:00
|
|
|
<button className={`${styles.subTab} ${configTab === 'variables' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('variables')}>Variables</button>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
</div>
|
|
|
|
|
|
2026-04-08 18:47:58 +02:00
|
|
|
{configTab === 'variables' && (
|
|
|
|
|
<>
|
|
|
|
|
{envVars.map((v, i) => (
|
|
|
|
|
<div key={i} className={styles.envVarRow}>
|
|
|
|
|
<Input disabled={busy} value={v.key} onChange={(e) => {
|
|
|
|
|
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
|
|
|
|
}} className={styles.envVarKey} placeholder="KEY" />
|
|
|
|
|
<Input disabled={busy} value={v.value} onChange={(e) => {
|
|
|
|
|
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
|
|
|
|
}} className={styles.envVarValue} placeholder="value" />
|
|
|
|
|
<button className={styles.envVarDelete} disabled={busy}
|
|
|
|
|
onClick={() => !busy && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
<Button size="sm" variant="secondary" disabled={busy} onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
{configTab === 'monitoring' && (
|
|
|
|
|
<div className={styles.configGrid}>
|
|
|
|
|
<span className={styles.configLabel}>Engine Level</span>
|
|
|
|
|
<Select disabled={busy} value={engineLevel} onChange={(e) => setEngineLevel(e.target.value)}
|
|
|
|
|
options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Payload Capture</span>
|
|
|
|
|
<Select disabled={busy} value={payloadCapture} onChange={(e) => setPayloadCapture(e.target.value)}
|
|
|
|
|
options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Max Payload Size</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled={busy} value={payloadSize} onChange={(e) => setPayloadSize(e.target.value)} style={{ width: 70 }} />
|
|
|
|
|
<Select disabled={busy} value={payloadUnit} onChange={(e) => setPayloadUnit(e.target.value)} style={{ width: 90 }}
|
|
|
|
|
options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<span className={styles.configLabel}>App Log Level</span>
|
|
|
|
|
<Select disabled={busy} value={appLogLevel} onChange={(e) => setAppLogLevel(e.target.value)}
|
|
|
|
|
options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Agent Log Level</span>
|
|
|
|
|
<Select disabled={busy} value={agentLogLevel} onChange={(e) => setAgentLogLevel(e.target.value)}
|
|
|
|
|
options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Metrics</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={metricsEnabled} onChange={() => !busy && setMetricsEnabled(!metricsEnabled)} disabled={busy} />
|
|
|
|
|
<span className={metricsEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{metricsEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
<span className={styles.cellMeta} style={{ marginLeft: 8 }}>Interval</span>
|
|
|
|
|
<Input disabled={busy} value={metricsInterval} onChange={(e) => setMetricsInterval(e.target.value)} style={{ width: 50 }} />
|
|
|
|
|
<span className={styles.cellMeta}>s</span>
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
|
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<span className={styles.configLabel}>Sampling Rate</span>
|
|
|
|
|
<Input disabled={busy} value={samplingRate} onChange={(e) => setSamplingRate(e.target.value)} style={{ width: 80 }} />
|
2026-04-08 17:48:20 +02:00
|
|
|
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
<span className={styles.configLabel}>Compress Success</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={compressSuccess} onChange={() => !busy && setCompressSuccess(!compressSuccess)} disabled={busy} />
|
|
|
|
|
<span className={compressSuccess ? styles.toggleEnabled : styles.toggleDisabled}>{compressSuccess ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Replay</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={replayEnabled} onChange={() => !busy && setReplayEnabled(!replayEnabled)} disabled={busy} />
|
|
|
|
|
<span className={replayEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{replayEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Route Control</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={routeControlEnabled} onChange={() => !busy && setRouteControlEnabled(!routeControlEnabled)} disabled={busy} />
|
|
|
|
|
<span className={routeControlEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{routeControlEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
2026-04-08 17:48:20 +02:00
|
|
|
</div>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{configTab === 'resources' && (
|
|
|
|
|
<>
|
|
|
|
|
<SectionHeader>Container Resources</SectionHeader>
|
|
|
|
|
<div className={styles.configGrid}>
|
|
|
|
|
<span className={styles.configLabel}>Memory Limit</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled={busy} value={memoryLimit} onChange={(e) => setMemoryLimit(e.target.value)} style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>MB</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Memory Reserve</span>
|
|
|
|
|
<div>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled={!isProd || busy} value={memoryReserve} onChange={(e) => setMemoryReserve(e.target.value)} placeholder="---" style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>MB</span>
|
|
|
|
|
</div>
|
|
|
|
|
{!isProd && <span className={styles.configHint}>Available in production environments only</span>}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-04-09 07:38:23 +02:00
|
|
|
<span className={styles.configLabel}>CPU Request</span>
|
|
|
|
|
<Input disabled={busy} value={cpuRequest} onChange={(e) => setCpuRequest(e.target.value)} style={{ width: 80 }} />
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>CPU Limit</span>
|
|
|
|
|
<div className={styles.configInline}>
|
2026-04-09 07:38:23 +02:00
|
|
|
<Input disabled={busy} value={cpuLimit} onChange={(e) => setCpuLimit(e.target.value)} placeholder="e.g. 1000" style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>millicores</span>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Exposed Ports</span>
|
|
|
|
|
<div className={styles.portPills}>
|
|
|
|
|
{ports.map((p) => (
|
|
|
|
|
<span key={p} className={styles.portPill}>
|
|
|
|
|
{p}
|
|
|
|
|
<button className={styles.portPillDelete} disabled={busy}
|
|
|
|
|
onClick={() => !busy && setPorts(ports.filter((x) => x !== p))}>×</button>
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
|
|
|
|
<input className={styles.portAddInput} disabled={busy} placeholder="+ port" value={newPort}
|
|
|
|
|
onChange={(e) => setNewPort(e.target.value)}
|
|
|
|
|
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
|
|
|
|
</div>
|
2026-04-08 20:33:41 +02:00
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>App Port</span>
|
|
|
|
|
<Input disabled={busy} value={appPort} onChange={(e) => setAppPort(e.target.value)} style={{ width: 80 }} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Replicas</span>
|
|
|
|
|
<Input disabled={busy} value={replicas} onChange={(e) => setReplicas(e.target.value)} style={{ width: 60 }} type="number" />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Deploy Strategy</span>
|
|
|
|
|
<Select disabled={busy} value={deployStrategy} onChange={(e) => setDeployStrategy(e.target.value)}
|
|
|
|
|
options={[{ value: 'blue-green', label: 'Blue/Green' }, { value: 'rolling', label: 'Rolling' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Strip Path Prefix</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={stripPrefix} onChange={() => !busy && setStripPrefix(!stripPrefix)} disabled={busy} />
|
|
|
|
|
<span className={stripPrefix ? styles.toggleEnabled : styles.toggleDisabled}>{stripPrefix ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>SSL Offloading</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={sslOffloading} onChange={() => !busy && setSslOffloading(!sslOffloading)} disabled={busy} />
|
|
|
|
|
<span className={sslOffloading ? styles.toggleEnabled : styles.toggleDisabled}>{sslOffloading ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
feat: replace create-app modal with full creation page at /apps/new
Full-page creation flow with:
- Identity section: name, auto-slug, environment, JAR upload, deploy toggle
- Monitoring tab: engine level, payload capture, log levels, metrics,
sampling, compress success, replay, route control
- Resources tab: memory, CPU, ports, environment variables
Environment variables are configurable before first deploy, addressing
the need to set app-specific config upfront.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:31:34 +02:00
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-04-08 17:48:20 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
// DETAIL VIEW
|
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
2026-04-08 16:23:30 +02:00
|
|
|
|
2026-04-08 23:43:14 +02:00
|
|
|
function AppDetailView({ appId: appSlug, environments, selectedEnv }: { appId: string; environments: Environment[]; selectedEnv: string | undefined }) {
|
2026-04-08 16:23:30 +02:00
|
|
|
const { toast } = useToast();
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const navigate = useNavigate();
|
2026-04-08 16:23:30 +02:00
|
|
|
const { data: allApps = [] } = useAllApps();
|
2026-04-08 23:43:14 +02:00
|
|
|
const app = useMemo(() => allApps.find((a) => a.slug === appSlug), [allApps, appSlug]);
|
2026-04-09 08:00:54 +02:00
|
|
|
const { data: catalogApps } = useCatalog(selectedEnv);
|
|
|
|
|
const catalogEntry = useMemo(() => (catalogApps ?? []).find((c: CatalogApp) => c.slug === appSlug), [catalogApps, appSlug]);
|
2026-04-08 23:43:14 +02:00
|
|
|
const { data: versions = [] } = useAppVersions(appSlug);
|
|
|
|
|
const { data: deployments = [] } = useDeployments(appSlug);
|
2026-04-08 16:23:30 +02:00
|
|
|
const uploadJar = useUploadJar();
|
|
|
|
|
const createDeployment = useCreateDeployment();
|
|
|
|
|
const stopDeployment = useStopDeployment();
|
|
|
|
|
const deleteApp = useDeleteApp();
|
|
|
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
2026-04-09 07:38:23 +02:00
|
|
|
const [subTab, setSubTab] = useState<'overview' | 'config'>('config');
|
2026-04-08 17:55:37 +02:00
|
|
|
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const envMap = useMemo(() => new Map(environments.map((e) => [e.id, e])), [environments]);
|
|
|
|
|
const sortedVersions = useMemo(() => [...versions].sort((a, b) => b.version - a.version), [versions]);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
|
|
|
|
if (!app) return <Spinner size="md" />;
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const env = envMap.get(app.environmentId);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
|
|
|
|
async function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {
|
|
|
|
|
const file = e.target.files?.[0];
|
|
|
|
|
if (!file) return;
|
|
|
|
|
try {
|
2026-04-08 23:43:14 +02:00
|
|
|
const v = await uploadJar.mutateAsync({ appId: appSlug, file });
|
2026-04-08 16:23:30 +02:00
|
|
|
toast({ title: `Version ${v.version} uploaded`, description: file.name, variant: 'success' });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
} catch { toast({ title: 'Upload failed', variant: 'error', duration: 86_400_000 }); }
|
2026-04-08 16:23:30 +02:00
|
|
|
if (fileInputRef.current) fileInputRef.current.value = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleDeploy(versionId: string, environmentId: string) {
|
|
|
|
|
try {
|
2026-04-08 23:43:14 +02:00
|
|
|
await createDeployment.mutateAsync({ appId: appSlug, appVersionId: versionId, environmentId });
|
2026-04-08 16:23:30 +02:00
|
|
|
toast({ title: 'Deployment started', variant: 'success' });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
} catch { toast({ title: 'Deploy failed', variant: 'error', duration: 86_400_000 }); }
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleStop(deploymentId: string) {
|
|
|
|
|
try {
|
2026-04-08 23:43:14 +02:00
|
|
|
await stopDeployment.mutateAsync({ appId: appSlug, deploymentId });
|
2026-04-08 16:23:30 +02:00
|
|
|
toast({ title: 'Deployment stopped', variant: 'warning' });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
} catch { toast({ title: 'Stop failed', variant: 'error', duration: 86_400_000 }); }
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleDelete() {
|
|
|
|
|
try {
|
2026-04-08 23:43:14 +02:00
|
|
|
await deleteApp.mutateAsync(appSlug);
|
2026-04-08 16:23:30 +02:00
|
|
|
toast({ title: 'App deleted', variant: 'warning' });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
navigate('/apps');
|
|
|
|
|
} catch { toast({ title: 'Delete failed', variant: 'error', duration: 86_400_000 }); }
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles.container}>
|
|
|
|
|
<div className={styles.detailHeader}>
|
|
|
|
|
<div>
|
2026-04-09 08:00:54 +02:00
|
|
|
<h2 className={styles.detailTitle}>
|
|
|
|
|
{catalogEntry && (
|
|
|
|
|
<span title={catalogEntry.healthTooltip} style={{ marginRight: 6, verticalAlign: 'middle' }}>
|
|
|
|
|
<StatusDot variant={catalogEntry.health === 'offline' ? 'dead' : catalogEntry.health as any} />
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
{app.displayName}
|
|
|
|
|
</h2>
|
2026-04-08 16:23:30 +02:00
|
|
|
<div className={styles.detailMeta}>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{app.slug} · <Badge label={env?.displayName ?? '?'} color="auto" />
|
2026-04-09 08:00:54 +02:00
|
|
|
{catalogEntry?.deployment && (
|
|
|
|
|
<> · <Badge label={catalogEntry.deployment.status} color={STATUS_COLORS[catalogEntry.deployment.status as keyof typeof STATUS_COLORS] ?? 'auto'} /></>
|
|
|
|
|
)}
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<div className={styles.detailActions}>
|
2026-04-08 21:17:50 +02:00
|
|
|
<input ref={fileInputRef} type="file" accept=".jar"
|
2026-04-08 21:23:05 +02:00
|
|
|
style={{ position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0,0,0,0)', border: 0 }}
|
2026-04-08 21:17:50 +02:00
|
|
|
onChange={handleUpload} />
|
|
|
|
|
<Button size="sm" variant="primary" type="button" onClick={() => fileInputRef.current?.click()} loading={uploadJar.isPending}>Upload JAR</Button>
|
2026-04-08 17:55:37 +02:00
|
|
|
<Button size="sm" variant="danger" onClick={() => setDeleteConfirm(true)}>Delete App</Button>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
</div>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<div className={styles.subTabs}>
|
|
|
|
|
<button className={`${styles.subTab} ${subTab === 'config' ? styles.subTabActive : ''}`} onClick={() => setSubTab('config')}>Configuration</button>
|
2026-04-09 07:38:23 +02:00
|
|
|
<button className={`${styles.subTab} ${subTab === 'overview' ? styles.subTabActive : ''}`} onClick={() => setSubTab('overview')}>Overview</button>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{subTab === 'overview' && (
|
|
|
|
|
<OverviewSubTab
|
|
|
|
|
app={app} deployments={deployments} versions={sortedVersions}
|
|
|
|
|
environments={environments} envMap={envMap} selectedEnv={selectedEnv}
|
|
|
|
|
onDeploy={handleDeploy} onStop={handleStop}
|
2026-04-08 16:23:30 +02:00
|
|
|
/>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
)}
|
|
|
|
|
{subTab === 'config' && (
|
|
|
|
|
<ConfigSubTab app={app} environment={env} />
|
|
|
|
|
)}
|
2026-04-08 17:55:37 +02:00
|
|
|
|
|
|
|
|
<ConfirmDialog
|
|
|
|
|
open={deleteConfirm}
|
|
|
|
|
onClose={() => setDeleteConfirm(false)}
|
|
|
|
|
onConfirm={handleDelete}
|
|
|
|
|
message={`Delete app "${app.displayName}"? All versions and deployments will be removed. This cannot be undone.`}
|
|
|
|
|
confirmText={app.slug}
|
|
|
|
|
loading={deleteApp.isPending}
|
|
|
|
|
/>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
// OVERVIEW SUB-TAB
|
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
|
|
|
|
|
function OverviewSubTab({ app, deployments, versions, environments, envMap, selectedEnv, onDeploy, onStop }: {
|
|
|
|
|
app: App; deployments: Deployment[]; versions: AppVersion[];
|
|
|
|
|
environments: Environment[]; envMap: Map<string, Environment>;
|
|
|
|
|
selectedEnv: string | undefined;
|
|
|
|
|
onDeploy: (versionId: string, envId: string) => void;
|
|
|
|
|
onStop: (deploymentId: string) => void;
|
2026-04-08 16:23:30 +02:00
|
|
|
}) {
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// Determine which env slug is selected
|
|
|
|
|
const selectedEnvId = useMemo(
|
|
|
|
|
() => selectedEnv ? environments.find((e) => e.slug === selectedEnv)?.id : undefined,
|
|
|
|
|
[environments, selectedEnv],
|
|
|
|
|
);
|
2026-04-08 16:23:30 +02:00
|
|
|
|
|
|
|
|
return (
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<>
|
|
|
|
|
<SectionHeader>Deployments</SectionHeader>
|
|
|
|
|
{deployments.length === 0 && <p className={styles.emptyNote}>No deployments yet.</p>}
|
|
|
|
|
{deployments.length > 0 && (
|
|
|
|
|
<table className={styles.table}>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Environment</th>
|
|
|
|
|
<th>Version</th>
|
|
|
|
|
<th>Status</th>
|
2026-04-08 20:33:41 +02:00
|
|
|
<th>Replicas</th>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<th>URL</th>
|
|
|
|
|
<th>Deployed</th>
|
|
|
|
|
<th style={{ textAlign: 'right' }}>Actions</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{deployments.map((d) => {
|
|
|
|
|
const dEnv = envMap.get(d.environmentId);
|
|
|
|
|
const version = versions.find((v) => v.id === d.appVersionId);
|
|
|
|
|
const isSelectedEnv = !selectedEnvId || d.environmentId === selectedEnvId;
|
|
|
|
|
const canAct = isSelectedEnv && (d.status === 'RUNNING' || d.status === 'STARTING');
|
|
|
|
|
const canStart = isSelectedEnv && d.status === 'STOPPED';
|
2026-04-09 07:41:11 +02:00
|
|
|
const configChanged = canAct && d.deployedAt && new Date(app.updatedAt) > new Date(d.deployedAt);
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const url = dEnv ? `/${dEnv.slug}/${app.slug}/` : '';
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<tr key={d.id} className={!isSelectedEnv ? styles.mutedRow : undefined}>
|
|
|
|
|
<td>
|
|
|
|
|
<Badge label={dEnv?.displayName ?? '?'} color={dEnv?.production ? 'error' : 'auto'} />
|
|
|
|
|
</td>
|
|
|
|
|
<td><Badge label={version ? `v${version.version}` : '?'} color="auto" /></td>
|
2026-04-09 08:00:54 +02:00
|
|
|
<td style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
|
|
|
|
<StatusDot variant={DEPLOY_STATUS_DOT[d.status] ?? 'dead'} />
|
|
|
|
|
<Badge label={d.status} color={STATUS_COLORS[d.status] ?? 'auto'} />
|
|
|
|
|
</td>
|
2026-04-08 20:33:41 +02:00
|
|
|
<td>
|
|
|
|
|
{d.replicaStates && d.replicaStates.length > 0 ? (
|
|
|
|
|
<span className={styles.cellMeta}>
|
|
|
|
|
{d.replicaStates.filter((r) => r.status === 'RUNNING').length}/{d.replicaStates.length}
|
|
|
|
|
</span>
|
|
|
|
|
) : '—'}
|
|
|
|
|
</td>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<td>
|
|
|
|
|
{d.status === 'RUNNING' ? (
|
|
|
|
|
<MonoText size="xs">{url}</MonoText>
|
|
|
|
|
) : (
|
|
|
|
|
<span className={styles.mutedMono}>{url}</span>
|
|
|
|
|
)}
|
|
|
|
|
</td>
|
|
|
|
|
<td><span className={styles.cellMeta}>{d.deployedAt ? timeAgo(d.deployedAt) : '—'}</span></td>
|
2026-04-09 07:41:11 +02:00
|
|
|
<td style={{ textAlign: 'right', display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
|
|
|
|
|
{configChanged && <Button size="sm" variant="primary" onClick={() => onDeploy(d.appVersionId, d.environmentId)}>Redeploy</Button>}
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{canAct && <Button size="sm" variant="danger" onClick={() => onStop(d.id)}>Stop</Button>}
|
|
|
|
|
{canStart && <Button size="sm" variant="secondary" onClick={() => onDeploy(d.appVersionId, d.environmentId)}>Start</Button>}
|
|
|
|
|
{!isSelectedEnv && <span className={styles.envHint}>switch env to manage</span>}
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
)}
|
2026-04-08 20:33:41 +02:00
|
|
|
{deployments.filter((d) => d.deployStage).map((d) => (
|
|
|
|
|
<div key={`progress-${d.id}`} style={{ marginBottom: 8 }}>
|
|
|
|
|
<span className={styles.cellMeta}>{d.containerName}</span>
|
|
|
|
|
<DeploymentProgress currentStage={d.deployStage} failed={d.status === 'FAILED'} />
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
|
|
|
|
<SectionHeader>Versions ({versions.length})</SectionHeader>
|
|
|
|
|
{versions.length === 0 && <p className={styles.emptyNote}>No versions uploaded yet.</p>}
|
|
|
|
|
{versions.map((v) => (
|
|
|
|
|
<VersionRow key={v.id} version={v} environments={environments} onDeploy={(envId) => onDeploy(v.id, envId)} />
|
|
|
|
|
))}
|
|
|
|
|
</>
|
2026-04-08 16:23:30 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
function VersionRow({ version, environments, onDeploy }: { version: AppVersion; environments: Environment[]; onDeploy: (envId: string) => void }) {
|
2026-04-08 16:23:30 +02:00
|
|
|
const [deployEnv, setDeployEnv] = useState('');
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles.row}>
|
|
|
|
|
<Badge label={`v${version.version}`} color="auto" />
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<span className={styles.rowText}>{version.jarFilename} ({formatBytes(version.jarSizeBytes)})</span>
|
|
|
|
|
<MonoText size="xs">{version.jarChecksum.substring(0, 8)}</MonoText>
|
|
|
|
|
<span className={styles.cellMeta}>{timeAgo(version.uploadedAt)}</span>
|
|
|
|
|
<select className={styles.nativeSelect} value={deployEnv} onChange={(e) => setDeployEnv(e.target.value)}>
|
2026-04-08 16:23:30 +02:00
|
|
|
<option value="">Deploy to...</option>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
{environments.filter((e) => e.enabled).map((e) => <option key={e.id} value={e.id}>{e.displayName}</option>)}
|
2026-04-08 16:23:30 +02:00
|
|
|
</select>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<Button size="sm" variant="secondary" disabled={!deployEnv} onClick={() => { onDeploy(deployEnv); setDeployEnv(''); }}>Deploy</Button>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
|
// CONFIGURATION SUB-TAB
|
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
2026-04-08 16:23:30 +02:00
|
|
|
|
2026-04-08 18:09:12 +02:00
|
|
|
interface TracedTapRow { id: string; processorId: string; captureMode: string | null; taps: TapDefinition[]; }
|
|
|
|
|
interface RouteRecordingRow { id: string; routeId: string; recording: boolean; }
|
|
|
|
|
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
function ConfigSubTab({ app, environment }: { app: App; environment?: Environment }) {
|
2026-04-08 16:23:30 +02:00
|
|
|
const { toast } = useToast();
|
2026-04-08 18:09:12 +02:00
|
|
|
const navigate = useNavigate();
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const { data: agentConfig } = useApplicationConfig(app.slug);
|
|
|
|
|
const updateAgentConfig = useUpdateApplicationConfig();
|
|
|
|
|
const updateContainerConfig = useUpdateContainerConfig();
|
2026-04-08 23:43:14 +02:00
|
|
|
const { data: catalog } = useCatalog();
|
2026-04-08 18:09:12 +02:00
|
|
|
const { data: processorToRoute = {} } = useProcessorRouteMapping(app.slug);
|
2026-04-08 16:23:30 +02:00
|
|
|
const isProd = environment?.production ?? false;
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const [editing, setEditing] = useState(false);
|
2026-04-09 07:38:23 +02:00
|
|
|
const [configTab, setConfigTab] = useState<'monitoring' | 'resources' | 'variables' | 'traces' | 'recording'>('monitoring');
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 23:43:14 +02:00
|
|
|
const appRoutes: CatalogRoute[] = useMemo(() => {
|
2026-04-08 18:09:12 +02:00
|
|
|
if (!catalog) return [];
|
2026-04-08 23:43:14 +02:00
|
|
|
const entry = (catalog as CatalogApp[]).find((e) => e.slug === app.slug);
|
2026-04-08 18:09:12 +02:00
|
|
|
return entry?.routes ?? [];
|
|
|
|
|
}, [catalog, app.slug]);
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
|
|
|
|
// Agent config state
|
|
|
|
|
const [engineLevel, setEngineLevel] = useState('REGULAR');
|
|
|
|
|
const [payloadCapture, setPayloadCapture] = useState('BOTH');
|
|
|
|
|
const [payloadSize, setPayloadSize] = useState('4');
|
|
|
|
|
const [payloadUnit, setPayloadUnit] = useState('KB');
|
|
|
|
|
const [appLogLevel, setAppLogLevel] = useState('INFO');
|
|
|
|
|
const [agentLogLevel, setAgentLogLevel] = useState('INFO');
|
|
|
|
|
const [metricsEnabled, setMetricsEnabled] = useState(true);
|
|
|
|
|
const [metricsInterval, setMetricsInterval] = useState('60');
|
|
|
|
|
const [samplingRate, setSamplingRate] = useState('1.0');
|
|
|
|
|
const [replayEnabled, setReplayEnabled] = useState(true);
|
|
|
|
|
const [routeControlEnabled, setRouteControlEnabled] = useState(true);
|
2026-04-08 18:09:12 +02:00
|
|
|
const [compressSuccess, setCompressSuccess] = useState(false);
|
|
|
|
|
const [tracedDraft, setTracedDraft] = useState<Record<string, string>>({});
|
|
|
|
|
const [routeRecordingDraft, setRouteRecordingDraft] = useState<Record<string, boolean>>({});
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
|
|
|
|
// Container config state
|
2026-04-08 16:23:30 +02:00
|
|
|
const defaults = environment?.defaultContainerConfig ?? {};
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const merged = useMemo(() => ({ ...defaults, ...app.containerConfig }), [defaults, app.containerConfig]);
|
|
|
|
|
const [memoryLimit, setMemoryLimit] = useState('512');
|
|
|
|
|
const [memoryReserve, setMemoryReserve] = useState('');
|
2026-04-09 07:38:23 +02:00
|
|
|
const [cpuRequest, setCpuRequest] = useState('500');
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
const [cpuLimit, setCpuLimit] = useState('');
|
|
|
|
|
const [ports, setPorts] = useState<number[]>([]);
|
|
|
|
|
const [newPort, setNewPort] = useState('');
|
|
|
|
|
const [envVars, setEnvVars] = useState<{ key: string; value: string }[]>([]);
|
2026-04-08 20:33:41 +02:00
|
|
|
const [appPort, setAppPort] = useState('8080');
|
|
|
|
|
const [replicas, setReplicas] = useState('1');
|
|
|
|
|
const [deployStrategy, setDeployStrategy] = useState('blue-green');
|
|
|
|
|
const [stripPrefix, setStripPrefix] = useState(true);
|
|
|
|
|
const [sslOffloading, setSslOffloading] = useState(true);
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
|
|
|
|
// Sync from server data
|
|
|
|
|
const syncFromServer = useCallback(() => {
|
|
|
|
|
if (agentConfig) {
|
|
|
|
|
setEngineLevel(agentConfig.engineLevel ?? 'REGULAR');
|
|
|
|
|
setPayloadCapture(agentConfig.payloadCaptureMode ?? 'BOTH');
|
|
|
|
|
setPayloadSize('4'); setPayloadUnit('KB');
|
|
|
|
|
setAppLogLevel(agentConfig.applicationLogLevel ?? 'INFO');
|
|
|
|
|
setAgentLogLevel(agentConfig.agentLogLevel ?? 'INFO');
|
|
|
|
|
setMetricsEnabled(agentConfig.metricsEnabled);
|
|
|
|
|
setSamplingRate(String(agentConfig.samplingRate));
|
2026-04-08 18:09:12 +02:00
|
|
|
setCompressSuccess(agentConfig.compressSuccess);
|
|
|
|
|
setTracedDraft({ ...agentConfig.tracedProcessors });
|
|
|
|
|
setRouteRecordingDraft({ ...agentConfig.routeRecording });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
}
|
|
|
|
|
setMemoryLimit(String(merged.memoryLimitMb ?? 512));
|
|
|
|
|
setMemoryReserve(String(merged.memoryReserveMb ?? ''));
|
2026-04-09 07:38:23 +02:00
|
|
|
setCpuRequest(String(merged.cpuRequest ?? 500));
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
setCpuLimit(String(merged.cpuLimit ?? ''));
|
|
|
|
|
setPorts(Array.isArray(merged.exposedPorts) ? merged.exposedPorts as number[] : []);
|
|
|
|
|
const vars = merged.customEnvVars as Record<string, string> | undefined;
|
|
|
|
|
setEnvVars(vars ? Object.entries(vars).map(([key, value]) => ({ key, value })) : []);
|
2026-04-08 20:33:41 +02:00
|
|
|
setAppPort(String(merged.appPort ?? 8080));
|
|
|
|
|
setReplicas(String(merged.replicas ?? 1));
|
|
|
|
|
setDeployStrategy(String(merged.deploymentStrategy ?? 'blue-green'));
|
|
|
|
|
setStripPrefix(merged.stripPathPrefix !== false);
|
|
|
|
|
setSslOffloading(merged.sslOffloading !== false);
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
}, [agentConfig, merged]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => { syncFromServer(); }, [syncFromServer]);
|
|
|
|
|
|
|
|
|
|
function handleCancel() {
|
|
|
|
|
syncFromServer();
|
|
|
|
|
setEditing(false);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 18:09:12 +02:00
|
|
|
function updateTracedProcessor(processorId: string, mode: string) {
|
|
|
|
|
setTracedDraft((prev) => {
|
|
|
|
|
if (mode === 'REMOVE') { const next = { ...prev }; delete next[processorId]; return next; }
|
|
|
|
|
return { ...prev, [processorId]: mode };
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateRouteRecording(routeId: string, recording: boolean) {
|
|
|
|
|
setRouteRecordingDraft((prev) => ({ ...prev, [routeId]: recording }));
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
}
|
2026-04-08 16:23:30 +02:00
|
|
|
|
|
|
|
|
async function handleSave() {
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
// Save agent config
|
|
|
|
|
if (agentConfig) {
|
|
|
|
|
try {
|
|
|
|
|
await updateAgentConfig.mutateAsync({
|
|
|
|
|
...agentConfig,
|
|
|
|
|
engineLevel, payloadCaptureMode: payloadCapture,
|
|
|
|
|
applicationLogLevel: appLogLevel, agentLogLevel,
|
|
|
|
|
metricsEnabled, samplingRate: parseFloat(samplingRate) || 1.0,
|
2026-04-08 18:09:12 +02:00
|
|
|
compressSuccess,
|
|
|
|
|
tracedProcessors: tracedDraft,
|
|
|
|
|
routeRecording: routeRecordingDraft,
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
});
|
|
|
|
|
} catch { toast({ title: 'Failed to save agent config', variant: 'error', duration: 86_400_000 }); return; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save container config
|
|
|
|
|
const containerConfig: Record<string, unknown> = {
|
|
|
|
|
memoryLimitMb: memoryLimit ? parseInt(memoryLimit) : null,
|
|
|
|
|
memoryReserveMb: memoryReserve ? parseInt(memoryReserve) : null,
|
2026-04-09 07:38:23 +02:00
|
|
|
cpuRequest: cpuRequest ? parseInt(cpuRequest) : null,
|
|
|
|
|
cpuLimit: cpuLimit ? parseInt(cpuLimit) : null,
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
exposedPorts: ports,
|
|
|
|
|
customEnvVars: Object.fromEntries(envVars.filter((v) => v.key.trim()).map((v) => [v.key, v.value])),
|
2026-04-08 20:33:41 +02:00
|
|
|
appPort: appPort ? parseInt(appPort) : 8080,
|
|
|
|
|
replicas: replicas ? parseInt(replicas) : 1,
|
|
|
|
|
deploymentStrategy: deployStrategy,
|
|
|
|
|
stripPathPrefix: stripPrefix,
|
|
|
|
|
sslOffloading: sslOffloading,
|
2026-04-08 16:23:30 +02:00
|
|
|
};
|
|
|
|
|
try {
|
2026-04-08 23:43:14 +02:00
|
|
|
await updateContainerConfig.mutateAsync({ appId: app.slug, config: containerConfig });
|
2026-04-09 07:41:11 +02:00
|
|
|
toast({ title: 'Configuration saved', description: 'Redeploy to apply changes to running deployments.', variant: 'success' });
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
setEditing(false);
|
|
|
|
|
} catch { toast({ title: 'Failed to save container config', variant: 'error', duration: 86_400_000 }); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addPort() {
|
|
|
|
|
const p = parseInt(newPort);
|
|
|
|
|
if (p && !ports.includes(p)) { setPorts([...ports, p]); setNewPort(''); }
|
2026-04-08 16:23:30 +02:00
|
|
|
}
|
|
|
|
|
|
2026-04-08 18:09:12 +02:00
|
|
|
// Traces & Taps
|
|
|
|
|
const tracedTapRows: TracedTapRow[] = useMemo(() => {
|
|
|
|
|
const traced = editing ? tracedDraft : (agentConfig?.tracedProcessors ?? {});
|
|
|
|
|
const taps = agentConfig?.taps ?? [];
|
|
|
|
|
const pids = new Set<string>([...Object.keys(traced), ...taps.map(t => t.processorId)]);
|
|
|
|
|
return Array.from(pids).sort().map(pid => ({ id: pid, processorId: pid, captureMode: traced[pid] ?? null, taps: taps.filter(t => t.processorId === pid) }));
|
|
|
|
|
}, [editing, tracedDraft, agentConfig?.tracedProcessors, agentConfig?.taps]);
|
|
|
|
|
|
|
|
|
|
const tracedCount = useMemo(() => Object.keys(editing ? tracedDraft : (agentConfig?.tracedProcessors ?? {})).length, [editing, tracedDraft, agentConfig?.tracedProcessors]);
|
|
|
|
|
const tapCount = agentConfig?.taps?.length ?? 0;
|
|
|
|
|
|
|
|
|
|
const tracedTapColumns: Column<TracedTapRow>[] = useMemo(() => [
|
|
|
|
|
{ key: 'route' as any, header: 'Route', render: (_v: unknown, row: TracedTapRow) => {
|
|
|
|
|
const routeId = processorToRoute[row.processorId];
|
|
|
|
|
return routeId ? <span className={styles.routeLabel}>{routeId}</span> : <span className={styles.hint}>—</span>;
|
|
|
|
|
}},
|
|
|
|
|
{ key: 'processorId', header: 'Processor', render: (_v: unknown, row: TracedTapRow) => <MonoText size="xs">{row.processorId}</MonoText> },
|
|
|
|
|
{
|
|
|
|
|
key: 'captureMode', header: 'Capture',
|
|
|
|
|
render: (_v: unknown, row: TracedTapRow) => {
|
|
|
|
|
if (row.captureMode === null) return <span className={styles.hint}>—</span>;
|
|
|
|
|
if (editing) return (
|
|
|
|
|
<select className={styles.nativeSelect} value={row.captureMode} onChange={(e) => updateTracedProcessor(row.processorId, e.target.value)}>
|
|
|
|
|
<option value="NONE">None</option><option value="INPUT">Input</option><option value="OUTPUT">Output</option><option value="BOTH">Both</option>
|
|
|
|
|
</select>
|
|
|
|
|
);
|
|
|
|
|
return <Badge label={row.captureMode} color={row.captureMode === 'BOTH' ? 'running' : row.captureMode === 'NONE' ? 'auto' : 'warning'} variant="filled" />;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'taps', header: 'Taps',
|
|
|
|
|
render: (_v: unknown, row: TracedTapRow) => row.taps.length === 0
|
|
|
|
|
? <span className={styles.hint}>—</span>
|
|
|
|
|
: <div className={styles.tapBadges}>{row.taps.map(t => (
|
|
|
|
|
<button key={t.tapId} className={styles.tapBadgeLink} title={`Manage tap on route page`}>
|
|
|
|
|
<Badge label={t.attributeName} color={t.enabled ? 'success' : 'auto'} variant="filled" />
|
|
|
|
|
</button>
|
|
|
|
|
))}</div>,
|
|
|
|
|
},
|
|
|
|
|
...(editing ? [{
|
|
|
|
|
key: '_remove' as const, header: '', width: '36px',
|
|
|
|
|
render: (_v: unknown, row: TracedTapRow) => row.captureMode === null ? null : (
|
|
|
|
|
<button className={styles.removeBtn} title="Remove" onClick={() => updateTracedProcessor(row.processorId, 'REMOVE')}>×</button>
|
|
|
|
|
),
|
|
|
|
|
}] : []),
|
|
|
|
|
], [editing, processorToRoute]);
|
|
|
|
|
|
|
|
|
|
// Route Recording
|
|
|
|
|
const routeRecordingRows: RouteRecordingRow[] = useMemo(() => {
|
|
|
|
|
const rec = editing ? routeRecordingDraft : (agentConfig?.routeRecording ?? {});
|
|
|
|
|
return appRoutes.map(r => ({ id: r.routeId, routeId: r.routeId, recording: rec[r.routeId] !== false }));
|
|
|
|
|
}, [editing, routeRecordingDraft, agentConfig?.routeRecording, appRoutes]);
|
|
|
|
|
|
|
|
|
|
const recordingCount = routeRecordingRows.filter(r => r.recording).length;
|
|
|
|
|
|
|
|
|
|
const routeRecordingColumns: Column<RouteRecordingRow>[] = useMemo(() => [
|
|
|
|
|
{ key: 'routeId', header: 'Route', render: (_v: unknown, row: RouteRecordingRow) => <MonoText size="xs">{row.routeId}</MonoText> },
|
|
|
|
|
{ key: 'recording', header: 'Recording', width: '100px', render: (_v: unknown, row: RouteRecordingRow) => <Toggle checked={row.recording} onChange={() => { if (editing) updateRouteRecording(row.routeId, !row.recording); }} disabled={!editing} /> },
|
|
|
|
|
], [editing, routeRecordingDraft]);
|
|
|
|
|
|
2026-04-08 16:23:30 +02:00
|
|
|
return (
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
<>
|
|
|
|
|
{!editing && (
|
|
|
|
|
<div className={styles.editBanner}>
|
|
|
|
|
<span className={styles.editBannerText}>Configuration is read-only. Enter edit mode to make changes.</span>
|
|
|
|
|
<Button size="sm" variant="secondary" onClick={() => setEditing(true)}>Edit</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{editing && (
|
|
|
|
|
<div className={`${styles.editBanner} ${styles.editBannerActive}`}>
|
|
|
|
|
<span className={styles.editBannerTextWarn}>Editing configuration. Changes are not saved until you click Save.</span>
|
|
|
|
|
<div className={styles.editBannerActions}>
|
|
|
|
|
<Button size="sm" variant="ghost" onClick={handleCancel}>Cancel</Button>
|
|
|
|
|
<Button size="sm" variant="primary" onClick={handleSave}
|
|
|
|
|
loading={updateAgentConfig.isPending || updateContainerConfig.isPending}>Save Configuration</Button>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-04-08 18:09:12 +02:00
|
|
|
<div className={styles.subTabs}>
|
2026-04-08 18:22:39 +02:00
|
|
|
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
2026-04-09 07:38:23 +02:00
|
|
|
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
|
|
|
|
<button className={`${styles.subTab} ${configTab === 'variables' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('variables')}>Variables</button>
|
2026-04-08 18:22:39 +02:00
|
|
|
<button className={`${styles.subTab} ${configTab === 'traces' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('traces')}>Traces & Taps</button>
|
|
|
|
|
<button className={`${styles.subTab} ${configTab === 'recording' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('recording')}>Route Recording</button>
|
2026-04-08 16:23:30 +02:00
|
|
|
</div>
|
|
|
|
|
|
2026-04-08 18:47:58 +02:00
|
|
|
{configTab === 'variables' && (
|
|
|
|
|
<>
|
|
|
|
|
{envVars.map((v, i) => (
|
|
|
|
|
<div key={i} className={styles.envVarRow}>
|
|
|
|
|
<Input disabled={!editing} value={v.key} onChange={(e) => {
|
|
|
|
|
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
|
|
|
|
}} className={styles.envVarKey} placeholder="KEY" />
|
|
|
|
|
<Input disabled={!editing} value={v.value} onChange={(e) => {
|
|
|
|
|
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
|
|
|
|
}} className={styles.envVarValue} placeholder="value" />
|
|
|
|
|
<button className={styles.envVarDelete} disabled={!editing}
|
|
|
|
|
onClick={() => editing && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
{editing && (
|
|
|
|
|
<Button size="sm" variant="secondary" onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
|
|
|
|
)}
|
|
|
|
|
{envVars.length === 0 && !editing && <p className={styles.emptyNote}>No environment variables configured.</p>}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
{configTab === 'monitoring' && (
|
|
|
|
|
<div className={styles.configGrid}>
|
|
|
|
|
<span className={styles.configLabel}>Engine Level</span>
|
|
|
|
|
<Select disabled={!editing} value={engineLevel} onChange={(e) => setEngineLevel(e.target.value)}
|
|
|
|
|
options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Payload Capture</span>
|
|
|
|
|
<Select disabled={!editing} value={payloadCapture} onChange={(e) => setPayloadCapture(e.target.value)}
|
|
|
|
|
options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Max Payload Size</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled={!editing} value={payloadSize} onChange={(e) => setPayloadSize(e.target.value)} style={{ width: 70 }} />
|
|
|
|
|
<Select disabled={!editing} value={payloadUnit} onChange={(e) => setPayloadUnit(e.target.value)} style={{ width: 90 }}
|
|
|
|
|
options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
|
|
|
|
|
</div>
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
<span className={styles.configLabel}>App Log Level</span>
|
|
|
|
|
<Select disabled={!editing} value={appLogLevel} onChange={(e) => setAppLogLevel(e.target.value)}
|
|
|
|
|
options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Agent Log Level</span>
|
|
|
|
|
<Select disabled={!editing} value={agentLogLevel} onChange={(e) => setAgentLogLevel(e.target.value)}
|
|
|
|
|
options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Metrics</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={metricsEnabled} onChange={() => editing && setMetricsEnabled(!metricsEnabled)} disabled={!editing} />
|
|
|
|
|
<span className={metricsEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{metricsEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
<span className={styles.cellMeta} style={{ marginLeft: 8 }}>Interval</span>
|
|
|
|
|
<Input disabled={!editing} value={metricsInterval} onChange={(e) => setMetricsInterval(e.target.value)} style={{ width: 50 }} />
|
|
|
|
|
<span className={styles.cellMeta}>s</span>
|
|
|
|
|
</div>
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
<span className={styles.configLabel}>Sampling Rate</span>
|
|
|
|
|
<Input disabled={!editing} value={samplingRate} onChange={(e) => setSamplingRate(e.target.value)} style={{ width: 80 }} />
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
<span className={styles.configLabel}>Compress Success</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={compressSuccess} onChange={() => editing && setCompressSuccess(!compressSuccess)} disabled={!editing} />
|
|
|
|
|
<span className={compressSuccess ? styles.toggleEnabled : styles.toggleDisabled}>{compressSuccess ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
<span className={styles.configLabel}>Replay</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={replayEnabled} onChange={() => editing && setReplayEnabled(!replayEnabled)} disabled={!editing} />
|
|
|
|
|
<span className={replayEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{replayEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
<span className={styles.configLabel}>Route Control</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={routeControlEnabled} onChange={() => editing && setRouteControlEnabled(!routeControlEnabled)} disabled={!editing} />
|
|
|
|
|
<span className={routeControlEnabled ? styles.toggleEnabled : styles.toggleDisabled}>{routeControlEnabled ? 'Enabled' : 'Disabled'}</span>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
</div>
|
2026-04-08 18:22:39 +02:00
|
|
|
</div>
|
|
|
|
|
)}
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
{configTab === 'traces' && (
|
|
|
|
|
<>
|
2026-04-08 18:09:12 +02:00
|
|
|
<span className={styles.sectionSummary}>{tracedCount} traced · {tapCount} taps</span>
|
|
|
|
|
{tracedTapRows.length > 0
|
|
|
|
|
? <DataTable<TracedTapRow> columns={tracedTapColumns} data={tracedTapRows} pageSize={20} flush />
|
|
|
|
|
: <p className={styles.emptyNote}>No processor traces or taps configured.</p>}
|
2026-04-08 18:22:39 +02:00
|
|
|
</>
|
|
|
|
|
)}
|
2026-04-08 18:09:12 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
{configTab === 'recording' && (
|
|
|
|
|
<>
|
2026-04-08 18:09:12 +02:00
|
|
|
<span className={styles.sectionSummary}>{recordingCount} of {routeRecordingRows.length} routes recording</span>
|
|
|
|
|
{routeRecordingRows.length > 0
|
|
|
|
|
? <DataTable<RouteRecordingRow> columns={routeRecordingColumns} data={routeRecordingRows} pageSize={20} flush />
|
|
|
|
|
: <p className={styles.emptyNote}>No routes found for this application.</p>}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
|
2026-04-08 18:22:39 +02:00
|
|
|
{configTab === 'resources' && (
|
2026-04-08 18:09:12 +02:00
|
|
|
<>
|
|
|
|
|
{/* Container Resources */}
|
|
|
|
|
<SectionHeader>Container Resources</SectionHeader>
|
|
|
|
|
<div className={styles.configGrid}>
|
|
|
|
|
<span className={styles.configLabel}>Memory Limit</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled={!editing} value={memoryLimit} onChange={(e) => setMemoryLimit(e.target.value)} style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>MB</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Memory Reserve</span>
|
|
|
|
|
<div>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Input disabled value={memoryReserve} onChange={(e) => setMemoryReserve(e.target.value)} placeholder="---" style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>MB</span>
|
|
|
|
|
</div>
|
|
|
|
|
{!isProd && <span className={styles.configHint}>Available in production environments only</span>}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-04-09 07:38:23 +02:00
|
|
|
<span className={styles.configLabel}>CPU Request</span>
|
|
|
|
|
<Input disabled={!editing} value={cpuRequest} onChange={(e) => setCpuRequest(e.target.value)} style={{ width: 80 }} />
|
2026-04-08 18:09:12 +02:00
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>CPU Limit</span>
|
|
|
|
|
<div className={styles.configInline}>
|
2026-04-09 07:38:23 +02:00
|
|
|
<Input disabled={!editing} value={cpuLimit} onChange={(e) => setCpuLimit(e.target.value)} placeholder="e.g. 1000" style={{ width: 80 }} />
|
|
|
|
|
<span className={styles.cellMeta}>millicores</span>
|
2026-04-08 18:09:12 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Exposed Ports</span>
|
|
|
|
|
<div className={styles.portPills}>
|
|
|
|
|
{ports.map((p) => (
|
|
|
|
|
<span key={p} className={styles.portPill}>
|
|
|
|
|
{p}
|
|
|
|
|
<button className={styles.portPillDelete} disabled={!editing}
|
|
|
|
|
onClick={() => editing && setPorts(ports.filter((x) => x !== p))}>×</button>
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
|
|
|
|
<input className={styles.portAddInput} disabled={!editing} placeholder="+ port" value={newPort}
|
|
|
|
|
onChange={(e) => setNewPort(e.target.value)}
|
|
|
|
|
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
|
|
|
|
</div>
|
2026-04-08 20:33:41 +02:00
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>App Port</span>
|
|
|
|
|
<Input disabled={!editing} value={appPort} onChange={(e) => setAppPort(e.target.value)} style={{ width: 80 }} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Replicas</span>
|
|
|
|
|
<Input disabled={!editing} value={replicas} onChange={(e) => setReplicas(e.target.value)} style={{ width: 60 }} type="number" />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Deploy Strategy</span>
|
|
|
|
|
<Select disabled={!editing} value={deployStrategy} onChange={(e) => setDeployStrategy(e.target.value)}
|
|
|
|
|
options={[{ value: 'blue-green', label: 'Blue/Green' }, { value: 'rolling', label: 'Rolling' }]} />
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>Strip Path Prefix</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={stripPrefix} onChange={() => editing && setStripPrefix(!stripPrefix)} disabled={!editing} />
|
|
|
|
|
<span className={stripPrefix ? styles.toggleEnabled : styles.toggleDisabled}>{stripPrefix ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<span className={styles.configLabel}>SSL Offloading</span>
|
|
|
|
|
<div className={styles.configInline}>
|
|
|
|
|
<Toggle checked={sslOffloading} onChange={() => editing && setSslOffloading(!sslOffloading)} disabled={!editing} />
|
|
|
|
|
<span className={sslOffloading ? styles.toggleEnabled : styles.toggleDisabled}>{sslOffloading ? 'Enabled' : 'Disabled'}</span>
|
|
|
|
|
</div>
|
2026-04-08 18:09:12 +02:00
|
|
|
</div>
|
|
|
|
|
</>
|
feat: redesign Deployments tab with Overview + Configuration sub-tabs
Overview sub-tab:
- Deployments table with env badge, version, status, URL, deployed time
- Actions (Start/Stop) scoped to selected environment; other envs show
"switch env to manage" hint with muted rows
- Versions list with per-env deploy target picker
Configuration sub-tab:
- Read-only by default with Edit mode gate (Cancel/Save banner)
- Agent observability: engine level, payload capture with size unit
selector, log levels, metrics toggle, sampling, replay and route
control (default enabled)
- Container resources: memory/CPU limits, exposed ports as deletable
pills with inline add input
- Environment variables: key-value editor with add/remove
- Reuses existing ApplicationConfig API for agent config push via SSE
Tab renamed from "Apps" to "Deployments" in the tab bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:36:09 +02:00
|
|
|
)}
|
|
|
|
|
</>
|
2026-04-08 16:23:30 +02:00
|
|
|
);
|
|
|
|
|
}
|