mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e128b7460d | ||
|
|
5b1cf0402c |
No files matched your search
@@ -1,3 +1,11 @@
|
|||||||
|
> [!IMPORTANT]
|
||||||
|
> **This project is archived.** Containr's goal — Railway's workflow on servers
|
||||||
|
> you own — is being done better by [Ployz](https://github.com/getployz/ployz)
|
||||||
|
> (Apache-2.0 engine + AGPL dashboard, self-hostable). Use that. This repo stays
|
||||||
|
> up as a reference; the canvas implementation in
|
||||||
|
> `app/frontend/src/features/workspace/canvas/` (group frames, context menus,
|
||||||
|
> inferred edges with reasons) may still be worth a look.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./containr.svg" alt="Containr" width="120">
|
<img src="./containr.svg" alt="Containr" width="120">
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,40 +1,50 @@
|
|||||||
|
import { lazy, Suspense, type ReactNode } from 'react';
|
||||||
import { Link, Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom';
|
import { Link, Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Compass, ShieldCheck } from 'lucide-react';
|
import { Compass, ShieldCheck } from 'lucide-react';
|
||||||
import { PlatformShell } from './layout/PlatformShell';
|
import { PlatformShell } from './layout/PlatformShell';
|
||||||
import { ProjectsPage } from '@/features/projects/pages/ProjectsPage';
|
|
||||||
import { ProjectWorkspacePage } from '@/features/workspace/pages/ProjectWorkspacePage';
|
|
||||||
import { ServiceDetailPage } from '@/features/service/pages/ServiceDetailPage';
|
|
||||||
import { ServiceMetricsDashboard } from '@/features/service/pages/ServiceMetricsDashboard';
|
|
||||||
import { BuildsPage } from '@/features/builds/pages/BuildsPage';
|
|
||||||
import { TemplatesPage } from '@/features/templates/pages/TemplatesPage';
|
|
||||||
import { AuditLogsPage } from '@/features/audit/pages/AuditLogsPage';
|
|
||||||
import { WebhooksPage } from '@/features/webhooks/pages/WebhooksPage';
|
|
||||||
import { OperationsPage } from '@/features/operations/pages/OperationsPage';
|
|
||||||
import { ActivityPage } from '@/features/activity/pages/ActivityPage';
|
|
||||||
import { AdminPage } from '@/features/admin/pages/AdminPage';
|
|
||||||
import { LandingPage } from '@/features/landing/LandingPage';
|
|
||||||
import { DashboardPage } from '@/features/dashboard/pages/DashboardPage';
|
|
||||||
import { useBranding } from '@/lib/use-branding';
|
import { useBranding } from '@/lib/use-branding';
|
||||||
import {
|
|
||||||
DocsPage,
|
|
||||||
PeoplePage,
|
|
||||||
SettingsPage,
|
|
||||||
UsagePage,
|
|
||||||
DatabasesPage,
|
|
||||||
HighAvailabilityPage,
|
|
||||||
SecurityPage,
|
|
||||||
ComponentShowcase,
|
|
||||||
GitHubAppCallbackPage,
|
|
||||||
} from '@/features/secondary/pages';
|
|
||||||
import { NodeDetailPage } from '@/features/nodes/NodeDetailPage';
|
|
||||||
import { AcceptInvitePage, SignInPage, SignUpPage } from '@/features/auth/pages';
|
|
||||||
import { SetupWizardPage } from '@/features/setup/SetupWizardPage';
|
|
||||||
import { useAuthSession } from '@/lib/use-auth-session';
|
import { useAuthSession } from '@/lib/use-auth-session';
|
||||||
import { useDemoMode } from '@/lib/demo-mode';
|
import { useDemoMode } from '@/lib/demo-mode';
|
||||||
import { getCurrentUserProfile } from '@/lib/api-client';
|
import { getCurrentUserProfile } from '@/lib/api-client';
|
||||||
import { ErrorBoundary, LoadingState } from '@/shared/components';
|
import { ErrorBoundary, LoadingState } from '@/shared/components';
|
||||||
|
|
||||||
|
const LandingPage = lazy(() => import('@/features/landing/LandingPage').then((m) => ({ default: m.LandingPage })));
|
||||||
|
const SignInPage = lazy(() => import('@/features/auth/pages').then((m) => ({ default: m.SignInPage })));
|
||||||
|
const SignUpPage = lazy(() => import('@/features/auth/pages').then((m) => ({ default: m.SignUpPage })));
|
||||||
|
const AcceptInvitePage = lazy(() => import('@/features/auth/pages').then((m) => ({ default: m.AcceptInvitePage })));
|
||||||
|
const SetupWizardPage = lazy(() => import('@/features/setup/SetupWizardPage').then((m) => ({ default: m.SetupWizardPage })));
|
||||||
|
const ProjectWorkspacePage = lazy(() => import('@/features/workspace/pages/ProjectWorkspacePage').then((m) => ({ default: m.ProjectWorkspacePage })));
|
||||||
|
const ServiceDetailPage = lazy(() => import('@/features/service/pages/ServiceDetailPage').then((m) => ({ default: m.ServiceDetailPage })));
|
||||||
|
const ServiceMetricsDashboard = lazy(() => import('@/features/service/pages/ServiceMetricsDashboard').then((m) => ({ default: m.ServiceMetricsDashboard })));
|
||||||
|
const DashboardPage = lazy(() => import('@/features/dashboard/pages/DashboardPage').then((m) => ({ default: m.DashboardPage })));
|
||||||
|
const ProjectsPage = lazy(() => import('@/features/projects/pages/ProjectsPage').then((m) => ({ default: m.ProjectsPage })));
|
||||||
|
const TemplatesPage = lazy(() => import('@/features/templates/pages/TemplatesPage').then((m) => ({ default: m.TemplatesPage })));
|
||||||
|
const DatabasesPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.DatabasesPage })));
|
||||||
|
const HighAvailabilityPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.HighAvailabilityPage })));
|
||||||
|
const OperationsPage = lazy(() => import('@/features/operations/pages/OperationsPage').then((m) => ({ default: m.OperationsPage })));
|
||||||
|
const ActivityPage = lazy(() => import('@/features/activity/pages/ActivityPage').then((m) => ({ default: m.ActivityPage })));
|
||||||
|
const SecurityPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.SecurityPage })));
|
||||||
|
const UsagePage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.UsagePage })));
|
||||||
|
const DocsPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.DocsPage })));
|
||||||
|
const BuildsPage = lazy(() => import('@/features/builds/pages/BuildsPage').then((m) => ({ default: m.BuildsPage })));
|
||||||
|
const PeoplePage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.PeoplePage })));
|
||||||
|
const SettingsPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.SettingsPage })));
|
||||||
|
const GitHubAppCallbackPage = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.GitHubAppCallbackPage })));
|
||||||
|
const AuditLogsPage = lazy(() => import('@/features/audit/pages/AuditLogsPage').then((m) => ({ default: m.AuditLogsPage })));
|
||||||
|
const WebhooksPage = lazy(() => import('@/features/webhooks/pages/WebhooksPage').then((m) => ({ default: m.WebhooksPage })));
|
||||||
|
const ComponentShowcase = lazy(() => import('@/features/secondary/pages').then((m) => ({ default: m.ComponentShowcase })));
|
||||||
|
const AdminPage = lazy(() => import('@/features/admin/pages/AdminPage').then((m) => ({ default: m.AdminPage })));
|
||||||
|
const NodeDetailPage = lazy(() => import('@/features/nodes/NodeDetailPage').then((m) => ({ default: m.NodeDetailPage })));
|
||||||
|
|
||||||
|
function Page({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<LoadingState message="Loading..." className="min-h-[60vh]" />}>
|
||||||
|
{children}
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function AuthRequired() {
|
function AuthRequired() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isDemoMode = useDemoMode();
|
const isDemoMode = useDemoMode();
|
||||||
@@ -136,44 +146,44 @@ export default function App() {
|
|||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/landing" element={<LandingPage />} />
|
<Route path="/landing" element={<Page><LandingPage /></Page>} />
|
||||||
<Route path="/auth/sign-in" element={<SignInPage />} />
|
<Route path="/auth/sign-in" element={<Page><SignInPage /></Page>} />
|
||||||
<Route path="/auth/sign-up" element={<SignUpPage />} />
|
<Route path="/auth/sign-up" element={<Page><SignUpPage /></Page>} />
|
||||||
<Route path="/auth/accept-invite" element={<AcceptInvitePage />} />
|
<Route path="/auth/accept-invite" element={<Page><AcceptInvitePage /></Page>} />
|
||||||
<Route path="/setup" element={<SetupWizardPage />} />
|
<Route path="/setup" element={<Page><SetupWizardPage /></Page>} />
|
||||||
|
|
||||||
{/* Public browsing — approved projects, templates, docs. */}
|
{/* Public browsing — approved projects, templates, docs. */}
|
||||||
{/* Project workspace renders outside the shell — fullscreen canvas, no nav chrome */}
|
{/* Project workspace renders outside the shell — fullscreen canvas, no nav chrome */}
|
||||||
<Route path="/projects/:projectId" element={<ProjectWorkspacePage />} />
|
<Route path="/projects/:projectId" element={<Page><ProjectWorkspacePage /></Page>} />
|
||||||
<Route path="/projects/:projectId/services/:serviceId" element={<ServiceDetailPage />} />
|
<Route path="/projects/:projectId/services/:serviceId" element={<Page><ServiceDetailPage /></Page>} />
|
||||||
|
|
||||||
<Route element={<PlatformShell />}>
|
<Route element={<PlatformShell />}>
|
||||||
<Route path="/" element={<DashboardPage />} />
|
<Route path="/" element={<Page><DashboardPage /></Page>} />
|
||||||
<Route path="/projects" element={<ProjectsPage />} />
|
<Route path="/projects" element={<Page><ProjectsPage /></Page>} />
|
||||||
<Route path="/templates" element={<TemplatesPage />} />
|
<Route path="/templates" element={<Page><TemplatesPage /></Page>} />
|
||||||
<Route path="/databases" element={<DatabasesPage />} />
|
<Route path="/databases" element={<Page><DatabasesPage /></Page>} />
|
||||||
<Route path="/ha" element={<HighAvailabilityPage />} />
|
<Route path="/ha" element={<Page><HighAvailabilityPage /></Page>} />
|
||||||
<Route path="/operations" element={<OperationsPage />} />
|
<Route path="/operations" element={<Page><OperationsPage /></Page>} />
|
||||||
<Route path="/activity" element={<ActivityPage />} />
|
<Route path="/activity" element={<Page><ActivityPage /></Page>} />
|
||||||
<Route path="/security" element={<SecurityPage />} />
|
<Route path="/security" element={<Page><SecurityPage /></Page>} />
|
||||||
<Route path="/usage" element={<UsagePage />} />
|
<Route path="/usage" element={<Page><UsagePage /></Page>} />
|
||||||
<Route path="/docs" element={<DocsPage />} />
|
<Route path="/docs" element={<Page><DocsPage /></Page>} />
|
||||||
|
|
||||||
{/* Authenticated areas */}
|
{/* Authenticated areas */}
|
||||||
<Route element={<AuthRequired />}>
|
<Route element={<AuthRequired />}>
|
||||||
<Route path="/builds" element={<BuildsPage />} />
|
<Route path="/builds" element={<Page><BuildsPage /></Page>} />
|
||||||
<Route path="/people" element={<PeoplePage />} />
|
<Route path="/people" element={<Page><PeoplePage /></Page>} />
|
||||||
<Route path="/settings" element={<SettingsPage />} />
|
<Route path="/settings" element={<Page><SettingsPage /></Page>} />
|
||||||
<Route path="/git/github-app/callback" element={<GitHubAppCallbackPage />} />
|
<Route path="/git/github-app/callback" element={<Page><GitHubAppCallbackPage /></Page>} />
|
||||||
<Route path="/settings/audit-logs" element={<AuditLogsPage />} />
|
<Route path="/settings/audit-logs" element={<Page><AuditLogsPage /></Page>} />
|
||||||
<Route path="/settings/webhooks" element={<WebhooksPage />} />
|
<Route path="/settings/webhooks" element={<Page><WebhooksPage /></Page>} />
|
||||||
<Route path="/showcase" element={<ComponentShowcase />} />
|
<Route path="/showcase" element={<Page><ComponentShowcase /></Page>} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* Platform owner only */}
|
{/* Platform owner only */}
|
||||||
<Route element={<AdminRequired />}>
|
<Route element={<AdminRequired />}>
|
||||||
<Route path="/admin" element={<AdminPage />} />
|
<Route path="/admin" element={<Page><AdminPage /></Page>} />
|
||||||
<Route path="/nodes/:id" element={<NodeDetailPage />} />
|
<Route path="/nodes/:id" element={<Page><NodeDetailPage /></Page>} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path="*" element={<NotFoundPage />} />
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
@@ -181,7 +191,7 @@ export default function App() {
|
|||||||
|
|
||||||
{/* Full-bleed design demo — renders its own chrome, no app shell */}
|
{/* Full-bleed design demo — renders its own chrome, no app shell */}
|
||||||
<Route element={<AuthRequired />}>
|
<Route element={<AuthRequired />}>
|
||||||
<Route path="/metrics-demo" element={<ServiceMetricsDashboard />} />
|
<Route path="/metrics-demo" element={<Page><ServiceMetricsDashboard /></Page>} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|||||||
Reference in new issue
Block a user