From 771513ffb332dab77886643ad94bc89d0053864c Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 28 Sep 2020 14:29:09 -0400 Subject: [PATCH 1/6] feat: Add clipboard node module --- ui/core/package.json | 3 ++- yarn.lock | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/core/package.json b/ui/core/package.json index ee54d5c47..b5fac0049 100644 --- a/ui/core/package.json +++ b/ui/core/package.json @@ -84,7 +84,8 @@ "qunit-dom": "^1.0.0", "rose": "*", "sass": "^1.26.5", - "sass-lint": "^1.13.1" + "sass-lint": "^1.13.1", + "clipboard": "^2.0.6" }, "engines": { "node": "10.* || >= 12" diff --git a/yarn.lock b/yarn.lock index a205584da..e8826e237 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7307,7 +7307,7 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== -clipboard@^2.0.0: +clipboard@^2.0.0, clipboard@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== From f88b7e848baa9885379d4fe28bc23c82b8e5a0ca Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 28 Sep 2020 14:41:40 -0400 Subject: [PATCH 2/6] feat: Add clipboardjs to vendor --- ui/core/ember-cli-build.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui/core/ember-cli-build.js b/ui/core/ember-cli-build.js index cc31a1b6c..25d88f3cc 100644 --- a/ui/core/ember-cli-build.js +++ b/ui/core/ember-cli-build.js @@ -20,6 +20,14 @@ module.exports = function (defaults) { }, }); + // Only import when in development or test mode + if (app.env.match(/(development)|(test)/i)) { + app.import('node_modules/clipboard/dist/clipboard.js'); + } + else { + app.import('node_modules/clipboard/dist/clipboard.min.js'); + } + // Use `app.import` to add additional libraries to the generated // output files. // From c7b49920f6ae65c4c5a648c63c401ed1ccb2073c Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 28 Sep 2020 14:43:02 -0400 Subject: [PATCH 3/6] feat: Add empty copy-button component to ui/core --- ui/core/app/components/copy-button/index.hbs | 1 + ui/core/app/components/copy-button/index.js | 4 +++ .../components/copy-button-test.js | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 ui/core/app/components/copy-button/index.hbs create mode 100644 ui/core/app/components/copy-button/index.js create mode 100644 ui/core/tests/integration/components/copy-button-test.js diff --git a/ui/core/app/components/copy-button/index.hbs b/ui/core/app/components/copy-button/index.hbs new file mode 100644 index 000000000..fb5c4b157 --- /dev/null +++ b/ui/core/app/components/copy-button/index.hbs @@ -0,0 +1 @@ +{{yield}} \ No newline at end of file diff --git a/ui/core/app/components/copy-button/index.js b/ui/core/app/components/copy-button/index.js new file mode 100644 index 000000000..1e32d2663 --- /dev/null +++ b/ui/core/app/components/copy-button/index.js @@ -0,0 +1,4 @@ +import Component from '@glimmer/component'; + +export default class CopyButtonComponent extends Component { +} diff --git a/ui/core/tests/integration/components/copy-button-test.js b/ui/core/tests/integration/components/copy-button-test.js new file mode 100644 index 000000000..428596788 --- /dev/null +++ b/ui/core/tests/integration/components/copy-button-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | copy-button', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); From c937d948223f84134cec839d68eaf985a982b493 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 29 Sep 2020 11:13:26 -0400 Subject: [PATCH 4/6] feat: Use clipboardjs library in copy-button component --- ui/core/app/components/copy-button/index.hbs | 20 +++++- ui/core/app/components/copy-button/index.js | 72 +++++++++++++++++++ ui/core/package.json | 5 +- .../components/copy-button-test.js | 20 ++---- ui/core/translations/actions/en-us.yaml | 1 + yarn.lock | 10 ++- 6 files changed, 108 insertions(+), 20 deletions(-) diff --git a/ui/core/app/components/copy-button/index.hbs b/ui/core/app/components/copy-button/index.hbs index fb5c4b157..94dca5ce1 100644 --- a/ui/core/app/components/copy-button/index.hbs +++ b/ui/core/app/components/copy-button/index.hbs @@ -1 +1,19 @@ -{{yield}} \ No newline at end of file +{{#if this.isClipboardLibrarySupported}} + + + {{yield}} + + + + +{{else}} + {{yield}} +{{/if}} diff --git a/ui/core/app/components/copy-button/index.js b/ui/core/app/components/copy-button/index.js index 1e32d2663..33f444ed0 100644 --- a/ui/core/app/components/copy-button/index.js +++ b/ui/core/app/components/copy-button/index.js @@ -1,4 +1,76 @@ import Component from '@glimmer/component'; +import ClipboardJS from 'clipboard'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { generateComponentID } from 'rose/utilities/component-auto-id'; +import { task, timeout } from 'ember-concurrency'; +import { set } from '@ember/object'; +import { bind } from '@ember/runloop'; export default class CopyButtonComponent extends Component { + + // =attributes + + id = generateComponentID(); + targetId = `copy-target-${this.id}`; + icon = 'copy-action'; + + @tracked clipboard; + + /** + * A Ember Concurrency-based task that updates copy icon to a success state + * and back after 1 second. This icon flash indicates success on + * copy to clipboard action. + * + * NOTE: tasks are sort of attributes and sort of methods, but they are not + * language-level constructs. Thus we annotate this task as if it + * is an attribute. + * @type {Task} + */ + @task(function * () { + set(this, 'icon', 'copy-success'); + yield timeout(1000); + set(this, 'icon', 'copy-action'); + }).drop() successIconTimer; + + // =methods + + /** + * Checks for ClipboardJS support. + * @return {boolean} + */ + get isClipboardLibrarySupported() { + return ClipboardJS?.isSupported(); + } + + /** + * When copy to clipboard is successful, begin timer to show success icon. + */ + onCopySuccess(clipboardEvent) { + clipboardEvent.clearSelection(); + this.successIconTimer.perform(); + } + + // =actions + + /** + * Initialize ClipboardJS library and register for it's events. + */ + @action + register() { + if(!this.clipboard) { + this.clipboard = new ClipboardJS('.copy-button'); + this.clipboard.on('success', bind(this, this.onCopySuccess)); + } + } + + /** + * Destroy ClipboardJS library instance and cancel icon timer. + */ + @action + destroy() { + this.clipboard?.destroy(); + this.successIconTimer.cancelAll(); + } + } diff --git a/ui/core/package.json b/ui/core/package.json index b5fac0049..6b6547fbd 100644 --- a/ui/core/package.json +++ b/ui/core/package.json @@ -29,6 +29,7 @@ "devDependencies": { "@babel/core": "^7.9.6", "@ember/optional-features": "^1.3.0", + "@ember/render-modifiers": "^1.0.2", "@glimmer/component": "^1.0.0", "@glimmer/tracking": "^1.0.0", "api": "*", @@ -36,6 +37,7 @@ "babel-eslint": "^10.0.3", "babel-loader": "^8.1.0", "broccoli-asset-rev": "^3.0.0", + "clipboard": "^2.0.6", "doctoc": "^1.4.0", "ember-a11y-testing": "^3.0.0", "ember-auto-import": "^1.5.3", @@ -84,8 +86,7 @@ "qunit-dom": "^1.0.0", "rose": "*", "sass": "^1.26.5", - "sass-lint": "^1.13.1", - "clipboard": "^2.0.6" + "sass-lint": "^1.13.1" }, "engines": { "node": "10.* || >= 12" diff --git a/ui/core/tests/integration/components/copy-button-test.js b/ui/core/tests/integration/components/copy-button-test.js index 428596788..be5d05a01 100644 --- a/ui/core/tests/integration/components/copy-button-test.js +++ b/ui/core/tests/integration/components/copy-button-test.js @@ -1,26 +1,14 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; +import { render, find } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; module('Integration | Component | copy-button', function(hooks) { setupRenderingTest(hooks); test('it renders', async function(assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); + await render(hbs`text`); + assert.ok(find('.copy-button')); + assert.equal(find('.copy-target').textContent.trim(), 'text'); }); }); diff --git a/ui/core/translations/actions/en-us.yaml b/ui/core/translations/actions/en-us.yaml index 40a38941d..5598ee942 100644 --- a/ui/core/translations/actions/en-us.yaml +++ b/ui/core/translations/actions/en-us.yaml @@ -28,3 +28,4 @@ add-hosts: Add Hosts set-password: Set Password change-password: Change Password edit-form: Edit Form +copy: Copy \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e8826e237..f13b0ae16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2543,6 +2543,14 @@ ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" +"@ember/render-modifiers@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@ember/render-modifiers/-/render-modifiers-1.0.2.tgz#2e87c48db49d922ce4850d707215caaac60d8444" + integrity sha512-6tEnHl5+62NTSAG2mwhGMFPhUrJQjoVqV+slsn+rlTknm2Zik+iwxBQEbwaiQOU1FUYxkS8RWcieovRNMR8inQ== + dependencies: + ember-cli-babel "^7.10.0" + ember-modifier-manager-polyfill "^1.1.0" + "@ember/test-helpers@^1.7.0", "@ember/test-helpers@^1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.7.1.tgz#cc22a954b3b46856518f034bd492a74e0482389f" @@ -9601,7 +9609,7 @@ ember-maybe-import-regenerator@^0.1.5, ember-maybe-import-regenerator@^0.1.6: ember-cli-babel "^6.0.0-beta.4" regenerator-runtime "^0.9.5" -ember-modifier-manager-polyfill@^1.2.0: +ember-modifier-manager-polyfill@^1.1.0, ember-modifier-manager-polyfill@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ember-modifier-manager-polyfill/-/ember-modifier-manager-polyfill-1.2.0.tgz#cf4444e11a42ac84f5c8badd85e635df57565dda" integrity sha512-bnaKF1LLKMkBNeDoetvIJ4vhwRPKIIumWr6dbVuW6W6p4QV8ZiO+GdF8J7mxDNlog9CeL9Z/7wam4YS86G8BYA== From 788dab94caef634d7782f0d6a7efe605fd9ea8d3 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 29 Sep 2020 15:08:21 -0400 Subject: [PATCH 5/6] refactor: CopyButton to Copyable component --- ui/core/app/components/copy-button/index.hbs | 19 --------------- ui/core/app/components/copyable/index.hbs | 23 +++++++++++++++++++ .../{copy-button => copyable}/index.js | 7 +++--- ui/core/app/styles/app.scss | 4 ++++ .../components/copy-button-test.js | 14 ----------- .../integration/components/copyable-test.js | 15 ++++++++++++ ui/core/translations/actions/en-us.yaml | 3 +-- 7 files changed, 46 insertions(+), 39 deletions(-) delete mode 100644 ui/core/app/components/copy-button/index.hbs create mode 100644 ui/core/app/components/copyable/index.hbs rename ui/core/app/components/{copy-button => copyable}/index.js (89%) delete mode 100644 ui/core/tests/integration/components/copy-button-test.js create mode 100644 ui/core/tests/integration/components/copyable-test.js diff --git a/ui/core/app/components/copy-button/index.hbs b/ui/core/app/components/copy-button/index.hbs deleted file mode 100644 index 94dca5ce1..000000000 --- a/ui/core/app/components/copy-button/index.hbs +++ /dev/null @@ -1,19 +0,0 @@ -{{#if this.isClipboardLibrarySupported}} - - - {{yield}} - - - - -{{else}} - {{yield}} -{{/if}} diff --git a/ui/core/app/components/copyable/index.hbs b/ui/core/app/components/copyable/index.hbs new file mode 100644 index 000000000..848fa7685 --- /dev/null +++ b/ui/core/app/components/copyable/index.hbs @@ -0,0 +1,23 @@ +{{#if this.isClipboardLibrarySupported}} + + + {{yield}} + + + {{@text}} + +{{else}} + {{yield}} +{{/if}} diff --git a/ui/core/app/components/copy-button/index.js b/ui/core/app/components/copyable/index.js similarity index 89% rename from ui/core/app/components/copy-button/index.js rename to ui/core/app/components/copyable/index.js index 33f444ed0..f77b4a4d9 100644 --- a/ui/core/app/components/copy-button/index.js +++ b/ui/core/app/components/copyable/index.js @@ -7,12 +7,11 @@ import { task, timeout } from 'ember-concurrency'; import { set } from '@ember/object'; import { bind } from '@ember/runloop'; -export default class CopyButtonComponent extends Component { +export default class CopyableComponent extends Component { // =attributes id = generateComponentID(); - targetId = `copy-target-${this.id}`; icon = 'copy-action'; @tracked clipboard; @@ -40,7 +39,7 @@ export default class CopyButtonComponent extends Component { * @return {boolean} */ get isClipboardLibrarySupported() { - return ClipboardJS?.isSupported(); + return ClipboardJS.isSupported(); } /** @@ -59,7 +58,7 @@ export default class CopyButtonComponent extends Component { @action register() { if(!this.clipboard) { - this.clipboard = new ClipboardJS('.copy-button'); + this.clipboard = new ClipboardJS('.copyable-button'); this.clipboard.on('success', bind(this, this.onCopySuccess)); } } diff --git a/ui/core/app/styles/app.scss b/ui/core/app/styles/app.scss index b1a6af3c1..9e72b055f 100644 --- a/ui/core/app/styles/app.scss +++ b/ui/core/app/styles/app.scss @@ -80,3 +80,7 @@ } } } + +.copyable .copyable-button { + padding: 0rem; +} diff --git a/ui/core/tests/integration/components/copy-button-test.js b/ui/core/tests/integration/components/copy-button-test.js deleted file mode 100644 index be5d05a01..000000000 --- a/ui/core/tests/integration/components/copy-button-test.js +++ /dev/null @@ -1,14 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render, find } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | copy-button', function(hooks) { - setupRenderingTest(hooks); - - test('it renders', async function(assert) { - await render(hbs`text`); - assert.ok(find('.copy-button')); - assert.equal(find('.copy-target').textContent.trim(), 'text'); - }); -}); diff --git a/ui/core/tests/integration/components/copyable-test.js b/ui/core/tests/integration/components/copyable-test.js new file mode 100644 index 000000000..07be2788f --- /dev/null +++ b/ui/core/tests/integration/components/copyable-test.js @@ -0,0 +1,15 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | copyable', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + await render(hbs`text`); + assert.ok(find('.copyable')); + assert.equal(find('.copyable-content').textContent.trim(), 'text'); + assert.equal(find('.copyable-button').textContent.trim(), 'Copy me'); + }); +}); diff --git a/ui/core/translations/actions/en-us.yaml b/ui/core/translations/actions/en-us.yaml index 5598ee942..7e7a9002a 100644 --- a/ui/core/translations/actions/en-us.yaml +++ b/ui/core/translations/actions/en-us.yaml @@ -27,5 +27,4 @@ add-members: Add Members add-hosts: Add Hosts set-password: Set Password change-password: Change Password -edit-form: Edit Form -copy: Copy \ No newline at end of file +edit-form: Edit Form \ No newline at end of file From 5febe3cb7df36440979788ae0f6e9be5d9738adc Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 30 Sep 2020 11:07:44 -0400 Subject: [PATCH 6/6] refactor: Specify copyable text during instantiation --- ui/core/app/components/copyable/index.hbs | 5 ++--- ui/core/app/components/copyable/index.js | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ui/core/app/components/copyable/index.hbs b/ui/core/app/components/copyable/index.hbs index 848fa7685..8d0a3df75 100644 --- a/ui/core/app/components/copyable/index.hbs +++ b/ui/core/app/components/copyable/index.hbs @@ -1,7 +1,7 @@ {{#if this.isClipboardLibrarySupported}} {{@text}} {{else}} diff --git a/ui/core/app/components/copyable/index.js b/ui/core/app/components/copyable/index.js index f77b4a4d9..01dcad838 100644 --- a/ui/core/app/components/copyable/index.js +++ b/ui/core/app/components/copyable/index.js @@ -12,8 +12,10 @@ export default class CopyableComponent extends Component { // =attributes id = generateComponentID(); + copyableButtonId = `copyable-button-${this.id}`; icon = 'copy-action'; + @tracked text; @tracked clipboard; /** @@ -58,7 +60,9 @@ export default class CopyableComponent extends Component { @action register() { if(!this.clipboard) { - this.clipboard = new ClipboardJS('.copyable-button'); + this.clipboard = new ClipboardJS(`#${this.copyableButtonId}`, { + text: () => this.args.text, + }); this.clipboard.on('success', bind(this, this.onCopySuccess)); } }