From b4b816f5fb575be91ce81e587cdec946771338fe Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 30 Oct 2024 11:42:11 -0600 Subject: [PATCH 01/17] initial changes need to add test coverage --- ui/app/styles/components/codemirror.scss | 6 ++++++ ui/lib/core/addon/components/json-editor.hbs | 11 +++++++++-- ui/lib/core/addon/components/json-editor.js | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ui/app/styles/components/codemirror.scss b/ui/app/styles/components/codemirror.scss index 49cd9d2d3330..c8e40cd23cd8 100644 --- a/ui/app/styles/components/codemirror.scss +++ b/ui/app/styles/components/codemirror.scss @@ -172,6 +172,12 @@ $gutter-grey: #2a2f36; } } +.expanded-codemirror > .cm-s-hashi { + &.CodeMirror { + height: 100%; + } +} + .readonly-codemirror { .CodeMirror-code { cursor: default; diff --git a/ui/lib/core/addon/components/json-editor.hbs b/ui/lib/core/addon/components/json-editor.hbs index 28b784a9e439..bac400a72e51 100644 --- a/ui/lib/core/addon/components/json-editor.hbs +++ b/ui/lib/core/addon/components/json-editor.hbs @@ -26,6 +26,14 @@ /> {{/if}}
+ - {{#if @helpText}}

{{@helpText}}

diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index 66507a6181cd..9d693e007833 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -5,6 +5,7 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; /** * @module JsonEditor @@ -32,6 +33,16 @@ import { action } from '@ember/object'; */ export default class JsonEditorComponent extends Component { + @tracked showExpandedView = false; + + get isExpanded() { + return this.showExpandedView ? 'expanded-codemirror' : ''; + } + + get isReadOnly() { + return this.args.readOnly ? 'readonly-codemirror' : ''; + } + get getShowToolbar() { return this.args.showToolbar === false ? false : true; } @@ -57,6 +68,12 @@ export default class JsonEditorComponent extends Component { } } + @action + toggleExpandView() { + // adds or removes the class 'expanded' to .cm-s-hashi .CodeMirror + this.args.valueUpdated(null, this._codemirrorEditor); + } + @action restoreExample() { // set value to null which will cause the example value to be passed into the editor From f4776be921aeb55e9a7dc8fca87e3cd40d58e57e Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 30 Oct 2024 11:58:37 -0600 Subject: [PATCH 02/17] change icon --- ui/lib/core/addon/components/json-editor.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/lib/core/addon/components/json-editor.hbs b/ui/lib/core/addon/components/json-editor.hbs index bac400a72e51..ebf8455be290 100644 --- a/ui/lib/core/addon/components/json-editor.hbs +++ b/ui/lib/core/addon/components/json-editor.hbs @@ -27,8 +27,8 @@ {{/if}}
Date: Fri, 1 Nov 2024 13:41:21 -0600 Subject: [PATCH 03/17] replace original idea with hds::codeblock on kvv2 details view --- ui/app/styles/components/codemirror.scss | 6 ------ ui/lib/core/addon/components/json-editor.hbs | 11 ++-------- ui/lib/core/addon/components/json-editor.js | 17 --------------- ui/lib/kv/addon/components/kv-data-fields.hbs | 21 +++++++++++++------ 4 files changed, 17 insertions(+), 38 deletions(-) diff --git a/ui/app/styles/components/codemirror.scss b/ui/app/styles/components/codemirror.scss index c8e40cd23cd8..49cd9d2d3330 100644 --- a/ui/app/styles/components/codemirror.scss +++ b/ui/app/styles/components/codemirror.scss @@ -172,12 +172,6 @@ $gutter-grey: #2a2f36; } } -.expanded-codemirror > .cm-s-hashi { - &.CodeMirror { - height: 100%; - } -} - .readonly-codemirror { .CodeMirror-code { cursor: default; diff --git a/ui/lib/core/addon/components/json-editor.hbs b/ui/lib/core/addon/components/json-editor.hbs index ebf8455be290..28b784a9e439 100644 --- a/ui/lib/core/addon/components/json-editor.hbs +++ b/ui/lib/core/addon/components/json-editor.hbs @@ -26,14 +26,6 @@ /> {{/if}}
-
+ {{#if @helpText}}

{{@helpText}}

diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index 9d693e007833..66507a6181cd 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -5,7 +5,6 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; -import { tracked } from '@glimmer/tracking'; /** * @module JsonEditor @@ -33,16 +32,6 @@ import { tracked } from '@glimmer/tracking'; */ export default class JsonEditorComponent extends Component { - @tracked showExpandedView = false; - - get isExpanded() { - return this.showExpandedView ? 'expanded-codemirror' : ''; - } - - get isReadOnly() { - return this.args.readOnly ? 'readonly-codemirror' : ''; - } - get getShowToolbar() { return this.args.showToolbar === false ? false : true; } @@ -68,12 +57,6 @@ export default class JsonEditorComponent extends Component { } } - @action - toggleExpandView() { - // adds or removes the class 'expanded' to .cm-s-hashi .CodeMirror - this.args.valueUpdated(null, this._codemirrorEditor); - } - @action restoreExample() { // set value to null which will cause the example value to be passed into the editor diff --git a/ui/lib/kv/addon/components/kv-data-fields.hbs b/ui/lib/kv/addon/components/kv-data-fields.hbs index e6af5effb985..dad90b35019c 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.hbs +++ b/ui/lib/kv/addon/components/kv-data-fields.hbs @@ -13,12 +13,21 @@
{{#if @showJson}} - + {{#if (eq @type "details")}} + + + Version data + + + {{else}} + + {{/if}} {{#if (or @modelValidations.secretData.errors this.lintingErrors)}} Date: Fri, 1 Nov 2024 13:49:49 -0600 Subject: [PATCH 04/17] changelog --- changelog/28808.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/28808.txt diff --git a/changelog/28808.txt b/changelog/28808.txt new file mode 100644 index 000000000000..4cc4f4527827 --- /dev/null +++ b/changelog/28808.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Replace KVv2 json secret details view with Hds::CodeBlock component allowing users to search full secret height. +``` From d3ba3e9e34af6a063a06eeb85779052e0f108f16 Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Mon, 4 Nov 2024 14:55:46 -0700 Subject: [PATCH 05/17] fixing edit view by addressing viewportMargin --- ui/app/templates/components/console/log-json.hbs | 3 ++- ui/app/templates/components/control-group-success.hbs | 3 ++- ui/lib/core/addon/components/json-editor.hbs | 2 +- ui/lib/core/addon/components/json-editor.js | 2 +- ui/lib/kv/addon/components/kv-data-fields.hbs | 7 ++++++- ui/lib/kv/addon/components/kv-data-fields.js | 7 +++++++ 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ui/app/templates/components/console/log-json.hbs b/ui/app/templates/components/console/log-json.hbs index 6a1044791aca..f1c64321bbea 100644 --- a/ui/app/templates/components/console/log-json.hbs +++ b/ui/app/templates/components/console/log-json.hbs @@ -8,7 +8,8 @@ @showToolbar={{false}} @value={{stringify this.content}} @readOnly={{true}} - @viewportMargin="Infinity" + {{! ideally we calculate the "height" of the json data, but 100 should cover most cases }} + @viewportMargin="100" @gutters={{false}} @theme="hashi auto-height" /> diff --git a/ui/app/templates/components/control-group-success.hbs b/ui/app/templates/components/control-group-success.hbs index fd79e5ec2d17..b5a913b7a2ee 100644 --- a/ui/app/templates/components/control-group-success.hbs +++ b/ui/app/templates/components/control-group-success.hbs @@ -21,7 +21,8 @@ @showToolbar={{false}} @value={{stringify this.unwrapData}} @readOnly={{true}} - @viewportMargin="Infinity" + {{! ideally we calculate the "height" of the json data, but 100 should cover most cases }} + @viewportMargin="100" @gutters={{false}} @theme="hashi-read-only auto-height" /> diff --git a/ui/lib/core/addon/components/json-editor.hbs b/ui/lib/core/addon/components/json-editor.hbs index 28b784a9e439..a7587a0cdffd 100644 --- a/ui/lib/core/addon/components/json-editor.hbs +++ b/ui/lib/core/addon/components/json-editor.hbs @@ -51,7 +51,7 @@ mode=@mode readOnly=@readOnly theme=@theme - viewportMarg=@viewportMargin + viewportMargin=@viewportMargin onSetup=this.onSetup onUpdate=this.onUpdate onFocus=this.onFocus diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index 66507a6181cd..f4ea0daa9d73 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -24,7 +24,7 @@ import { action } from '@ember/object'; * @param {Boolean} [readOnly] - Sets the view to readOnly, allowing for copying but no editing. It also hides the cursor. Defaults to false. * @param {String} [theme] - Specify or customize the look via a named "theme" class in scss. * @param {String} [value] - Value within the display. Generally, a json string. - * @param {String} [viewportMargin] - Size of viewport. Often set to "Infinity" to load/show all text regardless of length. + * @param {String} [viewportMargin] - Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. For KVv2, we calculate the height of the editor based on the number of lines in the value. This is a way to ensure that the editor is tall enough to show all the lines. This also allows the user to search the secret using cntrl +f. * @param {string} [example] - Example to show when value is null -- when example is provided a restore action will render in the toolbar to clear the current value and show the example after input * @param {string} [screenReaderLabel] - This label is read by the screen readers when CodeMirror text area is focused. This is helpful for accessibility. * @param {string} [container] - **REQUIRED if rendering within a modal** Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set `autoRefresh=true` so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code diff --git a/ui/lib/kv/addon/components/kv-data-fields.hbs b/ui/lib/kv/addon/components/kv-data-fields.hbs index dad90b35019c..c47e6fce7671 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.hbs +++ b/ui/lib/kv/addon/components/kv-data-fields.hbs @@ -26,7 +26,12 @@ {{else}} - + {{/if}} {{#if (or @modelValidations.secretData.errors this.lintingErrors)}} Date: Mon, 4 Nov 2024 17:55:09 -0700 Subject: [PATCH 06/17] fix failing test --- ui/lib/kv/addon/components/kv-data-fields.hbs | 3 +- .../kv/kv-v2-workflow-edge-cases-test.js | 30 ++++++++++++++----- ui/tests/helpers/general-selectors.ts | 1 + .../components/kv/kv-data-fields-test.js | 9 ++++-- .../kv/page/kv-page-secret-details-test.js | 16 ++++++---- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/ui/lib/kv/addon/components/kv-data-fields.hbs b/ui/lib/kv/addon/components/kv-data-fields.hbs index c47e6fce7671..1b75d56762bc 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.hbs +++ b/ui/lib/kv/addon/components/kv-data-fields.hbs @@ -15,6 +15,7 @@ {{#if @showJson}} {{#if (eq @type "details")}} {{else}} `[data-test-code-block="${label}"]`, // TODO replace one off data-test selectors on the Hds::CodeBlock component with this. codemirror: `[data-test-component="code-mirror-modifier"]`, codemirrorTextarea: `[data-test-component="code-mirror-modifier"] textarea`, }; diff --git a/ui/tests/integration/components/kv/kv-data-fields-test.js b/ui/tests/integration/components/kv/kv-data-fields-test.js index e9e18d99f368..83fa926b1312 100644 --- a/ui/tests/integration/components/kv/kv-data-fields-test.js +++ b/ui/tests/integration/components/kv/kv-data-fields-test.js @@ -11,6 +11,7 @@ import { hbs } from 'ember-cli-htmlbars'; import { fillIn, render, click } from '@ember/test-helpers'; import codemirror from 'vault/tests/helpers/codemirror'; import { PAGE, FORM } from 'vault/tests/helpers/kv/kv-selectors'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { setupRenderingTest(hooks); @@ -88,7 +89,7 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { assert.dom(PAGE.infoRowValue('foo')).hasText('bar', 'secret value shows after toggle'); }); - test('it shows readonly json editor when viewing secret details of complex secret', async function (assert) { + test('it shows hds codeblock when viewing secret details of complex secret', async function (assert) { this.secret.secretData = { foo: { bar: 'baz', @@ -100,7 +101,9 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { owner: this.engine, }); assert.dom(PAGE.infoRowValue('foo')).doesNotExist('does not render rows of secret data'); - assert.dom('[data-test-component="code-mirror-modifier"]').hasClass('readonly-codemirror'); - assert.dom('[data-test-component="code-mirror-modifier"]').includesText(`{ "foo": { "bar": "baz" }}`); + assert.dom(GENERAL.codeBlock('secret-data')).exists('hds codeBlock exists'); + assert + .dom(GENERAL.codeBlock('secret-data')) + .hasText(`Version data { "foo": { "bar": "baz" }} `, 'Json data is displayed'); }); }); diff --git a/ui/tests/integration/components/kv/page/kv-page-secret-details-test.js b/ui/tests/integration/components/kv/page/kv-page-secret-details-test.js index 430ff3765f08..298d1fd330a3 100644 --- a/ui/tests/integration/components/kv/page/kv-page-secret-details-test.js +++ b/ui/tests/integration/components/kv/page/kv-page-secret-details-test.js @@ -7,13 +7,14 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { setupEngine } from 'ember-engines/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support'; -import { click, find, render } from '@ember/test-helpers'; +import { click, render } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import { kvDataPath } from 'vault/utils/kv-path'; -import { FORM, PAGE, parseJsonEditor } from 'vault/tests/helpers/kv/kv-selectors'; +import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import { syncStatusResponse } from 'vault/mirage/handlers/sync'; import { encodePath } from 'vault/utils/path-encoding-helpers'; import { baseSetup } from 'vault/tests/helpers/kv/kv-run-commands'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | kv-v2 | Page::Secret::Details', function (hooks) { setupRenderingTest(hooks); @@ -126,19 +127,24 @@ module('Integration | Component | kv-v2 | Page::Secret::Details', function (hook await click(FORM.toggleMasked); assert.dom(PAGE.infoRowValue('foo')).hasText('bar', 'renders secret value'); await click(FORM.toggleJson); - assert.propEqual(parseJsonEditor(find), this.secretData, 'json editor renders secret data'); + assert.dom(GENERAL.codeBlock('secret-data')).hasText( + `Version data { + "foo": "bar" +}`, + 'json editor renders secret data' + ); assert .dom(PAGE.detail.versionTimestamp) .includesText(`Version ${this.version} created`, 'renders version and time created'); }); - test('it renders json view when secret is complex', async function (assert) { + test('it renders hds codeblock view when secret is complex', async function (assert) { assert.expect(4); await this.renderComponent(this.modelComplex); assert.dom(PAGE.infoRowValue('foo')).doesNotExist('does not render rows of secret data'); assert.dom(FORM.toggleJson).isChecked(); assert.dom(FORM.toggleJson).isNotDisabled(); - assert.dom('[data-test-component="code-mirror-modifier"]').exists('shows json editor'); + assert.dom(GENERAL.codeBlock('secret-data')).exists('hds codeBlock exists'); }); test('it renders deleted empty state', async function (assert) { From 6eeee824ddeac2aef6f790b3325026d74e18605b Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Mon, 4 Nov 2024 18:00:52 -0700 Subject: [PATCH 07/17] missedone --- ui/tests/integration/components/kv/kv-data-fields-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/tests/integration/components/kv/kv-data-fields-test.js b/ui/tests/integration/components/kv/kv-data-fields-test.js index 83fa926b1312..cc9813898d4e 100644 --- a/ui/tests/integration/components/kv/kv-data-fields-test.js +++ b/ui/tests/integration/components/kv/kv-data-fields-test.js @@ -104,6 +104,6 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { assert.dom(GENERAL.codeBlock('secret-data')).exists('hds codeBlock exists'); assert .dom(GENERAL.codeBlock('secret-data')) - .hasText(`Version data { "foo": { "bar": "baz" }} `, 'Json data is displayed'); + .hasText(`Version data { "foo": { "bar": "baz" } } `, 'Json data is displayed'); }); }); From c9d5bb00003e7baed4f29d3172cfc3d3763167f8 Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 15:29:21 -0700 Subject: [PATCH 08/17] Update 28808.txt --- changelog/28808.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog/28808.txt b/changelog/28808.txt index 4cc4f4527827..20d4d1ce4e36 100644 --- a/changelog/28808.txt +++ b/changelog/28808.txt @@ -1,3 +1,6 @@ ```release-note:improvement -ui: Replace KVv2 json secret details view with Hds::CodeBlock component allowing users to search full secret height. +ui: Replace KVv2 json secret details view with Hds::CodeBlock component allowing users to search the full secret height. +``` +```release-note:bug +ui: Allow users to search the full json object within the json code-editor edit/create view. ``` From 941d03c437965716ba921cab0ad6efe9ca6096cd Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 15:31:49 -0700 Subject: [PATCH 09/17] Update json-editor.js --- ui/lib/core/addon/components/json-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index f4ea0daa9d73..1a6d5ff805e4 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -24,7 +24,7 @@ import { action } from '@ember/object'; * @param {Boolean} [readOnly] - Sets the view to readOnly, allowing for copying but no editing. It also hides the cursor. Defaults to false. * @param {String} [theme] - Specify or customize the look via a named "theme" class in scss. * @param {String} [value] - Value within the display. Generally, a json string. - * @param {String} [viewportMargin] - Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. For KVv2, we calculate the height of the editor based on the number of lines in the value. This is a way to ensure that the editor is tall enough to show all the lines. This also allows the user to search the secret using cntrl +f. + * @param {String} [viewportMargin] - Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. Determines how much of the json object is rendered and what in the object can be searched using cntrl + f. * @param {string} [example] - Example to show when value is null -- when example is provided a restore action will render in the toolbar to clear the current value and show the example after input * @param {string} [screenReaderLabel] - This label is read by the screen readers when CodeMirror text area is focused. This is helpful for accessibility. * @param {string} [container] - **REQUIRED if rendering within a modal** Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set `autoRefresh=true` so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code From 76f340d2bad941f17c7bc9c2d6c4f63dd5471d87 Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 15:25:53 -0700 Subject: [PATCH 10/17] test coverage --- ui/lib/kv/addon/components/kv-data-fields.js | 3 +- .../secret-engine/secret-engine-helpers.js | 46 +++++++++++++++++++ .../components/json-editor-test.js | 31 +++++++++++++ .../components/kv/kv-data-fields-test.js | 23 ++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/ui/lib/kv/addon/components/kv-data-fields.js b/ui/lib/kv/addon/components/kv-data-fields.js index 45832684281d..f7253fbd9271 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.js +++ b/ui/lib/kv/addon/components/kv-data-fields.js @@ -45,7 +45,8 @@ export default class KvDataFields extends Component { if (!this.args.secret || !this.args.secret.secretData) return 10; const jsonHeight = Object.keys(this.args.secret.secretData).length; // return the higher of default 10 or the number of lines in the json - return Math.max(jsonHeight, 10); + const max = Math.max(jsonHeight, 10); + return Math.min(max, 1000); // cap at 1000 lines to avoid performance implications } @action diff --git a/ui/tests/helpers/secret-engine/secret-engine-helpers.js b/ui/tests/helpers/secret-engine/secret-engine-helpers.js index 2a9c88601c4d..e970bd0afa23 100644 --- a/ui/tests/helpers/secret-engine/secret-engine-helpers.js +++ b/ui/tests/helpers/secret-engine/secret-engine-helpers.js @@ -206,3 +206,49 @@ export const fillInAwsConfig = async (situation = 'withAccess') => { await fillIn(GENERAL.ttl.input('Identity token TTL'), '7200'); } }; + +// Example usage +// createLongJson (2, 3) will create a json object with 2 original keys, each with 3 nested keys +// { +// "key-0": { +// "nested-key-0": { +// "nested-key-1": { +// "nested-key-2": "nested-value" +// } +// } +// }, +// "key-1": { +// "nested-key-0": { +// "nested-key-1": { +// "nested-key-2": "nested-value" +// } +// } +// } +// } + +export function createLongJson(lines = 10, nestLevel = 3) { + const keys = Array.from({ length: nestLevel }, (_, i) => `nested-key-${i}`); + const jsonObject = {}; + + for (let i = 0; i < lines; i++) { + nestLevel > 0 + ? (jsonObject[`key-${i}`] = createNestedObject({}, keys, 'nested-value')) + : (jsonObject[`key-${i}`] = 'non-nested-value'); + } + return jsonObject; +} + +function createNestedObject(obj = {}, keys, value) { + let current = obj; + + for (let i = 0; i < keys.length - 1; i++) { + const key = keys[i]; + if (!current[key]) { + current[key] = {}; + } + current = current[key]; + } + + current[keys[keys.length - 1]] = value; + return obj; +} diff --git a/ui/tests/integration/components/json-editor-test.js b/ui/tests/integration/components/json-editor-test.js index 100b7d8ef9b8..c5834f695aea 100644 --- a/ui/tests/integration/components/json-editor-test.js +++ b/ui/tests/integration/components/json-editor-test.js @@ -11,6 +11,7 @@ import hbs from 'htmlbars-inline-precompile'; import jsonEditor from '../../pages/components/json-editor'; import sinon from 'sinon'; import { setRunOptions } from 'ember-a11y-testing/test-support'; +import { createLongJson } from 'vault/tests/helpers/secret-engine/secret-engine-helpers'; const component = create(jsonEditor); @@ -29,6 +30,7 @@ module('Integration | Component | json-editor', function (hooks) { this.set('onFocusOut', sinon.spy()); this.set('json_blob', JSON_BLOB); this.set('bad_json_blob', BAD_JSON_BLOB); + this.set('long_json', JSON.stringify(createLongJson(), null, `\t`)); this.set('hashi-read-only-theme', 'hashi-read-only auto-height'); setRunOptions({ rules: { @@ -36,6 +38,8 @@ module('Integration | Component | json-editor', function (hooks) { label: { enabled: false }, // TODO: investigate and fix Codemirror styling 'color-contrast': { enabled: false }, + // failing on .CodeMirror-scroll + 'scrollable-region-focusable': { enabled: false }, }, }); }); @@ -129,4 +133,31 @@ module('Integration | Component | json-editor', function (hooks) { 'even after hitting enter the value is still set correctly' ); }); + + test('when @viewportMargin is not set user is unable to search a long secret', async function (assert) { + await render(hbs` + + `); + assert + .dom('.CodeMirror-code') + .doesNotIncludeText('key-9', 'Without viewportMargin, user cannot search for key-9'); + }); + + test('when @viewportMargin is set user is able to search a long secret', async function (assert) { + await render(hbs` + + `); + assert + .dom('.CodeMirror-code') + .containsText('key-9', 'With viewportMargin set, user can search for key-9'); + }); }); diff --git a/ui/tests/integration/components/kv/kv-data-fields-test.js b/ui/tests/integration/components/kv/kv-data-fields-test.js index cc9813898d4e..ac3d5ed8b606 100644 --- a/ui/tests/integration/components/kv/kv-data-fields-test.js +++ b/ui/tests/integration/components/kv/kv-data-fields-test.js @@ -12,6 +12,8 @@ import { fillIn, render, click } from '@ember/test-helpers'; import codemirror from 'vault/tests/helpers/codemirror'; import { PAGE, FORM } from 'vault/tests/helpers/kv/kv-selectors'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { setRunOptions } from 'ember-a11y-testing/test-support'; +import { createLongJson } from 'vault/tests/helpers/secret-engine/secret-engine-helpers'; module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { setupRenderingTest(hooks); @@ -23,6 +25,12 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { this.backend = 'my-kv-engine'; this.path = 'my-secret'; this.secret = this.store.createRecord('kv/data', { backend: this.backend }); + setRunOptions({ + rules: { + // failing on .CodeMirror-scroll + 'scrollable-region-focusable': { enabled: false }, + }, + }); }); test('it updates the secret model', async function (assert) { @@ -106,4 +114,19 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) { .dom(GENERAL.codeBlock('secret-data')) .hasText(`Version data { "foo": { "bar": "baz" } } `, 'Json data is displayed'); }); + + test('it defaults to a viewportMargin 10 when there is no secret data', async function (assert) { + await render(hbs``, { owner: this.engine }); + assert.strictEqual(codemirror().options.viewportMargin, 10, 'viewportMargin defaults to 10'); + }); + + test('it calculates viewportMargin based on secret size', async function (assert) { + this.secret.secretData = createLongJson(100); + await render(hbs``, { owner: this.engine }); + assert.strictEqual( + codemirror().options.viewportMargin, + 100, + 'viewportMargin is set to 100 matching the height of the json' + ); + }); }); From a2ee07f8a06ad886d3c10de42c3cac1f9b99e47b Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 15:40:51 -0700 Subject: [PATCH 11/17] update codeblock selector --- ui/lib/kv/addon/components/kv-patch/subkeys-reveal.hbs | 2 +- ui/lib/kv/addon/components/kv-paths-card.hbs | 4 ++-- .../ldap/addon/components/page/library/details/accounts.hbs | 2 +- ui/tests/helpers/kv/kv-selectors.js | 4 ++-- .../integration/components/kv/kv-patch/editor/form-test.js | 6 +++--- .../integration/components/kv/kv-patch/json-form-test.js | 6 +++--- .../components/ldap/page/library/details/accounts-test.js | 3 ++- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/ui/lib/kv/addon/components/kv-patch/subkeys-reveal.hbs b/ui/lib/kv/addon/components/kv-patch/subkeys-reveal.hbs index be076f246c0d..61b799d761c6 100644 --- a/ui/lib/kv/addon/components/kv-patch/subkeys-reveal.hbs +++ b/ui/lib/kv/addon/components/kv-patch/subkeys-reveal.hbs @@ -8,6 +8,6 @@ Reveal subkeys in JSON {{#if this.showSubkeys}} - + {{/if}}
\ No newline at end of file diff --git a/ui/lib/kv/addon/components/kv-paths-card.hbs b/ui/lib/kv/addon/components/kv-paths-card.hbs index d7976d92f27c..8e1edceb5a4e 100644 --- a/ui/lib/kv/addon/components/kv-paths-card.hbs +++ b/ui/lib/kv/addon/components/kv-paths-card.hbs @@ -53,7 +53,7 @@ for other CLI commands.

`${PAGE.infoRowValue(label)} button`, - codeSnippet: (section) => `[data-test-commands="${section}"] code`, - snippetCopy: (section) => `[data-test-commands="${section}"] button`, + codeSnippet: (section) => `[data-test-code-block="${section}"] code`, + snippetCopy: (section) => `[data-test-code-block="${section}"] button`, }, }; diff --git a/ui/tests/integration/components/kv/kv-patch/editor/form-test.js b/ui/tests/integration/components/kv/kv-patch/editor/form-test.js index dca034ddd673..004e8a29dad7 100644 --- a/ui/tests/integration/components/kv/kv-patch/editor/form-test.js +++ b/ui/tests/integration/components/kv/kv-patch/editor/form-test.js @@ -96,14 +96,14 @@ module('Integration | Component | kv | kv-patch/editor/form', function (hooks) { await this.renderComponent(); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isNotChecked('toggle is initially unchecked'); - assert.dom('[data-test-subkeys]').doesNotExist(); + assert.dom(GENERAL.codeBlock('subkeys')).doesNotExist(); await click(GENERAL.toggleInput('Reveal subkeys')); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isChecked(); - assert.dom('[data-test-subkeys]').hasText(JSON.stringify(this.subkeys, null, 2)); + assert.dom(GENERAL.codeBlock('subkeys')).hasText(JSON.stringify(this.subkeys, null, 2)); await click(GENERAL.toggleInput('Reveal subkeys')); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isNotChecked(); - assert.dom('[data-test-subkeys]').doesNotExist('unchecking re-hides subkeys'); + assert.dom(GENERAL.codeBlock('subkeys')).doesNotExist('unchecking re-hides subkeys'); }); test('it enables and disables inputs', async function (assert) { diff --git a/ui/tests/integration/components/kv/kv-patch/json-form-test.js b/ui/tests/integration/components/kv/kv-patch/json-form-test.js index 166ea8d2fa7a..37703e2bd985 100644 --- a/ui/tests/integration/components/kv/kv-patch/json-form-test.js +++ b/ui/tests/integration/components/kv/kv-patch/json-form-test.js @@ -59,14 +59,14 @@ module('Integration | Component | kv | kv-patch/editor/json-form', function (hoo await this.renderComponent(); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isNotChecked('toggle is initially unchecked'); - assert.dom('[data-test-subkeys]').doesNotExist(); + assert.dom(GENERAL.codeBlock('subkeys')).doesNotExist(); await click(GENERAL.toggleInput('Reveal subkeys')); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isChecked(); - assert.dom('[data-test-subkeys]').hasText(JSON.stringify(this.subkeys, null, 2)); + assert.dom(GENERAL.codeBlock('subkeys')).hasText(JSON.stringify(this.subkeys, null, 2)); await click(GENERAL.toggleInput('Reveal subkeys')); assert.dom(GENERAL.toggleInput('Reveal subkeys')).isNotChecked(); - assert.dom('[data-test-subkeys]').doesNotExist('unchecking re-hides subkeys'); + assert.dom(GENERAL.codeBlock('subkeys')).doesNotExist('unchecking re-hides subkeys'); }); test('it renders linting errors', async function (assert) { diff --git a/ui/tests/integration/components/ldap/page/library/details/accounts-test.js b/ui/tests/integration/components/ldap/page/library/details/accounts-test.js index 8bb1ab696921..c7f7aa6ebbeb 100644 --- a/ui/tests/integration/components/ldap/page/library/details/accounts-test.js +++ b/ui/tests/integration/components/ldap/page/library/details/accounts-test.js @@ -11,6 +11,7 @@ import { render, click, fillIn } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs'; import sinon from 'sinon'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | ldap | Page::Library::Details::Accounts', function (hooks) { setupRenderingTest(hooks); @@ -76,7 +77,7 @@ module('Integration | Component | ldap | Page::Library::Details::Accounts', func assert.dom('[data-test-checked-out-card]').exists('Accounts checked out card renders'); assert - .dom('[data-test-accounts-code-block] code') + .dom(`${GENERAL.codeBlock('accounts')} code`) .hasText( 'vault lease renew ldap-test/library/test-library/check-out/:lease_id', 'Renew cli command renders with backend path' From 8e8a0711e85459b5862eb7fc3db746774f1578ba Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 15:43:52 -0700 Subject: [PATCH 12/17] Update general-selectors.ts --- ui/tests/helpers/general-selectors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/tests/helpers/general-selectors.ts b/ui/tests/helpers/general-selectors.ts index 285085ea1814..c9159350d3d4 100644 --- a/ui/tests/helpers/general-selectors.ts +++ b/ui/tests/helpers/general-selectors.ts @@ -95,7 +95,7 @@ export const GENERAL = { cancelButton: '[data-test-cancel]', saveButton: '[data-test-save]', backButton: '[data-test-back-button]', - codeBlock: (label: string) => `[data-test-code-block="${label}"]`, // TODO replace one off data-test selectors on the Hds::CodeBlock component with this. + codeBlock: (label: string) => `[data-test-code-block="${label}"]`, codemirror: `[data-test-component="code-mirror-modifier"]`, codemirrorTextarea: `[data-test-component="code-mirror-modifier"] textarea`, }; From 3bdf3c7e05dcb28b659e1bc608a72a530717ee6b Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Wed, 6 Nov 2024 16:01:39 -0700 Subject: [PATCH 13/17] Update kv-data-fields.js --- ui/lib/kv/addon/components/kv-data-fields.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/lib/kv/addon/components/kv-data-fields.js b/ui/lib/kv/addon/components/kv-data-fields.js index f7253fbd9271..92c0ffe01b3d 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.js +++ b/ui/lib/kv/addon/components/kv-data-fields.js @@ -44,7 +44,8 @@ export default class KvDataFields extends Component { get viewportMargin() { if (!this.args.secret || !this.args.secret.secretData) return 10; const jsonHeight = Object.keys(this.args.secret.secretData).length; - // return the higher of default 10 or the number of lines in the json + // return the higher of: 10 or the approimated number of lines in the json. jsonHeight only includes the first level of keys, so for objects + // with lots of nested values, it will undercount. const max = Math.max(jsonHeight, 10); return Math.min(max, 1000); // cap at 1000 lines to avoid performance implications } From abcd62a7e916d785616dcb900a00b6c69dcffcfa Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Thu, 7 Nov 2024 09:15:09 -0700 Subject: [PATCH 14/17] Update ui/lib/core/addon/components/json-editor.js Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> --- ui/lib/core/addon/components/json-editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index 1a6d5ff805e4..038c19ff067b 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -24,7 +24,7 @@ import { action } from '@ember/object'; * @param {Boolean} [readOnly] - Sets the view to readOnly, allowing for copying but no editing. It also hides the cursor. Defaults to false. * @param {String} [theme] - Specify or customize the look via a named "theme" class in scss. * @param {String} [value] - Value within the display. Generally, a json string. - * @param {String} [viewportMargin] - Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. Determines how much of the json object is rendered and what in the object can be searched using cntrl + f. + * @param {String} [viewportMargin] - Specifies the amount of lines rendered on the DOM (this is not the editor display height). * @param {string} [example] - Example to show when value is null -- when example is provided a restore action will render in the toolbar to clear the current value and show the example after input * @param {string} [screenReaderLabel] - This label is read by the screen readers when CodeMirror text area is focused. This is helpful for accessibility. * @param {string} [container] - **REQUIRED if rendering within a modal** Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set `autoRefresh=true` so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code From 112cd6dedc4ecf497fe9b62a24fe54034ee6ae53 Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Thu, 7 Nov 2024 09:15:38 -0700 Subject: [PATCH 15/17] Update ui/lib/kv/addon/components/kv-data-fields.js Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> --- ui/lib/kv/addon/components/kv-data-fields.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/lib/kv/addon/components/kv-data-fields.js b/ui/lib/kv/addon/components/kv-data-fields.js index 92c0ffe01b3d..cdd792bc00cc 100644 --- a/ui/lib/kv/addon/components/kv-data-fields.js +++ b/ui/lib/kv/addon/components/kv-data-fields.js @@ -42,7 +42,7 @@ export default class KvDataFields extends Component { } get viewportMargin() { - if (!this.args.secret || !this.args.secret.secretData) return 10; + if (!this.args?.secret?.secretData) return 10; const jsonHeight = Object.keys(this.args.secret.secretData).length; // return the higher of: 10 or the approimated number of lines in the json. jsonHeight only includes the first level of keys, so for objects // with lots of nested values, it will undercount. From 11bbd464095281bbdf0acd7a23d7d79cc194c7b4 Mon Sep 17 00:00:00 2001 From: Angel Garbarino Date: Thu, 7 Nov 2024 09:20:46 -0700 Subject: [PATCH 16/17] update test name --- ui/tests/integration/components/json-editor-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/tests/integration/components/json-editor-test.js b/ui/tests/integration/components/json-editor-test.js index c5834f695aea..56f4a674f8d9 100644 --- a/ui/tests/integration/components/json-editor-test.js +++ b/ui/tests/integration/components/json-editor-test.js @@ -134,7 +134,7 @@ module('Integration | Component | json-editor', function (hooks) { ); }); - test('when @viewportMargin is not set user is unable to search a long secret', async function (assert) { + test('no viewportMargin renders only default 10 lines of data on the DOM', async function (assert) { await render(hbs` Date: Fri, 8 Nov 2024 09:17:39 -0700 Subject: [PATCH 17/17] add default to modifier --- ui/lib/core/addon/components/json-editor.js | 2 +- ui/lib/core/addon/modifiers/code-mirror.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/lib/core/addon/components/json-editor.js b/ui/lib/core/addon/components/json-editor.js index 038c19ff067b..88b36ef8ff9b 100644 --- a/ui/lib/core/addon/components/json-editor.js +++ b/ui/lib/core/addon/components/json-editor.js @@ -24,7 +24,7 @@ import { action } from '@ember/object'; * @param {Boolean} [readOnly] - Sets the view to readOnly, allowing for copying but no editing. It also hides the cursor. Defaults to false. * @param {String} [theme] - Specify or customize the look via a named "theme" class in scss. * @param {String} [value] - Value within the display. Generally, a json string. - * @param {String} [viewportMargin] - Specifies the amount of lines rendered on the DOM (this is not the editor display height). + * @param {String} [viewportMargin] - Specifies the amount of lines rendered on the DOM (this is not the editor display height). The codemirror default is 10 which we set explicity in the code-mirror modifier per the recommendations from the codemirror docs. * @param {string} [example] - Example to show when value is null -- when example is provided a restore action will render in the toolbar to clear the current value and show the example after input * @param {string} [screenReaderLabel] - This label is read by the screen readers when CodeMirror text area is focused. This is helpful for accessibility. * @param {string} [container] - **REQUIRED if rendering within a modal** Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set `autoRefresh=true` so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code diff --git a/ui/lib/core/addon/modifiers/code-mirror.js b/ui/lib/core/addon/modifiers/code-mirror.js index b9b46900dcc8..8b6c73f66783 100644 --- a/ui/lib/core/addon/modifiers/code-mirror.js +++ b/ui/lib/core/addon/modifiers/code-mirror.js @@ -76,7 +76,7 @@ export default class CodeMirrorModifier extends Modifier { readOnly: namedArgs.readOnly || false, theme: namedArgs.theme || 'hashi', value: namedArgs.content || '', - viewportMargin: namedArgs.viewportMargin || '', + viewportMargin: namedArgs.viewportMargin || 10, autoRefresh: namedArgs.autoRefresh, });