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

Improved RoleGraph error handling, added a "Top 2 levels" select #3667

Merged
merged 4 commits into from
Jun 6, 2024
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
9 changes: 7 additions & 2 deletions admin/tabs/userData/roles/graph/RoleGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
* Copyright © 2024 Extremely Heavy Industries Inc.
*/
import {chart} from '@xh/hoist/cmp/chart';
import {errorBoundary} from '@xh/hoist/cmp/error';
import {div, hspacer, placeholder} from '@xh/hoist/cmp/layout';
import {creates, hoistCmp} from '@xh/hoist/core';
import {button} from '@xh/hoist/desktop/cmp/button';
import {buttonGroupInput, slider} from '@xh/hoist/desktop/cmp/input';
import {buttonGroupInput, slider, switchInput} from '@xh/hoist/desktop/cmp/input';
import {panel} from '@xh/hoist/desktop/cmp/panel';
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
import {Icon} from '@xh/hoist/icon';
Expand All @@ -31,7 +32,7 @@ export const roleGraph = hoistCmp.factory({
item: div({
item: div({
style: {margin: 'auto'},
item: content()
item: errorBoundary(content())
}),
style: {
display: 'flex',
Expand Down Expand Up @@ -78,6 +79,10 @@ export const roleGraph = hoistCmp.factory({
max: 2,
stepSize: 0.005,
labelRenderer: false
}),
'Limit to one level',
switchInput({
bind: 'limitToOneLevel'
})
],
omit: !role
Expand Down
67 changes: 40 additions & 27 deletions admin/tabs/userData/roles/graph/RoleGraphModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {ChartModel} from '@xh/hoist/cmp/chart';
import {HoistModel, lookup, managed, PlainObject} from '@xh/hoist/core';
import {bindable, computed} from '@xh/hoist/mobx';
import {wait} from '@xh/hoist/promise';
import {isEmpty, isMatch, sortBy, sumBy} from 'lodash';
import {compact, isEmpty, isMatch, sortBy, sumBy} from 'lodash';
import {RoleModel} from '../RoleModel';
import {EffectiveRoleMember, HoistRole} from '../Types';

Expand All @@ -22,6 +22,8 @@ export class RoleGraphModel extends HoistModel {

@bindable widthScale: number = 1.0;

@bindable limitToOneLevel: boolean = true;

get relatedRoles(): EffectiveRoleMember[] {
const {role, relationship} = this;
if (!role) return [];
Expand All @@ -35,7 +37,7 @@ export class RoleGraphModel extends HoistModel {

@computed
get size() {
const {inverted, maxDepth, leafCount, widthScale} = this;
const {inverted, leafCount, maxDepth, widthScale} = this;
if (inverted) {
const AVG_WIDTH = 150,
AVG_HEIGHT = 26;
Expand All @@ -57,7 +59,7 @@ export class RoleGraphModel extends HoistModel {
const {chartModel} = this;
this.addReaction(
{
track: () => [this.role, this.relationship],
track: () => [this.role, this.relationship, this.limitToOneLevel],
run: async ([role]) => {
chartModel.clear(); // avoid HC rendering glitches
await wait();
Expand Down Expand Up @@ -86,15 +88,15 @@ export class RoleGraphModel extends HoistModel {
// Implementation
// -------------------------------
private getSeriesData(): PlainObject[] {
const {role, relatedRoles} = this,
{name} = role;
const {role, relatedRoles, limitToOneLevel} = this,
{name: rootName} = role;
if (isEmpty(relatedRoles)) return [];
const alreadyAdded = new Set<string>();
return [
{
id: name,
id: rootName,
// Replace spaces with non-breaking spaces to prevent wrapping.
name: name.replaceAll(' ', '&nbsp'),
name: rootName.replaceAll(' ', '&nbsp'),
dataLabels: {
style: {
fontWeight: 600
Expand All @@ -105,24 +107,28 @@ export class RoleGraphModel extends HoistModel {
fillColor: 'var(--xh-bg-alt)'
}
},
...sortBy(relatedRoles, 'name').flatMap(({name, sourceRoles}) =>
[...sourceRoles]
.sort((a, b) => {
if (a === role.name) return -1;
if (b === role.name) return 1;
return a > b ? 1 : -1;
})
.map(source => {
// Adds a space to the id to differentiate subsequent nodes from the single expanded one.
const id = alreadyAdded.has(name) ? `${name} ` : name;
alreadyAdded.add(name);
return {
id,
// Replace spaces with non-breaking spaces to prevent wrapping.
name: name.replaceAll(' ', '&nbsp'),
parent: source
};
})
...compact(
sortBy(relatedRoles, 'name').flatMap(({name, sourceRoles}) =>
[...sourceRoles]
.sort((a, b) => {
if (a === role.name) return -1;
if (b === role.name) return 1;
return a > b ? 1 : -1;
})
.map(source => {
// Omit all non-root nodes if limitToOneLevel is true
if (limitToOneLevel && source !== rootName) return null;
// Adds a space to the id to differentiate subsequent nodes from the single expanded one.
const id = alreadyAdded.has(name) ? `${name} ` : name;
alreadyAdded.add(name);
return {
id,
// Replace spaces with non-breaking spaces to prevent wrapping.
name: name.replaceAll(' ', '&nbsp'),
parent: source
};
})
)
)
];
}
Expand Down Expand Up @@ -184,7 +190,11 @@ export class RoleGraphModel extends HoistModel {

@computed
private get leafCount(): number {
const {relatedRoles} = this;
const {relatedRoles, limitToOneLevel, role} = this;
// Limit to one level means that we only show the direct children of the root role.
if (limitToOneLevel)
return sumBy(relatedRoles, it => (it.sourceRoles.includes(role.name) ? 1 : 0));

return sumBy(relatedRoles, it => {
const hasChildren = relatedRoles.some(other => other.sourceRoles.includes(it.name)),
parentCount = it.sourceRoles.length;
Expand All @@ -195,8 +205,11 @@ export class RoleGraphModel extends HoistModel {

@computed
private get maxDepth(): number {
const {role: root, relatedRoles} = this;
const {role: root, relatedRoles, limitToOneLevel} = this;
// Only the root node.
if (isEmpty(relatedRoles)) return 1;
// Limit to one level means that we only show two levels.
if (limitToOneLevel) return 2;

const maxDepthRecursive = (roleName: string) => {
if (roleName === root.name) return 1;
Expand Down
Loading