Skip to content

Commit b7fd8fc

Browse files
committed
refactor:control-panel
1 parent 7d94cea commit b7fd8fc

File tree

13 files changed

+345
-641
lines changed

13 files changed

+345
-641
lines changed

dev-docker-compose.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,18 @@ services:
557557
- metastate-network
558558
<<: *common-host-access
559559

560+
# Loki for log aggregation
561+
loki:
562+
profiles:
563+
- all
564+
image: grafana/loki:latest
565+
ports:
566+
- "3100:3100"
567+
command: -config.file=/etc/loki/local-config.yaml
568+
networks:
569+
- metastate-network
570+
<<: *common-host-access
571+
560572
volumes:
561573
postgres_data:
562574
neo4j_data:

infrastructure/control-panel/src/lib/components/EVaultList.svelte

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@
138138
<div class="py-8 text-center">
139139
<p class="text-gray-500">No eVaults found</p>
140140
<p class="mt-1 text-sm text-gray-400">
141-
Try refreshing or check your Kubernetes connection
141+
Try refreshing or check your registry connection
142142
</p>
143143
</div>
144144
{:else}
@@ -155,7 +155,7 @@
155155
<th
156156
class="px-6 py-3 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
157157
>
158-
Namespace
158+
eName (w3id)
159159
</th>
160160
<th
161161
class="px-6 py-3 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
@@ -165,12 +165,7 @@
165165
<th
166166
class="px-6 py-3 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
167167
>
168-
Age
169-
</th>
170-
<th
171-
class="px-6 py-3 text-left text-xs font-medium tracking-wider text-gray-500 uppercase"
172-
>
173-
Service URL
168+
URI
174169
</th>
175170
</tr>
176171
</thead>
@@ -180,38 +175,35 @@
180175
<td
181176
class="px-6 py-4 text-sm font-medium whitespace-nowrap text-gray-900"
182177
>
183-
{evault.name}
178+
{evault.name || evault.ename || evault.evault}
184179
</td>
185180
<td class="px-6 py-4 text-sm whitespace-nowrap text-gray-500">
186-
{evault.namespace}
181+
{evault.ename || 'N/A'}
187182
</td>
188183
<td class="px-6 py-4 whitespace-nowrap">
189184
<span
190185
class="inline-flex rounded-full px-2 py-1 text-xs font-semibold {evault.status ===
191-
'Running'
186+
'Active'
192187
? 'bg-green-100 text-green-800'
193-
: evault.status === 'Pending'
194-
? 'bg-yellow-100 text-yellow-800'
195-
: 'bg-red-100 text-red-800'}"
188+
: evault.status === 'Inactive'
189+
? 'bg-red-100 text-red-800'
190+
: 'bg-gray-100 text-gray-800'}"
196191
>
197-
{evault.status}
192+
{evault.status || 'Unknown'}
198193
</span>
199194
</td>
200195
<td class="px-6 py-4 text-sm whitespace-nowrap text-gray-500">
201-
{evault.age || 'Unknown'}
202-
</td>
203-
<td class="px-6 py-4 text-sm whitespace-nowrap text-gray-500">
204-
{#if evault.serviceUrl}
196+
{#if evault.uri || evault.serviceUrl}
205197
<a
206-
href={evault.serviceUrl}
198+
href={evault.uri || evault.serviceUrl}
207199
target="_blank"
208200
rel="noopener noreferrer"
209201
class="text-blue-600 underline hover:text-blue-800"
210202
>
211-
{evault.serviceUrl}
203+
{evault.uri || evault.serviceUrl}
212204
</a>
213205
{:else}
214-
<span class="text-gray-400">No external access</span>
206+
<span class="text-gray-400">No URI available</span>
215207
{/if}
216208
</td>
217209
</tr>

infrastructure/control-panel/src/lib/services/evaultService.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,15 @@ export class EVaultService {
7575
}
7676

7777
/**
78-
* Get logs for a specific eVault pod
78+
* Get logs for a specific eVault by evaultId
7979
*/
80-
/**
81-
* Get logs for a specific eVault pod
82-
*/
83-
static async getEVaultLogs(namespace: string, podName: string): Promise<string[]> {
80+
static async getEVaultLogs(evaultId: string, tail?: number): Promise<string[]> {
8481
try {
85-
const response = await fetch(
86-
`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/logs`
87-
);
82+
const url = new URL(`/api/evaults/${encodeURIComponent(evaultId)}/logs`, window.location.origin);
83+
if (tail) {
84+
url.searchParams.set('tail', tail.toString());
85+
}
86+
const response = await fetch(url.toString());
8887
if (!response.ok) {
8988
throw new Error(`HTTP error! status: ${response.status}`);
9089
}
@@ -97,20 +96,20 @@ export class EVaultService {
9796
}
9897

9998
/**
100-
* Get metrics for a specific eVault pod
99+
* Get details for a specific eVault by evaultId
101100
*/
102-
static async getEVaultMetrics(namespace: string, podName: string): Promise<any> {
101+
static async getEVaultDetails(evaultId: string): Promise<any> {
103102
try {
104103
const response = await fetch(
105-
`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/metrics`
104+
`/api/evaults/${encodeURIComponent(evaultId)}/details`
106105
);
107106
if (!response.ok) {
108107
throw new Error(`HTTP error! status: ${response.status}`);
109108
}
110109
const data = await response.json();
111-
return data.metrics || {};
110+
return data.evault || {};
112111
} catch (error) {
113-
console.error('Failed to fetch eVault metrics:', error);
112+
console.error('Failed to fetch eVault details:', error);
114113
throw error;
115114
}
116115
}

infrastructure/control-panel/src/lib/services/loki.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,49 @@ export class LokiService {
9898
.filter((event): event is FlowEvent => event !== null);
9999
}
100100

101+
/**
102+
* Query logs for a specific evault by identifier
103+
* Supports querying by evault field or ename (w3id) in log labels
104+
*/
105+
async getEVaultLogs(
106+
evaultId: string,
107+
ename?: string,
108+
limit: number = 100,
109+
start?: string,
110+
end?: string
111+
): Promise<string[]> {
112+
// Try multiple query patterns to find logs for this evault
113+
// First try by evault field, then by ename/w3id
114+
const queries = [
115+
`{evault="${evaultId}"}`,
116+
...(ename ? [`{ename="${ename}"}`, `{w3id="${ename}"}`] : [])
117+
];
118+
119+
const allLogs: LogEntry[] = [];
120+
121+
// Try each query pattern
122+
for (const query of queries) {
123+
try {
124+
const logs = await this.queryLogs(query, start, end);
125+
allLogs.push(...logs);
126+
} catch (error) {
127+
console.log(`Query ${query} failed, trying next pattern`);
128+
}
129+
}
130+
131+
// Remove duplicates and sort by timestamp
132+
const uniqueLogs = Array.from(
133+
new Map(allLogs.map((log) => [`${log.timestamp}-${log.line}`, log])).values()
134+
).sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
135+
136+
// Extract log lines and limit to requested number
137+
const logLines = uniqueLogs
138+
.map((log) => log.line)
139+
.slice(-limit); // Get last N lines
140+
141+
return logLines;
142+
}
143+
101144
parseLogEntry(log: LogEntry): FlowEvent | null {
102145
try {
103146
// Parse the JSON log line

infrastructure/control-panel/src/lib/services/registry.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,37 @@ export interface Platform {
77
uptime: string;
88
}
99

10+
export interface RegistryVault {
11+
ename: string;
12+
uri: string;
13+
evault: string;
14+
originalUri?: string;
15+
resolved?: boolean;
16+
}
17+
1018
export class RegistryService {
1119
private baseUrl: string;
1220

1321
constructor() {
1422
this.baseUrl = env.PUBLIC_REGISTRY_URL || 'https://registry.staging.metastate.foundation';
1523
}
1624

25+
async getEVaults(): Promise<RegistryVault[]> {
26+
try {
27+
const response = await fetch(`${this.baseUrl}/list`);
28+
29+
if (!response.ok) {
30+
throw new Error(`HTTP error! status: ${response.status}`);
31+
}
32+
33+
const vaults: RegistryVault[] = await response.json();
34+
return vaults;
35+
} catch (error) {
36+
console.error('Error fetching evaults from registry:', error);
37+
return [];
38+
}
39+
}
40+
1741
async getPlatforms(): Promise<Platform[]> {
1842
try {
1943
const response = await fetch(`${this.baseUrl}/platforms`);

infrastructure/control-panel/src/routes/+page.svelte

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@
3030
let selectedPlatforms = $state<string[]>([]);
3131
3232
// Filtered data for search
33-
let filteredEVaults = $derived(() => {
33+
let filteredEVaults = $derived(() => {
3434
if (!evaultsSearchValue.trim()) return evaults;
3535
return evaults.filter(
3636
(evault) =>
37-
evault.name.toLowerCase().includes(evaultsSearchValue.toLowerCase()) ||
38-
evault.evaultId.toLowerCase().includes(evaultsSearchValue.toLowerCase()) ||
39-
evault.namespace.toLowerCase().includes(evaultsSearchValue.toLowerCase())
37+
evault.name?.toLowerCase().includes(evaultsSearchValue.toLowerCase()) ||
38+
evault.ename?.toLowerCase().includes(evaultsSearchValue.toLowerCase()) ||
39+
evault.evault?.toLowerCase().includes(evaultsSearchValue.toLowerCase()) ||
40+
evault.id?.toLowerCase().includes(evaultsSearchValue.toLowerCase())
4041
);
4142
});
4243
@@ -70,23 +71,23 @@
7071
let mappedEVaultsData = $derived(() => {
7172
const paginated = paginatedEVaults();
7273
return paginated.map((evault) => ({
73-
eName: {
74+
Name: {
7475
type: 'text',
75-
value: evault.evaultId,
76+
value: evault.name || evault.ename || evault.evault,
7677
className: 'cursor-pointer text-blue-600 hover:text-blue-800 hover:underline'
7778
},
78-
Uptime: {
79+
eName: {
7980
type: 'text',
80-
value: evault.age
81+
value: evault.ename || 'N/A'
8182
},
82-
IP: {
83+
Status: {
8384
type: 'text',
84-
value: evault.ip
85+
value: evault.status || 'Unknown'
8586
},
8687
URI: {
8788
type: 'link',
88-
value: evault.serviceUrl || 'N/A',
89-
link: evault.serviceUrl || '#',
89+
value: evault.uri || evault.serviceUrl || 'N/A',
90+
link: evault.uri || evault.serviceUrl || '#',
9091
external: true
9192
}
9293
}));
@@ -142,14 +143,16 @@
142143
}
143144
144145
if (checked) {
145-
selectedEVaults = [...selectedEVaults, selectedEVault.evaultId];
146+
const evaultId = selectedEVault.evault || selectedEVault.ename || selectedEVault.id;
147+
selectedEVaults = [...selectedEVaults, evaultId];
146148
} else {
147-
selectedEVaults = selectedEVaults.filter((id) => id !== selectedEVault.evaultId);
149+
const evaultId = selectedEVault.evault || selectedEVault.ename || selectedEVault.id;
150+
selectedEVaults = selectedEVaults.filter((id) => id !== evaultId);
148151
}
149152
150153
// Store selections immediately in sessionStorage
151154
const selectedEVaultData = selectedEVaults
152-
.map((id) => evaults.find((e) => e.evaultId === id))
155+
.map((id) => evaults.find((e) => (e.evault || e.ename || e.id) === id))
153156
.filter(Boolean);
154157
sessionStorage.setItem('selectedEVaults', JSON.stringify(selectedEVaultData));
155158
}
@@ -189,8 +192,8 @@
189192
console.log('filtered eVaults length:', filtered.length);
190193
191194
if (checked) {
192-
// Select all filtered eVaults by their evaultId
193-
selectedEVaults = filtered.map((evault) => evault.evaultId);
195+
// Select all filtered eVaults by their ID (evault or ename)
196+
selectedEVaults = filtered.map((evault) => evault.evault || evault.ename || evault.id);
194197
console.log('✅ Selected all filtered eVaults, selectedEVaults:', selectedEVaults);
195198
} else {
196199
// Deselect all eVaults
@@ -290,7 +293,7 @@
290293
const mapped = {
291294
eName: {
292295
type: 'text',
293-
value: evault.evaultId,
296+
value: evault.evault || evault.ename || evault.id,
294297
className:
295298
'cursor-pointer text-blue-600 hover:text-blue-800 hover:underline'
296299
},
@@ -349,7 +352,9 @@
349352
const paginated = paginatedEVaults();
350353
const evault = paginated[index];
351354
if (evault) {
352-
goto(`/monitoring/${evault.namespace}/${evault.name}`);
355+
// Use evault ID (evault field or ename) for navigation
356+
const evaultId = evault.evault || evault.ename || evault.id;
357+
goto(`/evaults/${encodeURIComponent(evaultId)}`);
353358
}
354359
}
355360
@@ -403,9 +408,10 @@
403408
onSelectionChange={handleEVaultSelectionChange}
404409
onSelectAllChange={handleSelectAllEVaults}
405410
selectedIndices={paginatedEVaults()
406-
.map((evault, index) =>
407-
selectedEVaults.includes(evault.evaultId) ? index : -1
408-
)
411+
.map((evault, index) => {
412+
const evaultId = evault.evault || evault.ename || evault.id;
413+
return selectedEVaults.includes(evaultId) ? index : -1;
414+
})
409415
.filter((index) => index !== -1)}
410416
/>
411417

0 commit comments

Comments
 (0)