diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index 459380e62..dfd2362a4 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -49,3 +49,5 @@ grant_scope: origin: label: Origin URL description: The Boundary URL to which to connect (e.g. protocol://host:port) +proxy: + label: Proxy diff --git a/ui/desktop/app/components/copyable/index.hbs b/ui/desktop/app/components/copyable/index.hbs new file mode 100644 index 000000000..618f3315b --- /dev/null +++ b/ui/desktop/app/components/copyable/index.hbs @@ -0,0 +1,30 @@ + + + {{#if this.copied}} + + {{yield}} + + {{else}} + + {{yield}} + + {{/if}} + + {{#if this.isClipboardLibrarySupported}} + + {{this.actionText}} + + {{/if}} + diff --git a/ui/desktop/app/components/copyable/index.js b/ui/desktop/app/components/copyable/index.js new file mode 100644 index 000000000..17652e911 --- /dev/null +++ b/ui/desktop/app/components/copyable/index.js @@ -0,0 +1,78 @@ +import Component from '@glimmer/component'; +import ClipboardJS from 'clipboard'; +import { action } from '@ember/object'; +import { generateComponentID } from 'rose/utilities/component-auto-id'; +import { task, timeout } from 'ember-concurrency'; +import { tracked } from '@glimmer/tracking'; + +export default class CopyableComponent extends Component { + + // =attributes + + id = generateComponentID(); + copyableButtonId = `copyable-button-${this.id}`; + + actionIcon = 'copy-action'; + successIcon = 'copy-success'; + actionText = this.args.buttonText; + successText = this.args.acknowledgeText; + + @tracked copied = false; + + clipboard = null; + + /** + * 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} + */ + /* istanbul ignore next */ + @task(function * () { + this.copied = true; + yield timeout(1000); + this.copied = false; + }).drop() confirmCopyTimer; + + /** + * Checks for ClipboardJS support. + * @return {boolean} + */ + get isClipboardLibrarySupported() { + return ClipboardJS.isSupported(); + } + + // =actions + + /** + * Initialize ClipboardJS library and register for it's events. + */ + @action + register() { + this.destroy(); + /* istanbul ignore next */ + this.clipboard = new ClipboardJS(`#${this.copyableButtonId}`, { + text: () => this.args.text, + }); + /* istanbul ignore next */ + this.clipboard.on('success', (clipboardEvent) => { + clipboardEvent.clearSelection(); + this.confirmCopyTimer.perform(); + }); + } + + /** + * Destroy ClipboardJS library instance and cancel icon timer. + */ + @action + destroy() { + this.clipboard?.destroy(); + this.clipboard = null; + this.confirmCopyTimer.cancelAll(); + } + +} diff --git a/ui/desktop/app/styles/app.scss b/ui/desktop/app/styles/app.scss index 14d7233c2..d361d91f6 100644 --- a/ui/desktop/app/styles/app.scss +++ b/ui/desktop/app/styles/app.scss @@ -167,7 +167,7 @@ 0% { background-color: var(--action-subtler-1); } - + 100% { background-color: transparent; } diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 06056a0df..3d865e587 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -36,11 +36,13 @@ "devDependencies": { "@doyensec/electronegativity": "^1.7.0", "@ember/optional-features": "^1.3.0", + "@ember/render-modifiers": "^1.0.2", "@glimmer/component": "^1.0.1", "@glimmer/tracking": "^1.0.0", "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", "broccoli-asset-rev": "^3.0.0", + "clipboard": "^2.0.6", "core": "*", "doctoc": "^1.4.0", "ember-auto-import": "^1.6.0", diff --git a/ui/desktop/tests/integration/components/copyable-test.js b/ui/desktop/tests/integration/components/copyable-test.js new file mode 100644 index 000000000..f00a0b00a --- /dev/null +++ b/ui/desktop/tests/integration/components/copyable-test.js @@ -0,0 +1,17 @@ +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/yarn.lock b/yarn.lock index 31a9b5a0d..b4a5c0378 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6249,9 +6249,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001181: - version "1.0.30001181" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001181.tgz#4f0e5184e1ea7c3bf2727e735cbe7ca9a451d673" - integrity sha512-m5ul/ARCX50JB8BSNM+oiPmQrR5UmngaQ3QThTTp5HcIIQGP/nPBs82BYLE+tigzm3VW+F4BJIhUyaVtEweelQ== + version "1.0.30001183" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001183.tgz#7a57ba9d6584119bb5f2bc76d3cc47ba9356b3e2" + integrity sha512-7JkwTEE1hlRKETbCFd8HDZeLiQIUcl8rC6JgNjvHCNaxOeNmQ9V4LvQXRUsKIV2CC73qKxljwVhToaA3kLRqTw== capture-exit@^2.0.0: version "2.0.0" @@ -7540,7 +7540,7 @@ debug@~4.1.0: dependencies: ms "^2.1.1" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -12357,7 +12357,7 @@ import-lazy@^4.0.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -14058,6 +14058,11 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= + lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -14066,11 +14071,16 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= + lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -14080,12 +14090,19 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= @@ -14298,7 +14315,7 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=