UI: Add page titles (#5924)

This uses ember-page-title to add dynamic page titles throughout the
route hierarchy. When there’s more than one region, the current
current region is added before the final entry of “- Nomad”.
This commit is contained in:
Buck Doyle
2019-07-17 15:02:58 -05:00
committed by GitHub
parent 0965379f27
commit 87d716ed0b
40 changed files with 69 additions and 2 deletions

View File

@@ -10,6 +10,7 @@ IMPROVEMENTS:
* metrics: Added namespace label as appropriate to metrics [[GH-5847](https://github.com/hashicorp/nomad/issues/5847)]
* ui: Moved client status, draining, and eligibility fields into single state column [[GH-5789](https://github.com/hashicorp/nomad/pull/5789)]
* ui: Added buttons to copy client and allocation UUIDs [[GH-5926](https://github.com/hashicorp/nomad/pull/5926)]
* ui: Added page titles [[GH-5924](https://github.com/hashicorp/nomad/pull/5924)]
BUG FIXES:

View File

@@ -1,3 +1,4 @@
{{title "Allocation " model.name}}
<section class="section">
{{#if error}}
<div data-test-inline-error class="notification is-danger">

View File

@@ -1,3 +1,4 @@
{{title "Task " model.name}}
{{partial "allocations/allocation/task/subnav"}}
<section class="section">
{{#if error}}

View File

@@ -1,3 +1,4 @@
{{title "Task " model.name " logs"}}
{{partial "allocations/allocation/task/subnav"}}
<section class="section full-width-section">
{{task-log data-test-task-log allocation=model.allocation task=model.name}}

View File

@@ -1,3 +1,5 @@
{{head-layout}}
{{title (if system.shouldShowRegions (concat system.activeRegion " - ")) "Nomad" separator=" - "}}
{{partial "svg-patterns"}}
{{#unless error}}
{{outlet}}

View File

@@ -1,3 +1,4 @@
{{title "Client " (or model.name model.shortId)}}
<section class="section">
<h1 data-test-title class="title">
<span data-test-node-status="{{model.compositeStatus}}" class="node-status-light {{model.compositeStatus}}"></span>

View File

@@ -1,3 +1,4 @@
{{title "Clients"}}
<section class="section">
{{#if isForbidden}}
{{partial "partials/forbidden-message"}}

View File

@@ -0,0 +1 @@
<title>{{model.title}}</title>

View File

@@ -1,3 +1,4 @@
{{title "Jobs"}}
<section class="section">
{{#if isForbidden}}
{{partial "partials/forbidden-message"}}

View File

@@ -1,3 +1,4 @@
{{title "Job " job.name " allocations"}}
{{partial "jobs/job/subnav"}}
<section class="section">
{{#if allocations.length}}

View File

@@ -1,3 +1,4 @@
{{title "Job " job.name " definition"}}
{{partial "jobs/job/subnav"}}
<section class="section">
{{#unless isEditing}}

View File

@@ -1,3 +1,4 @@
{{title "Job " job.name " deployments"}}
{{partial "jobs/job/subnav"}}
<section class="section">
{{job-deployments-stream deployments=model.deployments}}

View File

@@ -1,3 +1,4 @@
{{title "Job " job.name " evaluations"}}
{{partial "jobs/job/subnav"}}
<section class="section">
{{#if sortedEvaluations.length}}

View File

@@ -1,3 +1,4 @@
{{title "Job " model.name}}
{{component (concat "job-page/" model.templateType)
job=model
sortProperty=sortProperty

View File

@@ -1,3 +1,4 @@
{{title "Task group " model.name " - Job " model.job.name}}
<div class="tabs is-subnav">
<ul>
<li>{{#link-to "jobs.job.task-group" model.job model activeClass="is-active"}}Overview{{/link-to}}</li>

View File

@@ -1,3 +1,4 @@
{{title "Job " job.name " versions"}}
{{partial "jobs/job/subnav"}}
<section class="section">
{{job-versions-stream versions=model.versions verbose=true}}

View File

@@ -1,3 +1,4 @@
{{title "Run a job"}}
<section class="section">
{{job-editor
job=model

View File

@@ -0,0 +1 @@
{{title "Servers"}}

View File

@@ -1,3 +1,4 @@
{{title "Server " model.name}}
<div class="columns">
<div class="column is-half">
<div class="message">

View File

@@ -1,3 +1,4 @@
{{title "Tokens"}}
<section class="section">
<h1 class="title">Access Control Tokens</h1>
<div class="columns">

View File

@@ -76,6 +76,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-moment": "^7.8.1",
"ember-native-dom-helpers": "^0.5.4",
"ember-page-title": "^5.0.2",
"ember-power-select": "^2.2.3",
"ember-qunit-nice-errors": "^1.2.0",
"ember-resolver": "^5.0.1",

View File

@@ -49,6 +49,8 @@ module('Acceptance | allocation detail', function(hooks) {
'Node short id is in the subheading'
);
assert.equal(document.title, `Allocation ${allocation.name} - Nomad`);
await Allocation.details.visitJob();
assert.equal(currentURL(), `/jobs/${job.id}`, 'Job link navigates to the job');

View File

@@ -38,6 +38,8 @@ module('Acceptance | client detail', function(hooks) {
test('/clients/:id should have a breadcrumb trail linking back to clients', async function(assert) {
await ClientDetail.visit({ id: node.id });
assert.equal(document.title, `Client ${node.name} - Nomad`);
assert.equal(
ClientDetail.breadcrumbFor('clients.index').text,
'Clients',

View File

@@ -26,6 +26,8 @@ module('Acceptance | clients list', function(hooks) {
ClientsList.nodes.forEach((node, index) => {
assert.equal(node.id, sortedNodes[index].id.split('-')[0], 'Clients are ordered');
});
assert.equal(document.title, 'Clients - Nomad');
});
test('each client record should show high-level info of the client', async function(assert) {

View File

@@ -46,6 +46,8 @@ module('Acceptance | job allocations', function(hooks) {
const shortId = sortedAllocations[index].id.split('-')[0];
assert.equal(allocation.shortId, shortId, `Allocation ${index} is ${shortId}`);
});
assert.equal(document.title, `Job ${job.name} allocations - Nomad`);
});
test('allocations table is sortable', async function(assert) {

View File

@@ -21,6 +21,7 @@ module('Acceptance | job definition', function(hooks) {
test('visiting /jobs/:job_id/definition', async function(assert) {
assert.equal(currentURL(), `/jobs/${job.id}/definition`);
assert.equal(document.title, `Job ${job.name} definition - Nomad`);
});
test('the job definition page contains a json viewer component', async function(assert) {

View File

@@ -41,6 +41,7 @@ module('Acceptance | job deployments', function(hooks) {
deployments.length,
'Each deployment gets a row in the timeline'
);
assert.equal(document.title, `Job ${job.name} deployments - Nomad`);
});
test('each deployment mentions the deployment shortId, status, version, and time since it was submitted', async function(assert) {

View File

@@ -27,6 +27,8 @@ module('Acceptance | job evaluations', function(hooks) {
const shortId = sortedEvaluations[index].id.split('-')[0];
assert.equal(evaluation.id, shortId, `Evaluation ${index} is ${shortId}`);
});
assert.equal(document.title, `Job ${job.name} evaluations - Nomad`);
});
test('evaluations table is sortable', async function(assert) {

View File

@@ -51,6 +51,7 @@ module('Acceptance | job run', function(hooks) {
await JobRun.visit();
assert.equal(currentURL(), '/jobs/run');
assert.equal(document.title, 'Run a job - Nomad');
});
test('when submitting a job, the site redirects to the new job overview page', async function(assert) {

View File

@@ -21,6 +21,7 @@ module('Acceptance | job versions', function(hooks) {
test('/jobs/:id/versions should list all job versions', async function(assert) {
assert.ok(Versions.versions.length, versions.length, 'Each version gets a row in the timeline');
assert.equal(document.title, `Job ${job.name} versions - Nomad`);
});
test('each version mentions the version number, the stability, and the submitted time', async function(assert) {

View File

@@ -17,6 +17,7 @@ module('Acceptance | jobs list', function(hooks) {
await JobsList.visit();
assert.equal(currentURL(), '/jobs');
assert.equal(document.title, 'Jobs - Nomad');
});
test('/jobs should list the first page of jobs sorted by modify index', async function(assert) {

View File

@@ -18,12 +18,13 @@ module('Acceptance | regions (only one)', function(hooks) {
server.createList('job', 2, { createAllocations: false, noDeployments: true });
});
test('when there is only one region, the region switcher is not shown in the nav bar', async function(assert) {
test('when there is only one region, the region switcher is not shown in the nav bar and the region is not in the page title', async function(assert) {
server.create('region', { id: 'global' });
await JobsList.visit();
assert.notOk(PageLayout.navbar.regionSwitcher.isPresent, 'No region switcher');
assert.equal(document.title, 'Jobs - Nomad');
});
test('when the only region is not named "global", the region switcher still is not shown', async function(assert) {
@@ -74,10 +75,11 @@ module('Acceptance | regions (many)', function(hooks) {
server.create('region', { id: 'region-2' });
});
test('the region switcher is rendered in the nav bar', async function(assert) {
test('the region switcher is rendered in the nav bar and the region is in the page title', async function(assert) {
await JobsList.visit();
assert.ok(PageLayout.navbar.regionSwitcher.isPresent, 'Region switcher is shown');
assert.equal(document.title, 'Jobs - global - Nomad');
});
test('when on the default region, pages do not include the region query param', async function(assert) {

View File

@@ -18,6 +18,7 @@ module('Acceptance | server detail', function(hooks) {
test('visiting /servers/:server_name', async function(assert) {
assert.equal(currentURL(), `/servers/${encodeURIComponent(agent.name)}`);
assert.equal(document.title, `Server ${agent.name} - Nomad`);
});
test('the server detail page should list all tags for the server', async function(assert) {

View File

@@ -37,6 +37,8 @@ module('Acceptance | servers list', function(hooks) {
ServersList.servers.forEach((server, index) => {
assert.equal(server.name, sortedAgents[index].name, 'Servers are ordered');
});
assert.equal(document.title, 'Servers - Nomad');
});
test('each server should show high-level info of the server', async function(assert) {

View File

@@ -30,6 +30,8 @@ module('Acceptance | task detail', function(hooks) {
Task.startedAt.includes(moment(task.startedAt).format("MMM DD, 'YY HH:mm:ss ZZ")),
'Task started at'
);
assert.equal(document.title, `Task ${task.name} - Nomad`);
});
test('breadcrumbs match jobs / job / task group / allocation / task', async function(assert) {

View File

@@ -85,6 +85,8 @@ module('Acceptance | task group detail', function(hooks) {
`Reserved Disk ${totalDisk} MiB`,
'Aggregated Disk reservation for all tasks'
);
assert.equal(document.title, `Task group ${taskGroup.name} - Job ${job.name} - Nomad`);
});
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', async function(assert) {

View File

@@ -27,6 +27,7 @@ module('Acceptance | task logs', function(hooks) {
test('/allocation/:id/:task_name/logs should have a log component', async function(assert) {
assert.equal(currentURL(), `/allocations/${allocation.id}/${task.name}/logs`, 'No redirect');
assert.ok(TaskLogs.hasTaskLog, 'Task log component found');
assert.equal(document.title, `Task ${task.name} logs - Nomad`);
});
test('the stdout log immediately starts streaming', async function(assert) {

View File

@@ -32,6 +32,7 @@ module('Acceptance | tokens', function(hooks) {
await Tokens.visit();
assert.ok(window.localStorage.nomadTokenSecret == null, 'No token secret set');
assert.equal(document.title, 'Tokens - Nomad');
await Tokens.secret(secretId).submit();
assert.equal(window.localStorage.nomadTokenSecret, secretId, 'Token secret was set');

View File

@@ -26,6 +26,7 @@ export default function moduleForJob(title, context, jobFactory, additionalTests
test('visiting /jobs/:job_id', async function(assert) {
assert.equal(currentURL(), `/jobs/${job.id}`);
assert.equal(document.title, `Job ${job.name} - Nomad`);
});
test('the subnav links to overview', async function(assert) {

View File

@@ -4235,6 +4235,14 @@ ember-cli-get-component-path-option@^1.0.0:
resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771"
integrity sha1-DXtZVVni+QUKvtgE8djv8bCLx3E=
ember-cli-head@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/ember-cli-head/-/ember-cli-head-0.4.1.tgz#28b7ee86439746640834b232a3b34ab1329f3cf3"
integrity sha512-MIgshw5nGil7Q/TU4SDRCsgsiA3wPC9WqOig/g1LlHTNXjR4vH7s/ddG7GTfK5Kt4ZQHJEUDXpd/lIbdBkIQ/Q==
dependencies:
ember-cli-babel "^6.11.0"
ember-cli-htmlbars "^2.0.3"
ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompile@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a"
@@ -4824,6 +4832,16 @@ ember-native-dom-helpers@^0.5.3, ember-native-dom-helpers@^0.5.4:
broccoli-funnel "^1.1.0"
ember-cli-babel "^6.6.0"
ember-page-title@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/ember-page-title/-/ember-page-title-5.0.2.tgz#ab5a60c16318ba7f5e66cd41f580c9831ce3b612"
integrity sha512-v5K8tfPxdLmZRRdUP0L9ed+ufC1tw+tAhlHslt5MchDwHh192OH1JhDROp6Wci8/Np9kaSCICxS27nXEgXxxsg==
dependencies:
ember-cli-babel "^7.7.3"
ember-cli-head "^0.4.0"
ember-cli-htmlbars "^3.0.1"
ember-copy "^1.0.0"
ember-power-select@^2.2.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/ember-power-select/-/ember-power-select-2.3.0.tgz#f9f2d242381f715f860c76f168d63c6ff2688ae7"