mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-03 20:40:45 -05:00
UI: Update custom messages to be enterprise only feature (#25633)
* Update custom messages to be enterprise only feature * Fix tests! * Update changelog to be enterprise * Update tests to use mirage
This commit is contained in:
parent
19aeaa57a6
commit
770a3e0c8e
9 changed files with 168 additions and 70 deletions
|
|
@ -1,3 +0,0 @@
|
|||
```release-note:feature
|
||||
**Custom messages**: Introduces custom messages settings, allowing users to view, and operators to configure system-wide messages.
|
||||
```
|
||||
3
changelog/_23945.txt
Normal file
3
changelog/_23945.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
**Custom messages (enterprise)**: Introduces custom messages settings, allowing users to view, and operators to configure system-wide messages.
|
||||
```
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if (has-permission "settings")}}
|
||||
{{#if (and this.version.isEnterprise (has-permission "settings"))}}
|
||||
<Nav.Title data-test-sidebar-nav-heading="Settings">Settings</Nav.Title>
|
||||
<Nav.Link
|
||||
@route="vault.cluster.config-ui.messages"
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ export default Controller.extend({
|
|||
transition = this.router.transitionTo('vault.cluster', { queryParams: { namespace } });
|
||||
}
|
||||
transition.followRedirects().then(() => {
|
||||
this.customMessages.fetchMessages(namespace);
|
||||
if (this.version.isEnterprise) {
|
||||
this.customMessages.fetchMessages(namespace);
|
||||
}
|
||||
|
||||
if (isRoot) {
|
||||
this.auth.set('isRootToken', true);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@ export default Route.extend(ModelBoundaryRoute, {
|
|||
this.flashMessages.clearMessages();
|
||||
this.permissions.reset();
|
||||
this.version.version = null;
|
||||
this.customMessages.clearCustomMessages();
|
||||
|
||||
if (this.version.isEnterprise) {
|
||||
this.customMessages.clearCustomMessages();
|
||||
}
|
||||
|
||||
queryParams.with = authType;
|
||||
if (ns) {
|
||||
|
|
|
|||
|
|
@ -3,64 +3,66 @@
|
|||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
<Sidebar::Nav::Cluster />
|
||||
{{#each this.customMessages.bannerMessages as |bannerMessage|}}
|
||||
{{#if (get this.customMessages.bannerState bannerMessage.id)}}
|
||||
<Hds::Alert
|
||||
@type="inline"
|
||||
@color="highlight"
|
||||
data-test-custom-alert={{bannerMessage.id}}
|
||||
@onDismiss={{fn this.customMessages.onBannerDismiss bannerMessage.id}}
|
||||
as |A|
|
||||
>
|
||||
<A.Title data-test-custom-alert-title={{bannerMessage.id}}>{{bannerMessage.title}}</A.Title>
|
||||
{{#each (new-line-split bannerMessage.message) as |msg|}}
|
||||
<A.Description data-test-custom-alert-description={{bannerMessage.id}}>
|
||||
{{msg}}
|
||||
</A.Description>
|
||||
{{/each}}
|
||||
{{#unless (is-empty-value bannerMessage.link)}}
|
||||
{{#each-in bannerMessage.link as |title href|}}
|
||||
<A.Link::Standalone
|
||||
@color="secondary"
|
||||
@icon="external-link"
|
||||
@isHrefExternal={{true}}
|
||||
@iconPosition="trailing"
|
||||
@text={{title}}
|
||||
@href={{href}}
|
||||
data-test-custom-alert-action="link"
|
||||
/>
|
||||
{{/each-in}}
|
||||
{{/unless}}
|
||||
</Hds::Alert>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each this.customMessages.modalMessages as |modalMessage|}}
|
||||
<Hds::Modal id={{modalMessage.id}} @size="large" @color="warning" data-test-modal={{modalMessage.id}} as |M|>
|
||||
<M.Header data-test-modal-title={{modalMessage.id}}>
|
||||
{{modalMessage.title}}
|
||||
</M.Header>
|
||||
<M.Body data-test-modal-body={{modalMessage.id}}>
|
||||
{{#each (new-line-split modalMessage.message) as |msg|}}
|
||||
{{#if (eq msg "")}}
|
||||
<br />
|
||||
{{else}}
|
||||
<div>
|
||||
{{#if this.vaultVersion.isEnterprise}}
|
||||
{{#each this.customMessages.bannerMessages as |bannerMessage|}}
|
||||
{{#if (get this.customMessages.bannerState bannerMessage.id)}}
|
||||
<Hds::Alert
|
||||
@type="inline"
|
||||
@color="highlight"
|
||||
data-test-custom-alert={{bannerMessage.id}}
|
||||
@onDismiss={{fn this.customMessages.onBannerDismiss bannerMessage.id}}
|
||||
as |A|
|
||||
>
|
||||
<A.Title data-test-custom-alert-title={{bannerMessage.id}}>{{bannerMessage.title}}</A.Title>
|
||||
{{#each (new-line-split bannerMessage.message) as |msg|}}
|
||||
<A.Description data-test-custom-alert-description={{bannerMessage.id}}>
|
||||
{{msg}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#unless (is-empty-value modalMessage.link)}}
|
||||
{{#each-in modalMessage.link as |title href|}}
|
||||
<Hds::Link::Inline @icon="external-link" @isHrefExternal={{true}} @href={{href}}>{{title}}</Hds::Link::Inline>
|
||||
{{/each-in}}
|
||||
{{/unless}}
|
||||
</M.Body>
|
||||
</A.Description>
|
||||
{{/each}}
|
||||
{{#unless (is-empty-value bannerMessage.link)}}
|
||||
{{#each-in bannerMessage.link as |title href|}}
|
||||
<A.Link::Standalone
|
||||
@color="secondary"
|
||||
@icon="external-link"
|
||||
@isHrefExternal={{true}}
|
||||
@iconPosition="trailing"
|
||||
@text={{title}}
|
||||
@href={{href}}
|
||||
data-test-custom-alert-action="link"
|
||||
/>
|
||||
{{/each-in}}
|
||||
{{/unless}}
|
||||
</Hds::Alert>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each this.customMessages.modalMessages as |modalMessage|}}
|
||||
<Hds::Modal id={{modalMessage.id}} @size="large" @color="warning" data-test-modal={{modalMessage.id}} as |M|>
|
||||
<M.Header data-test-modal-title={{modalMessage.id}}>
|
||||
{{modalMessage.title}}
|
||||
</M.Header>
|
||||
<M.Body data-test-modal-body={{modalMessage.id}}>
|
||||
{{#each (new-line-split modalMessage.message) as |msg|}}
|
||||
{{#if (eq msg "")}}
|
||||
<br />
|
||||
{{else}}
|
||||
<div>
|
||||
{{msg}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#unless (is-empty-value modalMessage.link)}}
|
||||
{{#each-in modalMessage.link as |title href|}}
|
||||
<Hds::Link::Inline @icon="external-link" @isHrefExternal={{true}} @href={{href}}>{{title}}</Hds::Link::Inline>
|
||||
{{/each-in}}
|
||||
{{/unless}}
|
||||
</M.Body>
|
||||
|
||||
<M.Footer as |F|>
|
||||
<Hds::Button @text="Confirm" {{on "click" F.close}} data-test-modal-button={{modalMessage.id}} />
|
||||
</M.Footer>
|
||||
</Hds::Modal>
|
||||
{{/each}}
|
||||
<M.Footer as |F|>
|
||||
<Hds::Button @text="Confirm" {{on "click" F.close}} data-test-modal-button={{modalMessage.id}} />
|
||||
</M.Footer>
|
||||
</Hds::Modal>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
<div class="cluster-banners-wrapper">
|
||||
{{#if this.activeCluster.version.isEnterprise}}
|
||||
<LicenseBanners
|
||||
|
|
|
|||
|
|
@ -14,12 +14,68 @@ import { datetimeLocalStringFormat } from 'core/utils/date-formatters';
|
|||
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors';
|
||||
import { clickTrigger } from 'ember-power-select/test-support/helpers';
|
||||
|
||||
module('Acceptance | config-ui', function (hooks) {
|
||||
module('Acceptance | Community | config-ui/messages', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
this.server.get('sys/internal/ui/version', function () {
|
||||
return {
|
||||
data: {
|
||||
version: '1.16.0',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
this.server.get('/sys/health', function () {
|
||||
return {
|
||||
enterprise: false,
|
||||
initialized: true,
|
||||
sealed: false,
|
||||
standby: false,
|
||||
license: {
|
||||
expiry: '2024-01-12T23:20:50.52Z',
|
||||
state: 'stored',
|
||||
},
|
||||
performance_standby: false,
|
||||
replication_performance_mode: 'disabled',
|
||||
replication_dr_mode: 'disabled',
|
||||
server_time_utc: 1622562585,
|
||||
version: '1.16.0',
|
||||
cluster_name: 'vault-cluster-e779cd7c',
|
||||
cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
|
||||
last_wal: 121,
|
||||
};
|
||||
});
|
||||
await authPage.login();
|
||||
});
|
||||
|
||||
hooks.afterEach(async function () {
|
||||
await logout.visit();
|
||||
});
|
||||
|
||||
test('it should hide the sidebar settings section on community', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.dom(PAGE.navLink).doesNotExist();
|
||||
});
|
||||
});
|
||||
|
||||
module('Acceptance | Enterprise | config-ui/message', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
this.createMessage = async (messageType = 'banner', endTime = '2023-12-12', authenticated = true) => {
|
||||
await click(PAGE.navLink);
|
||||
|
||||
if (authenticated) {
|
||||
await click(PAGE.tab('After user logs in'));
|
||||
await click(PAGE.button('create message'));
|
||||
} else {
|
||||
await click(PAGE.tab('On login page'));
|
||||
await click(PAGE.button('create message'));
|
||||
}
|
||||
|
||||
await visit(`vault/config-ui/messages?authenticated=${authenticated}`);
|
||||
await click(PAGE.button('create message'));
|
||||
await fillIn(PAGE.input('title'), 'Awesome custom message title');
|
||||
|
|
@ -44,15 +100,42 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
|
||||
await click(PAGE.button('create-message'));
|
||||
};
|
||||
this.server.get('sys/internal/ui/version', function () {
|
||||
return {
|
||||
data: {
|
||||
version: '1.16.0+ent',
|
||||
},
|
||||
};
|
||||
});
|
||||
this.server.get('/sys/health', function () {
|
||||
return {
|
||||
enterprise: true,
|
||||
initialized: true,
|
||||
sealed: false,
|
||||
standby: false,
|
||||
license: {
|
||||
expiry: '2024-01-12T23:20:50.52Z',
|
||||
state: 'stored',
|
||||
},
|
||||
performance_standby: false,
|
||||
replication_performance_mode: 'disabled',
|
||||
replication_dr_mode: 'disabled',
|
||||
server_time_utc: 1622562585,
|
||||
version: '1.16.0+ent',
|
||||
cluster_name: 'vault-cluster-e779cd7c',
|
||||
cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
|
||||
last_wal: 121,
|
||||
};
|
||||
});
|
||||
await authPage.login();
|
||||
});
|
||||
|
||||
hooks.afterEach(async function () {
|
||||
await logout.visit();
|
||||
});
|
||||
|
||||
test('it should show an empty state when no messages are created', async function (assert) {
|
||||
assert.expect(4);
|
||||
await visit('vault/config-ui/messages');
|
||||
await click(PAGE.navLink);
|
||||
assert.dom('[data-test-component="empty-state"]').exists();
|
||||
assert.dom(PAGE.emptyStateTitle).hasText('No messages yet');
|
||||
await click(PAGE.tab('On login page'));
|
||||
|
|
@ -134,7 +217,8 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
});
|
||||
test('it should display preview a message when all required fields are filled out', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(`vault/config-ui/messages`);
|
||||
await click(PAGE.navLink);
|
||||
await click(PAGE.tab('After user logs in'));
|
||||
await click(PAGE.button('create message'));
|
||||
await fillIn(PAGE.input('title'), 'Awesome custom message title');
|
||||
await click(PAGE.radio('banner'));
|
||||
|
|
@ -153,7 +237,8 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
});
|
||||
test('it should not display preview a message when all required fields are not filled out', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(`vault/config-ui/messages`);
|
||||
await click(PAGE.navLink);
|
||||
await click(PAGE.tab('After user logs in'));
|
||||
await click(PAGE.button('create message'));
|
||||
await click(PAGE.radio('banner'));
|
||||
await fillIn(
|
||||
|
|
@ -203,7 +288,8 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
});
|
||||
test('it should show info message on create and edit form', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit('vault/config-ui/messages?authenticated=false');
|
||||
await click(PAGE.navLink);
|
||||
await click(PAGE.tab('On login page'));
|
||||
await click(PAGE.button('create message'));
|
||||
assert
|
||||
.dom(PAGE.unauthCreateFormInfo)
|
||||
|
|
@ -213,7 +299,8 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
});
|
||||
test('it should display preview a message when all required fields are filled out', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit('vault/config-ui/messages?authenticated=false');
|
||||
await click(PAGE.navLink);
|
||||
await click(PAGE.tab('On login page'));
|
||||
await click(PAGE.button('create message'));
|
||||
await fillIn(PAGE.input('title'), 'Awesome custom message title');
|
||||
await click(PAGE.radio('banner'));
|
||||
|
|
@ -232,7 +319,8 @@ module('Acceptance | config-ui', function (hooks) {
|
|||
});
|
||||
test('it should not display preview a message when all required fields are not filled out', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit('vault/config-ui/messages?authenticated=false');
|
||||
await click(PAGE.navLink);
|
||||
await click(PAGE.tab('On login page'));
|
||||
await click(PAGE.button('create message'));
|
||||
await click(PAGE.radio('banner'));
|
||||
await fillIn(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { setupApplicationTest } from 'ember-qunit';
|
|||
import { click, visit, fillIn, currentRouteName } from '@ember/test-helpers';
|
||||
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
|
||||
import authPage from 'vault/tests/pages/auth';
|
||||
import { datetimeLocalStringFormat } from 'core/utils/date-formatters';
|
||||
import { format, addDays, startOfDay } from 'date-fns';
|
||||
|
|
@ -50,6 +51,7 @@ const unauthenticatedMessageResponse = {
|
|||
mount_type: '',
|
||||
};
|
||||
|
||||
// custom messages is an enterprise feature, but since we're using mirage enterprise is omitted from the module name.
|
||||
module('Acceptance | auth custom messages auth tests', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const PAGE = {
|
|||
...GENERAL,
|
||||
inlineErrorMessage: `[data-test-inline-error-message]`,
|
||||
unauthCreateFormInfo: '[data-test-unauth-info]',
|
||||
navLink: '[data-test-sidebar-nav-link="Custom Messages"]',
|
||||
radio: (radioName) => `[data-test-radio="${radioName}"]`,
|
||||
field: (fieldName) => `[data-test-field="${fieldName}"]`,
|
||||
input: (input) => `[data-test-input="${input}"]`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue