Skip to content

Commit

Permalink
Merge pull request #317 from zalando-stups/316-suggest-mint-bucket
Browse files Browse the repository at this point in the history
suggest mint bucket
  • Loading branch information
prayerslayer committed Oct 1, 2015
2 parents 4ff3ba4 + 18e4f54 commit 77292d3
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 8 deletions.
3 changes: 2 additions & 1 deletion client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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";
</script>
</head>
<body>
Expand Down
27 changes: 26 additions & 1 deletion client/lib/application/src/access-form/access-form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -116,13 +129,25 @@ class AccessForm extends React.Component {
<div className='form-group'>
<label>Credential Distribution</label>
<small>Activate credential distribution into these S3 buckets (<a href='http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html'>Naming Conventions</a>). A <code>*</code> indicates unsaved changes.</small>
{ this.state.s3_buckets.length === 0 && defaultAccount ?
<div data-block='mint-bucket-suggestion'>
<small>Psst, your mint bucket is probably: </small>
<span
data-block='mint-bucket-add-suggestion'
onClick={this.addBucket.bind(this, getDefaultBucket(defaultAccount))}
className='btn btn-default btn-smaller'>
<Icon name='plus' /> <span>{getDefaultBucket(defaultAccount)}</span>
</span>
</div>
:
null}
<EditableList
placeholder='my-s3-bucket'
itemName={'bucket'}
minlength={3}
maxlength={64}
onChange={this.updateBuckets.bind(this)}
items={oauth.s3_buckets}
items={this.state.s3_buckets}
markedItems={_.difference(this.state.s3_buckets, oauth.s3_buckets)}
pattern={'^[a-z0-9][a-z0-9\-\.]*[a-z0-9]$'} />
</div>
Expand Down
8 changes: 8 additions & 0 deletions client/lib/application/src/editable-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
40 changes: 36 additions & 4 deletions client/lib/application/test/access-form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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() {
Expand Down Expand Up @@ -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'
Expand All @@ -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;
});
});
6 changes: 6 additions & 0 deletions client/lib/common/asset/less/button.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions client/lib/common/asset/less/form.less
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ input[type="search"] {
.form-group {
small {
color: @gray;
+ small {
display: block;
}
}
label {
font-weight: @weight-regular;
Expand Down
1 change: 1 addition & 0 deletions client/mocha-globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
3 changes: 2 additions & 1 deletion client/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
3 changes: 2 additions & 1 deletion client/webpack.production.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions client/webpack.test.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down

0 comments on commit 77292d3

Please sign in to comment.