Skip to content

Commit

Permalink
UI: Add copy button for client/allocation UUIDs (#5926)
Browse files Browse the repository at this point in the history
The button shows a success icon and tooltip on click, and resets
after two seconds.
  • Loading branch information
backspace committed Jul 15, 2019
1 parent 2d5aa6d commit 596b5aa
Show file tree
Hide file tree
Showing 16 changed files with 237 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ IMPROVEMENTS:
* driver/docker: Added logging defaults to use json-file log driver with log rotation [[GH-5846](https://github.com/hashicorp/nomad/pull/5846)]
* 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)]

BUG FIXES:

Expand Down
2 changes: 2 additions & 0 deletions ui/app/components/addon-copy-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This lets us use copy-button to wrap ember-cli-clipboard’s component
export { default } from 'ember-cli-clipboard/components/copy-button';
16 changes: 16 additions & 0 deletions ui/app/components/copy-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Component from '@ember/component';
import { task, timeout } from 'ember-concurrency';

export default Component.extend({
classNames: ['copy-button'],

clipboardText: null,
state: null,

indicateSuccess: task(function*() {
this.set('state', 'success');

yield timeout(2000);
this.set('state', null);
}).restartable(),
});
1 change: 1 addition & 0 deletions ui/app/styles/components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import './components/badge';
@import './components/boxed-section';
@import './components/codemirror';
@import './components/copy-button';
@import './components/cli-window';
@import './components/dropdown';
@import './components/ember-power-select';
Expand Down
16 changes: 16 additions & 0 deletions ui/app/styles/components/copy-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.copy-button {
padding-left: 0.5rem;
margin-bottom: 2px;

.button {
color: inherit;

&.is-static {
background-color: inherit;
}

svg {
fill: currentColor;
}
}
}
7 changes: 5 additions & 2 deletions ui/app/styles/components/tooltip.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.tooltip {
position: relative;
pointer-events: all;
}

.tooltip::after {
Expand Down Expand Up @@ -45,12 +46,14 @@
transition: top 0.1s ease-in-out;
}

.tooltip:hover::after {
.tooltip:hover::after,
.tooltip.always-active::after {
opacity: 1;
bottom: 120%;
}

.tooltip:hover::before {
.tooltip:hover::before,
.tooltip.always-active::before {
opacity: 1;
top: -20%;
}
5 changes: 5 additions & 0 deletions ui/app/styles/core/buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ $button-box-shadow-standard: 0 2px 0 0 rgba($grey, 0.2);
}
}

&.is-borderless {
border: 0;
box-shadow: none;
}

@each $name, $pair in $colors {
$color: nth($pair, 1);
$color-invert: nth($pair, 2);
Expand Down
5 changes: 4 additions & 1 deletion ui/app/templates/allocations/allocation/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
<h1 data-test-title class="title with-headroom">
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>
<span class="tag is-hollow is-small no-text-transform">
{{model.id}}
{{copy-button clipboardText=model.id}}
</span>
{{#if model.isRunning}}
{{two-step-button
data-test-stop
Expand Down
5 changes: 4 additions & 1 deletion ui/app/templates/clients/client.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<h1 data-test-title class="title">
<span data-test-node-status="{{model.compositeStatus}}" class="node-status-light {{model.compositeStatus}}"></span>
{{or model.name model.shortId}}
<span class="tag is-hollow is-small no-text-transform">{{model.id}}</span>
<span class="tag is-hollow is-small no-text-transform">
{{model.id}}
{{copy-button clipboardText=model.id}}
</span>
</h1>

<div class="boxed-section is-small">
Expand Down
22 changes: 22 additions & 0 deletions ui/app/templates/components/copy-button.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{#if (eq state 'success')}}
<div class='button is-borderless is-small is-static'>
<span class="tooltip text-center always-active" role="tooltip" aria-label="Copied!">
{{x-icon 'copy-success'}}
</span>
</div>
{{else if (eq state 'error')}}
<div class='button is-borderless is-small is-static'>
<span class="tooltip text-center" role="tooltip" aria-label="Error copying">
{{x-icon 'alert-triangle'}}
</span>
</div>
{{else}}
{{#addon-copy-button
class='button is-borderless is-small'
clipboardText=clipboardText
success=(perform indicateSuccess)
error=(action (mut state) 'error')
}}
{{x-icon 'copy-action'}}
{{/addon-copy-button}}
{{/if}}
6 changes: 6 additions & 0 deletions ui/app/templates/components/freestyle/sg-copy-button.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{#freestyle-usage "copy-button" title="Copy Button"}}
<span class="tag is-hollow is-small no-text-transform">
e8c898a0-794b-9063-7a7f-bf0c4a405f83
{{copy-button clipboardText="e8c898a0-794b-9063-7a7f-bf0c4a405f83"}}
</span>
{{/freestyle-usage}}
4 changes: 4 additions & 0 deletions ui/app/templates/freestyle.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
{{freestyle/sg-buttons}}
{{/section.subsection}}

{{#section.subsection name="Copy Button"}}
{{freestyle/sg-copy-button}}
{{/section.subsection}}

{{#section.subsection name="Diff Viewer"}}
{{freestyle/sg-diff-viewer}}
{{/section.subsection}}
Expand Down
2 changes: 1 addition & 1 deletion ui/ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = function(defaults) {
blacklist: isProd ? ['ember-freestyle'] : [],
},
svg: {
paths: ['public/images/icons'],
paths: ['node_modules/@hashicorp/structure-icons/dist', 'public/images/icons'],
optimize: {
plugins: [{ removeViewBox: false }],
},
Expand Down
3 changes: 3 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.4.3",
"@ember/jquery": "^0.6.0",
"@ember/optional-features": "^0.7.0",
"@hashicorp/structure-icons": "^1.3.0",
"broccoli-asset-rev": "^3.0.0",
"bulma": "0.6.1",
"core-js": "^2.4.1",
Expand All @@ -44,6 +45,7 @@
"ember-auto-import": "^1.2.21",
"ember-cli": "~3.4.4",
"ember-cli-babel": "^7.1.2",
"ember-cli-clipboard": "^0.13.0",
"ember-cli-dependency-checker": "^3.0.0",
"ember-cli-deprecation-workflow": "^1.0.1",
"ember-cli-eslint": "^5.1.0",
Expand Down Expand Up @@ -92,6 +94,7 @@
"lodash.intersection": "^4.4.0",
"prettier": "^1.4.4",
"query-string": "^5.0.0",
"qunit-dom": "^0.9.0",
"sass": "^1.17.3"
},
"engines": {
Expand Down
45 changes: 45 additions & 0 deletions ui/tests/integration/components/copy-button-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { click, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';

import sinon from 'sinon';

import { triggerCopyError, triggerCopySuccess } from 'ember-cli-clipboard/test-support';

module('Integration | Component | copy-button', function(hooks) {
setupRenderingTest(hooks);

test('it shows the copy icon by default', async function(assert) {
await render(hbs`{{copy-button class='copy-button'}}`);

assert.dom('.copy-button .icon-is-copy-action').exists();
});

test('it shows the success icon on success and resets afterward', async function(assert) {
const clock = sinon.useFakeTimers();

await render(hbs`{{copy-button class='copy-button'}}`);

await click('.copy-button button');
await triggerCopySuccess('.copy-button button');

assert.dom('.copy-button .icon-is-copy-success').exists();

clock.runAll();

assert.dom('.copy-button .icon-is-copy-success').doesNotExist();
assert.dom('.copy-button .icon-is-copy-action').exists();

clock.restore();
});

test('it shows the error icon on error', async function(assert) {
await render(hbs`{{copy-button class='copy-button'}}`);

await click('.copy-button button');
await triggerCopyError('.copy-button button');

assert.dom('.copy-button .icon-is-alert-triangle').exists();
});
});
Loading

0 comments on commit 596b5aa

Please sign in to comment.