Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Mount Description #105

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 83 additions & 7 deletions app/components/Secrets/Generic/Generic.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class GenericSecretBackend extends React.Component {
wrapPath: null,
useRootKey: window.localStorage.getItem("useRootKey") === 'true' || false,
rootKey: window.localStorage.getItem("secretsRootKey") || '',
description: '',
disableDescEdit: true,
genericName: ''
}

_.bindAll(
Expand All @@ -71,7 +74,13 @@ class GenericSecretBackend extends React.Component {
'DeleteObject',
'renderNewObjectDialog',
'renderEditObjectDialog',
'renderDeleteConfirmationDialog'
'renderDeleteConfirmationDialog',
/*
TODO:
Waiting on the ability to update mount description: https://github.com/hashicorp/vault/issues/2645
'editDescription',
'updateDescription'
*/
);
}

Expand Down Expand Up @@ -131,11 +140,54 @@ class GenericSecretBackend extends React.Component {
})
}

getMountDescription() {
this.setState({ genericName: this.props.params.namespace });
tokenHasCapabilities(['read'], 'sys/mounts')
.then(() => {
callVaultApi('get', 'sys/mounts')
.then((resp) => {
let desc = _.get(resp, `data.data.${this.state.genericName}/.description`, null);
if (desc) this.setState({ description: desc })
});
})
.catch();
}

/*
TODO:
Waiting on the ability to update mount description: https://github.com/hashicorp/vault/issues/2645

editDescription() {
let uri = `/sys/mounts/${this.state.genericName}`;
tokenHasCapabilities(['post'], uri)
.then(() => {
this.setState({ disableDescEdit: false });
})
.catch();
}

updateDescription() {
let uri = `/sys/mounts/${this.state.genericName}`;
tokenHasCapabilities(['post'], uri)
.then(() => {
callVaultApi('post', uri, {}, { description: this.state.description, type: 'generic', path: this.state.genericName })
.then((resp) => {
snackBarMessage('Description updated')
})
.catch((error) => {
snackBarMessage(error);
});
})
.catch();
}
*/

componentWillMount() {
this.setState({ currentLogicalPath: `${this.props.params.namespace}/${this.props.params.splat}` })
}

componentDidMount() {
this.getMountDescription();
if (this.isPathDirectory(this.props.params.splat)) {
this.loadSecretsList();
} else {
Expand All @@ -148,13 +200,15 @@ class GenericSecretBackend extends React.Component {
if (!_.isEqual(this.props.params.namespace, nextProps.params.namespace)) {
// Reset
this.setState({
secretList: []
secretList: [],
description: ''
})
}
}

componentDidUpdate(prevProps) {
if (!_.isEqual(this.props.params, prevProps.params)) {
this.getMountDescription();
if (this.isPathDirectory(this.props.params.splat)) {
this.loadSecretsList();
} else {
Expand Down Expand Up @@ -432,7 +486,29 @@ class GenericSecretBackend extends React.Component {
{this.renderDeleteConfirmationDialog()}
<Tabs>
<Tab label="Browse Secrets" >
<Paper className={sharedStyles.TabInfoSection} zDepth={0}>
<Paper
className={sharedStyles.TabInfoSection}
zDepth={0}
onDoubleClick={this.editDescription}
>
{this.state.description ? <TextField
inputStyle={{ textAlign: 'center' }}
underlineShow={false}
fullWidth={true}
value={this.state.description}
/*
TODO:
Waiting on the ability to update: https://github.com/hashicorp/vault/issues/2645
*/
disabled={true}
onBlur={() => {
this.setState({ disableDescEdit: true });
this.updateDescription();
}}
onChange={(e) => {
this.setState({ description: e.target.value })
}}
/> : null}
Here you can browse, edit, create and delete secrets.
</Paper>
<Paper className={sharedStyles.TabContentSection} zDepth={0}>
Expand All @@ -456,14 +532,14 @@ class GenericSecretBackend extends React.Component {
</ToolbarGroup>
<ToolbarGroup lastChild={true}>
<SelectField
style={{width: 150}}
style={{ width: 150 }}
autoWidth={true}
floatingLabelText="Sort Secrets"
floatingLabelFixed={true}
value={this.state.secretSortDir} onChange={(e,i,v) => {this.setState({secretSortDir: v})}}
value={this.state.secretSortDir} onChange={(e, i, v) => { this.setState({ secretSortDir: v }) }}
>
<MenuItem value={SORT_DIR.ASC} primaryText="Ascending"/>
<MenuItem value={SORT_DIR.DESC} primaryText="Descending"/>
<MenuItem value={SORT_DIR.ASC} primaryText="Ascending" />
<MenuItem value={SORT_DIR.DESC} primaryText="Descending" />
</SelectField>
</ToolbarGroup>
</Toolbar>
Expand Down
38 changes: 32 additions & 6 deletions app/components/shared/Menu/Menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,22 @@ class Menu extends React.Component {
config: backend.config
}

let secondaryText = (
<p>
{backend.description &&
<span className={styles.mountSecondaryText}>{backend.description}<br /></span>
}
<span className={styles.mountSecondaryText}>type: {backend.type}</span>
</p>
)

return (
<ListItem
key={idx}
className={styles.menuItem}
primaryText={backend.path}
secondaryText={`type: ${backend.type}`}
secondaryText={secondaryText}
secondaryTextLines={backend.description ? 2 : 1}
value={`/secrets/${backend.type}/${backend.path}`}
rightIconButton={
<IconButton
Expand All @@ -158,11 +169,22 @@ class Menu extends React.Component {
config: backend.config
}

let secondaryText = (
<p>
{backend.description &&
<span className={styles.mountSecondaryText}>{backend.description}<br /></span>
}
<span className={styles.mountSecondaryText}>type: {backend.type}</span>
</p>
)

return (
<ListItem
key={idx}
className={styles.menuItem}
primaryText={backend.path}
secondaryText={`type: ${backend.type}`}
secondaryText={secondaryText}
secondaryTextLines={backend.description ? 2 : 1}
value={`/auth/${backend.type}/${backend.path}`}
rightIconButton={
<IconButton
Expand Down Expand Up @@ -227,6 +249,7 @@ class Menu extends React.Component {
<Drawer containerClassName={styles.root} docked={true} open={true} >
<SelectableList value={this.state.selectedPath} onChange={handleMenuChange}>
<ListItem
className={styles.menuItem}
primaryText="Secret Backends"
primaryTogglesNestedList={true}
initiallyOpen={true}
Expand All @@ -235,13 +258,14 @@ class Menu extends React.Component {
<IconButton
style={{ opacity: 0.1 }}
hoveredStyle={{ opacity: 1.0 }}
onTouchTap={() => this.setState({openNewSecretMountDialog: true})}
onTouchTap={() => this.setState({ openNewSecretMountDialog: true })}
>
<ContentAdd />
</IconButton>
}
/>
<ListItem
className={styles.menuItem}
primaryText="Auth Backends"
primaryTogglesNestedList={true}
initiallyOpen={true}
Expand All @@ -250,23 +274,25 @@ class Menu extends React.Component {
<IconButton
style={{ opacity: 0.1 }}
hoveredStyle={{ opacity: 1.0 }}
onTouchTap={() => this.setState({openNewAuthMountDialog: true})}
onTouchTap={() => this.setState({ openNewAuthMountDialog: true })}
>
<ContentAdd />
</IconButton>
}

/>
<ListItem
className={styles.menuItem}
primaryText="System"
primaryTogglesNestedList={true}
initiallyOpen={true}
nestedItems={[
<ListItem primaryText="Policies" secondaryText="Manage Vault Access Policies" value="/sys/policies" />,
<ListItem primaryText="Data Wrapper" secondaryText="Securely Forward JSON Data" value="/responsewrapper" />
<ListItem className={styles.menuItem} primaryText="Policies" secondaryText="Manage Vault Access Policies" value="/sys/policies" />,
<ListItem className={styles.menuItem} primaryText="Data Wrapper" secondaryText="Securely Forward JSON Data" value="/responsewrapper" />
]}
/>
<ListItem
className={styles.menuItem}
primaryText="Preferences"
secondaryText="Customize Vault-UI"
primaryTogglesNestedList={false}
Expand Down
13 changes: 10 additions & 3 deletions app/components/shared/Menu/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
height: calc(100% - 60px) !important;
}

.root span {
font-size: 20px !important;
font-weight: 200 !important;
.menuItem > div > div > div {
font-size: 20px;
font-weight: 250;
}

.link {
Expand All @@ -31,4 +31,11 @@

.disabled {
display: none;
}

.mountSecondaryText {
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
9 changes: 9 additions & 0 deletions app/components/shared/MountUtils/NewMount.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ export default class NewMountDialog extends Component {
onChange={(e) => this.setState({ backendPath: e.target.value }) }
/>
</div>
<div>
<TextField
floatingLabelFixed={true}
floatingLabelText="Mount description"
fullWidth={true}
value={this.state.backendDescription}
onChange={(e) => this.setState({ backendDescription: e.target.value }) }
/>
</div>
</div>
</Dialog >
}
Expand Down