Files
nomad/ui/app/templates/storage/plugins/plugin/index.hbs
Phil Renaud 1976202cd6 Feature: Dynamic Host Volumes in the UI (#25224)
* DHV UI init

* /csi routes to /storage routes and a routeRedirector util (#25163)

* /csi routes to /storage routes and a routeRedirector util

* Tests and routes move csi/ to storage/

* Changelog added

* [ui] Storage UI overhaul + Dynamic Host Volumes UI (#25226)

* Storage index page and DHV model properties

* Naive version of a storage overview page

* Experimental fetch of alloc data dirs

* Fetch ephemeral disks and static host volumes as an ember concurrency task and nice table stylings

* Playing nice with section header labels to make eslint happy even though wcag was already cool with it

* inlined the storage type explainers and reordered things, plus tooltips and keynav

* Bones of a dynamic host volume individual page

* Woooo dynamic host volume model, adapter, and serializer with embedded alloc relationships

* Couple test fixes

* async:false relationship for dhv.hasMany('alloc') to prevent a ton of xhr requests

* DHV request type at index routemodel and better serialization

* Pagination and searching and query params oh my

* Test retrofits for csi volumes

* Really fantastic flake gets fixed

* DHV detail page acceptance test and a bunch of mirage hooks

* Seed so that the actions test has a guaranteed task

* removed ephemeral disk and static host volume manual scanning

* CapacityBytes and capabilities table added to DHV detail page

* Debugging actions flyout test

* was becoming clear that faker.seed editing was causing havoc elsewhere so might as well not boil the ocean and just tell this test to do what I want it to

* Post-create job gets taskCount instead of count

* CSI volumes now get /csi route prefix at detail level

* lazyclick method for unused keynav removed

* keyboard nav and table-watcher for DHV added

* Addressed PR comments, changed up capabilities table and id references, etc.

* Capabilities table for DHV and ID in details header

* Testfixes for pluginID and capabilities table on DHV page
2025-03-10 14:46:02 -04:00

194 lines
7.2 KiB
Handlebars

{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}
{{page-title "CSI Plugin " this.model.plainId}}
<PluginSubnav @plugin={{this.model}} />
<section class="section">
<h1 class="title" data-test-title>{{this.model.plainId}}</h1>
<div class="boxed-section is-small">
<div class="boxed-section-body inline-definitions">
<span class="label">Plugin Details</span>
{{#if this.model.controllerRequired}}
<span class="pair" data-test-plugin-controller-health>
<span class="term">Controller Health</span>
{{format-percentage this.model.controllersHealthy total=this.model.controllersExpected}}
({{this.model.controllersHealthy}}/{{this.model.controllersExpected}})
</span>
{{/if}}
<span class="pair" data-test-plugin-node-health>
<span class="term">Node Health</span>
{{format-percentage this.model.nodesHealthy total=this.model.nodesExpected}}
({{this.model.nodesHealthy}}/{{this.model.nodesExpected}})
</span>
<span class="pair" data-test-plugin-provider>
<span class="term">Provider</span>
{{this.model.provider}}
</span>
</div>
</div>
<div class="columns">
{{#if this.model.controllerRequired}}
<div class="column" data-test-plugin-controller-availability>
<div class="boxed-section">
<div class="boxed-section-head is-hollow">Controller Health</div>
<div class="boxed-section-body">
<div class="columns is-centered is-bottom-aligned">
<div class="column is-half">
<GaugeChart
@label="Availability"
@value={{this.model.controllersHealthy}}
@total={{this.model.controllersExpected}} />
</div>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{this.model.controllersHealthy}}</p>
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{this.model.controllersExpected}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
{{/if}}
<div class="column">
<div class="boxed-section" data-test-plugin-node-availability>
<div class="boxed-section-head is-hollow">Node Health</div>
<div class="boxed-section-body">
<div class="columns is-centered is-bottom-aligned {{unless this.model.controllerRequired "is-max-half"}}">
<div class="column is-half">
<GaugeChart
@label="Availability"
@value={{this.model.nodesHealthy}}
@total={{this.model.nodesExpected}} />
</div>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{this.model.nodesHealthy}}</p>
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{this.model.nodesExpected}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{#if this.model.controllerRequired}}
<div class="boxed-section" data-test-controller-allocations>
<div class="boxed-section-head">
Controller Allocations
</div>
<div class="boxed-section-body {{if this.model.controllers "is-full-bleed"}}">
{{#if this.model.controllers}}
<ListTable
@source={{take 10 this.sortedControllers}}
@class="with-foot" as |t|>
<t.head>
<th class="is-narrow"><span class="visually-hidden">Driver Health, Scheduling, and Preemption</span></th>
<td>ID</td>
<th>Created</th>
<th>Modified</th>
<th>Health</th>
<th>Client</th>
<th>Job</th>
<th>Version</th>
<th>Volumes</th>
<th>CPU</th>
<th>Memory</th>
</t.head>
<t.body @key="model.allocID" as |row|>
<PluginAllocationRow
@data-test-controller-allocation={{row.model.allocID}}
@pluginAllocation={{row.model}} />
</t.body>
</ListTable>
{{else}}
<div class="empty-message" data-test-empty-controller-allocations>
<h3 class="empty-message-headline" data-test-empty-controller-allocations-headline>No Controller Plugin Allocations</h3>
<p class="empty-message-body" data-test-empty-controller-allocations-message>No allocations are providing controller plugin service.</p>
</div>
{{/if}}
</div>
{{#if this.model.controllers}}
<div class="boxed-section-foot">
<p class="pull-right">
<LinkTo
@route="storage.plugins.plugin.allocations"
@model={{this.model}}
@query={{hash qpType=(qp-serialize (array "controller"))}}
data-test-go-to-controller-allocations>
View all {{this.model.controllers.length}} Controller {{pluralize "allocation" this.model.controllers.length}}
</LinkTo>
</p>
</div>
{{/if}}
</div>
{{/if}}
<div class="boxed-section">
<div class="boxed-section-head">
Node Allocations
</div>
<div class="boxed-section-body {{if this.model.nodes "is-full-bleed"}}">
{{#if this.model.nodes}}
<ListTable
@source={{take 10 this.sortedNodes}}
@class="with-foot" as |t|>
<t.head>
<th class="is-narrow"><span class="visually-hidden">Driver Health, Scheduling, and Preemption</span></th>
<td>ID</td>
<th>Created</th>
<th>Modified</th>
<th>Health</th>
<th>Client</th>
<th>Job</th>
<th>Version</th>
<th>Volumes</th>
<th>CPU</th>
<th>Memory</th>
</t.head>
<t.body @key="model.allocID" as |row|>
<PluginAllocationRow
@data-test-node-allocation={{row.model.allocID}}
@pluginAllocation={{row.model}} />
</t.body>
</ListTable>
{{else}}
<div class="empty-message" data-test-empty-node-allocations>
<h3 class="empty-message-headline" data-test-empty-node-allocations-headline>No Node Plugin Allocations</h3>
<p class="empty-message-body" data-test-empty-node-allocations-message>No allocations are providing node plugin service.</p>
</div>
{{/if}}
</div>
{{#if this.model.nodes}}
<div class="boxed-section-foot">
<p class="pull-right">
<LinkTo
@route="storage.plugins.plugin.allocations"
@model={{this.model}}
@query={{hash qpType=(qp-serialize (array "node"))}}
data-test-go-to-node-allocations>
View all {{this.model.nodes.length}} Node {{pluralize "allocation" this.model.nodes.length}}
</LinkTo>
</p>
</div>
{{/if}}
</div>
</section>