Merge pull request #3845 from hashicorp/f-ui-node-meta
UI: Add client meta attributes to the client detail page
This commit is contained in:
commit
d5254c1563
|
@ -9,8 +9,13 @@ export default Fragment.extend({
|
||||||
attributes: attr(),
|
attributes: attr(),
|
||||||
|
|
||||||
attributesStructured: computed('attributes', function() {
|
attributesStructured: computed('attributes', function() {
|
||||||
// `unflatten` doesn't sort keys before unflattening, so manual preprocessing is necessary.
|
|
||||||
const original = this.get('attributes');
|
const original = this.get('attributes');
|
||||||
|
|
||||||
|
if (!original) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `unflatten` doesn't sort keys before unflattening, so manual preprocessing is necessary.
|
||||||
const attrs = Object.keys(original)
|
const attrs = Object.keys(original)
|
||||||
.sort()
|
.sort()
|
||||||
.reduce((obj, key) => {
|
.reduce((obj, key) => {
|
||||||
|
|
|
@ -20,6 +20,7 @@ export default Model.extend({
|
||||||
httpAddr: attr('string'),
|
httpAddr: attr('string'),
|
||||||
tlsEnabled: attr('boolean'),
|
tlsEnabled: attr('boolean'),
|
||||||
attributes: fragment('node-attributes'),
|
attributes: fragment('node-attributes'),
|
||||||
|
meta: fragment('node-attributes'),
|
||||||
resources: fragment('resources'),
|
resources: fragment('resources'),
|
||||||
reserved: fragment('resources'),
|
reserved: fragment('resources'),
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,24 @@
|
||||||
attributes=model.attributes.attributesStructured
|
attributes=model.attributes.attributesStructured
|
||||||
class="attributes-table"}}
|
class="attributes-table"}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="boxed-section-head">
|
||||||
|
Meta
|
||||||
|
</div>
|
||||||
|
{{#if model.meta.attributesStructured}}
|
||||||
|
<div class="boxed-section-body is-full-bleed">
|
||||||
|
{{attributes-table
|
||||||
|
data-test-meta
|
||||||
|
attributes=model.meta.attributesStructured
|
||||||
|
class="attributes-table"}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="boxed-section-body">
|
||||||
|
<div data-test-empty-meta-message class="empty-message">
|
||||||
|
<h3 class="empty-message-headline">No Meta Attributes</h3>
|
||||||
|
<p class="empty-message-body">This client is configured with no meta attributes.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{{/gutter-menu}}
|
{{/gutter-menu}}
|
||||||
|
|
|
@ -58,6 +58,14 @@ export default Factory.extend({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
withMeta: trait({
|
||||||
|
meta: {
|
||||||
|
just: 'some',
|
||||||
|
prop: 'erties',
|
||||||
|
'over.here': 100,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
afterCreate(node, server) {
|
afterCreate(node, server) {
|
||||||
// Each node has a corresponding client stats resource that's queried via node IP.
|
// Each node has a corresponding client stats resource that's queried via node IP.
|
||||||
// Create that record, even though it's not a relationship.
|
// Create that record, even though it's not a relationship.
|
||||||
|
|
|
@ -197,9 +197,7 @@ test('each allocation should have high-level details for the allocation', functi
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('each allocation should show job information even if the job is incomplete and already in the store', function(
|
test('each allocation should show job information even if the job is incomplete and already in the store', function(assert) {
|
||||||
assert
|
|
||||||
) {
|
|
||||||
// First, visit clients to load the allocations for each visible node.
|
// First, visit clients to load the allocations for each visible node.
|
||||||
// Don't load the job belongsTo of the allocation! Leave it unfulfilled.
|
// Don't load the job belongsTo of the allocation! Leave it unfulfilled.
|
||||||
|
|
||||||
|
@ -288,9 +286,39 @@ test('/clients/:id should list all attributes for the node', function(assert) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('when the node is not found, an error message is shown, but the URL persists', function(
|
test('/clients/:id lists all meta attributes', function(assert) {
|
||||||
assert
|
node = server.create('node', 'forceIPv4', 'withMeta');
|
||||||
) {
|
|
||||||
|
visit(`/clients/${node.id}`);
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
assert.ok(find('[data-test-meta]'), 'Meta attributes table is on the page');
|
||||||
|
assert.notOk(find('[data-test-empty-meta-message]'), 'Meta attributes is not empty');
|
||||||
|
|
||||||
|
const firstMetaKey = Object.keys(node.meta)[0];
|
||||||
|
assert.equal(
|
||||||
|
find('[data-test-meta] [data-test-key]').textContent.trim(),
|
||||||
|
firstMetaKey,
|
||||||
|
'Meta attributes for the node are bound to the attributes table'
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
find('[data-test-meta] [data-test-value]').textContent.trim(),
|
||||||
|
node.meta[firstMetaKey],
|
||||||
|
'Meta attributes for the node are bound to the attributes table'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('/clients/:id shows an empty message when there is no meta data', function(assert) {
|
||||||
|
visit(`/clients/${node.id}`);
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
assert.notOk(find('[data-test-meta]'), 'Meta attributes table is not on the page');
|
||||||
|
assert.ok(find('[data-test-empty-meta-message]'), 'Meta attributes is empty');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('when the node is not found, an error message is shown, but the URL persists', function(assert) {
|
||||||
visit('/clients/not-a-real-node');
|
visit('/clients/not-a-real-node');
|
||||||
|
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
|
|
Loading…
Reference in New Issue