mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-29 08:04:53 +00:00
feat(app): unified demo mode + public-demo build for Vercel
- Central demo-mode helper (lib/demo-mode.ts): ?demo=1 query flag plus
VITE_PUBLIC_DEMO build flag that makes every route demo for the
public Vercel showcase.
- Single demo fixture source (lib/demo-data.ts): projects, services,
builds, databases, cron, HA, security, host monitoring, templates.
Fixes cross-page ID drift that broke project navigation.
- Demo support on Projects, HA, Security, Usage, Templates, Landing,
Service detail; DemoRestricted gate on People/Settings/Audit/Admin.
- Demo-aware PlatformShell: nav filtering, env:demo, demo account menu,
?demo=1 preserved through internal links.
- TemplatesPage: selection moved into ?template= URL param for deep
links; template fixtures shared via demo-data.
- requestJson returns {} for unparseable 200 bodies (SPA fallback) so
envelope unwraps degrade instead of dereferencing null.
- Recharts ResponsiveContainer initialDimension kills -1 warnings.
- vercel.json: vite framework + SPA rewrites for direct deep links.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
84b102a2c6
commit
5b0a8e0759
20 files changed
+873
-525
No files matched your search
@@ -1,6 +1,5 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import {
|
||||
cancelBuild,
|
||||
getBuildLogs,
|
||||
@@ -9,6 +8,8 @@ import {
|
||||
type BuildStatus,
|
||||
} from '@/lib/api-client';
|
||||
import { useBuildUpdates } from '@/lib/use-build-updates';
|
||||
import { useDemoMode } from '@/lib/demo-mode';
|
||||
import { demoBuilds } from '@/lib/demo-data';
|
||||
import { formatRelative } from '@/lib/time';
|
||||
import {
|
||||
Check,
|
||||
@@ -33,36 +34,6 @@ const statusOptions: Array<{ value: '' | BuildStatus; label: string }> = [
|
||||
{ value: 'cancelled', label: 'Cancelled' },
|
||||
];
|
||||
|
||||
const demoBuilds: BuildEntity[] = [
|
||||
{
|
||||
id: 'build-demo-01',
|
||||
projectId: 'project-demo',
|
||||
serviceId: 'service-api',
|
||||
status: 'success',
|
||||
progress: 100,
|
||||
startedAt: new Date(Date.now() - 20 * 60_000).toISOString(),
|
||||
completedAt: new Date(Date.now() - 18 * 60_000).toISOString(),
|
||||
imageName: 'ghcr.io/containr/api',
|
||||
imageTag: 'sha-1f2e3d4',
|
||||
size: 156_000_000,
|
||||
log: '[demo] Build finished successfully.',
|
||||
metadata: { branch: 'main' },
|
||||
},
|
||||
{
|
||||
id: 'build-demo-02',
|
||||
projectId: 'project-demo',
|
||||
serviceId: 'service-worker',
|
||||
status: 'running',
|
||||
progress: 54,
|
||||
startedAt: new Date(Date.now() - 2 * 60_000).toISOString(),
|
||||
imageName: 'ghcr.io/containr/worker',
|
||||
imageTag: 'sha-9a8b7c6',
|
||||
size: 0,
|
||||
log: '[demo] Building image layers...',
|
||||
metadata: { branch: 'feature/queue' },
|
||||
},
|
||||
];
|
||||
|
||||
function StatusBadge({ status }: { status: BuildStatus }) {
|
||||
const config = {
|
||||
success: { color: 'var(--success)', bg: 'var(--success-soft)', Icon: Check, animate: false },
|
||||
@@ -99,8 +70,7 @@ function bytesToHumanReadable(bytes: number): string {
|
||||
|
||||
export function BuildsPage() {
|
||||
const queryClient = useQueryClient();
|
||||
const [searchParams] = useSearchParams();
|
||||
const isDemoMode = searchParams.get('demo') === '1';
|
||||
const isDemoMode = useDemoMode();
|
||||
|
||||
const [projectFilter, setProjectFilter] = useState('');
|
||||
const [serviceFilter, setServiceFilter] = useState('');
|
||||
|
||||
Reference in new issue
Block a user