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
21 changes: 15 additions & 6 deletions ui/consumer/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Compute Portal Plugin

A read-only operational dashboard for the compute service (`compute.datumapis.com`),
An operational dashboard for the compute service (`compute.datumapis.com`),
shipped as a **Module Federation remote** that the cloud portal loads at
runtime — the [Portal Plugin System](https://github.com/datum-cloud/cloud-portal/blob/main/docs/enhancements/portal-plugin-system.md).
Structural template: [`examples/sample-plugin/`](https://github.com/datum-cloud/cloud-portal/tree/main/examples/sample-plugin)
in the `cloud-portal` repo.

## Scope — v1 is read-only
## Scope — visibility, plus delete

This is a **CLI-first** service: workload creation, deployment, scaling,
restarts, and deletion all happen via `datumctl compute …`. The plugin's job
is to give operators visibility into what's already running:
This is a **CLI-first** service: workload creation, deployment, scaling and
restarts all happen via `datumctl compute …`. The plugin's job is to give
operators visibility into what's already running, and to delete workloads:

Paths below are relative to the plugin mount, `/project/:projectId/services/<slug>`
(the slug is operator-supplied; `workloads` locally). The list page is the
Expand All @@ -29,7 +29,16 @@ mount root so URLs read `…/services/workloads/<workloadName>`, not
tab always queries instance stdout; ALB access logs are merged in when an
HTTPProxy exists. Manage/Activity remain placeholders.

No deploy/edit/delete forms. Activity stays out of scope until there is a
**Delete** is in the workload detail page header.
The confirmation dialog (`src/components/delete-workload-dialog.tsx`) also
offers the workload's Application Load Balancers (HTTPProxy plus the
NetworkService behind it) and Networks as opt-in extras, because deleting the
Workload doesn't remove them. Anything shared with another workload can't be
ticked. Following the portal's RBAC conventions, the delete action is
hidden when a `delete` SelfSubjectAccessReview on `workloads` fails, and
extras the user can't delete are disabled with a tooltip.

No deploy/edit 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.
Expand Down
2 changes: 1 addition & 1 deletion ui/consumer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"version": "0.1.0",
"type": "module",
"description": "Compute service Portal Plugin: read-only workload/instance operational dashboard, a Module Federation remote reading data exclusively through the portal's Milo control-plane proxy. Workload creation stays in datumctl (CLI-first).",
"description": "Compute service Portal Plugin: workload/instance operational dashboard with workload delete, a Module Federation remote reading data exclusively through the portal's Milo control-plane proxy. Workload creation stays in datumctl (CLI-first).",
"scripts": {
"dev": "vite",
"preview": "vite preview",
Expand Down
16 changes: 15 additions & 1 deletion ui/consumer/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface RawObjectMeta {
namespace?: string;
resourceVersion?: string;
creationTimestamp?: string;
deletionTimestamp?: string;
labels?: Record<string, string>;
}

Expand Down Expand Up @@ -88,7 +89,12 @@ interface RawWorkloadPlacementStatus {
export interface RawWorkload {
metadata?: RawObjectMeta;
spec?: {
template?: { spec?: { runtime?: RawRuntime } };
template?: {
spec?: {
runtime?: RawRuntime;
networkInterfaces?: Array<{ network?: { name?: string } }>;
};
};
placements?: RawWorkloadPlacement[];
};
status?: {
Expand Down Expand Up @@ -275,6 +281,12 @@ function toPlacementRegions(
});
}

/** Distinct network names across the template's interfaces, in declaration order. */
function deriveNetworks(interfaces?: Array<{ network?: { name?: string } }>): string[] {
const names = (interfaces ?? []).map((iface) => iface.network?.name).filter(Boolean) as string[];
return [...new Set(names)];
}

export function toWorkload(raw: RawWorkload): Workload {
const conditions = raw.status?.conditions ?? [];
const placements = raw.spec?.placements ?? [];
Expand Down Expand Up @@ -304,6 +316,8 @@ export function toWorkload(raw: RawWorkload): Workload {
locations: workloadLocations(placements, raw.status?.placements ?? []),
resources: deriveResources(runtime),
replicasPerRegion: deriveReplicasPerRegion(placements),
networks: deriveNetworks(raw.spec?.template?.spec?.networkInterfaces),
deleting: !!raw.metadata?.deletionTimestamp,
conditions: conditions.map((c) => ({
type: c.type ?? '',
status: c.status ?? 'Unknown',
Expand Down
Loading
Loading