Skip to content

Commit

Permalink
Merge pull request #3472 from hashicorp/f-ui-task-hierarchy
Browse files Browse the repository at this point in the history
Task route hierarchy in the UI
  • Loading branch information
DingoEatingFuzz committed Nov 14, 2017
2 parents 4847b30 + b3dc736 commit 4de2ad3
Show file tree
Hide file tree
Showing 20 changed files with 564 additions and 195 deletions.
16 changes: 2 additions & 14 deletions ui/app/controllers/allocations/allocation.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import Ember from 'ember';
import Sortable from 'nomad-ui/mixins/sortable';

const { Controller, computed } = Ember;
const { Controller } = Ember;

export default Controller.extend(Sortable, {
queryParams: {
sortProperty: 'sort',
sortDescending: 'desc',
},

sortProperty: 'name',
sortDescending: false,

listToSort: computed.alias('model.states'),
sortedStates: computed.alias('listSorted'),
});
export default Controller.extend({});
17 changes: 17 additions & 0 deletions ui/app/controllers/allocations/allocation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Ember from 'ember';
import Sortable from 'nomad-ui/mixins/sortable';

const { Controller, computed } = Ember;

export default Controller.extend(Sortable, {
queryParams: {
sortProperty: 'sort',
sortDescending: 'desc',
},

sortProperty: 'name',
sortDescending: false,

listToSort: computed.alias('model.states'),
sortedStates: computed.alias('listSorted'),
});
23 changes: 23 additions & 0 deletions ui/app/controllers/allocations/allocation/task/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Ember from 'ember';

const { Controller, computed } = Ember;

export default Controller.extend({
network: computed.alias('model.resources.networks.firstObject'),
ports: computed('network.reservedPorts.[]', 'network.dynamicPorts.[]', function() {
return this.get('network.reservedPorts')
.map(port => ({
name: port.Label,
port: port.Value,
isDynamic: false,
}))
.concat(
this.get('network.dynamicPorts').map(port => ({
name: port.Label,
port: port.Value,
isDynamic: true,
}))
)
.sortBy('name');
}),
});
12 changes: 12 additions & 0 deletions ui/app/models/allocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ export default Model.extend({
return STATUS_ORDER[this.get('clientStatus')] || 100;
}),

statusClass: computed('clientStatus', function() {
const classMap = {
pending: 'is-pending',
running: 'is-primary',
complete: 'is-complete',
failed: 'is-error',
lost: 'is-light',
};

return classMap[this.get('clientStatus')] || 'is-dark';
}),

taskGroup: computed('taskGroupName', 'job.taskGroups.[]', function() {
const taskGroups = this.get('job.taskGroups');
return taskGroups && taskGroups.findBy('name', this.get('taskGroupName'));
Expand Down
11 changes: 11 additions & 0 deletions ui/app/models/task-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,15 @@ export default Fragment.extend({

resources: fragment('resources'),
events: fragmentArray('task-event'),

stateClass: computed('state', function() {
const classMap = {
pending: 'is-pending',
running: 'is-primary',
finished: 'is-complete',
failed: 'is-error',
};

return classMap[this.get('state')] || 'is-dark';
}),
});
6 changes: 5 additions & 1 deletion ui/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ Router.map(function() {
});

this.route('allocations', function() {
this.route('allocation', { path: '/:allocation_id' });
this.route('allocation', { path: '/:allocation_id' }, function() {
this.route('task', { path: '/:name' }, function() {
this.route('logs');
});
});
});

this.route('settings', function() {
Expand Down
22 changes: 22 additions & 0 deletions ui/app/routes/allocations/allocation/task.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Ember from 'ember';

const { Route, inject, Error: EmberError } = Ember;

export default Route.extend({
store: inject.service(),

model({ name }) {
const allocation = this.modelFor('allocations.allocation');
if (allocation) {
const task = allocation.get('states').findBy('name', name);

if (task) {
return task;
}

const err = new EmberError(`Task ${name} not found for allocation ${allocation.get('id')}`);
err.code = '404';
this.controllerFor('application').set('error', err);
}
},
});
10 changes: 5 additions & 5 deletions ui/app/styles/components/breadcrumbs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@
opacity: 0.7;
text-decoration: none;

&:hover {
color: $primary-invert;
opacity: 1;
}

+ .breadcrumb {
margin-left: 15px;
&::before {
Expand All @@ -23,4 +18,9 @@
opacity: 1;
}
}

a.breadcrumb:hover {
color: $primary-invert;
opacity: 1;
}
}
10 changes: 10 additions & 0 deletions ui/app/styles/core/tag.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
color: $blue-invert;
}

&.is-primary {
background: $primary;
color: $primary-invert;
}

&.is-complete {
background: $nomad-green-dark;
color: findColorInvert($nomad-green-dark);
}

&.is-error {
background: $danger;
color: $danger-invert;
Expand Down
7 changes: 1 addition & 6 deletions ui/app/templates/allocations.hbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
<div class="page-layout">
{{#global-header class="page-header"}}
Allocations
{{/global-header}}
{{#gutter-menu class="page-body"}}
{{outlet}}
{{/gutter-menu}}
{{outlet}}
</div>
92 changes: 1 addition & 91 deletions ui/app/templates/allocations/allocation.hbs
Original file line number Diff line number Diff line change
@@ -1,91 +1 @@
<section class="section">
<h1 class="title">Allocation {{model.name}}</h1>
<h3 class="subtitle">
For job {{#link-to "jobs.job" model.job (query-params jobNamespace=model.job.namespace.id)}}{{model.job.name}}{{/link-to}}
on client {{#link-to "clients.client" model.node}}{{model.node.shortId}}{{/link-to}}
</h3>

<div class="message">
<div class="message-header">
Tasks
</div>
{{#list-table
source=sortedStates
sortProperty=sortProperty
sortDescending=sortDescending
class="is-striped tasks" as |t|}}
{{#t.head}}
{{#t.sort-by prop="name"}}Name{{/t.sort-by}}
{{#t.sort-by prop="state"}}State{{/t.sort-by}}
<th>Last Event</th>
{{#t.sort-by prop="events.lastObject.time"}}Time{{/t.sort-by}}
<th>Addresses</th>
{{/t.head}}
{{#t.body as |row|}}
<tr>
<td>{{row.model.task.name}}</td>
<td>{{row.model.state}}</td>
<td>
{{#if row.model.events.lastObject.displayMessage}}
{{row.model.events.lastObject.displayMessage}}
{{else}}
<em>No message</em>
{{/if}}
</td>
<td>{{moment-format row.model.events.lastObject.time "MM/DD/YY HH:mm:ss [UTC]"}}</td>
<td>
<ul>
{{#each row.model.resources.networks.firstObject.reservedPorts as |port|}}
<li>
<strong>{{port.Label}}:</strong>
<a href="http://{{row.model.allocation.node.address}}:{{port.Value}}" target="_blank">{{row.model.allocation.node.address}}:{{port.Value}}</a>
</li>
{{/each}}
{{#each row.model.resources.networks.firstObject.dynamicPorts as |port|}}
<li>
<strong>{{port.Label}}:</strong>
<a href="http://{{row.model.allocation.node.address}}:{{port.Value}}" target="_blank">{{row.model.allocation.node.address}}:{{port.Value}}</a>
</li>
{{/each}}
</ul>
</td>
</tr>
{{/t.body}}
{{/list-table}}
</div>

{{#each model.states as |state|}}
<div class="message task-state-events">
<div class="message-header">
{{state.task.name}} ({{state.state}}) Started: {{moment-format state.startedAt "MM/DD/YY HH:mm:ss [UTC]"}}
{{#unless state.isActive}}
Ended: {{moment-format state.finishedAt "MM/DD/YY HH:mm:ss [UTC]"}}
{{/unless}}
</div>
<table class="table is-striped task-events">
<thead>
<tr>
<td class="is-3">Time</td>
<td class="is-1">Type</td>
<td>Description</td>
</tr>
</thead>
<tbody>
{{#each (reverse state.events) as |event|}}
<tr>
<td>{{moment-format event.time "MM/DD/YY HH:mm:ss [UTC]"}}</td>
<td>{{event.type}}</td>
<td>
{{#if event.displayMessage}}
{{event.displayMessage}}
{{else}}
<em>No message</em>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
{{/each}}
</section>
{{outlet}}
82 changes: 82 additions & 0 deletions ui/app/templates/allocations/allocation/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{{#global-header class="page-header"}}
<span class="breadcrumb">Allocations</span>
{{#link-to "allocations.allocation" model class="breadcrumb"}}
{{model.shortId}}
{{/link-to}}
{{/global-header}}
{{#gutter-menu class="page-body"}}
<section class="section">
<h1 class="title">
Allocation {{model.name}}
<span class="bumper-left tag {{model.statusClass}}">{{model.clientStatus}}</span>
<span class="tag is-hollow is-small no-text-transform">{{model.id}}</span>
</h1>

<div class="boxed-section is-small">
<div class="boxed-section-body inline-definitions">
<span class="label">Allocation Details</span>
<span class="pair job-link"><span class="term">Job</span>
{{#link-to "jobs.job" model.job (query-params jobNamespace=model.job.namespace.id)}}{{model.job.name}}{{/link-to}}
</span>
<span class="pair node-link"><span class="term">Client</span>
{{#link-to "clients.client" model.node}}{{model.node.shortId}}{{/link-to}}
</span>
</div>
</div>

<div class="boxed-section">
<div class="boxed-section-head">
Tasks
</div>
<div class="boxed-section-body is-full-bleed">
{{#list-table
source=sortedStates
sortProperty=sortProperty
sortDescending=sortDescending
class="is-striped tasks" as |t|}}
{{#t.head}}
{{#t.sort-by prop="name"}}Name{{/t.sort-by}}
{{#t.sort-by prop="state"}}State{{/t.sort-by}}
<th>Last Event</th>
{{#t.sort-by prop="events.lastObject.time"}}Time{{/t.sort-by}}
<th>Addresses</th>
{{/t.head}}
{{#t.body as |row|}}
<tr>
<td>
{{#link-to "allocations.allocation.task" row.model.allocation row.model}}
{{row.model.task.name}}
{{/link-to}}
</td>
<td>{{row.model.state}}</td>
<td>
{{#if row.model.events.lastObject.displayMessage}}
{{row.model.events.lastObject.displayMessage}}
{{else}}
<em>No message</em>
{{/if}}
</td>
<td>{{moment-format row.model.events.lastObject.time "MM/DD/YY HH:mm:ss [UTC]"}}</td>
<td>
<ul>
{{#each row.model.resources.networks.firstObject.reservedPorts as |port|}}
<li>
<strong>{{port.Label}}:</strong>
<a href="http://{{row.model.allocation.node.address}}:{{port.Value}}" target="_blank">{{row.model.allocation.node.address}}:{{port.Value}}</a>
</li>
{{/each}}
{{#each row.model.resources.networks.firstObject.dynamicPorts as |port|}}
<li>
<strong>{{port.Label}}:</strong>
<a href="http://{{row.model.allocation.node.address}}:{{port.Value}}" target="_blank">{{row.model.allocation.node.address}}:{{port.Value}}</a>
</li>
{{/each}}
</ul>
</td>
</tr>
{{/t.body}}
{{/list-table}}
</div>
</div>
</section>
{{/gutter-menu}}
1 change: 1 addition & 0 deletions ui/app/templates/allocations/allocation/task.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{outlet}}
Loading

0 comments on commit 4de2ad3

Please sign in to comment.