mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-14 18:47:01 +02:00
UI namespace additions (#5150)
* add switch link on namespace link page if user has access to the namespace * refresh list when you delete, only show manage if you can list * fix bug where disconnected namespaces wouldn't show the picker properly * namespaces list should end in a slash * end full namespace paths with a / * shorten pop up menu link
This commit is contained in:
parent
62eae43c07
commit
d6ab7bcd54
@ -9,11 +9,12 @@ export default Ember.Component.extend({
|
|||||||
componentName: null,
|
componentName: null,
|
||||||
hasMenu: false,
|
hasMenu: false,
|
||||||
|
|
||||||
callMethod: task(function*(method, model, successMessage, failureMessage) {
|
callMethod: task(function*(method, model, successMessage, failureMessage, successCallback = () => {}) {
|
||||||
let flash = this.get('flashMessages');
|
let flash = this.get('flashMessages');
|
||||||
try {
|
try {
|
||||||
yield model[method]();
|
yield model[method]();
|
||||||
flash.success(successMessage);
|
flash.success(successMessage);
|
||||||
|
successCallback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
let errString = e.errors.join(' ');
|
let errString = e.errors.join(' ');
|
||||||
flash.danger(failureMessage + errString);
|
flash.danger(failureMessage + errString);
|
||||||
|
14
ui/app/controllers/vault/cluster/access/namespaces/index.js
Normal file
14
ui/app/controllers/vault/cluster/access/namespaces/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
const { computed, inject, Controller } = Ember;
|
||||||
|
export default Controller.extend({
|
||||||
|
namespaceService: inject.service('namespace'),
|
||||||
|
accessibleNamespaces: computed.alias('namespaceService.accessibleNamespaces'),
|
||||||
|
currentNamespace: computed.alias('namespaceService.path'),
|
||||||
|
actions: {
|
||||||
|
refreshNamespaceList() {
|
||||||
|
// fetch new namespaces for the namespace picker
|
||||||
|
this.get('namespaceService.findNamespacesForUser').perform();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -1,5 +1,6 @@
|
|||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
|
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||||||
|
|
||||||
const { Service, computed, inject } = Ember;
|
const { Service, computed, inject } = Ember;
|
||||||
const ROOT_NAMESPACE = '';
|
const ROOT_NAMESPACE = '';
|
||||||
@ -18,6 +19,8 @@ export default Service.extend({
|
|||||||
setNamespace(path) {
|
setNamespace(path) {
|
||||||
this.set('path', path);
|
this.set('path', path);
|
||||||
},
|
},
|
||||||
|
listPath: lazyCapabilities(apiPath`sys/namespaces/`, 'path'),
|
||||||
|
canList: computed.alias('listPath.canList'),
|
||||||
|
|
||||||
findNamespacesForUser: task(function*() {
|
findNamespacesForUser: task(function*() {
|
||||||
// uses the adapter and the raw response here since
|
// uses the adapter and the raw response here since
|
||||||
@ -25,14 +28,28 @@ export default Service.extend({
|
|||||||
// want to keep track of these separately
|
// want to keep track of these separately
|
||||||
let store = this.get('store');
|
let store = this.get('store');
|
||||||
let adapter = store.adapterFor('namespace');
|
let adapter = store.adapterFor('namespace');
|
||||||
|
let userRoot = this.get('auth.authData.userRootNamespace');
|
||||||
try {
|
try {
|
||||||
let ns = yield adapter.findAll(store, 'namespace', null, {
|
let ns = yield adapter.findAll(store, 'namespace', null, {
|
||||||
adapterOptions: {
|
adapterOptions: {
|
||||||
forUser: true,
|
forUser: true,
|
||||||
namespace: this.get('userRootNamespace'),
|
namespace: userRoot,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.set('accessibleNamespaces', ns.data.keys.map(n => n.replace(/\/$/, '')));
|
this.set(
|
||||||
|
'accessibleNamespaces',
|
||||||
|
ns.data.keys.map(n => {
|
||||||
|
let fullNS = n;
|
||||||
|
// if the user's root isn't '', then we need to construct
|
||||||
|
// the paths so they connect to the user root to the list
|
||||||
|
// otherwise using the current ns to grab the correct leaf
|
||||||
|
// node in the graph doesn't work
|
||||||
|
if (userRoot) {
|
||||||
|
fullNS = `${userRoot}/${n}`;
|
||||||
|
}
|
||||||
|
return fullNS.replace(/\/$/, '');
|
||||||
|
})
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//do nothing here
|
//do nothing here
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,17 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="level-right">
|
<div class="level-right">
|
||||||
|
{{#if namespaceService.canList}}
|
||||||
{{#link-to "vault.cluster.access.namespaces" class="namespace-manage-link"}}
|
{{#link-to "vault.cluster.access.namespaces" class="namespace-manage-link"}}
|
||||||
Manage
|
Manage
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<header class="current-namespace">
|
<header class="current-namespace">
|
||||||
<h5 class="namespace-header">Current namespace</h5>
|
<h5 class="namespace-header">Current namespace</h5>
|
||||||
<div class="level is-mobile namespace-link">
|
<div class="level is-mobile namespace-link">
|
||||||
<span class="level-left">{{or namespacePath "root"}}</span>
|
<span class="level-left">{{if namespacePath (concat namespacePath "/") "root"}}</span>
|
||||||
<ICon @glyph="checkmark-circled-outline" @size="16" @class="has-text-success level-right" />
|
<ICon @glyph="checkmark-circled-outline" @size="16" @class="has-text-success level-right" />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{{#if showMessage}}
|
{{#if showMessage}}
|
||||||
<p class="namespace-reminder">
|
<p class="namespace-reminder">
|
||||||
This {{noun}} will be {{modeVerb}} in the <span class="tag">{{namespace.path}}</span>namespace.
|
This {{noun}} will be {{modeVerb}} in the <span class="tag">{{namespace.path}}/</span>namespace.
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -18,12 +18,30 @@
|
|||||||
{{list.item.id}}
|
{{list.item.id}}
|
||||||
</Item.content>
|
</Item.content>
|
||||||
<Item.menu>
|
<Item.menu>
|
||||||
|
{{#with (concat currentNamespace (if currentNamespace "/") list.item.id) as |targetNamespace|}}
|
||||||
|
{{#if (contains targetNamespace accessibleNamespaces)}}
|
||||||
|
<li class="action">
|
||||||
|
{{#link-to "vault.cluster.secrets" (query-params namespace=targetNamespace) class="is-block"}}
|
||||||
|
Switch to namespace
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
{{/with}}
|
||||||
<li class="action">
|
<li class="action">
|
||||||
<ConfirmAction
|
<ConfirmAction
|
||||||
@confirmButtonClasses="button is-primary"
|
@confirmButtonClasses="button is-primary"
|
||||||
@confirmButtonText="Remove"
|
@confirmButtonText="Remove"
|
||||||
@buttonClasses="link is-destroy"
|
@buttonClasses="link is-destroy"
|
||||||
@onConfirmAction={{action (perform Item.callMethod "destroyRecord" list.item (concat "Successfully deleted namespace: " list.item.id) "There was an error deleting this namespace: ") }}
|
@onConfirmAction={{action
|
||||||
|
(perform
|
||||||
|
Item.callMethod
|
||||||
|
"destroyRecord"
|
||||||
|
list.item
|
||||||
|
(concat "Successfully deleted namespace: " list.item.id)
|
||||||
|
"There was an error deleting this namespace: "
|
||||||
|
(action "refreshNamespaceList")
|
||||||
|
)
|
||||||
|
}}
|
||||||
@confirmMessage={{concat "Are you sure you want to delete " list.item.id "?"}}
|
@confirmMessage={{concat "Are you sure you want to delete " list.item.id "?"}}
|
||||||
@showConfirm={{get this (concat "shouldDelete-" list.item.id)}}
|
@showConfirm={{get this (concat "shouldDelete-" list.item.id)}}
|
||||||
@class={{if (get this (concat "shouldDelete-" list.item.id)) "message is-block is-warning is-outline"}}
|
@class={{if (get this (concat "shouldDelete-" list.item.id)) "message is-block is-warning is-outline"}}
|
||||||
|
Loading…
Reference in New Issue
Block a user