diff --git a/.changelog/10062.txt b/.changelog/10062.txt new file mode 100644 index 000000000..0dfb118f1 --- /dev/null +++ b/.changelog/10062.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Added humanized formatting to lock session durations +``` diff --git a/.circleci/config.yml b/.circleci/config.yml index b4f98c96c..8314f7ef5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ references: test-results: &TEST_RESULTS_DIR /tmp/test-results cache: - yarn: &YARN_CACHE_KEY consul-ui-v3-{{ checksum "ui/yarn.lock" }} + yarn: &YARN_CACHE_KEY consul-ui-v4-{{ checksum "ui/yarn.lock" }} rubygem: &RUBYGEM_CACHE_KEY static-site-gems-v1-{{ checksum "Gemfile.lock" }} environment: &ENVIRONMENT diff --git a/ui/packages/consul-ui/app/components/consul/lock-session/form/index.hbs b/ui/packages/consul-ui/app/components/consul/lock-session/form/index.hbs index 5872006d4..70a9d6809 100644 --- a/ui/packages/consul-ui/app/components/consul/lock-session/form/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/lock-session/form/index.hbs @@ -28,7 +28,7 @@
{{api.data.Behavior}}
{{#if form.data.Delay }}
Delay
-
{{api.data.LockDelay}}
+
{{duration-from api.data.LockDelay}}
{{/if}} {{#if form.data.TTL }}
TTL
diff --git a/ui/packages/consul-ui/app/components/consul/lock-session/list/index.hbs b/ui/packages/consul-ui/app/components/consul/lock-session/list/index.hbs index 6f3a16de2..d0dcd35ac 100644 --- a/ui/packages/consul-ui/app/components/consul/lock-session/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/lock-session/list/index.hbs @@ -19,7 +19,7 @@ Delay -
{{item.LockDelay}}
+
{{duration-from item.LockDelay}}
diff --git a/ui/packages/consul-ui/app/helpers/duration-from.js b/ui/packages/consul-ui/app/helpers/duration-from.js new file mode 100644 index 000000000..63f2e6257 --- /dev/null +++ b/ui/packages/consul-ui/app/helpers/duration-from.js @@ -0,0 +1,10 @@ +import Helper from '@ember/component/helper'; +import { inject as service } from '@ember/service'; + +export default class DurationFromHelper extends Helper { + @service('temporal') temporal; + + compute([value], hash) { + return this.temporal.durationFrom(value); + } +} diff --git a/ui/packages/consul-ui/app/helpers/duration-from.mdx b/ui/packages/consul-ui/app/helpers/duration-from.mdx new file mode 100644 index 000000000..acc1b4e9a --- /dev/null +++ b/ui/packages/consul-ui/app/helpers/duration-from.mdx @@ -0,0 +1,13 @@ +# duration-from + +`{{duration-from nanoseconds}}` is used to format a number in nanoseconds to a +short golang-like human format, for example: + +```hbs preview-template +

{{duration-from 15000000000}}

+

{{duration-from 15000010001}}

+``` + +**Note:** The helper only accepts a javascript number primitive currently + +Also see the `temporal` service for the implementation. diff --git a/ui/packages/consul-ui/app/services/temporal.js b/ui/packages/consul-ui/app/services/temporal.js new file mode 100644 index 000000000..a5b9884ad --- /dev/null +++ b/ui/packages/consul-ui/app/services/temporal.js @@ -0,0 +1,21 @@ +import format from 'pretty-ms'; +import { assert } from '@ember/debug'; + +import Service from '@ember/service'; + +export default class TemporalService extends Service { + durationFrom(value, options = {}) { + switch (true) { + case typeof value === 'number': + // if its zero, don't format just return zero as a string + if (value === 0) { + return '0'; + } + return format(value / 1000000, { formatSubMilliseconds: true }) + .split(' ') + .join(''); + } + assert(`${value} is not a valid type`, false); + return value; + } +} diff --git a/ui/packages/consul-ui/package.json b/ui/packages/consul-ui/package.json index f776022db..473a5c3ba 100644 --- a/ui/packages/consul-ui/package.json +++ b/ui/packages/consul-ui/package.json @@ -153,6 +153,7 @@ "parse-duration": "^1.0.0", "pretender": "^3.2.0", "prettier": "^1.10.2", + "pretty-ms": "^7.0.1", "qunit-dom": "^1.0.0", "react-is": "^17.0.1", "refractor": "^3.3.1", diff --git a/ui/packages/consul-ui/tests/acceptance/dc/nodes/sessions/list.feature b/ui/packages/consul-ui/tests/acceptance/dc/nodes/sessions/list.feature index 28e1859b0..916781d18 100644 --- a/ui/packages/consul-ui/tests/acceptance/dc/nodes/sessions/list.feature +++ b/ui/packages/consul-ui/tests/acceptance/dc/nodes/sessions/list.feature @@ -26,16 +26,17 @@ Feature: dc / nodes / sessions / list: List Lock Sessions - 30s - 60m --- - Scenario: Given 2 session with LockDelay in milliseconds + Scenario: Given 3 session with LockDelay in nanoseconds Given 1 datacenter model with the value "dc1" And 1 node model from yaml --- ID: node-0 --- - And 2 session models from yaml + And 3 session models from yaml --- - LockDelay: 120000 - LockDelay: 18000000 + - LockDelay: 15000000000 --- When I visit the node page for yaml --- @@ -46,6 +47,7 @@ Feature: dc / nodes / sessions / list: List Lock Sessions Then I see lockSessionsIsSelected on the tabs Then I see delay on the sessions like yaml --- - - 120000 - - 18000000 + - 120µs + - 18ms + - 15s --- diff --git a/ui/packages/consul-ui/tests/integration/helpers/duration-from-test.js b/ui/packages/consul-ui/tests/integration/helpers/duration-from-test.js new file mode 100644 index 000000000..6d1473de5 --- /dev/null +++ b/ui/packages/consul-ui/tests/integration/helpers/duration-from-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | duration-from', function(hooks) { + setupRenderingTest(hooks); + + // TODO: Replace this with your real tests. + test('it renders', async function(assert) { + this.set('inputValue', 15000000000); + + await render(hbs`{{duration-from inputValue}}`); + + assert.equal(this.element.textContent.trim(), '15s'); + }); +}); diff --git a/ui/packages/consul-ui/tests/unit/services/temporal-test.js b/ui/packages/consul-ui/tests/unit/services/temporal-test.js new file mode 100644 index 000000000..2b66564a6 --- /dev/null +++ b/ui/packages/consul-ui/tests/unit/services/temporal-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Service | temporal', function(hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function(assert) { + let service = this.owner.lookup('service:temporal'); + assert.ok(service); + }); +}); diff --git a/ui/yarn.lock b/ui/yarn.lock index ac319b71d..825c3edaf 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -11093,6 +11093,11 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-ms@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" + integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -11336,6 +11341,13 @@ prettier@^1.10.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +pretty-ms@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.1.tgz#7d903eaab281f7d8e03c66f867e239dc32fb73e8" + integrity sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q== + dependencies: + parse-ms "^2.1.0" + printf@^0.5.1: version "0.5.3" resolved "https://registry.yarnpkg.com/printf/-/printf-0.5.3.tgz#8b7eec278d886833312238b2bf42b2b6f250880a"