Merge pull request #4785 from FinnStutzenstein/historyQuicklink

Quicklink to history (closes #4777)
This commit is contained in:
Finn Stutzenstein 2019-06-28 08:50:54 +02:00 committed by GitHub
commit b71e73fe7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 12 deletions

View File

@ -112,4 +112,29 @@ export class CollectionStringMapperService {
public getAllRepositories(): BaseRepository<any, any, any>[] {
return Object.values(this.collectionStringMapping).map((types: CollectionStringMappedTypes) => types[2]);
}
/**
* Validates the given element id. It must have the form `<collection>:<id>`, with
* <collection> being a registered collection and the id a valid integer greater then 0.
*
* @param elementId The element id.
* @returns true, if the element id is valid.
*/
public isElementIdValid(elementId: any): boolean {
if (!elementId || typeof elementId !== 'string') {
return false;
}
const splitted = elementId.split(':');
if (splitted.length !== 2) {
return false;
}
const id = parseInt(splitted[1], 10);
if (isNaN(id) || id <= 0) {
return false;
}
return Object.keys(this.collectionStringMapping).some(collection => collection === splitted[0]);
}
}

View File

@ -38,6 +38,13 @@ export abstract class BaseViewModel<M extends BaseModel = any>
return this._collectionString;
}
/**
* @returns the element id of the model
*/
public get elementId(): string {
return `${this.collectionString}:${this.id}`;
}
public getTitle: () => string;
public getListTitle: () => string;

View File

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { MatSnackBar, MatTableDataSource } from '@angular/material';
import { Router } from '@angular/router';
import { Router, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
@ -21,6 +21,7 @@ import { MotionRepositoryService } from 'app/core/repositories/motions/motion-re
import { BaseViewModel } from 'app/site/base/base-view-model';
import { Motion } from 'app/shared/models/motions/motion';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
/**
* A list view for the history.
@ -40,10 +41,6 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
public dataSource: MatTableDataSource<History> = new MatTableDataSource<History>();
public get isSuperAdmin(): boolean {
return this.operator.isSuperAdmin();
}
public pageSizes = [50, 100, 150, 200, 250];
/**
@ -67,6 +64,10 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
return this.modelSelectForm.controls.model.value;
}
public get isSuperAdmin(): boolean {
return this.operator.isSuperAdmin();
}
/**
* Constructor for the history list component
*
@ -89,7 +90,9 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
private http: HttpService,
private formBuilder: FormBuilder,
private motionRepo: MotionRepositoryService,
private promptService: PromptService
private promptService: PromptService,
private activatedRoute: ActivatedRoute,
private collectionMapper: CollectionStringMapperService
) {
super(titleService, translate, matSnackBar);
@ -99,7 +102,15 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
this.collectionObserver = this.motionRepo.getViewModelListBehaviorSubject();
this.modelSelectForm.controls.model.valueChanges.subscribe((id: number) => {
this.queryElementId(this.currentCollection, id);
const elementId = `${this.currentCollection}:${id}`;
this.queryByElementId(elementId);
// Update the URL.
this.router.navigate([], {
relativeTo: this.activatedRoute,
queryParams: { element: elementId },
replaceUrl: true
});
});
}
@ -136,6 +147,18 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
.indexOf(filter) >= 0
);
};
// If an element id is given, validate it and update the view.
const params = this.activatedRoute.snapshot.queryParams;
if (this.collectionMapper.isElementIdValid(params.element)) {
this.queryByElementId(params.element);
this.modelSelectForm.patchValue(
{
model: parseInt(params.element.split(':')[1], 10)
},
{ emitEvent: false }
);
}
}
/**
@ -201,7 +224,7 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
public refresh(): void {
if (this.currentCollection && this.currentModelId) {
this.queryElementId(this.currentCollection, this.currentModelId);
this.queryByElementId(`${this.currentCollection}:${this.currentModelId}`);
}
}
@ -238,12 +261,12 @@ export class HistoryListComponent extends BaseViewComponent implements OnInit {
}
/**
* Sets the data source to the request element id given by the collection string and the id.
* Sets the data source to the requested element id.
*/
private async queryElementId(collectionString: string, id: number): Promise<void> {
private async queryByElementId(elementId: string): Promise<void> {
const historyData = await this.http.get<History[]>(`${environment.urlPrefix}/core/history/information/`, null, {
type: 'element',
value: `${collectionString}:${id}`
value: elementId
});
this.dataSource.data = historyData.map(data => new History(data));
}

View File

@ -101,6 +101,13 @@
<span translate>Show entire motion text</span>
</button>
<button mat-menu-item *osPerms="'core.can_see_history'" [routerLink]="['/history']" [queryParams]="{element: motion.elementId}">
<mat-icon>history</mat-icon>
<span translate>
History
</span>
</button>
<div *ngIf="perms.isAllowed('manage')">
<mat-divider></mat-divider>
<!-- Delete -->

View File

@ -504,7 +504,7 @@ class HistoryInformationView(utils_views.APIView):
"""
Checks permission and parses query parameters.
"""
if not has_perm(self.request.user, "users.can_see_history"):
if not has_perm(self.request.user, "core.can_see_history"):
self.permission_denied(self.request)
type = self.request.query_params.get("type")
value = self.request.query_params.get("value")