mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 11:08:10 +00:00
UI: Ember deprecation - addObject, removeObject (#25952)
* Update add-to-array and remove-from-array helpers * remove search-select-has-many, moved logic directly into mfa-login-enforcement-form (see #16470) * Replace add/remove object in MFA files - All MFA tests pass * Replace in PKI components (pki tests all passing) * Replace in core addon where applicable * glimmerize console service -- console tests pass * more replacements * update string-list, add comment to vertical-bar-chart * Refactor CSP Event service - only used one place (auth-form) so simplified that usage - glimmerize and refactor so that the tests work * small updates * more cleanup * Fix tests * Remove objectAt from console-helpers * Address PR comments * move commandIndex clearing back * Remove extra model set
This commit is contained in:
@@ -144,7 +144,7 @@ export default ApplicationAdapter.extend({
|
|||||||
async _updateAllowedRoles(store, { role, backend, db, type = 'add' }) {
|
async _updateAllowedRoles(store, { role, backend, db, type = 'add' }) {
|
||||||
const connection = await store.queryRecord('database/connection', { backend, id: db });
|
const connection = await store.queryRecord('database/connection', { backend, id: db });
|
||||||
const roles = [...(connection.allowed_roles || [])];
|
const roles = [...(connection.allowed_roles || [])];
|
||||||
const allowedRoles = type === 'add' ? addToArray([roles, role]) : removeFromArray([roles, role]);
|
const allowedRoles = type === 'add' ? addToArray(roles, role) : removeFromArray(roles, role);
|
||||||
connection.allowed_roles = allowedRoles;
|
connection.allowed_roles = allowedRoles;
|
||||||
return connection.save();
|
return connection.save();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import NamedPathAdapter from 'vault/adapters/named-path';
|
|||||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||||
import { service } from '@ember/service';
|
import { service } from '@ember/service';
|
||||||
import AdapterError from '@ember-data/adapter/error';
|
import AdapterError from '@ember-data/adapter/error';
|
||||||
|
import { addManyToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
export default class LdapRoleAdapter extends NamedPathAdapter {
|
export default class LdapRoleAdapter extends NamedPathAdapter {
|
||||||
@service flashMessages;
|
@service flashMessages;
|
||||||
@@ -33,7 +34,7 @@ export default class LdapRoleAdapter extends NamedPathAdapter {
|
|||||||
async query(store, type, query, recordArray, options) {
|
async query(store, type, query, recordArray, options) {
|
||||||
const { showPartialError } = options.adapterOptions || {};
|
const { showPartialError } = options.adapterOptions || {};
|
||||||
const { backend } = query;
|
const { backend } = query;
|
||||||
const roles = [];
|
let roles = [];
|
||||||
const errors = [];
|
const errors = [];
|
||||||
|
|
||||||
for (const roleType of ['static', 'dynamic']) {
|
for (const roleType of ['static', 'dynamic']) {
|
||||||
@@ -42,7 +43,7 @@ export default class LdapRoleAdapter extends NamedPathAdapter {
|
|||||||
const models = await this.ajax(url, 'GET', { data: { list: true } }).then((resp) => {
|
const models = await this.ajax(url, 'GET', { data: { list: true } }).then((resp) => {
|
||||||
return resp.data.keys.map((name) => ({ id: name, name, backend, type: roleType }));
|
return resp.data.keys.map((name) => ({ id: name, name, backend, type: roleType }));
|
||||||
});
|
});
|
||||||
roles.addObjects(models);
|
roles = addManyToArray(roles, models);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.httpStatus !== 404) {
|
if (error.httpStatus !== 404) {
|
||||||
errors.push(error);
|
errors.push(error);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import { next } from '@ember/runloop';
|
import { next } from '@ember/runloop';
|
||||||
import { service } from '@ember/service';
|
import { service } from '@ember/service';
|
||||||
import { match, alias, or } from '@ember/object/computed';
|
import { match, or } from '@ember/object/computed';
|
||||||
import { dasherize } from '@ember/string';
|
import { dasherize } from '@ember/string';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
@@ -166,9 +166,12 @@ export default Component.extend(DEFAULTS, {
|
|||||||
return templateName;
|
return templateName;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
hasCSPError: alias('csp.connectionViolations'),
|
cspError: computed('csp.connectionViolations.length', function () {
|
||||||
|
if (this.csp.connectionViolations.length) {
|
||||||
cspErrorText: `This is a standby Vault node but can't communicate with the active node via request forwarding. Sign in at the active node to use the Vault UI.`,
|
return `This is a standby Vault node but can't communicate with the active node via request forwarding. Sign in at the active node to use the Vault UI.`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}),
|
||||||
|
|
||||||
allSupportedMethods: computed('methodsToShow', 'hasMethodsWithPath', 'authMethods', function () {
|
allSupportedMethods: computed('methodsToShow', 'hasMethodsWithPath', 'authMethods', function () {
|
||||||
const hasMethodsWithPath = this.hasMethodsWithPath;
|
const hasMethodsWithPath = this.hasMethodsWithPath;
|
||||||
|
|||||||
@@ -175,7 +175,9 @@ export default class HorizontalBarChart extends Component {
|
|||||||
this.isLabel = false;
|
this.isLabel = false;
|
||||||
this.tooltipText = []; // clear stats
|
this.tooltipText = []; // clear stats
|
||||||
this.args.chartLegend.forEach(({ key, label }) => {
|
this.args.chartLegend.forEach(({ key, label }) => {
|
||||||
this.tooltipText.pushObject(`${formatNumber([data[key]])} ${label}`);
|
// since we're relying on D3 not ember reactivity,
|
||||||
|
// pushing directly to this.tooltipText updates the DOM
|
||||||
|
this.tooltipText.push(`${formatNumber([data[key]])} ${label}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
select(hoveredElement).style('opacity', 1);
|
select(hoveredElement).style('opacity', 1);
|
||||||
|
|||||||
@@ -155,7 +155,9 @@ export default class VerticalBarChart extends Component {
|
|||||||
this.tooltipStats = []; // clear stats
|
this.tooltipStats = []; // clear stats
|
||||||
this.args.chartLegend.forEach(({ key, label }) => {
|
this.args.chartLegend.forEach(({ key, label }) => {
|
||||||
stackedNumbers.push(data[key]);
|
stackedNumbers.push(data[key]);
|
||||||
this.tooltipStats.pushObject(`${formatNumber([data[key]])} ${label}`);
|
// since we're relying on D3 not ember reactivity,
|
||||||
|
// pushing directly to this.tooltipStats updates the DOM
|
||||||
|
this.tooltipStats.push(`${formatNumber([data[key]])} ${label}`);
|
||||||
});
|
});
|
||||||
this.tooltipTotal = `${formatNumber([calculateSum(stackedNumbers)])} ${
|
this.tooltipTotal = `${formatNumber([calculateSum(stackedNumbers)])} ${
|
||||||
data.new_clients ? 'total' : 'new'
|
data.new_clients ? 'total' : 'new'
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { action } from '@ember/object';
|
|||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import { waitFor } from '@ember/test-waiters';
|
import { waitFor } from '@ember/test-waiters';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module KeymgmtProviderEdit
|
* @module KeymgmtProviderEdit
|
||||||
@@ -94,8 +95,9 @@ export default class KeymgmtProviderEdit extends Component {
|
|||||||
@action
|
@action
|
||||||
async onDeleteKey(model) {
|
async onDeleteKey(model) {
|
||||||
try {
|
try {
|
||||||
|
const providerKeys = removeFromArray(this.args.model.keys, model);
|
||||||
await model.destroyRecord();
|
await model.destroyRecord();
|
||||||
this.args.model.keys.removeObject(model);
|
this.args.model.keys = providerKeys;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.flashMessages.danger(error.errors.join('. '));
|
this.flashMessages.danger(error.errors.join('. '));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { service } from '@ember/service';
|
import { service } from '@ember/service';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import handleHasManySelection from 'core/utils/search-select-has-many';
|
import { addManyToArray, addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module MfaLoginEnforcementForm
|
* @module MfaLoginEnforcementForm
|
||||||
@@ -64,7 +65,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
|||||||
for (const { label, key } of this.targetTypes) {
|
for (const { label, key } of this.targetTypes) {
|
||||||
const targetArray = await this.args.model[key];
|
const targetArray = await this.args.model[key];
|
||||||
const targets = targetArray.map((value) => ({ label, key, value }));
|
const targets = targetArray.map((value) => ({ label, key, value }));
|
||||||
this.targets.addObjects(targets);
|
this.targets = addManyToArray(this.targets, targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async resetTargetState() {
|
async resetTargetState() {
|
||||||
@@ -102,7 +103,6 @@ export default class MfaLoginEnforcementForm extends Component {
|
|||||||
|
|
||||||
updateModelForKey(key) {
|
updateModelForKey(key) {
|
||||||
const newValue = this.targets.filter((t) => t.key === key).map((t) => t.value);
|
const newValue = this.targets.filter((t) => t.key === key).map((t) => t.value);
|
||||||
// Set the model value directly instead of using Array methods (like .addObject)
|
|
||||||
this.args.model[key] = newValue;
|
this.args.model[key] = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,8 +126,18 @@ export default class MfaLoginEnforcementForm extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
async onMethodChange(selectedIds) {
|
async onMethodChange(selectedIds) {
|
||||||
|
// first make sure the async relationship is loaded
|
||||||
const methods = await this.args.model.mfa_methods;
|
const methods = await this.args.model.mfa_methods;
|
||||||
handleHasManySelection(selectedIds, methods, this.store, 'mfa-method');
|
// then remove items that are no longer selected
|
||||||
|
const updatedList = methods.filter((model) => {
|
||||||
|
return selectedIds.includes(model.id);
|
||||||
|
});
|
||||||
|
// then add selected items that don't exist in the list already
|
||||||
|
const modelIds = updatedList.map((model) => model.id);
|
||||||
|
const toAdd = selectedIds
|
||||||
|
.filter((id) => !modelIds.includes(id))
|
||||||
|
.map((id) => this.store.peekRecord('mfa-method', id));
|
||||||
|
this.args.model.mfa_methods = addManyToArray(updatedList, toAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@@ -150,7 +160,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
|||||||
addTarget() {
|
addTarget() {
|
||||||
const { label, key } = this.selectedTarget;
|
const { label, key } = this.selectedTarget;
|
||||||
const value = this.selectedTargetValue;
|
const value = this.selectedTargetValue;
|
||||||
this.targets.addObject({ label, value, key });
|
this.targets = addToArray(this.targets, { label, value, key });
|
||||||
// recalculate value for appropriate model property
|
// recalculate value for appropriate model property
|
||||||
this.updateModelForKey(key);
|
this.updateModelForKey(key);
|
||||||
this.selectedTargetValue = null;
|
this.selectedTargetValue = null;
|
||||||
@@ -158,7 +168,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
|||||||
}
|
}
|
||||||
@action
|
@action
|
||||||
removeTarget(target) {
|
removeTarget(target) {
|
||||||
this.targets.removeObject(target);
|
this.targets = removeFromArray(this.targets, target);
|
||||||
// recalculate value for appropriate model property
|
// recalculate value for appropriate model property
|
||||||
this.updateModelForKey(target.key);
|
this.updateModelForKey(target.key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ export default class SecretCreateOrUpdate extends Component {
|
|||||||
if (isBlank(item.name)) {
|
if (isBlank(item.name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// secretData is a KVObject/ArrayProxy so removeObject is fine here
|
||||||
data.removeObject(item);
|
data.removeObject(item);
|
||||||
this.checkRows();
|
this.checkRows();
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { capitalize } from '@ember/string';
|
import { capitalize } from '@ember/string';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
export default class MfaMethodCreateController extends Controller {
|
export default class MfaMethodCreateController extends Controller {
|
||||||
@service store;
|
@service store;
|
||||||
@@ -95,7 +96,8 @@ export default class MfaMethodCreateController extends Controller {
|
|||||||
// first save method
|
// first save method
|
||||||
yield this.method.save();
|
yield this.method.save();
|
||||||
if (this.enforcement) {
|
if (this.enforcement) {
|
||||||
this.enforcement.mfa_methods.addObject(this.method);
|
// mfa_methods is type PromiseManyArray so slice in necessary to convert it to an Array
|
||||||
|
this.enforcement.mfa_methods = addToArray(this.enforcement.mfa_methods.slice(), this.method);
|
||||||
try {
|
try {
|
||||||
// now save enforcement and catch error separately
|
// now save enforcement and catch error separately
|
||||||
yield this.enforcement.save();
|
yield this.enforcement.save();
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ function dedupe(items) {
|
|||||||
return items.filter((v, i) => items.indexOf(v) === i);
|
return items.filter((v, i) => items.indexOf(v) === i);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addToArray([array, string]) {
|
export function addManyToArray(array, otherArray) {
|
||||||
|
assert(`Both values must be an array`, Array.isArray(array) && Array.isArray(otherArray));
|
||||||
|
const newArray = [...array].concat(otherArray);
|
||||||
|
return dedupe(newArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addToArray(array, string) {
|
||||||
if (!Array.isArray(array)) {
|
if (!Array.isArray(array)) {
|
||||||
assert(`Value provided is not an array`, false);
|
assert(`Value provided is not an array`, false);
|
||||||
}
|
}
|
||||||
@@ -19,4 +25,9 @@ export function addToArray([array, string]) {
|
|||||||
return dedupe(newArray);
|
return dedupe(newArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default buildHelper(addToArray);
|
export default buildHelper(function ([array, string]) {
|
||||||
|
if (Array.isArray(string)) {
|
||||||
|
return addManyToArray(array, string);
|
||||||
|
}
|
||||||
|
return addToArray(array, string);
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,10 +10,14 @@ function dedupe(items) {
|
|||||||
return items.filter((v, i) => items.indexOf(v) === i);
|
return items.filter((v, i) => items.indexOf(v) === i);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeFromArray([array, string]) {
|
export function removeManyFromArray(array, toRemove) {
|
||||||
if (!Array.isArray(array)) {
|
assert(`Both values must be an array`, Array.isArray(array) && Array.isArray(toRemove));
|
||||||
assert(`Value provided is not an array`, false);
|
const a = [...(array || [])];
|
||||||
}
|
return a.filter((v) => !toRemove.includes(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeFromArray(array, string) {
|
||||||
|
assert(`Value provided is not an array`, Array.isArray(array));
|
||||||
const newArray = [...array];
|
const newArray = [...array];
|
||||||
const idx = newArray.indexOf(string);
|
const idx = newArray.indexOf(string);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
@@ -22,4 +26,9 @@ export function removeFromArray([array, string]) {
|
|||||||
return dedupe(newArray);
|
return dedupe(newArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default buildHelper(removeFromArray);
|
export default buildHelper(function ([array, string]) {
|
||||||
|
if (Array.isArray(string)) {
|
||||||
|
return removeManyFromArray(array, string);
|
||||||
|
}
|
||||||
|
return removeFromArray(array, string);
|
||||||
|
});
|
||||||
|
|||||||
@@ -241,7 +241,8 @@ export function shiftCommandIndex(keyCode: number, history: CommandLog[], index:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newInputValue !== '') {
|
if (newInputValue !== '') {
|
||||||
newInputValue = history.objectAt(index)?.content;
|
const objAt = history[index];
|
||||||
|
newInputValue = objAt?.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [index, newInputValue];
|
return [index, newInputValue];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { computed } from '@ember/object';
|
|||||||
import fieldToAttrs, { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
import fieldToAttrs, { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||||||
import apiPath from 'vault/utils/api-path';
|
import apiPath from 'vault/utils/api-path';
|
||||||
import lazyCapabilities from 'vault/macros/lazy-capabilities';
|
import lazyCapabilities from 'vault/macros/lazy-capabilities';
|
||||||
|
import { removeManyFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
export const COMPUTEDS = {
|
export const COMPUTEDS = {
|
||||||
operationFields: computed('newFields', function () {
|
operationFields: computed('newFields', function () {
|
||||||
@@ -15,7 +16,7 @@ export const COMPUTEDS = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
operationFieldsWithoutSpecial: computed('operationFields', function () {
|
operationFieldsWithoutSpecial: computed('operationFields', function () {
|
||||||
return this.operationFields.slice().removeObjects(['operationAll', 'operationNone']);
|
return removeManyFromArray(this.operationFields, ['operationAll', 'operationNone']);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
tlsFields: computed(function () {
|
tlsFields: computed(function () {
|
||||||
@@ -25,12 +26,12 @@ export const COMPUTEDS = {
|
|||||||
// For rendering on the create/edit pages
|
// For rendering on the create/edit pages
|
||||||
defaultFields: computed('newFields', 'operationFields', 'tlsFields', function () {
|
defaultFields: computed('newFields', 'operationFields', 'tlsFields', function () {
|
||||||
const excludeFields = ['role'].concat(this.operationFields, this.tlsFields);
|
const excludeFields = ['role'].concat(this.operationFields, this.tlsFields);
|
||||||
return this.newFields.slice().removeObjects(excludeFields);
|
return removeManyFromArray(this.newFields, excludeFields);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// For adapter/serializer
|
// For adapter/serializer
|
||||||
nonOperationFields: computed('newFields', 'operationFields', function () {
|
nonOperationFields: computed('newFields', 'operationFields', function () {
|
||||||
return this.newFields.slice().removeObjects(this.operationFields);
|
return removeManyFromArray(this.newFields, this.operationFields);
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,9 +65,11 @@ export default Model.extend(COMPUTEDS, {
|
|||||||
|
|
||||||
const attributes = ['operationAddAttribute', 'operationGetAttributes'];
|
const attributes = ['operationAddAttribute', 'operationGetAttributes'];
|
||||||
const server = ['operationDiscoverVersions'];
|
const server = ['operationDiscoverVersions'];
|
||||||
const others = this.operationFieldsWithoutSpecial
|
const others = removeManyFromArray(this.operationFieldsWithoutSpecial, [
|
||||||
.slice()
|
...objects,
|
||||||
.removeObjects(objects.concat(attributes, server));
|
...attributes,
|
||||||
|
...server,
|
||||||
|
]);
|
||||||
const groups = [
|
const groups = [
|
||||||
{ 'Managed Cryptographic Objects': objects },
|
{ 'Managed Cryptographic Objects': objects },
|
||||||
{ 'Object Attributes': attributes },
|
{ 'Object Attributes': attributes },
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { methods } from 'vault/helpers/mountable-auth-methods';
|
|||||||
import { withModelValidations } from 'vault/decorators/model-validations';
|
import { withModelValidations } from 'vault/decorators/model-validations';
|
||||||
import { isPresent } from '@ember/utils';
|
import { isPresent } from '@ember/utils';
|
||||||
import { service } from '@ember/service';
|
import { service } from '@ember/service';
|
||||||
|
import { addManyToArray, addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
const validations = {
|
const validations = {
|
||||||
name: [{ type: 'presence', message: 'Name is required' }],
|
name: [{ type: 'presence', message: 'Name is required' }],
|
||||||
@@ -52,7 +53,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
|||||||
|
|
||||||
async prepareTargets() {
|
async prepareTargets() {
|
||||||
let authMethods;
|
let authMethods;
|
||||||
const targets = [];
|
let targets = [];
|
||||||
|
|
||||||
if (this.auth_method_accessors.length || this.auth_method_types.length) {
|
if (this.auth_method_accessors.length || this.auth_method_types.length) {
|
||||||
// fetch all auth methods and lookup by accessor to get mount path and type
|
// fetch all auth methods and lookup by accessor to get mount path and type
|
||||||
@@ -68,7 +69,8 @@ export default class MfaLoginEnforcementModel extends Model {
|
|||||||
const selectedAuthMethods = authMethods.filter((model) => {
|
const selectedAuthMethods = authMethods.filter((model) => {
|
||||||
return this.auth_method_accessors.includes(model.accessor);
|
return this.auth_method_accessors.includes(model.accessor);
|
||||||
});
|
});
|
||||||
targets.addObjects(
|
targets = addManyToArray(
|
||||||
|
targets,
|
||||||
selectedAuthMethods.map((method) => ({
|
selectedAuthMethods.map((method) => ({
|
||||||
icon: this.iconForMount(method.type),
|
icon: this.iconForMount(method.type),
|
||||||
link: 'vault.cluster.access.method',
|
link: 'vault.cluster.access.method',
|
||||||
@@ -82,7 +84,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
|||||||
this.auth_method_types.forEach((type) => {
|
this.auth_method_types.forEach((type) => {
|
||||||
const icon = this.iconForMount(type);
|
const icon = this.iconForMount(type);
|
||||||
const mountCount = authMethods.filterBy('type', type).length;
|
const mountCount = authMethods.filterBy('type', type).length;
|
||||||
targets.addObject({
|
targets = addToArray(targets, {
|
||||||
key: 'auth_method_types',
|
key: 'auth_method_types',
|
||||||
icon,
|
icon,
|
||||||
title: type,
|
title: type,
|
||||||
@@ -92,7 +94,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
|||||||
|
|
||||||
for (const key of ['identity_entities', 'identity_groups']) {
|
for (const key of ['identity_entities', 'identity_groups']) {
|
||||||
(await this[key]).forEach((model) => {
|
(await this[key]).forEach((model) => {
|
||||||
targets.addObject({
|
targets = addToArray(targets, {
|
||||||
key,
|
key,
|
||||||
icon: 'user',
|
icon: 'user',
|
||||||
link: 'vault.cluster.access.identity.show',
|
link: 'vault.cluster.access.identity.show',
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default class SyncDestinationSerializer extends ApplicationSerializer {
|
|||||||
const type = key.replace(/\/$/, '');
|
const type = key.replace(/\/$/, '');
|
||||||
const id = `${type}/${name}`;
|
const id = `${type}/${name}`;
|
||||||
// create object with destination's id and attributes, add to payload
|
// create object with destination's id and attributes, add to payload
|
||||||
transformedPayload.pushObject({ id, name, type });
|
transformedPayload.push({ id, name, type });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return transformedPayload;
|
return transformedPayload;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { resolve, reject } from 'rsvp';
|
|||||||
import getStorage from 'vault/lib/token-storage';
|
import getStorage from 'vault/lib/token-storage';
|
||||||
import ENV from 'vault/config/environment';
|
import ENV from 'vault/config/environment';
|
||||||
import { allSupportedAuthBackends } from 'vault/helpers/supported-auth-backends';
|
import { allSupportedAuthBackends } from 'vault/helpers/supported-auth-backends';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
const TOKEN_SEPARATOR = '☃';
|
const TOKEN_SEPARATOR = '☃';
|
||||||
const TOKEN_PREFIX = 'vault-';
|
const TOKEN_PREFIX = 'vault-';
|
||||||
@@ -250,7 +251,6 @@ export default Service.extend({
|
|||||||
|
|
||||||
persistAuthData() {
|
persistAuthData() {
|
||||||
const [firstArg, resp] = arguments;
|
const [firstArg, resp] = arguments;
|
||||||
const tokens = this.tokens;
|
|
||||||
const currentNamespace = this.namespaceService.path || '';
|
const currentNamespace = this.namespaceService.path || '';
|
||||||
// dropdown vs tab format
|
// dropdown vs tab format
|
||||||
const mountPath = firstArg?.data?.path || firstArg?.selectedAuth;
|
const mountPath = firstArg?.data?.path || firstArg?.selectedAuth;
|
||||||
@@ -303,8 +303,7 @@ export default Service.extend({
|
|||||||
if (!data.displayName) {
|
if (!data.displayName) {
|
||||||
data.displayName = (this.getTokenData(tokenName) || {}).displayName;
|
data.displayName = (this.getTokenData(tokenName) || {}).displayName;
|
||||||
}
|
}
|
||||||
tokens.addObject(tokenName);
|
this.set('tokens', addToArray(this.tokens, tokenName));
|
||||||
this.set('tokens', tokens);
|
|
||||||
this.set('allowExpiration', false);
|
this.set('allowExpiration', false);
|
||||||
this.setTokenData(tokenName, data);
|
this.setTokenData(tokenName, data);
|
||||||
return resolve({
|
return resolve({
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
// Low level service that allows users to input paths to make requests to vault
|
// Low level service that allows users to input paths to make requests to vault
|
||||||
// this service provides the UI synecdote to the cli commands read, write, delete, and list
|
// this service provides the UI synecdote to the cli commands read, write, delete, and list
|
||||||
import Service from '@ember/service';
|
import Service from '@ember/service';
|
||||||
|
|
||||||
import { getOwner } from '@ember/application';
|
import { getOwner } from '@ember/application';
|
||||||
import { computed } from '@ember/object';
|
|
||||||
import { shiftCommandIndex } from 'vault/lib/console-helpers';
|
import { shiftCommandIndex } from 'vault/lib/console-helpers';
|
||||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||||
import { sanitizePath, ensureTrailingSlash } from 'core/utils/sanitize-path';
|
import { sanitizePath, ensureTrailingSlash } from 'core/utils/sanitize-path';
|
||||||
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
import { addManyToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
const VERBS = {
|
const VERBS = {
|
||||||
read: 'GET',
|
read: 'GET',
|
||||||
@@ -20,51 +20,51 @@ const VERBS = {
|
|||||||
delete: 'DELETE',
|
delete: 'DELETE',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Service.extend({
|
export default class ConsoleService extends Service {
|
||||||
isOpen: false,
|
@tracked isOpen = false;
|
||||||
|
@tracked commandIndex = null;
|
||||||
|
@tracked log = [];
|
||||||
|
|
||||||
adapter() {
|
|
||||||
return getOwner(this).lookup('adapter:console');
|
|
||||||
},
|
|
||||||
get commandHistory() {
|
get commandHistory() {
|
||||||
return this.log.filter((log) => log.type === 'command');
|
return this.log.filter((log) => log.type === 'command');
|
||||||
},
|
}
|
||||||
log: computed(function () {
|
|
||||||
return [];
|
// Not a getter so it can be stubbed in tests
|
||||||
}),
|
adapter() {
|
||||||
commandIndex: null,
|
return getOwner(this).lookup('adapter:console');
|
||||||
|
}
|
||||||
|
|
||||||
shiftCommandIndex(keyCode, setCommandFn = () => {}) {
|
shiftCommandIndex(keyCode, setCommandFn = () => {}) {
|
||||||
const [newIndex, newCommand] = shiftCommandIndex(keyCode, this.commandHistory, this.commandIndex);
|
const [newIndex, newCommand] = shiftCommandIndex(keyCode, this.commandHistory, this.commandIndex);
|
||||||
if (newCommand !== undefined && newIndex !== undefined) {
|
if (newCommand !== undefined && newIndex !== undefined) {
|
||||||
this.set('commandIndex', newIndex);
|
this.commandIndex = newIndex;
|
||||||
setCommandFn(newCommand);
|
setCommandFn(newCommand);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
clearLog(clearAll = false) {
|
clearLog(clearAll = false) {
|
||||||
const log = this.log;
|
|
||||||
let history;
|
let history;
|
||||||
if (!clearAll) {
|
if (!clearAll) {
|
||||||
history = this.commandHistory.slice();
|
history = this.commandHistory.slice();
|
||||||
history.setEach('hidden', true);
|
history.setEach('hidden', true);
|
||||||
}
|
}
|
||||||
log.clear();
|
this.log = [];
|
||||||
if (history) {
|
if (history) {
|
||||||
log.addObjects(history);
|
this.log = addManyToArray(this.log, history);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
logAndOutput(command, logContent) {
|
logAndOutput(command, logContent) {
|
||||||
const log = this.log;
|
const log = this.log.slice();
|
||||||
if (command) {
|
if (command) {
|
||||||
log.pushObject({ type: 'command', content: command });
|
log.push({ type: 'command', content: command });
|
||||||
this.set('commandIndex', null);
|
this.commandIndex = null;
|
||||||
}
|
}
|
||||||
if (logContent) {
|
if (logContent) {
|
||||||
log.pushObject(logContent);
|
log.push(logContent);
|
||||||
}
|
}
|
||||||
},
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
ajax(operation, path, options = {}) {
|
ajax(operation, path, options = {}) {
|
||||||
const verb = VERBS[operation];
|
const verb = VERBS[operation];
|
||||||
@@ -75,7 +75,7 @@ export default Service.extend({
|
|||||||
data,
|
data,
|
||||||
wrapTTL,
|
wrapTTL,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
kvGet(path, data, flags = {}) {
|
kvGet(path, data, flags = {}) {
|
||||||
const { wrapTTL, metadata } = flags;
|
const { wrapTTL, metadata } = flags;
|
||||||
@@ -84,21 +84,21 @@ export default Service.extend({
|
|||||||
const [backend, secretPath] = path.split(/\/(.+)?/);
|
const [backend, secretPath] = path.split(/\/(.+)?/);
|
||||||
const kvPath = `${backend}/${pathSegment}/${secretPath}`;
|
const kvPath = `${backend}/${pathSegment}/${secretPath}`;
|
||||||
return this.ajax('read', sanitizePath(kvPath), { wrapTTL });
|
return this.ajax('read', sanitizePath(kvPath), { wrapTTL });
|
||||||
},
|
}
|
||||||
|
|
||||||
read(path, data, flags) {
|
read(path, data, flags) {
|
||||||
const wrapTTL = flags?.wrapTTL;
|
const wrapTTL = flags?.wrapTTL;
|
||||||
return this.ajax('read', sanitizePath(path), { wrapTTL });
|
return this.ajax('read', sanitizePath(path), { wrapTTL });
|
||||||
},
|
}
|
||||||
|
|
||||||
write(path, data, flags) {
|
write(path, data, flags) {
|
||||||
const wrapTTL = flags?.wrapTTL;
|
const wrapTTL = flags?.wrapTTL;
|
||||||
return this.ajax('write', sanitizePath(path), { data, wrapTTL });
|
return this.ajax('write', sanitizePath(path), { data, wrapTTL });
|
||||||
},
|
}
|
||||||
|
|
||||||
delete(path) {
|
delete(path) {
|
||||||
return this.ajax('delete', sanitizePath(path));
|
return this.ajax('delete', sanitizePath(path));
|
||||||
},
|
}
|
||||||
|
|
||||||
list(path, data, flags) {
|
list(path, data, flags) {
|
||||||
const wrapTTL = flags?.wrapTTL;
|
const wrapTTL = flags?.wrapTTL;
|
||||||
@@ -109,5 +109,5 @@ export default Service.extend({
|
|||||||
},
|
},
|
||||||
wrapTTL,
|
wrapTTL,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -3,34 +3,35 @@
|
|||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*eslint-disable no-constant-condition*/
|
|
||||||
import { computed } from '@ember/object';
|
|
||||||
|
|
||||||
import Service from '@ember/service';
|
import Service from '@ember/service';
|
||||||
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { task, waitForEvent } from 'ember-concurrency';
|
import { task, waitForEvent } from 'ember-concurrency';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
export default Service.extend({
|
export default class CspEventService extends Service {
|
||||||
events: computed(function () {
|
@tracked connectionViolations = [];
|
||||||
return [];
|
|
||||||
}),
|
|
||||||
connectionViolations: computed('events.@each.violatedDirective', function () {
|
|
||||||
return this.events.some((e) => e.violatedDirective.startsWith('connect-src'));
|
|
||||||
}),
|
|
||||||
|
|
||||||
attach() {
|
attach() {
|
||||||
this.monitor.perform();
|
this.monitor.perform();
|
||||||
},
|
}
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
this.monitor.cancelAll();
|
this.monitor.cancelAll();
|
||||||
},
|
}
|
||||||
|
|
||||||
monitor: task(function* () {
|
handleEvent(event) {
|
||||||
this.events.clear();
|
if (event.violatedDirective.startsWith('connect-src')) {
|
||||||
|
this.connectionViolations = addToArray(this.connectionViolations, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@task
|
||||||
|
*monitor() {
|
||||||
|
this.connectionViolations = [];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const event = yield waitForEvent(window.document, 'securitypolicyviolation');
|
const event = yield waitForEvent(window.document, 'securitypolicyviolation');
|
||||||
this.events.addObject(event);
|
this.handleEvent(event);
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { capitalize } from '@ember/string';
|
|||||||
|
|
||||||
import getStorage from 'vault/lib/token-storage';
|
import getStorage from 'vault/lib/token-storage';
|
||||||
import { STORAGE_KEYS, DEFAULTS, MACHINES } from 'vault/helpers/wizard-constants';
|
import { STORAGE_KEYS, DEFAULTS, MACHINES } from 'vault/helpers/wizard-constants';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
const {
|
const {
|
||||||
TUTORIAL_STATE,
|
TUTORIAL_STATE,
|
||||||
COMPONENT_STATE,
|
COMPONENT_STATE,
|
||||||
@@ -101,7 +102,7 @@ export default Service.extend(DEFAULTS, {
|
|||||||
} else {
|
} else {
|
||||||
if (this.featureMachineHistory) {
|
if (this.featureMachineHistory) {
|
||||||
if (!this.featureMachineHistory.includes(state)) {
|
if (!this.featureMachineHistory.includes(state)) {
|
||||||
const newHistory = this.featureMachineHistory.addObject(state);
|
const newHistory = addToArray(this.featureMachineHistory, state);
|
||||||
this.set('featureMachineHistory', newHistory);
|
this.set('featureMachineHistory', newHistory);
|
||||||
} else {
|
} else {
|
||||||
//we're repeating steps
|
//we're repeating steps
|
||||||
@@ -293,7 +294,7 @@ export default Service.extend(DEFAULTS, {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.startFeature();
|
this.startFeature();
|
||||||
const nextFeature = this.featureList.length > 1 ? capitalize(this.featureList.objectAt(1)) : 'Finish';
|
const nextFeature = this.featureList.length > 1 ? capitalize(this.featureList[1]) : 'Finish';
|
||||||
this.set('nextFeature', nextFeature);
|
this.set('nextFeature', nextFeature);
|
||||||
let next;
|
let next;
|
||||||
if (this.currentMachine === 'secrets' && this.featureState === 'display') {
|
if (this.currentMachine === 'secrets' && this.featureState === 'display') {
|
||||||
@@ -311,9 +312,9 @@ export default Service.extend(DEFAULTS, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
startFeature() {
|
startFeature() {
|
||||||
const FeatureMachineConfig = MACHINES[this.featureList.objectAt(0)];
|
const FeatureMachineConfig = MACHINES[this.featureList[0]];
|
||||||
FeatureMachine = Machine(FeatureMachineConfig);
|
FeatureMachine = Machine(FeatureMachineConfig);
|
||||||
this.set('currentMachine', this.featureList.objectAt(0));
|
this.set('currentMachine', this.featureList[0]);
|
||||||
if (this.storageHasKey(FEATURE_STATE)) {
|
if (this.storageHasKey(FEATURE_STATE)) {
|
||||||
this.saveState('featureState', this.getExtState(FEATURE_STATE));
|
this.saveState('featureState', this.getExtState(FEATURE_STATE));
|
||||||
} else {
|
} else {
|
||||||
@@ -337,7 +338,7 @@ export default Service.extend(DEFAULTS, {
|
|||||||
completed.push(done);
|
completed.push(done);
|
||||||
this.saveExtState(COMPLETED_FEATURES, completed);
|
this.saveExtState(COMPLETED_FEATURES, completed);
|
||||||
} else {
|
} else {
|
||||||
this.saveExtState(COMPLETED_FEATURES, this.getExtState(COMPLETED_FEATURES).addObject(done));
|
this.saveExtState(COMPLETED_FEATURES, addToArray(this.getExtState(COMPLETED_FEATURES), done));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.saveExtState(FEATURE_LIST, features.length ? features : null);
|
this.saveExtState(FEATURE_LIST, features.length ? features : null);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="box is-marginless is-shadowless">
|
<div class="box is-marginless is-shadowless">
|
||||||
<MessageError @errorMessage={{if (and this.cluster.standby this.hasCSPError) this.cspErrorText this.error}} />
|
<MessageError @errorMessage={{if (and this.cluster.standby this.cspError) this.cspError this.error}} />
|
||||||
{{#if this.selectedAuthBackend.path}}
|
{{#if this.selectedAuthBackend.path}}
|
||||||
<div class="has-bottom-margin-s">
|
<div class="has-bottom-margin-s">
|
||||||
<p class="is-label">{{this.selectedAuthBackend.path}}</p>
|
<p class="is-label">{{this.selectedAuthBackend.path}}</p>
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { capitalize } from 'vault/helpers/capitalize';
|
|||||||
import { humanize } from 'vault/helpers/humanize';
|
import { humanize } from 'vault/helpers/humanize';
|
||||||
import { dasherize } from 'vault/helpers/dasherize';
|
import { dasherize } from 'vault/helpers/dasherize';
|
||||||
import { assert } from '@ember/debug';
|
import { assert } from '@ember/debug';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module FormField
|
* @module FormField
|
||||||
@@ -193,9 +195,12 @@ export default class FormFieldComponent extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
handleChecklist(event) {
|
handleChecklist(event) {
|
||||||
const valueArray = this.args.model[this.valuePath];
|
let updatedValue = this.args.model[this.valuePath];
|
||||||
const method = event.target.checked ? 'addObject' : 'removeObject';
|
if (event.target.checked) {
|
||||||
valueArray[method](event.target.value);
|
updatedValue = addToArray(updatedValue, event.target.value);
|
||||||
this.setAndBroadcast(valueArray);
|
} else {
|
||||||
|
updatedValue = removeFromArray(updatedValue, event.target.value);
|
||||||
|
}
|
||||||
|
this.setAndBroadcast(updatedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import KVObject from 'vault/lib/kv-object';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default class KvObjectEditor extends Component {
|
export default class KvObjectEditor extends Component {
|
||||||
|
// kvData is type ArrayProxy, so addObject etc are fine here
|
||||||
@tracked kvData;
|
@tracked kvData;
|
||||||
|
|
||||||
get placeholders() {
|
get placeholders() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Component from '@glimmer/component';
|
|||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { assert } from '@ember/debug';
|
import { assert } from '@ember/debug';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module ObjectListInput
|
* @module ObjectListInput
|
||||||
@@ -65,7 +66,7 @@ export default class ObjectListInput extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
handleInput(idx, { target }) {
|
handleInput(idx, { target }) {
|
||||||
const inputObj = this.inputList.objectAt(idx);
|
const inputObj = this.inputList[idx];
|
||||||
inputObj[target.name] = target.value;
|
inputObj[target.name] = target.value;
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
@@ -79,8 +80,8 @@ export default class ObjectListInput extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
removeRow(idx) {
|
removeRow(idx) {
|
||||||
const row = this.inputList.objectAt(idx);
|
const row = this.inputList[idx];
|
||||||
this.inputList.removeObject(row);
|
this.inputList = removeFromArray(this.inputList, row);
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { action } from '@ember/object';
|
|||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils';
|
import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module SearchSelectWithModal
|
* @module SearchSelectWithModal
|
||||||
@@ -31,7 +33,7 @@ import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-ut
|
|||||||
* />
|
* />
|
||||||
*
|
*
|
||||||
// * component functionality
|
// * component functionality
|
||||||
* @param {function} onChange - The onchange action for this form field. ** SEE UTIL ** search-select-has-many.js if selecting models from a hasMany relationship
|
* @param {function} onChange - The onchange action for this form field. ** SEE EXAMPLE ** mfa-login-enforcement-form.js (onMethodChange) for example when selecting models from a hasMany relationship
|
||||||
* @param {array} [inputValue] - Array of strings corresponding to the input's initial value, e.g. an array of model ids that on edit will appear as selected items below the input
|
* @param {array} [inputValue] - Array of strings corresponding to the input's initial value, e.g. an array of model ids that on edit will appear as selected items below the input
|
||||||
* @param {boolean} [shouldRenderName=false] - By default an item's id renders in the dropdown, `true` displays the name with its id in smaller text beside it *NOTE: the boolean flips automatically with 'identity' models
|
* @param {boolean} [shouldRenderName=false] - By default an item's id renders in the dropdown, `true` displays the name with its id in smaller text beside it *NOTE: the boolean flips automatically with 'identity' models
|
||||||
* @param {array} [excludeOptions] - array of strings containing model ids to filter from the dropdown (ex: ['allow_all'])
|
* @param {array} [excludeOptions] - array of strings containing model ids to filter from the dropdown (ex: ['allow_all'])
|
||||||
@@ -81,7 +83,7 @@ export default class SearchSelectWithModal extends Component {
|
|||||||
return inputValues.map((option) => {
|
return inputValues.map((option) => {
|
||||||
const matchingOption = this.dropdownOptions.find((opt) => opt.id === option);
|
const matchingOption = this.dropdownOptions.find((opt) => opt.id === option);
|
||||||
// remove any matches from dropdown list
|
// remove any matches from dropdown list
|
||||||
this.dropdownOptions.removeObject(matchingOption);
|
this.dropdownOptions = removeFromArray(this.dropdownOptions, matchingOption);
|
||||||
return {
|
return {
|
||||||
id: option,
|
id: option,
|
||||||
name: matchingOption ? matchingOption.name : option,
|
name: matchingOption ? matchingOption.name : option,
|
||||||
@@ -168,8 +170,8 @@ export default class SearchSelectWithModal extends Component {
|
|||||||
// -----
|
// -----
|
||||||
@action
|
@action
|
||||||
discardSelection(selected) {
|
discardSelection(selected) {
|
||||||
this.selectedOptions.removeObject(selected);
|
this.selectedOptions = removeFromArray(this.selectedOptions, selected);
|
||||||
this.dropdownOptions.pushObject(selected);
|
this.dropdownOptions = addToArray(this.dropdownOptions, selected);
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +198,8 @@ export default class SearchSelectWithModal extends Component {
|
|||||||
this.showModal = true;
|
this.showModal = true;
|
||||||
} else {
|
} else {
|
||||||
// user has selected an existing item, handleChange immediately
|
// user has selected an existing item, handleChange immediately
|
||||||
this.selectedOptions.pushObject(selection);
|
this.selectedOptions = addToArray(this.selectedOptions, selection);
|
||||||
this.dropdownOptions.removeObject(selection);
|
this.dropdownOptions = removeFromArray(this.dropdownOptions, selection);
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +211,7 @@ export default class SearchSelectWithModal extends Component {
|
|||||||
this.showModal = false;
|
this.showModal = false;
|
||||||
if (model && model.currentState.isSaved) {
|
if (model && model.currentState.isSaved) {
|
||||||
const { name } = model;
|
const { name } = model;
|
||||||
this.selectedOptions.pushObject({ name, id: name });
|
this.selectedOptions = addToArray(this.selectedOptions, { name, id: name });
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
this.nameInput = null;
|
this.nameInput = null;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { action } from '@ember/object';
|
|||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import { resolve } from 'rsvp';
|
import { resolve } from 'rsvp';
|
||||||
import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils';
|
import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
/**
|
/**
|
||||||
* @module SearchSelect
|
* @module SearchSelect
|
||||||
* The `SearchSelect` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
|
* The `SearchSelect` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
|
||||||
@@ -28,7 +30,7 @@ import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-ut
|
|||||||
* />
|
* />
|
||||||
*
|
*
|
||||||
// * component functionality
|
// * component functionality
|
||||||
* @param {function} onChange - The onchange action for this form field. ** SEE UTIL ** search-select-has-many.js if selecting models from a hasMany relationship
|
* @param {function} onChange - The onchange action for this form field. ** SEE EXAMPLE ** mfa-login-enforcement-form.js (onMethodChange) for example when selecting models from a hasMany relationship
|
||||||
* @param {array} [inputValue] - Array of strings corresponding to the input's initial value, e.g. an array of model ids that on edit will appear as selected items below the input
|
* @param {array} [inputValue] - Array of strings corresponding to the input's initial value, e.g. an array of model ids that on edit will appear as selected items below the input
|
||||||
* @param {boolean} [disallowNewItems=false] - Controls whether or not the user can add a new item if none found
|
* @param {boolean} [disallowNewItems=false] - Controls whether or not the user can add a new item if none found
|
||||||
* @param {boolean} [shouldRenderName=false] - By default an item's id renders in the dropdown, `true` displays the name with its id in smaller text beside it *NOTE: the boolean flips automatically with 'identity' models or if this.idKey !== 'id'
|
* @param {boolean} [shouldRenderName=false] - By default an item's id renders in the dropdown, `true` displays the name with its id in smaller text beside it *NOTE: the boolean flips automatically with 'identity' models or if this.idKey !== 'id'
|
||||||
@@ -118,7 +120,7 @@ export default class SearchSelect extends Component {
|
|||||||
: false;
|
: false;
|
||||||
|
|
||||||
// remove any matches from dropdown list
|
// remove any matches from dropdown list
|
||||||
this.dropdownOptions.removeObject(matchingOption);
|
this.dropdownOptions = removeFromArray(this.dropdownOptions, matchingOption);
|
||||||
return {
|
return {
|
||||||
id: option,
|
id: option,
|
||||||
name: matchingOption ? matchingOption[this.nameKey] : option,
|
name: matchingOption ? matchingOption[this.nameKey] : option,
|
||||||
@@ -263,9 +265,9 @@ export default class SearchSelect extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
discardSelection(selected) {
|
discardSelection(selected) {
|
||||||
this.selectedOptions.removeObject(selected);
|
this.selectedOptions = removeFromArray(this.selectedOptions, selected);
|
||||||
if (!selected.new) {
|
if (!selected.new) {
|
||||||
this.dropdownOptions.pushObject(selected);
|
this.dropdownOptions = addToArray(this.dropdownOptions, selected);
|
||||||
}
|
}
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
@@ -291,10 +293,10 @@ export default class SearchSelect extends Component {
|
|||||||
selectOrCreate(selection) {
|
selectOrCreate(selection) {
|
||||||
if (selection && selection.__isSuggestion__) {
|
if (selection && selection.__isSuggestion__) {
|
||||||
const name = selection.__value__;
|
const name = selection.__value__;
|
||||||
this.selectedOptions.pushObject({ name, id: name, new: true });
|
this.selectedOptions = addToArray(this.selectedOptions, { name, id: name, new: true });
|
||||||
} else {
|
} else {
|
||||||
this.selectedOptions.pushObject(selection);
|
this.selectedOptions = addToArray(this.selectedOptions, selection);
|
||||||
this.dropdownOptions.removeObject(selection);
|
this.dropdownOptions = removeFromArray(this.dropdownOptions, selection);
|
||||||
}
|
}
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { action } from '@ember/object';
|
|||||||
import { set } from '@ember/object';
|
import { set } from '@ember/object';
|
||||||
import { next } from '@ember/runloop';
|
import { next } from '@ember/runloop';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module StringList
|
* @module StringList
|
||||||
@@ -33,6 +35,7 @@ export default class StringList extends Component {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
|
||||||
|
// inputList is type ArrayProxy, so addObject etc are fine here
|
||||||
this.inputList = ArrayProxy.create({
|
this.inputList = ArrayProxy.create({
|
||||||
// trim the `value` when accessing objects
|
// trim the `value` when accessing objects
|
||||||
content: [],
|
content: [],
|
||||||
@@ -90,9 +93,11 @@ export default class StringList extends Component {
|
|||||||
@action
|
@action
|
||||||
inputChanged(idx, event) {
|
inputChanged(idx, event) {
|
||||||
if (event.target.value.includes(',') && !this.indicesWithComma.includes(idx)) {
|
if (event.target.value.includes(',') && !this.indicesWithComma.includes(idx)) {
|
||||||
this.indicesWithComma.pushObject(idx);
|
this.indicesWithComma = addToArray(this.indicesWithComma, idx);
|
||||||
|
}
|
||||||
|
if (!event.target.value.includes(',')) {
|
||||||
|
this.indicesWithComma = removeFromArray(this.indicesWithComma, idx);
|
||||||
}
|
}
|
||||||
if (!event.target.value.includes(',')) this.indicesWithComma.removeObject(idx);
|
|
||||||
|
|
||||||
const inputObj = this.inputList.objectAt(idx);
|
const inputObj = this.inputList.objectAt(idx);
|
||||||
set(inputObj, 'value', event.target.value);
|
set(inputObj, 'value', event.target.value);
|
||||||
@@ -109,8 +114,8 @@ export default class StringList extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
removeInput(idx) {
|
removeInput(idx) {
|
||||||
const inputs = this.inputList;
|
const itemToRemove = this.inputList.objectAt(idx);
|
||||||
inputs.removeObject(inputs.objectAt(idx));
|
this.inputList.removeObject(itemToRemove);
|
||||||
this.args.onChange(this.toVal());
|
this.args.onChange(this.toVal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Util to add/remove models in a hasMany relationship via the search-select component
|
|
||||||
*
|
|
||||||
* @example of using the util within an action in a component
|
|
||||||
*```js
|
|
||||||
* @action
|
|
||||||
* async onSearchSelectChange(selectedIds) {
|
|
||||||
* const methods = await this.args.model.mfa_methods;
|
|
||||||
* handleHasManySelection(selectedIds, methods, this.store, 'mfa-method');
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @param selectedIds array of selected options from search-select component
|
|
||||||
* @param modelCollection array-like, list of models from the hasMany relationship
|
|
||||||
* @param store the store so we can call peekRecord()
|
|
||||||
* @param modelRecord string passed to peekRecord
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default function handleHasManySelection(selectedIds, modelCollection, store, modelRecord) {
|
|
||||||
// first check for existing models that have been removed from selection
|
|
||||||
modelCollection.forEach((model) => {
|
|
||||||
if (!selectedIds.includes(model.id)) {
|
|
||||||
modelCollection.removeObject(model);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// now check for selected items that don't exist and add them to the model
|
|
||||||
const modelIds = modelCollection.map((model) => model.id);
|
|
||||||
selectedIds.forEach((id) => {
|
|
||||||
if (!modelIds.includes(id)) {
|
|
||||||
const model = store.peekRecord(modelRecord, id);
|
|
||||||
modelCollection.addObject(model);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -32,7 +32,6 @@ export default class RolesPageComponent extends Component {
|
|||||||
try {
|
try {
|
||||||
const message = `Successfully deleted role ${model.name}`;
|
const message = `Successfully deleted role ${model.name}`;
|
||||||
await model.destroyRecord();
|
await model.destroyRecord();
|
||||||
this.args.roles.removeObject(model);
|
|
||||||
this.flashMessages.success(message);
|
this.flashMessages.success(message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = errorMessage(error, 'Error deleting role. Please try again or contact support');
|
const message = errorMessage(error, 'Error deleting role. Please try again or contact support');
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import type PkiConfigClusterModel from 'vault/models/pki/config/cluster';
|
|||||||
import type PkiConfigCrlModel from 'vault/models/pki/config/crl';
|
import type PkiConfigCrlModel from 'vault/models/pki/config/crl';
|
||||||
import type PkiConfigUrlsModel from 'vault/models/pki/config/urls';
|
import type PkiConfigUrlsModel from 'vault/models/pki/config/urls';
|
||||||
import type { FormField, TtlEvent } from 'vault/app-types';
|
import type { FormField, TtlEvent } from 'vault/app-types';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
acme: PkiConfigAcmeModel;
|
acme: PkiConfigAcmeModel;
|
||||||
@@ -76,7 +77,7 @@ export default class PkiConfigurationEditComponent extends Component<Args> {
|
|||||||
message: errorMessage(error),
|
message: errorMessage(error),
|
||||||
};
|
};
|
||||||
this.flashMessages.danger(`Error updating config/${modelName}`, { sticky: true });
|
this.flashMessages.danger(`Error updating config/${modelName}`, { sticky: true });
|
||||||
this.errors.pushObject(errorObject);
|
this.errors = addToArray(this.errors, errorObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import errorMessage from 'vault/utils/error-message';
|
|||||||
import type RouterService from '@ember/routing/router-service';
|
import type RouterService from '@ember/routing/router-service';
|
||||||
import type FlashMessageService from 'vault/services/flash-messages';
|
import type FlashMessageService from 'vault/services/flash-messages';
|
||||||
import type PkiIssuerModel from 'vault/models/pki/issuer';
|
import type PkiIssuerModel from 'vault/models/pki/issuer';
|
||||||
|
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
model: PkiIssuerModel;
|
model: PkiIssuerModel;
|
||||||
@@ -36,8 +38,11 @@ export default class PkiIssuerEditComponent extends Component<Args> {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
setUsage(value: string) {
|
setUsage(value: string) {
|
||||||
const method = this.usageValues.includes(value) ? 'removeObject' : 'addObject';
|
if (this.usageValues.includes(value)) {
|
||||||
this.usageValues[method](value);
|
this.usageValues = removeFromArray(this.usageValues, value);
|
||||||
|
} else {
|
||||||
|
this.usageValues = addToArray(this.usageValues, value);
|
||||||
|
}
|
||||||
this.args.model.usage = this.usageValues.join(',');
|
this.args.model.usage = this.usageValues.join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import errorMessage from 'vault/utils/error-message';
|
import errorMessage from 'vault/utils/error-message';
|
||||||
import { waitFor } from '@ember/test-waiters';
|
import { waitFor } from '@ember/test-waiters';
|
||||||
import { parseCertificate } from 'vault/utils/parse-pki-cert';
|
import { parseCertificate } from 'vault/utils/parse-pki-cert';
|
||||||
|
import { addToArray } from 'vault/helpers/add-to-array';
|
||||||
/**
|
/**
|
||||||
* @module PkiIssuerCrossSign
|
* @module PkiIssuerCrossSign
|
||||||
* PkiIssuerCrossSign components render from a parent issuer's details page to cross-sign an intermediate issuer (from a different mount).
|
* PkiIssuerCrossSign components render from a parent issuer's details page to cross-sign an intermediate issuer (from a different mount).
|
||||||
@@ -92,7 +93,7 @@ export default class PkiIssuerCrossSign extends Component {
|
|||||||
|
|
||||||
// for cross-signing error handling we want to record the list of issuers before the process starts
|
// for cross-signing error handling we want to record the list of issuers before the process starts
|
||||||
this.intermediateIssuers[intermediateMount] = issuers;
|
this.intermediateIssuers[intermediateMount] = issuers;
|
||||||
this.validationErrors.addObject({
|
this.validationErrors = addToArray(this.validationErrors, {
|
||||||
newCrossSignedIssuer: this.nameValidation(newCrossSignedIssuer, issuers),
|
newCrossSignedIssuer: this.nameValidation(newCrossSignedIssuer, issuers),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,9 +110,9 @@ export default class PkiIssuerCrossSign extends Component {
|
|||||||
intermediateIssuer,
|
intermediateIssuer,
|
||||||
newCrossSignedIssuer
|
newCrossSignedIssuer
|
||||||
);
|
);
|
||||||
this.signedIssuers.addObject({ ...data, hasError: false });
|
this.signedIssuers = addToArray(this.signedIssuers, { ...data, hasError: false });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.signedIssuers.addObject({
|
this.signedIssuers = addToArray(this.signedIssuers, {
|
||||||
...this.formData[row],
|
...this.formData[row],
|
||||||
hasError: errorMessage(error),
|
hasError: errorMessage(error),
|
||||||
hasUnsupportedParams: error.cause ? error.cause.map((e) => e.message).join(', ') : null,
|
hasUnsupportedParams: error.cause ? error.cause.map((e) => e.message).join(', ') : null,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default function (server) {
|
|||||||
let records = [];
|
let records = [];
|
||||||
if (isMethod) {
|
if (isMethod) {
|
||||||
methods.forEach((method) => {
|
methods.forEach((method) => {
|
||||||
records.addObjects(schema.db[dbKeyFromType(method)].where({}));
|
records = [...records, ...schema.db[dbKeyFromType(method)].where({})];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
records = schema.db.mfaLoginEnforcements.where({});
|
records = schema.db.mfaLoginEnforcements.where({});
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module('Acceptance | mfa-method', function (hooks) {
|
|||||||
this.store = this.owner.lookup('service:store');
|
this.store = this.owner.lookup('service:store');
|
||||||
this.getMethods = () =>
|
this.getMethods = () =>
|
||||||
['Totp', 'Duo', 'Okta', 'Pingid'].reduce((methods, type) => {
|
['Totp', 'Duo', 'Okta', 'Pingid'].reduce((methods, type) => {
|
||||||
methods.addObjects(this.server.db[`mfa${type}Methods`].where({}));
|
methods = [...methods, ...this.server.db[`mfa${type}Methods`].where({})];
|
||||||
return methods;
|
return methods;
|
||||||
}, []);
|
}, []);
|
||||||
return authPage.login();
|
return authPage.login();
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
assert.expect(2);
|
assert.expect(2);
|
||||||
this.set('cluster', EmberObject.create({ standby: true }));
|
this.set('cluster', EmberObject.create({ standby: true }));
|
||||||
this.set('selectedAuth', 'token');
|
this.set('selectedAuth', 'token');
|
||||||
await render(hbs`{{auth-form cluster=this.cluster selectedAuth=this.selectedAuth}}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} @selectedAuth={{this.selectedAuth}} />`);
|
||||||
assert.false(component.errorMessagePresent, false);
|
assert.false(component.errorMessagePresent, false);
|
||||||
this.owner.lookup('service:csp-event').events.addObject({ violatedDirective: 'connect-src' });
|
this.owner.lookup('service:csp-event').handleEvent({ violatedDirective: 'connect-src' });
|
||||||
await settled();
|
await settled();
|
||||||
assert.strictEqual(component.errorText, CSP_ERR_TEXT);
|
assert.strictEqual(component.errorText, CSP_ERR_TEXT);
|
||||||
});
|
});
|
||||||
@@ -75,7 +75,7 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
|
|
||||||
this.set('cluster', EmberObject.create({}));
|
this.set('cluster', EmberObject.create({}));
|
||||||
this.set('selectedAuth', 'token');
|
this.set('selectedAuth', 'token');
|
||||||
await render(hbs`{{auth-form cluster=this.cluster selectedAuth=this.selectedAuth}}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} @selectedAuth={{this.selectedAuth}} />`);
|
||||||
return component.login().then(() => {
|
return component.login().then(() => {
|
||||||
assert.strictEqual(component.errorText, 'Error Authentication failed: Not allowed');
|
assert.strictEqual(component.errorText, 'Error Authentication failed: Not allowed');
|
||||||
server.shutdown();
|
server.shutdown();
|
||||||
@@ -86,17 +86,20 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
assert.expect(1);
|
assert.expect(1);
|
||||||
const server = new Pretender(function () {
|
const server = new Pretender(function () {
|
||||||
this.get('/v1/auth/**', () => {
|
this.get('/v1/auth/**', () => {
|
||||||
return [400, { 'Content-Type': 'application/json' }];
|
return [400, { 'Content-Type': 'application/json' }, JSON.stringify({ errors: ['API Error here'] })];
|
||||||
});
|
});
|
||||||
this.get('/v1/sys/internal/ui/mounts', this.passthrough);
|
this.get('/v1/sys/internal/ui/mounts', this.passthrough);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('cluster', EmberObject.create({}));
|
this.set('cluster', EmberObject.create({}));
|
||||||
this.set('selectedAuth', 'token');
|
this.set('selectedAuth', 'token');
|
||||||
await render(hbs`{{auth-form cluster=this.cluster selectedAuth=this.selectedAuth}}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} @selectedAuth={{this.selectedAuth}} />`);
|
||||||
// returns null because test does not return details of failed network request. On the app it will return the details of the error instead of null.
|
|
||||||
return component.login().then(() => {
|
return component.login().then(() => {
|
||||||
assert.strictEqual(component.errorText, 'Error Authentication failed: null');
|
assert.strictEqual(
|
||||||
|
component.errorText,
|
||||||
|
'Error Authentication failed: API Error here',
|
||||||
|
'shows the error from the API'
|
||||||
|
);
|
||||||
server.shutdown();
|
server.shutdown();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -134,7 +137,7 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.set('cluster', EmberObject.create({}));
|
this.set('cluster', EmberObject.create({}));
|
||||||
await render(hbs`{{auth-form cluster=this.cluster }}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} />`);
|
||||||
|
|
||||||
assert.strictEqual(component.tabs.length, 2, 'renders a tab for userpass and Other');
|
assert.strictEqual(component.tabs.length, 2, 'renders a tab for userpass and Other');
|
||||||
assert.strictEqual(component.tabs.objectAt(0).name, 'foo', 'uses the path in the label');
|
assert.strictEqual(component.tabs.objectAt(0).name, 'foo', 'uses the path in the label');
|
||||||
@@ -155,7 +158,7 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.set('cluster', EmberObject.create({}));
|
this.set('cluster', EmberObject.create({}));
|
||||||
await render(hbs`{{auth-form cluster=this.cluster }}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} />`);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
component.descriptionText,
|
component.descriptionText,
|
||||||
@@ -183,7 +186,7 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
|
|
||||||
this.set('cluster', EmberObject.create({}));
|
this.set('cluster', EmberObject.create({}));
|
||||||
this.set('selectedAuth', 'foo/');
|
this.set('selectedAuth', 'foo/');
|
||||||
await render(hbs`{{auth-form cluster=this.cluster selectedAuth=this.selectedAuth}}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} @selectedAuth={{this.selectedAuth}} />`);
|
||||||
await component.login();
|
await component.login();
|
||||||
|
|
||||||
await settled();
|
await settled();
|
||||||
@@ -267,7 +270,7 @@ module('Integration | Component | auth form', function (hooks) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.set('wrappedToken', '54321');
|
this.set('wrappedToken', '54321');
|
||||||
await render(hbs`{{auth-form cluster=this.cluster wrappedToken=this.wrappedToken}}`);
|
await render(hbs`<AuthForm @cluster={{this.cluster}} @wrappedToken={{this.wrappedToken}} />`);
|
||||||
later(() => cancelTimers(), 50);
|
later(() => cancelTimers(), 50);
|
||||||
|
|
||||||
await settled();
|
await settled();
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ module('Integration | Component | ldap | Page::Library::CreateAndEdit', function
|
|||||||
|
|
||||||
await this.renderComponent();
|
await this.renderComponent();
|
||||||
|
|
||||||
await click('[data-test-string-list-button="delete"]');
|
await click('[data-test-string-list-row="0"] [data-test-string-list-button="delete"]');
|
||||||
await click('[data-test-input="disable_check_in_enforcement"] input#Disabled');
|
await click('[data-test-input="disable_check_in_enforcement"] input#Disabled');
|
||||||
await click('[data-test-save]');
|
await click('[data-test-save]');
|
||||||
|
|
||||||
|
|||||||
@@ -153,8 +153,8 @@ module('Integration | Component | mfa-login-enforcement-form', function (hooks)
|
|||||||
test('it should populate fields with model data', async function (assert) {
|
test('it should populate fields with model data', async function (assert) {
|
||||||
this.model.name = 'foo';
|
this.model.name = 'foo';
|
||||||
const [method] = await this.store.query('mfa-method', {});
|
const [method] = await this.store.query('mfa-method', {});
|
||||||
this.model.mfa_methods.addObject(method);
|
this.model.mfa_methods = [method];
|
||||||
this.model.auth_method_accessors.addObject('auth_userpass_1234');
|
this.model.auth_method_accessors = ['auth_userpass_1234'];
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<Mfa::MfaLoginEnforcementForm
|
<Mfa::MfaLoginEnforcementForm
|
||||||
@@ -207,12 +207,12 @@ module('Integration | Component | mfa-login-enforcement-form', function (hooks)
|
|||||||
keys: ['1234'],
|
keys: ['1234'],
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
this.model.auth_method_accessors.addObject('auth_userpass_1234');
|
this.model.auth_method_accessors = ['auth_userpass_1234'];
|
||||||
this.model.auth_method_types.addObject('userpass');
|
this.model.auth_method_types = ['userpass'];
|
||||||
const [entity] = await this.store.query('identity/entity', {});
|
const [entity] = await this.store.query('identity/entity', {});
|
||||||
this.model.identity_entities.addObject(entity);
|
this.model.identity_entities = [entity];
|
||||||
const [group] = await this.store.query('identity/group', {});
|
const [group] = await this.store.query('identity/group', {});
|
||||||
this.model.identity_groups.addObject(group);
|
this.model.identity_groups = [group];
|
||||||
|
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
<Mfa::MfaLoginEnforcementForm
|
<Mfa::MfaLoginEnforcementForm
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ module('Integration | Component | path filter config list', function (hooks) {
|
|||||||
await clickTrigger();
|
await clickTrigger();
|
||||||
await searchSelect.deleteButtons.objectAt(1).click();
|
await searchSelect.deleteButtons.objectAt(1).click();
|
||||||
await clickTrigger();
|
await clickTrigger();
|
||||||
|
await typeInSearch('ns1');
|
||||||
assert.dom('.ember-power-select-group').hasText('Namespaces ns1', 'puts ns back within group');
|
assert.dom('.ember-power-select-group').hasText('Namespaces ns1', 'puts ns back within group');
|
||||||
await clickTrigger();
|
await clickTrigger();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module('Integration | Helper | add-to-array', function (hooks) {
|
|||||||
|
|
||||||
test('it correctly adds a value to an array without mutating the original', function (assert) {
|
test('it correctly adds a value to an array without mutating the original', function (assert) {
|
||||||
const ARRAY = ['horse', 'cow', 'chicken'];
|
const ARRAY = ['horse', 'cow', 'chicken'];
|
||||||
const result = addToArray([ARRAY, 'pig']);
|
const result = addToArray(ARRAY, 'pig');
|
||||||
assert.deepEqual(result, [...ARRAY, 'pig'], 'Result has additional item');
|
assert.deepEqual(result, [...ARRAY, 'pig'], 'Result has additional item');
|
||||||
assert.deepEqual(ARRAY, ['horse', 'cow', 'chicken'], 'original array is not mutated');
|
assert.deepEqual(ARRAY, ['horse', 'cow', 'chicken'], 'original array is not mutated');
|
||||||
});
|
});
|
||||||
@@ -20,7 +20,7 @@ module('Integration | Helper | add-to-array', function (hooks) {
|
|||||||
test('it fails if the first value is not an array', function (assert) {
|
test('it fails if the first value is not an array', function (assert) {
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = addToArray(['not-array', 'string']);
|
result = addToArray('not-array', 'string');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = e.message;
|
result = e.message;
|
||||||
}
|
}
|
||||||
@@ -29,13 +29,13 @@ module('Integration | Helper | add-to-array', function (hooks) {
|
|||||||
|
|
||||||
test('it works with non-string arrays', function (assert) {
|
test('it works with non-string arrays', function (assert) {
|
||||||
const ARRAY = ['five', 6, '7'];
|
const ARRAY = ['five', 6, '7'];
|
||||||
const result = addToArray([ARRAY, 10]);
|
const result = addToArray(ARRAY, 10);
|
||||||
assert.deepEqual(result, ['five', 6, '7', 10], 'added number value');
|
assert.deepEqual(result, ['five', 6, '7', 10], 'added number value');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it de-dupes the result', function (assert) {
|
test('it de-dupes the result', function (assert) {
|
||||||
const ARRAY = ['horse', 'cow', 'chicken'];
|
const ARRAY = ['horse', 'cow', 'chicken'];
|
||||||
const result = addToArray([ARRAY, 'horse']);
|
const result = addToArray(ARRAY, 'horse');
|
||||||
assert.deepEqual(result, ['horse', 'cow', 'chicken']);
|
assert.deepEqual(result, ['horse', 'cow', 'chicken']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,28 +5,28 @@
|
|||||||
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { removeFromArray } from '../../../helpers/remove-from-array';
|
import { removeManyFromArray, removeFromArray } from 'vault/helpers/remove-from-array';
|
||||||
|
|
||||||
module('Integration | Helper | remove-from-array', function (hooks) {
|
module('Integration | Helper | remove-from-array', function (hooks) {
|
||||||
setupRenderingTest(hooks);
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
test('it correctly removes a value from an array without mutating the original', function (assert) {
|
test('it correctly removes a value from an array without mutating the original', function (assert) {
|
||||||
const ARRAY = ['horse', 'cow', 'chicken'];
|
const ARRAY = ['horse', 'cow', 'chicken'];
|
||||||
const result = removeFromArray([ARRAY, 'horse']);
|
const result = removeFromArray(ARRAY, 'horse');
|
||||||
assert.deepEqual(result, ['cow', 'chicken'], 'Result does not have removed item');
|
assert.deepEqual(result, ['cow', 'chicken'], 'Result does not have removed item');
|
||||||
assert.deepEqual(ARRAY, ['horse', 'cow', 'chicken'], 'original array is not mutated');
|
assert.deepEqual(ARRAY, ['horse', 'cow', 'chicken'], 'original array is not mutated');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it returns the same value if the item is not found', function (assert) {
|
test('it returns the same value if the item is not found', function (assert) {
|
||||||
const ARRAY = ['horse', 'cow', 'chicken'];
|
const ARRAY = ['horse', 'cow', 'chicken'];
|
||||||
const result = removeFromArray([ARRAY, 'pig']);
|
const result = removeFromArray(ARRAY, 'pig');
|
||||||
assert.deepEqual(result, ARRAY, 'Results are the same as original array');
|
assert.deepEqual(result, ARRAY, 'Results are the same as original array');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it fails if the first value is not an array', function (assert) {
|
test('it fails if the first value is not an array', function (assert) {
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = removeFromArray(['not-array', 'string']);
|
result = removeFromArray('not-array', 'string');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = e.message;
|
result = e.message;
|
||||||
}
|
}
|
||||||
@@ -35,15 +35,23 @@ module('Integration | Helper | remove-from-array', function (hooks) {
|
|||||||
|
|
||||||
test('it works with non-string arrays', function (assert) {
|
test('it works with non-string arrays', function (assert) {
|
||||||
const ARRAY = ['five', 6, '7'];
|
const ARRAY = ['five', 6, '7'];
|
||||||
const result1 = removeFromArray([ARRAY, 6]);
|
const result1 = removeFromArray(ARRAY, 6);
|
||||||
const result2 = removeFromArray([ARRAY, 7]);
|
const result2 = removeFromArray(ARRAY, 7);
|
||||||
assert.deepEqual(result1, ['five', '7'], 'removed number value');
|
assert.deepEqual(result1, ['five', '7'], 'removed number value');
|
||||||
assert.deepEqual(result2, ARRAY, 'did not match on different types');
|
assert.deepEqual(result2, ARRAY, 'did not match on different types');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it de-dupes the result', function (assert) {
|
test('it de-dupes the result', function (assert) {
|
||||||
const ARRAY = ['horse', 'cow', 'chicken', 'cow'];
|
const ARRAY = ['horse', 'cow', 'chicken', 'cow'];
|
||||||
const result = removeFromArray([ARRAY, 'horse']);
|
const result = removeFromArray(ARRAY, 'horse');
|
||||||
assert.deepEqual(result, ['cow', 'chicken']);
|
assert.deepEqual(result, ['cow', 'chicken']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it works with two arrays', function (assert) {
|
||||||
|
const ARRAY = ['five', 6, '7'];
|
||||||
|
const result1 = removeManyFromArray(ARRAY, [6, '7']);
|
||||||
|
const result2 = removeManyFromArray(ARRAY, ['foo', 'five']);
|
||||||
|
assert.deepEqual(result1, ['five'], 'removed multiple values');
|
||||||
|
assert.deepEqual(result2, [6, '7'], 'did nothing with values that were not in the array');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user