mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +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' }) {
|
||||
const connection = await store.queryRecord('database/connection', { backend, id: db });
|
||||
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;
|
||||
return connection.save();
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import NamedPathAdapter from 'vault/adapters/named-path';
|
||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
import { service } from '@ember/service';
|
||||
import AdapterError from '@ember-data/adapter/error';
|
||||
import { addManyToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
export default class LdapRoleAdapter extends NamedPathAdapter {
|
||||
@service flashMessages;
|
||||
@@ -33,7 +34,7 @@ export default class LdapRoleAdapter extends NamedPathAdapter {
|
||||
async query(store, type, query, recordArray, options) {
|
||||
const { showPartialError } = options.adapterOptions || {};
|
||||
const { backend } = query;
|
||||
const roles = [];
|
||||
let roles = [];
|
||||
const errors = [];
|
||||
|
||||
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) => {
|
||||
return resp.data.keys.map((name) => ({ id: name, name, backend, type: roleType }));
|
||||
});
|
||||
roles.addObjects(models);
|
||||
roles = addManyToArray(roles, models);
|
||||
} catch (error) {
|
||||
if (error.httpStatus !== 404) {
|
||||
errors.push(error);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import Ember from 'ember';
|
||||
import { next } from '@ember/runloop';
|
||||
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 Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
@@ -166,9 +166,12 @@ export default Component.extend(DEFAULTS, {
|
||||
return templateName;
|
||||
}),
|
||||
|
||||
hasCSPError: alias('csp.connectionViolations'),
|
||||
|
||||
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.`,
|
||||
cspError: computed('csp.connectionViolations.length', function () {
|
||||
if (this.csp.connectionViolations.length) {
|
||||
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 () {
|
||||
const hasMethodsWithPath = this.hasMethodsWithPath;
|
||||
|
||||
@@ -175,7 +175,9 @@ export default class HorizontalBarChart extends Component {
|
||||
this.isLabel = false;
|
||||
this.tooltipText = []; // clear stats
|
||||
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);
|
||||
|
||||
@@ -155,7 +155,9 @@ export default class VerticalBarChart extends Component {
|
||||
this.tooltipStats = []; // clear stats
|
||||
this.args.chartLegend.forEach(({ key, label }) => {
|
||||
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)])} ${
|
||||
data.new_clients ? 'total' : 'new'
|
||||
|
||||
@@ -9,6 +9,7 @@ import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { waitFor } from '@ember/test-waiters';
|
||||
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
/**
|
||||
* @module KeymgmtProviderEdit
|
||||
@@ -94,8 +95,9 @@ export default class KeymgmtProviderEdit extends Component {
|
||||
@action
|
||||
async onDeleteKey(model) {
|
||||
try {
|
||||
const providerKeys = removeFromArray(this.args.model.keys, model);
|
||||
await model.destroyRecord();
|
||||
this.args.model.keys.removeObject(model);
|
||||
this.args.model.keys = providerKeys;
|
||||
} catch (error) {
|
||||
this.flashMessages.danger(error.errors.join('. '));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { service } from '@ember/service';
|
||||
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
|
||||
@@ -64,7 +65,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
||||
for (const { label, key } of this.targetTypes) {
|
||||
const targetArray = await this.args.model[key];
|
||||
const targets = targetArray.map((value) => ({ label, key, value }));
|
||||
this.targets.addObjects(targets);
|
||||
this.targets = addManyToArray(this.targets, targets);
|
||||
}
|
||||
}
|
||||
async resetTargetState() {
|
||||
@@ -102,7 +103,6 @@ export default class MfaLoginEnforcementForm extends Component {
|
||||
|
||||
updateModelForKey(key) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -126,8 +126,18 @@ export default class MfaLoginEnforcementForm extends Component {
|
||||
|
||||
@action
|
||||
async onMethodChange(selectedIds) {
|
||||
// first make sure the async relationship is loaded
|
||||
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
|
||||
@@ -150,7 +160,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
||||
addTarget() {
|
||||
const { label, key } = this.selectedTarget;
|
||||
const value = this.selectedTargetValue;
|
||||
this.targets.addObject({ label, value, key });
|
||||
this.targets = addToArray(this.targets, { label, value, key });
|
||||
// recalculate value for appropriate model property
|
||||
this.updateModelForKey(key);
|
||||
this.selectedTargetValue = null;
|
||||
@@ -158,7 +168,7 @@ export default class MfaLoginEnforcementForm extends Component {
|
||||
}
|
||||
@action
|
||||
removeTarget(target) {
|
||||
this.targets.removeObject(target);
|
||||
this.targets = removeFromArray(this.targets, target);
|
||||
// recalculate value for appropriate model property
|
||||
this.updateModelForKey(target.key);
|
||||
}
|
||||
|
||||
@@ -195,6 +195,7 @@ export default class SecretCreateOrUpdate extends Component {
|
||||
if (isBlank(item.name)) {
|
||||
return;
|
||||
}
|
||||
// secretData is a KVObject/ArrayProxy so removeObject is fine here
|
||||
data.removeObject(item);
|
||||
this.checkRows();
|
||||
this.handleChange();
|
||||
|
||||
@@ -9,6 +9,7 @@ import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { capitalize } from '@ember/string';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
export default class MfaMethodCreateController extends Controller {
|
||||
@service store;
|
||||
@@ -95,7 +96,8 @@ export default class MfaMethodCreateController extends Controller {
|
||||
// first save method
|
||||
yield this.method.save();
|
||||
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 {
|
||||
// now save enforcement and catch error separately
|
||||
yield this.enforcement.save();
|
||||
|
||||
@@ -10,7 +10,13 @@ function dedupe(items) {
|
||||
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)) {
|
||||
assert(`Value provided is not an array`, false);
|
||||
}
|
||||
@@ -19,4 +25,9 @@ export function addToArray([array, string]) {
|
||||
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);
|
||||
}
|
||||
|
||||
export function removeFromArray([array, string]) {
|
||||
if (!Array.isArray(array)) {
|
||||
assert(`Value provided is not an array`, false);
|
||||
}
|
||||
export function removeManyFromArray(array, toRemove) {
|
||||
assert(`Both values must be an array`, Array.isArray(array) && Array.isArray(toRemove));
|
||||
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 idx = newArray.indexOf(string);
|
||||
if (idx >= 0) {
|
||||
@@ -22,4 +26,9 @@ export function removeFromArray([array, string]) {
|
||||
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 !== '') {
|
||||
newInputValue = history.objectAt(index)?.content;
|
||||
const objAt = history[index];
|
||||
newInputValue = objAt?.content;
|
||||
}
|
||||
|
||||
return [index, newInputValue];
|
||||
|
||||
@@ -8,6 +8,7 @@ import { computed } from '@ember/object';
|
||||
import fieldToAttrs, { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||||
import apiPath from 'vault/utils/api-path';
|
||||
import lazyCapabilities from 'vault/macros/lazy-capabilities';
|
||||
import { removeManyFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
export const COMPUTEDS = {
|
||||
operationFields: computed('newFields', function () {
|
||||
@@ -15,7 +16,7 @@ export const COMPUTEDS = {
|
||||
}),
|
||||
|
||||
operationFieldsWithoutSpecial: computed('operationFields', function () {
|
||||
return this.operationFields.slice().removeObjects(['operationAll', 'operationNone']);
|
||||
return removeManyFromArray(this.operationFields, ['operationAll', 'operationNone']);
|
||||
}),
|
||||
|
||||
tlsFields: computed(function () {
|
||||
@@ -25,12 +26,12 @@ export const COMPUTEDS = {
|
||||
// For rendering on the create/edit pages
|
||||
defaultFields: computed('newFields', 'operationFields', 'tlsFields', function () {
|
||||
const excludeFields = ['role'].concat(this.operationFields, this.tlsFields);
|
||||
return this.newFields.slice().removeObjects(excludeFields);
|
||||
return removeManyFromArray(this.newFields, excludeFields);
|
||||
}),
|
||||
|
||||
// For adapter/serializer
|
||||
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 server = ['operationDiscoverVersions'];
|
||||
const others = this.operationFieldsWithoutSpecial
|
||||
.slice()
|
||||
.removeObjects(objects.concat(attributes, server));
|
||||
const others = removeManyFromArray(this.operationFieldsWithoutSpecial, [
|
||||
...objects,
|
||||
...attributes,
|
||||
...server,
|
||||
]);
|
||||
const groups = [
|
||||
{ 'Managed Cryptographic Objects': objects },
|
||||
{ 'Object Attributes': attributes },
|
||||
|
||||
@@ -10,6 +10,7 @@ import { methods } from 'vault/helpers/mountable-auth-methods';
|
||||
import { withModelValidations } from 'vault/decorators/model-validations';
|
||||
import { isPresent } from '@ember/utils';
|
||||
import { service } from '@ember/service';
|
||||
import { addManyToArray, addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
const validations = {
|
||||
name: [{ type: 'presence', message: 'Name is required' }],
|
||||
@@ -52,7 +53,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
||||
|
||||
async prepareTargets() {
|
||||
let authMethods;
|
||||
const targets = [];
|
||||
let targets = [];
|
||||
|
||||
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
|
||||
@@ -68,7 +69,8 @@ export default class MfaLoginEnforcementModel extends Model {
|
||||
const selectedAuthMethods = authMethods.filter((model) => {
|
||||
return this.auth_method_accessors.includes(model.accessor);
|
||||
});
|
||||
targets.addObjects(
|
||||
targets = addManyToArray(
|
||||
targets,
|
||||
selectedAuthMethods.map((method) => ({
|
||||
icon: this.iconForMount(method.type),
|
||||
link: 'vault.cluster.access.method',
|
||||
@@ -82,7 +84,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
||||
this.auth_method_types.forEach((type) => {
|
||||
const icon = this.iconForMount(type);
|
||||
const mountCount = authMethods.filterBy('type', type).length;
|
||||
targets.addObject({
|
||||
targets = addToArray(targets, {
|
||||
key: 'auth_method_types',
|
||||
icon,
|
||||
title: type,
|
||||
@@ -92,7 +94,7 @@ export default class MfaLoginEnforcementModel extends Model {
|
||||
|
||||
for (const key of ['identity_entities', 'identity_groups']) {
|
||||
(await this[key]).forEach((model) => {
|
||||
targets.addObject({
|
||||
targets = addToArray(targets, {
|
||||
key,
|
||||
icon: 'user',
|
||||
link: 'vault.cluster.access.identity.show',
|
||||
|
||||
@@ -50,7 +50,7 @@ export default class SyncDestinationSerializer extends ApplicationSerializer {
|
||||
const type = key.replace(/\/$/, '');
|
||||
const id = `${type}/${name}`;
|
||||
// create object with destination's id and attributes, add to payload
|
||||
transformedPayload.pushObject({ id, name, type });
|
||||
transformedPayload.push({ id, name, type });
|
||||
});
|
||||
}
|
||||
return transformedPayload;
|
||||
|
||||
@@ -17,6 +17,7 @@ import { resolve, reject } from 'rsvp';
|
||||
import getStorage from 'vault/lib/token-storage';
|
||||
import ENV from 'vault/config/environment';
|
||||
import { allSupportedAuthBackends } from 'vault/helpers/supported-auth-backends';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
const TOKEN_SEPARATOR = '☃';
|
||||
const TOKEN_PREFIX = 'vault-';
|
||||
@@ -250,7 +251,6 @@ export default Service.extend({
|
||||
|
||||
persistAuthData() {
|
||||
const [firstArg, resp] = arguments;
|
||||
const tokens = this.tokens;
|
||||
const currentNamespace = this.namespaceService.path || '';
|
||||
// dropdown vs tab format
|
||||
const mountPath = firstArg?.data?.path || firstArg?.selectedAuth;
|
||||
@@ -303,8 +303,7 @@ export default Service.extend({
|
||||
if (!data.displayName) {
|
||||
data.displayName = (this.getTokenData(tokenName) || {}).displayName;
|
||||
}
|
||||
tokens.addObject(tokenName);
|
||||
this.set('tokens', tokens);
|
||||
this.set('tokens', addToArray(this.tokens, tokenName));
|
||||
this.set('allowExpiration', false);
|
||||
this.setTokenData(tokenName, data);
|
||||
return resolve({
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
// 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
|
||||
import Service from '@ember/service';
|
||||
|
||||
import { getOwner } from '@ember/application';
|
||||
import { computed } from '@ember/object';
|
||||
import { shiftCommandIndex } from 'vault/lib/console-helpers';
|
||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
import { sanitizePath, ensureTrailingSlash } from 'core/utils/sanitize-path';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { addManyToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
const VERBS = {
|
||||
read: 'GET',
|
||||
@@ -20,51 +20,51 @@ const VERBS = {
|
||||
delete: 'DELETE',
|
||||
};
|
||||
|
||||
export default Service.extend({
|
||||
isOpen: false,
|
||||
export default class ConsoleService extends Service {
|
||||
@tracked isOpen = false;
|
||||
@tracked commandIndex = null;
|
||||
@tracked log = [];
|
||||
|
||||
adapter() {
|
||||
return getOwner(this).lookup('adapter:console');
|
||||
},
|
||||
get commandHistory() {
|
||||
return this.log.filter((log) => log.type === 'command');
|
||||
},
|
||||
log: computed(function () {
|
||||
return [];
|
||||
}),
|
||||
commandIndex: null,
|
||||
}
|
||||
|
||||
// Not a getter so it can be stubbed in tests
|
||||
adapter() {
|
||||
return getOwner(this).lookup('adapter:console');
|
||||
}
|
||||
|
||||
shiftCommandIndex(keyCode, setCommandFn = () => {}) {
|
||||
const [newIndex, newCommand] = shiftCommandIndex(keyCode, this.commandHistory, this.commandIndex);
|
||||
if (newCommand !== undefined && newIndex !== undefined) {
|
||||
this.set('commandIndex', newIndex);
|
||||
this.commandIndex = newIndex;
|
||||
setCommandFn(newCommand);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clearLog(clearAll = false) {
|
||||
const log = this.log;
|
||||
let history;
|
||||
if (!clearAll) {
|
||||
history = this.commandHistory.slice();
|
||||
history.setEach('hidden', true);
|
||||
}
|
||||
log.clear();
|
||||
this.log = [];
|
||||
if (history) {
|
||||
log.addObjects(history);
|
||||
this.log = addManyToArray(this.log, history);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
logAndOutput(command, logContent) {
|
||||
const log = this.log;
|
||||
const log = this.log.slice();
|
||||
if (command) {
|
||||
log.pushObject({ type: 'command', content: command });
|
||||
this.set('commandIndex', null);
|
||||
log.push({ type: 'command', content: command });
|
||||
this.commandIndex = null;
|
||||
}
|
||||
if (logContent) {
|
||||
log.pushObject(logContent);
|
||||
log.push(logContent);
|
||||
}
|
||||
},
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
ajax(operation, path, options = {}) {
|
||||
const verb = VERBS[operation];
|
||||
@@ -75,7 +75,7 @@ export default Service.extend({
|
||||
data,
|
||||
wrapTTL,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
kvGet(path, data, flags = {}) {
|
||||
const { wrapTTL, metadata } = flags;
|
||||
@@ -84,21 +84,21 @@ export default Service.extend({
|
||||
const [backend, secretPath] = path.split(/\/(.+)?/);
|
||||
const kvPath = `${backend}/${pathSegment}/${secretPath}`;
|
||||
return this.ajax('read', sanitizePath(kvPath), { wrapTTL });
|
||||
},
|
||||
}
|
||||
|
||||
read(path, data, flags) {
|
||||
const wrapTTL = flags?.wrapTTL;
|
||||
return this.ajax('read', sanitizePath(path), { wrapTTL });
|
||||
},
|
||||
}
|
||||
|
||||
write(path, data, flags) {
|
||||
const wrapTTL = flags?.wrapTTL;
|
||||
return this.ajax('write', sanitizePath(path), { data, wrapTTL });
|
||||
},
|
||||
}
|
||||
|
||||
delete(path) {
|
||||
return this.ajax('delete', sanitizePath(path));
|
||||
},
|
||||
}
|
||||
|
||||
list(path, data, flags) {
|
||||
const wrapTTL = flags?.wrapTTL;
|
||||
@@ -109,5 +109,5 @@ export default Service.extend({
|
||||
},
|
||||
wrapTTL,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,35 @@
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
/*eslint-disable no-constant-condition*/
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
import Service from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { task, waitForEvent } from 'ember-concurrency';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
export default Service.extend({
|
||||
events: computed(function () {
|
||||
return [];
|
||||
}),
|
||||
connectionViolations: computed('events.@each.violatedDirective', function () {
|
||||
return this.events.some((e) => e.violatedDirective.startsWith('connect-src'));
|
||||
}),
|
||||
export default class CspEventService extends Service {
|
||||
@tracked connectionViolations = [];
|
||||
|
||||
attach() {
|
||||
this.monitor.perform();
|
||||
},
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.monitor.cancelAll();
|
||||
},
|
||||
}
|
||||
|
||||
monitor: task(function* () {
|
||||
this.events.clear();
|
||||
handleEvent(event) {
|
||||
if (event.violatedDirective.startsWith('connect-src')) {
|
||||
this.connectionViolations = addToArray(this.connectionViolations, event);
|
||||
}
|
||||
}
|
||||
|
||||
@task
|
||||
*monitor() {
|
||||
this.connectionViolations = [];
|
||||
|
||||
while (true) {
|
||||
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 { STORAGE_KEYS, DEFAULTS, MACHINES } from 'vault/helpers/wizard-constants';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
const {
|
||||
TUTORIAL_STATE,
|
||||
COMPONENT_STATE,
|
||||
@@ -101,7 +102,7 @@ export default Service.extend(DEFAULTS, {
|
||||
} else {
|
||||
if (this.featureMachineHistory) {
|
||||
if (!this.featureMachineHistory.includes(state)) {
|
||||
const newHistory = this.featureMachineHistory.addObject(state);
|
||||
const newHistory = addToArray(this.featureMachineHistory, state);
|
||||
this.set('featureMachineHistory', newHistory);
|
||||
} else {
|
||||
//we're repeating steps
|
||||
@@ -293,7 +294,7 @@ export default Service.extend(DEFAULTS, {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
let next;
|
||||
if (this.currentMachine === 'secrets' && this.featureState === 'display') {
|
||||
@@ -311,9 +312,9 @@ export default Service.extend(DEFAULTS, {
|
||||
},
|
||||
|
||||
startFeature() {
|
||||
const FeatureMachineConfig = MACHINES[this.featureList.objectAt(0)];
|
||||
const FeatureMachineConfig = MACHINES[this.featureList[0]];
|
||||
FeatureMachine = Machine(FeatureMachineConfig);
|
||||
this.set('currentMachine', this.featureList.objectAt(0));
|
||||
this.set('currentMachine', this.featureList[0]);
|
||||
if (this.storageHasKey(FEATURE_STATE)) {
|
||||
this.saveState('featureState', this.getExtState(FEATURE_STATE));
|
||||
} else {
|
||||
@@ -337,7 +338,7 @@ export default Service.extend(DEFAULTS, {
|
||||
completed.push(done);
|
||||
this.saveExtState(COMPLETED_FEATURES, completed);
|
||||
} 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);
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</nav>
|
||||
{{/if}}
|
||||
<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}}
|
||||
<div class="has-bottom-margin-s">
|
||||
<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 { dasherize } from 'vault/helpers/dasherize';
|
||||
import { assert } from '@ember/debug';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
/**
|
||||
* @module FormField
|
||||
@@ -193,9 +195,12 @@ export default class FormFieldComponent extends Component {
|
||||
|
||||
@action
|
||||
handleChecklist(event) {
|
||||
const valueArray = this.args.model[this.valuePath];
|
||||
const method = event.target.checked ? 'addObject' : 'removeObject';
|
||||
valueArray[method](event.target.value);
|
||||
this.setAndBroadcast(valueArray);
|
||||
let updatedValue = this.args.model[this.valuePath];
|
||||
if (event.target.checked) {
|
||||
updatedValue = addToArray(updatedValue, event.target.value);
|
||||
} 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 {
|
||||
// kvData is type ArrayProxy, so addObject etc are fine here
|
||||
@tracked kvData;
|
||||
|
||||
get placeholders() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { assert } from '@ember/debug';
|
||||
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
/**
|
||||
* @module ObjectListInput
|
||||
@@ -65,7 +66,7 @@ export default class ObjectListInput extends Component {
|
||||
|
||||
@action
|
||||
handleInput(idx, { target }) {
|
||||
const inputObj = this.inputList.objectAt(idx);
|
||||
const inputObj = this.inputList[idx];
|
||||
inputObj[target.name] = target.value;
|
||||
this.handleChange();
|
||||
}
|
||||
@@ -79,8 +80,8 @@ export default class ObjectListInput extends Component {
|
||||
|
||||
@action
|
||||
removeRow(idx) {
|
||||
const row = this.inputList.objectAt(idx);
|
||||
this.inputList.removeObject(row);
|
||||
const row = this.inputList[idx];
|
||||
this.inputList = removeFromArray(this.inputList, row);
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { task } from 'ember-concurrency';
|
||||
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
|
||||
@@ -31,7 +33,7 @@ import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-ut
|
||||
* />
|
||||
*
|
||||
// * 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 {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'])
|
||||
@@ -81,7 +83,7 @@ export default class SearchSelectWithModal extends Component {
|
||||
return inputValues.map((option) => {
|
||||
const matchingOption = this.dropdownOptions.find((opt) => opt.id === option);
|
||||
// remove any matches from dropdown list
|
||||
this.dropdownOptions.removeObject(matchingOption);
|
||||
this.dropdownOptions = removeFromArray(this.dropdownOptions, matchingOption);
|
||||
return {
|
||||
id: option,
|
||||
name: matchingOption ? matchingOption.name : option,
|
||||
@@ -168,8 +170,8 @@ export default class SearchSelectWithModal extends Component {
|
||||
// -----
|
||||
@action
|
||||
discardSelection(selected) {
|
||||
this.selectedOptions.removeObject(selected);
|
||||
this.dropdownOptions.pushObject(selected);
|
||||
this.selectedOptions = removeFromArray(this.selectedOptions, selected);
|
||||
this.dropdownOptions = addToArray(this.dropdownOptions, selected);
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
@@ -196,8 +198,8 @@ export default class SearchSelectWithModal extends Component {
|
||||
this.showModal = true;
|
||||
} else {
|
||||
// user has selected an existing item, handleChange immediately
|
||||
this.selectedOptions.pushObject(selection);
|
||||
this.dropdownOptions.removeObject(selection);
|
||||
this.selectedOptions = addToArray(this.selectedOptions, selection);
|
||||
this.dropdownOptions = removeFromArray(this.dropdownOptions, selection);
|
||||
this.handleChange();
|
||||
}
|
||||
}
|
||||
@@ -209,7 +211,7 @@ export default class SearchSelectWithModal extends Component {
|
||||
this.showModal = false;
|
||||
if (model && model.currentState.isSaved) {
|
||||
const { name } = model;
|
||||
this.selectedOptions.pushObject({ name, id: name });
|
||||
this.selectedOptions = addToArray(this.selectedOptions, { name, id: name });
|
||||
this.handleChange();
|
||||
}
|
||||
this.nameInput = null;
|
||||
|
||||
@@ -10,6 +10,8 @@ import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { resolve } from 'rsvp';
|
||||
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
|
||||
* 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
|
||||
* @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 {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'
|
||||
@@ -118,7 +120,7 @@ export default class SearchSelect extends Component {
|
||||
: false;
|
||||
|
||||
// remove any matches from dropdown list
|
||||
this.dropdownOptions.removeObject(matchingOption);
|
||||
this.dropdownOptions = removeFromArray(this.dropdownOptions, matchingOption);
|
||||
return {
|
||||
id: option,
|
||||
name: matchingOption ? matchingOption[this.nameKey] : option,
|
||||
@@ -263,9 +265,9 @@ export default class SearchSelect extends Component {
|
||||
|
||||
@action
|
||||
discardSelection(selected) {
|
||||
this.selectedOptions.removeObject(selected);
|
||||
this.selectedOptions = removeFromArray(this.selectedOptions, selected);
|
||||
if (!selected.new) {
|
||||
this.dropdownOptions.pushObject(selected);
|
||||
this.dropdownOptions = addToArray(this.dropdownOptions, selected);
|
||||
}
|
||||
this.handleChange();
|
||||
}
|
||||
@@ -291,10 +293,10 @@ export default class SearchSelect extends Component {
|
||||
selectOrCreate(selection) {
|
||||
if (selection && selection.__isSuggestion__) {
|
||||
const name = selection.__value__;
|
||||
this.selectedOptions.pushObject({ name, id: name, new: true });
|
||||
this.selectedOptions = addToArray(this.selectedOptions, { name, id: name, new: true });
|
||||
} else {
|
||||
this.selectedOptions.pushObject(selection);
|
||||
this.dropdownOptions.removeObject(selection);
|
||||
this.selectedOptions = addToArray(this.selectedOptions, selection);
|
||||
this.dropdownOptions = removeFromArray(this.dropdownOptions, selection);
|
||||
}
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { action } from '@ember/object';
|
||||
import { set } from '@ember/object';
|
||||
import { next } from '@ember/runloop';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
/**
|
||||
* @module StringList
|
||||
@@ -33,6 +35,7 @@ export default class StringList extends Component {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
// inputList is type ArrayProxy, so addObject etc are fine here
|
||||
this.inputList = ArrayProxy.create({
|
||||
// trim the `value` when accessing objects
|
||||
content: [],
|
||||
@@ -90,9 +93,11 @@ export default class StringList extends Component {
|
||||
@action
|
||||
inputChanged(idx, event) {
|
||||
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);
|
||||
set(inputObj, 'value', event.target.value);
|
||||
@@ -109,8 +114,8 @@ export default class StringList extends Component {
|
||||
|
||||
@action
|
||||
removeInput(idx) {
|
||||
const inputs = this.inputList;
|
||||
inputs.removeObject(inputs.objectAt(idx));
|
||||
const itemToRemove = this.inputList.objectAt(idx);
|
||||
this.inputList.removeObject(itemToRemove);
|
||||
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 {
|
||||
const message = `Successfully deleted role ${model.name}`;
|
||||
await model.destroyRecord();
|
||||
this.args.roles.removeObject(model);
|
||||
this.flashMessages.success(message);
|
||||
} catch (error) {
|
||||
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 PkiConfigUrlsModel from 'vault/models/pki/config/urls';
|
||||
import type { FormField, TtlEvent } from 'vault/app-types';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
interface Args {
|
||||
acme: PkiConfigAcmeModel;
|
||||
@@ -76,7 +77,7 @@ export default class PkiConfigurationEditComponent extends Component<Args> {
|
||||
message: errorMessage(error),
|
||||
};
|
||||
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 FlashMessageService from 'vault/services/flash-messages';
|
||||
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 {
|
||||
model: PkiIssuerModel;
|
||||
@@ -36,8 +38,11 @@ export default class PkiIssuerEditComponent extends Component<Args> {
|
||||
|
||||
@action
|
||||
setUsage(value: string) {
|
||||
const method = this.usageValues.includes(value) ? 'removeObject' : 'addObject';
|
||||
this.usageValues[method](value);
|
||||
if (this.usageValues.includes(value)) {
|
||||
this.usageValues = removeFromArray(this.usageValues, value);
|
||||
} else {
|
||||
this.usageValues = addToArray(this.usageValues, value);
|
||||
}
|
||||
this.args.model.usage = this.usageValues.join(',');
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { tracked } from '@glimmer/tracking';
|
||||
import errorMessage from 'vault/utils/error-message';
|
||||
import { waitFor } from '@ember/test-waiters';
|
||||
import { parseCertificate } from 'vault/utils/parse-pki-cert';
|
||||
import { addToArray } from 'vault/helpers/add-to-array';
|
||||
/**
|
||||
* @module PkiIssuerCrossSign
|
||||
* 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
|
||||
this.intermediateIssuers[intermediateMount] = issuers;
|
||||
this.validationErrors.addObject({
|
||||
this.validationErrors = addToArray(this.validationErrors, {
|
||||
newCrossSignedIssuer: this.nameValidation(newCrossSignedIssuer, issuers),
|
||||
});
|
||||
}
|
||||
@@ -109,9 +110,9 @@ export default class PkiIssuerCrossSign extends Component {
|
||||
intermediateIssuer,
|
||||
newCrossSignedIssuer
|
||||
);
|
||||
this.signedIssuers.addObject({ ...data, hasError: false });
|
||||
this.signedIssuers = addToArray(this.signedIssuers, { ...data, hasError: false });
|
||||
} catch (error) {
|
||||
this.signedIssuers.addObject({
|
||||
this.signedIssuers = addToArray(this.signedIssuers, {
|
||||
...this.formData[row],
|
||||
hasError: errorMessage(error),
|
||||
hasUnsupportedParams: error.cause ? error.cause.map((e) => e.message).join(', ') : null,
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function (server) {
|
||||
let records = [];
|
||||
if (isMethod) {
|
||||
methods.forEach((method) => {
|
||||
records.addObjects(schema.db[dbKeyFromType(method)].where({}));
|
||||
records = [...records, ...schema.db[dbKeyFromType(method)].where({})];
|
||||
});
|
||||
} else {
|
||||
records = schema.db.mfaLoginEnforcements.where({});
|
||||
|
||||
@@ -21,7 +21,7 @@ module('Acceptance | mfa-method', function (hooks) {
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.getMethods = () =>
|
||||
['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 authPage.login();
|
||||
|
||||
@@ -51,9 +51,9 @@ module('Integration | Component | auth form', function (hooks) {
|
||||
assert.expect(2);
|
||||
this.set('cluster', EmberObject.create({ standby: true }));
|
||||
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);
|
||||
this.owner.lookup('service:csp-event').events.addObject({ violatedDirective: 'connect-src' });
|
||||
this.owner.lookup('service:csp-event').handleEvent({ violatedDirective: 'connect-src' });
|
||||
await settled();
|
||||
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('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(() => {
|
||||
assert.strictEqual(component.errorText, 'Error Authentication failed: Not allowed');
|
||||
server.shutdown();
|
||||
@@ -86,17 +86,20 @@ module('Integration | Component | auth form', function (hooks) {
|
||||
assert.expect(1);
|
||||
const server = new Pretender(function () {
|
||||
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.set('cluster', EmberObject.create({}));
|
||||
this.set('selectedAuth', 'token');
|
||||
await render(hbs`{{auth-form 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.
|
||||
await render(hbs`<AuthForm @cluster={{this.cluster}} @selectedAuth={{this.selectedAuth}} />`);
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -134,7 +137,7 @@ module('Integration | Component | auth form', function (hooks) {
|
||||
});
|
||||
|
||||
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.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({}));
|
||||
await render(hbs`{{auth-form cluster=this.cluster }}`);
|
||||
await render(hbs`<AuthForm @cluster={{this.cluster}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
component.descriptionText,
|
||||
@@ -183,7 +186,7 @@ module('Integration | Component | auth form', function (hooks) {
|
||||
|
||||
this.set('cluster', EmberObject.create({}));
|
||||
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 settled();
|
||||
@@ -267,7 +270,7 @@ module('Integration | Component | auth form', function (hooks) {
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
await settled();
|
||||
|
||||
@@ -147,7 +147,7 @@ module('Integration | Component | ldap | Page::Library::CreateAndEdit', function
|
||||
|
||||
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-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) {
|
||||
this.model.name = 'foo';
|
||||
const [method] = await this.store.query('mfa-method', {});
|
||||
this.model.mfa_methods.addObject(method);
|
||||
this.model.auth_method_accessors.addObject('auth_userpass_1234');
|
||||
this.model.mfa_methods = [method];
|
||||
this.model.auth_method_accessors = ['auth_userpass_1234'];
|
||||
|
||||
await render(hbs`
|
||||
<Mfa::MfaLoginEnforcementForm
|
||||
@@ -207,12 +207,12 @@ module('Integration | Component | mfa-login-enforcement-form', function (hooks)
|
||||
keys: ['1234'],
|
||||
},
|
||||
}));
|
||||
this.model.auth_method_accessors.addObject('auth_userpass_1234');
|
||||
this.model.auth_method_types.addObject('userpass');
|
||||
this.model.auth_method_accessors = ['auth_userpass_1234'];
|
||||
this.model.auth_method_types = ['userpass'];
|
||||
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', {});
|
||||
this.model.identity_groups.addObject(group);
|
||||
this.model.identity_groups = [group];
|
||||
|
||||
await render(hbs`
|
||||
<Mfa::MfaLoginEnforcementForm
|
||||
|
||||
@@ -159,6 +159,7 @@ module('Integration | Component | path filter config list', function (hooks) {
|
||||
await clickTrigger();
|
||||
await searchSelect.deleteButtons.objectAt(1).click();
|
||||
await clickTrigger();
|
||||
await typeInSearch('ns1');
|
||||
assert.dom('.ember-power-select-group').hasText('Namespaces ns1', 'puts ns back within group');
|
||||
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) {
|
||||
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(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) {
|
||||
let result;
|
||||
try {
|
||||
result = addToArray(['not-array', 'string']);
|
||||
result = addToArray('not-array', 'string');
|
||||
} catch (e) {
|
||||
result = e.message;
|
||||
}
|
||||
@@ -29,13 +29,13 @@ module('Integration | Helper | add-to-array', function (hooks) {
|
||||
|
||||
test('it works with non-string arrays', function (assert) {
|
||||
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');
|
||||
});
|
||||
|
||||
test('it de-dupes the result', function (assert) {
|
||||
const ARRAY = ['horse', 'cow', 'chicken'];
|
||||
const result = addToArray([ARRAY, 'horse']);
|
||||
const result = addToArray(ARRAY, 'horse');
|
||||
assert.deepEqual(result, ['horse', 'cow', 'chicken']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,28 +5,28 @@
|
||||
|
||||
import { module, test } from '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) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it correctly removes a value from an array without mutating the original', function (assert) {
|
||||
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(ARRAY, ['horse', 'cow', 'chicken'], 'original array is not mutated');
|
||||
});
|
||||
|
||||
test('it returns the same value if the item is not found', function (assert) {
|
||||
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');
|
||||
});
|
||||
|
||||
test('it fails if the first value is not an array', function (assert) {
|
||||
let result;
|
||||
try {
|
||||
result = removeFromArray(['not-array', 'string']);
|
||||
result = removeFromArray('not-array', 'string');
|
||||
} catch (e) {
|
||||
result = e.message;
|
||||
}
|
||||
@@ -35,15 +35,23 @@ module('Integration | Helper | remove-from-array', function (hooks) {
|
||||
|
||||
test('it works with non-string arrays', function (assert) {
|
||||
const ARRAY = ['five', 6, '7'];
|
||||
const result1 = removeFromArray([ARRAY, 6]);
|
||||
const result2 = removeFromArray([ARRAY, 7]);
|
||||
const result1 = removeFromArray(ARRAY, 6);
|
||||
const result2 = removeFromArray(ARRAY, 7);
|
||||
assert.deepEqual(result1, ['five', '7'], 'removed number value');
|
||||
assert.deepEqual(result2, ARRAY, 'did not match on different types');
|
||||
});
|
||||
|
||||
test('it de-dupes the result', function (assert) {
|
||||
const ARRAY = ['horse', 'cow', 'chicken', 'cow'];
|
||||
const result = removeFromArray([ARRAY, 'horse']);
|
||||
const result = removeFromArray(ARRAY, 'horse');
|
||||
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