Skip to content

Commit 2314591

Browse files
Merge pull request #2 from url4irl/claude/issue-1-20250611_194209
feat: implement Git-Proof Next.js application
2 parents 3cfd630 + bf65868 commit 2314591

File tree

7 files changed

+1026
-1
lines changed

7 files changed

+1026
-1
lines changed

app/dashboard/failover/page.tsx

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
export default function FailoverPage() {
2+
const recoveryEvents = [
3+
{
4+
id: 1,
5+
type: 'failover',
6+
provider: 'Forgejo',
7+
fallbackProvider: 'GitHub',
8+
reason: 'Connection timeout',
9+
affectedRepos: 12,
10+
timestamp: '2 hours ago',
11+
status: 'resolved',
12+
duration: '15 minutes'
13+
},
14+
{
15+
id: 2,
16+
type: 'recovery',
17+
provider: 'GitLab',
18+
fallbackProvider: null,
19+
reason: 'Service restored',
20+
affectedRepos: 45,
21+
timestamp: '6 hours ago',
22+
status: 'completed',
23+
duration: '2 minutes'
24+
},
25+
{
26+
id: 3,
27+
type: 'failover',
28+
provider: 'Custom Git Server',
29+
fallbackProvider: 'GitLab',
30+
reason: 'HTTP 503 Service Unavailable',
31+
affectedRepos: 8,
32+
timestamp: '1 day ago',
33+
status: 'resolved',
34+
duration: '45 minutes'
35+
}
36+
];
37+
38+
const backupStatus = {
39+
lastBackup: '30 minutes ago',
40+
backupSize: '2.4 GB',
41+
totalRepos: 156,
42+
incrementalEnabled: true,
43+
nextScheduled: 'in 30 minutes'
44+
};
45+
46+
return (
47+
<div>
48+
<div className="mb-8">
49+
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
50+
Failover & Recovery
51+
</h1>
52+
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
53+
Monitor failover events and manage recovery procedures
54+
</p>
55+
</div>
56+
57+
{/* Alert Banner */}
58+
<div className="mb-6 rounded-md bg-yellow-50 dark:bg-yellow-900/20 p-4">
59+
<div className="flex">
60+
<div className="flex-shrink-0">
61+
<svg className="h-5 w-5 text-yellow-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
62+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
63+
</svg>
64+
</div>
65+
<div className="ml-3">
66+
<h3 className="text-sm font-medium text-yellow-800 dark:text-yellow-200">
67+
Failover Configuration Active
68+
</h3>
69+
<div className="mt-2 text-sm text-yellow-700 dark:text-yellow-300">
70+
<p>
71+
Automatic failover is enabled. Failed syncs will be redirected to available providers.
72+
</p>
73+
</div>
74+
</div>
75+
</div>
76+
</div>
77+
78+
{/* Failover Configuration */}
79+
<div className="mb-8 grid grid-cols-1 gap-6 lg:grid-cols-2">
80+
{/* Failover Rules */}
81+
<div className="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow">
82+
<div className="p-6">
83+
<h3 className="text-lg font-medium text-gray-900 dark:text-white">
84+
Failover Rules
85+
</h3>
86+
<div className="mt-4 space-y-4">
87+
<div className="flex items-center justify-between">
88+
<div>
89+
<p className="text-sm font-medium text-gray-900 dark:text-white">
90+
Primary → Fallback Priority
91+
</p>
92+
<p className="text-sm text-gray-500 dark:text-gray-400">
93+
GitHub → GitLab → Forgejo → Local Backup
94+
</p>
95+
</div>
96+
<button className="text-sm text-blue-600 hover:text-blue-500">
97+
Edit
98+
</button>
99+
</div>
100+
<div className="flex items-center justify-between">
101+
<div>
102+
<p className="text-sm font-medium text-gray-900 dark:text-white">
103+
Retry Attempts
104+
</p>
105+
<p className="text-sm text-gray-500 dark:text-gray-400">
106+
3 attempts with exponential backoff
107+
</p>
108+
</div>
109+
<button className="text-sm text-blue-600 hover:text-blue-500">
110+
Edit
111+
</button>
112+
</div>
113+
<div className="flex items-center justify-between">
114+
<div>
115+
<p className="text-sm font-medium text-gray-900 dark:text-white">
116+
Health Check Interval
117+
</p>
118+
<p className="text-sm text-gray-500 dark:text-gray-400">
119+
Every 60 seconds
120+
</p>
121+
</div>
122+
<button className="text-sm text-blue-600 hover:text-blue-500">
123+
Edit
124+
</button>
125+
</div>
126+
</div>
127+
</div>
128+
</div>
129+
130+
{/* Backup Status */}
131+
<div className="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow">
132+
<div className="p-6">
133+
<h3 className="text-lg font-medium text-gray-900 dark:text-white">
134+
Local Backup Status
135+
</h3>
136+
<div className="mt-4 space-y-3">
137+
<div className="flex justify-between">
138+
<span className="text-sm text-gray-500 dark:text-gray-400">Last Backup</span>
139+
<span className="text-sm font-medium text-gray-900 dark:text-white">
140+
{backupStatus.lastBackup}
141+
</span>
142+
</div>
143+
<div className="flex justify-between">
144+
<span className="text-sm text-gray-500 dark:text-gray-400">Backup Size</span>
145+
<span className="text-sm font-medium text-gray-900 dark:text-white">
146+
{backupStatus.backupSize}
147+
</span>
148+
</div>
149+
<div className="flex justify-between">
150+
<span className="text-sm text-gray-500 dark:text-gray-400">Total Repositories</span>
151+
<span className="text-sm font-medium text-gray-900 dark:text-white">
152+
{backupStatus.totalRepos}
153+
</span>
154+
</div>
155+
<div className="flex justify-between">
156+
<span className="text-sm text-gray-500 dark:text-gray-400">Next Scheduled</span>
157+
<span className="text-sm font-medium text-gray-900 dark:text-white">
158+
{backupStatus.nextScheduled}
159+
</span>
160+
</div>
161+
<div className="mt-4 flex space-x-3">
162+
<button className="flex-1 rounded-md bg-blue-600 px-3 py-2 text-sm font-medium text-white hover:bg-blue-500">
163+
Run Backup Now
164+
</button>
165+
<button className="flex-1 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600">
166+
View Backups
167+
</button>
168+
</div>
169+
</div>
170+
</div>
171+
</div>
172+
</div>
173+
174+
{/* Recovery Events */}
175+
<div>
176+
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-4">
177+
Recent Failover Events
178+
</h3>
179+
<div className="overflow-hidden bg-white dark:bg-gray-800 shadow sm:rounded-md">
180+
<ul className="divide-y divide-gray-200 dark:divide-gray-700">
181+
{recoveryEvents.map((event) => (
182+
<li key={event.id} className="px-4 py-4 sm:px-6">
183+
<div className="flex items-center justify-between">
184+
<div className="flex items-center">
185+
<div className="flex-shrink-0">
186+
{event.type === 'failover' ? (
187+
<div className="h-10 w-10 rounded-full bg-red-100 dark:bg-red-900 flex items-center justify-center">
188+
<svg className="h-6 w-6 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" strokeWidth="2">
189+
<path strokeLinecap="round" strokeLinejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
190+
</svg>
191+
</div>
192+
) : (
193+
<div className="h-10 w-10 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center">
194+
<svg className="h-6 w-6 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" strokeWidth="2">
195+
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
196+
</svg>
197+
</div>
198+
)}
199+
</div>
200+
<div className="ml-4">
201+
<p className="text-sm font-medium text-gray-900 dark:text-white">
202+
{event.type === 'failover' ? 'Failover triggered' : 'Recovery completed'} for {event.provider}
203+
</p>
204+
<p className="text-sm text-gray-500 dark:text-gray-400">
205+
{event.reason}{event.affectedRepos} repositories affected
206+
{event.fallbackProvider && ` • Fallback: ${event.fallbackProvider}`}
207+
</p>
208+
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
209+
{event.timestamp} • Duration: {event.duration}
210+
</p>
211+
</div>
212+
</div>
213+
<div className="ml-2 flex-shrink-0">
214+
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
215+
event.status === 'resolved'
216+
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
217+
: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200'
218+
}`}>
219+
{event.status.charAt(0).toUpperCase() + event.status.slice(1)}
220+
</span>
221+
</div>
222+
</div>
223+
</li>
224+
))}
225+
</ul>
226+
</div>
227+
</div>
228+
</div>
229+
);
230+
}

app/dashboard/layout.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import DashboardNav from '@/components/dashboard-nav';
2+
3+
export default function DashboardLayout({
4+
children,
5+
}: {
6+
children: React.ReactNode;
7+
}) {
8+
return (
9+
<div className="min-h-screen bg-background">
10+
<DashboardNav />
11+
{/* Main content */}
12+
<main className="py-10">
13+
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
14+
{children}
15+
</div>
16+
</main>
17+
</div>
18+
);
19+
}

0 commit comments

Comments
 (0)