From b450fd813de821e7296f8b518542195df95503ad Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Thu, 1 Oct 2015 11:26:16 +0200 Subject: [PATCH 1/2] #316 suggest mint bucket --- client/index.html | 3 ++- .../src/access-form/access-form.jsx | 26 ++++++++++++++++++- client/lib/application/src/editable-list.jsx | 8 ++++++ client/lib/common/asset/less/button.less | 6 +++++ client/lib/common/asset/less/form.less | 3 +++ client/mocha-globals.js | 1 + client/webpack.config.js | 3 ++- 7 files changed, 47 insertions(+), 3 deletions(-) diff --git a/client/index.html b/client/index.html index 5dda3a41..48a0c775 100644 --- a/client/index.html +++ b/client/index.html @@ -25,7 +25,8 @@ YTENV_DOCKER_REGISTRY="docker.io"; YTENV_SERVICE_URL_TLD="com"; YTENV_RESOURCE_WHITELIST="npiccolotto"; - YTENV_APPLICATION_WHITELIST="npiccolotto" + YTENV_APPLICATION_WHITELIST="npiccolotto"; + YTENV_MINT_BUCKET_TEMPLATE="default-bucket-${id}-eu-west-1"; diff --git a/client/lib/application/src/access-form/access-form.jsx b/client/lib/application/src/access-form/access-form.jsx index 2c30fd34..c6d4ad40 100644 --- a/client/lib/application/src/access-form/access-form.jsx +++ b/client/lib/application/src/access-form/access-form.jsx @@ -7,6 +7,12 @@ import ScopeList from 'application/src/scope-list.jsx'; import EditableList from 'application/src/editable-list.jsx'; import {constructLocalUrl} from 'common/src/data/services'; import 'common/asset/less/application/access-form.less'; +import MINT_BUCKET_TEMPLATE from 'MINT_BUCKET_TEMPLATE'; + +function getDefaultBucket(account) { + return MINT_BUCKET_TEMPLATE + .replace("${id}", account.id); +} class AccessForm extends React.Component { constructor(props) { @@ -30,6 +36,12 @@ class AccessForm extends React.Component { }); } + addBucket(bucket) { + this.setState({ + s3_buckets: this.state.s3_buckets.concat([bucket]) + }); + } + updateBuckets(s3_buckets) { this.setState({ s3_buckets: s3_buckets @@ -82,6 +94,7 @@ class AccessForm extends React.Component { {kio, user, mint, essentials} = this.stores, allAppScopes = essentials.getAllScopes().filter(s => !s.is_resource_owner_scope), application = kio.getApplication(applicationId), + defaultAccount = user.getUserCloudAccounts().filter(a => a.name === application.team_id)[0], isOwnApplication = user.getUserCloudAccounts().some(t => t.name === application.team_id), oauth = mint.getOAuthConfig(applicationId); @@ -116,13 +129,24 @@ class AccessForm extends React.Component {
Activate credential distribution into these S3 buckets (Naming Conventions). A * indicates unsaved changes. + { this.state.s3_buckets.length === 0 && defaultAccount ? +
+ Psst, your mint bucket is probably: + + {getDefaultBucket(defaultAccount)} + +
+ : + null}
diff --git a/client/lib/application/src/editable-list.jsx b/client/lib/application/src/editable-list.jsx index e4c7b381..c2e57f5e 100644 --- a/client/lib/application/src/editable-list.jsx +++ b/client/lib/application/src/editable-list.jsx @@ -18,6 +18,14 @@ class EditableList extends React.Component { }); } + componentWillReceiveProps(nextProps) { + if (nextProps.items.length !== this.props.items.length) { + this.setState({ + items: nextProps.items + }); + } + } + addItem(evt) { evt.preventDefault(); let regex = new RegExp(this.props.pattern); diff --git a/client/lib/common/asset/less/button.less b/client/lib/common/asset/less/button.less index 203ed6a3..87980274 100644 --- a/client/lib/common/asset/less/button.less +++ b/client/lib/common/asset/less/button.less @@ -51,6 +51,12 @@ line-height: 1; } + &.btn-smaller { + padding: 0 @padding-tiniest; + line-height: 1; + font-size: @small-font-size; + } + &.btn-primary { .transition(background, border-color); background: @orange; diff --git a/client/lib/common/asset/less/form.less b/client/lib/common/asset/less/form.less index 4a0bda23..69a33008 100644 --- a/client/lib/common/asset/less/form.less +++ b/client/lib/common/asset/less/form.less @@ -48,6 +48,9 @@ input[type="search"] { .form-group { small { color: @gray; + + small { + display: block; + } } label { font-weight: @weight-regular; diff --git a/client/mocha-globals.js b/client/mocha-globals.js index 6a1a5736..0e998062 100644 --- a/client/mocha-globals.js +++ b/client/mocha-globals.js @@ -116,3 +116,4 @@ global.YTENV_SERVICE_URL_TLD = ''; global.YTENV_DOCKER_REGISTRY = ''; global.YTENV_RESOURCE_WHITELIST = ''; global.YTENV_APPLICATION_WHITELIST = ''; +global.YTENV_MINT_BUCKET_TEMPLATE = ''; \ No newline at end of file diff --git a/client/webpack.config.js b/client/webpack.config.js index 1e60832c..25f9d115 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -50,7 +50,8 @@ module.exports = { DOCKER_REGISTRY: 'YTENV_DOCKER_REGISTRY', SERVICE_URL_TLD: 'YTENV_SERVICE_URL_TLD', RESOURCE_WHITELIST: 'YTENV_RESOURCE_WHITELIST', - APPLICATION_WHITELIST: 'YTENV_APPLICATION_WHITELIST' + APPLICATION_WHITELIST: 'YTENV_APPLICATION_WHITELIST', + MINT_BUCKET_TEMPLATE: 'YTENV_MINT_BUCKET_TEMPLATE' }, module: { loaders: [ From 18e4f541cc896d554cf0581d394b78ec9124e3ba Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Thu, 1 Oct 2015 12:17:48 +0200 Subject: [PATCH 2/2] #316 tests --- .../src/access-form/access-form.jsx | 5 ++- .../lib/application/test/access-form.test.js | 40 +++++++++++++++++-- client/mocha-globals.js | 2 +- client/webpack.production.config.js | 3 +- client/webpack.test.config.js | 1 + 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/client/lib/application/src/access-form/access-form.jsx b/client/lib/application/src/access-form/access-form.jsx index c6d4ad40..c2042409 100644 --- a/client/lib/application/src/access-form/access-form.jsx +++ b/client/lib/application/src/access-form/access-form.jsx @@ -11,7 +11,7 @@ import MINT_BUCKET_TEMPLATE from 'MINT_BUCKET_TEMPLATE'; function getDefaultBucket(account) { return MINT_BUCKET_TEMPLATE - .replace("${id}", account.id); + .replace('${id}', account.id); } class AccessForm extends React.Component { @@ -130,9 +130,10 @@ class AccessForm extends React.Component { Activate credential distribution into these S3 buckets (Naming Conventions). A * indicates unsaved changes. { this.state.s3_buckets.length === 0 && defaultAccount ? -
+
Psst, your mint bucket is probably: {getDefaultBucket(defaultAccount)} diff --git a/client/lib/application/test/access-form.test.js b/client/lib/application/test/access-form.test.js index 6abab2c4..ccf7c17c 100644 --- a/client/lib/application/test/access-form.test.js +++ b/client/lib/application/test/access-form.test.js @@ -10,7 +10,7 @@ import UserStore from 'common/src/data/user/user-store'; import UserActions from 'common/src/data/user/user-actions'; import AccessForm from 'application/src/access-form/access-form.jsx'; -const MOCK_KIO = { +const OAUTH_KIO = { id: 'kio', username: 'kio-robot', last_password_rotation: '2015-01-01T12:42:41Z', @@ -20,13 +20,21 @@ const MOCK_KIO = { has_problems: false, redirect_url: 'http://example.com/oauth', s3_buckets: [ - 'kio-stups-bucket' ], scopes: [{ resource_type_id: 'customer', scope_id: 'read_all' }] -}; +}, +APP_KIO = { + id: 'kio', + team_id: 'stups', + active: true +}, +ACCOUNTS = [{ + id: '123', + name: 'stups' +}]; class MockFlux extends Flummox { constructor() { @@ -58,10 +66,13 @@ describe('The access control form view', () => { flux.getStore('essentials').receiveScopes(['customer', [{ id: 'read_all' }]]); - flux.getStore('mint').receiveOAuthConfig(['kio', MOCK_KIO]); + flux.getStore('mint').receiveOAuthConfig(['kio', OAUTH_KIO]); + flux.getStore('kio').receiveApplication(APP_KIO); + flux.getStore('user').receiveAccounts(ACCOUNTS); actionSpy = sinon.stub(flux.getActions('mint'), 'saveOAuthConfig', () => { return Promise.resolve(); }); + props = { flux: flux, applicationId: 'kio' @@ -74,4 +85,25 @@ describe('The access control form view', () => { TestUtils.Simulate.submit(f); expect(actionSpy.calledOnce).to.be.true; }); + + it('should suggest a mint bucket', () => { + TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'mint-bucket-suggestion'); + }); + + it('should add suggested bucket to list', () => { + expect(() => { + TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'editable-list-item'); + }).to.throw; + let btn = TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'mint-bucket-add-suggestion'); + TestUtils.Simulate.click(btn); + TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'editable-list-item'); + }); + + it('should not suggest after adding', () => { + let btn = TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'mint-bucket-add-suggestion'); + TestUtils.Simulate.click(btn); + expect(() => { + TestUtils.findRenderedDOMComponentWithAttributeValue(form, 'data-block', 'mint-bucket-suggestion'); + }).to.throw; + }); }); \ No newline at end of file diff --git a/client/mocha-globals.js b/client/mocha-globals.js index 0e998062..0dd9d58f 100644 --- a/client/mocha-globals.js +++ b/client/mocha-globals.js @@ -116,4 +116,4 @@ global.YTENV_SERVICE_URL_TLD = ''; global.YTENV_DOCKER_REGISTRY = ''; global.YTENV_RESOURCE_WHITELIST = ''; global.YTENV_APPLICATION_WHITELIST = ''; -global.YTENV_MINT_BUCKET_TEMPLATE = ''; \ No newline at end of file +global.YTENV_MINT_BUCKET_TEMPLATE = ''; diff --git a/client/webpack.production.config.js b/client/webpack.production.config.js index 16b7cfc8..da724e19 100644 --- a/client/webpack.production.config.js +++ b/client/webpack.production.config.js @@ -61,7 +61,8 @@ module.exports = { DOCKER_REGISTRY: 'YTENV_DOCKER_REGISTRY', SERVICE_URL_TLD: 'YTENV_SERVICE_URL_TLD', RESOURCE_WHITELIST: 'YTENV_RESOURCE_WHITELIST', - APPLICATION_WHITELIST: 'YTENV_APPLICATION_WHITELIST' + APPLICATION_WHITELIST: 'YTENV_APPLICATION_WHITELIST', + MINT_BUCKET_TEMPLATE: 'YTENV_MINT_BUCKET_TEMPLATE' }, eslint: { configFile: './.eslintrc', diff --git a/client/webpack.test.config.js b/client/webpack.test.config.js index 84c8d18d..ffad0369 100644 --- a/client/webpack.test.config.js +++ b/client/webpack.test.config.js @@ -56,6 +56,7 @@ module.exports = { SERVICE_URL_TLD: 'YTENV_SERVICE_URL_TLD', RESOURCE_WHITELIST: 'YTENV_RESOURCE_WHITELIST', APPLICATION_WHITELIST: 'YTENV_APPLICATION_WHITELIST', + MINT_BUCKET_TEMPLATE: 'YTENV_MINT_BUCKET_TEMPLATE', // needed because otherwise two react instances // are running in tests and they trip each other up react: 'var React'