mirror of
https://github.com/kemko/nomad.git
synced 2026-01-04 17:35:43 +03:00
ui: display empty message in the client details page if there are no allocations to show
This commit is contained in:
@@ -61,19 +61,16 @@ export default class ClientController extends Controller.extend(Sortable, Search
|
||||
|
||||
onlyPreemptions = false;
|
||||
|
||||
@computed(
|
||||
'model.allocations.[]',
|
||||
'preemptions.[]',
|
||||
'onlyPreemptions',
|
||||
'selectionNamespace',
|
||||
'selectionJob',
|
||||
'selectionStatus'
|
||||
)
|
||||
@computed('model.allocations.[]', 'preemptions.[]', 'onlyPreemptions')
|
||||
get visibleAllocations() {
|
||||
const allocations = this.onlyPreemptions ? this.preemptions : this.model.allocations;
|
||||
return this.onlyPreemptions ? this.preemptions : this.model.allocations;
|
||||
}
|
||||
|
||||
@computed('visibleAllocations.[]', 'selectionNamespace', 'selectionJob', 'selectionStatus')
|
||||
get filteredAllocations() {
|
||||
const { selectionNamespace, selectionJob, selectionStatus } = this;
|
||||
|
||||
return allocations.filter(alloc => {
|
||||
return this.visibleAllocations.filter(alloc => {
|
||||
if (selectionNamespace.length && !selectionNamespace.includes(alloc.get('namespace'))) {
|
||||
return false;
|
||||
}
|
||||
@@ -87,7 +84,7 @@ export default class ClientController extends Controller.extend(Sortable, Search
|
||||
});
|
||||
}
|
||||
|
||||
@alias('visibleAllocations') listToSort;
|
||||
@alias('filteredAllocations') listToSort;
|
||||
@alias('listSorted') listToSearch;
|
||||
@alias('listSearched') sortedAllocations;
|
||||
|
||||
|
||||
@@ -325,47 +325,66 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxed-section-body is-full-bleed">
|
||||
<ListPagination
|
||||
@source={{this.sortedAllocations}}
|
||||
@size={{this.pageSize}}
|
||||
@page={{this.currentPage}} as |p|>
|
||||
<ListTable
|
||||
@source={{p.list}}
|
||||
@sortProperty={{this.sortProperty}}
|
||||
@sortDescending={{this.sortDescending}}
|
||||
@class="with-foot" as |t|>
|
||||
<t.head>
|
||||
<th class="is-narrow"></th>
|
||||
<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
|
||||
@allocation={{row.model}}
|
||||
@context="node"
|
||||
@onClick={{action "gotoAllocation" row.model}}
|
||||
@data-test-allocation={{row.model.id}} />
|
||||
</t.body>
|
||||
</ListTable>
|
||||
<div class="table-foot">
|
||||
<nav class="pagination">
|
||||
<div class="pagination-numbers">
|
||||
{{p.startsAt}}–{{p.endsAt}} of {{this.sortedAllocations.length}}
|
||||
</div>
|
||||
<p.prev @class="pagination-previous"> < </p.prev>
|
||||
<p.next @class="pagination-next"> > </p.next>
|
||||
<ul class="pagination-list"></ul>
|
||||
</nav>
|
||||
<div class="boxed-section-body {{if this.sortedAllocations.length "is-full-bleed"}}">
|
||||
{{#if this.sortedAllocations.length}}
|
||||
<ListPagination
|
||||
@source={{this.sortedAllocations}}
|
||||
@size={{this.pageSize}}
|
||||
@page={{this.currentPage}} as |p|>
|
||||
<ListTable
|
||||
@source={{p.list}}
|
||||
@sortProperty={{this.sortProperty}}
|
||||
@sortDescending={{this.sortDescending}}
|
||||
@class="with-foot" as |t|>
|
||||
<t.head>
|
||||
<th class="is-narrow"></th>
|
||||
<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
|
||||
@allocation={{row.model}}
|
||||
@context="node"
|
||||
@onClick={{action "gotoAllocation" row.model}}
|
||||
@data-test-allocation={{row.model.id}} />
|
||||
</t.body>
|
||||
</ListTable>
|
||||
<div class="table-foot">
|
||||
<nav class="pagination">
|
||||
<div class="pagination-numbers">
|
||||
{{p.startsAt}}–{{p.endsAt}} of {{this.sortedAllocations.length}}
|
||||
</div>
|
||||
<p.prev @class="pagination-previous"> < </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)}}
|
||||
<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}}
|
||||
<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)}}
|
||||
<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}}
|
||||
</div>
|
||||
</ListPagination>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -130,6 +130,15 @@ module('Acceptance | client detail', function(hooks) {
|
||||
);
|
||||
});
|
||||
|
||||
test('/clients/:id should show empty message if there are no allocations on the node', async function(assert) {
|
||||
const emptyNode = server.create('node');
|
||||
|
||||
await ClientDetail.visit({ id: emptyNode.id });
|
||||
|
||||
assert.true(ClientDetail.emptyAllocations.isVisible, 'Empty message is visible');
|
||||
assert.equal(ClientDetail.emptyAllocations.headline, 'No Allocations');
|
||||
});
|
||||
|
||||
test('each allocation should have high-level details for the allocation', async function(assert) {
|
||||
const allocation = server.db.allocations
|
||||
.where({ nodeId: node.id })
|
||||
@@ -1028,6 +1037,19 @@ module('Acceptance | client detail', function(hooks) {
|
||||
},
|
||||
filter: (alloc, selection) => selection.includes(alloc.clientStatus),
|
||||
});
|
||||
|
||||
test('fiter results with no matches display empty message', async function(assert) {
|
||||
const job = server.create('job', { createAllocations: false });
|
||||
server.create('allocation', { jobId: job.id, clientStatus: 'running' });
|
||||
|
||||
await ClientDetail.visit({ id: node.id });
|
||||
const statusFacet = ClientDetail.facets.status;
|
||||
await statusFacet.toggle();
|
||||
await statusFacet.options.objectAt(0).toggle();
|
||||
|
||||
assert.true(ClientDetail.emptyAllocations.isVisible);
|
||||
assert.equal(ClientDetail.emptyAllocations.headline, 'No Matches');
|
||||
});
|
||||
});
|
||||
|
||||
module('Acceptance | client detail (multi-namespace)', function(hooks) {
|
||||
|
||||
@@ -39,6 +39,12 @@ export default create({
|
||||
|
||||
...allocations(),
|
||||
|
||||
emptyAllocations: {
|
||||
scope: '[data-test-empty-allocations-list]',
|
||||
headline: text('[data-test-empty-allocations-list-headline]'),
|
||||
body: text('[data-test-empty-allocations-list-body]'),
|
||||
},
|
||||
|
||||
allocationFilter: {
|
||||
preemptions: clickable('[data-test-filter-preemptions]'),
|
||||
all: clickable('[data-test-filter-all]'),
|
||||
|
||||
Reference in New Issue
Block a user