Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Implement read-only KV/Session and Intention views based on ACLs #9706

Merged
merged 17 commits into from
Feb 18, 2021
Merged
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
1 change: 1 addition & 0 deletions ui/packages/consul-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ token/secret.
| `CONSUL_EXPOSED_COUNT` | (random) | Configure the number of exposed paths that the API returns. |
| `CONSUL_CHECK_COUNT` | (random) | Configure the number of health checks that the API returns. |
| `CONSUL_OIDC_PROVIDER_COUNT` | (random) | Configure the number of OIDC providers that the API returns. |
| `CONSUL_RESOURCE_<singular-resource-name>_<access-type>` | true | Configure permissions e.g `CONSUL_RESOURCE_INTENTION_WRITE=false`. |
| `DEBUG_ROUTES_ENDPOINT` | undefined | When using the window.Routes() debug utility ([see utility functions](#browser-debug-utility-functions)), use a URL to pass the route DSL to. %s in the URL will be replaced with the route DSL - http://url.com?routes=%s |

See `./mock-api` for more details.
Expand Down
20 changes: 12 additions & 8 deletions ui/packages/consul-ui/app/abilities/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,27 @@ export default class BaseAbility extends Ability {
return this.permissions.generate(this.resource, action);
}

get canCreate() {
return this.permissions.has(this.generate(ACCESS_WRITE));
get canRead() {
return this.permissions.has(this.generate(ACCESS_READ));
}

get canDelete() {
get canList() {
return this.permissions.has(this.generate(ACCESS_LIST));
}

get canWrite() {
return this.permissions.has(this.generate(ACCESS_WRITE));
}

get canRead() {
return this.permissions.has(this.generate(ACCESS_READ));
get canCreate() {
return this.canWrite;
}

get canList() {
return this.permissions.has(this.generate(ACCESS_LIST));
get canDelete() {
return this.canWrite;
}

get canUpdate() {
return this.permissions.has(this.generate(ACCESS_WRITE));
return this.canWrite;
}
}
4 changes: 4 additions & 0 deletions ui/packages/consul-ui/app/abilities/intention.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ import BaseAbility from './base';

export default class IntentionAbility extends BaseAbility {
resource = 'intention';

get canWrite() {
return super.canWrite && (typeof this.item === 'undefined' || this.item.IsEditable);
}
}
5 changes: 5 additions & 0 deletions ui/packages/consul-ui/app/abilities/session.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import BaseAbility from './base';

export default class SessionAbility extends BaseAbility {
resource = 'session';
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ as |api|>

<BlockSlot @name="form">
{{#let api.data as |item|}}
{{#if item.IsEditable}}
{{#if (can 'write intention' item=item)}}

{{#if this.warn}}
{{#let (changeset-get item 'Action') as |newAction|}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ as |item index|>
More
</BlockSlot>
<BlockSlot @name="menu" as |confirm send keypressClick change|>
{{#if item.IsEditable}}
{{#if (can "write intention" item=item)}}
<li role="none">
<a role="menuitem" tabindex="-1" href={{href-to (or routeName 'dc.intentions.edit') item.ID}}>Edit</a>
</li>
Expand Down
33 changes: 29 additions & 4 deletions ui/packages/consul-ui/app/components/consul/kv/form/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
as |api|
>
<BlockSlot @name="content">
{{#let (cannot 'write kv' item=api.data) as |disabld|}}
<form onsubmit={{action api.submit}}>
<fieldset disabled={{api.disabled}}>
<fieldset
{{disabled (or disabld api.disabled)}}
>
{{#if api.isCreate}}
<label class="type-text{{if api.data.error.Key ' has-error'}}">
<span>Key or folder</span>
Expand All @@ -24,27 +27,47 @@
<div>
<div class="type-toggle">
<label>
<input type="checkbox" name="json" checked={{if json 'checked'}} onchange={{action api.change}} />
<input
type="checkbox"
name="json"
{{disabled false}}
checked={{if json 'checked'}}
onchange={{action api.change}}
/>
<span>Code</span>
</label>
</div>
<label for="" class="type-text{{if api.data.error.Value ' has-error'}}">
<span>Value</span>
{{#if json}}
<CodeEditor @name="value" @value={{atob api.data.Value}} @onkeyup={{action api.change "value"}} />
<CodeEditor
@name="value"
@readonly={{or disabld api.disabled}}
@value={{atob api.data.Value}}
@onkeyup={{action api.change "value"}}
/>
{{else}}
<textarea autofocus={{not api.isCreate}} name="value" oninput={{action api.change}}>{{atob api.data.Value}}</textarea>
<textarea
{{disabled (or disabld api.disabled)}}
autofocus={{not api.isCreate}}
name="value"
oninput={{action api.change}}>{{atob api.data.Value}}</textarea>
{{/if}}
</label>
</div>
{{/if}}
</fieldset>
{{#if api.isCreate}}
{{#if (not disabld)}}
<button type="submit" disabled={{or api.data.isPristine api.data.isInvalid api.disabled}}>Save</button>
{{/if}}
<button type="reset" onclick={{action oncancel api.data}} disabled={{api.disabled}}>Cancel</button>
{{else}}
{{#if (not disabld)}}
<button type="submit" disabled={{or api.data.isInvalid api.disabled}}>Save</button>
{{/if}}
<button type="reset" onclick={{action oncancel api.data}} disabled={{api.disabled}}>Cancel</button>
{{#if (not disabld)}}
<ConfirmationDialog @message="Are you sure you want to delete this key?">
<BlockSlot @name="action" as |confirm|>
<button data-test-delete type="button" class="type-delete" {{action confirm api.delete}} disabled={{api.disabled}}>Delete</button>
Expand All @@ -54,6 +77,8 @@
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{/if}}
</form>
{{/let}}
</BlockSlot>
</DataForm>
6 changes: 6 additions & 0 deletions ui/packages/consul-ui/app/components/consul/kv/list/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ as |item index|>
More
</BlockSlot>
<BlockSlot @name="menu" as |confirm send keypressClick|>
{{#if (can 'write kv' item=item)}}
<li role="none">
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>{{if item.isFolder 'View' 'Edit'}}</a>
</li>
Expand Down Expand Up @@ -55,6 +56,11 @@ as |item index|>
</InformedAction>
</div>
</li>
{{else}}
<li role="none">
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to (if item.isFolder 'dc.kv.folder' 'dc.kv.edit') item.Key}}>View</a>
</li>
{{/if}}
</BlockSlot>
</PopoverMenu>
</BlockSlot>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
</dd>
{{/if}}
</dl>
{{#if (can 'delete session' item=api.data)}}
<ConfirmationDialog @message="Are you sure you want to invalidate this session?">
<BlockSlot @name="action" as |confirm|>
<button type="button" data-test-delete class="type-delete" {{action confirm api.delete session}} disabled={{api.disabled}}>Invalidate Session</button>
Expand All @@ -53,6 +54,7 @@
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
</BlockSlot>
</ConfirmationDialog>
{{/if}}
</div>
</BlockSlot>
</DataForm>
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
</dd>
</dl>
</BlockSlot>
{{#if (can "delete sessions")}}
<BlockSlot @name="actions">
<ConfirmationDialog @message="Are you sure you want to invalidate this session?">
<BlockSlot @name="action" as |confirm|>
Expand All @@ -70,5 +71,6 @@
</BlockSlot>
</ConfirmationDialog>
</BlockSlot>
{{/if}}
</ListCollection>
{{/if}}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
returns=(set this 'popoverController')
}}
{{on 'click' (fn (optional this.popoverController.show))}}
{{disabled (cannot 'update intention' item=item.Intention)}}
type="button"
style={{{concat 'top:' @position.y 'px;left:' @position.x 'px;'}}}
aria-label={{if (eq @type 'deny') 'Add intention' 'View intention'}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
background-color: $white;
padding: 1px 1px;
&:hover {
cursor:pointer;
cursor: pointer;
}
&:active, &:focus {
outline: none;
}
&:disabled {
cursor: default;
}
}
&.deny .informed-action header::before {
display: none;
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/consul-ui/app/instance-initializers/nspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export function initialize(container) {
.filter(function(item) {
return item.startsWith('dc');
})
.filter(function(item) {
return item.endsWith('path');
})
.map(function(item) {
return item.replace('._options.path', '').replace(dotRe, '/');
})
Expand Down
17 changes: 17 additions & 0 deletions ui/packages/consul-ui/app/modifiers/disabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { modifier } from 'ember-modifier';

export default modifier(function enabled($element, [bool], hash) {
if (['input', 'textarea', 'select', 'button'].includes($element.nodeName.toLowerCase())) {
if (bool) {
$element.disabled = bool;
} else {
$element.dataset.disabled = false;
}
return;
}
for (const $el of $element.querySelectorAll('input,textarea')) {
if ($el.dataset.disabled !== 'false') {
$el.disabled = bool;
}
}
});
20 changes: 16 additions & 4 deletions ui/packages/consul-ui/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,16 @@ export const routes = {
intentions: {
_options: { path: '/intentions' },
edit: {
_options: { path: '/:intention_id' },
_options: {
path: '/:intention_id',
abilities: ['read intentions'],
},
},
create: {
_options: { path: '/create' },
_options: {
path: '/create',
abilities: ['create intentions'],
},
},
},
// Key/Value
Expand All @@ -107,10 +113,16 @@ export const routes = {
_options: { path: '/*key/edit' },
},
create: {
_options: { path: '/*key/create' },
_options: {
path: '/*key/create',
abilities: ['create kvs'],
},
},
'root-create': {
_options: { path: '/create' },
_options: {
path: '/create',
abilities: ['create kvs'],
},
},
},
// ACLs
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/consul-ui/app/routes/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default Route.extend(WithBlockingActions, {
error: function(e, transition) {
// TODO: Normalize all this better
let error = {
status: e.code || '',
status: e.code || e.statusCode || '',
message: e.message || e.detail || 'Error',
};
if (e.errors && e.errors[0]) {
Expand Down
10 changes: 4 additions & 6 deletions ui/packages/consul-ui/app/routes/dc/kv/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import { get } from '@ember/object';
import ascend from 'consul-ui/utils/ascend';

export default class EditRoute extends Route {
@service('repository/kv')
repo;

@service('repository/session')
sessionRepo;
@service('repository/kv') repo;
@service('repository/session') sessionRepo;
@service('repository/permission') permissions;

model(params) {
const create =
Expand Down Expand Up @@ -39,7 +37,7 @@ export default class EditRoute extends Route {
// TODO: Consider loading this after initial page load
if (typeof model.item !== 'undefined') {
const session = get(model.item, 'Session');
if (session) {
if (session && this.permissions.can('read sessions')) {
return hash({
...model,
...{
Expand Down
Loading