@alepha/devtools 0.13.6 → 0.13.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +249 -32
- package/dist/index.js +253 -22
- package/dist/index.js.map +1 -1
- package/package.json +12 -6
- package/src/{DevToolsProvider.ts → api/DevToolsProvider.ts} +29 -1
- package/src/{providers → api/providers}/DevToolsMetadataProvider.ts +210 -2
- package/src/api/schemas/DevAtomMetadata.ts +26 -0
- package/src/api/schemas/DevCommandMetadata.ts +9 -0
- package/src/api/schemas/DevEntityMetadata.ts +57 -0
- package/src/api/schemas/DevEnvMetadata.ts +22 -0
- package/src/{schemas → api/schemas}/DevMetadata.ts +10 -1
- package/src/api/schemas/DevRouteMetadata.ts +8 -0
- package/src/index.ts +23 -16
- package/src/ui/AppRouter.tsx +85 -2
- package/src/ui/components/DevAtomsViewer.tsx +636 -0
- package/src/ui/components/DevCacheInspector.tsx +423 -0
- package/src/ui/components/DevDashboard.tsx +188 -0
- package/src/ui/components/DevEnvExplorer.tsx +462 -0
- package/src/ui/components/DevLayout.tsx +65 -4
- package/src/ui/components/DevLogViewer.tsx +161 -163
- package/src/ui/components/DevQueueMonitor.tsx +51 -0
- package/src/ui/components/DevTopicsViewer.tsx +690 -0
- package/src/ui/components/actions/ActionGroup.tsx +37 -0
- package/src/ui/components/actions/ActionItem.tsx +138 -0
- package/src/ui/components/actions/DevActionsExplorer.tsx +132 -0
- package/src/ui/components/actions/MethodBadge.tsx +18 -0
- package/src/ui/components/actions/SchemaViewer.tsx +21 -0
- package/src/ui/components/actions/TryItPanel.tsx +140 -0
- package/src/ui/components/actions/constants.ts +7 -0
- package/src/ui/components/actions/helpers.ts +18 -0
- package/src/ui/components/actions/index.ts +8 -0
- package/src/ui/components/db/ColumnBadge.tsx +55 -0
- package/src/ui/components/db/DevDbStudio.tsx +485 -0
- package/src/ui/components/db/constants.ts +11 -0
- package/src/ui/components/db/index.ts +4 -0
- package/src/ui/components/db/types.ts +7 -0
- package/src/ui/components/graph/DevDependencyGraph.tsx +358 -0
- package/src/ui/components/graph/GraphControls.tsx +162 -0
- package/src/ui/components/graph/NodeDetails.tsx +181 -0
- package/src/ui/components/graph/ProviderNode.tsx +97 -0
- package/src/ui/components/graph/constants.ts +35 -0
- package/src/ui/components/graph/helpers.ts +443 -0
- package/src/ui/components/graph/index.ts +7 -0
- package/src/ui/components/graph/types.ts +28 -0
- package/src/ui/styles.css +0 -6
- package/src/ui/resources/wotfardregular/stylesheet.css +0 -12
- package/src/ui/resources/wotfardregular/wotfard-regular-webfont.eot +0 -0
- package/src/ui/resources/wotfardregular/wotfard-regular-webfont.ttf +0 -0
- package/src/ui/resources/wotfardregular/wotfard-regular-webfont.woff2 +0 -0
- /package/src/{entities → api/entities}/logs.ts +0 -0
- /package/src/{providers → api/providers}/DevToolsDatabaseProvider.ts +0 -0
- /package/src/{repositories → api/repositories}/LogRepository.ts +0 -0
- /package/src/{schemas → api/schemas}/DevActionMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevBucketMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevCacheMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevModuleMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevPageMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevProviderMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevQueueMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevRealmMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevSchedulerMetadata.ts +0 -0
- /package/src/{schemas → api/schemas}/DevTopicMetadata.ts +0 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import { useInject } from "@alepha/react";
|
|
2
|
+
import { ui } from "@alepha/ui";
|
|
3
|
+
import {
|
|
4
|
+
Badge,
|
|
5
|
+
Box,
|
|
6
|
+
Code,
|
|
7
|
+
CopyButton,
|
|
8
|
+
Flex,
|
|
9
|
+
ScrollArea,
|
|
10
|
+
Stack,
|
|
11
|
+
Table,
|
|
12
|
+
Text,
|
|
13
|
+
TextInput,
|
|
14
|
+
Tooltip,
|
|
15
|
+
} from "@mantine/core";
|
|
16
|
+
import {
|
|
17
|
+
IconCheck,
|
|
18
|
+
IconCopy,
|
|
19
|
+
IconKey,
|
|
20
|
+
IconSearch,
|
|
21
|
+
IconSettings,
|
|
22
|
+
IconVariable,
|
|
23
|
+
} from "@tabler/icons-react";
|
|
24
|
+
import { HttpClient } from "alepha/server";
|
|
25
|
+
import { useEffect, useMemo, useState } from "react";
|
|
26
|
+
import type { DevEnvMetadata } from "../../api/schemas/DevEnvMetadata.ts";
|
|
27
|
+
import { devMetadataSchema } from "../../api/schemas/DevMetadata.ts";
|
|
28
|
+
|
|
29
|
+
interface EnvVariable {
|
|
30
|
+
name: string;
|
|
31
|
+
value: any;
|
|
32
|
+
type: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
format?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const parseEnvVariables = (envs: DevEnvMetadata[]): EnvVariable[] => {
|
|
38
|
+
const variableMap = new Map<string, EnvVariable>();
|
|
39
|
+
|
|
40
|
+
for (const env of envs) {
|
|
41
|
+
const schema = env.schema;
|
|
42
|
+
if (!schema?.properties) continue;
|
|
43
|
+
|
|
44
|
+
for (const [name, propSchema] of Object.entries(schema.properties)) {
|
|
45
|
+
// Skip if already added (deduplication)
|
|
46
|
+
if (variableMap.has(name)) continue;
|
|
47
|
+
|
|
48
|
+
const prop = propSchema as any;
|
|
49
|
+
const value = env.values[name];
|
|
50
|
+
|
|
51
|
+
// Get the actual type from schema
|
|
52
|
+
let type = prop.type ?? "unknown";
|
|
53
|
+
let format = prop.format;
|
|
54
|
+
|
|
55
|
+
// Handle union types (optional)
|
|
56
|
+
if (prop.anyOf) {
|
|
57
|
+
const nonNull = prop.anyOf.find((t: any) => t.type !== "null");
|
|
58
|
+
if (nonNull) {
|
|
59
|
+
type = nonNull.type ?? "unknown";
|
|
60
|
+
format = nonNull.format;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
variableMap.set(name, {
|
|
65
|
+
name,
|
|
66
|
+
value,
|
|
67
|
+
type,
|
|
68
|
+
description: prop.description,
|
|
69
|
+
format,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return Array.from(variableMap.values()).sort((a, b) =>
|
|
75
|
+
a.name.localeCompare(b.name),
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const EnvSidebar = ({
|
|
80
|
+
variables,
|
|
81
|
+
selectedVar,
|
|
82
|
+
onSelectVar,
|
|
83
|
+
search,
|
|
84
|
+
onSearchChange,
|
|
85
|
+
}: {
|
|
86
|
+
variables: EnvVariable[];
|
|
87
|
+
selectedVar: EnvVariable | null;
|
|
88
|
+
onSelectVar: (v: EnvVariable) => void;
|
|
89
|
+
search: string;
|
|
90
|
+
onSearchChange: (s: string) => void;
|
|
91
|
+
}) => {
|
|
92
|
+
return (
|
|
93
|
+
<Stack gap={0} h="100%">
|
|
94
|
+
<Box p="sm" style={{ borderBottom: `1px solid ${ui.colors.border}` }}>
|
|
95
|
+
<TextInput
|
|
96
|
+
placeholder="Search variables..."
|
|
97
|
+
leftSection={<IconSearch size={14} />}
|
|
98
|
+
size="xs"
|
|
99
|
+
value={search}
|
|
100
|
+
onChange={(e) => onSearchChange(e.target.value)}
|
|
101
|
+
/>
|
|
102
|
+
</Box>
|
|
103
|
+
<ScrollArea style={{ flex: 1 }}>
|
|
104
|
+
<Box>
|
|
105
|
+
<Text
|
|
106
|
+
size="xs"
|
|
107
|
+
fw={600}
|
|
108
|
+
c="dimmed"
|
|
109
|
+
px="sm"
|
|
110
|
+
py="xs"
|
|
111
|
+
style={{
|
|
112
|
+
backgroundColor: ui.colors.background,
|
|
113
|
+
borderBottom: `1px solid ${ui.colors.border}`,
|
|
114
|
+
textTransform: "uppercase",
|
|
115
|
+
letterSpacing: "0.05em",
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
Variables ({variables.length})
|
|
119
|
+
</Text>
|
|
120
|
+
{variables.map((v) => {
|
|
121
|
+
const isSelected = selectedVar?.name === v.name;
|
|
122
|
+
return (
|
|
123
|
+
<Flex
|
|
124
|
+
key={v.name}
|
|
125
|
+
align="center"
|
|
126
|
+
gap="xs"
|
|
127
|
+
px="sm"
|
|
128
|
+
py={6}
|
|
129
|
+
onClick={() => onSelectVar(v)}
|
|
130
|
+
style={{
|
|
131
|
+
cursor: "pointer",
|
|
132
|
+
backgroundColor: isSelected ? "#228be615" : undefined,
|
|
133
|
+
borderLeft: isSelected
|
|
134
|
+
? "2px solid #228be6"
|
|
135
|
+
: "2px solid transparent",
|
|
136
|
+
borderBottom: `1px solid ${ui.colors.border}`,
|
|
137
|
+
}}
|
|
138
|
+
>
|
|
139
|
+
<IconVariable size={14} opacity={0.5} />
|
|
140
|
+
<Text size="sm" style={{ flex: 1 }} truncate ff="monospace">
|
|
141
|
+
{v.name}
|
|
142
|
+
</Text>
|
|
143
|
+
</Flex>
|
|
144
|
+
);
|
|
145
|
+
})}
|
|
146
|
+
</Box>
|
|
147
|
+
</ScrollArea>
|
|
148
|
+
</Stack>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const EnvPanel = ({ variable }: { variable: EnvVariable }) => {
|
|
153
|
+
const hasValue = variable.value !== undefined && variable.value !== "";
|
|
154
|
+
const displayValue = hasValue ? String(variable.value) : "(not set)";
|
|
155
|
+
const isSensitive =
|
|
156
|
+
variable.name.toLowerCase().includes("secret") ||
|
|
157
|
+
variable.name.toLowerCase().includes("password") ||
|
|
158
|
+
variable.name.toLowerCase().includes("key") ||
|
|
159
|
+
variable.name.toLowerCase().includes("token");
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<Flex direction="column" h="100%">
|
|
163
|
+
{/* Header */}
|
|
164
|
+
<Box
|
|
165
|
+
px="md"
|
|
166
|
+
py="sm"
|
|
167
|
+
style={{
|
|
168
|
+
borderBottom: `1px solid ${ui.colors.border}`,
|
|
169
|
+
backgroundColor: "#228be608",
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
<Flex align="center" gap="sm">
|
|
173
|
+
<IconVariable size={18} opacity={0.7} />
|
|
174
|
+
<Text size="md" fw={600} ff="monospace">
|
|
175
|
+
{variable.name}
|
|
176
|
+
</Text>
|
|
177
|
+
<Badge size="xs" variant="outline" color="blue">
|
|
178
|
+
{variable.format || variable.type}
|
|
179
|
+
</Badge>
|
|
180
|
+
</Flex>
|
|
181
|
+
</Box>
|
|
182
|
+
|
|
183
|
+
<ScrollArea style={{ flex: 1 }} p="md">
|
|
184
|
+
<Stack gap="lg">
|
|
185
|
+
{/* Description */}
|
|
186
|
+
{variable.description && (
|
|
187
|
+
<Box>
|
|
188
|
+
<Text size="sm" fw={600} mb="xs">
|
|
189
|
+
Description
|
|
190
|
+
</Text>
|
|
191
|
+
<Text size="sm" c="dimmed">
|
|
192
|
+
{variable.description}
|
|
193
|
+
</Text>
|
|
194
|
+
</Box>
|
|
195
|
+
)}
|
|
196
|
+
|
|
197
|
+
{/* Current Value */}
|
|
198
|
+
<Box>
|
|
199
|
+
<Text size="sm" fw={600} mb="xs">
|
|
200
|
+
Current Value
|
|
201
|
+
</Text>
|
|
202
|
+
<Flex align="center" gap="sm">
|
|
203
|
+
<Code
|
|
204
|
+
block
|
|
205
|
+
style={{
|
|
206
|
+
flex: 1,
|
|
207
|
+
filter: isSensitive && hasValue ? "blur(4px)" : undefined,
|
|
208
|
+
transition: "filter 0.2s",
|
|
209
|
+
}}
|
|
210
|
+
onMouseEnter={(e) => {
|
|
211
|
+
if (isSensitive) e.currentTarget.style.filter = "none";
|
|
212
|
+
}}
|
|
213
|
+
onMouseLeave={(e) => {
|
|
214
|
+
if (isSensitive && hasValue)
|
|
215
|
+
e.currentTarget.style.filter = "blur(4px)";
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
218
|
+
{displayValue}
|
|
219
|
+
</Code>
|
|
220
|
+
{hasValue && (
|
|
221
|
+
<CopyButton value={String(variable.value)}>
|
|
222
|
+
{({ copied, copy }) => (
|
|
223
|
+
<Tooltip label={copied ? "Copied!" : "Copy value"}>
|
|
224
|
+
<Box
|
|
225
|
+
onClick={copy}
|
|
226
|
+
style={{ cursor: "pointer" }}
|
|
227
|
+
c={copied ? "teal" : "dimmed"}
|
|
228
|
+
>
|
|
229
|
+
{copied ? (
|
|
230
|
+
<IconCheck size={16} />
|
|
231
|
+
) : (
|
|
232
|
+
<IconCopy size={16} />
|
|
233
|
+
)}
|
|
234
|
+
</Box>
|
|
235
|
+
</Tooltip>
|
|
236
|
+
)}
|
|
237
|
+
</CopyButton>
|
|
238
|
+
)}
|
|
239
|
+
</Flex>
|
|
240
|
+
{isSensitive && (
|
|
241
|
+
<Text size="xs" c="dimmed" mt="xs">
|
|
242
|
+
Hover to reveal sensitive value
|
|
243
|
+
</Text>
|
|
244
|
+
)}
|
|
245
|
+
</Box>
|
|
246
|
+
|
|
247
|
+
{/* Schema Info */}
|
|
248
|
+
<Box>
|
|
249
|
+
<Text size="sm" fw={600} mb="xs">
|
|
250
|
+
Schema
|
|
251
|
+
</Text>
|
|
252
|
+
<Table striped highlightOnHover withTableBorder>
|
|
253
|
+
<Table.Tbody>
|
|
254
|
+
<Table.Tr>
|
|
255
|
+
<Table.Td w={120}>
|
|
256
|
+
<Text size="sm" c="dimmed">
|
|
257
|
+
Type
|
|
258
|
+
</Text>
|
|
259
|
+
</Table.Td>
|
|
260
|
+
<Table.Td>
|
|
261
|
+
<Text size="sm" ff="monospace">
|
|
262
|
+
{variable.type}
|
|
263
|
+
</Text>
|
|
264
|
+
</Table.Td>
|
|
265
|
+
</Table.Tr>
|
|
266
|
+
{variable.format && (
|
|
267
|
+
<Table.Tr>
|
|
268
|
+
<Table.Td>
|
|
269
|
+
<Text size="sm" c="dimmed">
|
|
270
|
+
Format
|
|
271
|
+
</Text>
|
|
272
|
+
</Table.Td>
|
|
273
|
+
<Table.Td>
|
|
274
|
+
<Text size="sm" ff="monospace">
|
|
275
|
+
{variable.format}
|
|
276
|
+
</Text>
|
|
277
|
+
</Table.Td>
|
|
278
|
+
</Table.Tr>
|
|
279
|
+
)}
|
|
280
|
+
</Table.Tbody>
|
|
281
|
+
</Table>
|
|
282
|
+
</Box>
|
|
283
|
+
|
|
284
|
+
{/* Usage hint */}
|
|
285
|
+
<Box>
|
|
286
|
+
<Text size="sm" fw={600} mb="xs">
|
|
287
|
+
Usage
|
|
288
|
+
</Text>
|
|
289
|
+
<Code block>
|
|
290
|
+
{`# Set in .env file or environment
|
|
291
|
+
${variable.name}=${hasValue ? variable.value : "<value>"}`}
|
|
292
|
+
</Code>
|
|
293
|
+
</Box>
|
|
294
|
+
</Stack>
|
|
295
|
+
</ScrollArea>
|
|
296
|
+
</Flex>
|
|
297
|
+
);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const EmptyState = () => (
|
|
301
|
+
<Flex align="center" justify="center" h="100%" c="dimmed">
|
|
302
|
+
<Stack align="center" gap="xs">
|
|
303
|
+
<IconVariable size={48} opacity={0.3} />
|
|
304
|
+
<Text size="sm">Select a variable to view details</Text>
|
|
305
|
+
</Stack>
|
|
306
|
+
</Flex>
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const NoEnvsState = () => (
|
|
310
|
+
<Flex align="center" justify="center" h="100%" c="dimmed">
|
|
311
|
+
<Stack align="center" gap="xs">
|
|
312
|
+
<IconSettings size={48} opacity={0.3} />
|
|
313
|
+
<Text>No environment variables found</Text>
|
|
314
|
+
<Text size="sm" c="dimmed">
|
|
315
|
+
Use $env primitive to define expected environment variables
|
|
316
|
+
</Text>
|
|
317
|
+
</Stack>
|
|
318
|
+
</Flex>
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
const AllEnvsTable = ({ variables }: { variables: EnvVariable[] }) => {
|
|
322
|
+
return (
|
|
323
|
+
<ScrollArea h="100%" p="md">
|
|
324
|
+
<Stack gap="lg">
|
|
325
|
+
<Box>
|
|
326
|
+
<Flex align="center" gap="xs" mb="sm">
|
|
327
|
+
<IconKey size={18} opacity={0.7} />
|
|
328
|
+
<Text size="md" fw={600}>
|
|
329
|
+
All Environment Variables
|
|
330
|
+
</Text>
|
|
331
|
+
<Badge size="sm" variant="light">
|
|
332
|
+
{variables.length} variables
|
|
333
|
+
</Badge>
|
|
334
|
+
</Flex>
|
|
335
|
+
<Table striped highlightOnHover withTableBorder>
|
|
336
|
+
<Table.Thead>
|
|
337
|
+
<Table.Tr>
|
|
338
|
+
<Table.Th>Name</Table.Th>
|
|
339
|
+
<Table.Th>Type</Table.Th>
|
|
340
|
+
<Table.Th>Value</Table.Th>
|
|
341
|
+
</Table.Tr>
|
|
342
|
+
</Table.Thead>
|
|
343
|
+
<Table.Tbody>
|
|
344
|
+
{variables.map((v) => {
|
|
345
|
+
const hasValue = v.value !== undefined && v.value !== "";
|
|
346
|
+
const isSensitive =
|
|
347
|
+
v.name.toLowerCase().includes("secret") ||
|
|
348
|
+
v.name.toLowerCase().includes("password") ||
|
|
349
|
+
v.name.toLowerCase().includes("key") ||
|
|
350
|
+
v.name.toLowerCase().includes("token");
|
|
351
|
+
return (
|
|
352
|
+
<Table.Tr key={v.name}>
|
|
353
|
+
<Table.Td>
|
|
354
|
+
<Text size="sm" ff="monospace" fw={500}>
|
|
355
|
+
{v.name}
|
|
356
|
+
</Text>
|
|
357
|
+
</Table.Td>
|
|
358
|
+
<Table.Td>
|
|
359
|
+
<Badge size="xs" variant="outline" color="blue">
|
|
360
|
+
{v.format || v.type}
|
|
361
|
+
</Badge>
|
|
362
|
+
</Table.Td>
|
|
363
|
+
<Table.Td>
|
|
364
|
+
{hasValue ? (
|
|
365
|
+
<Text
|
|
366
|
+
size="sm"
|
|
367
|
+
ff="monospace"
|
|
368
|
+
c="dimmed"
|
|
369
|
+
style={{
|
|
370
|
+
filter: isSensitive ? "blur(4px)" : undefined,
|
|
371
|
+
}}
|
|
372
|
+
>
|
|
373
|
+
{String(v.value).slice(0, 30)}
|
|
374
|
+
{String(v.value).length > 30 ? "..." : ""}
|
|
375
|
+
</Text>
|
|
376
|
+
) : (
|
|
377
|
+
<Text size="sm" c="dimmed" fs="italic">
|
|
378
|
+
(not set)
|
|
379
|
+
</Text>
|
|
380
|
+
)}
|
|
381
|
+
</Table.Td>
|
|
382
|
+
</Table.Tr>
|
|
383
|
+
);
|
|
384
|
+
})}
|
|
385
|
+
</Table.Tbody>
|
|
386
|
+
</Table>
|
|
387
|
+
</Box>
|
|
388
|
+
</Stack>
|
|
389
|
+
</ScrollArea>
|
|
390
|
+
);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
export const DevEnvExplorer = () => {
|
|
394
|
+
const http = useInject(HttpClient);
|
|
395
|
+
const [envs, setEnvs] = useState<DevEnvMetadata[]>([]);
|
|
396
|
+
const [loading, setLoading] = useState(true);
|
|
397
|
+
const [selectedVar, setSelectedVar] = useState<EnvVariable | null>(null);
|
|
398
|
+
const [search, setSearch] = useState("");
|
|
399
|
+
|
|
400
|
+
useEffect(() => {
|
|
401
|
+
http
|
|
402
|
+
.fetch("/devtools/api/metadata", {
|
|
403
|
+
schema: { response: devMetadataSchema },
|
|
404
|
+
})
|
|
405
|
+
.then((res) => {
|
|
406
|
+
setEnvs(res.data.envs);
|
|
407
|
+
setLoading(false);
|
|
408
|
+
});
|
|
409
|
+
}, []);
|
|
410
|
+
|
|
411
|
+
const variables = useMemo(() => parseEnvVariables(envs), [envs]);
|
|
412
|
+
|
|
413
|
+
const filteredVariables = useMemo(() => {
|
|
414
|
+
if (!search) return variables;
|
|
415
|
+
const searchLower = search.toLowerCase();
|
|
416
|
+
return variables.filter((v) => v.name.toLowerCase().includes(searchLower));
|
|
417
|
+
}, [variables, search]);
|
|
418
|
+
|
|
419
|
+
if (loading) {
|
|
420
|
+
return (
|
|
421
|
+
<Flex align="center" justify="center" h="100%">
|
|
422
|
+
<Text c="dimmed">Loading...</Text>
|
|
423
|
+
</Flex>
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (variables.length === 0) {
|
|
428
|
+
return <NoEnvsState />;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return (
|
|
432
|
+
<Flex h="100%" style={{ overflow: "hidden" }}>
|
|
433
|
+
{/* Sidebar */}
|
|
434
|
+
<Box
|
|
435
|
+
w={280}
|
|
436
|
+
style={{
|
|
437
|
+
borderRight: `1px solid ${ui.colors.border}`,
|
|
438
|
+
backgroundColor: ui.colors.surface,
|
|
439
|
+
}}
|
|
440
|
+
>
|
|
441
|
+
<EnvSidebar
|
|
442
|
+
variables={filteredVariables}
|
|
443
|
+
selectedVar={selectedVar}
|
|
444
|
+
onSelectVar={setSelectedVar}
|
|
445
|
+
search={search}
|
|
446
|
+
onSearchChange={setSearch}
|
|
447
|
+
/>
|
|
448
|
+
</Box>
|
|
449
|
+
|
|
450
|
+
{/* Main content */}
|
|
451
|
+
<Box style={{ flex: 1, overflow: "hidden" }}>
|
|
452
|
+
{selectedVar ? (
|
|
453
|
+
<EnvPanel variable={selectedVar} />
|
|
454
|
+
) : (
|
|
455
|
+
<AllEnvsTable variables={variables} />
|
|
456
|
+
)}
|
|
457
|
+
</Box>
|
|
458
|
+
</Flex>
|
|
459
|
+
);
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
export default DevEnvExplorer;
|
|
@@ -3,11 +3,23 @@ import {
|
|
|
3
3
|
ActionButton,
|
|
4
4
|
AdminShell,
|
|
5
5
|
DarkModeButton,
|
|
6
|
-
Flex,
|
|
7
6
|
OmnibarButton,
|
|
8
7
|
ui,
|
|
9
8
|
} from "@alepha/ui";
|
|
10
|
-
import {
|
|
9
|
+
import { Flex } from "@mantine/core";
|
|
10
|
+
import {
|
|
11
|
+
IconApi,
|
|
12
|
+
IconArchive,
|
|
13
|
+
IconAtom,
|
|
14
|
+
IconDashboard,
|
|
15
|
+
IconDatabase,
|
|
16
|
+
IconLogs,
|
|
17
|
+
IconMessageCircle,
|
|
18
|
+
IconStack2,
|
|
19
|
+
IconTools,
|
|
20
|
+
IconTopologyRing,
|
|
21
|
+
IconVariable,
|
|
22
|
+
} from "@tabler/icons-react";
|
|
11
23
|
|
|
12
24
|
export const DevLayout = () => {
|
|
13
25
|
return (
|
|
@@ -34,6 +46,49 @@ export const DevLayout = () => {
|
|
|
34
46
|
icon: <IconDashboard />,
|
|
35
47
|
href: "/",
|
|
36
48
|
},
|
|
49
|
+
{ type: "divider" },
|
|
50
|
+
{
|
|
51
|
+
label: "Actions",
|
|
52
|
+
icon: <IconApi />,
|
|
53
|
+
href: "/actions",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: "Queues",
|
|
57
|
+
icon: <IconStack2 />,
|
|
58
|
+
href: "/queues",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: "Topics",
|
|
62
|
+
icon: <IconMessageCircle />,
|
|
63
|
+
href: "/topics",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: "Caches",
|
|
67
|
+
icon: <IconArchive />,
|
|
68
|
+
href: "/caches",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: "DB Studio",
|
|
72
|
+
icon: <IconDatabase />,
|
|
73
|
+
href: "/db",
|
|
74
|
+
},
|
|
75
|
+
{ type: "divider" },
|
|
76
|
+
{
|
|
77
|
+
label: "Environment",
|
|
78
|
+
icon: <IconVariable />,
|
|
79
|
+
href: "/env",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: "Atoms",
|
|
83
|
+
icon: <IconAtom />,
|
|
84
|
+
href: "/atoms",
|
|
85
|
+
},
|
|
86
|
+
{ type: "divider" },
|
|
87
|
+
{
|
|
88
|
+
label: "Graph",
|
|
89
|
+
icon: <IconTopologyRing />,
|
|
90
|
+
href: "/graph",
|
|
91
|
+
},
|
|
37
92
|
{
|
|
38
93
|
label: "Logs",
|
|
39
94
|
icon: <IconLogs />,
|
|
@@ -47,7 +102,12 @@ export const DevLayout = () => {
|
|
|
47
102
|
{
|
|
48
103
|
position: "left",
|
|
49
104
|
element: (
|
|
50
|
-
<ActionButton
|
|
105
|
+
<ActionButton
|
|
106
|
+
intent={"none"}
|
|
107
|
+
icon={IconTools}
|
|
108
|
+
href={"/"}
|
|
109
|
+
active={false}
|
|
110
|
+
>
|
|
51
111
|
Devtools
|
|
52
112
|
</ActionButton>
|
|
53
113
|
),
|
|
@@ -64,11 +124,12 @@ export const DevLayout = () => {
|
|
|
64
124
|
}}
|
|
65
125
|
>
|
|
66
126
|
<Flex
|
|
127
|
+
className={"overflow-auto"}
|
|
67
128
|
w={"100%"}
|
|
68
129
|
flex={1}
|
|
130
|
+
direction={"column"}
|
|
69
131
|
bd={`1px solid ${ui.colors.border}`}
|
|
70
132
|
bg={ui.colors.elevated}
|
|
71
|
-
p={"xl"}
|
|
72
133
|
ml={-16}
|
|
73
134
|
mr={-16}
|
|
74
135
|
mt={-16}
|