open-nomad/ui/app/templates/clients/client/index.hbs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

900 lines
28 KiB
Handlebars
Raw Normal View History

{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}
{{page-title "Client " (or this.model.name this.model.shortId)}}
<ClientSubnav @client={{this.model}} />
2020-06-13 03:59:33 +00:00
<section class="section">
{{#if this.eligibilityError}}
2020-06-13 03:59:33 +00:00
<div data-test-eligibility-error class="columns">
<div class="column">
<div class="notification is-danger">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Eligibility Error
</h3>
<p data-test-message>
{{this.eligibilityError}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dismiss
class="button is-danger"
onclick={{action (mut this.eligibilityError) ""}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
{{/if}}
{{#if this.stopDrainError}}
2020-06-13 03:59:33 +00:00
<div data-test-stop-drain-error class="columns">
<div class="column">
<div class="notification is-danger">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Stop Drain Error
</h3>
<p data-test-message>
{{this.stopDrainError}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dismiss
class="button is-danger"
onclick={{action (mut this.stopDrainError) ""}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
{{/if}}
{{#if this.drainError}}
2020-06-13 03:59:33 +00:00
<div data-test-drain-error class="columns">
<div class="column">
<div class="notification is-danger">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Drain Error
</h3>
<p data-test-message>
{{this.drainError}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dismiss
class="button is-danger"
onclick={{action (mut this.drainError) ""}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
{{/if}}
{{#if this.showDrainStoppedNotification}}
2020-06-13 03:59:33 +00:00
<div class="notification is-info">
<div data-test-drain-stopped-notification class="columns">
<div class="column">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Drain Stopped
</h3>
<p data-test-message>
The drain has been stopped and the node has been set to ineligible.
</p>
2020-06-13 03:59:33 +00:00
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dismiss
class="button is-info"
onclick={{action (mut this.showDrainStoppedNotification) false}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
</div>
{{/if}}
{{#if this.showDrainUpdateNotification}}
2020-06-13 03:59:33 +00:00
<div class="notification is-info">
<div data-test-drain-updated-notification class="columns">
<div class="column">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Drain Updated
</h3>
<p data-test-message>
The new drain specification has been applied.
</p>
2020-06-13 03:59:33 +00:00
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dismiss
class="button is-info"
onclick={{action (mut this.showDrainUpdateNotification) false}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
</div>
{{/if}}
{{#if this.showDrainNotification}}
2020-06-13 03:59:33 +00:00
<div class="notification is-info">
<div data-test-drain-complete-notification class="columns">
<div class="column">
2022-01-26 16:28:21 +00:00
<h3 data-test-title class="title is-4">
Drain Complete
</h3>
<p data-test-message>
Allocations have been drained and the node has been set to ineligible.
</p>
2020-06-13 03:59:33 +00:00
</div>
<div class="column is-centered is-minimum">
2022-01-26 16:28:21 +00:00
<button
data-test-dimiss
class="button is-info"
onclick={{action (mut this.showDrainNotification) false}}
type="button"
>
Okay
</button>
2020-06-13 03:59:33 +00:00
</div>
</div>
</div>
{{/if}}
<div class="toolbar">
<div class="toolbar-item is-top-aligned is-minimum">
<span class="title">
2022-01-26 16:28:21 +00:00
<span
data-test-node-status="{{this.model.compositeStatus}}"
class="node-status-light {{this.model.compositeStatus}}"
>
{{x-icon this.model.compositeStatusIcon}}
2020-06-13 03:59:33 +00:00
</span>
</span>
</div>
<div class="toolbar-item">
<h1 data-test-title class="title with-subheading">
{{or this.model.name this.model.shortId}}
2020-06-13 03:59:33 +00:00
</h1>
<p>
<label class="is-interactive">
<Toggle
2020-06-13 03:59:33 +00:00
data-test-eligibility-toggle
@isActive={{this.model.isEligible}}
2022-01-26 16:28:21 +00:00
@isDisabled={{or
this.setEligibility.isRunning
this.model.isDraining
(cannot "write client")
}}
@onToggle={{perform this.setEligibility (not this.model.isEligible)
}}
>
2020-06-13 03:59:33 +00:00
Eligible
</Toggle>
2022-01-26 16:28:21 +00:00
<span
class="tooltip"
aria-label="Only eligible clients can receive allocations"
>
2020-06-13 03:59:33 +00:00
{{x-icon "info-circle-outline" class="is-faded"}}
</span>
</label>
2022-01-26 16:28:21 +00:00
<span
data-test-node-id
class="tag is-hollow is-small no-text-transform"
>
{{this.model.id}}
<CopyButton @clipboardText={{this.model.id}} />
2020-06-13 03:59:33 +00:00
</span>
</p>
</div>
<div class="toolbar-item is-right-aligned is-top-aligned">
{{#if this.model.isDraining}}
2020-06-13 03:59:33 +00:00
<TwoStepButton
data-test-drain-stop
@idleText="Stop Drain"
@cancelText="Cancel"
2022-03-24 20:38:43 +00:00
@confirmText="Yes, Stop Drain"
2020-06-13 03:59:33 +00:00
@confirmationMessage="Are you sure you want to stop this drain?"
@awaitingConfirmation={{this.stopDrain.isRunning}}
2022-01-26 16:28:21 +00:00
@onConfirm={{perform this.stopDrain}}
/>
2020-06-13 03:59:33 +00:00
{{/if}}
</div>
<div class="toolbar-item is-right-aligned is-top-aligned">
<DrainPopover
@client={{this.model}}
2020-06-13 03:59:33 +00:00
@isDisabled={{cannot "write client"}}
@onDrain={{action "drainNotify"}}
2022-01-26 16:28:21 +00:00
@onError={{action "setDrainError"}}
/>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="boxed-section is-small">
<div class="boxed-section-body inline-definitions">
2022-01-26 16:28:21 +00:00
<span class="label">
Client Details
</span>
2020-06-13 03:59:33 +00:00
<span class="pair" data-test-status-definition>
2022-01-26 16:28:21 +00:00
<span class="term">
Status
</span>
<span class="status-text node-{{this.model.status}}">
{{this.model.status}}
</span>
2020-06-13 03:59:33 +00:00
</span>
<span class="pair" data-test-address-definition>
2022-01-26 16:28:21 +00:00
<span class="term">
Address
</span>
{{this.model.httpAddr}}
2020-06-13 03:59:33 +00:00
</span>
<span class="pair" data-test-datacenter-definition>
2022-01-26 16:28:21 +00:00
<span class="term">
Datacenter
</span>
{{this.model.datacenter}}
2020-06-13 03:59:33 +00:00
</span>
2020-10-23 20:50:47 +00:00
{{#if this.model.nodeClass}}
<span class="pair" data-test-node-class>
2022-01-26 16:28:21 +00:00
<span class="term">
Class
</span>
2020-10-23 20:50:47 +00:00
{{this.model.nodeClass}}
</span>
{{/if}}
2020-06-13 03:59:33 +00:00
<span class="pair" data-test-driver-health>
2022-01-26 16:28:21 +00:00
<span class="term">
Drivers
</span>
{{#if this.model.unhealthyDrivers.length}}
{{x-icon "alert-triangle" class="is-text is-warning"}}
2022-01-26 16:28:21 +00:00
{{this.model.unhealthyDrivers.length}}
of
{{this.model.detectedDrivers.length}}
{{pluralize "driver" this.model.detectedDrivers.length}}
unhealthy
2020-06-13 03:59:33 +00:00
{{else}}
All healthy
{{/if}}
</span>
</div>
</div>
{{#if this.model.drainStrategy}}
2020-06-13 03:59:33 +00:00
<div data-test-drain-details class="boxed-section is-info">
<div class="boxed-section-head">
2022-01-26 16:28:21 +00:00
<div class="boxed-section-row">
Drain Strategy
</div>
2020-06-13 03:59:33 +00:00
<div class="boxed-section-row">
<div class="inline-definitions is-small">
{{#unless this.model.drainStrategy.hasNoDeadline}}
2020-06-13 03:59:33 +00:00
<span class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
Duration
</span>
{{#if this.model.drainStrategy.isForced}}
2022-01-26 16:28:21 +00:00
<span data-test-duration>
--
</span>
2020-06-13 03:59:33 +00:00
{{else}}
2022-01-26 16:28:21 +00:00
<span
data-test-duration
class="tooltip"
aria-label={{format-duration
this.model.drainStrategy.deadline
}}
>
{{format-duration this.model.drainStrategy.deadline}}
2020-06-13 03:59:33 +00:00
</span>
{{/if}}
</span>
{{/unless}}
2020-06-13 03:59:33 +00:00
<span class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
{{if
this.model.drainStrategy.hasNoDeadline
"Deadline"
"Remaining"
}}
</span>
{{#if this.model.drainStrategy.hasNoDeadline}}
2022-01-26 16:28:21 +00:00
<span data-test-deadline>
No deadline
</span>
{{else if this.model.drainStrategy.isForced}}
2022-01-26 16:28:21 +00:00
<span data-test-deadline>
--
</span>
2020-06-13 03:59:33 +00:00
{{else}}
2022-01-26 16:28:21 +00:00
<span
data-test-deadline
class="tooltip"
aria-label={{format-ts this.model.drainStrategy.forceDeadline
}}
>
{{moment-from-now
this.model.drainStrategy.forceDeadline
interval=1000
hideAffix=true
}}
2020-06-13 03:59:33 +00:00
</span>
{{/if}}
</span>
<span data-test-force-drain-text class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
Force Drain
</span>
{{#if this.model.drainStrategy.isForced}}
2022-01-26 16:28:21 +00:00
{{x-icon "alert-triangle" class="is-text is-warning"}}Yes
2020-06-13 03:59:33 +00:00
{{else}}
No
{{/if}}
</span>
<span data-test-drain-system-jobs-text class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
Drain System Jobs
</span>
{{if this.model.drainStrategy.ignoreSystemJobs "No" "Yes"}}
2020-06-13 03:59:33 +00:00
</span>
</div>
{{#unless this.model.drainStrategy.isForced}}
2020-06-13 03:59:33 +00:00
<div class="pull-right">
<TwoStepButton
data-test-force
@alignRight={{true}}
@classes={{hash
idleButton="is-warning"
confirmationMessage="inherit-color"
cancelButton="is-danger is-important"
2022-01-26 16:28:21 +00:00
confirmButton="is-warning"
}}
2020-06-13 03:59:33 +00:00
@idleText="Force Drain"
@cancelText="Cancel"
@confirmText="Yes, Force Drain"
@confirmationMessage="Are you sure you want to force drain?"
@awaitingConfirmation={{this.forceDrain.isRunning}}
2022-01-26 16:28:21 +00:00
@onConfirm={{perform this.forceDrain}}
/>
2020-06-13 03:59:33 +00:00
</div>
{{/unless}}
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="boxed-section-body">
<div class="columns">
<div class="column nowrap is-minimum">
<div class="metric-group">
<div class="metric is-primary">
2022-01-26 16:28:21 +00:00
<h3 class="label">
Complete
</h3>
<p data-test-complete-count class="value">
{{this.model.completeAllocations.length}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="metric-group">
<div class="metric">
2022-01-26 16:28:21 +00:00
<h3 class="label">
Migrating
</h3>
<p data-test-migrating-count class="value">
{{this.model.migratingAllocations.length}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
<div class="metric-group">
<div class="metric">
2022-01-26 16:28:21 +00:00
<h3 class="label">
Remaining
</h3>
<p data-test-remaining-count class="value">
{{this.model.runningAllocations.length}}
</p>
2020-06-13 03:59:33 +00:00
</div>
</div>
</div>
<div class="column">
2022-01-26 16:28:21 +00:00
<h3 class="title is-4">
Status
</h3>
{{#if this.model.lastMigrateTime}}
2022-01-26 16:28:21 +00:00
<p data-test-status>
{{moment-to-now
this.model.lastMigrateTime
interval=1000
hideAffix=true
}}
since an allocation was successfully migrated.
</p>
2020-06-13 03:59:33 +00:00
{{else}}
2022-01-26 16:28:21 +00:00
<p data-test-status>
No allocations migrated.
</p>
2020-06-13 03:59:33 +00:00
{{/if}}
</div>
</div>
</div>
</div>
{{/if}}
<div class="boxed-section">
<div class="boxed-section-head is-hollow">
Host Resource Utilization
2022-01-26 16:28:21 +00:00
<span
class="tooltip multiline pad-left"
aria-label="All allocation and system processes aggregated"
>
{{x-icon "info-circle-outline" class="is-faded"}}
</span>
2020-06-13 03:59:33 +00:00
</div>
<div class="boxed-section-body">
<div class="columns">
<div class="column">
<PrimaryMetric::Node @node={{this.model}} @metric="cpu" />
2020-06-13 03:59:33 +00:00
</div>
<div class="column">
<PrimaryMetric::Node @node={{this.model}} @metric="memory" />
2020-06-13 03:59:33 +00:00
</div>
</div>
</div>
</div>
<div class="boxed-section">
<div class="boxed-section-head">
<div>
Allocations
2022-01-26 16:28:21 +00:00
<button
role="button"
class="badge is-white"
onclick={{action "setPreemptionFilter" false}}
data-test-filter-all
type="button"
>
{{this.model.allocations.length}}
2020-06-13 03:59:33 +00:00
</button>
{{#if this.preemptions.length}}
2022-01-26 16:28:21 +00:00
<button
role="button"
class="badge is-warning"
onclick={{action "setPreemptionFilter" true}}
data-test-filter-preemptions
type="button"
>
{{this.preemptions.length}}
{{pluralize "preemption" this.preemptions.length}}
2020-06-13 03:59:33 +00:00
</button>
{{/if}}
</div>
<div class="pull-right is-subsection">
<MultiSelectDropdown
data-test-allocation-namespace-facet
@label="Namespace"
@options={{this.optionsNamespace}}
@selection={{this.selectionNamespace}}
@onSelect={{action this.setFacetQueryParam "qpNamespace"}}
/>
<MultiSelectDropdown
data-test-allocation-job-facet
@label="Job"
@options={{this.optionsJob}}
@selection={{this.selectionJob}}
@onSelect={{action this.setFacetQueryParam "qpJob"}}
/>
<MultiSelectDropdown
data-test-allocation-status-facet
@label="Status"
@options={{this.optionsAllocationStatus}}
@selection={{this.selectionStatus}}
@onSelect={{action this.setFacetQueryParam "qpStatus"}}
/>
<SearchBox
@searchTerm={{mut this.searchTerm}}
@onChange={{action this.resetPagination}}
@placeholder="Search allocations..."
@inputClass="is-compact"
@class="is-padded"
/>
<span class="is-padded is-one-line">
<Toggle
@isActive={{this.showSubTasks}}
@onToggle={{this.toggleShowSubTasks}}
title="Show tasks of allocations"
>
Show Tasks
</Toggle>
</span>
</div>
2020-06-13 03:59:33 +00:00
</div>
2022-01-26 16:28:21 +00:00
<div
class="boxed-section-body
{{if this.sortedAllocations.length "is-full-bleed"}}"
>
{{#if this.sortedAllocations.length}}
<ListPagination
@source={{this.sortedAllocations}}
@size={{this.pageSize}}
2022-01-26 16:28:21 +00:00
@page={{this.currentPage}} as |p|
>
<ListTable
@source={{p.list}}
@sortProperty={{this.sortProperty}}
@sortDescending={{this.sortDescending}}
@class="with-foot {{if this.showSubTasks "with-collapsed-borders"}}" as |t|
2022-01-26 16:28:21 +00:00
>
<t.head>
<th class="is-narrow"></th>
2022-01-26 16:28:21 +00:00
<t.sort-by @prop="shortId">
ID
</t.sort-by>
<t.sort-by @prop="createIndex" @title="Create Index">
Created
</t.sort-by>
<t.sort-by @prop="modifyIndex" @title="Modify Index">
Modified
</t.sort-by>
<t.sort-by @prop="statusIndex">
Status
</t.sort-by>
<t.sort-by @prop="job.name">
Job
</t.sort-by>
<t.sort-by @prop="jobVersion">
Version
</t.sort-by>
<th>
Volume
</th>
<th>
CPU
</th>
<th>
Memory
</th>
</t.head>
<t.body as |row|>
<AllocationRow
[ui] general keyboard navigation: 1.3.4 release (#14138) * Initialized keyboard service Neat but funky: dynamic subnav traversal 👻 generalized traverseSubnav method Shift as special modifier key Nice little demo panel Keyboard shortcuts keycard Some animation styles on keyboard shortcuts Handle situations where a link is deeply nested from its parent menu item Keyboard service cleanup helper-based initializer and teardown for new contextual commands Keyboard shortcuts modal component added and demo-ghost removed Removed j and k from subnav traversal Register and unregister methods for subnav plus new subnavs for volumes and volume register main nav method Generalizing the register nav method 12762 table keynav (#12975) * Experimental feature: shortcut visual hints * Long way around to a custom modifier for keyboard shortcuts * dynamic table and list iterative shortcuts * Progress with regular old tether * Delogging * Table Keynav tether fix, server and client navs, and fix to shiftless on modified arrow keys Go to Optimize keyboard link and storage key changed to g r parameterized jobs keyboard nav Dynamic numeric keynav for multiple tables (#13482) * Multiple tables init * URL-bind enumerable keyboard commands and add to more taskRow and allocationRows * Type safety and lint fixes * Consolidated push to keyCommands * Default value when removing keyCommands * Remove the URL-based removal method and perform a recompute on any add Get tests passing in Keynav: remove math helpers and a few other defensive moves (#13761) * Remove ember math helpers * Test fixes for jobparts/body * Kill an unneeded integration helper test * delog * Trying if disabling percy lets this finish * Okay so its not percy; try parallelism in circle * Percyless yet again * Trying a different angle to not have percy * Upgrade percy to 1.6.1 [ui] Keyboard nav: "u" key to go up a level (#13754) * U to go up a level * Mislabelled my conditional * Custom lint ignore rule * Custom lint ignore rule, this time with commas * Since we're getting rid of ember math helpers elsewhere, do the math ourselves here Replace ArrowLeft etc. with an ascii arrow (#13776) * Replace ArrowLeft etc. with an ascii arrow * non-mutative helper cleanup Keyboard Nav: let users rebind their shortcuts (#13781) * click-outside and shortcuts enabled/disabled toggle * Trap focus when modal open * Enabled/disabled saved to localStorage * Autofocus edit button on variable index * Modal overflow styles * Functional rebind * Saving rebinds to localStorage for all majors * Started on defaultCommandBindings * Modal header style and cancel rebind on escape * keyboardable keybindings w buttons instead of spans * recording and defaultvalues * Enter short-circuits rebind * Only some commands are rebindable, and dont show dupes * No unused get import * More visually distinct header on modal * Disallowed keys for rebind, showing buffer as you type, and moving dedupe to modal logic willDestroy hook to prevent tests from doubling/tripling up addEventListener on kb events remove unused tests Keyboard Navigation acceptance tests (#13893) * Acceptance tests for keyboard modal * a11y audit fix and localStorage clear * Bind/rebind/localStorage tests * Keyboard tests for dynamic nav and tables * Rebinder and assert expectation * Second percy snapshot showing hints no longer relevant Weird issue where linktos with query props specifically from the task-groups page would fail to route / hit undefined.shouldSuperCede errors Adds the concept of exclusivity to a keycommand, removing peers that also share its label Lintfix Changelog and PR feedback Changelog and PR feedback Fix to rebinding in firefox by blurring the now-disabled button on rebind (#14053) * Secure Variables shortcuts removed * Variable index route autofocus removed * Updated changelog entry * Updated changelog entry * Keynav docs (#14148) * Section added to the API Docs UI page * Added a note about disabling * Prev and Next order * Remove dev log and unneeded comments
2022-08-17 16:59:33 +00:00
{{keyboard-shortcut
enumerated=true
action=(action "gotoAllocation" row.model)
}}
@allocation={{row.model}}
@context="node"
@onClick={{action "gotoAllocation" row.model}}
2022-01-26 16:28:21 +00:00
@data-test-allocation={{row.model.id}}
/>
{{#if this.showSubTasks}}
{{#each row.model.states as |task|}}
<TaskSubRow @namespan="8" @taskState={{task}} @active={{eq this.activeTask (concat task.allocation.id "-" task.name)}} @onSetActiveTask={{action 'setActiveTaskQueryParam'}} />
{{/each}}
{{/if}}
</t.body>
</ListTable>
<div class="table-foot">
<nav class="pagination">
<div class="pagination-numbers">
2022-01-26 16:28:21 +00:00
{{p.startsAt}}
{{p.endsAt}}
of
{{this.sortedAllocations.length}}
</div>
2022-01-26 16:28:21 +00:00
<p.prev @class="pagination-previous">
2022-11-28 17:26:18 +00:00
&lt;
2022-01-26 16:28:21 +00:00
</p.prev>
<p.next @class="pagination-next">
>
</p.next>
<ul class="pagination-list"></ul>
</nav>
</div>
</ListPagination>
{{else}}
<div data-test-empty-allocations-list class="empty-message">
{{#if (eq this.visibleAllocations.length 0)}}
2022-01-26 16:28:21 +00:00
<h3
data-test-empty-allocations-list-headline
class="empty-message-headline"
>
No Allocations
</h3>
<p data-test-empty-allocations-list-body class="empty-message-body">
The node doesn't have any allocations.
</p>
{{else if this.searchTerm}}
2022-01-26 16:28:21 +00:00
<h3
data-test-empty-allocations-list-headline
class="empty-message-headline"
>
No Matches
</h3>
<p class="empty-message-body">
No allocations match the term
<strong>
{{this.searchTerm}}
</strong>
</p>
{{else if (eq this.sortedAllocations.length 0)}}
2022-01-26 16:28:21 +00:00
<h3
data-test-empty-allocations-list-headline
class="empty-message-headline"
>
No Matches
</h3>
<p class="empty-message-body">
No allocations match your current filter selection.
</p>
{{/if}}
2020-06-13 03:59:33 +00:00
</div>
{{/if}}
2020-06-13 03:59:33 +00:00
</div>
</div>
<div data-test-client-events class="boxed-section">
<div class="boxed-section-head">
Client Events
</div>
<div class="boxed-section-body is-full-bleed">
<ListTable @source={{this.sortedEvents}} @class="is-striped" as |t|>
2020-06-13 03:59:33 +00:00
<t.head>
2022-01-26 16:28:21 +00:00
<th class="is-2">
Time
</th>
<th class="is-2">
Subsystem
</th>
<th>
Message
</th>
2020-06-13 03:59:33 +00:00
</t.head>
<t.body as |row|>
<tr data-test-client-event>
2022-01-26 16:28:21 +00:00
<td data-test-client-event-time>
{{format-ts row.model.time}}
</td>
<td data-test-client-event-subsystem>
{{row.model.subsystem}}
</td>
2020-06-13 03:59:33 +00:00
<td data-test-client-event-message>
{{#if row.model.message}}
{{#if row.model.driver}}
2022-01-26 16:28:21 +00:00
<span class="badge is-secondary is-small">
{{row.model.driver}}
</span>
2020-06-13 03:59:33 +00:00
{{/if}}
{{row.model.message}}
{{else}}
2022-01-26 16:28:21 +00:00
<em>
No message
</em>
2020-06-13 03:59:33 +00:00
{{/if}}
</td>
</tr>
</t.body>
</ListTable>
</div>
</div>
{{#if this.sortedHostVolumes.length}}
2020-06-13 03:59:33 +00:00
<div data-test-client-host-volumes class="boxed-section">
<div class="boxed-section-head">
Host Volumes
</div>
<div class="boxed-section-body is-full-bleed">
2022-01-26 16:28:21 +00:00
<ListTable
@source={{this.sortedHostVolumes}}
@class="is-striped" as |t|
>
2020-06-13 03:59:33 +00:00
<t.head>
2022-01-26 16:28:21 +00:00
<th>
Name
</th>
<th>
Source
</th>
<th>
Permissions
</th>
2020-06-13 03:59:33 +00:00
</t.head>
<t.body as |row|>
<tr data-test-client-host-volume>
2022-01-26 16:28:21 +00:00
<td data-test-name>
{{row.model.name}}
</td>
<td data-test-path>
<code>
{{row.model.path}}
</code>
</td>
<td data-test-permissions>
{{if row.model.readOnly "Read" "Read/Write"}}
</td>
2020-06-13 03:59:33 +00:00
</tr>
</t.body>
</ListTable>
</div>
</div>
{{/if}}
<div data-test-driver-status class="boxed-section">
<div class="boxed-section-head">
Driver Status
</div>
<div class="boxed-section-body">
<ListAccordion @source={{this.sortedDrivers}} @key="name" as |a|>
2022-01-26 16:28:21 +00:00
<a.head
@buttonLabel="details"
@buttonType={{"client-detail"}}
@isExpandable={{a.item.detected}}
>
<div
class="columns inline-definitions
{{unless a.item.detected "is-faded"}}"
>
2020-06-13 03:59:33 +00:00
<div class="column is-1">
2022-01-26 16:28:21 +00:00
<span data-test-name>
{{a.item.name}}
</span>
2020-06-13 03:59:33 +00:00
</div>
<div class="column is-2">
{{#if a.item.detected}}
<span data-test-health>
<span class="color-swatch {{a.item.healthClass}}"></span>
{{if a.item.healthy "Healthy" "Unhealthy"}}
</span>
{{/if}}
</div>
<div class="column">
<span class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
Detected
</span>
<span data-test-detected>
{{if a.item.detected "Yes" "No"}}
</span>
2020-06-13 03:59:33 +00:00
</span>
<span class="is-pulled-right">
<span class="pair">
2022-01-26 16:28:21 +00:00
<span class="term">
Last Updated
</span>
<span
data-test-last-updated
class="tooltip"
aria-label="{{format-ts a.item.updateTime}}"
>
2020-06-13 03:59:33 +00:00
{{moment-from-now a.item.updateTime interval=1000}}
</span>
</span>
</span>
</div>
</div>
</a.head>
<a.body>
2022-01-26 16:28:21 +00:00
<p data-test-health-description class="message">
{{a.item.healthDescription}}
</p>
2020-06-13 03:59:33 +00:00
<div data-test-driver-attributes class="boxed-section">
<div class="boxed-section-head">
2022-01-26 16:28:21 +00:00
{{capitalize a.item.name}}
Attributes
2020-06-13 03:59:33 +00:00
</div>
2021-10-12 20:36:10 +00:00
{{#if a.item.attributes.structured}}
2020-06-13 03:59:33 +00:00
<div class="boxed-section-body is-full-bleed">
<AttributesTable
@attributePairs={{a.item.attributesShort}}
2022-01-26 16:28:21 +00:00
@class="attributes-table"
/>
2020-06-13 03:59:33 +00:00
</div>
{{else}}
<div class="boxed-section-body">
<div class="empty-message">
2022-01-26 16:28:21 +00:00
<h3 class="empty-message-headline">
No Driver Attributes
</h3>
2020-06-13 03:59:33 +00:00
</div>
</div>
{{/if}}
</div>
</a.body>
</ListAccordion>
</div>
</div>
<div class="boxed-section">
<div class="boxed-section-head">
Attributes
</div>
<div class="boxed-section-body is-full-bleed">
<AttributesTable
data-test-attributes
2021-10-12 20:36:10 +00:00
@attributePairs={{this.model.attributes.structured}}
2022-01-26 16:28:21 +00:00
@class="attributes-table"
@copyable={{true}}
2022-01-26 16:28:21 +00:00
/>
2020-06-13 03:59:33 +00:00
</div>
2022-01-26 16:28:21 +00:00
</div>
<div class="boxed-section">
<div class="boxed-section-head">
Meta
2020-06-13 03:59:33 +00:00
</div>
{{#if this.hasMeta}}
2022-01-26 16:28:21 +00:00
<div class="boxed-section-body is-full-bleed">
<AttributesTable
data-test-meta
@attributePairs={{this.model.meta.structured}}
@editable={{can "write client"}}
@onKVSave={{this.addDynamicMetaData}}
@onKVEdit={{this.validateMetadata}}
2022-01-26 16:28:21 +00:00
@class="attributes-table"
/>
2020-06-13 03:59:33 +00:00
</div>
2022-01-26 16:28:21 +00:00
{{else}}
<div class="boxed-section-body">
<div data-test-empty-meta-message class="empty-message">
<h3 class="empty-message-headline">
No Meta Attributes
</h3>
<p class="empty-message-body">
This client is configured with no meta attributes.
</p>
2021-11-05 16:55:54 +00:00
</div>
2022-01-26 16:28:21 +00:00
</div>
{{/if}}
{{#if (can "write client")}}
{{#if this.editingMetadata}}
<div class="add-dynamic-metadata">
<h3 class="title is-6">Add Dynamic Metadata</h3>
<MetadataEditor
@kv={{this.newMetaData}}
@onEdit={{this.validateMetadata}}
>
<button
data-test-new-metadata-button
disabled={{or (not this.newMetaData.key) (not this.newMetaData.value)}}
type="submit"
class="button is-primary"
{{on "click" (queue
(action this.addDynamicMetaData this.newMetaData)
this.resetNewMetaData
(action (mut this.editingMetadata) false)
)}}
>
Add {{this.newMetaData.key}} to node metadata
</button>
<button
type="button"
class="button is-secondary"
{{on "click" (queue
this.resetNewMetaData
(action (mut this.editingMetadata) false)
)}}
>
Cancel
</button>
</MetadataEditor>
</div>
{{else}}
<div class="add-dynamic-metadata">
<button
type="button"
class="button is-primary"
{{on "click" (action (mut this.editingMetadata) true)}}
{{keyboard-shortcut
label="Add Dynamic Node Metadata"
pattern=(array "m" "e" "t" "a")
action=(action (mut this.editingMetadata) true)
}}
>
Add new Dynamic Metadata
</button>
</div>
{{/if}}
{{/if}}
2020-06-13 03:59:33 +00:00
</div>
2022-01-26 16:28:21 +00:00
</section>