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: Auth Methods List view #9617

Merged
merged 33 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
21072b4
Create mock-api endpoints for auth-methods
kaxcode Jan 12, 2021
b53eb96
Implement auth-method endpoints and model with tests
kaxcode Jan 15, 2021
a7135b2
Create route and tab for auth-methods
kaxcode Jan 15, 2021
049580e
Create auth-method list and type components with styles
kaxcode Jan 21, 2021
15438bc
Add JWT and OIDC svg logos to codebase
kaxcode Jan 21, 2021
6060443
Add brand translations
kaxcode Jan 21, 2021
dc6ff75
Add SearchBar to Auth Methods
kaxcode Jan 21, 2021
4eda507
Add acceptance test for Auth Methods UI
kaxcode Jan 21, 2021
d20a342
Skip auth method repo test
kaxcode Jan 22, 2021
890e6e4
Changes from review notes
kaxcode Jan 25, 2021
e35ae5a
Fixup auth-method modela and mock-data
kaxcode Jan 27, 2021
213de03
Update SearhBar with rebased changes
kaxcode Jan 28, 2021
ae921b3
Add filterBy source and sortBy max token ttl
kaxcode Jan 28, 2021
da3eb48
Update to SortBy MethodName
kaxcode Jan 29, 2021
d0e7c6f
Update UI acceptance tests
kaxcode Jan 29, 2021
5db3aac
Update mock data DisplayNames
kaxcode Jan 29, 2021
f3b85d2
Skip repo test
kaxcode Feb 1, 2021
a692a07
Fix to breaking serializer test
kaxcode Feb 2, 2021
d8d70f6
Implement auth-method endpoints and model with tests
kaxcode Jan 15, 2021
cd00f7b
Add acceptance test for Auth Methods UI
kaxcode Jan 21, 2021
31c6a16
Update SearhBar with rebased changes
kaxcode Jan 28, 2021
8d20dbb
Add filterBy source and sortBy max token ttl
kaxcode Jan 28, 2021
3a6715a
Update to SortBy MethodName
kaxcode Jan 29, 2021
a0a22ad
Update UI acceptance tests
kaxcode Jan 29, 2021
5d96185
Update mock data DisplayNames
kaxcode Jan 29, 2021
8bfda1d
Fix to breaking serializer test
kaxcode Feb 2, 2021
9b81e2f
Update class for search
kaxcode Feb 3, 2021
4dd97e9
Add auth-methods link to sidebar
kaxcode Feb 3, 2021
90170dc
Fixup PR review notes
kaxcode Feb 3, 2021
76be052
Fixup review notes
kaxcode Feb 4, 2021
9d4b3ce
Only show OIDC filter with enterprise
kaxcode Feb 8, 2021
149b57c
Update conditionals for MaxTokenTTL & TokenLocality
kaxcode Feb 16, 2021
2e53fcb
Refactor
kaxcode Feb 17, 2021
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
28 changes: 28 additions & 0 deletions ui/packages/consul-ui/app/adapters/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Adapter from './application';

export default class AuthMethodAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id }) {
return request`
GET /v1/acl/auth-methods?${{ dc }}

${{
...this.formatNspace(ns),
index,
}}
`;
}

requestForQueryRecord(request, { dc, ns, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/acl/auth-method/${id}?${{ dc }}

${{
...this.formatNspace(ns),
index,
}}
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.consul-auth-method-list ul {
.consul-auth-method-type {
@extend %pill-200, %frame-gray-600;
}
.locality::before {
@extend %with-public-default-mask, %as-pseudo;
margin-right: 4px;
}
}
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<ListCollection
class="consul-auth-method-list"
@items={{@items}}
as |item|>
<BlockSlot @name="header">
{{#if (not-eq item.DisplayName '')}}
<p data-test-auth-method>{{item.DisplayName}}</p>
{{else}}
<p data-test-auth-method>{{item.Name}}</p>
{{/if}}
</BlockSlot>
<BlockSlot @name="details">
<Consul::AuthMethod::Type @item={{item}} />
{{#if (not-eq item.DisplayName '')}}
<span data-test-display-name>{{item.Name}}</span>
{{/if}}
{{#if (eq item.TokenLocality 'global')}}
<span class="locality">creates global tokens</span>
{{/if}}
{{#if item.MaxTokenTTL}}
<dl class="ttl">
<dt>
<Tooltip>
Maximum Time to Live: the maximum life of any token created by this auth method
</Tooltip>
</dt>
<dd>{{item.MaxTokenTTL}}</dd>
</dl>
{{/if}}
</BlockSlot>
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
</ListCollection>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default (collection, text) => () => {
return collection('.consul-auth-method-list [data-test-list-row]', {
name: text('[data-test-auth-method]'),
displayName: text('[data-test-display-name]'),
type: text('[data-test-type]'),
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<SearchBar
class="consul-auth-method-search-bar"
...attributes
@filter={{@filter}}
>
<:status as |search|>

{{#let

(t (concat "components.consul.auth-method.search-bar." search.status.key ".name")
default=(array
(concat "common.search." search.status.key)
(concat "common.consul." search.status.key)
)
)

(t (concat "components.consul.auth-method.search-bar." search.status.key ".options." search.status.value)
default=(array
(concat "common.search." search.status.value)
(concat "common.consul." search.status.value)
(concat "common.brand." search.status.value)
)
)

as |key value|}}
<search.RemoveFilter
aria-label={{t "common.ui.remove" item=(concat key " " value)}}
>
<dl>
<dt>{{key}}</dt>
<dd>{{value}}</dd>
</dl>
</search.RemoveFilter>
{{/let}}

</:status>
<:search as |search|>
<search.Search
@onsearch={{action @onsearch}}
@value={{@search}}
@placeholder={{t "common.search.search"}}
>
<search.Select
class="type-search-properties"
@position="right"
@onchange={{action @filter.searchproperty.change}}
@multiple={{true}}
@required={{true}}
as |components|>
<BlockSlot @name="selected">
<span>
{{t "common.search.searchproperty"}}
</span>
</BlockSlot>
<BlockSlot @name="options">
{{#let components.Optgroup components.Option as |Optgroup Option|}}
{{#each @filter.searchproperty.default as |prop|}}
<Option @value={{prop}} @selected={{contains prop @filter.searchproperty.value}}>
{{t (concat "common.consul." (lowercase prop))}}
</Option>
{{/each}}
{{/let}}
</BlockSlot>
</search.Select>
</search.Search>
</:search>
<:filter as |search|>
<search.Select
class="type-kind"
@position="left"
@onchange={{action @filter.kind.change}}
@multiple={{true}}
as |components|>
<BlockSlot @name="selected">
<span>
{{t "components.consul.auth-method.search-bar.kind.name"}}
</span>
</BlockSlot>
<BlockSlot @name="options">
{{#let components.Optgroup components.Option as |Optgroup Option|}}
<Option class="kubernetes" @value="kubernetes" @selected={{contains 'kubernetes' @filter.kind.value}}>Kubernetes</Option>
<Option class="jwt" @value="jwt" @selected={{contains 'jwt' @filter.kind.value}}>JWT</Option>
{{#if (env 'CONSUL_SSO_ENABLED')}}
<Option class="oidc" @value="oidc" @selected={{contains 'oidc' @filter.kind.value}}>OIDC</Option>
{{/if}}
{{/let}}
</BlockSlot>
</search.Select>
<search.Select
class="type-locality"
@position="left"
@onchange={{action @filter.source.change}}
@multiple={{true}}
as |components|>
<BlockSlot @name="selected">
<span>
{{t "components.consul.auth-method.search-bar.locality.name"}}
</span>
</BlockSlot>
<BlockSlot @name="options">
{{#let components.Optgroup components.Option as |Optgroup Option|}}
{{#each (array "local" "global") as |option|}}
<Option class="{{option}}" @value={{option}} @selected={{contains option @filter.types}}>
{{t (concat "components.consul.auth-method.search-bar.locality.options." option)}}
</Option>
{{/each}}
{{/let}}
</BlockSlot>
</search.Select>
</:filter>
<:sort as |search|>
<search.Select
class="type-sort"
data-test-sort-control
@position="right"
@onchange={{action @sort.change}}
@multiple={{false}}
@required={{true}}
as |components|>
<BlockSlot @name="selected">
<span>
{{#let (from-entries (array
(array "MethodName:asc" (t "common.sort.alpha.asc"))
(array "MethodName:desc" (t "common.sort.alpha.desc"))
(array "MaxTokenTTL:desc" (t "common.sort.duration.asc"))
(array "MaxTokenTTL:asc" (t "common.sort.duration.desc"))
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
))
as |selectable|
}}
{{get selectable @sort.value}}
{{/let}}
</span>
</BlockSlot>
<BlockSlot @name="options">
{{#let components.Optgroup components.Option as |Optgroup Option|}}
<Optgroup @label={{t "common.ui.name"}}>
<Option @value="MethodName:asc" @selected={{eq "MethodName:asc" @sort.value}}>{{t "common.sort.alpha.asc"}}</Option>
<Option @value="MethodName:desc" @selected={{eq "MethodName:desc" @sort.value}}>{{t "common.sort.alpha.desc"}}</Option>
</Optgroup>
<Optgroup @label={{t "common.ui.maxttl"}}>
<Option @value="MaxTokenTTL:desc" @selected={{eq "MaxTokenTTL:desc" @sort.value}}>{{t "common.sort.duration.asc"}}</Option>
<Option @value="MaxTokenTTL:asc" @selected={{eq "MaxTokenTTL:asc" @sort.value}}>{{t "common.sort.duration.desc"}}</Option>
</Optgroup>
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
{{/let}}
</BlockSlot>
</search.Select>
</:sort>
</SearchBar>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<span class="consul-auth-method-type {{@item.Type}}" data-test-type={{@item.Type}}>
{{t (concat "common.brand." @item.Type)}}
</span>
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
<li data-test-main-nav-roles class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}>
<a href={{href-to 'dc.acls.roles' @dc.Name}}>Roles</a>
</li>
<li data-test-main-nav-auth-methods class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}>
<a href={{href-to 'dc.acls.auth-methods' @dc.Name}}>Auth Methods</a>
</li>
</ul>
{{/if}}

Expand Down
11 changes: 11 additions & 0 deletions ui/packages/consul-ui/app/filter/predicates/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
kind: {
kubernetes: (item, value) => item.Type === value,
jwt: (item, value) => item.Type === value,
oidc: (item, value) => item.Type === value,
},
source: {
local: (item, value) => item.TokenLocality === value,
global: (item, value) => item.TokenLocality === value,
},
};
5 changes: 4 additions & 1 deletion ui/packages/consul-ui/app/instance-initializers/nspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ export function initialize(container) {
register(container, index, indexed);
}
}
register(container, route, item);

if (typeof route !== 'undefined') {
register(container, route, item);
}
});
}
}
Expand Down
24 changes: 24 additions & 0 deletions ui/packages/consul-ui/app/models/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Model, { attr } from '@ember-data/model';
import { or } from '@ember/object/computed';

export const PRIMARY_KEY = 'uid';
export const SLUG_KEY = 'Name';

export default class AuthMethod extends Model {
@attr('string') uid;
@attr('string') Name;

@attr('string') Datacenter;
@attr('string') Namespace;
@attr('string', { defaultValue: () => '' }) Description;
@attr('string', { defaultValue: () => '' }) DisplayName;
@attr('string', { defaultValue: () => 'local' }) TokenLocality;
@attr('string') Type;
@or('DisplayName', 'Name') MethodName;
@attr() Config;
@attr('string') MaxTokenTTL;
@attr('number') CreateIndex;
@attr('number') ModifyIndex;
@attr() Datacenters; // string[]
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
@attr() meta; // {}
}
6 changes: 6 additions & 0 deletions ui/packages/consul-ui/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ export const routes = {
_options: { path: '/create' },
},
},
'auth-methods': {
_options: { path: '/auth-methods' },
show: {
_options: { path: '/show' },
},
},
},
},
// Shows a datacenter picker. If you only have one
Expand Down
38 changes: 38 additions & 0 deletions ui/packages/consul-ui/app/routes/dc/acls/auth-methods/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { inject as service } from '@ember/service';
import Route from 'consul-ui/routing/route';
import { hash } from 'rsvp';

export default class IndexRoute extends Route {
@service('repository/auth-method') repo;

queryParams = {
sortBy: 'sort',
source: 'source',
kind: 'kind',
searchproperty: {
as: 'searchproperty',
empty: [['Name', 'DisplayName']],
},
search: {
as: 'filter',
replace: true,
},
};

model(params) {
return hash({
...this.repo.status({
items: this.repo.findAllByDatacenter(
this.modelFor('dc').dc.Name,
this.modelFor('nspace').nspace.substr(1)
),
}),
searchProperties: this.queryParams.searchproperty.empty[0],
});
}

setupController(controller, model) {
super.setupController(...arguments);
controller.setProperties(model);
}
}
4 changes: 4 additions & 0 deletions ui/packages/consul-ui/app/search/predicates/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
Name: item => item.Name,
DisplayName: item => item.DisplayName,
};
7 changes: 7 additions & 0 deletions ui/packages/consul-ui/app/serializers/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Serializer from './application';
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/auth-method';

export default class AuthMethodSerializer extends Serializer {
primaryKey = PRIMARY_KEY;
slugKey = SLUG_KEY;
}
2 changes: 2 additions & 0 deletions ui/packages/consul-ui/app/services/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import kv from 'consul-ui/filter/predicates/kv';
import intention from 'consul-ui/filter/predicates/intention';
import token from 'consul-ui/filter/predicates/token';
import policy from 'consul-ui/filter/predicates/policy';
import authMethod from 'consul-ui/filter/predicates/auth-method';

const predicates = {
acl: andOr(acl),
service: andOr(service),
['service-instance']: andOr(serviceInstance),
['health-check']: andOr(healthCheck),
['auth-method']: andOr(authMethod),
node: andOr(node),
kv: andOr(kv),
intention: andOr(intention),
Expand Down
26 changes: 26 additions & 0 deletions ui/packages/consul-ui/app/services/repository/auth-method.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import RepositoryService from 'consul-ui/services/repository';
import statusFactory from 'consul-ui/utils/acls-status';
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/auth-method';

const isValidServerError = isValidServerErrorFactory();
const status = statusFactory(isValidServerError, Promise);
const MODEL_NAME = 'auth-method';

export default class AuthMethodService extends RepositoryService {
getModelName() {
return MODEL_NAME;
}

getPrimaryKey() {
return PRIMARY_KEY;
}

getSlugKey() {
return SLUG_KEY;
}

status(obj) {
return status(obj);
}
kaxcode marked this conversation as resolved.
Show resolved Hide resolved
}
Loading