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:
Kianna 2024-02-26 13:16:21 -08:00 committed by GitHub
parent 19aeaa57a6
commit 770a3e0c8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 168 additions and 70 deletions

View file

@ -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
View 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.
```

View file

@ -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"

View file

@ -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);

View file

@ -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) {

View file

@ -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

View file

@ -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(

View file

@ -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);

View file

@ -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}"]`,