mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 18:17:55 +00:00 
			
		
		
		
	Clients config updates for census reporting (#20125)
* 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 | ||||
| ``` | ||||
| @@ -23,9 +23,11 @@ import { task } from 'ember-concurrency'; | ||||
|  | ||||
| export default class ConfigComponent extends Component { | ||||
|   @service router; | ||||
|  | ||||
|   @tracked mode = 'show'; | ||||
|   @tracked modalOpen = false; | ||||
|   error = null; | ||||
|   @tracked validations; | ||||
|   @tracked error = null; | ||||
|  | ||||
|   get infoRows() { | ||||
|     return [ | ||||
| @@ -43,38 +45,36 @@ export default class ConfigComponent extends Component { | ||||
|   } | ||||
|  | ||||
|   get modalTitle() { | ||||
|     let content = 'Turn usage tracking off?'; | ||||
|     if (this.args.model && this.args.model.enabled === 'On') { | ||||
|       content = 'Turn usage tracking on?'; | ||||
|     } | ||||
|     return content; | ||||
|     return `Turn usage tracking ${this.args.model.enabled.toLowerCase()}?`; | ||||
|   } | ||||
|  | ||||
|   @(task(function* () { | ||||
|     try { | ||||
|       yield this.args.model.save(); | ||||
|       this.router.transitionTo('vault.cluster.clients.config'); | ||||
|     } catch (err) { | ||||
|       this.error = err.message; | ||||
|       return; | ||||
|       this.modalOpen = false; | ||||
|     } | ||||
|     this.router.transitionTo('vault.cluster.clients.config'); | ||||
|   }).drop()) | ||||
|   save; | ||||
|  | ||||
|   @action | ||||
|   updateBooleanValue(attr, value) { | ||||
|     const valueToSet = value === true ? attr.options.trueValue : attr.options.falseValue; | ||||
|     this.args.model[attr.name] = valueToSet; | ||||
|   toggleEnabled(event) { | ||||
|     this.args.model.enabled = event.target.checked ? 'On' : 'Off'; | ||||
|   } | ||||
|  | ||||
|   @action | ||||
|   onSaveChanges(evt) { | ||||
|     evt.preventDefault(); | ||||
|     const { isValid, state } = this.args.model.validate(); | ||||
|     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(); | ||||
|       return; | ||||
|     } | ||||
|     this.modalOpen = true; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import { get } from '@ember/object'; | ||||
|  * options - an optional object for given validator -- min, max, nullable etc. -- see validators in util | ||||
|  * | ||||
|  * message - string added to the errors array and returned from the validate method if validation fails | ||||
|  * function may also be provided with model as single argument that returns a string | ||||
|  * | ||||
|  * level - optional string that defaults to 'error'. Currently the only other accepted value is 'warn' | ||||
|  * | ||||
| @@ -120,12 +121,14 @@ export function withModelValidations(validations) { | ||||
|               : validator(get(this, key), options); // dot notation may be used to define key for nested property | ||||
|  | ||||
|             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 | ||||
|               // for now return an errors object | ||||
|               if (level === 'warn') { | ||||
|                 state[key].warnings.push(message); | ||||
|                 state[key].warnings.push(validationMessage); | ||||
|               } else { | ||||
|                 state[key].errors.push(message); | ||||
|                 state[key].errors.push(validationMessage); | ||||
|                 if (isValid) { | ||||
|                   isValid = false; | ||||
|                 } | ||||
|   | ||||
| @@ -4,32 +4,45 @@ | ||||
|  */ | ||||
|  | ||||
| import Model, { attr } from '@ember-data/model'; | ||||
| import { computed } from '@ember/object'; | ||||
| import attachCapabilities from 'vault/lib/attach-capabilities'; | ||||
| import { expandAttributeMeta } from 'vault/utils/field-to-attrs'; | ||||
| import { apiPath } from 'vault/macros/lazy-capabilities'; | ||||
| import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; | ||||
| import { withFormFields } from 'vault/decorators/model-form-fields'; | ||||
| import { withModelValidations } from 'vault/decorators/model-validations'; | ||||
|  | ||||
| const M = Model.extend({ | ||||
|   queriesAvailable: attr('boolean'), // true only if historical data exists, will be false if there is only current month data | ||||
|   retentionMonths: attr('number', { | ||||
| const validations = { | ||||
|   retentionMonths: [ | ||||
|     { | ||||
|       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', | ||||
|     subText: 'The number of months of activity logs to maintain for client tracking.', | ||||
|   }), | ||||
|   enabled: attr('string', { | ||||
|     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.', | ||||
|   }), | ||||
|   }) | ||||
|   retentionMonths; | ||||
|  | ||||
|   configAttrs: computed(function () { | ||||
|     const keys = ['enabled', 'retentionMonths']; | ||||
|     return expandAttributeMeta(this, keys); | ||||
|   }), | ||||
| }); | ||||
|   @attr('number') minimumRetentionMonths; | ||||
|  | ||||
| export default attachCapabilities(M, { | ||||
|   configPath: apiPath`sys/internal/counters/config`, | ||||
| }); | ||||
|   @attr('string') enabled; | ||||
|  | ||||
|   @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")}} | ||||
|   <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"> | ||||
|       <MessageError @model={{@model}} @errorMessage={{this.error}} /> | ||||
|       {{#each @model.configAttrs as |attr|}} | ||||
|         {{#if (and (eq attr.type "string") (eq attr.options.editType "boolean"))}} | ||||
|       {{#each @model.formFields as |attr|}} | ||||
|         {{#if (eq attr.name "enabled")}} | ||||
|           <label class="is-label">Usage data collection</label> | ||||
|           {{#if attr.options.helpText}} | ||||
|             <p class="sub-text"> | ||||
|               {{attr.options.helpText}} | ||||
|               {{#if attr.options.docLink}} | ||||
|                 <DocLink @path={{attr.options.docLink}}> | ||||
|                   See our documentation | ||||
|                 </DocLink> | ||||
|                 for help. | ||||
|               {{/if}} | ||||
|             </p> | ||||
|           {{/if}} | ||||
|           <p class="sub-text"> | ||||
|             Enable or disable client tracking. Keep in mind that disabling tracking will delete the data for the current | ||||
|             month. | ||||
|           </p> | ||||
|           <div class="control is-flex has-bottom-margin-l"> | ||||
|             <input | ||||
|               data-test-field | ||||
|               data-test-input="enabled" | ||||
|               type="checkbox" | ||||
|               id={{attr.name}} | ||||
|               name={{attr.name}} | ||||
|               id="enabled" | ||||
|               name="enabled" | ||||
|               class="switch is-rounded is-success is-small" | ||||
|               checked={{eq (get @model attr.name) attr.options.trueValue}} | ||||
|               onchange={{action (action "updateBooleanValue" attr) value="target.checked"}} | ||||
|               disabled={{@model.reportingEnabled}} | ||||
|               checked={{eq @model.enabled "On"}} | ||||
|               {{on "change" this.toggleEnabled}} | ||||
|             /> | ||||
|             <label for={{attr.name}}> | ||||
|               {{#if (eq @model.enabled "Off")}} | ||||
|                 Data collection is off | ||||
|               {{else}} | ||||
|                 Data collection is on | ||||
|               {{/if}} | ||||
|             <label for="enabled"> | ||||
|               Data collection is | ||||
|               {{lowercase @model.enabled}} | ||||
|             </label> | ||||
|           </div> | ||||
|         {{else if (eq attr.type "number")}} | ||||
|           <div class="has-top-margin-s"> | ||||
|             <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> | ||||
|         {{else}} | ||||
|           <FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.validations}} /> | ||||
|         {{/if}} | ||||
|       {{/each}} | ||||
|     </div> | ||||
|     <div class="field is-grouped-split box is-fullwidth is-bottomless"> | ||||
|       <div class="control"> | ||||
|         <button | ||||
|           type="submit" | ||||
|           disabled={{this.buttonDisabled}} | ||||
|           class="button is-primary" | ||||
|           data-test-edit-metrics-config-save={{true}} | ||||
|         > | ||||
|         <button type="submit" disabled={{this.buttonDisabled}} class="button is-primary" data-test-clients-config-save> | ||||
|           Save | ||||
|         </button> | ||||
|         <LinkTo @route="vault.cluster.clients.config" class="button"> | ||||
| @@ -83,6 +41,7 @@ | ||||
|       </div> | ||||
|     </div> | ||||
|   </form> | ||||
|  | ||||
|   <Modal | ||||
|     @title={{this.modalTitle}} | ||||
|     @onClose={{action (mut this.modalOpen) false}} | ||||
| @@ -92,13 +51,13 @@ | ||||
|   > | ||||
|     <section class="modal-card-body"> | ||||
|       {{#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, | ||||
|           {{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>If you’ve previously enabled usage tracking, that historical data will still be available to you.</p> | ||||
|       {{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 | ||||
|           query previous months. | ||||
|         </p> | ||||
| @@ -106,24 +65,26 @@ | ||||
|       {{/if}} | ||||
|     </section> | ||||
|     <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 | ||||
|         type="button" | ||||
|         class="button is-secondary" | ||||
|         onclick={{action (mut this.modalOpen) false}} | ||||
|         data-test-metrics-config-cancel | ||||
|         {{on "click" (fn (mut this.modalOpen) false)}} | ||||
|         data-test-clients-config-modal="cancel" | ||||
|       > | ||||
|         Cancel | ||||
|       </button> | ||||
|       <button type="button" class="button is-primary" onclick={{perform this.save}}> | ||||
|         Continue | ||||
|       </button> | ||||
|     </footer> | ||||
|   </Modal> | ||||
| {{else}} | ||||
|   <div | ||||
|     class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" | ||||
|     data-test-pricing-metrics-config-table | ||||
|   > | ||||
|   <div class="tabs-container box is-bottomless is-marginless is-fullwidth is-paddingless" data-test-clients-config-table> | ||||
|     {{#each this.infoRows as |item|}} | ||||
|       <InfoTableRow @label={{item.label}} @helperText={{item.helperText}} @value={{get @model item.valueKey}} /> | ||||
|     {{/each}} | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
|         @title="Data tracking is disabled" | ||||
|         @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> | ||||
|             <LinkTo @route="vault.cluster.clients.config"> | ||||
|               Go to configuration | ||||
|   | ||||
| @@ -12,8 +12,11 @@ | ||||
|       <LinkTo @route="vault.cluster.clients.dashboard" data-test-dashboard> | ||||
|         Dashboard | ||||
|       </LinkTo> | ||||
|       {{#if (or @model.config.configPath.canRead @model.configPath.canRead)}} | ||||
|         <LinkTo @route="vault.cluster.clients.config"> | ||||
|       {{#if (or @model.config.canRead @model.canRead)}} | ||||
|         <LinkTo | ||||
|           @route="vault.cluster.clients.config" | ||||
|           @current-when="vault.cluster.clients.config vault.cluster.clients.edit" | ||||
|         > | ||||
|           Configuration | ||||
|         </LinkTo> | ||||
|       {{/if}} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <Toolbar> | ||||
|   <ToolbarActions> | ||||
|     {{#if @model.configPath.canUpdate}} | ||||
|     {{#if @model.canEdit}} | ||||
|       <LinkTo @route="vault.cluster.clients.edit" class="toolbar-link"> | ||||
|         Edit configuration | ||||
|       </LinkTo> | ||||
|   | ||||
| @@ -5,57 +5,42 @@ | ||||
|  | ||||
| import { module, test } from 'qunit'; | ||||
| import { setupRenderingTest } from 'ember-qunit'; | ||||
| import { render, find, click } from '@ember/test-helpers'; | ||||
| import { resolve } from 'rsvp'; | ||||
| import { render, find, click, fillIn } from '@ember/test-helpers'; | ||||
| import { setupMirage } from 'ember-cli-mirage/test-support'; | ||||
| import hbs from 'htmlbars-inline-precompile'; | ||||
| import sinon from 'sinon'; | ||||
|  | ||||
| module('Integration | Component | client count config', function (hooks) { | ||||
|   setupRenderingTest(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, | ||||
|     }; | ||||
|   }; | ||||
|   setupMirage(hooks); | ||||
|  | ||||
|   hooks.beforeEach(function () { | ||||
|     this.router = this.owner.lookup('service:router'); | ||||
|     this.router.reopen({ | ||||
|       transitionTo() { | ||||
|         return { | ||||
|           followRedirects() { | ||||
|             return resolve(); | ||||
|           }, | ||||
|         }; | ||||
|       }, | ||||
|     }); | ||||
|     const model = generateModel(); | ||||
|     this.model = model; | ||||
|     this.transitionStub = sinon.stub(this.router, 'transitionTo'); | ||||
|     const store = this.owner.lookup('service:store'); | ||||
|     this.createModel = (enabled = 'enable', reporting_enabled = false, minimum_retention_months = 0) => { | ||||
|       store.pushPayload('clients/config', { | ||||
|         modelName: 'clients/config', | ||||
|         id: 'foo', | ||||
|         data: { | ||||
|           enabled, | ||||
|           reporting_enabled, | ||||
|           minimum_retention_months, | ||||
|           retention_months: 24, | ||||
|         }, | ||||
|       }); | ||||
|       this.model = store.peekRecord('clients/config', 'foo'); | ||||
|     }; | ||||
|   }); | ||||
|  | ||||
|   test('it shows the table with the correct rows by default', async function (assert) { | ||||
|     this.createModel(); | ||||
|  | ||||
|     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'); | ||||
|     assert.strictEqual(rows.length, 2, 'renders 2 infotable rows'); | ||||
|     assert.strictEqual(rows.length, 2, 'renders 2 info table rows'); | ||||
|     assert.ok( | ||||
|       find('[data-test-row-value="Usage data collection"]').textContent.includes('On'), | ||||
|       'Enabled value matches model' | ||||
| @@ -66,72 +51,122 @@ module('Integration | Component | client count config', function (hooks) { | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   test('TODO: it shows the config edit form when mode = edit', async function (assert) { | ||||
|     await render(hbs` | ||||
|       <div id="modal-wormhole"></div> | ||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||
|     `); | ||||
|   test('it should function in edit mode when reporting is disabled', async function (assert) { | ||||
|     assert.expect(13); | ||||
|  | ||||
|     assert.dom('[data-test-pricing-metrics-config-form]').exists('Pricing metrics config form exists'); | ||||
|     const fields = document.querySelectorAll('[data-test-field]'); | ||||
|     assert.strictEqual(fields.length, 2, 'renders 2 fields'); | ||||
|   }); | ||||
|  | ||||
|   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.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('disable'); | ||||
|  | ||||
|     await render(hbs` | ||||
|       <div id="modal-wormhole"></div> | ||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||
|     `); | ||||
|  | ||||
|     await click('[data-test-edit-metrics-config-save]'); | ||||
|     assert.dom('.modal.is-active').exists('Modal appears'); | ||||
|     assert.dom('[data-test-input="enabled"]').isNotChecked('Data collection checkbox is not checked'); | ||||
|     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( | ||||
|       find('[data-test-modal-title]').textContent.includes('Turn usage tracking off?'), | ||||
|       'Modal confirming turn tracking off' | ||||
|       this.transitionStub.calledWith('vault.cluster.clients.config'), | ||||
|       '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) { | ||||
|     // Simulates the model when enabled value has been changed from On to Off | ||||
|     const simModel = generateModel({ | ||||
|       changedAttributes: () => ({ enabled: ['Off', 'On'] }), | ||||
|   test('it should function in edit mode when reporting is enabled', async function (assert) { | ||||
|     assert.expect(6); | ||||
|  | ||||
|     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` | ||||
|       <div id="modal-wormhole"></div> | ||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||
|     `); | ||||
|  | ||||
|     await click('[data-test-edit-metrics-config-save]'); | ||||
|     assert.dom('.modal.is-active').exists('Modal appears'); | ||||
|     assert.ok( | ||||
|       find('[data-test-modal-title]').textContent.includes('Turn usage tracking on?'), | ||||
|       'Modal confirming turn tracking on' | ||||
|     ); | ||||
|     await click('[data-test-metrics-config-cancel]'); | ||||
|     assert.dom('.modal.is-active').doesNotExist('Modal goes away'); | ||||
|     assert.dom('[data-test-input="enabled"]').isChecked('Data collection input is checked'); | ||||
|     assert | ||||
|       .dom('[data-test-input="enabled"]') | ||||
|       .isDisabled('Data collection input disabled when reporting is enabled'); | ||||
|     assert | ||||
|       .dom('label[for="enabled"]') | ||||
|       .hasText('Data collection is on', 'Correct label renders when data collection is on'); | ||||
|     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) { | ||||
|     // Simulates the model when something other than enabled changed | ||||
|     const simModel = generateModel({ | ||||
|       changedAttributes: () => ({ retentionMonths: [24, '48'] }), | ||||
|   test('it should not show modal when data collection is not changed', async function (assert) { | ||||
|     assert.expect(1); | ||||
|  | ||||
|     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` | ||||
|       <div id="modal-wormhole"></div> | ||||
|       <Clients::Config @model={{this.model}} @mode="edit" /> | ||||
|     `); | ||||
|  | ||||
|     await click('[data-test-edit-metrics-config-save]'); | ||||
|     assert.dom('.modal.is-active').doesNotExist('No modal appears'); | ||||
|     await fillIn('[data-test-input="retentionMonths"]', 5); | ||||
|     await click('[data-test-clients-config-save]'); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jordan Reimer
					Jordan Reimer