Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions ui/consumer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ is to give operators visibility into what's already running:
- **Workload detail** (`workloads/:workloadName`) — Overview tab only: stat
tiles, configuration, and an embedded running-instances table.
- **Instance detail** (`workloads/:workloadName/instances/:instanceName`) —
Overview tab only: stat tiles (uptime, region, instance type, image),
network card, health conditions, runtime config.

No deploy/edit/delete forms, and no Activity/Metrics/Settings tabs in v1 —
those stay out of scope until there's a real telemetry/activity source to back
them. `CliBanner`/`SectionCard` (in `src/components/cli-section.tsx`) point
users at the equivalent `datumctl` commands wherever the portal can't do
Overview, Metrics, and Logs. Overview shows live CPU/memory KPIs (and ALB
request/p99/error KPIs when the workload is published on a URL). The Logs
tab is ALB access logs via the o11y Loki API when an HTTPProxy exists;
otherwise it stays empty. Manage/Activity remain placeholders.

No deploy/edit/delete forms. Activity stays out of scope until there is a
real activity source. `CliBanner`/`SectionCard` (in `src/components/cli-section.tsx`)
point users at the equivalent `datumctl` commands wherever the portal can't do
something itself.

## Relationship to cloud-portal PR #1315
Expand Down Expand Up @@ -128,10 +129,13 @@ server you want running:
`workloads/:workloadName` (`WorkloadDetail`), and
`workloads/:workloadName/instances/:instanceName/*` (`InstanceDetail`
layout). The instance layout owns breadcrumbs / title / tabs and nests
Overview (index) plus Logs (`…/logs`) through `<Outlet />`. Instance pages
gate on `{compute.datumapis.com, instances, get}`. Overview embeds a
last-30-minutes `Logs.Table`; the Logs tab mounts the full explorer.
Entries stay empty until a Loki query is wired.
Overview (index), Metrics (`…/metrics`), and Logs (`…/logs`) through
`<Outlet />`. Instance pages gate on `{compute.datumapis.com, instances, get}`.
Overview embeds a last-30-minutes `Logs.Table` and live metric KPIs. The
Logs tab mounts the full explorer against ALB access logs when the workload
has a published HTTPProxy. Metrics query the portal `POST /api/prometheus`
VictoriaMetrics path for `datum_compute_instance_*` CPU/memory (and Envoy
ALB series when published).

Three things stay in lockstep, same as the sample plugin:

Expand All @@ -154,7 +158,10 @@ ui/consumer/
vite.config.ts MF container "workload.compute.datumapis.com"
public/plugin-manifest.json
src/
lib/api.ts fetch wrappers + useQuery hooks (workloads/instances)
lib/api.ts fetch wrappers + useQuery hooks (workloads/instances/HTTPProxy)
lib/prometheus.ts POST /api/prometheus helpers
lib/o11y-logs.ts Loki query_range + ALB LogQL
lib/metrics-queries.ts PromQL builders + instance identity discovery
lib/format.ts formatUptime / splitSlashValue (ported as-is)
schema.ts Zod schemas for Workload / Instance
adapter.ts raw K8s JSON → schema mappers
Expand All @@ -163,5 +170,8 @@ ui/consumer/
pages/workload-list.tsx
pages/workload-detail.tsx
pages/instance-detail.tsx
pages/instance-overview.tsx
pages/instance-logs.tsx
pages/instance-metrics.tsx
main.tsx standalone preview harness only
```
81 changes: 79 additions & 2 deletions ui/consumer/bun.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion ui/consumer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@datum-cloud/datum-ui": "^2.5.0",
"@datum-cloud/datum-ui": "^2.9.1",
"@tanstack/react-query": "5.101.4",
"@tanstack/react-virtual": "^3",
"date-fns": "^4.1.0",
Expand All @@ -22,6 +22,7 @@
"react-day-picker": "^10",
"react-dom": "19.3.0",
"react-router": "8.3.1",
"recharts": "^3.10.1",
"sonner": "^2.0.7",
"zod": "^4.4.3"
},
Expand Down
2,774 changes: 0 additions & 2,774 deletions ui/consumer/src/assets/world-map-dots.svg

This file was deleted.

28 changes: 13 additions & 15 deletions ui/consumer/src/components/cli-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* - Icons rendered via `@datum-cloud/datum-ui/icons` `Icon` wrapper.
*/
import { useCopyToClipboard } from '@datum-cloud/datum-ui/hooks';
import { Card, CardContent } from '@datum-cloud/datum-ui/card';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@datum-cloud/datum-ui/card';
import { Icon } from '@datum-cloud/datum-ui/icons';
import { toast } from '@datum-cloud/datum-ui/toast';
import { cn } from '@datum-cloud/datum-ui/utils';
Expand Down Expand Up @@ -60,20 +60,18 @@ export function SectionCard({
danger?: boolean;
}) {
return (
<Card className={cn(danger && 'border-red-200 dark:border-red-900')}>
<CardContent className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<span className={cn('shrink-0', danger ? 'text-red-500' : 'text-foreground')}>
{icon}
</span>
<h3 className={cn('font-semibold', danger && 'text-red-500')}>{title}</h3>
</div>
<p className="text-muted-foreground text-sm">{description}</p>
<div className="flex flex-col gap-2">
{commands.map((cmd) => (
<CommandBlock key={cmd} value={cmd} danger={danger} />
))}
</div>
<Card size="sm" sectioned className={cn(danger && 'border-red-200 dark:border-red-900')}>
<CardHeader size="sm" bordered>
<CardTitle className={cn('flex items-center gap-2 text-sm', danger && 'text-red-500')}>
<span className={cn('shrink-0', danger ? 'text-red-500' : 'text-secondary')}>{icon}</span>
{title}
</CardTitle>
<CardDescription>{description}</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-2">
{commands.map((cmd) => (
<CommandBlock key={cmd} value={cmd} danger={danger} />
))}
</CardContent>
</Card>
);
Expand Down
28 changes: 8 additions & 20 deletions ui/consumer/src/components/detail-list.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/**
* Field list matching cloud-portal `app/components/list/list.tsx` exactly
* (same classes as ALB General / Configuration — do not add flex-1 on values).
* Field list matching cloud-portal `app/components/list/list.tsx`: datum-ui
* `CardField` rows so a list inside a `sectioned` Card lines up with
* hand-written fields (50/50 grid, inset dividers).
*/
import { Badge } from '@datum-cloud/datum-ui/badge';
import { CardField, CardFieldLabel, CardFieldValue } from '@datum-cloud/datum-ui/card';
import { cn } from '@datum-cloud/datum-ui/utils';

export interface DetailListItem {
Expand All @@ -28,24 +30,10 @@ export function DetailList({
{items
.filter((item) => !item.hidden)
.map((item, index) => (
<div
key={index}
className={cn(
'border-border flex w-full flex-col gap-2 py-3 not-last:border-b sm:flex-row sm:items-center',
itemClassName,
item.className
)}>
<div
className={cn(
'flex min-w-0 items-center justify-start gap-1.5 text-left text-sm font-semibold sm:min-w-[200px]',
labelClassName
)}>
{item.label}
</div>
<div className="flex min-w-0 max-w-full justify-start overflow-hidden text-left text-sm font-normal wrap-break-word sm:justify-end sm:text-right">
{item.content}
</div>
</div>
<CardField key={index} className={cn(itemClassName, item.className)}>
<CardFieldLabel className={labelClassName}>{item.label}</CardFieldLabel>
<CardFieldValue className="min-w-0 wrap-break-word">{item.content}</CardFieldValue>
</CardField>
))}
</div>
);
Expand Down
Loading
Loading