mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
Merge pull request #3305 from hashicorp/f-ui-empty-states
UI empty states
This commit is contained in:
@@ -12,7 +12,7 @@ export default Component.extend({
|
||||
// Used to throttle sets to searchTerm
|
||||
debounce: 150,
|
||||
|
||||
classNames: ['field', 'has-addons'],
|
||||
classNames: ['search-box', 'field', 'has-addons'],
|
||||
|
||||
actions: {
|
||||
setSearchTerm(e) {
|
||||
|
||||
12
ui/app/initializers/app-token.js
Normal file
12
ui/app/initializers/app-token.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export function initialize() {
|
||||
const application = arguments[1] || arguments[0];
|
||||
|
||||
// Provides the acl token service to all templates
|
||||
application.inject('controller', 'token', 'service:token');
|
||||
application.inject('component', 'token', 'service:token');
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'app-token',
|
||||
initialize,
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
@import "./components/badge";
|
||||
@import "./components/boxed-section";
|
||||
@import "./components/breadcrumbs";
|
||||
@import "./components/empty-message";
|
||||
@import "./components/gutter";
|
||||
@import "./components/inline-definitions";
|
||||
@import "./components/job-diff";
|
||||
|
||||
21
ui/app/styles/components/empty-message.scss
Normal file
21
ui/app/styles/components/empty-message.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.empty-message {
|
||||
padding: 1.5rem;
|
||||
background: $white-ter;
|
||||
border-radius: $radius;
|
||||
|
||||
.empty-message-headline {
|
||||
font-size: $size-3;
|
||||
color: $grey;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-message-body {
|
||||
padding: 0 20%;
|
||||
text-align: center;
|
||||
color: $grey;
|
||||
|
||||
strong {
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,11 @@
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
<div class="content">
|
||||
<div>{{search-box searchTerm=(mut searchTerm) placeholder="Search jobs..."}}</div>
|
||||
</div>
|
||||
{{#if model.length}}
|
||||
<div class="content">
|
||||
<div>{{search-box searchTerm=(mut searchTerm) placeholder="Search jobs..."}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#list-pagination
|
||||
source=sortedJobs
|
||||
size=pageSize
|
||||
@@ -37,6 +39,18 @@
|
||||
<ul class="pagination-list"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="empty-message">
|
||||
{{#if (eq model.length 0)}}
|
||||
<h3 class="empty-message-headline">No Jobs</h3>
|
||||
<p class="empty-message-body">
|
||||
There are currently no visible jobs in the cluster. It could be that the cluster is empty. It could also mean {{#link-to "settings.tokens"}}you don't have access to see any jobs{{/link-to}}.
|
||||
</p>
|
||||
{{else if searchTerm}}
|
||||
<h3 class="empty-message-headline">No Matches</h3>
|
||||
<p class="empty-message-body">No jobs match the term <strong>{{searchTerm}}</strong></p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/list-pagination}}
|
||||
</section>
|
||||
{{/gutter-menu}}
|
||||
|
||||
@@ -90,6 +90,13 @@
|
||||
{{#p.last class="pagination-link"}} >| {{/p.last}}
|
||||
</ul>
|
||||
</nav>
|
||||
{{else}}
|
||||
<div class="boxed-section-body">
|
||||
<div class="empty-message">
|
||||
<h3 class="empty-message-headline">No Matches</h3>
|
||||
<p class="empty-message-body">No allocations match the term <strong>{{searchTerm}}</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
{{/list-pagination}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
<div class="content">
|
||||
<div>{{search-box searchTerm=(mut searchTerm) placeholder="Search nodes..."}}</div>
|
||||
</div>
|
||||
{{#if nodes.length}}
|
||||
<div class="content">
|
||||
<div>{{search-box searchTerm=(mut searchTerm) placeholder="Search nodes..."}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#list-pagination
|
||||
source=sortedNodes
|
||||
size=pageSize
|
||||
@@ -38,6 +40,18 @@
|
||||
<ul class="pagination-list"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="empty-message">
|
||||
{{#if (eq nodes.length 0)}}
|
||||
<h3 class="empty-message-headline">No Clients</h3>
|
||||
<p class="empty-message-body">
|
||||
There are currently no visible nodes in the cluster. This could mean that the cluster is bootstrapped with no clients. It could also mean {{#link-to "settings.tokens"}}you don't have access to see any clients{{/link-to}}.
|
||||
</p>
|
||||
{{else if searchTerm}}
|
||||
<h3 class="empty-message-headline">No Matches</h3>
|
||||
<p class="empty-message-body">No clients match the term <strong>{{searchTerm}}</strong></p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/list-pagination}}
|
||||
</section>
|
||||
{{/gutter-menu}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
Nodes
|
||||
Servers
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
@@ -35,6 +35,17 @@
|
||||
<ul class="pagination-list"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="empty-message">
|
||||
<h3 class="empty-message-headline">Invalid Permissions</h3>
|
||||
<p class="empty-message-body">
|
||||
{{#if token.secret}}
|
||||
Your ACL token does not grant access to see servers.
|
||||
{{else}}
|
||||
You have no ACL token set. {{#link-to "settings.tokens"}}Provide a token{{/link-to}} with the appropriate permissions to see servers.
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
{{/list-pagination}}
|
||||
{{outlet}}
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers';
|
||||
import { click, find, findAll, currentURL, visit, fillIn } from 'ember-native-dom-helpers';
|
||||
import { test } from 'qunit';
|
||||
import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance';
|
||||
|
||||
@@ -80,3 +80,30 @@ test('each job row should link to the corresponding job', function(assert) {
|
||||
assert.equal(currentURL(), `/jobs/${job.id}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('when there are no jobs, there is an empty message', function(assert) {
|
||||
visit('/jobs');
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.empty-message'));
|
||||
assert.equal(find('.empty-message-headline').textContent, 'No Jobs');
|
||||
});
|
||||
});
|
||||
|
||||
test('when there are jobs, but no matches for a search result, there is an empty message', function(
|
||||
assert
|
||||
) {
|
||||
server.create('job', { name: 'cat 1' });
|
||||
server.create('job', { name: 'cat 2' });
|
||||
|
||||
visit('/jobs');
|
||||
|
||||
andThen(() => {
|
||||
fillIn('.search-box input', 'dog');
|
||||
});
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.empty-message'));
|
||||
assert.equal(find('.empty-message-headline').textContent, 'No Matches');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers';
|
||||
import { click, find, findAll, currentURL, visit } from 'ember-native-dom-helpers';
|
||||
import { test } from 'qunit';
|
||||
import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance';
|
||||
import { findLeader } from '../../mirage/config';
|
||||
@@ -75,6 +75,35 @@ test('each client should link to the client detail page', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('when there are no clients, there is an empty message', function(assert) {
|
||||
server.createList('agent', 1);
|
||||
|
||||
visit('/nodes');
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.empty-message'));
|
||||
assert.equal(find('.empty-message-headline').textContent, 'No Clients');
|
||||
});
|
||||
});
|
||||
|
||||
test('when there are clients, but no matches for a search term, there is an empty message', function(
|
||||
assert
|
||||
) {
|
||||
server.createList('agent', 1);
|
||||
server.create('node', { name: 'node' });
|
||||
|
||||
visit('/nodes');
|
||||
|
||||
andThen(() => {
|
||||
fillIn('.search-box input', 'client');
|
||||
});
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.empty-message'));
|
||||
assert.equal(find('.empty-message-headline').textContent, 'No Matches');
|
||||
});
|
||||
});
|
||||
|
||||
test('/servers should list all servers', function(assert) {
|
||||
const agentsCount = 10;
|
||||
const pageSize = 8;
|
||||
@@ -141,3 +170,24 @@ test('each server should link to the server detail page', function(assert) {
|
||||
assert.equal(currentURL(), `/servers/${agent.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('when the API returns no agents, show an empty message', function(assert) {
|
||||
minimumSetup();
|
||||
|
||||
// Override the members handler to act as if server-side permissions
|
||||
// are preventing a qualified response.
|
||||
server.pretender.get('/v1/agent/members', () => [
|
||||
200,
|
||||
{},
|
||||
JSON.stringify({
|
||||
Members: [],
|
||||
}),
|
||||
]);
|
||||
|
||||
visit('/servers');
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.empty-message'));
|
||||
assert.equal(find('.empty-message-headline').textContent, 'Invalid Permissions');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
import { click, findAll, currentURL, visit } from 'ember-native-dom-helpers';
|
||||
import { click, find, findAll, fillIn, currentURL, visit } from 'ember-native-dom-helpers';
|
||||
import { test } from 'qunit';
|
||||
import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance';
|
||||
|
||||
@@ -41,6 +41,11 @@ moduleForAcceptance('Acceptance | task group detail', {
|
||||
taskGroup: taskGroups[1].name,
|
||||
});
|
||||
|
||||
// Set a static name to make the search test deterministic
|
||||
server.db.allocations.forEach(alloc => {
|
||||
alloc.name = 'aaaaa';
|
||||
});
|
||||
|
||||
visit(`/jobs/${job.id}/${taskGroup.name}`);
|
||||
},
|
||||
});
|
||||
@@ -212,3 +217,12 @@ test('each allocation should show stats about the allocation, retrieved directly
|
||||
`Requests ${nodeStatsUrl}`
|
||||
);
|
||||
});
|
||||
|
||||
test('when the allocation search has no matches, there is an empty message', function(assert) {
|
||||
fillIn('.search-box input', 'zzzzzz');
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(find('.allocations .empty-message'));
|
||||
assert.equal(find('.allocations .empty-message-headline').textContent, 'No Matches');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user