merge: resolve main into feat/app-demo-polish

This commit is contained in:
Tomas Dvorak committed 2026-09-23 19:06:42 +02:00
commit 38e0bc1802
42 files changed
+4125 -585

No files matched your search

@@ -1,6 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useNavigate, useParams } from 'react-router-dom';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import {
createDeployment,
deleteService,
@@ -37,6 +37,8 @@ import {
} from '@/lib/api-client';
import { getDemoProjectById, getDemoServiceById, getDemoCronJobsByService } from '@/lib/demo-data';
import { useDemoMode } from '@/lib/demo-mode';
import { ServiceIcon } from '@/features/workspace/canvas/ServiceIcon';
import { serviceAccent } from '@/features/workspace/canvas/service-visuals';
import { useAuthSession } from '@/lib/use-auth-session';
import { getCurrentUserProfile } from '@/lib/api-client';
import { parseDotenv, validateVariableRows, type VariableDraft } from '../variable-utils';
@@ -122,6 +124,7 @@ function StatusBadge({ status }: { status: string }) {
export function ServiceDetailPage() {
const { projectId = '', serviceId = '' } = useParams<{ projectId: string; serviceId: string }>();
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const queryClient = useQueryClient();
const isDemoMode = useDemoMode();
const sessionQuery = useAuthSession({ enabled: !isDemoMode });
@@ -134,7 +137,10 @@ export function ServiceDetailPage() {
});
const isAdmin = Boolean(profileQuery.data?.isAdmin);
const [activeSection, setActiveSection] = useState<ServiceSection>('metrics');
const [activeSection, setActiveSection] = useState<ServiceSection>(() => {
const requested = searchParams.get('section');
return sectionItems.some((item) => item.key === requested) ? (requested as ServiceSection) : 'metrics';
});
const [logTail, setLogTail] = useState('100');
const [varDrafts, setVarDrafts] = useState<VariableDraft[] | null>(null);
const [bulkOpen, setBulkOpen] = useState(false);
@@ -382,7 +388,7 @@ export function ServiceDetailPage() {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['project-services', projectId] });
queryClient.invalidateQueries({ queryKey: ['projects'] });
navigate(`/projects/${projectId}`);
navigate(isDemoMode ? `/projects/${projectId}?demo=1` : `/projects/${projectId}`);
},
});
@@ -590,18 +596,17 @@ export function ServiceDetailPage() {
{/* Project Header - self.html exact match */}
<div className="flex items-center" style={{ padding: '0 24px 18px' }}>
<div
<div
className="rounded-[13px] flex items-center justify-center flex-shrink-0"
style={{
width: '46px',
height: '46px',
background: 'var(--accent-primary)',
style={{
width: '46px',
height: '46px',
background: `${serviceAccent(service)}1f`,
color: serviceAccent(service),
marginRight: '14px'
}}
>
<svg width="22" height="22" viewBox="0 0 24 24" fill="white">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/>
</svg>
<ServiceIcon service={service} size={22} />
</div>
<div>
<div className="flex items-center" style={{ gap: '10px' }}>