Skip to content

Commit

Permalink
fix: tuning menu layout - colors
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryT-CG committed Dec 30, 2024
1 parent 57bcc84 commit 58d2f77
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 81 deletions.
8 changes: 8 additions & 0 deletions src/app/_ws-mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
}
}
}
@mixin readable-disabled-components {
:host ::ng-deep {
.p-component:disabled,
.p-disabled {
opacity: unset;
}
}
}

@mixin compact-dropdown-list-items {
:host ::ng-deep {
Expand Down
33 changes: 18 additions & 15 deletions src/app/workspace/workspace-menu/menu.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<!-- If menu exist -->
<p-treeTable
*ngIf="!(exceptionKey && menuNodes.length === 0 && roleFilterValue.length === 0)"
*ngIf="(!exceptionKey && menuNodes.length > 0) || (menuNodes.length === 0 && roleFilterValue.length > 0)"
#menuTree
id="ws_menu_table"
styleClass="px-2 sm:px-3 mb-3"
Expand Down Expand Up @@ -143,13 +143,13 @@
</th>
<th
id="ws_menu_table_header_row_1_2"
class="pl-4 vertical-align-top text-left border-transparent"
class="pl-5 vertical-align-top text-left border-transparent"
[attr.colspan]="displayRoles ? 1 + columns.length : 6"
>
<div class="flex flex-row justify-content-start align-items-center column-gap-4">
<div class="flex flex-row justify-content-start align-items-center column-gap-5">
<p-toggleButton
inputid="ws_menu_table_header_row_1_switch_details_n_roles"
styleClass="small-toggle-button white-space-nowrap hidden-xs"
styleClass="white-space-nowrap hidden-xs"
[onIcon]="'pi pi-search-plus'"
[offIcon]="'pi pi-lock'"
[onLabel]="'DIALOG.MENU.HEADER.DETAILS' | translate"
Expand Down Expand Up @@ -180,24 +180,26 @@
</th>
</tr>

<!-- DETAIL Columns -->
<!-- ROW 2 -->
<tr id="ws_menu_table_header_row_2">
<th id="ws_menu_table_header_row_2_1" class="pr-4 vertical-align-bottom border-transparent border-bottom-2">
<p-toggleButton
inputId="ws_menu_table_header_tree_toggle"
styleClass="small-toggle-button white-space-nowrap"
styleClass="white-space-nowrap"
[onIcon]="'pi pi-arrow-down-left-and-arrow-up-right-to-center'"
[offIcon]="'pi pi-arrow-up-right-and-arrow-down-left-from-center'"
[onLabel]="'ACTIONS.TREE.COLLAPSE_ALL' | translate"
[offLabel]="'ACTIONS.TREE.EXPAND_ALL' | translate"
[(ngModel)]="treeExpanded"
[disabled]="menuNodes.length === 0"
(onChange)="onToggleTreeViewMode($event)"
[ariaLabel]="'ACTIONS.TREE.EXPAND_ALL.TOOLTIP' | translate"
[pTooltip]="'ACTIONS.TREE.EXPAND_ALL.TOOLTIP' | translate"
tooltipPosition="top"
tooltipEvent="hover"
/>
</th>
<!-- ROW 2: DETAIL Columns -->
<ng-container *ngIf="!displayRoles">
<th
*ngFor="let col of treeDetailColumns"
Expand All @@ -212,9 +214,9 @@
</th>
</ng-container>

<!-- ROLES Columns -->
<!-- ROW 2: ROLE Columns -->
<ng-container *ngIf="displayRoles">
<!-- no filtered columns while loading and no roles => no filter -->
<!-- no filtered columns while loading and if no roles => no filter -->
<th
*ngIf="columns.length === 0"
id="ws_menu_table_header_roles_messages"
Expand All @@ -239,7 +241,7 @@
[text]="'DIALOG.MENU.HEADER.ROLES.NOT_MATCHING' | translate"
></p-message>
</th>
<!-- filtered columns => no match = no columns-->
<!-- role filter -->
<th class="p-0 hidden-xs border-bottom-none vertical-align-bottom">
<span
*ngIf="roleFilterValue.length === 0"
Expand All @@ -265,19 +267,20 @@
<span class="text-primary font-medium p-button-icon pi pi-filter-slash" aria-hidden="true"></span>
</button>
</th>
<!-- filtered columns => no match = no columns-->
<th
*ngFor="let role of columns"
class="hidden-xs text-center border-bottom-2 border-right-1 role-name"
class="p-1 hidden-xs text-center border-bottom-2 border-right-1 role-name"
[class.vertical-align-bottom]="columns.length <= 5"
[class.vertical-align-top]="columns.length > 5"
[class.bg-primary]="roleFilterValue.includes(role.name)"
(keydown.space)="onChangeRoleFilter(role.name)"
(click)="onChangeRoleFilter(role.name)"
[class.vertical-align-bottom]="columns.length > 5"
>
<a
[id]="'ws_menu_table_header_roles_' + role.name"
class="cursor-pointer"
class="p-1 cursor-pointer"
[class.bg-primary]="roleFilterValue.includes(role.name)"
tabindex="0"
(keydown.space)="onChangeRoleFilter(role.name)"
(click)="onChangeRoleFilter(role.name)"
[attr.aria-label]="'DIALOG.DATAVIEW.FILTER_CLEAR' | translate"
[pTooltip]="'DIALOG.DATAVIEW.FILTER_CLEAR' | translate"
tooltipPosition="top"
Expand Down
37 changes: 22 additions & 15 deletions src/app/workspace/workspace-menu/menu.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@include invisible;
@include danger-action;
@include displaying-text-responsive;
@include readable-disabled-components;
@include correct-select-button;
@include search-criteria-select-button-slim;
@include correct-data-view-control;
Expand All @@ -23,27 +24,33 @@
padding-bottom: 0;
overflow-y: hidden;
}

.p-togglebutton.p-button:not(.p-disabled) {
text-align: center;
padding: 0.5rem 0.8rem;
font-weight: var(--font-weight);
color: var(--primary-text-color);
background: var(--primary-color);
&:hover {
background: var(--button-hover-bg);
}
.p-button-label,
.p-button-icon-left,
.p-button-icon-right {
/* togglebuttons should look like buttons */
.p-togglebutton.p-button:not(.p-highlight),
.p-togglebutton.p-button.p-highlight {
&:not(.p-disabled) {
background: var(--primary-color);
color: var(--primary-text-color);
&:hover {
background: var(--button-hover-bg);
}
.p-button-label,
.p-button-icon-left,
.p-button-icon-right {
color: inherit;
}
}
&:not(.p-highlight):hover {
&.p-disabled {
background: var(--emphasis-lower);
color: var(--emphasis-low);
.p-button-label,
.p-button-icon-left,
.p-button-icon-right {
color: var(--primary-text-color);
color: inherit;
}
}
text-align: center;
padding: 0.5rem 0.8rem;
font-weight: var(--font-weight);
}

.p-treetable {
Expand Down
100 changes: 61 additions & 39 deletions src/app/workspace/workspace-menu/menu.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const state: MenuState = {
workspaceMenuItems: []
}

describe('MenuComponent', () => {
fdescribe('MenuComponent', () => {
let component: MenuComponent
let fixture: ComponentFixture<MenuComponent>

Expand Down Expand Up @@ -125,9 +125,8 @@ describe('MenuComponent', () => {

const mockUserService = jasmine.createSpyObj('UserService', ['hasPermission'])
mockUserService.hasPermission.and.callFake((permission: string) => {
return ['MENU#VIEW', 'MENU#EDIT', 'MENU#GRANT', 'WORKSPACE_ROLE#EDIT'].includes(permission)
return ['MENU#VIEW', 'MENU#CREATE', 'MENU#EDIT', 'MENU#GRANT', 'WORKSPACE_ROLE#EDIT'].includes(permission)
})

const mockActivatedRouteSnapshot: Partial<ActivatedRouteSnapshot> = {
params: { id: 'mockId' }
}
Expand Down Expand Up @@ -188,56 +187,75 @@ describe('MenuComponent', () => {
assgmtApiServiceSpy.searchAssignments.and.returnValue(of({}))
})

it('should create', () => {
expect(component).toBeTruthy()
})
describe('Initialize:', () => {
it('should create', () => {
expect(component).toBeTruthy()
})

it('it should push permissions to array if userService has them', () => {
expect(component.myPermissions).toContain('MENU#VIEW')
expect(component.myPermissions).toContain('MENU#EDIT')
expect(component.myPermissions).toContain('MENU#GRANT')
expect(component.myPermissions).toContain('WORKSPACE_ROLE#EDIT')
it('it should push permissions to array if userService has them', () => {
expect(component.myPermissions).toContain('MENU#VIEW')
expect(component.myPermissions).toContain('MENU#CREATE')
expect(component.myPermissions).toContain('MENU#EDIT')
expect(component.myPermissions).toContain('MENU#GRANT')
expect(component.myPermissions).toContain('WORKSPACE_ROLE#EDIT')
})
})

describe('prepare page actions', () => {
it('should have prepared action buttons onInit: onClose, and called it', () => {
fdescribe('Page actions:', () => {
beforeEach(() => {
component.ngOnInit()
})

it('should have BACK navigation', () => {
if (component.actions$) {
component.actions$.subscribe((actions) => {
const action = actions[0]
action.actionCallback()

expect(locationSpy.back).toHaveBeenCalled()
})
}
})

it('should have prepared action buttons onInit: hide Export button due to no menu items', () => {
spyOn(component, 'onExportMenu')

component.ngOnInit()
it('should call CREATE', () => {
spyOn(component, 'onCreateMenu')

if (component.actions$) {
component.actions$.subscribe((actions) => {
const action = actions[1]
action.actionCallback()
expect(component.onExportMenu).toHaveBeenCalled()

expect(action.permission).toEqual('MENU#CREATE')
//expect(component.changeMode).toEqual('CREATE')
expect(component.onCreateMenu).toHaveBeenCalled()
//expect(component.displayMenuDetail).toBeTrue()
})
}
})

it('should call EXPORT: hide button if there are no menu items', () => {
spyOn(component, 'onExportMenu')

if (component.actions$) {
component.actions$.subscribe((actions) => {
const action = actions[2]
action.actionCallback()

expect(action.permission).toEqual('MENU#EXPORT')
expect(action.showCondition).toBeFalse()
expect(component.onExportMenu).toHaveBeenCalled()
expect(component.menuItems).toEqual([])
expect(component.menuItems?.length).toBe(0)
})
}
})
it('should have prepared action buttons onInit: hide Export button due to no menu items', () => {
it('should call EXPORT', () => {
spyOn(component, 'onExportMenu')

component.ngOnInit()
component.menuItems = mockMenuItems

if (component.actions$) {
component.actions$.subscribe((actions) => {
const action = actions[1]
const action = actions[2]
action.actionCallback()
expect(component.onExportMenu).toHaveBeenCalled()
expect(action.permission).toEqual('MENU#EXPORT')
Expand All @@ -246,25 +264,24 @@ describe('MenuComponent', () => {
})
}
})
it('should have exclude some actions', () => {

it('should call EXPORT: hide on conditions', () => {
component.menuItems = undefined
component.prepareActionButtons()

if (component.actions$) {
component.actions$.subscribe((actions) => {
expect(actions[1].showCondition).toBeFalse()
expect(actions[2].showCondition).toBeFalse()
})
}
})

it('should have prepared action buttons onInit: onImportMenu', () => {
it('should call IMPORT', () => {
spyOn(component, 'onImportMenu')

component.ngOnInit()

if (component.actions$) {
component.actions$.subscribe((actions) => {
const action = actions[2]
const action = actions[3]
action.actionCallback()
expect(component.onImportMenu).toHaveBeenCalled()
})
Expand Down Expand Up @@ -510,18 +527,23 @@ describe('MenuComponent', () => {
expect(component.displayMenuDetail).toBeFalse()
})

it('should handle onCreateMenu correctly', () => {
const mockEvent = jasmine.createSpyObj('MouseEvent', ['stopPropagation'])
const mockParent = {
key: '1-1',
id: 'id1'
}
component.onCreateMenu(mockEvent, mockParent)
describe('create menu item', () => {
it('should handle onCreateMenu correctly: with parent', () => {
const mockParent = { key: '1-1', id: 'id1' }
component.onCreateMenu(mockParent)

expect(mockEvent.stopPropagation).toHaveBeenCalled()
expect(component.changeMode).toEqual('CREATE')
expect(component.menuItem).toEqual(mockParent)
expect(component.displayMenuDetail).toBeTrue()
expect(component.changeMode).toEqual('CREATE')
expect(component.menuItem).toEqual(mockParent)
expect(component.displayMenuDetail).toBeTrue()
})

it('should handle onCreateMenu correctly: without parent', () => {
component.onCreateMenu()

expect(component.changeMode).toEqual('CREATE')
expect(component.menuItem).toEqual(undefined)
expect(component.displayMenuDetail).toBeTrue()
})
})

it('should removeNodeFromTree if key is present and refresh menuNodes if delete displayed onMenuItemChanged', () => {
Expand Down
5 changes: 4 additions & 1 deletion src/app/workspace/workspace-menu/menu.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class MenuComponent implements OnInit, OnDestroy {
public parentItems!: SelectItem[]
public usedLanguages: Map<string, number> = new Map()
// detail
public changeMode: ChangeMode = 'EDIT'
public changeMode: ChangeMode = 'VIEW'
public displayMenuDetail = false
public displayMenuImport = false
public displayMenuDelete = false
Expand All @@ -124,6 +124,7 @@ export class MenuComponent implements OnInit, OnDestroy {
this.menuItems = state.workspaceMenuItems
// simplify permission checks
if (this.userService.hasPermission('MENU#VIEW')) this.myPermissions.push('MENU#VIEW')
if (this.userService.hasPermission('MENU#VIEW')) this.myPermissions.push('MENU#CREATE')
if (this.userService.hasPermission('MENU#EDIT')) this.myPermissions.push('MENU#EDIT')
if (this.userService.hasPermission('MENU#GRANT')) this.myPermissions.push('MENU#GRANT')
if (this.userService.hasPermission('WORKSPACE_ROLE#EDIT')) this.myPermissions.push('WORKSPACE_ROLE#EDIT')
Expand Down Expand Up @@ -276,6 +277,7 @@ export class MenuComponent implements OnInit, OnDestroy {

public onToggleTreeTableContent(ev: any): void {
this.displayRoles = ev.checked
if (!this.displayRoles) this.onResetRoleFilter()
this.loadRolesAndAssignments()
}
public isObjectEmpty(obj: object) {
Expand Down Expand Up @@ -336,6 +338,7 @@ export class MenuComponent implements OnInit, OnDestroy {
this.menuItem = parent
this.displayMenuDetail = true
}

// triggered by change event in menu detail dialog
public onMenuItemChanged(changed: boolean): void {
if (changed) {
Expand Down
Loading

0 comments on commit 58d2f77

Please sign in to comment.