Skip to content

Commit eeb124c

Browse files
committed
latest changes
1 parent 32b7ad1 commit eeb124c

22 files changed

Lines changed: 622 additions & 80 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Widget::IamDashboardWidget @endpoint="privileged-access" @title="Access Risk" @subtitle="Privileged exposure requiring review" @icon="user-lock" as |data|>
2+
<div class="iam-stat-grid iam-stat-grid-3 iam-risk-summary">
3+
<div class="iam-stat-card"><span>{{data.privileged_roles_count}}</span><small>Admin roles</small></div>
4+
<div class="iam-stat-card"><span>{{data.wildcard_policies_count}}</span><small>Wildcard policies</small></div>
5+
<div class="iam-stat-card"><span>{{data.direct_privileged_grants}}</span><small>Direct grants</small></div>
6+
</div>
7+
<div class="iam-scroll-list mt-3">
8+
{{#each data.roles as |role|}}
9+
<div class="iam-list-row iam-risk-row">
10+
<div class="min-w-0">
11+
<div class="iam-list-title">{{role.name}}</div>
12+
<div class="iam-list-subtitle">{{role.type}}</div>
13+
</div>
14+
<strong>{{role.permissions_count}}</strong>
15+
</div>
16+
{{else}}
17+
<div class="iam-widget-empty">No privileged access risks detected</div>
18+
{{/each}}
19+
</div>
20+
</Widget::IamDashboardWidget>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Component from '@glimmer/component';
2+
3+
export default class WidgetAccessRiskComponent extends Component {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Widget::IamDashboardWidget
2+
@endpoint="users-by-type-created"
3+
@title="Users by Type Created Over Time"
4+
@subtitle="New identities grouped by user type"
5+
@icon="chart-column"
6+
as |data|
7+
>
8+
<div class="iam-chart-frame iam-chart-frame-tall">
9+
<Chart @type="bar" @labels={{data.labels}} @datasets={{data.datasets}} @options={{this.chartOptions}} />
10+
</div>
11+
</Widget::IamDashboardWidget>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Component from '@glimmer/component';
2+
3+
export default class WidgetUserTypeCreationTrendComponent extends Component {
4+
get chartOptions() {
5+
return {
6+
responsive: true,
7+
maintainAspectRatio: false,
8+
plugins: {
9+
legend: { position: 'bottom' },
10+
tooltip: { mode: 'index', intersect: false },
11+
},
12+
scales: {
13+
x: { stacked: true, grid: { display: false }, ticks: { font: { size: 10 } } },
14+
y: { stacked: true, ticks: { precision: 0, font: { size: 10 } } },
15+
},
16+
};
17+
}
18+
}

addon/controllers/application.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import Controller from '@ember/controller';
2+
import { inject as service } from '@ember/service';
3+
import { action } from '@ember/object';
4+
5+
export default class ApplicationController extends Controller {
6+
@service intl;
7+
@service abilities;
8+
@service fetch;
9+
10+
get navigationItems() {
11+
return [
12+
{
13+
label: this.intl.t('iam.common.dashboard'),
14+
description: 'Identity and access overview.',
15+
tooltip: true,
16+
icon: 'home',
17+
route: 'console.iam.home',
18+
keywords: ['home', 'overview', 'metrics'],
19+
},
20+
{
21+
label: this.intl.t('iam.common.user'),
22+
description: 'Manage identities and account types.',
23+
icon: 'id-card',
24+
route: 'console.iam.users',
25+
permission: 'iam list user',
26+
visible: this.can('iam see user'),
27+
keywords: ['identity', 'accounts', 'members'],
28+
children: [
29+
{
30+
label: 'Users',
31+
description: 'All console users.',
32+
icon: 'user',
33+
route: 'console.iam.users.index',
34+
permission: 'iam list user',
35+
visible: this.can('iam see user'),
36+
keywords: ['people', 'members'],
37+
},
38+
{
39+
label: 'Drivers',
40+
description: 'Driver accounts.',
41+
icon: 'id-card',
42+
route: 'console.iam.users.drivers',
43+
permission: 'iam list user',
44+
visible: this.can('iam see user'),
45+
keywords: ['fleet operators'],
46+
},
47+
{
48+
label: 'Customers',
49+
description: 'Customer accounts.',
50+
icon: 'users',
51+
route: 'console.iam.users.customers',
52+
permission: 'iam list user',
53+
visible: this.can('iam see user'),
54+
keywords: ['clients'],
55+
},
56+
],
57+
},
58+
{
59+
label: this.intl.t('iam.common.group'),
60+
description: 'Organize users into access groups.',
61+
icon: 'building',
62+
route: 'console.iam.groups',
63+
permission: 'iam list group',
64+
visible: this.can('iam see group'),
65+
keywords: ['teams', 'memberships'],
66+
},
67+
{
68+
label: this.intl.t('iam.common.roles'),
69+
description: 'Define reusable permission bundles.',
70+
icon: 'tag',
71+
route: 'console.iam.roles',
72+
permission: 'iam list role',
73+
visible: this.can('iam see role'),
74+
keywords: ['access levels'],
75+
},
76+
{
77+
label: this.intl.t('iam.common.policies'),
78+
description: 'Manage fine-grained access policies.',
79+
icon: 'shield',
80+
route: 'console.iam.policies',
81+
permission: 'iam list policy',
82+
visible: this.can('iam see policy'),
83+
keywords: ['permissions', 'rules'],
84+
},
85+
];
86+
}
87+
88+
can(permission) {
89+
try {
90+
return this.abilities.can(permission);
91+
} catch (_) {
92+
return true;
93+
}
94+
}
95+
96+
@action
97+
async searchNavigation({ query, limit = 12 }) {
98+
const trimmedQuery = query?.trim();
99+
100+
if (!trimmedQuery) {
101+
return [];
102+
}
103+
104+
try {
105+
const response = await this.fetch.get('iam/search', {
106+
query: trimmedQuery,
107+
limit,
108+
});
109+
110+
return response.results ?? [];
111+
} catch (_) {
112+
return [];
113+
}
114+
}
115+
}

addon/controllers/groups/index.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default class GroupsIndexController extends Controller {
2323
*
2424
* @var {Array}
2525
*/
26-
queryParams = ['page', 'limit', 'sort', 'query', 'type', 'created_by', 'updated_by', 'status'];
26+
queryParams = ['view_group', 'page', 'limit', 'sort', 'query', 'type', 'created_by', 'updated_by', 'status'];
2727

2828
/**
2929
* The current page of data being viewed
@@ -45,6 +45,7 @@ export default class GroupsIndexController extends Controller {
4545
* @var {Integer}
4646
*/
4747
@tracked query;
48+
@tracked view_group;
4849

4950
/**
5051
* The param to sort the data on, the param with prepended `-` is descending
@@ -271,4 +272,32 @@ export default class GroupsIndexController extends Controller {
271272
},
272273
});
273274
}
275+
276+
@action async openDeepLinkedResource() {
277+
const resourceId = this.view_group;
278+
279+
if (!resourceId) {
280+
return;
281+
}
282+
283+
try {
284+
const record = this.store.peekRecord('group', resourceId) ?? (await this.store.findRecord('group', resourceId));
285+
this.editGroup(record, {
286+
onDecline: this.clearDeepLinkedResource,
287+
onFinish: this.clearDeepLinkedResource,
288+
});
289+
} catch (_) {
290+
this.notifications.warning('Unable to open the selected IAM resource.');
291+
this.clearDeepLinkedResource();
292+
}
293+
}
294+
295+
@action clearDeepLinkedResource() {
296+
if (!this.view_group) {
297+
return;
298+
}
299+
300+
this.view_group = null;
301+
this.hostRouter.transitionTo({ queryParams: { view_group: null } });
302+
}
274303
}

addon/controllers/policies/index.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default class PoliciesIndexController extends Controller {
2323
*
2424
* @var {Array}
2525
*/
26-
queryParams = ['page', 'limit', 'sort', 'query', 'type', 'created_by', 'updated_by', 'status', 'service', 'type'];
26+
queryParams = ['view_policy', 'page', 'limit', 'sort', 'query', 'type', 'created_by', 'updated_by', 'status', 'service', 'type'];
2727

2828
/**
2929
* The current page of data being viewed
@@ -45,6 +45,7 @@ export default class PoliciesIndexController extends Controller {
4545
* @var {Integer}
4646
*/
4747
@tracked query;
48+
@tracked view_policy;
4849

4950
/**
5051
* The param to sort the data on, the param with prepended `-` is descending
@@ -244,7 +245,7 @@ export default class PoliciesIndexController extends Controller {
244245
*/
245246
@action editPolicy(policy, options = {}) {
246247
if (!policy.is_mutable) {
247-
return this.viewPolicyPermissions(policy);
248+
return this.viewPolicyPermissions(policy, options);
248249
}
249250

250251
const formPermission = 'iam update policy';
@@ -282,12 +283,13 @@ export default class PoliciesIndexController extends Controller {
282283
* @param {PolicyModel} policy
283284
* @memberof PoliciesIndexController
284285
*/
285-
@action viewPolicyPermissions(policy) {
286+
@action viewPolicyPermissions(policy, options = {}) {
286287
this.modalsManager.show('modals/view-policy-permissions', {
287288
title: this.intl.t('iam.components.modals.view-policy-permissions.view-permissions', { policyName: policy.name }),
288289
hideDeclineButton: true,
289290
acceptButtonText: this.intl.t('common.done'),
290291
policy,
292+
...options,
291293
});
292294
}
293295

@@ -335,4 +337,32 @@ export default class PoliciesIndexController extends Controller {
335337
@action reload() {
336338
return this.hostRouter.refresh();
337339
}
340+
341+
@action async openDeepLinkedResource() {
342+
const resourceId = this.view_policy;
343+
344+
if (!resourceId) {
345+
return;
346+
}
347+
348+
try {
349+
const record = this.store.peekRecord('policy', resourceId) ?? (await this.store.findRecord('policy', resourceId));
350+
this.editPolicy(record, {
351+
onDecline: this.clearDeepLinkedResource,
352+
onFinish: this.clearDeepLinkedResource,
353+
});
354+
} catch (_) {
355+
this.notifications.warning('Unable to open the selected IAM resource.');
356+
this.clearDeepLinkedResource();
357+
}
358+
}
359+
360+
@action clearDeepLinkedResource() {
361+
if (!this.view_policy) {
362+
return;
363+
}
364+
365+
this.view_policy = null;
366+
this.hostRouter.transitionTo({ queryParams: { view_policy: null } });
367+
}
338368
}

addon/controllers/roles/index.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default class RolesIndexController extends Controller {
2323
*
2424
* @var {Array}
2525
*/
26-
queryParams = ['page', 'limit', 'sort', 'query', 'service', 'type'];
26+
queryParams = ['view_role', 'page', 'limit', 'sort', 'query', 'service', 'type'];
2727

2828
/**
2929
* The current page of data being viewed
@@ -45,6 +45,7 @@ export default class RolesIndexController extends Controller {
4545
* @var {Integer}
4646
*/
4747
@tracked query;
48+
@tracked view_role;
4849

4950
/**
5051
* The param to sort the data on, the param with prepended `-` is descending
@@ -253,7 +254,7 @@ export default class RolesIndexController extends Controller {
253254
*/
254255
@action editRole(role, options = {}) {
255256
if (!role.is_mutable) {
256-
return this.viewRolePermissions(role);
257+
return this.viewRolePermissions(role, options);
257258
}
258259

259260
const formPermission = 'iam update role';
@@ -335,12 +336,13 @@ export default class RolesIndexController extends Controller {
335336
* @param {RoleModel} role
336337
* @memberof RolesIndexController
337338
*/
338-
@action viewRolePermissions(role) {
339+
@action viewRolePermissions(role, options = {}) {
339340
this.modalsManager.show('modals/view-role-permissions', {
340341
title: this.intl.t('iam.components.modals.view-role-permissions.view-permissions', { roleName: role.name }),
341342
hideDeclineButton: true,
342343
acceptButtonText: this.intl.t('common.done'),
343344
role,
345+
...options,
344346
});
345347
}
346348

@@ -359,4 +361,32 @@ export default class RolesIndexController extends Controller {
359361
@action reload() {
360362
return this.hostRouter.refresh();
361363
}
364+
365+
@action async openDeepLinkedResource() {
366+
const resourceId = this.view_role;
367+
368+
if (!resourceId) {
369+
return;
370+
}
371+
372+
try {
373+
const record = this.store.peekRecord('role', resourceId) ?? (await this.store.findRecord('role', resourceId));
374+
this.editRole(record, {
375+
onDecline: this.clearDeepLinkedResource,
376+
onFinish: this.clearDeepLinkedResource,
377+
});
378+
} catch (_) {
379+
this.notifications.warning('Unable to open the selected IAM resource.');
380+
this.clearDeepLinkedResource();
381+
}
382+
}
383+
384+
@action clearDeepLinkedResource() {
385+
if (!this.view_role) {
386+
return;
387+
}
388+
389+
this.view_role = null;
390+
this.hostRouter.transitionTo({ queryParams: { view_role: null } });
391+
}
362392
}

0 commit comments

Comments
 (0)