mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 02:02:43 +00:00 
			
		
		
		
	* updates clients config view for census reporting * adds changelog entry * fixes issue with modal staying open and error not showing on clients config save failure * adds min retention months to clients config model and form validation
This commit is contained in:
		
							
								
								
									
										3
									
								
								changelog/20125.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/20125.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:improvement | ||||||
|  | ui: updates clients configuration edit form state based on census reporting configuration | ||||||
|  | ``` | ||||||
| @@ -18,9 +18,11 @@ import { task } from 'ember-concurrency'; | |||||||
|  |  | ||||||
| export default class ConfigComponent extends Component { | export default class ConfigComponent extends Component { | ||||||
|   @service router; |   @service router; | ||||||
|  |  | ||||||
|   @tracked mode = 'show'; |   @tracked mode = 'show'; | ||||||
|   @tracked modalOpen = false; |   @tracked modalOpen = false; | ||||||
|   error = null; |   @tracked validations; | ||||||
|  |   @tracked error = null; | ||||||
|  |  | ||||||
|   get infoRows() { |   get infoRows() { | ||||||
|     return [ |     return [ | ||||||
| @@ -38,38 +40,36 @@ export default class ConfigComponent extends Component { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   get modalTitle() { |   get modalTitle() { | ||||||
|     let content = 'Turn usage tracking off?'; |     return `Turn usage tracking ${this.args.model.enabled.toLowerCase()}?`; | ||||||
|     if (this.args.model && this.args.model.enabled === 'On') { |  | ||||||
|       content = 'Turn usage tracking on?'; |  | ||||||
|     } |  | ||||||
|     return content; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @(task(function* () { |   @(task(function* () { | ||||||
|     try { |     try { | ||||||
|       yield this.args.model.save(); |       yield this.args.model.save(); | ||||||
|  |       this.router.transitionTo('vault.cluster.clients.config'); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       this.error = err.message; |       this.error = err.message; | ||||||
|       return; |       this.modalOpen = false; | ||||||
|     } |     } | ||||||
|     this.router.transitionTo('vault.cluster.clients.config'); |  | ||||||
|   }).drop()) |   }).drop()) | ||||||
|   save; |   save; | ||||||
|  |  | ||||||
|   @action |   @action | ||||||
|   updateBooleanValue(attr, value) { |   toggleEnabled(event) { | ||||||
|     const valueToSet = value === true ? attr.options.trueValue : attr.options.falseValue; |     this.args.model.enabled = event.target.checked ? 'On' : 'Off'; | ||||||
|     this.args.model[attr.name] = valueToSet; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @action |   @action | ||||||
|   onSaveChanges(evt) { |   onSaveChanges(evt) { | ||||||
|     evt.preventDefault(); |     evt.preventDefault(); | ||||||
|  |     const { isValid, state } = this.args.model.validate(); | ||||||
|     const changed = this.args.model.changedAttributes(); |     const changed = this.args.model.changedAttributes(); | ||||||
|     if (!changed.enabled) { |     if (!isValid) { | ||||||
|  |       this.validations = state; | ||||||
|  |     } else if (changed.enabled) { | ||||||
|  |       this.modalOpen = true; | ||||||
|  |     } else { | ||||||
|       this.save.perform(); |       this.save.perform(); | ||||||
|       return; |  | ||||||
|     } |     } | ||||||
|     this.modalOpen = true; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -108,9 +108,11 @@ export function withModelValidations(validations) { | |||||||
|               : validator(get(this, key), options); // dot notation may be used to define key for nested property |               : validator(get(this, key), options); // dot notation may be used to define key for nested property | ||||||
|  |  | ||||||
|             if (!passedValidation) { |             if (!passedValidation) { | ||||||
|  |               // message can also be a function | ||||||
|  |               const validationMessage = typeof message === 'function' ? message(this) : message; | ||||||
|               // consider setting a prop like validationErrors directly on the model |               // consider setting a prop like validationErrors directly on the model | ||||||
|               // for now return an errors object |               // for now return an errors object | ||||||
|               state[key].errors.push(message); |               state[key].errors.push(validationMessage); | ||||||
|               if (isValid) { |               if (isValid) { | ||||||
|                 isValid = false; |                 isValid = false; | ||||||
|               } |               } | ||||||
|   | |||||||
| @@ -1,30 +1,43 @@ | |||||||
| import Model, { attr } from '@ember-data/model'; | import Model, { attr } from '@ember-data/model'; | ||||||
| import { computed } from '@ember/object'; | import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; | ||||||
| import attachCapabilities from 'vault/lib/attach-capabilities'; | import { withFormFields } from 'vault/decorators/model-form-fields'; | ||||||
| import { expandAttributeMeta } from 'vault/utils/field-to-attrs'; | import { withModelValidations } from 'vault/decorators/model-validations'; | ||||||
| import { apiPath } from 'vault/macros/lazy-capabilities'; |  | ||||||
|  |  | ||||||
| const M = Model.extend({ | const validations = { | ||||||
|   queriesAvailable: attr('boolean'), // true only if historical data exists, will be false if there is only current month data |   retentionMonths: [ | ||||||
|   retentionMonths: attr('number', { |     { | ||||||
|  |       validator: (model) => parseInt(model.retentionMonths) >= model.minimumRetentionMonths, | ||||||
|  |       message: (model) => | ||||||
|  |         `Retention period must be greater than or equal to ${model.minimumRetentionMonths}.`, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @withModelValidations(validations) | ||||||
|  | @withFormFields(['enabled', 'retentionMonths']) | ||||||
|  | export default class ClientsConfigModel extends Model { | ||||||
|  |   @attr('boolean') queriesAvailable; // true only if historical data exists, will be false if there is only current month data | ||||||
|  |  | ||||||
|  |   @attr('number', { | ||||||
|     label: 'Retention period', |     label: 'Retention period', | ||||||
|     subText: 'The number of months of activity logs to maintain for client tracking.', |     subText: 'The number of months of activity logs to maintain for client tracking.', | ||||||
|   }), |   }) | ||||||
|   enabled: attr('string', { |   retentionMonths; | ||||||
|     editType: 'boolean', |  | ||||||
|     trueValue: 'On', |  | ||||||
|     falseValue: 'Off', |  | ||||||
|     label: 'Enable usage data collection', |  | ||||||
|     helpText: |  | ||||||
|       'Enable or disable client tracking. Keep in mind that disabling tracking will delete the data for the current month.', |  | ||||||
|   }), |  | ||||||
|  |  | ||||||
|   configAttrs: computed(function () { |   @attr('number') minimumRetentionMonths; | ||||||
|     const keys = ['enabled', 'retentionMonths']; |  | ||||||
|     return expandAttributeMeta(this, keys); |  | ||||||
|   }), |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| export default attachCapabilities(M, { |   @attr('string') enabled; | ||||||
|   configPath: apiPath`sys/internal/counters/config`, |  | ||||||
| }); |   @attr('boolean') reportingEnabled; | ||||||
|  |  | ||||||
|  |   @attr('date') billingStartTimestamp; | ||||||
|  |  | ||||||
|  |   @lazyCapabilities(apiPath`sys/internal/counters/config`) configPath; | ||||||
|  |  | ||||||
|  |   get canRead() { | ||||||
|  |     return this.configPath.get('canRead') !== false; | ||||||
|  |   } | ||||||
|  |   get canEdit() { | ||||||
|  |     return this.configPath.get('canUpdate') !== false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,80 +1,38 @@ | |||||||
| {{#if (eq @mode "edit")}} | {{#if (eq @mode "edit")}} | ||||||
|   <form onsubmit={{action "onSaveChanges"}} data-test-pricing-metrics-config-form> |   <form onsubmit={{action "onSaveChanges"}} data-test-clients-config-form> | ||||||
|     <div class="box is-sideless is-fullwidth is-marginless"> |     <div class="box is-sideless is-fullwidth is-marginless"> | ||||||
|       <MessageError @model={{@model}} @errorMessage={{this.error}} /> |       <MessageError @model={{@model}} @errorMessage={{this.error}} /> | ||||||
|       {{#each @model.configAttrs as |attr|}} |       {{#each @model.formFields as |attr|}} | ||||||
|         {{#if (and (eq attr.type "string") (eq attr.options.editType "boolean"))}} |         {{#if (eq attr.name "enabled")}} | ||||||
|           <label class="is-label">Usage data collection</label> |           <label class="is-label">Usage data collection</label> | ||||||
|           {{#if attr.options.helpText}} |           <p class="sub-text"> | ||||||
|             <p class="sub-text"> |             Enable or disable client tracking. Keep in mind that disabling tracking will delete the data for the current | ||||||
|               {{attr.options.helpText}} |             month. | ||||||
|               {{#if attr.options.docLink}} |           </p> | ||||||
|                 <DocLink @path={{attr.options.docLink}}> |  | ||||||
|                   See our documentation |  | ||||||
|                 </DocLink> |  | ||||||
|                 for help. |  | ||||||
|               {{/if}} |  | ||||||
|             </p> |  | ||||||
|           {{/if}} |  | ||||||
|           <div class="control is-flex has-bottom-margin-l"> |           <div class="control is-flex has-bottom-margin-l"> | ||||||
|             <input |             <input | ||||||
|               data-test-field |               data-test-input="enabled" | ||||||
|               type="checkbox" |               type="checkbox" | ||||||
|               id={{attr.name}} |               id="enabled" | ||||||
|               name={{attr.name}} |               name="enabled" | ||||||
|               class="switch is-rounded is-success is-small" |               class="switch is-rounded is-success is-small" | ||||||
|               checked={{eq (get @model attr.name) attr.options.trueValue}} |               disabled={{@model.reportingEnabled}} | ||||||
|               onchange={{action (action "updateBooleanValue" attr) value="target.checked"}} |               checked={{eq @model.enabled "On"}} | ||||||
|  |               {{on "change" this.toggleEnabled}} | ||||||
|             /> |             /> | ||||||
|             <label for={{attr.name}}> |             <label for="enabled"> | ||||||
|               {{#if (eq @model.enabled "Off")}} |               Data collection is | ||||||
|                 Data collection is off |               {{lowercase @model.enabled}} | ||||||
|               {{else}} |  | ||||||
|                 Data collection is on |  | ||||||
|               {{/if}} |  | ||||||
|             </label> |             </label> | ||||||
|           </div> |           </div> | ||||||
|         {{else if (eq attr.type "number")}} |         {{else}} | ||||||
|           <div class="has-top-margin-s"> |           <FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.validations}} /> | ||||||
|             <label for={{attr.name}} class="is-label"> |  | ||||||
|               {{attr.options.label}} |  | ||||||
|             </label> |  | ||||||
|             {{#if attr.options.subText}} |  | ||||||
|               <p class="sub-text"> |  | ||||||
|                 {{attr.options.subText}} |  | ||||||
|                 {{#if attr.options.docLink}} |  | ||||||
|                   <DocLink @path={{attr.options.docLink}}> |  | ||||||
|                     See our documentation |  | ||||||
|                   </DocLink> |  | ||||||
|                   for help. |  | ||||||
|                 {{/if}} |  | ||||||
|               </p> |  | ||||||
|             {{/if}} |  | ||||||
|             <div class="control"> |  | ||||||
|               <input |  | ||||||
|                 data-test-field |  | ||||||
|                 id={{attr.name}} |  | ||||||
|                 disabled={{eq @model.enabled "Off"}} |  | ||||||
|                 autocomplete="off" |  | ||||||
|                 spellcheck="false" |  | ||||||
|                 onchange={{action (mut (get @model attr.name)) value="target.value"}} |  | ||||||
|                 value={{or (get @model attr.name) attr.options.defaultValue}} |  | ||||||
|                 class="input" |  | ||||||
|                 maxLength={{attr.options.characterLimit}} |  | ||||||
|               /> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         {{/if}} |         {{/if}} | ||||||
|       {{/each}} |       {{/each}} | ||||||
|     </div> |     </div> | ||||||
|     <div class="field is-grouped-split box is-fullwidth is-bottomless"> |     <div class="field is-grouped-split box is-fullwidth is-bottomless"> | ||||||
|       <div class="control"> |       <div class="control"> | ||||||
|         <button |         <button type="submit" disabled={{this.buttonDisabled}} class="button is-primary" data-test-clients-config-save> | ||||||
|           type="submit" |  | ||||||
|           disabled={{this.buttonDisabled}} |  | ||||||
|           class="button is-primary" |  | ||||||
|           data-test-edit-metrics-config-save={{true}} |  | ||||||
|         > |  | ||||||
|           Save |           Save | ||||||
|         </button> |         </button> | ||||||
|         <LinkTo @route="vault.cluster.clients.config" class="button"> |         <LinkTo @route="vault.cluster.clients.config" class="button"> | ||||||
| @@ -83,6 +41,7 @@ | |||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </form> |   </form> | ||||||
|  |  | ||||||
|   <Modal |   <Modal | ||||||
|     @title={{this.modalTitle}} |     @title={{this.modalTitle}} | ||||||
|     @onClose={{action (mut this.modalOpen) false}} |     @onClose={{action (mut this.modalOpen) false}} | ||||||
| @@ -92,13 +51,13 @@ | |||||||
|   > |   > | ||||||
|     <section class="modal-card-body"> |     <section class="modal-card-body"> | ||||||
|       {{#if (eq @model.enabled "On")}} |       {{#if (eq @model.enabled "On")}} | ||||||
|         <p class="has-bottom-margin-s"> |         <p class="has-bottom-margin-s" data-test-clients-config-modal="on"> | ||||||
|           Vault will start tracking data starting from today’s date, |           Vault will start tracking data starting from today’s date, | ||||||
|           {{date-format (now) "d MMMM yyyy"}}. You will not be able to see or query usage until the end of the month. |           {{date-format (now) "MMMM d, yyyy"}}. If you’ve previously enabled usage tracking, that historical data will still | ||||||
|  |           be available to you. | ||||||
|         </p> |         </p> | ||||||
|         <p>If you’ve previously enabled usage tracking, that historical data will still be available to you.</p> |  | ||||||
|       {{else}} |       {{else}} | ||||||
|         <p class="has-bottom-margin-s"> |         <p class="has-bottom-margin-s" data-test-clients-config-modal="off"> | ||||||
|           Turning usage tracking off means that all data for the current month will be deleted. You will still be able to |           Turning usage tracking off means that all data for the current month will be deleted. You will still be able to | ||||||
|           query previous months. |           query previous months. | ||||||
|         </p> |         </p> | ||||||
| @@ -106,24 +65,26 @@ | |||||||
|       {{/if}} |       {{/if}} | ||||||
|     </section> |     </section> | ||||||
|     <footer class="modal-card-foot modal-card-foot-outlined"> |     <footer class="modal-card-foot modal-card-foot-outlined"> | ||||||
|  |       <button | ||||||
|  |         type="button" | ||||||
|  |         class="button is-primary" | ||||||
|  |         data-test-clients-config-modal="continue" | ||||||
|  |         {{on "click" (perform this.save)}} | ||||||
|  |       > | ||||||
|  |         Continue | ||||||
|  |       </button> | ||||||
|       <button |       <button | ||||||
|         type="button" |         type="button" | ||||||
|         class="button is-secondary" |         class="button is-secondary" | ||||||
|         onclick={{action (mut this.modalOpen) false}} |         {{on "click" (fn (mut this.modalOpen) false)}} | ||||||
|         data-test-metrics-config-cancel |         data-test-clients-config-modal="cancel" | ||||||
|       > |       > | ||||||
|         Cancel |         Cancel | ||||||
|       </button> |       </button> | ||||||
|       <button type="button" class="button is-primary" onclick={{perform this.save}}> |  | ||||||
|         Continue |  | ||||||
|       </button> |  | ||||||
|     </footer> |     </footer> | ||||||
|   </Modal> |   </Modal> | ||||||
| {{else}} | {{else}} | ||||||
|   <div |   <div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" data-test-clients-config-table> | ||||||
|     class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" |  | ||||||
|     data-test-pricing-metrics-config-table |  | ||||||
|   > |  | ||||||
|     {{#each this.infoRows as |item|}} |     {{#each this.infoRows as |item|}} | ||||||
|       <InfoTableRow @label={{item.label}} @helperText={{item.helperText}} @value={{get @model item.valueKey}} /> |       <InfoTableRow @label={{item.label}} @helperText={{item.helperText}} @value={{get @model item.valueKey}} /> | ||||||
|     {{/each}} |     {{/each}} | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ | |||||||
|         @title="Data tracking is disabled" |         @title="Data tracking is disabled" | ||||||
|         @message="Tracking is disabled, and no data is being collected. To turn it on, edit the configuration." |         @message="Tracking is disabled, and no data is being collected. To turn it on, edit the configuration." | ||||||
|       > |       > | ||||||
|         {{#if @model.config.configPath.canUpdate}} |         {{#if @model.config.canEdit}} | ||||||
|           <p> |           <p> | ||||||
|             <LinkTo @route="vault.cluster.clients.config"> |             <LinkTo @route="vault.cluster.clients.config"> | ||||||
|               Go to configuration |               Go to configuration | ||||||
|   | |||||||
| @@ -12,8 +12,11 @@ | |||||||
|       <LinkTo @route="vault.cluster.clients.dashboard" data-test-dashboard> |       <LinkTo @route="vault.cluster.clients.dashboard" data-test-dashboard> | ||||||
|         Dashboard |         Dashboard | ||||||
|       </LinkTo> |       </LinkTo> | ||||||
|       {{#if (or @model.config.configPath.canRead @model.configPath.canRead)}} |       {{#if (or @model.config.canRead @model.canRead)}} | ||||||
|         <LinkTo @route="vault.cluster.clients.config"> |         <LinkTo | ||||||
|  |           @route="vault.cluster.clients.config" | ||||||
|  |           @current-when="vault.cluster.clients.config vault.cluster.clients.edit" | ||||||
|  |         > | ||||||
|           Configuration |           Configuration | ||||||
|         </LinkTo> |         </LinkTo> | ||||||
|       {{/if}} |       {{/if}} | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <Toolbar> | <Toolbar> | ||||||
|   <ToolbarActions> |   <ToolbarActions> | ||||||
|     {{#if @model.configPath.canUpdate}} |     {{#if @model.canEdit}} | ||||||
|       <LinkTo @route="vault.cluster.clients.edit" class="toolbar-link"> |       <LinkTo @route="vault.cluster.clients.edit" class="toolbar-link"> | ||||||
|         Edit configuration |         Edit configuration | ||||||
|       </LinkTo> |       </LinkTo> | ||||||
|   | |||||||
| @@ -1,56 +1,41 @@ | |||||||
| import { module, test } from 'qunit'; | import { module, test } from 'qunit'; | ||||||
| import { setupRenderingTest } from 'ember-qunit'; | import { setupRenderingTest } from 'ember-qunit'; | ||||||
| import { render, find, click } from '@ember/test-helpers'; | import { render, find, click, fillIn } from '@ember/test-helpers'; | ||||||
| import { resolve } from 'rsvp'; | import { setupMirage } from 'ember-cli-mirage/test-support'; | ||||||
| import hbs from 'htmlbars-inline-precompile'; | import hbs from 'htmlbars-inline-precompile'; | ||||||
|  | import sinon from 'sinon'; | ||||||
|  |  | ||||||
| module('Integration | Component | client count config', function (hooks) { | module('Integration | Component | client count config', function (hooks) { | ||||||
|   setupRenderingTest(hooks); |   setupRenderingTest(hooks); | ||||||
|  |   setupMirage(hooks); | ||||||
|   const createAttr = (name, type, options) => { |  | ||||||
|     return { |  | ||||||
|       name, |  | ||||||
|       type, |  | ||||||
|       options, |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const generateModel = (overrides) => { |  | ||||||
|     return { |  | ||||||
|       enabled: 'On', |  | ||||||
|       retentionMonths: 24, |  | ||||||
|       defaultReportMonths: 12, |  | ||||||
|       configAttrs: [ |  | ||||||
|         createAttr('enabled', 'string', { editType: 'boolean' }), |  | ||||||
|         createAttr('retentionMonths', 'number'), |  | ||||||
|       ], |  | ||||||
|       changedAttributes: () => ({}), |  | ||||||
|       save: () => {}, |  | ||||||
|       ...overrides, |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   hooks.beforeEach(function () { |   hooks.beforeEach(function () { | ||||||
|     this.router = this.owner.lookup('service:router'); |     this.router = this.owner.lookup('service:router'); | ||||||
|     this.router.reopen({ |     this.transitionStub = sinon.stub(this.router, 'transitionTo'); | ||||||
|       transitionTo() { |     const store = this.owner.lookup('service:store'); | ||||||
|         return { |     this.createModel = (enabled = 'enable', reporting_enabled = false, minimum_retention_months = 0) => { | ||||||
|           followRedirects() { |       store.pushPayload('clients/config', { | ||||||
|             return resolve(); |         modelName: 'clients/config', | ||||||
|           }, |         id: 'foo', | ||||||
|         }; |         data: { | ||||||
|       }, |           enabled, | ||||||
|     }); |           reporting_enabled, | ||||||
|     const model = generateModel(); |           minimum_retention_months, | ||||||
|     this.model = model; |           retention_months: 24, | ||||||
|  |         }, | ||||||
|  |       }); | ||||||
|  |       this.model = store.peekRecord('clients/config', 'foo'); | ||||||
|  |     }; | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('it shows the table with the correct rows by default', async function (assert) { |   test('it shows the table with the correct rows by default', async function (assert) { | ||||||
|  |     this.createModel(); | ||||||
|  |  | ||||||
|     await render(hbs`<Clients::Config @model={{this.model}} />`); |     await render(hbs`<Clients::Config @model={{this.model}} />`); | ||||||
|  |  | ||||||
|     assert.dom('[data-test-pricing-metrics-config-table]').exists('Pricing metrics config table exists'); |     assert.dom('[data-test-clients-config-table]').exists('Clients config table exists'); | ||||||
|     const rows = document.querySelectorAll('.info-table-row'); |     const rows = document.querySelectorAll('.info-table-row'); | ||||||
|     assert.strictEqual(rows.length, 2, 'renders 2 infotable rows'); |     assert.strictEqual(rows.length, 2, 'renders 2 info table rows'); | ||||||
|     assert.ok( |     assert.ok( | ||||||
|       find('[data-test-row-value="Usage data collection"]').textContent.includes('On'), |       find('[data-test-row-value="Usage data collection"]').textContent.includes('On'), | ||||||
|       'Enabled value matches model' |       'Enabled value matches model' | ||||||
| @@ -61,72 +46,122 @@ module('Integration | Component | client count config', function (hooks) { | |||||||
|     ); |     ); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('TODO: it shows the config edit form when mode = edit', async function (assert) { |   test('it should function in edit mode when reporting is disabled', async function (assert) { | ||||||
|     await render(hbs` |     assert.expect(13); | ||||||
|       <div id="modal-wormhole"></div> |  | ||||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> |  | ||||||
|     `); |  | ||||||
|  |  | ||||||
|     assert.dom('[data-test-pricing-metrics-config-form]').exists('Pricing metrics config form exists'); |     this.server.put('/sys/internal/counters/config', (schema, req) => { | ||||||
|     const fields = document.querySelectorAll('[data-test-field]'); |       const { enabled, retention_months } = JSON.parse(req.requestBody); | ||||||
|     assert.strictEqual(fields.length, 2, 'renders 2 fields'); |       const expected = { enabled: 'enable', retention_months: 5 }; | ||||||
|   }); |       assert.deepEqual(expected, { enabled, retention_months }, 'Correct data sent in PUT request'); | ||||||
|  |       return {}; | ||||||
|   test('it shows a modal with correct messaging when disabling', async function (assert) { |  | ||||||
|     // Simulates the model when enabled value has been changed from On to Off |  | ||||||
|     const simModel = generateModel({ |  | ||||||
|       enabled: 'Off', |  | ||||||
|       changedAttributes: () => ({ enabled: ['On', 'Off'] }), |  | ||||||
|     }); |     }); | ||||||
|     this.set('model', simModel); |  | ||||||
|  |     this.createModel('disable'); | ||||||
|  |  | ||||||
|     await render(hbs` |     await render(hbs` | ||||||
|       <div id="modal-wormhole"></div> |       <div id="modal-wormhole"></div> | ||||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> |       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||||
|     `); |     `); | ||||||
|  |  | ||||||
|     await click('[data-test-edit-metrics-config-save]'); |     assert.dom('[data-test-input="enabled"]').isNotChecked('Data collection checkbox is not checked'); | ||||||
|     assert.dom('.modal.is-active').exists('Modal appears'); |     assert | ||||||
|  |       .dom('label[for="enabled"]') | ||||||
|  |       .hasText('Data collection is off', 'Correct label renders when data collection is off'); | ||||||
|  |     assert.dom('[data-test-input="retentionMonths"]').hasValue('24', 'Retention months render'); | ||||||
|  |  | ||||||
|  |     await click('[data-test-input="enabled"]'); | ||||||
|  |     await fillIn('[data-test-input="retentionMonths"]', -3); | ||||||
|  |     await click('[data-test-clients-config-save]'); | ||||||
|  |     assert | ||||||
|  |       .dom('[data-test-inline-error-message]') | ||||||
|  |       .hasText( | ||||||
|  |         'Retention period must be greater than or equal to 0.', | ||||||
|  |         'Validation error shows for incorrect retention period' | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |     await fillIn('[data-test-input="retentionMonths"]', 5); | ||||||
|  |     await click('[data-test-clients-config-save]'); | ||||||
|  |     assert.dom('.modal.is-active').exists('Modal renders'); | ||||||
|  |     assert | ||||||
|  |       .dom('[data-test-modal-title] span') | ||||||
|  |       .hasText('Turn usage tracking on?', 'Correct modal title renders'); | ||||||
|  |     assert.dom('[data-test-clients-config-modal="on"]').exists('Correct modal description block renders'); | ||||||
|  |  | ||||||
|  |     await click('[data-test-clients-config-modal="continue"]'); | ||||||
|     assert.ok( |     assert.ok( | ||||||
|       find('[data-test-modal-title]').textContent.includes('Turn usage tracking off?'), |       this.transitionStub.calledWith('vault.cluster.clients.config'), | ||||||
|       'Modal confirming turn tracking off' |       'Route transitions correctly on save success' | ||||||
|     ); |     ); | ||||||
|     await click('[data-test-metrics-config-cancel]'); |  | ||||||
|     assert.dom('.modal.is-active').doesNotExist('Modal goes away'); |     await click('[data-test-input="enabled"]'); | ||||||
|  |     await click('[data-test-clients-config-save]'); | ||||||
|  |     assert.dom('.modal.is-active').exists('Modal renders'); | ||||||
|  |     assert | ||||||
|  |       .dom('[data-test-modal-title] span') | ||||||
|  |       .hasText('Turn usage tracking off?', 'Correct modal title renders'); | ||||||
|  |     assert.dom('[data-test-clients-config-modal="off"]').exists('Correct modal description block renders'); | ||||||
|  |  | ||||||
|  |     await click('[data-test-clients-config-modal="cancel"]'); | ||||||
|  |     assert.dom('.modal.is-active').doesNotExist('Modal is hidden on cancel'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('it shows a modal with correct messaging when enabling', async function (assert) { |   test('it should function in edit mode when reporting is enabled', async function (assert) { | ||||||
|     // Simulates the model when enabled value has been changed from On to Off |     assert.expect(6); | ||||||
|     const simModel = generateModel({ |  | ||||||
|       changedAttributes: () => ({ enabled: ['Off', 'On'] }), |     this.server.put('/sys/internal/counters/config', (schema, req) => { | ||||||
|  |       const { enabled, retention_months } = JSON.parse(req.requestBody); | ||||||
|  |       const expected = { enabled: 'enable', retention_months: 48 }; | ||||||
|  |       assert.deepEqual(expected, { enabled, retention_months }, 'Correct data sent in PUT request'); | ||||||
|  |       return {}; | ||||||
|     }); |     }); | ||||||
|     this.set('model', simModel); |  | ||||||
|  |     this.createModel('enable', true, 24); | ||||||
|  |  | ||||||
|     await render(hbs` |     await render(hbs` | ||||||
|       <div id="modal-wormhole"></div> |       <div id="modal-wormhole"></div> | ||||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> |       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||||
|     `); |     `); | ||||||
|  |  | ||||||
|     await click('[data-test-edit-metrics-config-save]'); |     assert.dom('[data-test-input="enabled"]').isChecked('Data collection input is checked'); | ||||||
|     assert.dom('.modal.is-active').exists('Modal appears'); |     assert | ||||||
|     assert.ok( |       .dom('[data-test-input="enabled"]') | ||||||
|       find('[data-test-modal-title]').textContent.includes('Turn usage tracking on?'), |       .isDisabled('Data collection input disabled when reporting is enabled'); | ||||||
|       'Modal confirming turn tracking on' |     assert | ||||||
|     ); |       .dom('label[for="enabled"]') | ||||||
|     await click('[data-test-metrics-config-cancel]'); |       .hasText('Data collection is on', 'Correct label renders when data collection is on'); | ||||||
|     assert.dom('.modal.is-active').doesNotExist('Modal goes away'); |     assert.dom('[data-test-input="retentionMonths"]').hasValue('24', 'Retention months render'); | ||||||
|  |  | ||||||
|  |     await fillIn('[data-test-input="retentionMonths"]', 5); | ||||||
|  |     await click('[data-test-clients-config-save]'); | ||||||
|  |     assert | ||||||
|  |       .dom('[data-test-inline-error-message]') | ||||||
|  |       .hasText( | ||||||
|  |         'Retention period must be greater than or equal to 24.', | ||||||
|  |         'Validation error shows for incorrect retention period' | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |     await fillIn('[data-test-input="retentionMonths"]', 48); | ||||||
|  |     await click('[data-test-clients-config-save]'); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   test('it does not show a modal on save if enable left unchanged', async function (assert) { |   test('it should not show modal when data collection is not changed', async function (assert) { | ||||||
|     // Simulates the model when something other than enabled changed |     assert.expect(1); | ||||||
|     const simModel = generateModel({ |  | ||||||
|       changedAttributes: () => ({ retentionMonths: [24, '48'] }), |     this.server.put('/sys/internal/counters/config', (schema, req) => { | ||||||
|  |       const { enabled, retention_months } = JSON.parse(req.requestBody); | ||||||
|  |       const expected = { enabled: 'enable', retention_months: 5 }; | ||||||
|  |       assert.deepEqual(expected, { enabled, retention_months }, 'Correct data sent in PUT request'); | ||||||
|  |       return {}; | ||||||
|     }); |     }); | ||||||
|     this.set('model', simModel); |  | ||||||
|  |     this.createModel(); | ||||||
|  |  | ||||||
|     await render(hbs` |     await render(hbs` | ||||||
|       <div id="modal-wormhole"></div> |       <div id="modal-wormhole"></div> | ||||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> |       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||||
|     `); |     `); | ||||||
|  |  | ||||||
|     await click('[data-test-edit-metrics-config-save]'); |     await fillIn('[data-test-input="retentionMonths"]', 5); | ||||||
|     assert.dom('.modal.is-active').doesNotExist('No modal appears'); |     await click('[data-test-clients-config-save]'); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jordan Reimer
					Jordan Reimer