mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-03 20:17:59 +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 {
 | 
					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 [
 | 
				
			||||||
@@ -43,38 +45,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.save.perform();
 | 
					      this.validations = state;
 | 
				
			||||||
      return;
 | 
					    } else if (changed.enabled) {
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
      this.modalOpen = true;
 | 
					      this.modalOpen = true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.save.perform();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ import { get } from '@ember/object';
 | 
				
			|||||||
 * options - an optional object for given validator -- min, max, nullable etc. -- see validators in util
 | 
					 * 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
 | 
					 * 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'
 | 
					 * 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
 | 
					              : 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
 | 
				
			||||||
              if (level === 'warn') {
 | 
					              if (level === 'warn') {
 | 
				
			||||||
                state[key].warnings.push(message);
 | 
					                state[key].warnings.push(validationMessage);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                state[key].errors.push(message);
 | 
					                state[key].errors.push(validationMessage);
 | 
				
			||||||
                if (isValid) {
 | 
					                if (isValid) {
 | 
				
			||||||
                  isValid = false;
 | 
					                  isValid = false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,32 +4,45 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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">
 | 
				
			||||||
              {{attr.options.helpText}}
 | 
					            Enable or disable client tracking. Keep in mind that disabling tracking will delete the data for the current
 | 
				
			||||||
              {{#if attr.options.docLink}}
 | 
					            month.
 | 
				
			||||||
                <DocLink @path={{attr.options.docLink}}>
 | 
					 | 
				
			||||||
                  See our documentation
 | 
					 | 
				
			||||||
                </DocLink>
 | 
					 | 
				
			||||||
                for help.
 | 
					 | 
				
			||||||
              {{/if}}
 | 
					 | 
				
			||||||
          </p>
 | 
					          </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}}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
        {{else}}
 | 
					        {{else}}
 | 
				
			||||||
                Data collection is on
 | 
					          <FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.validations}} />
 | 
				
			||||||
              {{/if}}
 | 
					 | 
				
			||||||
            </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>
 | 
					 | 
				
			||||||
        {{/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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,55 +5,40 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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,
 | 
				
			||||||
 | 
					          minimum_retention_months,
 | 
				
			||||||
 | 
					          retention_months: 24,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    const model = generateModel();
 | 
					      this.model = store.peekRecord('clients/config', 'foo');
 | 
				
			||||||
    this.model = model;
 | 
					    };
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  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 info table rows');
 | 
					    assert.strictEqual(rows.length, 2, 'renders 2 info table rows');
 | 
				
			||||||
    assert.ok(
 | 
					    assert.ok(
 | 
				
			||||||
@@ -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) {
 | 
					  test('it should function in edit mode when reporting is disabled', async function (assert) {
 | 
				
			||||||
 | 
					    assert.expect(13);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.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" />
 | 
				
			||||||
    `);
 | 
					    `);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert.dom('[data-test-pricing-metrics-config-form]').exists('Pricing metrics config form exists');
 | 
					    assert.dom('[data-test-input="enabled"]').isNotChecked('Data collection checkbox is not checked');
 | 
				
			||||||
    const fields = document.querySelectorAll('[data-test-field]');
 | 
					    assert
 | 
				
			||||||
    assert.strictEqual(fields.length, 2, 'renders 2 fields');
 | 
					      .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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('it shows a modal with correct messaging when disabling', async function (assert) {
 | 
					    await click('[data-test-input="enabled"]');
 | 
				
			||||||
    // Simulates the model when enabled value has been changed from On to Off
 | 
					    await fillIn('[data-test-input="retentionMonths"]', -3);
 | 
				
			||||||
    const simModel = generateModel({
 | 
					    await click('[data-test-clients-config-save]');
 | 
				
			||||||
      enabled: 'Off',
 | 
					    assert
 | 
				
			||||||
      changedAttributes: () => ({ enabled: ['On', 'Off'] }),
 | 
					      .dom('[data-test-inline-error-message]')
 | 
				
			||||||
    });
 | 
					      .hasText(
 | 
				
			||||||
    this.set('model', simModel);
 | 
					        'Retention period must be greater than or equal to 0.',
 | 
				
			||||||
    await render(hbs`
 | 
					        'Validation error shows for incorrect retention period'
 | 
				
			||||||
      <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 off?'),
 | 
					 | 
				
			||||||
      'Modal confirming turn tracking off'
 | 
					 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    await click('[data-test-metrics-config-cancel]');
 | 
					 | 
				
			||||||
    assert.dom('.modal.is-active').doesNotExist('Modal goes away');
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('it shows a modal with correct messaging when enabling', async function (assert) {
 | 
					    await fillIn('[data-test-input="retentionMonths"]', 5);
 | 
				
			||||||
    // Simulates the model when enabled value has been changed from On to Off
 | 
					    await click('[data-test-clients-config-save]');
 | 
				
			||||||
    const simModel = generateModel({
 | 
					    assert.dom('.modal.is-active').exists('Modal renders');
 | 
				
			||||||
      changedAttributes: () => ({ enabled: ['Off', 'On'] }),
 | 
					    assert
 | 
				
			||||||
    });
 | 
					      .dom('[data-test-modal-title] span')
 | 
				
			||||||
    this.set('model', simModel);
 | 
					      .hasText('Turn usage tracking on?', 'Correct modal title renders');
 | 
				
			||||||
    await render(hbs`
 | 
					    assert.dom('[data-test-clients-config-modal="on"]').exists('Correct modal description block renders');
 | 
				
			||||||
      <div id="modal-wormhole"></div>
 | 
					 | 
				
			||||||
      <Clients::Config @model={{this.model}} @mode="edit" />
 | 
					 | 
				
			||||||
    `);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await click('[data-test-edit-metrics-config-save]');
 | 
					    await click('[data-test-clients-config-modal="continue"]');
 | 
				
			||||||
    assert.dom('.modal.is-active').exists('Modal appears');
 | 
					 | 
				
			||||||
    assert.ok(
 | 
					    assert.ok(
 | 
				
			||||||
      find('[data-test-modal-title]').textContent.includes('Turn usage tracking on?'),
 | 
					      this.transitionStub.calledWith('vault.cluster.clients.config'),
 | 
				
			||||||
      'Modal confirming turn tracking on'
 | 
					      '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 does not show a modal on save if enable left unchanged', async function (assert) {
 | 
					  test('it should function in edit mode when reporting is enabled', async function (assert) {
 | 
				
			||||||
    // Simulates the model when something other than enabled changed
 | 
					    assert.expect(6);
 | 
				
			||||||
    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: 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').doesNotExist('No modal appears');
 | 
					    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 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.createModel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await render(hbs`
 | 
				
			||||||
 | 
					      <div id="modal-wormhole"></div>
 | 
				
			||||||
 | 
					      <Clients::Config @model={{this.model}} @mode="edit" />
 | 
				
			||||||
 | 
					    `);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await fillIn('[data-test-input="retentionMonths"]', 5);
 | 
				
			||||||
 | 
					    await click('[data-test-clients-config-save]');
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user