mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 03:58:01 +00:00
ui: Add version diff comparison to KV v2 (#23200)
* add diff route * add version diff toolbar link * finish functionality of version diff comparison * add tests * update empty state message * update selectors * wip tests * finish test * add empty state test * switch dropdowns * add changelog * add comment
This commit is contained in:
3
changelog/23200.txt
Normal file
3
changelog/23200.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
ui: Move access to KV V2 version diff view to toolbar in Version History
|
||||||
|
```
|
||||||
@@ -9,6 +9,24 @@
|
|||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
{{#each @metadata.sortedVersions as |versionData|}}
|
{{#each @metadata.sortedVersions as |versionData|}}
|
||||||
<li data-test-version={{versionData.version}} class="action">
|
<li data-test-version={{versionData.version}} class="action">
|
||||||
|
{{#if @onSelect}}
|
||||||
|
<button
|
||||||
|
disabled={{or versionData.destroyed versionData.isSecretDeleted}}
|
||||||
|
{{on "click" (fn @onSelect versionData.version D.actions)}}
|
||||||
|
type="button"
|
||||||
|
class="link {{if (loose-equal versionData.version @displayVersion) 'is-active'}}"
|
||||||
|
>
|
||||||
|
Version
|
||||||
|
{{versionData.version}}
|
||||||
|
{{#if versionData.destroyed}}
|
||||||
|
<Icon @name="x-square-fill" class="has-text-danger is-pulled-right" />
|
||||||
|
{{else if versionData.isSecretDeleted}}
|
||||||
|
<Icon @name="x-square-fill" class="has-text-grey is-pulled-right" />
|
||||||
|
{{else if (loose-equal versionData.version @metadata.currentVersion)}}
|
||||||
|
<Icon @name="check-circle" class="has-text-success is-pulled-right" />
|
||||||
|
{{/if}}
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
<LinkTo @query={{hash version=versionData.version}} {{on "click" (fn @onClose D)}}>
|
<LinkTo @query={{hash version=versionData.version}} {{on "click" (fn @onClose D)}}>
|
||||||
Version
|
Version
|
||||||
{{versionData.version}}
|
{{versionData.version}}
|
||||||
@@ -20,6 +38,7 @@
|
|||||||
<Icon @name="check-circle" class="has-text-success is-pulled-right" />
|
<Icon @name="check-circle" class="has-text-success is-pulled-right" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</LinkTo>
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<KvPageHeader @breadcrumbs={{@breadcrumbs}} @pageTitle="Version Diff">
|
||||||
|
<:toolbarFilters>
|
||||||
|
<span class="has-text-grey has-text-weight-semibold is-size-8">FROM:</span>
|
||||||
|
<KvVersionDropdown
|
||||||
|
@displayVersion={{this.leftVersion}}
|
||||||
|
@metadata={{@metadata}}
|
||||||
|
@onSelect={{fn this.handleSelect "leftVersion"}}
|
||||||
|
/>
|
||||||
|
<span class="has-text-grey has-text-weight-semibold is-size-8">TO:</span>
|
||||||
|
<KvVersionDropdown
|
||||||
|
@displayVersion={{this.rightVersion}}
|
||||||
|
@metadata={{@metadata}}
|
||||||
|
@onSelect={{fn this.handleSelect "rightVersion"}}
|
||||||
|
/>
|
||||||
|
{{#if this.statesMatch}}
|
||||||
|
<div class="has-left-padding-s">
|
||||||
|
<Icon @name="check-circle-fill" class="has-text-success" />
|
||||||
|
<span>States match</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</:toolbarFilters>
|
||||||
|
</KvPageHeader>
|
||||||
|
|
||||||
|
{{#if this.deactivatedState}}
|
||||||
|
<EmptyState
|
||||||
|
@title="Version {{this.rightVersion}} has been {{this.deactivatedState}}"
|
||||||
|
@message="The current version of this secret has been {{this.deactivatedState}}. Select another version to compare."
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<div class="form-section visual-diff text-grey-lightest background-color-black has-top-margin-s">
|
||||||
|
<pre data-test-visual-diff>{{sanitized-html this.visualDiff}}</pre>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
import { kvDataPath } from 'vault/utils/kv-path';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module KvSecretMetadataVersionDiff renders the version diff comparison
|
||||||
|
* <Page::Secret::Metadata::VersionDiff
|
||||||
|
* @metadata={{this.model.metadata}}
|
||||||
|
* @path={{this.model.path}}
|
||||||
|
* @backend={{this.model.backend}}
|
||||||
|
* @breadcrumbs={{this.breadcrumbs}}
|
||||||
|
* />
|
||||||
|
*
|
||||||
|
* @param {model} metadata - Ember data model: 'kv/metadata'
|
||||||
|
* @param {string} path - path to request secret data for selected version
|
||||||
|
* @param {string} backend - kv secret mount to make network request
|
||||||
|
* @param {array} breadcrumbs - Array to generate breadcrumbs, passed to the page header component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable no-undef */
|
||||||
|
export default class KvSecretMetadataVersionDiff extends Component {
|
||||||
|
@service store;
|
||||||
|
@tracked leftVersion;
|
||||||
|
@tracked rightVersion;
|
||||||
|
@tracked visualDiff;
|
||||||
|
@tracked statesMatch = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
|
||||||
|
// initialize with most recently (before current), active version on left
|
||||||
|
const olderVersions = this.args.metadata.sortedVersions.slice(1);
|
||||||
|
const recentlyActive = olderVersions.find((v) => !v.destroyed && !v.isSecretDeleted);
|
||||||
|
this.leftVersion = Number(recentlyActive?.version);
|
||||||
|
this.rightVersion = this.args.metadata.currentVersion;
|
||||||
|
|
||||||
|
// this diff is from older to newer (current) secret data
|
||||||
|
this.createVisualDiff();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this can only be true on initialization if the current version is inactive
|
||||||
|
// selecting a deleted/destroyed version is otherwise disabled
|
||||||
|
get deactivatedState() {
|
||||||
|
const { currentVersion, currentSecret } = this.args.metadata;
|
||||||
|
return this.rightVersion === currentVersion && currentSecret.isDeactivated ? currentSecret.state : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
handleSelect(side, version, actions) {
|
||||||
|
this[side] = Number(version);
|
||||||
|
actions.close();
|
||||||
|
this.createVisualDiff();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createVisualDiff() {
|
||||||
|
const leftSecretData = await this.fetchSecretData(this.leftVersion);
|
||||||
|
const rightSecretData = await this.fetchSecretData(this.rightVersion);
|
||||||
|
const diffpatcher = jsondiffpatch.create({});
|
||||||
|
const delta = diffpatcher.diff(leftSecretData, rightSecretData);
|
||||||
|
|
||||||
|
this.statesMatch = !delta;
|
||||||
|
this.visualDiff = delta
|
||||||
|
? jsondiffpatch.formatters.html.format(delta, leftSecretData)
|
||||||
|
: JSON.stringify(rightSecretData, undefined, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchSecretData(version) {
|
||||||
|
const { backend, path } = this.args;
|
||||||
|
// check the store first, avoiding an extra network request if possible.
|
||||||
|
const storeData = await this.store.peekRecord('kv/data', kvDataPath(backend, path, version));
|
||||||
|
const data = storeData ? storeData : await this.store.queryRecord('kv/data', { backend, path, version });
|
||||||
|
|
||||||
|
return data?.secretData;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,14 @@
|
|||||||
<LinkTo @route="secret.paths" data-test-secrets-tab="Paths">Paths</LinkTo>
|
<LinkTo @route="secret.paths" data-test-secrets-tab="Paths">Paths</LinkTo>
|
||||||
<LinkTo @route="secret.metadata.versions" data-test-secrets-tab="Version History">Version History</LinkTo>
|
<LinkTo @route="secret.metadata.versions" data-test-secrets-tab="Version History">Version History</LinkTo>
|
||||||
</:tabLinks>
|
</:tabLinks>
|
||||||
|
|
||||||
|
<:toolbarActions>
|
||||||
|
{{#if @metadata.canReadMetadata}}
|
||||||
|
<ToolbarLink @route="secret.metadata.diff">Version diff</ToolbarLink>
|
||||||
|
{{/if}}
|
||||||
|
</:toolbarActions>
|
||||||
</KvPageHeader>
|
</KvPageHeader>
|
||||||
|
|
||||||
<Toolbar />
|
|
||||||
{{#if @metadata.canReadMetadata}}
|
{{#if @metadata.canReadMetadata}}
|
||||||
<div class="sub-text has-text-weight-semibold is-flex-end has-short-padding">
|
<div class="sub-text has-text-weight-semibold is-flex-end has-short-padding">
|
||||||
<KvTooltipTimestamp @text="Secret last updated" @timestamp={{@metadata.updatedTime}} />
|
<KvTooltipTimestamp @text="Secret last updated" @timestamp={{@metadata.updatedTime}} />
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export default buildRoutes(function () {
|
|||||||
this.route('metadata', function () {
|
this.route('metadata', function () {
|
||||||
this.route('edit');
|
this.route('edit');
|
||||||
this.route('versions');
|
this.route('versions');
|
||||||
|
this.route('diff');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.route('configuration');
|
this.route('configuration');
|
||||||
|
|||||||
23
ui/lib/kv/addon/routes/secret/metadata/diff.js
Normal file
23
ui/lib/kv/addon/routes/secret/metadata/diff.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
import { breadcrumbsForSecret } from 'kv/utils/kv-breadcrumbs';
|
||||||
|
|
||||||
|
export default class KvSecretMetadataDiffRoute extends Route {
|
||||||
|
// model passed from parent secret route, if we need to access or intercept
|
||||||
|
// it can retrieved via `this.modelFor('secret'), which includes the metadata model.
|
||||||
|
setupController(controller, resolvedModel) {
|
||||||
|
super.setupController(controller, resolvedModel);
|
||||||
|
const breadcrumbsArray = [
|
||||||
|
{ label: 'secrets', route: 'secrets', linkExternal: true },
|
||||||
|
{ label: resolvedModel.backend, route: 'list' },
|
||||||
|
...breadcrumbsForSecret(resolvedModel.path),
|
||||||
|
{ label: 'version history', route: 'secret.metadata.versions' },
|
||||||
|
{ label: 'diff' },
|
||||||
|
];
|
||||||
|
controller.set('breadcrumbs', breadcrumbsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
ui/lib/kv/addon/templates/secret/metadata/diff.hbs
Normal file
6
ui/lib/kv/addon/templates/secret/metadata/diff.hbs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<Page::Secret::Metadata::VersionDiff
|
||||||
|
@metadata={{this.model.metadata}}
|
||||||
|
@path={{this.model.path}}
|
||||||
|
@backend={{this.model.backend}}
|
||||||
|
@breadcrumbs={{this.breadcrumbs}}
|
||||||
|
/>
|
||||||
@@ -53,9 +53,6 @@ export const PAGE = {
|
|||||||
edit: {
|
edit: {
|
||||||
toggleDiff: '[data-test-toggle-input="Show diff"',
|
toggleDiff: '[data-test-toggle-input="Show diff"',
|
||||||
toggleDiffDescription: '[data-test-diff-description]',
|
toggleDiffDescription: '[data-test-diff-description]',
|
||||||
visualDiff: '[data-test-visual-diff]',
|
|
||||||
added: `.jsondiffpatch-added`,
|
|
||||||
deleted: `.jsondiffpatch-deleted`,
|
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
createSecret: '[data-test-toolbar-create-secret]',
|
createSecret: '[data-test-toolbar-create-secret]',
|
||||||
@@ -73,10 +70,14 @@ export const PAGE = {
|
|||||||
icon: (version) => `[data-test-icon-holder="${version}"]`,
|
icon: (version) => `[data-test-icon-holder="${version}"]`,
|
||||||
linkedBlock: (version) =>
|
linkedBlock: (version) =>
|
||||||
version ? `[data-test-version-linked-block="${version}"]` : '[data-test-version-linked-block]',
|
version ? `[data-test-version-linked-block="${version}"]` : '[data-test-version-linked-block]',
|
||||||
button: (version) => `[data-test-version-button="${version}"]`,
|
|
||||||
versionMenu: (version) => `[data-test-version-linked-block="${version}"] [data-test-popup-menu-trigger]`,
|
versionMenu: (version) => `[data-test-version-linked-block="${version}"] [data-test-popup-menu-trigger]`,
|
||||||
createFromVersion: (version) => `[data-test-create-new-version-from="${version}"]`,
|
createFromVersion: (version) => `[data-test-create-new-version-from="${version}"]`,
|
||||||
},
|
},
|
||||||
|
diff: {
|
||||||
|
visualDiff: '[data-test-visual-diff]',
|
||||||
|
added: `.jsondiffpatch-added`,
|
||||||
|
deleted: `.jsondiffpatch-deleted`,
|
||||||
|
},
|
||||||
create: {
|
create: {
|
||||||
metadataSection: '[data-test-metadata-section]',
|
metadataSection: '[data-test-metadata-section]',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -108,24 +108,24 @@ module('Integration | Component | kv-v2 | Page::Secret::Edit', function (hooks)
|
|||||||
|
|
||||||
assert.dom(PAGE.edit.toggleDiff).isDisabled('Diff toggle is disabled');
|
assert.dom(PAGE.edit.toggleDiff).isDisabled('Diff toggle is disabled');
|
||||||
assert.dom(PAGE.edit.toggleDiffDescription).hasText('No changes to show. Update secret to view diff');
|
assert.dom(PAGE.edit.toggleDiffDescription).hasText('No changes to show. Update secret to view diff');
|
||||||
assert.dom(PAGE.edit.visualDiff).doesNotExist('Does not show visual diff');
|
assert.dom(PAGE.diff.visualDiff).doesNotExist('Does not show visual diff');
|
||||||
|
|
||||||
await fillIn(FORM.keyInput(1), 'foo2');
|
await fillIn(FORM.keyInput(1), 'foo2');
|
||||||
await fillIn(FORM.maskedValueInput(1), 'bar2');
|
await fillIn(FORM.maskedValueInput(1), 'bar2');
|
||||||
|
|
||||||
assert.dom(PAGE.edit.toggleDiff).isNotDisabled('Diff toggle is not disabled');
|
assert.dom(PAGE.edit.toggleDiff).isNotDisabled('Diff toggle is not disabled');
|
||||||
assert.dom(PAGE.edit.toggleDiffDescription).hasText('Showing the diff will reveal secret values');
|
assert.dom(PAGE.edit.toggleDiffDescription).hasText('Showing the diff will reveal secret values');
|
||||||
assert.dom(PAGE.edit.visualDiff).doesNotExist('Does not show visual diff');
|
assert.dom(PAGE.diff.visualDiff).doesNotExist('Does not show visual diff');
|
||||||
await click(PAGE.edit.toggleDiff);
|
await click(PAGE.edit.toggleDiff);
|
||||||
assert.dom(PAGE.edit.visualDiff).exists('Shows visual diff');
|
assert.dom(PAGE.diff.visualDiff).exists('Shows visual diff');
|
||||||
assert.dom(PAGE.edit.added).hasText(`foo2"bar2"`);
|
assert.dom(PAGE.diff.added).hasText(`foo2"bar2"`);
|
||||||
|
|
||||||
await click(FORM.toggleJson);
|
await click(FORM.toggleJson);
|
||||||
codemirror().setValue('{ "foo3": "bar3" }');
|
codemirror().setValue('{ "foo3": "bar3" }');
|
||||||
|
|
||||||
assert.dom(PAGE.edit.visualDiff).exists('Visual diff updates');
|
assert.dom(PAGE.diff.visualDiff).exists('Visual diff updates');
|
||||||
assert.dom(PAGE.edit.deleted).hasText(`foo"bar"`);
|
assert.dom(PAGE.diff.deleted).hasText(`foo"bar"`);
|
||||||
assert.dom(PAGE.edit.added).hasText(`foo3"bar3"`);
|
assert.dom(PAGE.diff.added).hasText(`foo3"bar3"`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it saves nested secrets', async function (assert) {
|
test('it saves nested secrets', async function (assert) {
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
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, findAll, render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
import { kvMetadataPath, kvDataPath } from 'vault/utils/kv-path';
|
||||||
|
import { PAGE } from 'vault/tests/helpers/kv/kv-selectors';
|
||||||
|
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
|
||||||
|
|
||||||
|
module('Integration | Component | kv | Page::Secret::Metadata::VersionDiff', function (hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
setupEngine(hooks, 'kv');
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
this.backend = 'kv-engine';
|
||||||
|
this.path = 'my-secret';
|
||||||
|
this.breadcrumbs = [{ label: 'version history', route: 'secret.metadata.versions' }, { label: 'diff' }];
|
||||||
|
|
||||||
|
this.store = this.owner.lookup('service:store');
|
||||||
|
this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub());
|
||||||
|
|
||||||
|
const metadata = this.server.create('kv-metadatum');
|
||||||
|
metadata.id = kvMetadataPath(this.backend, this.path);
|
||||||
|
this.store.pushPayload('kv/metadata', { modelName: 'kv/metadata', ...metadata });
|
||||||
|
this.metadata = this.store.peekRecord('kv/metadata', metadata.id);
|
||||||
|
// push current secret version record into the store to assert only one request is made
|
||||||
|
const dataId = kvDataPath(this.backend, this.path, 4);
|
||||||
|
this.store.pushPayload('kv/data', {
|
||||||
|
modelName: 'kv/data',
|
||||||
|
id: dataId,
|
||||||
|
secret_data: { foo: 'bar' },
|
||||||
|
version: this.metadata.currentVersion,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders empty states when current version is deleted or destroyed', async function (assert) {
|
||||||
|
assert.expect(4);
|
||||||
|
this.server.get(`/${this.backend}/data/${this.path}`, () => {});
|
||||||
|
const { currentVersion } = this.metadata;
|
||||||
|
|
||||||
|
// destroyed
|
||||||
|
this.metadata.versions[currentVersion].destroyed = true;
|
||||||
|
await render(
|
||||||
|
hbs`
|
||||||
|
<Page::Secret::Metadata::VersionDiff
|
||||||
|
@metadata={{this.metadata}}
|
||||||
|
@path={{this.path}}
|
||||||
|
@backend={{this.backend}}
|
||||||
|
@breadcrumbs={{this.breadcrumbs}}
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
{ owner: this.engine }
|
||||||
|
);
|
||||||
|
assert.dom(PAGE.emptyStateTitle).hasText(`Version ${currentVersion} has been destroyed`);
|
||||||
|
assert
|
||||||
|
.dom(PAGE.emptyStateMessage)
|
||||||
|
.hasText('The current version of this secret has been destroyed. Select another version to compare.');
|
||||||
|
|
||||||
|
// deleted
|
||||||
|
this.metadata.versions[currentVersion].destroyed = false;
|
||||||
|
this.metadata.versions[currentVersion].deletion_time = '2023-07-25T00:36:19.950545Z';
|
||||||
|
await render(
|
||||||
|
hbs`
|
||||||
|
<Page::Secret::Metadata::VersionDiff
|
||||||
|
@metadata={{this.metadata}}
|
||||||
|
@path={{this.path}}
|
||||||
|
@backend={{this.backend}}
|
||||||
|
@breadcrumbs={{this.breadcrumbs}}
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
{ owner: this.engine }
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.dom(PAGE.emptyStateTitle).hasText(`Version ${currentVersion} has been deleted`);
|
||||||
|
assert
|
||||||
|
.dom(PAGE.emptyStateMessage)
|
||||||
|
.hasText('The current version of this secret has been deleted. Select another version to compare.');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders compared data of the two versions and shows icons for deleted, destroyed and current', async function (assert) {
|
||||||
|
assert.expect(14);
|
||||||
|
this.server.get(`/${this.backend}/data/${this.path}`, (schema, req) => {
|
||||||
|
assert.ok('request made to the fetch version 1 data.');
|
||||||
|
// request should not be made for version 4 (current version) because that record already exists in the store
|
||||||
|
assert.strictEqual(req.queryParams.version, '1', 'request includes version param');
|
||||||
|
return {
|
||||||
|
request_id: 'foobar',
|
||||||
|
data: {
|
||||||
|
data: { hello: 'world' },
|
||||||
|
metadata: {
|
||||||
|
created_time: '2023-06-20T21:26:47.592306Z',
|
||||||
|
custom_metadata: null,
|
||||||
|
deletion_time: '',
|
||||||
|
destroyed: false,
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`
|
||||||
|
<Page::Secret::Metadata::VersionDiff
|
||||||
|
@metadata={{this.metadata}}
|
||||||
|
@path={{this.path}}
|
||||||
|
@backend={{this.backend}}
|
||||||
|
@breadcrumbs={{this.breadcrumbs}}
|
||||||
|
/>
|
||||||
|
`,
|
||||||
|
{ owner: this.engine }
|
||||||
|
);
|
||||||
|
|
||||||
|
const [left, right] = findAll(PAGE.detail.versionDropdown);
|
||||||
|
assert.dom(PAGE.diff.visualDiff).hasText(
|
||||||
|
`foo\"bar\"hello\"world\"`, // eslint-disable-line no-useless-escape
|
||||||
|
'correctly pull in the data from version 4 and compared to version 1.'
|
||||||
|
);
|
||||||
|
assert.dom(PAGE.diff.deleted).hasText(`hello"world"`);
|
||||||
|
assert.dom(PAGE.diff.added).hasText(`foo"bar"`);
|
||||||
|
assert.dom(right).hasText('Version 4', 'shows the current version for the left side default version.');
|
||||||
|
assert.dom(left).hasText('Version 1', 'shows the latest active version on init.');
|
||||||
|
|
||||||
|
await click(left);
|
||||||
|
|
||||||
|
for (const num in this.metadata.versions) {
|
||||||
|
const data = this.metadata.versions[num];
|
||||||
|
assert.dom(PAGE.detail.version(num)).exists('renders the button for each version.');
|
||||||
|
|
||||||
|
if (data.destroyed || data.deletion_time) {
|
||||||
|
assert
|
||||||
|
.dom(`${PAGE.detail.version(num)} [data-test-icon="x-square-fill"]`)
|
||||||
|
.hasClass(`${data.destroyed ? 'has-text-danger' : 'has-text-grey'}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert
|
||||||
|
.dom(`${PAGE.detail.version('1')} button`)
|
||||||
|
.hasClass('is-active', 'correctly shows the selected version 1 as active.');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user