diff --git a/CHANGELOG.md b/CHANGELOG.md index 991feec77d2..342c5337844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/ui/app/templates/allocations/allocation/index.hbs b/ui/app/templates/allocations/allocation/index.hbs index 578ec2ab7e9..4a961c80828 100644 --- a/ui/app/templates/allocations/allocation/index.hbs +++ b/ui/app/templates/allocations/allocation/index.hbs @@ -1,3 +1,4 @@ +{{title "Allocation " model.name}}
{{#if error}}
diff --git a/ui/app/templates/allocations/allocation/task/index.hbs b/ui/app/templates/allocations/allocation/task/index.hbs index 2e1d56fb0fb..ee711f6fe65 100644 --- a/ui/app/templates/allocations/allocation/task/index.hbs +++ b/ui/app/templates/allocations/allocation/task/index.hbs @@ -1,3 +1,4 @@ +{{title "Task " model.name}} {{partial "allocations/allocation/task/subnav"}}
{{#if error}} diff --git a/ui/app/templates/allocations/allocation/task/logs.hbs b/ui/app/templates/allocations/allocation/task/logs.hbs index bbbff1ccf9f..4b1e74d5272 100644 --- a/ui/app/templates/allocations/allocation/task/logs.hbs +++ b/ui/app/templates/allocations/allocation/task/logs.hbs @@ -1,3 +1,4 @@ +{{title "Task " model.name " logs"}} {{partial "allocations/allocation/task/subnav"}}
{{task-log data-test-task-log allocation=model.allocation task=model.name}} diff --git a/ui/app/templates/application.hbs b/ui/app/templates/application.hbs index cfa4247bff4..8c48c97e358 100644 --- a/ui/app/templates/application.hbs +++ b/ui/app/templates/application.hbs @@ -1,3 +1,5 @@ +{{head-layout}} +{{title (if system.shouldShowRegions (concat system.activeRegion " - ")) "Nomad" separator=" - "}} {{partial "svg-patterns"}} {{#unless error}} {{outlet}} diff --git a/ui/app/templates/clients/client.hbs b/ui/app/templates/clients/client.hbs index a7aff9372dd..a71becadfa8 100644 --- a/ui/app/templates/clients/client.hbs +++ b/ui/app/templates/clients/client.hbs @@ -1,3 +1,4 @@ +{{title "Client " (or model.name model.shortId)}}

diff --git a/ui/app/templates/clients/index.hbs b/ui/app/templates/clients/index.hbs index 6326a85e7de..6d842a884e5 100644 --- a/ui/app/templates/clients/index.hbs +++ b/ui/app/templates/clients/index.hbs @@ -1,3 +1,4 @@ +{{title "Clients"}}
{{#if isForbidden}} {{partial "partials/forbidden-message"}} diff --git a/ui/app/templates/head.hbs b/ui/app/templates/head.hbs new file mode 100644 index 00000000000..d2eda4f162d --- /dev/null +++ b/ui/app/templates/head.hbs @@ -0,0 +1 @@ +{{model.title}} diff --git a/ui/app/templates/jobs/index.hbs b/ui/app/templates/jobs/index.hbs index 169bd5b5d23..79baa065f02 100644 --- a/ui/app/templates/jobs/index.hbs +++ b/ui/app/templates/jobs/index.hbs @@ -1,3 +1,4 @@ +{{title "Jobs"}}
{{#if isForbidden}} {{partial "partials/forbidden-message"}} diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index acd57bc9acc..062a43b301b 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -1,3 +1,4 @@ +{{title "Job " job.name " allocations"}} {{partial "jobs/job/subnav"}}
{{#if allocations.length}} diff --git a/ui/app/templates/jobs/job/definition.hbs b/ui/app/templates/jobs/job/definition.hbs index 4f30522b665..64002df4721 100644 --- a/ui/app/templates/jobs/job/definition.hbs +++ b/ui/app/templates/jobs/job/definition.hbs @@ -1,3 +1,4 @@ +{{title "Job " job.name " definition"}} {{partial "jobs/job/subnav"}}
{{#unless isEditing}} diff --git a/ui/app/templates/jobs/job/deployments.hbs b/ui/app/templates/jobs/job/deployments.hbs index 8bc4cb70790..255ccf01df0 100644 --- a/ui/app/templates/jobs/job/deployments.hbs +++ b/ui/app/templates/jobs/job/deployments.hbs @@ -1,3 +1,4 @@ +{{title "Job " job.name " deployments"}} {{partial "jobs/job/subnav"}}
{{job-deployments-stream deployments=model.deployments}} diff --git a/ui/app/templates/jobs/job/evaluations.hbs b/ui/app/templates/jobs/job/evaluations.hbs index 0c6e18290ed..ee2bdd0ff50 100644 --- a/ui/app/templates/jobs/job/evaluations.hbs +++ b/ui/app/templates/jobs/job/evaluations.hbs @@ -1,3 +1,4 @@ +{{title "Job " job.name " evaluations"}} {{partial "jobs/job/subnav"}}
{{#if sortedEvaluations.length}} diff --git a/ui/app/templates/jobs/job/index.hbs b/ui/app/templates/jobs/job/index.hbs index 8cd4928e6e3..b633740b3a1 100644 --- a/ui/app/templates/jobs/job/index.hbs +++ b/ui/app/templates/jobs/job/index.hbs @@ -1,3 +1,4 @@ +{{title "Job " model.name}} {{component (concat "job-page/" model.templateType) job=model sortProperty=sortProperty diff --git a/ui/app/templates/jobs/job/task-group.hbs b/ui/app/templates/jobs/job/task-group.hbs index 1b511adb81c..c74461a8e0e 100644 --- a/ui/app/templates/jobs/job/task-group.hbs +++ b/ui/app/templates/jobs/job/task-group.hbs @@ -1,3 +1,4 @@ +{{title "Task group " model.name " - Job " model.job.name}}
  • {{#link-to "jobs.job.task-group" model.job model activeClass="is-active"}}Overview{{/link-to}}
  • diff --git a/ui/app/templates/jobs/job/versions.hbs b/ui/app/templates/jobs/job/versions.hbs index 9f2d59b10fa..2b451ee2c72 100644 --- a/ui/app/templates/jobs/job/versions.hbs +++ b/ui/app/templates/jobs/job/versions.hbs @@ -1,3 +1,4 @@ +{{title "Job " job.name " versions"}} {{partial "jobs/job/subnav"}}
    {{job-versions-stream versions=model.versions verbose=true}} diff --git a/ui/app/templates/jobs/run.hbs b/ui/app/templates/jobs/run.hbs index 2fa8f850f26..8fd2e5473ff 100644 --- a/ui/app/templates/jobs/run.hbs +++ b/ui/app/templates/jobs/run.hbs @@ -1,3 +1,4 @@ +{{title "Run a job"}}
    {{job-editor job=model diff --git a/ui/app/templates/servers/index.hbs b/ui/app/templates/servers/index.hbs new file mode 100644 index 00000000000..e3956245947 --- /dev/null +++ b/ui/app/templates/servers/index.hbs @@ -0,0 +1 @@ +{{title "Servers"}} \ No newline at end of file diff --git a/ui/app/templates/servers/server.hbs b/ui/app/templates/servers/server.hbs index c9ef7a92544..bdc47a22bde 100644 --- a/ui/app/templates/servers/server.hbs +++ b/ui/app/templates/servers/server.hbs @@ -1,3 +1,4 @@ +{{title "Server " model.name}}
    diff --git a/ui/app/templates/settings/tokens.hbs b/ui/app/templates/settings/tokens.hbs index 3cd92bc8974..6561c2f1820 100644 --- a/ui/app/templates/settings/tokens.hbs +++ b/ui/app/templates/settings/tokens.hbs @@ -1,3 +1,4 @@ +{{title "Tokens"}}

    Access Control Tokens

    diff --git a/ui/package.json b/ui/package.json index aedf7edd58b..5fa57e079dd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -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", diff --git a/ui/tests/acceptance/allocation-detail-test.js b/ui/tests/acceptance/allocation-detail-test.js index 66bc2b71b76..7ac41a65cd3 100644 --- a/ui/tests/acceptance/allocation-detail-test.js +++ b/ui/tests/acceptance/allocation-detail-test.js @@ -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'); diff --git a/ui/tests/acceptance/client-detail-test.js b/ui/tests/acceptance/client-detail-test.js index df44f873d3c..42f11dd470b 100644 --- a/ui/tests/acceptance/client-detail-test.js +++ b/ui/tests/acceptance/client-detail-test.js @@ -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', diff --git a/ui/tests/acceptance/clients-list-test.js b/ui/tests/acceptance/clients-list-test.js index 9670bdd9876..6b3a1e69c62 100644 --- a/ui/tests/acceptance/clients-list-test.js +++ b/ui/tests/acceptance/clients-list-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-allocations-test.js b/ui/tests/acceptance/job-allocations-test.js index 546d40e7c88..d9b846b2577 100644 --- a/ui/tests/acceptance/job-allocations-test.js +++ b/ui/tests/acceptance/job-allocations-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-definition-test.js b/ui/tests/acceptance/job-definition-test.js index 0b69f11e2e5..280fe753932 100644 --- a/ui/tests/acceptance/job-definition-test.js +++ b/ui/tests/acceptance/job-definition-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-deployments-test.js b/ui/tests/acceptance/job-deployments-test.js index 3293b35e952..5a9107d23d8 100644 --- a/ui/tests/acceptance/job-deployments-test.js +++ b/ui/tests/acceptance/job-deployments-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-evaluations-test.js b/ui/tests/acceptance/job-evaluations-test.js index 9a7752b372b..71ba22a4551 100644 --- a/ui/tests/acceptance/job-evaluations-test.js +++ b/ui/tests/acceptance/job-evaluations-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-run-test.js b/ui/tests/acceptance/job-run-test.js index fed997f480f..f5c5e9d189a 100644 --- a/ui/tests/acceptance/job-run-test.js +++ b/ui/tests/acceptance/job-run-test.js @@ -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) { diff --git a/ui/tests/acceptance/job-versions-test.js b/ui/tests/acceptance/job-versions-test.js index a06cf8a97ad..6eba598b188 100644 --- a/ui/tests/acceptance/job-versions-test.js +++ b/ui/tests/acceptance/job-versions-test.js @@ -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) { diff --git a/ui/tests/acceptance/jobs-list-test.js b/ui/tests/acceptance/jobs-list-test.js index 069151ea0e0..1b1a57287f6 100644 --- a/ui/tests/acceptance/jobs-list-test.js +++ b/ui/tests/acceptance/jobs-list-test.js @@ -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) { diff --git a/ui/tests/acceptance/regions-test.js b/ui/tests/acceptance/regions-test.js index c8b54c90eb0..994199b512f 100644 --- a/ui/tests/acceptance/regions-test.js +++ b/ui/tests/acceptance/regions-test.js @@ -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) { diff --git a/ui/tests/acceptance/server-detail-test.js b/ui/tests/acceptance/server-detail-test.js index 3ae9ae3a632..e38c38df818 100644 --- a/ui/tests/acceptance/server-detail-test.js +++ b/ui/tests/acceptance/server-detail-test.js @@ -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) { diff --git a/ui/tests/acceptance/servers-list-test.js b/ui/tests/acceptance/servers-list-test.js index f1750c0022d..85ed0ffd607 100644 --- a/ui/tests/acceptance/servers-list-test.js +++ b/ui/tests/acceptance/servers-list-test.js @@ -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) { diff --git a/ui/tests/acceptance/task-detail-test.js b/ui/tests/acceptance/task-detail-test.js index a19ce0d89dd..5fe8e7560c1 100644 --- a/ui/tests/acceptance/task-detail-test.js +++ b/ui/tests/acceptance/task-detail-test.js @@ -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) { diff --git a/ui/tests/acceptance/task-group-detail-test.js b/ui/tests/acceptance/task-group-detail-test.js index fbfca4f78a9..0ec64dd5410 100644 --- a/ui/tests/acceptance/task-group-detail-test.js +++ b/ui/tests/acceptance/task-group-detail-test.js @@ -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) { diff --git a/ui/tests/acceptance/task-logs-test.js b/ui/tests/acceptance/task-logs-test.js index df2ca3f735f..4bacd989854 100644 --- a/ui/tests/acceptance/task-logs-test.js +++ b/ui/tests/acceptance/task-logs-test.js @@ -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) { diff --git a/ui/tests/acceptance/token-test.js b/ui/tests/acceptance/token-test.js index c02864e7ecb..4c295e168be 100644 --- a/ui/tests/acceptance/token-test.js +++ b/ui/tests/acceptance/token-test.js @@ -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'); diff --git a/ui/tests/helpers/module-for-job.js b/ui/tests/helpers/module-for-job.js index 75beffc9ce5..0cd34c5a863 100644 --- a/ui/tests/helpers/module-for-job.js +++ b/ui/tests/helpers/module-for-job.js @@ -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) { diff --git a/ui/yarn.lock b/ui/yarn.lock index df23003fb17..c73e49ba971 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -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"