Update ui dependencies (#7244)

* be more specific about node version, and specify a yarn version

* update ember, ember-cli, ember-data, ember-data-model-fragments

* use router handlers to access transition information

* fix shadowing of component helper

* update ivy-codemirror, ember-cli-inject-live-reload

* remove custom router service

* don't use transition.queryParams

* update ember-cli-deprecation-workflow

* refactor kv v1 to use 'path' instead of 'id' on creation

* fix auth-jwt-test and toolbar-link-test

* update ember composable helpers

* remove Ember.copy from test file

* no more deprecations in the workflow

* fix more secret tests

* fix remaining failed tests

* move select component to core because it's used by ttl-picker

* generate new model class for each test instead of reusing an existing one

* fix selectors on kmip tests

* refactor how control groups construct urls from the new transition objects

* add router service override back in, and have it be evented so that we can trigger router events on it

* move stories and markdown files to core if the component lives in core

* update ember-cli, ember-cli-babel, ember-auto-import

* update base64js, date-fns, deepmerge, codemirror, broccoli-asset-rev

* update linting rules

* fix test selectors

* update ember-api-actions, ember-concurrency, ember-load-initializers, escape-string-regexp, normalize.css, prettier-eslint-cli, jsdoc-to-markdown

* remove test-results dir

* update base64js, ember-cli-clipboard, ember-cli-sass, ember-cli-string-helpers, ember-cli-template-lint, ember-cli-uglify, ember-link-action

* fix linting

* run yarn install without restoring from cache

* refactor how tests are run and handle the vault server subprocess

* update makefile for new test task names

* update circle config to use the new yarn task

* fix writing the seal keys when starting the dev server

* remove optional deps from the lockfile

* don't ignore-optional on yarn install

* remove errant console.log

* update ember-basic-dropdown-hover, jsonlint, yargs-parser

* update ember-cli-flash

* add back optionalDeps

* update @babel/core@7.5.5, ember-basic-dropdown@1.1.3, eslint-plugin-ember@6.8.2

* update storybook to the latest release

* add a babel config with targets so that the ember babel plugin works properly

* update ember-resolver, move ember-cli-storybook to devDependencies

* revert normalize.css upgrade

* silence fetchadapter warning for now

* exclude 3rd party array helper now that ember includes one

* fix switch and entity lookup styling

* only add -root suffix if it's not in versions mode

* make sure drop always has an array on the aws role form

* fix labels like we did with the backport

* update eslintignore

* update the yarn version in the docker build file

* update eslint ignore
This commit is contained in:
Matthew Irish 2019-08-19 15:45:39 -05:00 committed by GitHub
parent e4be09ead5
commit 4a1013e915
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
114 changed files with 5169 additions and 7207 deletions

4
.circleci/config.yml generated
View File

@ -130,7 +130,7 @@ jobs:
# Run Ember tests
cd ui
mkdir -p test-results/qunit
yarn run test-oss
yarn test:oss
name: Test UI
- store_artifacts:
path: ui/test-results
@ -561,7 +561,7 @@ workflows:
# # Run Ember tests
# cd ui
# mkdir -p test-results/qunit
# yarn run test-oss
# yarn test:oss
# name: Test UI
# - store_artifacts:
# path: ui/test-results

View File

@ -26,7 +26,7 @@ steps:
# Run Ember tests
cd ui
mkdir -p test-results/qunit
yarn run test-oss
yarn test:oss
- store_artifacts:
path: ui/test-results
- store_test_results:

View File

@ -142,9 +142,9 @@ static-assets:
test-ember:
@echo "--> Installing JavaScript assets"
@cd ui && yarn --ignore-optional
@cd ui && yarn
@echo "--> Running ember tests"
@cd ui && yarn run test-oss
@cd ui && yarn run test:oss
ember-ci-test: # Deprecated, to be removed soon.
@echo "ember-ci-test is deprecated in favour of test-ui-browserstack"
@ -161,13 +161,13 @@ check-browserstack-creds:
test-ui-browserstack: check-vault-in-path check-browserstack-creds
@echo "--> Installing JavaScript assets"
@cd ui && yarn --ignore-optional
@cd ui && yarn
@echo "--> Running ember tests in Browserstack"
@cd ui && yarn run test:browserstack
ember-dist:
@echo "--> Installing JavaScript assets"
@cd ui && yarn --ignore-optional
@cd ui && yarn
@cd ui && npm rebuild node-sass
@echo "--> Building Ember application"
@cd ui && yarn run build
@ -175,10 +175,10 @@ ember-dist:
ember-dist-dev:
@echo "--> Installing JavaScript assets"
@cd ui && yarn --ignore-optional
@cd ui && yarn
@cd ui && npm rebuild node-sass
@echo "--> Building Ember application"
@cd ui && yarn run build-dev
@cd ui && yarn run build:dev
static-dist: ember-dist static-assets
static-dist-dev: ember-dist-dev static-assets

View File

@ -16,7 +16,7 @@ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -y && apt-get install -y -q nodejs yarn=1.12.1-1
RUN apt-get update -y && apt-get install -y -q nodejs yarn=1.17.3
RUN rm -rf /var/lib/apt/lists/*

View File

@ -8,6 +8,8 @@
# dependencies
/bower_components/
/node_modules/
/.storybook/
/stories/
# misc

View File

@ -1,3 +1,4 @@
// env: node
module.exports = {
parser: 'babel-eslint',
root: true,

View File

@ -0,0 +1,26 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
shippedProposals: true,
useBuiltIns: 'usage',
corejs: '3',
targets: ['last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions'],
},
],
],
plugins: [
[
'@babel/plugin-proposal-decorators',
{
legacy: true,
},
],
['@babel/plugin-proposal-class-properties', { loose: true }],
'@babel/plugin-syntax-dynamic-import',
['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }],
'babel-plugin-macros',
['emotion', { sourceMap: true, autoLabel: true }],
],
};

View File

@ -1,7 +1,6 @@
import { configure, addParameters, addDecorator } from '@storybook/ember';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import theme from './theme.js';
import { assign } from '@ember/polyfills';
function loadStories() {
// automatically import all files ending in *.stories.js
@ -28,7 +27,7 @@ addDecorator(storyFn => {
// Create a div to wrap the Canvas tab with the applied styles.
const element = document.createElement('div');
assign(element.style, styles.style);
Object.assign(element.style, styles.style);
const innerElement = document.createElement('div');
const wormhole = document.createElement('div');

View File

@ -1,6 +1,8 @@
<meta name="vault/config/environment" content="%7B%22modulePrefix%22%3A%22vault%22%2C%22environment%22%3A%22development%22%2C%22rootURL%22%3A%22/ui/%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%7D%2C%22APP%22%3A%7B%22POLLING_URLS%22%3A%5B%22sys/health%22%2C%22sys/replication/status%22%2C%22sys/seal-status%22%5D%2C%22NAMESPACE_ROOT_URLS%22%3A%5B%22sys/health%22%2C%22sys/seal-status%22%2C%22sys/license/features%22%5D%2C%22DEFAULT_PAGE_SIZE%22%3A15%2C%22LOG_TRANSITIONS%22%3Atrue%7D%2C%22flashMessageDefaults%22%3A%7B%22timeout%22%3A7000%2C%22sticky%22%3Afalse%7D%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy%22%2C%22contentSecurityPolicyMeta%22%3Atrue%2C%22contentSecurityPolicy%22%3A%7B%22connect-src%22%3A%5B%22%27self%27%22%5D%2C%22img-src%22%3A%5B%22%27self%27%22%2C%22data%3A%22%5D%2C%22form-action%22%3A%5B%22%27none%27%22%5D%2C%22script-src%22%3A%5B%22%27self%27%22%5D%2C%22style-src%22%3A%5B%22%27unsafe-inline%27%22%2C%22%27self%27%22%5D%2C%22default-src%22%3A%5B%22%27none%27%22%5D%2C%22font-src%22%3A%5B%22%27self%27%22%5D%2C%22media-src%22%3A%5B%22%27self%27%22%5D%7D%2C%22emberData%22%3A%7B%22enableRecordDataRFCBuild%22%3Afalse%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
<meta name="vault/config/environment" content="%7B%22modulePrefix%22%3A%22vault%22%2C%22environment%22%3A%22development%22%2C%22rootURL%22%3A%22%2Fui%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_JQUERY_INTEGRATION%22%3Afalse%7D%2C%22APP%22%3A%7B%22POLLING_URLS%22%3A%5B%22sys%2Fhealth%22%2C%22sys%2Freplication%2Fstatus%22%2C%22sys%2Fseal-status%22%5D%2C%22NAMESPACE_ROOT_URLS%22%3A%5B%22sys%2Fhealth%22%2C%22sys%2Fseal-status%22%2C%22sys%2Flicense%2Ffeatures%22%5D%2C%22DEFAULT_PAGE_SIZE%22%3A15%2C%22LOG_TRANSITIONS%22%3Atrue%7D%2C%22flashMessageDefaults%22%3A%7B%22timeout%22%3A7000%2C%22sticky%22%3Afalse%7D%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy%22%2C%22contentSecurityPolicyMeta%22%3Atrue%2C%22contentSecurityPolicy%22%3A%7B%22connect-src%22%3A%5B%22'self'%22%5D%2C%22img-src%22%3A%5B%22'self'%22%2C%22data%3A%22%5D%2C%22form-action%22%3A%5B%22'none'%22%5D%2C%22script-src%22%3A%5B%22'self'%22%5D%2C%22style-src%22%3A%5B%22'unsafe-inline'%22%2C%22'self'%22%5D%2C%22default-src%22%3A%5B%22'none'%22%5D%2C%22font-src%22%3A%5B%22'self'%22%5D%2C%22media-src%22%3A%5B%22'self'%22%5D%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
<meta name="kmip/config/environment" content="%7B%22modulePrefix%22%3A%22kmip%22%2C%22environment%22%3A%22development%22%7D" />
<meta name="open-api-explorer/config/environment" content="%7B%22modulePrefix%22%3A%22open-api-explorer%22%2C%22environment%22%3A%22development%22%2C%22APP%22%3A%7B%22NAMESPACE_ROOT_URLS%22%3A%5B%22sys/health%22%2C%22sys/seal-status%22%2C%22sys/license/features%22%5D%7D%7D" />
<meta name="replication/config/environment" content="%7B%22modulePrefix%22%3A%22replication%22%2C%22environment%22%3A%22development%22%7D" />
<meta name="vault/config/asset-manifest" content="%7B%22bundles%22%3A%7B%22replication%22%3A%7B%22assets%22%3A%5B%7B%22uri%22%3A%22/ui/engines-dist/replication/assets/engine-vendor.js%22%2C%22type%22%3A%22js%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/replication/assets/engine.js%22%2C%22type%22%3A%22js%22%7D%5D%7D%7D%7D" />
<meta name="vault/config/asset-manifest" content="%7B%22bundles%22%3A%7B%22kmip%22%3A%7B%22assets%22%3A%5B%7B%22uri%22%3A%22/ui/engines-dist/kmip/assets/engine-vendor.js%22%2C%22type%22%3A%22js%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/kmip/assets/engine.js%22%2C%22type%22%3A%22js%22%7D%5D%7D%2C%22open-api-explorer%22%3A%7B%22assets%22%3A%5B%7B%22uri%22%3A%22/ui/engines-dist/open-api-explorer/assets/engine-vendor.css%22%2C%22type%22%3A%22css%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/open-api-explorer/assets/engine-vendor.js%22%2C%22type%22%3A%22js%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/open-api-explorer/assets/engine.css%22%2C%22type%22%3A%22css%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/open-api-explorer/assets/engine.js%22%2C%22type%22%3A%22js%22%7D%5D%7D%2C%22replication%22%3A%7B%22assets%22%3A%5B%7B%22uri%22%3A%22/ui/engines-dist/replication/assets/engine-vendor.js%22%2C%22type%22%3A%22js%22%7D%2C%7B%22uri%22%3A%22/ui/engines-dist/replication/assets/engine.js%22%2C%22type%22%3A%22js%22%7D%5D%7D%7D%7D" />
<link rel="stylesheet" href="/assets/vendor.css" />
<link rel="stylesheet" href="/assets/vault.css" />
<link rel="icon" href="/favicon.png" />

View File

@ -9,8 +9,11 @@ export default ApplicationAdapter.extend({
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const { id } = snapshot;
return this.ajax(this.urlForSecret(snapshot.attr('backend'), id), 'POST', { data });
const path = snapshot.record.path;
return this.ajax(this.urlForSecret(snapshot.attr('backend'), path || id), 'POST', { data }).then(() => {
data.id = path || id;
return data;
});
},
createRecord() {

View File

@ -158,22 +158,18 @@ export default Component.extend(FocusOnInsertMixin, WithNavToNearestAncestor, {
return this.secretDataIsAdvanced || this.preferAdvancedEdit;
}),
isWriteWithoutRead: computed(
'model.{failedServerRead,selectedVersion.failedServerRead}',
'isV2',
function() {
if (!this.model) return;
// if the version couldn't be read from the server
if (this.isV2 && this.model.selectedVersion.failedServerRead) {
return true;
}
// if the model couldn't be read from the server
if (!this.isV2 && this.model.failedServerRead) {
return true;
}
return false;
isWriteWithoutRead: computed('model.failedServerRead', 'modelForData.failedServerRead', 'isV2', function() {
if (!this.model) return;
// if the version couldn't be read from the server
if (this.isV2 && this.modelForData.failedServerRead) {
return true;
}
),
// if the model couldn't be read from the server
if (!this.isV2 && this.model.failedServerRead) {
return true;
}
return false;
}),
transitionToRoute() {
return this.router.transitionTo(...arguments);
@ -307,12 +303,12 @@ export default Component.extend(FocusOnInsertMixin, WithNavToNearestAncestor, {
let model = this.modelForData;
// prevent from submitting if there's no key
// maybe do something fancier later
if (type === 'create' && isBlank(model.get('path') || model.id)) {
if (type === 'create' && isBlank(model.path || model.id)) {
return;
}
this.persistKey(() => {
this.transitionToRoute(SHOW_ROUTE, this.model.id);
this.transitionToRoute(SHOW_ROUTE, this.model.path || this.model.id);
});
},

View File

@ -6,7 +6,7 @@ export function linkParams({ mode, secret, queryParams }) {
let params;
const route = `vault.cluster.secrets.backend.${mode}`;
if (!secret || secret === ' ') {
if ((mode !== 'versions' && !secret) || secret === ' ') {
params = [route + '-root'];
} else {
params = [route, encodePath(secret)];

View File

@ -14,10 +14,10 @@ export default Helper.extend({
if (interval) {
/*
* NOTE: intentionally a setTimeout so tests do not block on it
* as the run loop queue is never clear so tests will stay locked waiting
* for queue to clear.
*/
* NOTE: intentionally a setTimeout so tests do not block on it
* as the run loop queue is never clear so tests will stay locked waiting
* for queue to clear.
*/
this.intervalTimer = setTimeout(() => {
run(() => this.recompute());
}, parseInt(interval, 10));

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html lang="en">
<html>
<head>
<meta charset="utf-8">

View File

@ -5,17 +5,17 @@ import utils from 'vault/lib/key-utils';
export default Mixin.create({
// what attribute has the path for the key
// will.be 'path' for v2 or 'id' v1
pathAttr: 'id',
pathAttr: 'path',
flags: null,
initialParentKey: null,
isCreating: computed('initialParentKey', function() {
return this.get('initialParentKey') != null;
return this.initialParentKey != null;
}),
pathVal() {
return this.get(this.pathAttr);
return this[this.pathAttr] || this.id;
},
// rather than using defineProperty for all of these,

View File

@ -1,4 +1,5 @@
import Mixin from '@ember/object/mixin';
import removeRecord from 'vault/utils/remove-record';
// removes Ember Data records from the cache when the model
// changes or you move away from the current route
@ -10,7 +11,7 @@ export default Mixin.create({
if (!model || !model.unloadRecord) {
return;
}
this.store.unloadRecord(model);
removeRecord(this.store, model);
model.destroy();
// it's important to unset the model on the controller since controllers are singletons
this.controller.set(modelPath, null);

View File

@ -5,6 +5,7 @@ import { bool } from '@ember/object/computed';
const { attr, belongsTo } = DS;
export default Secret.extend({
failedServerRead: attr('boolean'),
pathAttr: 'path',
version: attr('number'),
secret: belongsTo('secret-v2'),

View File

@ -8,6 +8,7 @@ import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
const { attr, hasMany, belongsTo, Model } = DS;
export default Model.extend(KeyMixin, {
failedServerRead: attr('boolean'),
engine: belongsTo('secret-engine', { async: false }),
engineId: attr('string'),
versions: hasMany('secret-v2-version', { async: false, inverse: null }),

View File

@ -6,6 +6,7 @@ const { attr } = DS;
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
export default DS.Model.extend(KeyMixin, {
failedServerRead: attr('boolean'),
auth: attr('string'),
lease_duration: attr('number'),
lease_id: attr('string'),

View File

@ -23,6 +23,7 @@ export default Route.extend({
}
let router = this.get('routing');
//FIXME transition.intent likely needs to be replaced
let errorURL = transition.intent.url;
let { name, contexts, queryParams } = transition.intent;

View File

@ -1,8 +1,16 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
router: service(),
init() {
this._super(...arguments);
this.router.on('routeWillChange', transition => {
this.set('myTargetRouteName', transition.to.name);
});
},
renderTemplate() {
let { targetName } = this._router.currentState.routerJs.activeTransition;
let targetName = this.myTargetRouteName;
let isCallback =
targetName === 'vault.cluster.oidc-callback' || targetName === 'vault.cluster.oidc-callback-namespace';
if (isCallback) {

View File

@ -6,8 +6,9 @@ let secretModel = (store, backend, key) => {
let backendModel = store.peekRecord('secret-engine', backend);
let modelType = backendModel.get('modelTypeForKV');
if (modelType !== 'secret-v2') {
let model = store.createRecord(modelType);
model.set('id', key);
let model = store.createRecord(modelType, {
path: key,
});
return model;
}
let secret = store.createRecord(modelType);
@ -33,7 +34,8 @@ export default EditBase.extend({
}
return this.store.createRecord(modelType);
}
return secretModel(this.store, backend, transition.queryParams.initialKey);
return secretModel(this.store, backend, transition.to.queryParams.initialKey);
},
model(params, transition) {

View File

@ -127,9 +127,12 @@ export default Route.extend(UnloadModelRoute, {
try {
if (secretModel.failedServerRead) {
// we couldn't read metadata, so we want to directly fetch the version
versionModel = await this.store.findRecord('secret-v2-version', JSON.stringify(versionId), {
reload: true,
});
versionModel =
this.store.peekRecord('secret-v2-version', JSON.stringify(versionId)) ||
(await this.store.findRecord('secret-v2-version', JSON.stringify(versionId), {
reload: true,
}));
} else {
// we may have previously errored, so roll it back here
version.rollbackAttributes();
@ -142,18 +145,20 @@ export default Route.extend(UnloadModelRoute, {
if (error.httpStatus === 403 && capabilities.get('canUpdate')) {
// versionModel is then a partial model from the metadata (if we have read there), or
// we need to create one on the client
versionModel = version || this.store.createRecord('secret-v2-version');
versionModel.setProperties({
failedServerRead: true,
});
// if it was created on the client we need to trigger an event via ember-data
// so that it won't try to create the record on save
if (versionModel.isNew) {
versionModel.set('id', JSON.stringify(versionId));
//TODO make this a util to better show what's happening
// this is because we want the ember-data model save to call update instead of create
// in the adapter so we have to force the frontend model to a "saved" state
versionModel.send('pushedData');
if (version) {
version.set('failedServerRead', true);
versionModel = version;
} else {
this.store.push({
data: {
type: 'secret-v2-version',
id: JSON.stringify(versionId),
attributes: {
failedServerRead: true,
},
},
});
versionModel = this.store.peekRecord('secret-v2-version', JSON.stringify(versionId));
}
} else {
throw error;
@ -162,18 +167,23 @@ export default Route.extend(UnloadModelRoute, {
return versionModel;
},
handleSecretModelError(capabilities, secret, modelType, error) {
handleSecretModelError(capabilities, secretId, modelType, error) {
// can't read the path and don't have update capability, so re-throw
if (!capabilities.get('canUpdate') && modelType === 'secret') {
throw error;
}
// don't have access to the metadata for v2 or the secret for v1,
// so we make a stub model and mark it as `failedServerRead`
let secretModel = this.store.createRecord(modelType);
secretModel.setProperties({
id: secret,
failedServerRead: true,
this.store.push({
data: {
id: secretId,
type: modelType,
attributes: {
failedServerRead: true,
},
},
});
let secretModel = this.store.peekRecord(modelType, secretId);
return secretModel;
},

View File

@ -4,7 +4,12 @@ import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
secretDataPath: 'data',
normalizeItems(payload, requestType) {
if (requestType !== 'queryRecord' && payload.data.keys && Array.isArray(payload.data.keys)) {
if (
requestType !== 'queryRecord' &&
payload.data &&
payload.data.keys &&
Array.isArray(payload.data.keys)
) {
// if we have data.keys, it's a list of ids, so we map over that
// and create objects with id's
return payload.data.keys.map(secret => {

View File

@ -95,17 +95,29 @@ export default Service.extend({
return RSVP.reject(error);
},
urlFromTransition(transition) {
let routes = Object.keys(transition.params);
let params = [];
for (let route of routes) {
let param = transition.params[route];
if (Object.keys(param).length) {
params.push(param);
paramsFromTransition(transitionTo, params, queryParams) {
let returnedParams = params.slice();
let qps = queryParams;
transitionTo.paramNames.map(name => {
let param = transitionTo.params[name];
if (param.length) {
// push on to the front of the array since were're started at the end
returnedParams.unshift(param);
}
});
qps = { ...queryParams, ...transitionTo.queryParams };
// if there's a parent transition, recurse to get its route params
if (transitionTo.parent) {
[returnedParams, qps] = this.paramsFromTransition(transitionTo.parent, returnedParams, qps);
}
let url = this.get('router').urlFor(transition.targetName, ...params, {
queryParams: transition.queryParams,
return [returnedParams, qps];
},
urlFromTransition(transitionObj) {
let transition = transitionObj.to;
let [params, queryParams] = this.paramsFromTransition(transition, [], {});
let url = this.get('router').urlFor(transition.name, ...params, {
queryParams,
});
return url.replace('/ui', '');
},

View File

@ -144,7 +144,8 @@ export default Service.extend({
return pathName.includes(k) || pathName.includes(k.replace(/\/$/, ''));
});
const hasMatchingPath =
(matchingPath && !this.isDenied(globPaths[matchingPath])) || globPaths.hasOwnProperty('');
(matchingPath && !this.isDenied(globPaths[matchingPath])) ||
Object.prototype.hasOwnProperty.call(globPaths, '');
if (matchingPath && capability) {
return this.hasCapability(globPaths[matchingPath], capability) && hasMatchingPath;

View File

@ -1,12 +1,19 @@
import Evented from '@ember/object/evented';
import Service from '@ember/service';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
let hasOwn = (obj, prop) => {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
export function extractRouteArgs(args) {
args = args.slice();
let possibleQueryParams = args[args.length - 1];
let queryParams;
if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) {
if (possibleQueryParams && hasOwn(possibleQueryParams, 'queryParams')) {
queryParams = args.pop().queryParams;
} else {
queryParams = {};
@ -22,7 +29,7 @@ export function shallowEqual(a, b) {
let aCount = 0;
let bCount = 0;
for (k in a) {
if (a.hasOwnProperty(k)) {
if (hasOwn(a, k)) {
if (a[k] !== b[k]) {
return false;
}
@ -31,7 +38,7 @@ export function shallowEqual(a, b) {
}
for (k in b) {
if (b.hasOwnProperty(k)) {
if (hasOwn(b, k)) {
bCount++;
}
}
@ -39,31 +46,43 @@ export function shallowEqual(a, b) {
return aCount === bCount;
}
export default Service.extend({
export default Service.extend(Evented, {
init() {
this._super(...arguments);
this._router.on('routeWillChange', transition => {
this.trigger('routeWillChange', transition);
});
this._router.on('routeDidChange', transition => {
this.trigger('routeDidChange', transition);
});
},
routing: service('-routing'),
router: alias('routing.router'),
_router: alias('routing.router'),
transitionTo() {
let r = this.router;
let r = this._router;
return r.transitionTo.call(r, ...arguments);
},
replaceWith() {
let r = this.router;
let r = this._router;
return r.replaceWith.call(r, ...arguments);
},
urlFor() {
let r = this.router;
let r = this._router;
return r.generate.call(r, ...arguments);
},
currentURL: alias('router.currentURL'),
currentRouteName: alias('router.currentRouteName'),
rootURL: alias('router.rootURL'),
location: alias('router.location'),
currentURL: alias('_router.currentURL'),
currentRouteName: alias('_router.currentRouteName'),
rootURL: alias('_router.rootURL'),
location: alias('_router.location'),
//adapted from:
// https://github.com/emberjs/ember.js/blob/abf753a3d494830dc9e95b1337b3654b671b11be/packages/ember-routing/lib/services/router.js#L220
isActive(...args) {
let { routeName, models, queryParams } = extractRouteArgs(args);
let routerMicrolib = this.router._routerMicrolib;
let routerMicrolib = this._router._routerMicrolib;
if (!routerMicrolib.isActiveIntent(routeName, models, null)) {
return false;
@ -71,7 +90,7 @@ export default Service.extend({
let hasQueryParams = Object.keys(queryParams).length > 0;
if (hasQueryParams) {
this.router._prepareQueryParams(routeName, models, queryParams, true /* fromRouterService */);
this._router._prepareQueryParams(routeName, models, queryParams, true /* fromRouterService */);
return shallowEqual(queryParams, routerMicrolib.state.queryParams);
}

View File

@ -24,11 +24,11 @@
.select {
min-width: 190px;
}
}
label[for='namespace'] {
padding: $spacing-xs;
color: $grey;
}
.toolbar-label {
padding: $spacing-xs;
color: $grey;
}
.toolbar-scroller {

View File

@ -1,3 +1,6 @@
form {
margin: 0;
}
label {
cursor: pointer;
&.is-select-list {

View File

@ -9,7 +9,7 @@
Multiple credential types is deprecated and you must choose one in order to save this role."
/>
{{/if}}
{{#each (if (eq mode 'edit') (drop 1 model.fields) model.fields) as |attr|}}
{{#each (if (eq mode 'edit') (drop 1 (or model.fields (array))) model.fields) as |attr|}}
{{form-field data-test-field attr=attr model=model}}
{{/each}}
</div>

View File

@ -91,7 +91,7 @@
{{/if}}
<div class="global-flash">
{{#each flashMessages.queue as |flash|}}
{{#flash-message data-test-flash-message=true flash=flash as |component flash close|}}
{{#flash-message data-test-flash-message=true flash=flash as |customComponent flash close|}}
{{#if flash.componentName}}
{{component flash.componentName content=flash.content}}
{{else}}

View File

@ -0,0 +1,30 @@
// Unlinks a record from all its relationships and unloads it from
// the store.
export default function removeRecord(store, record) {
let id = record.path || record.id;
if (id) {
// Collect relationship property names and types
const relationshipMeta = [];
record.eachRelationship((key, { kind }) => {
relationshipMeta.push({ key, kind });
});
// Push an update to this record with the relationships nulled out.
// This unlinks the relationship from the models that aren't about to
// be unloaded.
store.push({
data: {
id,
type: record.constructor.modelName,
relationships: relationshipMeta.reduce((hash, rel) => {
hash[rel.key] = { data: rel.kind === 'hasMany' ? [] : null };
return hash;
}, {}),
},
});
}
// Now that the record has no attachments, it can be safely unloaded
// from the store.
store.unloadRecord(record);
}

View File

@ -1,11 +1,11 @@
/* global self */
self.deprecationWorkflow = self.deprecationWorkflow || {};
//self.deprecationWorkflow.config = {
//throwOnUnhandled: true
//}
self.deprecationWorkflow.config = {
workflow: [
// ivy-codemirror and ember-radio-button still use send-action
{ handler: 'silence', matchId: 'ember-component.send-action' },
{ handler: 'silence', matchId: 'ember-runtime.deprecate-copy-copyable' },
// ember-cli-page-object uses jquery's this.$() by default - this will change when we remove jquery
{ handler: 'silence', matchId: 'ember-test-helpers.rendering-context.jquery-element' },
// after ED 3.9 this shouldn't be necessary
{ handler: 'silence', matchId: 'deprecate-fetch-ember-data-support' },
],
};

View File

@ -23,13 +23,12 @@ module.exports = function(defaults) {
return `${config.rootURL.replace(/\/$/, '')}${filePath}`;
},
},
codemirror: {
modes: ['javascript', 'ruby'],
keyMaps: ['sublime'],
},
babel: {
plugins: ['transform-object-rest-spread'],
plugins: ['@babel/plugin-proposal-object-rest-spread'],
},
'ember-cli-babel': {
includePolyfill: isTest || isProd || isCI,
@ -50,12 +49,7 @@ module.exports = function(defaults) {
browsers: ['defaults', 'ie 11'],
},
autoImport: {
webpack: {
// this makes `unsafe-eval` CSP unnecessary
// see https://github.com/ef4/ember-auto-import/issues/50
// and https://github.com/webpack/webpack/issues/5627
devtool: 'inline-source-map',
},
forbidEval: true,
},
'ember-test-selectors': {
strip: isProd,
@ -64,6 +58,9 @@ module.exports = function(defaults) {
'ember-fetch': {
preferNative: true,
},
'ember-composable-helpers': {
except: ['array'],
},
});
app.import('vendor/string-includes.js');
@ -74,7 +71,7 @@ module.exports = function(defaults) {
app.import('node_modules/codemirror/addon/lint/lint.css');
app.import('node_modules/codemirror/addon/lint/lint.js');
app.import('node_modules/codemirror/addon/lint/json-lint.js');
app.import('node_modules/text-encoder-lite/index.js');
app.import('node_modules/text-encoder-lite/text-encoder-lite.js');
app.import('app/styles/bulma/bulma-radio-checkbox.css');

View File

@ -1,4 +1,5 @@
import Component from '@ember/component';
import layout from '../templates/components/select';
/**
* @module Select
@ -21,6 +22,7 @@ import Component from '@ember/component';
*/
export default Component.extend({
layout,
classNames: ['field'],
label: null,
selectedValue: null,

View File

@ -41,29 +41,29 @@ export default Component.extend({
}),
/*
*
* @public
* @param String - ['array'|'string]
*
* Optional type for `inputValue` - defaults to `'array'`
* Needs to match type of `inputValue` because it is set by the component on init.
*
*/
*
* @public
* @param String - ['array'|'string]
*
* Optional type for `inputValue` - defaults to `'array'`
* Needs to match type of `inputValue` because it is set by the component on init.
*
*/
type: 'array',
/*
*
* @private
* @param Ember.ArrayProxy
*
* mutable array that contains objects in the form of
* {
* value: 'somestring',
* }
*
* used to track the state of values bound to the various inputs
*
*/
*
* @private
* @param Ember.ArrayProxy
*
* mutable array that contains objects in the form of
* {
* value: 'somestring',
* }
*
* used to track the state of values bound to the various inputs
*
*/
/* eslint-disable ember/no-side-effects */
inputList: computed(function() {
return ArrayProxy.create({

View File

@ -0,0 +1 @@
export { default } from 'core/components/select';

View File

@ -1,9 +1,7 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './alert-banner.md';
import { MESSAGE_TYPES } from '../lib/core/addon/helpers/message-types.js';
import { MESSAGE_TYPES } from '../addon/helpers/message-types.js';
storiesOf('Alerts/AlertBanner/', module)
.addParameters({ options: { showPanel: false } })

View File

@ -1,8 +1,7 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './alert-inline.md';
import { MESSAGE_TYPES } from '../lib/core/addon/helpers/message-types.js';
import { MESSAGE_TYPES } from '../addon/helpers/message-types.js';
storiesOf('Alerts/AlertInline/', module)
.addParameters({ options: { showPanel: false } })

View File

@ -1,21 +1,21 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
import notes from './chevron.md';
storiesOf('Chevron/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`Chevron`, () => ({
template: hbs`
.add(
`Chevron`,
() => ({
template: hbs`
<h5 class="title is-5">Chevron</h5>
<Chevron @direction={{direction}} />
`,
context: {
direction: select('Direction', ['right', 'down', 'left', 'up'], 'right'),
},
}),
{notes}
);
context: {
direction: select('Direction', ['right', 'down', 'left', 'up'], 'right'),
},
}),
{ notes }
);

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, text, boolean } from '@storybook/addon-knobs';
@ -12,7 +11,8 @@ storiesOf('ConfirmAction/', module)
})
)
.add(
`ConfirmAction`, () => ({
`ConfirmAction`,
() => ({
template: hbs`
<h5 class="title is-5">Confirm Action</h5>
<ConfirmAction

View File

@ -1,16 +1,16 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './doc-link.md';
storiesOf('DocLink/', module)
.addParameters({ options: { showPanel: true } })
.add(`DocLink`, () => ({
template: hbs`
.add(
`DocLink`,
() => ({
template: hbs`
<h5 class="title is-5">Doc Link</h5>
<DocLink @path="/docs/secrets/kv/kv-v2.html">Learn about KV v2</DocLink>
`
}),
{notes}
);
`,
}),
{ notes }
);

View File

@ -0,0 +1,44 @@
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, text } from '@storybook/addon-knobs';
import notes from './empty-state.md';
storiesOf('EmptyState/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs({ escapeHTML: false }))
.add(
`EmptyState`,
() => ({
template: hbs`
<h5 class="title is-5">Empty State</h5>
<EmptyState @title={{title}} @message={{message}} />
`,
context: {
title: text('Title', "You don't have an secrets yet"),
message: text(
'Message',
"An explanation of why you don't have any secrets but also you maybe want to create one."
),
},
}),
{ notes }
)
.add(
`EmptyState with content block`,
() => ({
template: hbs`
<h5 class="title is-5">Empty State</h5>
<EmptyState @title={{title}} @message={{message}}>
<DocLink @path="/docs/secrets/kv/kv-v2.html">Learn about KV v2</DocLink>
</EmptyState>
`,
context: {
title: text('Title', "You don't have an secrets yet"),
message: text(
'Message',
"An explanation of why you don't have any secrets but also you maybe want to create one."
),
},
}),
{ notes }
);

View File

@ -1,8 +1,8 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
import notes from './form-field-groups.md';
import { getOwner } from '@ember/application';
// This will need to be replaced with a fake model, since the form fields associated with
// each model come from OpenApi and Storybook doesn't have a Vault server to call OpenApi from.
@ -37,7 +37,7 @@ storiesOf('Form/FormFieldGroups/', module)
context: {
actions: {
getModel(modelType) {
return Ember.getOwner(this)
return getOwner(this)
.lookup('service:store')
.createRecord(`auth-config/${modelType}`);
},

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './form-field.md';

View File

@ -1,12 +1,11 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './icon.md';
import icons from '../node_modules/@hashicorp/structure-icons/dist/index.js';
import icons from '../../../node_modules/@hashicorp/structure-icons/dist/index.js';
import { withKnobs, select } from '@storybook/addon-knobs';
storiesOf('Icon/', module)
.addParameters({ options: { showPanel: true} })
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(
'Icon',

View File

@ -1,36 +1,38 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
import notes from './info-table-row.md';
storiesOf('InfoTableRow/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs({escapeHTML: false}))
.add(`InfoTableRow with text value`, () => ({
template: hbs`
.addDecorator(withKnobs({ escapeHTML: false }))
.add(
`InfoTableRow with text value`,
() => ({
template: hbs`
<h5 class="title is-5">Info Table Row</h5>
<InfoTableRow @value={{value}} @label={{label}} @alwaysRender={{alwaysRender}} />
`,
context: {
label: text('Label', 'TTL'),
value: text('Value', '30m'),
alwaysRender: boolean('Always render?', false),
},
}),
{notes}
context: {
label: text('Label', 'TTL'),
value: text('Value', '30m'),
alwaysRender: boolean('Always render?', false),
},
}),
{ notes }
)
.add(`InfoTableRow with boolean value`, () => ({
template: hbs`
.add(
`InfoTableRow with boolean value`,
() => ({
template: hbs`
<h5 class="title is-5">Info Table Row</h5>
<InfoTableRow @value={{value}} @label={{label}} @alwaysRender={{alwaysRender}} />
`,
context: {
label: 'Local mount?',
value: boolean('Value', true),
alwaysRender: boolean('Always render?', true),
},
}),
{notes}
);
context: {
label: 'Local mount?',
value: boolean('Value', true),
alwaysRender: boolean('Always render?', true),
},
}),
{ notes }
);

View File

@ -1,16 +1,17 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './layout-loading.md';
storiesOf('Loading/LayoutLoading/', module)
.addParameters({ options: { showPanel: true } })
.add(`LayoutLoading`, () => ({
template: hbs`
.add(
`LayoutLoading`,
() => ({
template: hbs`
<h5 class="title is-5">Layout Loading</h5>
<LayoutLoading/>
`,
context: {},
}),
{notes}
);
context: {},
}),
{ notes }
);

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, text, boolean } from '@storybook/addon-knobs';

View File

@ -1,25 +1,27 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './message-error.md';
import EmberObject from '@ember/object';
let model = Ember.Object.create({
let model = EmberObject.create({
adapterError: {
message: 'This is an adapterError on the model'
message: 'This is an adapterError on the model',
},
isError: true
isError: true,
});
storiesOf('MessageError/', module)
.addParameters({ options: { showPanel: true } })
.add(`MessageError`, () => ({
template: hbs`
.add(
`MessageError`,
() => ({
template: hbs`
<h5 class="title is-5">Message Error</h5>
<MessageError @model={{model}} />
`,
context: {
model
}
}),
{notes}
);
context: {
model,
},
}),
{ notes }
);

View File

@ -1,13 +1,13 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './popup-menu.md';
storiesOf('PopupMenu/', module)
.addParameters({ options: { showPanel: true } })
.add(`PopupMenu`, () => ({
template: hbs`
.add(
`PopupMenu`,
() => ({
template: hbs`
<h5 class="title is-5">Popup Menu</h5>
<PopupMenu>
<nav class="menu">
@ -21,7 +21,7 @@ storiesOf('PopupMenu/', module)
</nav>
</PopupMenu>
`,
context: {},
}),
{notes}
);
context: {},
}),
{ notes }
);

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, object, text, boolean, select } from '@storybook/addon-knobs';

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './toggle-button.md';

View File

@ -1,14 +1,15 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
import { withKnobs } from '@storybook/addon-knobs';
import notes from './toolbar-actions.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`ToolbarActions`, () => ({
template: hbs`
.add(
`ToolbarActions`,
() => ({
template: hbs`
<h5 class="title is-5">ToolbarActions</h5>
<Toolbar>
<ToolbarActions>
@ -21,7 +22,7 @@ storiesOf('Toolbar/', module)
</ToolbarActions>
</Toolbar>
`,
context: {},
}),
{notes}
);
context: {},
}),
{ notes }
);

View File

@ -1,15 +1,15 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, text } from '@storybook/addon-knobs';
import notes from './toolbar-download-button.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`ToolbarDownloadButton`,() => ({
template: hbs`
.add(
`ToolbarDownloadButton`,
() => ({
template: hbs`
<h5 class="title is-5">ToolbarLink</h5>
<div style="width: 400px;">
<Toolbar>
@ -21,9 +21,9 @@ storiesOf('Toolbar/', module)
</Toolbar>
</div>
`,
context: {
label: text('Button text', 'Download policy'),
},
}),
{notes}
);
context: {
label: text('Button text', 'Download policy'),
},
}),
{ notes }
);

View File

@ -1,14 +1,15 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
import { withKnobs } from '@storybook/addon-knobs';
import notes from './toolbar-filters.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`ToolbarFilters`, () => ({
template: hbs`
.add(
`ToolbarFilters`,
() => ({
template: hbs`
<h5 class="title is-5">ToolbarFilters</h5>
<Toolbar>
<ToolbarFilters>
@ -29,7 +30,7 @@ storiesOf('Toolbar/', module)
</ToolbarFilters>
</Toolbar>
`,
context: {},
}),
{notes}
);
context: {},
}),
{ notes }
);

View File

@ -1,15 +1,15 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select, text } from '@storybook/addon-knobs';
import notes from './toolbar-link.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`ToolbarLink`,() => ({
template: hbs`
.add(
`ToolbarLink`,
() => ({
template: hbs`
<h5 class="title is-5">ToolbarLink</h5>
<div style="width: 400px;">
<Toolbar>
@ -24,10 +24,10 @@ storiesOf('Toolbar/', module)
</Toolbar>
</div>
`,
context: {
type: select('Type', ['', 'add']),
label: text('Button text', 'Edit secret'),
},
}),
{notes}
);
context: {
type: select('Type', ['', 'add']),
label: text('Button text', 'Edit secret'),
},
}),
{ notes }
);

View File

@ -1,15 +1,15 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select, text } from '@storybook/addon-knobs';
import notes from './toolbar-secret-link.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`ToolbarSecretLink`,() => ({
template: hbs`
.add(
`ToolbarSecretLink`,
() => ({
template: hbs`
<h5 class="title is-5">ToolbarLink</h5>
<div style="width: 400px;">
<Toolbar>
@ -27,10 +27,10 @@ storiesOf('Toolbar/', module)
</Toolbar>
</div>
`,
context: {
type: select('Type', ['', 'add']),
label: text('Button text', 'Edit role'),
},
}),
{notes}
);
context: {
type: select('Type', ['', 'add']),
label: text('Button text', 'Edit role'),
},
}),
{ notes }
);

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
@ -7,8 +6,10 @@ import notes from './toolbar.md';
storiesOf('Toolbar/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(`Toolbar`, () => ({
template: hbs`
.add(
`Toolbar`,
() => ({
template: hbs`
<h5 class="title is-5">Toolbar</h5>
<section class="box is-fullwidth is-shadowless">
<h5 class="title is-6">Example for list views</h5>
@ -72,9 +73,9 @@ storiesOf('Toolbar/', module)
</Toolbar>
</section>
`,
context: {
example: select('Example', ['List', 'Show', 'Code editor'], 'List'),
},
}),
{notes}
);
context: {
example: select('Example', ['List', 'Show', 'Code editor'], 'List'),
},
}),
{ notes }
);

View File

@ -1,16 +1,16 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './ttl-picker.md';
storiesOf('TtlPicker/', module)
.addParameters({ options: { showPanel: false } })
.add(`TtlPicker`, () => ({
template: hbs`
.add(
`TtlPicker`,
() => ({
template: hbs`
<h5 class="title is-5">Ttl Picker</h5>
<TtlPicker />
`,
}),
{notes}
);
}),
{ notes }
);

View File

@ -1,17 +1,17 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './vault-logo-spinner.md';
storiesOf('Loading/VaultLogoSpinner/', module)
.addParameters({ options: { showPanel: true } })
.add(`VaultLogoSpinner`, () => ({
template: hbs`
.add(
`VaultLogoSpinner`,
() => ({
template: hbs`
<h5 class="title is-5">Vault Logo Spinner</h5>
<VaultLogoSpinner/>
`,
context: {},
}),
{notes}
);
context: {},
}),
{ notes }
);

View File

@ -10,48 +10,47 @@
},
"scripts": {
"build": "ember build -prod",
"build-dev": "ember build",
"lint:hbs": "ember-template-lint .",
"build:dev": "ember build",
"lint:hbs": "ember-template-lint app/**/* lib/**/*",
"lint:js": "eslint .",
"fmt": "yarn run fmt-js && yarn run fmt-styles",
"fmt-js": "prettier-eslint --single-quote --no-use-tabs --trailing-comma es5 --print-width=110 --write '{app,tests,config,lib}/**/*.js'",
"fmt-styles": "prettier --write app/styles/**/*.*",
"fmt:js": "prettier-eslint --single-quote --no-use-tabs --trailing-comma es5 --print-width=110 --write '{app,tests,config,lib}/**/*.js'",
"fmt:styles": "prettier --write app/styles/**/*.*",
"start": "export VAULT_ADDR=http://localhost:8200; ember server --proxy=$VAULT_ADDR",
"start2": "ember server --proxy=http://localhost:8202 --port=4202",
"test": "node scripts/start-vault.js & yarn run lint:js & ember test",
"test:browserstack": "export CI=true; node scripts/start-vault.js & node scripts/run-browserstack-tests.js",
"test-oss": "yarn run test -f='!enterprise'",
"test-quick": "node scripts/start-vault.js & ember test",
"test-quick-oss": "yarn run test-quick -f='!enterprise'",
"build-storybook": "build-storybook -s ../pkg/web_ui",
"test": "yarn lint:js && node scripts/start-vault.js",
"test:oss": "yarn run test -f='!enterprise'",
"test:browserstack": "export CI=true; node scripts/start-vault.js --browserstack",
"test:quick": "node scripts/start-vault.js",
"test:quick-oss": "yarn test-quick -f='!enterprise'",
"build:storybook": "build-storybook -s ../pkg/web_ui",
"storybook": "start-storybook -p 6006 -s ../pkg/web_ui",
"gen-story-md": "node scripts/gen-story-md.js"
},
"lint-staged": {
"linters": {
"*.js": [
"prettier-eslint --single-quote --no-use-tabs --trailing-comma es5 --print-width 110 --write",
"git add"
],
"*.scss": [
"prettier --write",
"git add"
]
}
"*.js": [
"prettier-eslint --single-quote --no-use-tabs --trailing-comma es5 --print-width 110 --write",
"git add"
],
"*.scss": [
"prettier --write",
"git add"
]
},
"devDependencies": {
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
"@ember/optional-features": "^0.7.0",
"@hashicorp/structure-icons": "^1.3.0",
"@storybook/ember-cli-storybook": "meirish/ember-cli-storybook#6bd58326d8c21e986d390b541ae5e49089d61b93",
"Duration.js": "icholy/Duration.js#golang_compatible",
"autosize": "^4.0.0",
"babel-eslint": "^10.0.2",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"base64-js": "1.2.1",
"broccoli-asset-rev": "^2.7.0",
"base64-js": "^1.3.1",
"broccoli-asset-rev": "^3.0.0",
"broccoli-sri-hash": "meirish/broccoli-sri-hash#rooturl",
"bulma": "^0.5.2",
"bulma-switch": "^0.0.1",
"codemirror": "5.15.2",
"codemirror": "^5.48.2",
"columnify": "^1.5.4",
"cool-checkboxes-for-bulma.io": "^1.1.0",
"d3-axis": "^1.0.8",
@ -61,72 +60,71 @@
"d3-time-format": "^2.1.1",
"d3-tip": "^0.9.1",
"d3-transition": "^1.2.0",
"date-fns": "^1.29.0",
"deepmerge": "^2.1.1",
"date-fns": "^1.30.0",
"deepmerge": "^4.0.0",
"doctoc": "^1.4.0",
"ember-api-actions": "^0.1.8",
"ember-auto-import": "^1.2.3",
"ember-api-actions": "^0.2.8",
"ember-auto-import": "^1.5.2",
"ember-basic-dropdown": "^1.0.0",
"ember-basic-dropdown-hover": "^0.5.0",
"ember-cli": "~3.5.1",
"ember-basic-dropdown-hover": "^0.6.0",
"ember-cli": "~3.11.0",
"ember-cli-autoprefixer": "^0.8.1",
"ember-cli-babel": "^6.16.0",
"ember-cli-babel": "^7.8.0",
"ember-cli-browserstack": "^0.0.7",
"ember-cli-clipboard": "^0.8.0",
"ember-cli-clipboard": "^0.13.0",
"ember-cli-content-security-policy": "^1.0.0",
"ember-cli-dependency-checker": "^3.0.0",
"ember-cli-deprecation-workflow": "^1.0.1",
"ember-cli-element-closest-polyfill": "^0.0.1",
"ember-cli-flash": "1.7.1",
"ember-cli-flash": "^1.7.2",
"ember-cli-htmlbars": "^3.0.0",
"ember-cli-htmlbars-inline-precompile": "^1.0.3",
"ember-cli-inject-live-reload": "^1.8.2",
"ember-cli-htmlbars-inline-precompile": "^2.1.0",
"ember-cli-inject-live-reload": "^2.0.1",
"ember-cli-page-object": "^1.15.3",
"ember-cli-pretender": "^3.1.1",
"ember-cli-sass": "^9.0.0",
"ember-cli-sass": "^10.0.1",
"ember-cli-sri": "meirish/ember-cli-sri#rooturl",
"ember-cli-string-helpers": "^1.5.0",
"ember-cli-template-lint": "^1.0.0-beta.1",
"ember-cli-uglify": "^2.1.0",
"ember-composable-helpers": "^2.0.3",
"ember-computed-query": "^0.1.1",
"ember-concurrency": "^0.10.0",
"ember-cli-string-helpers": "^4.0.0",
"ember-cli-template-lint": "^1.0.0-beta.3",
"ember-cli-uglify": "^3.0.0",
"ember-composable-helpers": "^2.3.1",
"ember-concurrency": "^1.0.0",
"ember-concurrency-test-waiter": "^0.3.1",
"ember-copy": "^1.0.0",
"ember-data": "~3.4.0",
"ember-data-model-fragments": "^3.3.0",
"ember-data": "~3.8.0",
"ember-data-model-fragments": "^4.0.0",
"ember-engines": "^0.8.0",
"ember-export-application-global": "^2.0.0",
"ember-fetch": "^6.5.1",
"ember-inflector": "^3.0.0",
"ember-link-action": "^0.1.2",
"ember-load-initializers": "^1.1.0",
"ember-link-action": "^1.0.0",
"ember-load-initializers": "^2.0.0",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-maybe-in-element": "^0.1.3",
"ember-maybe-in-element": "^0.4.0",
"ember-power-select-with-create": "cibernox/ember-power-select-with-create#6203918f247c1c5d692db4f9185ab8321d2125e1",
"ember-qunit": "^4.4.1",
"ember-radio-button": "^1.1.1",
"ember-radio-button": "^2.0.1",
"ember-resolver": "^5.0.1",
"ember-responsive": "^3.0.0-beta.3",
"ember-router-helpers": "^0.2.0",
"ember-sinon": "^1.0.1",
"ember-source": "~3.4.0",
"ember-svg-jar": "^1.2.2",
"ember-sinon": "^4.0.0",
"ember-source": "~3.8.0",
"ember-svg-jar": "^2.1.0",
"ember-test-selectors": "^2.1.0",
"ember-truth-helpers": "^2.1.0",
"escape-string-regexp": "^1.0.5",
"eslint": "^5.16.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-ember": "^6.3.0",
"eslint-plugin-prettier": "^3.0.0",
"escape-string-regexp": "^2.0.0",
"eslint": "^6.1.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-ember": "^6.7.0",
"eslint-plugin-prettier": "^3.1.0",
"flat": "^4.1.0",
"ivy-codemirror": "2.1.0",
"jsonlint": "1.6.0",
"ivy-codemirror": "IvyApp/ivy-codemirror#fb09333c5144da47e14a9e6260f80577d5408374",
"jsonlint": "^1.6.3",
"loader.js": "^4.7.0",
"node-sass": "^4.10.0",
"normalize.css": "4.1.1",
"prettier": "^1.14.3",
"prettier-eslint-cli": "^4.7.1",
"prettier-eslint-cli": "^5.0.0",
"qunit-dom": "^0.7.1",
"route-recognizer": "^0.3.4",
"sass-svg-uri": "^1.0.0",
@ -134,29 +132,29 @@
"string.prototype.endswith": "^0.2.0",
"string.prototype.startswith": "^0.2.0",
"swagger-ui-dist": "^3.22.3",
"text-encoder-lite": "1.0.0",
"walk-sync": "^0.3.3",
"text-encoder-lite": "2.0.0",
"walk-sync": "^2.0.2",
"xstate": "^3.3.3",
"yargs-parser": "^13.0.0"
"yargs-parser": "^13.1.1"
},
"optionalDependencies": {
"@babel/core": "^7.3.4",
"@storybook/addon-knobs": "^5.0.5",
"@storybook/addon-links": "^5.0.5",
"@storybook/addon-notes": "^5.0.5",
"@storybook/addon-viewport": "^5.0.5",
"@storybook/addons": "^5.0.5",
"@storybook/ember": "^5.0.5",
"@storybook/ember-cli-storybook": "meirish/ember-cli-storybook#6bd58326d8c21e986d390b541ae5e49089d61b93",
"babel-loader": "^8.0.5",
"jsdoc-to-markdown": "^4.0.1",
"lint-staged": "^8.0.4"
"@babel/core": "^7.5.5",
"@storybook/addon-knobs": "^5.1.10",
"@storybook/addon-links": "^5.1.10",
"@storybook/addon-notes": "^5.1.10",
"@storybook/addon-viewport": "^5.1.10",
"@storybook/addons": "^5.1.10",
"@storybook/ember": "^5.1.10",
"babel-loader": "^8.0.6",
"jsdoc-to-markdown": "^5.0.0",
"lint-staged": "^9.2.1"
},
"resolutions": {
"handlebars": "^4.1.2"
},
"engines": {
"node": " >= 10.*"
"node": " >= 10.* <11",
"yarn": "1.17.3"
},
"private": true,
"ember-addon": {

View File

@ -1,37 +0,0 @@
#!/usr/bin/env node
/* eslint-env node */
/* eslint-disable no-console */
const execa = require('execa');
const chalk = require('chalk');
function run(command, args = []) {
console.log(chalk.dim('$ ' + command + ' ' + args.join(' ')));
let p = execa(command, args);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
return p;
}
(async function() {
try {
await run('ember', ['browserstack:connect']);
try {
await run('ember', ['test', '-f=secrets/secret/create', '-c', 'testem.browserstack.js']);
console.log('success');
process.exit(0);
} finally {
if (process.env.CI === 'true') {
await run('ember', ['browserstack:results']);
}
await run('ember', ['browserstack:disconnect']);
}
} catch (error) {
console.log('error');
console.log(error);
process.exit(1);
}
})();

View File

@ -1,80 +1,104 @@
#!/usr/bin/env node
/* eslint-disable */
/* eslint-env node */
/* eslint-disable no-console */
if (process.argv[2]) {
process.kill(process.argv[2], 'SIGINT');
process.exit(0);
}
process.env.TERM = 'dumb';
var fs = require('fs');
var path = require('path');
var readline = require('readline');
var spawn = require('child_process').spawn;
var vault = spawn('vault', [
'server',
'-dev',
'-dev-ha',
'-dev-transactional',
'-dev-root-token-id=root',
'-dev-listen-address=127.0.0.1:9200',
]);
var execa = require('execa');
var chalk = require('chalk');
function run(command, args = [], shareStd = true) {
console.log(chalk.dim('$ ' + command + ' ' + args.join(' ')));
// cleanup means that execa will handle stopping the vault subprocess
// inherit all of the stdin/out/err so that testem still works as if you were running it directly
if (shareStd) {
return execa(command, args, { cleanup: true, stdin: 'inherit', stdout: 'inherit', stderr: 'inherit' });
}
let p = execa(command, args, { cleanup: true });
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
return p;
}
var output = '';
var unseal, root;
var unseal, root, written;
readline
.createInterface({
input: vault.stdout,
terminal: false,
})
.on('line', function(line) {
output = output + line;
console.log(line);
var unsealMatch = output.match(/Unseal Key: (.+)$/m);
if (unsealMatch && !unseal) {
unseal = unsealMatch[1];
}
var rootMatch = output.match(/Root Token: (.+)$/m);
if (rootMatch && !root) {
root = rootMatch[1];
}
if (root && unseal) {
fs.writeFile(
path.join(process.cwd(), 'tests/helpers/vault-keys.js'),
`export default ${JSON.stringify({ unseal, root }, null, 2)}`,
err => {
if (err) throw err;
}
);
console.log('VAULT SERVER READY');
}
async function processLines(input, eachLine = () => {}) {
const rl = readline.createInterface({
input,
terminal: true,
});
for await (const line of rl) {
eachLine(line);
}
}
vault.stderr.on('data', function(data) {
console.log(data.toString());
});
(async function() {
try {
let vault = run(
'vault',
[
'server',
'-dev',
'-dev-ha',
'-dev-transactional',
'-dev-root-token-id=root',
'-dev-listen-address=127.0.0.1:9200',
],
false
);
vault.on('close', function(code) {
console.log(`child process exited with code ${code}`);
process.exit();
});
vault.on('error', function(error) {
console.log(`child process errored: ${error}`);
process.exit();
});
processLines(vault.stdout, function(line) {
if (written) {
output = null;
return;
}
output = output + line;
var unsealMatch = output.match(/Unseal Key: (.+)$/m);
if (unsealMatch && !unseal) {
unseal = unsealMatch[1];
}
var rootMatch = output.match(/Root Token: (.+)$/m);
if (rootMatch && !root) {
root = rootMatch[1];
}
if (root && unseal && !written) {
fs.writeFile(
path.join(process.cwd(), 'tests/helpers/vault-keys.js'),
`export default ${JSON.stringify({ unseal, root }, null, 2)}`,
err => {
if (err) throw err;
}
);
written = true;
console.log('VAULT SERVER READY');
}
});
try {
if (process.argv[2] === '--browserstack') {
await run('ember', ['browserstack:connect']);
try {
await run('ember', ['test', '-f=secrets/secret/create', '-c', 'testem.browserstack.js']);
var pidFile = 'vault-ui-integration-server.pid';
process.on('SIGINT', function() {
vault.kill('SIGINT');
process.exit();
});
process.on('exit', function() {
vault.kill('SIGINT');
});
fs.writeFile(pidFile, process.pid, err => {
if (err) throw err;
console.log('The file has been saved!');
});
console.log('success');
process.exit(0);
} finally {
if (process.env.CI === 'true') {
await run('ember', ['browserstack:results']);
}
await run('ember', ['browserstack:disconnect']);
}
} else {
await run('ember', ['test', ...process.argv.slice(2)]);
}
} catch (error) {
console.log(error);
} finally {
process.exit(0);
}
} catch (error) {
console.log(error);
process.exit(0);
}
})();

View File

@ -1,35 +0,0 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, text } from '@storybook/addon-knobs';
import notes from './empty-state.md';
storiesOf('EmptyState/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs({escapeHTML: false}))
.add(`EmptyState`, () => ({
template: hbs`
<h5 class="title is-5">Empty State</h5>
<EmptyState @title={{title}} @message={{message}} />
`,
context: {
title: text('Title', 'You don\'t have an secrets yet'),
message: text('Message', 'An explanation of why you don\'t have any secrets but also you maybe want to create one.')
},
}),
{notes}
)
.add(`EmptyState with content block`, () => ({
template: hbs`
<h5 class="title is-5">Empty State</h5>
<EmptyState @title={{title}} @message={{message}}>
<DocLink @path="/docs/secrets/kv/kv-v2.html">Learn about KV v2</DocLink>
</EmptyState>
`,
context: {
title: text('Title', 'You don\'t have an secrets yet'),
message: text('Message', 'An explanation of why you don\'t have any secrets but also you maybe want to create one.')
},
}),
{notes}
);

View File

@ -1,4 +1,3 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import notes from './search-select.md';
@ -13,13 +12,13 @@ storiesOf('SearchSelect/', module)
.add(`SearchSelect`, () => ({
template: hbs`
<h5 class="title is-5">Search Select</h5>
<SearchSelect
@id="groups"
@models={{models}}
@onChange={{onChange}}
<SearchSelect
@id="groups"
@models={{models}}
@onChange={{onChange}}
@inputValue={{inputValue}}
@label={{label}}
@fallbackComponent="string-list"
@fallbackComponent="string-list"
@staticOptions={{staticOptions}}/>
`,
context: {

View File

@ -18,9 +18,6 @@ const config = {
].filter(Boolean),
},
},
on_exit:
'[ -e ../../vault-ui-integration-server.pid ] && node ../../scripts/start-vault.js `cat ../../vault-ui-integration-server.pid`; [ -e ../../vault-ui-integration-server.pid ] && rm ../../vault-ui-integration-server.pid',
proxies: {
'/v1': {
target: 'http://localhost:9200',

View File

@ -171,10 +171,8 @@ module('Acceptance | Enterprise | KMIP secrets', function(hooks) {
`/vault/secrets/${path}/kmip/scopes/${scope}/roles/${role}`,
'cancel navigates to role show'
);
await rolesPage
.detailDelete()
.delete()
.confirmDelete();
await rolesPage.delete().confirmDelete();
assert.equal(
currentURL(),
`/vault/secrets/${path}/kmip/scopes/${scope}/roles`,
@ -209,8 +207,7 @@ module('Acceptance | Enterprise | KMIP secrets', function(hooks) {
await credentialsPage.visit({ backend: path, scope, role });
// revoke the credentials
await credentialsPage.listItemLinks.objectAt(0).menuToggle();
await credentialsPage.delete();
await credentialsPage.confirmDelete();
await credentialsPage.delete().confirmDelete();
assert.equal(credentialsPage.listItemLinks.length, 0, 'renders no credentials');
assert.ok(credentialsPage.isEmpty, 'renders empty');
});
@ -218,10 +215,7 @@ module('Acceptance | Enterprise | KMIP secrets', function(hooks) {
test('it can revoke from the credentials show page', async function(assert) {
let { path, scope, role, serial } = await generateCreds();
await credentialsPage.visitDetail({ backend: path, scope, role, serial });
await credentialsPage
.detailRevoke()
.delete()
.confirmDelete();
await credentialsPage.delete().confirmDelete();
assert.equal(
currentURL(),

View File

@ -1,4 +1,4 @@
import { click, currentRouteName, currentURL, visit } from '@ember/test-helpers';
import { click } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { create } from 'ember-cli-page-object';

View File

@ -25,7 +25,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
hooks.beforeEach(async function() {
this.server = apiStub({ usePassthrough: true });
await logout.visit();
return authPage.login();
});
@ -215,7 +214,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
await writeSecret(backend, 'secret', 'foo', 'bar');
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
assert.ok(showPage.editIsPresent, 'shows the edit button');
await logout.visit();
});
test('version 2 with restricted policy still allows edit', async function(assert) {
@ -247,7 +245,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
assert.ok(showPage.editIsPresent, 'shows the edit button');
await logout.visit();
});
test('paths are properly encoded', async function(assert) {
@ -389,7 +386,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
await editPage.editSecret('bar', 'baz');
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
await logout.visit();
});
test('write without read: version 2 with metadata read', async function(assert) {
@ -409,7 +405,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
await editPage.editSecret('bar', 'baz');
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
await logout.visit();
});
test('write without read: version 1', async function(assert) {
@ -428,6 +423,5 @@ module('Acceptance | secrets/secret/create', function(hooks) {
await editPage.editSecret('bar', 'baz');
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
await logout.visit();
});
});

View File

@ -248,7 +248,7 @@ module('Acceptance | transit', function(hooks) {
// wait for capabilities
await settled();
assert.dom('[data-test-transit-key-version-row]').exists({ count: 1 }, `${name}: only one key version`);
await click('[data-test-confirm-action-trigger');
await click('[data-test-confirm-action-trigger]');
await click('[data-test-confirm-button]');
// wait for rotate call
await settled();

View File

@ -14,12 +14,14 @@ import form from '../../pages/components/auth-jwt';
import { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS } from 'vault/components/auth-jwt';
const component = create(form);
const windows = [];
const fakeWindow = EmberObject.extend(Evented, {
init() {
this._super(...arguments);
this.__proto__.on('close', () => {
this.on('close', () => {
this.set('closed', true);
});
windows.push(this);
},
screen: computed(function() {
return {
@ -41,7 +43,7 @@ fakeWindow.reopen({
},
close() {
fakeWindow.proto().trigger('close');
windows.forEach(w => w.trigger('close'));
},
});

View File

@ -71,14 +71,14 @@ module('Integration | Component | edit form kmip role', function(hooks) {
this.set('model', model);
await render(hbs`<EditFormKmipRole @model={{model}} />`);
assert.dom('[data-test-input="operationAll"').isChecked('sets operationAll');
assert.dom('[data-test-input="operationAll"]').isChecked('sets operationAll');
});
test('it renders: operationAll', async function(assert) {
let model = createModel({ operationAll: true });
this.set('model', model);
await render(hbs`<EditFormKmipRole @model={{model}} />`);
assert.dom('[data-test-input="operationAll"').isChecked('sets operationAll');
assert.dom('[data-test-input="operationAll"]').isChecked('sets operationAll');
});
test('it renders: operationNone', async function(assert) {
@ -95,7 +95,7 @@ module('Integration | Component | edit form kmip role', function(hooks) {
await render(hbs`<EditFormKmipRole @model={{model}} />`);
assert.dom('[data-test-input="operationNone"]').isChecked('sets operationNone');
assert.dom('[data-test-input="operationAll"').isNotChecked('sets operationAll');
assert.dom('[data-test-input="operationAll"]').isNotChecked('sets operationAll');
});
let savingTests = [

View File

@ -8,7 +8,7 @@ module('Integration | Component | toolbar-link', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
await render(hbs`<ToolbarLink @params="/secrets">Link</ToolbarLink>`);
await render(hbs`<ToolbarLink @params={{array '/secrets'}}>Link</ToolbarLink>`);
assert.equal(this.element.textContent.trim(), 'Link');
assert.ok(isPresent('.toolbar-link'));

Some files were not shown because too many files have changed in this diff Show More