-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Basic services table implemented #13856
Changes from all commits
c493400
efb76b6
ff79a48
3cf40b7
b53296f
24fd942
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,6 +144,8 @@ export default class Job extends Model { | |
|
||
@hasMany('recommendation-summary') recommendationSummaries; | ||
|
||
@hasMany('services') services; | ||
|
||
@computed('[email protected]') | ||
get drivers() { | ||
return this.taskGroups | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { attr } from '@ember-data/model'; | ||
import Fragment from 'ember-data-model-fragments/fragment'; | ||
import { fragment } from 'ember-data-model-fragments/attributes'; | ||
|
||
export default class ServiceFragment extends Fragment { | ||
@attr('string') name; | ||
@attr('string') portLabel; | ||
@attr() tags; | ||
@attr('string') onUpdate; | ||
@fragment('consul-connect') connect; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
import { attr } from '@ember-data/model'; | ||
import Fragment from 'ember-data-model-fragments/fragment'; | ||
import { fragment } from 'ember-data-model-fragments/attributes'; | ||
// import { fragment } from 'ember-data-model-fragments/attributes'; | ||
import Model from '@ember-data/model'; | ||
import { alias } from '@ember/object/computed'; | ||
|
||
export default class Service extends Fragment { | ||
@attr('string') name; | ||
@attr('string') portLabel; | ||
export default class Service extends Model { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Answered this elsewhere, but these are not properties that return in the list view for Services. As I build out pieces of the UI that use things like nodeID, alloId, and job, I'll model those as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, I'm not a fan of modeling as you go. And I think not modeling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
https://github.com/hashicorp/nomad/blob/main/api/services.go#L14-L60 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely agreed, but as the scope of this is limited to just the main /services page, and it only returns ServiceName and Tags, that's all I'm extending to the model here. As we build out more of the UI that fetches and gets more properties, those'll be added to the model. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For context, the total of what returns at the /services endpoint
|
||
@attr('string') serviceName; | ||
@alias('serviceName') name; | ||
@attr() tags; | ||
@attr('string') onUpdate; | ||
@fragment('consul-connect') connect; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,7 @@ export default class TaskGroup extends Fragment { | |
|
||
@fragmentArray('task') tasks; | ||
|
||
@fragmentArray('service') services; | ||
@fragmentArray('service-fragment') services; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
@fragmentArray('volume-definition') volumes; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,4 +95,5 @@ Router.map(function () { | |
path: '/path/*absolutePath', | ||
}); | ||
}); | ||
this.route('services', function () {}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { inject as service } from '@ember/service'; | ||
import Route from '@ember/routing/route'; | ||
import RSVP from 'rsvp'; | ||
import WithForbiddenState from 'nomad-ui/mixins/with-forbidden-state'; | ||
import notifyForbidden from 'nomad-ui/utils/notify-forbidden'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
@classic | ||
export default class ServicesRoute extends Route.extend(WithForbiddenState) { | ||
@service store; | ||
@service system; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
async model() { | ||
return RSVP.hash({ | ||
services: this.store.findAll('service'), | ||
}).catch(notifyForbidden(this)); | ||
Comment on lines
+14
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import Route from '@ember/routing/route'; | ||
|
||
export default class ServicesIndexRoute extends Route {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import ApplicationSerializer from './application'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
@classic | ||
export default class ServiceFragmentSerializer extends ApplicationSerializer { | ||
attrs = { | ||
connect: 'Connect', | ||
}; | ||
|
||
arrayNullOverrides = ['Tags']; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<Breadcrumb @crumb={{hash label="Services" args=(array "services.index")}} /> | ||
<PageLayout> | ||
{{outlet}} | ||
</PageLayout> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{{page-title "Services"}} | ||
<section class="section"> | ||
<ListTable | ||
@source={{this.model.services}} | ||
as |t| | ||
> | ||
<t.head> | ||
<th> | ||
Name | ||
</th> | ||
<th> | ||
Tags | ||
</th> | ||
</t.head> | ||
<t.body as |row|> | ||
<tr data-test-service-row> | ||
<td>{{row.model.name}}</td> | ||
<td> | ||
{{#each row.model.tags as |tag|}} | ||
<span class="tag">{{tag}}</span> | ||
{{/each}} | ||
</td> | ||
</tr> | ||
</t.body> | ||
</ListTable> | ||
</section> | ||
Comment on lines
+1
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -863,6 +863,17 @@ export default function () { | |
}); | ||
|
||
//#endregion Secure Variables | ||
|
||
//#region Services | ||
this.get('/services', function (schema) { | ||
return [ | ||
{ | ||
Namespace: 'default', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
Services: schema.services.all().models, | ||
}, | ||
]; | ||
}); | ||
//#endregion Services | ||
} | ||
|
||
function filterKeys(object, ...keys) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Factory } from 'ember-cli-mirage'; | ||
import faker from 'nomad-ui/mirage/faker'; | ||
import { provide } from '../utils'; | ||
import { dasherize } from '@ember/string'; | ||
|
||
const ON_UPDATE = ['default', 'ignore', 'ignore_warnings']; | ||
|
||
export default Factory.extend({ | ||
name: (id) => `${dasherize(faker.hacker.noun())}-${id}-service`, | ||
portLabel: () => dasherize(faker.hacker.noun()), | ||
onUpdate: faker.helpers.randomize(ON_UPDATE), | ||
tags: () => { | ||
if (!faker.random.boolean()) { | ||
return provide( | ||
faker.random.number({ min: 0, max: 2 }), | ||
faker.hacker.noun.bind(faker.hacker.noun) | ||
); | ||
} else { | ||
return null; | ||
} | ||
}, | ||
Connect: { | ||
SidecarService: { | ||
Proxy: { | ||
Upstreams: [ | ||
{ | ||
DestinationName: dasherize(faker.hacker.noun()), | ||
LocalBindPort: faker.random.number({ min: 5000, max: 60000 }), | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,11 @@ | ||
import { Factory } from 'ember-cli-mirage'; | ||
import faker from 'nomad-ui/mirage/faker'; | ||
import { pickOne } from '../utils'; | ||
import { provide } from '../utils'; | ||
Comment on lines
+3
to
4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
import { dasherize } from '@ember/string'; | ||
|
||
const ON_UPDATE = ['default', 'ignore', 'ignore_warnings']; | ||
|
||
export default Factory.extend({ | ||
name: (id) => `${dasherize(faker.hacker.noun())}-${id}-service`, | ||
portLabel: () => dasherize(faker.hacker.noun()), | ||
onUpdate: faker.helpers.randomize(ON_UPDATE), | ||
tags: () => { | ||
ServiceName: () => `${faker.hacker.adjective()}-${faker.hacker.noun()}`, | ||
Tags: () => { | ||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if (!faker.random.boolean()) { | ||
return provide( | ||
faker.random.number({ min: 0, max: 2 }), | ||
|
@@ -19,16 +15,4 @@ export default Factory.extend({ | |
return null; | ||
} | ||
}, | ||
Connect: { | ||
SidecarService: { | ||
Proxy: { | ||
Upstreams: [ | ||
{ | ||
DestinationName: dasherize(faker.hacker.noun()), | ||
LocalBindPort: faker.random.number({ min: 5000, max: 60000 }), | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { module, test } from 'qunit'; | ||
import { visit, currentURL, findAll } from '@ember/test-helpers'; | ||
import { setupApplicationTest } from 'ember-qunit'; | ||
import { setupMirage } from 'ember-cli-mirage/test-support'; | ||
import percySnapshot from '@percy/ember'; | ||
import Services from 'nomad-ui/tests/pages/services'; | ||
import Layout from 'nomad-ui/tests/pages/layout'; | ||
import defaultScenario from '../../mirage/scenarios/default'; | ||
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; | ||
|
||
module('Acceptance | services', function (hooks) { | ||
setupApplicationTest(hooks); | ||
setupMirage(hooks); | ||
|
||
test('it passes an accessibility audit', async function (assert) { | ||
assert.expect(1); | ||
defaultScenario(server); | ||
await Services.visit(); | ||
await a11yAudit(assert); | ||
}); | ||
|
||
module('traversal', function () { | ||
test('visiting /services by url', async function (assert) { | ||
defaultScenario(server); | ||
await Services.visit(); | ||
assert.equal(currentURL(), '/services'); | ||
}); | ||
|
||
test('main menu correctly takes you to services', async function (assert) { | ||
assert.expect(1); | ||
defaultScenario(server); | ||
await visit('/'); | ||
await Layout.gutter.visitServices(); | ||
assert.equal(currentURL(), '/services'); | ||
await percySnapshot(assert); | ||
}); | ||
}); | ||
|
||
module('services index table', function () { | ||
test('services table shows expected number of services', async function (assert) { | ||
server.createList('service', 3); | ||
await Services.visit(); | ||
assert.equal( | ||
findAll('[data-test-service-row]').length, | ||
3, | ||
'correctly shows 3 services' | ||
); | ||
Comment on lines
+40
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { create, visitable } from 'ember-cli-page-object'; | ||
|
||
export default create({ | ||
visit: visitable('/services'), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
: Unused import.