Skip to content

Commit d87bb76

Browse files
committed
Adding in password login not complete
1 parent 15a560c commit d87bb76

File tree

9 files changed

+1461
-704
lines changed

9 files changed

+1461
-704
lines changed
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
<template>
2+
<div class="api-health-checker">
3+
<h4 class="api-health-title">API Health Status</h4>
4+
5+
<div v-if="loading" class="api-health-loading">
6+
<div class="spinner"></div>
7+
<p>Checking API endpoints...</p>
8+
</div>
9+
10+
<div v-else class="api-health-results">
11+
<div class="api-health-summary" :class="healthSummaryClass">
12+
<div class="health-icon">{{ healthIcon }}</div>
13+
<div class="health-status">
14+
<p><strong>{{ healthSummary }}</strong></p>
15+
<p class="health-description">{{ healthDescription }}</p>
16+
</div>
17+
</div>
18+
19+
<div v-if="showEndpoints" class="api-health-endpoints">
20+
<h5>Endpoint Status</h5>
21+
<ul>
22+
<li v-for="(endpoint, index) in endpoints" :key="index"
23+
:class="{ 'endpoint-ok': endpoint.status === 'ok', 'endpoint-error': endpoint.status === 'error' }">
24+
<span class="endpoint-path">{{ endpoint.path }}</span>
25+
<span class="endpoint-status">
26+
<span v-if="endpoint.status === 'ok'" class="status-badge ok">OK</span>
27+
<span v-else-if="endpoint.status === 'error'" class="status-badge error">{{ endpoint.code || 'ERROR' }}</span>
28+
<span v-else class="status-badge unknown">?</span>
29+
</span>
30+
</li>
31+
</ul>
32+
</div>
33+
</div>
34+
35+
<div class="api-health-actions">
36+
<button @click="checkAllEndpoints" :disabled="loading" class="check-api-button">
37+
{{ loading ? 'Checking...' : 'Check API Health' }}
38+
</button>
39+
</div>
40+
</div>
41+
</template>
42+
43+
<script>
44+
export default {
45+
name: 'ApiHealthChecker',
46+
props: {
47+
endpointsToCheck: {
48+
type: Array,
49+
default: () => [
50+
'/api/v1/health',
51+
'/api/v1/health/ping',
52+
'/api/v1/auth/current-user',
53+
'/api/v1'
54+
]
55+
},
56+
showEndpoints: {
57+
type: Boolean,
58+
default: true
59+
},
60+
autoCheck: {
61+
type: Boolean,
62+
default: false
63+
}
64+
},
65+
data() {
66+
return {
67+
endpoints: [],
68+
loading: false,
69+
lastCheck: null
70+
};
71+
},
72+
computed: {
73+
healthSummary() {
74+
const totalCount = this.endpoints.length;
75+
const okCount = this.endpoints.filter(e => e.status === 'ok').length;
76+
77+
if (totalCount === 0) return 'Not Checked';
78+
if (okCount === totalCount) return 'All Endpoints OK';
79+
if (okCount === 0) return 'All Endpoints Failed';
80+
return `${okCount}/${totalCount} Endpoints OK`;
81+
},
82+
healthDescription() {
83+
const totalCount = this.endpoints.length;
84+
const okCount = this.endpoints.filter(e => e.status === 'ok').length;
85+
86+
if (totalCount === 0) return 'Click the button below to check API health';
87+
if (okCount === totalCount) return 'All API endpoints are responding correctly';
88+
if (okCount === 0) return 'All API endpoints are failing. The server may be down.';
89+
90+
if (this.endpoints.find(e => e.path === '/api/v1/health')?.status === 'ok') {
91+
return 'The API server is running but some endpoints are failing';
92+
}
93+
94+
return 'Some API endpoints are responding, but there may be issues';
95+
},
96+
healthSummaryClass() {
97+
const totalCount = this.endpoints.length;
98+
const okCount = this.endpoints.filter(e => e.status === 'ok').length;
99+
100+
if (totalCount === 0) return 'status-unknown';
101+
if (okCount === totalCount) return 'status-ok';
102+
if (okCount === 0) return 'status-error';
103+
return 'status-partial';
104+
},
105+
healthIcon() {
106+
const totalCount = this.endpoints.length;
107+
const okCount = this.endpoints.filter(e => e.status === 'ok').length;
108+
109+
if (totalCount === 0) return '';
110+
if (okCount === totalCount) return '';
111+
if (okCount === 0) return '';
112+
return '⚠️';
113+
}
114+
},
115+
mounted() {
116+
if (this.autoCheck) {
117+
this.checkAllEndpoints();
118+
}
119+
},
120+
methods: {
121+
async checkAllEndpoints() {
122+
this.loading = true;
123+
this.endpoints = [];
124+
125+
try {
126+
for (const path of this.endpointsToCheck) {
127+
await this.checkEndpoint(path);
128+
}
129+
} finally {
130+
this.loading = false;
131+
this.lastCheck = new Date();
132+
this.$emit('check-complete', {
133+
summary: this.healthSummary,
134+
endpoints: this.endpoints,
135+
timestamp: this.lastCheck
136+
});
137+
}
138+
},
139+
140+
async checkEndpoint(path) {
141+
try {
142+
const controller = new AbortController();
143+
const timeoutId = setTimeout(() => controller.abort(), 5000);
144+
145+
const startTime = Date.now();
146+
const response = await fetch(path, {
147+
method: 'HEAD',
148+
cache: 'no-store',
149+
signal: controller.signal
150+
});
151+
const endTime = Date.now();
152+
153+
clearTimeout(timeoutId);
154+
155+
this.endpoints.push({
156+
path,
157+
status: response.ok ? 'ok' : 'error',
158+
code: response.status,
159+
latency: endTime - startTime
160+
});
161+
} catch (error) {
162+
this.endpoints.push({
163+
path,
164+
status: 'error',
165+
error: error instanceof Error ? error.message : 'Unknown error'
166+
});
167+
}
168+
}
169+
}
170+
};
171+
</script>
172+
173+
<style scoped>
174+
.api-health-checker {
175+
background-color: rgba(0, 0, 0, 0.1);
176+
border-radius: 8px;
177+
padding: 1.25rem;
178+
margin-bottom: 1.5rem;
179+
}
180+
181+
.api-health-title {
182+
margin-top: 0;
183+
margin-bottom: 1rem;
184+
font-size: 1.1rem;
185+
font-weight: 600;
186+
}
187+
188+
.api-health-loading {
189+
display: flex;
190+
align-items: center;
191+
margin-bottom: 1rem;
192+
}
193+
194+
.spinner {
195+
width: 20px;
196+
height: 20px;
197+
border: 2px solid rgba(255, 255, 255, 0.3);
198+
border-radius: 50%;
199+
border-top-color: #fff;
200+
animation: spin 1s linear infinite;
201+
margin-right: 10px;
202+
}
203+
204+
@keyframes spin {
205+
to { transform: rotate(360deg); }
206+
}
207+
208+
.api-health-summary {
209+
display: flex;
210+
align-items: center;
211+
padding: 1rem;
212+
margin-bottom: 1rem;
213+
border-radius: 6px;
214+
}
215+
216+
.status-unknown {
217+
background-color: rgba(128, 128, 128, 0.2);
218+
}
219+
220+
.status-ok {
221+
background-color: rgba(72, 199, 142, 0.2);
222+
}
223+
224+
.status-error {
225+
background-color: rgba(255, 56, 96, 0.2);
226+
}
227+
228+
.status-partial {
229+
background-color: rgba(255, 204, 0, 0.2);
230+
}
231+
232+
.health-icon {
233+
font-size: 1.5rem;
234+
margin-right: 1rem;
235+
}
236+
237+
.health-status p {
238+
margin: 0;
239+
}
240+
241+
.health-description {
242+
font-size: 0.9rem;
243+
opacity: 0.8;
244+
margin-top: 0.25rem;
245+
}
246+
247+
.api-health-endpoints {
248+
margin-bottom: 1rem;
249+
}
250+
251+
.api-health-endpoints h5 {
252+
font-size: 0.9rem;
253+
margin-bottom: 0.5rem;
254+
}
255+
256+
.api-health-endpoints ul {
257+
list-style: none;
258+
padding: 0;
259+
margin: 0;
260+
}
261+
262+
.api-health-endpoints li {
263+
display: flex;
264+
justify-content: space-between;
265+
padding: 0.5rem;
266+
margin-bottom: 0.25rem;
267+
border-radius: 4px;
268+
font-size: 0.9rem;
269+
background-color: rgba(0, 0, 0, 0.1);
270+
}
271+
272+
.endpoint-ok {
273+
border-left: 3px solid #48c78e;
274+
}
275+
276+
.endpoint-error {
277+
border-left: 3px solid #ff3860;
278+
}
279+
280+
.endpoint-path {
281+
font-family: monospace;
282+
}
283+
284+
.status-badge {
285+
padding: 0.1rem 0.5rem;
286+
border-radius: 4px;
287+
font-size: 0.8rem;
288+
font-weight: bold;
289+
}
290+
291+
.status-badge.ok {
292+
background-color: #48c78e;
293+
color: white;
294+
}
295+
296+
.status-badge.error {
297+
background-color: #ff3860;
298+
color: white;
299+
}
300+
301+
.status-badge.unknown {
302+
background-color: #888;
303+
color: white;
304+
}
305+
306+
.api-health-actions {
307+
display: flex;
308+
justify-content: center;
309+
}
310+
311+
.check-api-button {
312+
background-color: #485fc7;
313+
color: white;
314+
border: none;
315+
padding: 0.5rem 1rem;
316+
border-radius: 4px;
317+
cursor: pointer;
318+
transition: background-color 0.2s;
319+
}
320+
321+
.check-api-button:hover:not(:disabled) {
322+
background-color: #3e56c4;
323+
}
324+
325+
.check-api-button:disabled {
326+
opacity: 0.6;
327+
cursor: not-allowed;
328+
}
329+
</style>

0 commit comments

Comments
 (0)