Skip to content

feat(nodes): 876 show a pgpu card's device profile in the row and the full view - #876

Open
raven-pan wants to merge 3 commits into
developfrom
feat/876-show-pgpu-device-profile
Open

raven-pan wants to merge 3 commits into
developfrom
feat/876-show-pgpu-device-profile

Conversation

@raven-pan

@raven-pan raven-pan commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

What type of PR is this?

/kind feature

What this PR does / why we need it

A pgpu (passthrough) card is scheduled by name: a flavor asks for it with
accel:device_profile=<name>, and Cyborg matches that name to the card. Until
now the UI showed that name nowhere, so an operator had to read it off the
controller before they could write the flavor.

The card now carries the name in both places it can appear:

  • The expanded row shows it under Profiles / ID, with a copy button.
  • The full-view modal's Profiles / ID tab shows it too. The tab used to be
    locked for a pgpu card.

Two bugs found on the way came along:

  • The Profiles / ID and Attached Instances tables sat 32px from their
    border, twice what the design asks for.
  • A failed Edit GPU Type wrote the reason to the console only, so the modal
    looked the same before and after pressing Confirm.

Screenshot placeholders — attach by hand

Full-view modal, pgpu card, Profiles / ID tab

876-pgpu-fullview-profiles

Expanded row, both tables with the corrected padding

876-infotable-expanded-after

Full-view modal, MIG-backed vGPU, unchanged

876-vgpu-fullview-regression

Edit GPU Type modal, confirm step, API error shown

876-edit-gpu-type-error

QA perspective

What changed on screen

Node Details page > GPU Resources table.

Place Before After
Expanded row of a Passthrough card no Profiles / ID section Profiles / ID (1) with an Alias Name column, the device profile name and a copy button
Full-view modal of a Passthrough card Profiles / ID tab locked, opens on Attached Instances tab opens first and holds the same name, one Alias Name column, one row, no copy button
Padding of Profiles / ID and Attached Instances 32px from the border to the first cell 16px, the same as the gap between two cells
Edit GPU Type when the API rejects the change nothing on screen, modal stays open red message with the API text above the step content, modal stays open

A Passthrough card whose device profile is missing keeps the old behaviour: no
section in the row, Profiles / ID tab locked, modal opens on
Attached Instances.

SR-IOV vGPU and MIG-backed vGPU cards keep the tables they had. Only their
padding changes.

Repo dependency

  • cube-cos-api supplies the deviceProfile field on
    GET /nodes/{node}/gpuCards. Without an API build that carries it, the field
    arrives as null and the section stays hidden — that is the expected
    fallback, not a defect.
  • cube-cos-openapi holds the contract. The field is already on develop, so
    this PR moves no submodule.
  • cube-cos-ui (this repo) renders it.

Check list

  1. Open Node Details for a node with a Passthrough GPU attached to an instance.
  2. Expand the Passthrough card's row. Profiles / ID (1) shows, column header
    Alias Name, the device profile name below it.
  3. Click the copy button. The clipboard holds the exact name.
  4. Paste it into
    openstack flavor set --property accel:device_profile=<name>. The flavor
    schedules onto that card.
  5. Click the full-view button on the same row. The modal opens on
    Profiles / ID and shows the same name, one column, one row, no copy button.
  6. Switch to the Attached Instances tab and back. Both tabs stay clickable.
  7. Expand an SR-IOV vGPU card. Its profiles table keeps the VRAM, Counts,
    Alias Name columns.
  8. Expand a MIG-backed vGPU card. Its profiles table keeps the extra
    Remaining column. Open its full view — five columns and pagination, as
    before.
  9. Measure any expanded table: the border to the first cell is 16px, the same
    as the gap between two columns.
  10. A Passthrough card in Idle state stays non-expandable.
  11. Open Edit GPU Type on a card the API will reject — for example a card an
    instance still holds. Press Next, then Confirm. A red message shows the
    API's own text above the confirm table. The modal stays open and Confirm
    stays clickable.
  12. Press Back to edit in that state. The message disappears. Close and
    reopen the modal — no stale message.
  13. Switch the UI language to 中文. Titles and column headers are translated;
    the profile name and the API error text are not.

Developer perspective

The device profile (fb6879e6)

  • GpuDeviceProfile.tsx — new component. It returns null on a falsy
    deviceProfile, so it renders on a pgpu card only. The API reports null for
    every other resource type, and for a pgpu card whose profile does not exist or
    could not be read; it gives no reason for the absence, so a label with no
    value would tell the operator neither what to paste nor why.
  • The block renders through GetInfoTable, the same component GpuDetails.tsx
    uses for the profiles and instances tables, with scrollBehavior="vertical"
    and one row. Title and column header reuse
    nodes.details.profilesIdList.title and
    nodes.details.profilesIdList.aliasName.
  • The section reuses existing keys, so the JSON resources gain none. An earlier
    draft added nodes.details.deviceProfile.title; it is not in this branch.
    If that row reached the translation sheet, delete it there, or the next
    pnpm i18n:sync brings it back.
  • FullViewDeviceProfileTable.tsx — new component. One Alias Name column
    through GetCosBasicTable, no pagination: a pgpu card has exactly one device
    profile.
  • GpuDetailsFullViewModal.tsx — the tab is disabled only when a pgpu card has
    no deviceProfile, not for every pgpu card. The default tab follows the same
    flag, so the modal opens on Profiles / ID whenever that tab has content.

The padding (f9041507)

InfoTable.tsx set border-separate border-spacing-4 on the table and p-4 on
the box around it. border-spacing also applies at the table's outer edge, so
the two stacked: 16 + 16. Dropping the box padding leaves one source of
spacing.

Measured against the design (Figma nodes 130:21557 and 130:21598): border to
first cell 32 -> 16. Column gap, header to first row and title to table were
already 16 / 16 / 8.

The change reaches four call sites, all under NodeGpuResources: the two tables
in an expanded row, the pgpu block, and the confirm step of the Edit GPU
Resource modal.

The error message (5c4ea995)

EditGPUResourceModal.tsx only wrote the failure to the console, and its catch
does not close the modal, so the confirm step stayed on screen with no reason.
It now renders errorState in a CosInlineNotification above the step content.

Inline, not a toast: the surface the action came from is still on screen, and
the operator can press Confirm again. That matches VerifyEmailSenderModal and
the tunings / triggers forms. A toast fits an action whose surface disappears,
such as GpuConsoleLink.

useCosMutationRequest already returns errorState and clearError, so the
modal holds no state of its own. oversee clears the error when the next
request starts; clearError covers Back to edit and closing the modal.

Mocks

src/mocks/gpu.ts already carries deviceProfile on every card from develop.
handlers.ts is unchanged on this branch — register mockListNodeGpuCards
locally to see the cards without a GPU host.

Which issue(s) this PR fixes

Fixes bigstack-oss/cubecos#876

Special notes for your reviewer

  • The PR carries three commits: the device profile, the padding, the error
    message. The last two came out of reviewing the first.
  • The branch was rewritten twice: a commit that carried only local scratch files
    (.claude/settings.json, .playwright-mcp/, two throwaway .mjs probes) is
    gone -- its message claimed an openapi submodule bump it never contained --
    and the rest squashed into the two commits above.
  • pnpm test: 7 files, 121 tests pass.
  • pnpm lint: tsc clean for every package. Prettier flags
    .impeccable/hook.cache.json, a local tool cache outside this branch.
  • One 1px gap is left: the design puts 32px between rows, the UI renders 31,
    because primary-body5 has a 15px line height. Not addressed here.
  • Screenshots must be attached by hand.

Additional documentation


🤖 Generated with Claude Code

@raven-pan
raven-pan requested a review from a team as a code owner September 15, 2026 07:52
@raven-pan
raven-pan marked this pull request as draft September 15, 2026 07:53
@raven-pan
raven-pan force-pushed the feat/876-show-pgpu-device-profile branch 2 times, most recently from ebead5d to 375374f Compare September 16, 2026 07:55
@raven-pan raven-pan changed the title feat(nodes): 876 show a pgpu card's device profile feat(nodes): 876 show a pgpu card's device profile in the row and the full view Sep 16, 2026
raven-pan and others added 2 commits September 16, 2026 15:58
To attach a GPU to a VM the operator names that GPU in the flavor, and the
property depends on the resource type. A vGPU card is named through
`pci_passthrough:alias`, which the profiles table already shows in its Alias
Name column. A pgpu card is named through `accel:device_profile`, and the UI
showed that string nowhere -- the only way to read it was a root shell running
`openstack accelerator device profile list`.

The card now carries the name wherever it shows what it can serve:

- The expanded row shows `Profiles / ID (1)` with an `Alias Name` column and a
  copy button. The string exists to be pasted into a flavor command.
- The full-view modal's `Profiles / ID` tab shows the same name, one column,
  one row, no pagination and no copy button. The tab used to be locked for
  every pgpu card, so the modal dropped the name the row had just shown.

Rendered from the card's `deviceProfile` alone, with no second check on the
resource type. The spec reports null on every type but pgpu, so a check would
only repeat what the value already says.

Nothing renders when the value is null, and the modal's tab stays locked -- on a
pgpu card that means the profile does not exist yet or could not be looked up.
The API gives no reason for the absence and does not mark the card degraded, so
a label with no value would tell the operator neither what to paste nor why it
is missing.

The expanded area was empty for a pgpu card until now: getProfilesByResourceType
returns no profiles for one, so the profiles table never rendered, and a card
with no VM attached showed nothing at all.

Refs bigstack-oss/cubecos#876

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: raven-pan-bigstack <raven.pan@bigstack.co>
The Profiles / ID and Attached Instances tables sat 32px from their border,
twice what the design says. `border-separate` puts `border-spacing` around the
table's outer edge as well as between cells, and the box added `p-4` on top of
it.

Drop the box padding. The spacing now comes from one source, so the gap between
the border and a cell is the same 16px as the gap between two cells.

Measured against the design (Figma nodes 130:21557 and 130:21598):

- Border to first cell: 32 -> 16
- Column gap, header to first row, title to table: already 16 / 16 / 8

The change reaches four call sites, all under NodeGpuResources: the two tables
in an expanded row, the pgpu device profile block, and the confirm step of the
Edit GPU Resource modal.

Refs bigstack-oss/cubecos#876

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: raven-pan-bigstack <raven.pan@bigstack.co>
@raven-pan
raven-pan force-pushed the feat/876-show-pgpu-device-profile branch from 375374f to f904150 Compare September 16, 2026 07:58
A failed resource-type change told the operator nothing. The catch block only
wrote to the console, and the modal stays open on its confirm step, so the
screen looked the same before and after pressing Confirm -- the operator could
not tell whether the request had run.

The modal now renders the API message in a `CosInlineNotification` above the
step content. The error belongs next to the button the operator is about to
press again, which is why this is inline and not a toast: the surface is still
on screen. A toast fits an action whose surface disappears, such as the GPU
console link.

`useCosMutationRequest` already carries `errorState` and `clearError`, so the
modal needs no state of its own. `oversee` clears the error when the next
request starts; `clearError` covers the two other ways the operator leaves the
failed state -- Back to edit, and closing the modal.

Refs bigstack-oss/cubecos#876

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: raven-pan-bigstack <raven.pan@bigstack.co>
@raven-pan raven-pan self-assigned this Sep 16, 2026
@raven-pan
raven-pan marked this pull request as ready for review September 16, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[User Story] Set GPU Resource Type to pGPU UI Implementation

1 participant