Better visually unify management list & other list pages

This commit is contained in:
shamoon 2023-09-24 15:13:14 -07:00
parent f921af9a96
commit 3fe3af85c5
7 changed files with 97 additions and 29 deletions

View File

@ -4,7 +4,7 @@
<ng-container *ngIf="users"> <ng-container *ngIf="users">
<h4 class="d-flex"> <h4 class="d-flex">
<ng-container i18n>Users</ng-container> <ng-container i18n>Users</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editUser()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.User }"> <button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editUser()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.User }">
<svg class="sidebaricon me-1" fill="currentColor"> <svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" /> <use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg> </svg>
@ -29,8 +29,16 @@
<div class="col d-flex align-items-center">{{user.groups?.map(getGroupName, this).join(', ')}}</div> <div class="col d-flex align-items-center">{{user.groups?.map(getGroupName, this).join(', ')}}</div>
<div class="col"> <div class="col">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-sm btn-primary" type="button" (click)="editUser(user)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.User }" i18n>Edit</button> <button class="btn btn-sm btn-outline-secondary" type="button" (click)="editUser(user)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.User }">
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteUser(user)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.User }" i18n>Delete</button> <svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>&nbsp;<ng-container i18n>Edit</ng-container>
</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteUser(user)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.User }">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>&nbsp;<ng-container i18n>Delete</ng-container>
</button>
</div> </div>
</div> </div>
</div> </div>
@ -41,7 +49,7 @@
<ng-container *ngIf="groups"> <ng-container *ngIf="groups">
<h4 class="mt-4 d-flex"> <h4 class="mt-4 d-flex">
<ng-container i18n>Groups</ng-container> <ng-container i18n>Groups</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editGroup()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Group }"> <button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editGroup()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Group }">
<svg class="sidebaricon me-1" fill="currentColor"> <svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" /> <use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg> </svg>
@ -66,8 +74,16 @@
<div class="col"></div> <div class="col"></div>
<div class="col"> <div class="col">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-sm btn-primary" type="button" (click)="editGroup(group)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Group }" i18n>Edit</button> <button class="btn btn-sm btn-outline-secondary" type="button" (click)="editGroup(group)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Group }">
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteGroup(group)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Group }" i18n>Delete</button> <svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>&nbsp;<ng-container i18n>Edit</ng-container>
</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteGroup(group)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Group }">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>&nbsp;<ng-container i18n>Delete</ng-container>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -25,8 +25,16 @@
<div class="col d-flex align-items-center">{{getSourceList(template)}}</div> <div class="col d-flex align-items-center">{{getSourceList(template)}}</div>
<div class="col"> <div class="col">
<div class="btn-group"> <div class="btn-group">
<button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.ConsumptionTemplate }" class="btn btn-sm btn-primary" type="button" (click)="editTemplate(template)" i18n>Edit</button> <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.ConsumptionTemplate }" class="btn btn-sm btn-outline-secondary" type="button" (click)="editTemplate(template)">
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.ConsumptionTemplate }" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteTemplate(template)" i18n>Delete</button> <svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>&nbsp;<ng-container i18n>Edit</ng-container>
</button>
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.ConsumptionTemplate }" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteTemplate(template)">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>&nbsp;<ng-container i18n>Delete</ng-container>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailAccount }"> <ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailAccount }">
<h4> <h4>
<ng-container i18n>Mail accounts</ng-container> <ng-container i18n>Mail accounts</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailAccount()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }"> <button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editMailAccount()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }">
<svg class="sidebaricon me-1" fill="currentColor"> <svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" /> <use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg> </svg>
@ -27,9 +27,21 @@
<div class="col d-flex align-items-center">{{account.imap_server}}</div> <div class="col d-flex align-items-center">{{account.imap_server}}</div>
<div class="col"> <div class="col">
<div class="btn-group"> <div class="btn-group">
<button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-primary" type="button" (click)="editMailAccount(account)" i18n>Edit</button> <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailAccount(account)">
<button *pngxIfOwner="account" class="btn btn-sm btn-primary" type="button" (click)="editPermissions(account)" i18n>Permissions</button> <svg class="buttonicon-sm" fill="currentColor">
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)" i18n>Delete</button> <use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>&nbsp;<ng-container i18n>Edit</ng-container>
</button>
<button *pngxIfOwner="account" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(account)">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#person-lock" />
</svg>&nbsp;<ng-container i18n>Permissions</ng-container>
</button>
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>&nbsp;<ng-container i18n>Delete</ng-container>
</button>
</div> </div>
</div> </div>
</div> </div>
@ -42,7 +54,7 @@
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailRule }"> <ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailRule }">
<h4 class="mt-4"> <h4 class="mt-4">
<ng-container i18n>Mail rules</ng-container> <ng-container i18n>Mail rules</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailRule()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailRule }"> <button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editMailRule()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailRule }">
<svg class="sidebaricon me-1" fill="currentColor"> <svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" /> <use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg> </svg>
@ -65,9 +77,21 @@
<div class="col d-flex align-items-center">{{(mailAccountService.getCached(rule.account) | async)?.name}}</div> <div class="col d-flex align-items-center">{{(mailAccountService.getCached(rule.account) | async)?.name}}</div>
<div class="col"> <div class="col">
<div class="btn-group"> <div class="btn-group">
<button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" [disabled]="!userCanEdit(rule)" class="btn btn-sm btn-primary" type="button" (click)="editMailRule(rule)" i18n>Edit</button> <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" [disabled]="!userCanEdit(rule)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailRule(rule)">
<button *pngxIfOwner="rule" class="btn btn-sm btn-primary" type="button" (click)="editPermissions(rule)" i18n>Permissions</button> <svg class="buttonicon-sm" fill="currentColor">
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailRule }" [disabled]="!userIsOwner(rule)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailRule(rule)" i18n>Delete</button> <use xlink:href="assets/bootstrap-icons.svg#pencil" />
</svg>&nbsp;<ng-container i18n>Edit</ng-container>
</button>
<button *pngxIfOwner="rule" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(rule)">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#person-lock" />
</svg>&nbsp;<ng-container i18n>Permissions</ng-container>
</button>
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailRule }" [disabled]="!userIsOwner(rule)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailRule(rule)">
<svg class="buttonicon-sm" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#trash" />
</svg>&nbsp;<ng-container i18n>Delete</ng-container>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,7 +9,12 @@
<use xlink:href="assets/bootstrap-icons.svg#person-fill-lock" /> <use xlink:href="assets/bootstrap-icons.svg#person-fill-lock" />
</svg>&nbsp;<ng-container i18n>Permissions</ng-container> </svg>&nbsp;<ng-container i18n>Permissions</ng-container>
</button> </button>
<button type="button" class="btn btn-sm btn-outline-primary" (click)="openCreateDialog()" *pngxIfPermissions="{ action: PermissionAction.Add, type: permissionType }" i18n>Create</button> <button type="button" class="btn btn-sm btn-outline-primary" (click)="openCreateDialog()" *pngxIfPermissions="{ action: PermissionAction.Add, type: permissionType }" i18n>
<svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
Create
</button>
</pngx-page-header> </pngx-page-header>
<div class="row mb-3"> <div class="row mb-3">
@ -23,20 +28,21 @@
<ngb-pagination class="col-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" [maxSize]="5" (pageChange)="reloadData()" size="sm" aria-label="Pagination"></ngb-pagination> <ngb-pagination class="col-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" [maxSize]="5" (pageChange)="reloadData()" size="sm" aria-label="Pagination"></ngb-pagination>
</div> </div>
<table class="table table-striped align-middle border shadow-sm"> <div class="card border mb-3">
<table class="table table-striped align-middle shadow-sm mb-0">
<thead> <thead>
<tr> <tr>
<th scope="col"> <th scope="col">
<div class="form-check"> <div class="form-check m-0 ms-2 me-n2">
<input type="checkbox" class="form-check-input" id="all-objects" [disabled]="data.length === 0" (click)="toggleAll($event); $event.stopPropagation();"> <input type="checkbox" class="form-check-input" id="all-objects" [disabled]="data.length === 0" (click)="toggleAll($event); $event.stopPropagation();">
<label class="form-check-label" for="all-objects"></label> <label class="form-check-label" for="all-objects"></label>
</div> </div>
</th> </th>
<th scope="col" pngxSortable="name" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Name</th> <th scope="col" class="fw-normal" pngxSortable="name" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Name</th>
<th scope="col" class="d-none d-sm-table-cell" pngxSortable="matching_algorithm" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Matching</th> <th scope="col" class="fw-normal d-none d-sm-table-cell" pngxSortable="matching_algorithm" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Matching</th>
<th scope="col" pngxSortable="document_count" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Document count</th> <th scope="col" class="fw-normal" pngxSortable="document_count" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)" i18n>Document count</th>
<th scope="col" *ngFor="let column of extraColumns" pngxSortable="{{column.key}}" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)">{{column.name}}</th> <th scope="col" class="fw-normal" *ngFor="let column of extraColumns" pngxSortable="{{column.key}}" [currentSortField]="sortField" [currentSortReverse]="sortReverse" (sort)="onSort($event)">{{column.name}}</th>
<th scope="col" i18n>Actions</th> <th scope="col" class="fw-normal" i18n>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -48,12 +54,12 @@
</tr> </tr>
<tr *ngFor="let object of data" (click)="toggleSelected(object, $event); $event.stopPropagation();"> <tr *ngFor="let object of data" (click)="toggleSelected(object, $event); $event.stopPropagation();">
<td> <td>
<div class="form-check"> <div class="form-check m-0 ms-2 me-n2">
<input type="checkbox" class="form-check-input" id="{{typeName}}{{object.id}}" [checked]="selectedObjects.has(object.id)" (click)="toggleSelected(object); $event.stopPropagation();"> <input type="checkbox" class="form-check-input" id="{{typeName}}{{object.id}}" [checked]="selectedObjects.has(object.id)" (click)="toggleSelected(object); $event.stopPropagation();">
<label class="form-check-label" for="{{typeName}}{{object.id}}"></label> <label class="form-check-label" for="{{typeName}}{{object.id}}"></label>
</div> </div>
</td> </td>
<td scope="row">{{ object.name }}</td> <td scope="row"><button class="btn btn-link ms-0 ps-0" (click)="openEditDialog(object)">{{ object.name }}</button> </td>
<td scope="row" class="d-none d-sm-table-cell">{{ getMatching(object) }}</td> <td scope="row" class="d-none d-sm-table-cell">{{ getMatching(object) }}</td>
<td scope="row">{{ object.document_count }}</td> <td scope="row">{{ object.document_count }}</td>
<td scope="row" *ngFor="let column of extraColumns"> <td scope="row" *ngFor="let column of extraColumns">
@ -96,6 +102,7 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
<div class="d-flex mb-2" *ngIf="!isLoading"> <div class="d-flex mb-2" *ngIf="!isLoading">
<div *ngIf="collectionSize > 0"> <div *ngIf="collectionSize > 0">

View File

@ -2,3 +2,11 @@
.d-block.d-sm-none .dropdown-toggle::after { .d-block.d-sm-none .dropdown-toggle::after {
display: none; display: none;
} }
tbody tr:last-child td {
border-bottom: none !important;
}
.form-check {
min-height: 0;
}

View File

@ -172,7 +172,7 @@ describe('ManagementListComponent', () => {
const toastInfoSpy = jest.spyOn(toastService, 'showInfo') const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
const reloadSpy = jest.spyOn(component, 'reloadData') const reloadSpy = jest.spyOn(component, 'reloadData')
const editButton = fixture.debugElement.queryAll(By.css('button'))[5] const editButton = fixture.debugElement.queryAll(By.css('button'))[6]
editButton.triggerEventHandler('click') editButton.triggerEventHandler('click')
expect(modal).not.toBeUndefined() expect(modal).not.toBeUndefined()
@ -198,7 +198,7 @@ describe('ManagementListComponent', () => {
const deleteSpy = jest.spyOn(tagService, 'delete') const deleteSpy = jest.spyOn(tagService, 'delete')
const reloadSpy = jest.spyOn(component, 'reloadData') const reloadSpy = jest.spyOn(component, 'reloadData')
const deleteButton = fixture.debugElement.queryAll(By.css('button'))[6] const deleteButton = fixture.debugElement.queryAll(By.css('button'))[7]
deleteButton.triggerEventHandler('click') deleteButton.triggerEventHandler('click')
expect(modal).not.toBeUndefined() expect(modal).not.toBeUndefined()
@ -218,7 +218,7 @@ describe('ManagementListComponent', () => {
it('should support quick filter for objects', () => { it('should support quick filter for objects', () => {
const qfSpy = jest.spyOn(documentListViewService, 'quickFilter') const qfSpy = jest.spyOn(documentListViewService, 'quickFilter')
const filterButton = fixture.debugElement.queryAll(By.css('button'))[4] const filterButton = fixture.debugElement.queryAll(By.css('button'))[5]
filterButton.triggerEventHandler('click') filterButton.triggerEventHandler('click')
expect(qfSpy).toHaveBeenCalledWith([ expect(qfSpy).toHaveBeenCalledWith([
{ rule_type: FILTER_HAS_TAGS_ALL, value: tags[0].id.toString() }, { rule_type: FILTER_HAS_TAGS_ALL, value: tags[0].id.toString() },

View File

@ -50,6 +50,11 @@ svg.logo {
color: var(--bs-body-color); color: var(--bs-body-color);
} }
.list-group-item .btn-link,
table .btn-link {
font-size: 1em;
}
.bg-body { .bg-body {
background-color: var(--bs-body-bg); background-color: var(--bs-body-bg);
} }