Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit ad172b72 authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

Pull request #123: [EDELIVERY-11682] review workflow implementation

Merge in EDELIVERY/smp from feature/EDELIVERY-11682-smp-ui-review-document-process-part-2 to development

* commit '3bc4498a':
  [EDELIVERY-1682] PR updates + implement review list page
  [EDELIVERY-1682] PR updates + implement review list page
  PR
  [EDELIVERY-11682] review workflow implementation
parents 7ad83f26 3bc4498a
No related branches found
No related tags found
No related merge requests found
Pipeline #205333 failed
Showing
with 1557 additions and 47 deletions
<div id="resource-document-panel">
<mat-toolbar class="mat-elevation-z2" style="min-height: 50px !important;">
<mat-toolbar-row class="smp-toolbar-row"
style="justify-content: space-between;min-height: 50px !important;">
<button id="newVersion_id"
*ngIf="isNotReviewMode"
mat-raised-button
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.version.new' | translate }}"
[disabled]="emptyDocument"
(click)="onNewDocumentVersionButtonClicked()">
<mat-icon>add_circle</mat-icon>
<span>{{ "document.edit.panel.button.version.new" | translate }}</span>
</button>
<button id="validateResource_id" mat-raised-button
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.validate' | translate }}"
[disabled]="emptyDocument"
(click)="onDocumentValidateButtonClicked()">
<mat-icon>check_circle</mat-icon>
<span>{{ "document.edit.panel.button.validate" | translate }}</span>
</button>
<button id="GenerateResource_id"
*ngIf="isNotReviewMode"
mat-raised-button
color="primary"
[disabled]="!documentEditable"
matTooltip="{{ 'document.edit.panel.tooltip.generate' | translate }}"
(click)="onGenerateButtonClicked()">
<mat-icon>change_circle</mat-icon>
<span>{{ "document.edit.panel.button.generate" | translate }}</span>
</button>
<button id="documentWizard_id" mat-raised-button
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.document.wizard' | translate }}"
[disabled]="!documentEditable"
*ngIf="showWizardDialog && isNotReviewMode"
(click)="onShowDocumentWizardDialog()">
<mat-icon>code_block</mat-icon>
<span>{{ "document.edit.panel.button.document.wizard" | translate }}</span>
</button>
<span style="flex: 1 1 auto;"></span>
</mat-toolbar-row>
</mat-toolbar>
<div class="panel" [formGroup]="documentForm"
style="display: flex;flex-direction: row;flex-grow: 1; ">
<div
style="display:flex; overflow: auto;flex: 2;align-self: stretch; flex-direction: column;">
<div style="display: flex;flex-direction: row">
<mat-form-field style="min-width: 140px"
subscriptSizing="dynamic"
appearance="fill"
>
<mat-label>{{ "document.edit.panel.label.selected.version" | translate }}</mat-label>
<mat-select
placeholder="{{ 'document.edit.panel.placeholder.version' | translate }}"
matTooltip="{{ 'document.edit.panel.tooltip.version' | translate }}"
id="document-version_id"
formControlName="payloadVersion"
(selectionChange)="onSelectionDocumentVersionChanged()">
<mat-option *ngFor="let version of getDocumentVersions"
[value]="version">
{{ version }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field style="min-width: 180px"
subscriptSizing="dynamic"
appearance="fill">
<mat-label>{{ "document.edit.panel.label.selected.status" | translate }}</mat-label>
<input matInput id="status_id"
formControlName="documentVersionStatus"
readonly>
</mat-form-field>
<mat-form-field style="width:100%"
subscriptSizing="dynamic"
appearance="fill">
<mat-label>{{ "document.edit.panel.label.selected.created.on" | translate }}</mat-label>
<input id="payloadCreatedOn_id"
matInput [ngxMatDatetimePicker]="payloadCreatedOnPicker"
formControlName="payloadCreatedOn"
readonly>
<mat-datepicker-toggle matSuffix [for]="payloadCreatedOnPicker"
style="visibility: hidden"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #payloadCreatedOnPicker [showSpinners]="true"
[showSeconds]="false"
[hideTime]="false"></ngx-mat-datetime-picker>
</mat-form-field>
</div>
<div
style="display:block; overflow: auto;flex: 2;align-self: stretch; flex-direction: column;border: ridge 3px #b0bec5"
(click)="onEditPanelClick()">
<smp-editor #smpDocumentEditor formControlName="payload"
ngDefaultControl></smp-editor>
</div>
<smp-warning-panel *ngIf="!documentEditable"
icon="info"
type="desc"
[label]="'document.edit.panel.note.editable' | translate: { editableDocStatusList: editableDocStatusList }">
</smp-warning-panel>
</div>
<expandable-panel>
<expandable-item icon="settings"
title="{{'document.properties.panel.tab.title' | translate }}"
buttonLabel="{{'document.properties.panel.tab.button.properties' | translate }}">
<document-properties-panel formControlName="properties"
[showEditToolbarButton]="isNotReviewMode"
ngDefaultControl></document-properties-panel>
</expandable-item>
<expandable-item icon="list"
*ngIf="isNotReviewMode"
title="{{'document.versions.panel.tab.title' | translate }}"
buttonLabel="{{'document.versions.panel.tab.button.versions' | translate }}">
<document-versions-panel
formControlName="documentVersions"
[selectedVersion]="currentDocumentVersion"
(selectedVersionChange) = "loadDocumentForVersion($event)"
ngDefaultControl></document-versions-panel>
</expandable-item>
<expandable-item icon="event"
title="{{'document.events.panel.tab.title' | translate }}"
buttonLabel="{{'document.events.panel.tab.button.events' | translate }}">
<document-events-panel formControlName="documentVersionEvents"
ngDefaultControl></document-events-panel>
</expandable-item>
</expandable-panel>
</div>
<mat-toolbar class="mat-elevation-z2"
style="flex-grow: 0;">
<mat-toolbar-row class="smp-toolbar-row">
<button id="back_id" mat-raised-button color="primary"
(click)="onBackButtonClicked()">
<mat-icon>arrow_circle_left</mat-icon>
<span>{{ "document.edit.panel.button.back" | translate }}</span>
</button>
<button id="cancel_id"
*ngIf="isNotReviewMode"
mat-raised-button
color="primary"
[disabled]="cancelButtonDisabled"
(click)="onDocumentResetButtonClicked()">
<mat-icon>cancel</mat-icon>
<span>{{ "document.edit.panel.button.cancel" | translate }}</span>
</button>
<tool-button-spacer></tool-button-spacer>
<button id="saveResource_id"
*ngIf="isNotReviewMode"
mat-raised-button
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.save' | translate }}"
[disabled]="saveButtonDisabled"
(click)="onSaveButtonClicked()">
<mat-icon>save</mat-icon>
<span>{{ "document.edit.panel.button.save" | translate }}</span>
</button>
<button id="publishResource_id" mat-raised-button
*ngIf="isNotReviewMode"
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.version.publish' | translate }}"
[disabled]="publishButtonDisabled"
(click)="onPublishButtonClicked()">
<mat-icon>publish</mat-icon>
<span>{{ "document.edit.panel.button.version.publish" | translate }}</span>
</button>
<tool-button-spacer></tool-button-spacer>
<button *ngIf="reviewEnabled && isNotReviewMode" id="reviewResource_id" mat-raised-button
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.version.review' | translate }}"
[disabled]="reviewButtonDisabled"
(click)="onReviewRequestButtonClicked()">
<mat-icon>task</mat-icon>
<span>{{ "document.edit.panel.button.version.review" | translate }}</span>
</button>
<button mat-raised-button
*ngIf="!isNotReviewMode || reviewEnabled"
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.version.approve' | translate }}"
[disabled]="reviewActionButtonDisabled"
(click)="onApproveButtonClicked()">
<mat-icon>check_circle</mat-icon>
<span>{{ "document.edit.panel.button.version.approve" | translate }}</span>
</button>
<button mat-raised-button
*ngIf="!isNotReviewMode || reviewEnabled"
color="primary"
matTooltip="{{ 'document.edit.panel.tooltip.version.reject' | translate }}"
[disabled]="reviewActionButtonDisabled"
(click)="onRejectButtonClicked()">
<mat-icon>unpublished</mat-icon>
<span>{{ "document.edit.panel.button.version.reject" | translate }}</span>
</button>
</mat-toolbar-row>
</mat-toolbar>
</div>
#resource-document-panel {
display: flex;
height: 100%;
flex-direction: column;
}
.CodeMirror {
height: auto;
}
<div style="display:flex; flex-grow: 1; flex-direction: column">
<mat-form-field style="width: 100%">
<mat-label>{{ "document.events.panel.label.filter" | translate }}</mat-label>
<input matInput (keyup)="applyFilter($event)" #input>
</mat-form-field>
<div id="events-table-container">
<table #DocumentEventTable mat-table class="mat-elevation-z1"
style="max-height: 100%;flex-grow: 1;"
id="document-events-table"
[dataSource]="eventDataSource" matSort>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.events.panel.label.date" | translate }}
</th>
<td mat-cell *matCellDef="let row;">
{{ row.eventOn | date: dateTimeFormat }}
</td>
</ng-container>
<ng-container matColumnDef="eventType">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.events.panel.label.type" | translate }}
</th>
<td mat-cell *matCellDef="let row">{{ row.eventType }}</td>
</ng-container>
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.events.panel.label.username" | translate }}
</th>
<td mat-cell *matCellDef="let row">{{ row.username }}</td>
</ng-container>
<ng-container matColumnDef="eventSource">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.events.panel.label.source" | translate }}
</th>
<td mat-cell *matCellDef="let row">{{ row.eventSourceType }}</td>
</ng-container>
<tr mat-header-row
*matHeaderRowDef="displayedColumns; sticky:true"></tr>
<tr mat-row
*matRowDef="let odd = odd; let row; columns: displayedColumns;"
[ngClass]="getRowClass(row, odd)"
></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell"
colspan="2">{{ "document.events.panel.label.no.properties.found" | translate }}
</td>
</tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons
[pageSize]="10" [length]="eventDataSource.data?.length"
attr.aria-label="{{ 'document.events.panel.label.select.page' | translate }}"></mat-paginator>
</div>
#document-events-panel {
display: flex;
flex-direction: column;
flex-grow: 1;
padding: 0 1em;
min-width: 600px;
}
#events-table-container {
position: relative;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow-y: scroll;
}
#events-table-container table {
width: 100%;
}
/*-
* #START_LICENSE#
* smp-webapp
* %%
* Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP
* %%
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
* #END_LICENSE#
*/
import {
AfterViewInit,
Component,
forwardRef,
Input,
ViewChild,
} from '@angular/core';
import {MatTable, MatTableDataSource} from "@angular/material/table";
import {
ControlContainer,
ControlValueAccessor,
FormControl,
FormControlDirective,
NG_VALUE_ACCESSOR
} from "@angular/forms";
import {MatSort} from "@angular/material/sort";
import {MatDialog} from "@angular/material/dialog";
import {MatPaginator} from "@angular/material/paginator";
import {DocumentVersionEventRo} from "../../model/document-version-event-ro.model";
import {
BeforeLeaveGuard
} from "../../../window/sidenav/navigation-on-leave-guard";
import {GlobalLookups} from "../../global-lookups";
/**
* Component to display the properties of a document in a table. The properties can be edited and saved.
* @author Joze Rihtarsic
* @since 5.1
*/
@Component({
selector: 'document-events-panel',
templateUrl: './document-events-panel.component.html',
styleUrls: ['./document-events-panel.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DocumentEventsPanelComponent),
multi: true
}
]
})
export class DocumentEventsPanelComponent implements AfterViewInit, BeforeLeaveGuard, ControlValueAccessor {
displayedColumns: string[] = [ 'date', 'eventType', 'username', 'eventSource'];
private onChangeCallback: (_: any) => void = () => {
};
eventDataSource: MatTableDataSource<DocumentVersionEventRo> = new MatTableDataSource();
dataChanged: boolean = false;
selected: DocumentVersionEventRo;
@ViewChild("DocumentVersionEventTable") table: MatTable<DocumentVersionEventRo>;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
private globalLookups: GlobalLookups,
public dialog: MatDialog,
private controlContainer: ControlContainer) {
}
get dateTimeFormat(): string {
return this.globalLookups.getDateTimeFormat();
}
@ViewChild(FormControlDirective, {static: true})
formControlDirective: FormControlDirective;
@Input()
formControl: FormControl;
@Input()
formControlName: string; /* get hold of FormControl instance no matter formControl or formControlName is given. If formControlName is given, then this.controlContainer.control is the parent FormGroup (or FormArray) instance. */
get control() {
return this.formControl || this.controlContainer.control.get(this.formControlName);
}
/**
* Implementation of the ControlValueAccessor method to write value to the component.
* @param eventList
*/
writeValue(eventList: DocumentVersionEventRo[]): void {
this.eventDataSource.data = !eventList?.length ? [] : [...eventList];
this.dataChanged = false;
}
ngAfterViewInit() {
this.eventDataSource.paginator = this.paginator;
this.eventDataSource.sort = this.sort;
}
applyFilter(event: Event) {
const filterValue: string = (event.target as HTMLInputElement).value;
this.eventDataSource.filter = filterValue?.trim().toLowerCase();
if (this.eventDataSource.paginator) {
this.eventDataSource.paginator.firstPage();
}
}
isDirty(): boolean {
return this.dataChanged;
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
// not implemented
}
setDisabledState(isDisabled: boolean): void {
// not implemented
}
getRowClass(row, oddRow: boolean) {
return {
'datatable-row-selected': row === this.selected,
'datatable-row-odd': oddRow
};
}
}
<div style="display: flex;flex-direction: row;height: 100%"> <div style="display:flex; flex-grow: 1; flex-direction: column">
<div *ngIf="showPropertyPanel" id="document-properties-panel"> <mat-toolbar *ngIf="shotToolbar"
<div style="display:flex; flex-grow: 1; flex-direction: column"> class="mat-elevation-z2"
style="flex-grow: 0;">
<mat-toolbar-row class="smp-toolbar-row">
<button id="createButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.create' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.create' | translate }}"
(click)="onCreateProperty()">
<mat-icon>add</mat-icon>
</button>
<button id="editButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.edit' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.edit' | translate }}"
(click)="onEditSelectedProperty()"
[disabled]="editButtonDisabled">
<mat-icon>edit</mat-icon>
</button>
<button id="deleteButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.delete.remove' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.delete.remove' | translate }}"
(click)="onDeleteSelectedProperty()"
[disabled]="deleteButtonDisabled"
>
<mat-icon>remove</mat-icon>
</button>
<tool-button-spacer></tool-button-spacer>
<button id="resetButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.reset' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.reset' | translate }}"
(click)="onResetButtonClicked()"
color="primary"
[disabled]="!cancelButtonEnabled">
<mat-icon>refresh</mat-icon>
</button>
</mat-toolbar-row>
</mat-toolbar>
<mat-form-field style="width: 100%"> <mat-form-field style="width: 100%">
<mat-label>{{ "document.properties.panel.label.filter" | translate }}</mat-label> <mat-label>{{ "document.properties.panel.label.filter" | translate }}</mat-label>
<input matInput (keyup)="applyFilter($event)" #input> <input matInput (keyup)="applyFilter($event)" #input>
...@@ -39,41 +69,3 @@ ...@@ -39,41 +69,3 @@
attr.aria-label="{{ 'document.properties.panel.label.select.page' | translate }}"></mat-paginator> attr.aria-label="{{ 'document.properties.panel.label.select.page' | translate }}"></mat-paginator>
</div> </div>
</div>
<!-- table Toolbar -->
<div style="width: 42px">
<button mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.expand.collapse' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.expand.collapse' | translate }}"
(click)="onToggleButtonClicked()">
<mat-icon *ngIf="showPropertyPanel">chevron_left</mat-icon>
<mat-icon *ngIf="!showPropertyPanel">chevron_right</mat-icon>
</button>
<tool-button-spacer [vertical]="false"></tool-button-spacer>
<button id="createButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.create' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.create' | translate }}"
(click)="onCreateProperty()">
<mat-icon>add</mat-icon>
</button>
<button id="editButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.edit' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.edit' | translate }}"
(click)="onEditSelectedProperty()"
[disabled]="editButtonDisabled">
<mat-icon>edit</mat-icon>
</button>
<button id="deleteButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.delete.remove' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.delete.remove' | translate }}"
(click)="onDeleteSelectedProperty()"
[disabled]="deleteButtonDisabled"
>
<mat-icon>remove</mat-icon>
</button>
<tool-button-spacer [vertical]="false"></tool-button-spacer>
<button id="resetButton" mat-mini-fab attr.aria-label="{{ 'document.properties.panel.label.reset' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.reset' | translate }}"
(click)="onResetButtonClicked()"
color="primary"
[disabled]="!cancelButtonEnabled">
<mat-icon>refresh</mat-icon>
</button>
</div>
</div>
...@@ -68,13 +68,13 @@ export class DocumentPropertiesPanelComponent implements AfterViewInit, BeforeLe ...@@ -68,13 +68,13 @@ export class DocumentPropertiesPanelComponent implements AfterViewInit, BeforeLe
private onChangeCallback: (_: any) => void = () => { private onChangeCallback: (_: any) => void = () => {
}; };
selected?: DocumentPropertyRo = null; selected?: DocumentPropertyRo = null;
dataChanged: boolean = false @Input() showEditToolbarButton: boolean = true;
showPropertyPanel: boolean = true; dataChanged: boolean = false;
initPropertyList: DocumentPropertyRo[] = []; initPropertyList: DocumentPropertyRo[] = [];
propertyDataSource: MatTableDataSource<DocumentPropertyRo> = new MatTableDataSource(); propertyDataSource: MatTableDataSource<DocumentPropertyRo> = new MatTableDataSource();
@ViewChild("DocumentPropertyTable") table: MatTable<DocumentPropertyRo>; @ViewChild("DocumentPropertyTable") table: MatTable<DocumentPropertyRo>;
@ViewChild(MatPaginator) paginator: MatPaginator @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
constructor(public dialog: MatDialog, private controlContainer: ControlContainer) { constructor(public dialog: MatDialog, private controlContainer: ControlContainer) {
...@@ -115,8 +115,8 @@ export class DocumentPropertiesPanelComponent implements AfterViewInit, BeforeLe ...@@ -115,8 +115,8 @@ export class DocumentPropertiesPanelComponent implements AfterViewInit, BeforeLe
return this.dataChanged; return this.dataChanged;
} }
public onToggleButtonClicked(): void { get shotToolbar(): boolean {
this.showPropertyPanel = !this.showPropertyPanel; return this.showEditToolbarButton;
} }
/** /**
......
<div style="display:flex; flex-grow: 1; flex-direction: column">
<mat-form-field style="width: 100%">
<mat-label>{{ "document.versions.panel.label.filter" | translate }}</mat-label>
<input matInput (keyup)="applyFilter($event)" #input>
</mat-form-field>
<div id="versions-table-container">
<table #DocumentVersionsTable mat-table class="mat-elevation-z1"
style="max-height: 100%;flex-grow: 1;"
id="document-versions-table"
[dataSource]="versionDataSource" matSort>
<ng-container matColumnDef="version">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.versions.panel.label.version" | translate }}
</th>
<td mat-cell *matCellDef="let row">{{ row.version }}</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.versions.panel.label.status" | translate }}
</th>
<td mat-cell *matCellDef="let row">{{ row.versionStatus }}</td>
</ng-container>
<ng-container matColumnDef="createdOn">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.versions.panel.label.created" | translate }}
</th>
<td mat-cell *matCellDef="let row;">
{{ row.createdOn | date: dateTimeFormat }}
</ng-container>
<ng-container matColumnDef="lastUpdatedOn">
<th mat-header-cell *matHeaderCellDef
mat-sort-header>{{ "document.versions.panel.label.updated" | translate }}
</th>
<td mat-cell *matCellDef="let row;">
{{ row.lastUpdatedOn | date: dateTimeFormat }}
</ng-container>
<tr mat-header-row
*matHeaderRowDef="displayedColumns; sticky:true"></tr>
<tr mat-row
*matRowDef="let odd = odd; let row; columns: displayedColumns;"
(dblclick)="onRowSelect(row)"
[ngClass]="getRowClass(row, odd)"
></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell"
colspan="2">{{ "document.versions.panel.label.no.properties.found" | translate }}
</td>
</tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons
[pageSize]="10" [length]="versionDataSource.data?.length"
attr.aria-label="{{ 'document.versions.panel.label.select.page' | translate }}"></mat-paginator>
</div>
#document-version-panel {
display: flex;
flex-direction: column;
flex-grow: 1;
padding: 0 1em;
min-width: 600px;
}
#version-table-container {
position: relative;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow-y: scroll;
}
#version-table-container table {
width: 100%;
}
/*-
* #START_LICENSE#
* smp-webapp
* %%
* Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP
* %%
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
* #END_LICENSE#
*/
import {
AfterViewInit,
Component,
EventEmitter,
forwardRef,
Input,
Output,
ViewChild,
} from '@angular/core';
import {MatTable, MatTableDataSource} from "@angular/material/table";
import {
ControlContainer,
ControlValueAccessor,
FormControl,
FormControlDirective,
NG_VALUE_ACCESSOR
} from "@angular/forms";
import {MatSort} from "@angular/material/sort";
import {MatDialog} from "@angular/material/dialog";
import {MatPaginator} from "@angular/material/paginator";
import {DocumentVersionRo} from "../../model/document-version-ro.model";
import {
BeforeLeaveGuard
} from "../../../window/sidenav/navigation-on-leave-guard";
import {GlobalLookups} from "../../global-lookups";
/**
* Component to display the properties of a document in a table. The properties can be edited and saved.
* @author Joze Rihtarsic
* @since 5.1
*/
@Component({
selector: 'document-versions-panel',
templateUrl: './document-versions-panel.component.html',
styleUrls: ['./document-versions-panel.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DocumentVersionsPanelComponent),
multi: true
}
]
})
export class DocumentVersionsPanelComponent implements AfterViewInit, BeforeLeaveGuard, ControlValueAccessor {
@Output() selectedVersionChange: EventEmitter<number> = new EventEmitter<number>();
displayedColumns: string[] = ['version', 'status', 'createdOn', 'lastUpdatedOn'];
private onChangeCallback: (_: any) => void = () => {
};
versionDataSource: MatTableDataSource<DocumentVersionRo> = new MatTableDataSource();
dataChanged: boolean = false;
selected: DocumentVersionRo;
_currentVersion: number;
@ViewChild("DocumentVersionsTable") table: MatTable<DocumentVersionRo>;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
private globalLookups: GlobalLookups,
public dialog: MatDialog,
private controlContainer: ControlContainer) {
}
get dateTimeFormat(): string {
return this.globalLookups.getDateTimeFormat();
}
@Input() set selectedVersion(version: number) {
this._currentVersion = version;
// find selected version
this.updateSelectedVersion();
}
get selectedVersion(): number {
return this._currentVersion;
}
/**
* Private method to locate selected row for current version
* @private
*/
private updateSelectedVersion(): void {
const selectedVersion :DocumentVersionRo = this.versionDataSource.data.find(v => v.version === this._currentVersion);
this.selected = selectedVersion;
}
/**
* Method to handle row selection
* @param row
*/
onRowSelect(row: DocumentVersionRo) {
this.selected = row;
this.selectedVersionChange.emit(row.version);
}
@ViewChild(FormControlDirective, {static: true})
formControlDirective: FormControlDirective;
@Input()
formControl: FormControl;
@Input()
formControlName: string; /* get hold of FormControl instance no matter formControl or formControlName is given. If formControlName is given, then this.controlContainer.control is the parent FormGroup (or FormArray) instance. */
get control() {
return this.formControl || this.controlContainer.control.get(this.formControlName);
}
/**
* Implementation of the ControlValueAccessor method to write value to the component.
* @param eventList
*/
writeValue(eventList: DocumentVersionRo[]): void {
this.versionDataSource.data = !eventList?.length ? [] : [...eventList];
this.updateSelectedVersion();
this.dataChanged = false;
}
ngAfterViewInit() {
this.versionDataSource.paginator = this.paginator;
this.versionDataSource.sort = this.sort;
}
applyFilter(event: Event) {
const filterValue: string = (event.target as HTMLInputElement).value;
this.versionDataSource.filter = filterValue?.trim().toLowerCase();
if (this.versionDataSource.paginator) {
this.versionDataSource.paginator.firstPage();
}
}
isDirty(): boolean {
return this.dataChanged;
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
// not implemented
}
setDisabledState(isDisabled: boolean): void {
// not implemented
}
getRowClass(row, oddRow: boolean) {
return {
'datatable-row-selected': row === this.selected,
'datatable-row-odd': oddRow
};
}
}
<div #root style="display: none;flex-direction: column">
<div class="expandable-item-title">{{title}}</div>
<ng-content></ng-content>
</div>
.expandable-item-title {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: bold;
padding: 2px 2px 2px 10px;
border-bottom: 1px solid #e0e0e0;
width: 100%;
}
/*-
* #START_LICENSE#
* smp-webapp
* %%
* Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP
* %%
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
* #END_LICENSE#
*/
import {Component, Input, ViewChild,} from '@angular/core';
/**
* Component to display the properties of a document in a table. The properties can be edited and saved.
* @author Joze Rihtarsic
* @since 5.1
*/
@Component({
selector: 'expandable-item',
templateUrl: './expandable-item.component.html',
styleUrls: ['./expandable-item.component.scss'],
})
export class ExpandableItemComponent {
@Input() title: string;
@Input() buttonLabel: string;
@Input() icon: string;
@Input() tooltip: string;
@ViewChild('root') expandableItem: any;
constructor() {
}
showItem(show: boolean) {
this.expandableItem.nativeElement.style.display = show ? 'block' : 'none';
}
}
<div style="display: flex;flex-direction: row;height: 100%">
<div *ngIf="expandPanel" id="expand-panel_id">
<ng-content></ng-content>
</div>
<!-- table Toolbar -->
<div style="width: 42px">
<button mat-mini-fab
attr.aria-label="{{ 'expandable.panel.label.expand.collapse' | translate }}"
matTooltip="{{ 'document.properties.panel.tooltip.expand.collapse' | translate }}"
(click)="onToggleExpandButtonClicked()">
<mat-icon *ngIf="expandPanel">chevron_left</mat-icon>
<mat-icon *ngIf="!expandPanel">chevron_right</mat-icon>
</button>
<tool-button-spacer [vertical]="false"></tool-button-spacer>
<button *ngFor="let item of expandableItems; let i = index;"
[class]="getButtonClass(i)"
(click)="selectItem(item, i)"
[matTooltip]="item.title"
>
<mat-icon *ngIf="item.icon">{{ item.icon }}</mat-icon>
<span *ngIf="showButtonLabel"
class="vertical-button-label">{{item.buttonLabel}}</span>
</button>
</div>
</div>
#expand-panel_id {
display: flex;
flex-direction: column;
flex-grow: 1;
padding: 0 1em;
min-width: 600px;
}
.vertical-button-label {
font-size: 0.8em;
min-height: 100px;
writing-mode: vertical-rl;
}
.button-deselected {
margin: 1px 3px !important;
background: transparent;
border-style: none;
}
/*-
* #START_LICENSE#
* smp-webapp
* %%
* Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP
* %%
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
* #END_LICENSE#
*/
import {
AfterViewInit,
Component,
ContentChildren,
Input,
QueryList,
} from '@angular/core';
import {
ExpandableItemComponent
} from "./expandable-item-component/expandable-item.component";
/**
* Component to display the properties of a document in a table. The properties can be edited and saved.
* @author Joze Rihtarsic
* @since 5.1
*/
@Component({
selector: 'expandable-panel',
templateUrl: './expandable-panel.component.html',
styleUrls: ['./expandable-panel.component.scss'],
})
export class ExpandablePanelComponent implements AfterViewInit {
@ContentChildren(ExpandableItemComponent) private _expandableItems: QueryList<ExpandableItemComponent>;
@Input() showButtonLabel: boolean = false;
expandPanel: boolean = true;
selectedIndex: number = 0;
constructor() {
}
ngAfterViewInit(): void {
this.updateShowItem()
}
get expandableItems(): ExpandableItemComponent[] {
return this._expandableItems?.toArray();
}
public onToggleExpandButtonClicked(): void {
this.expandPanel = !this.expandPanel;
}
selectItem(item: ExpandableItemComponent, index: number): void {
this.selectedIndex = index;
this.updateShowItem();
}
// show item at index and hide all others
updateShowItem(): void {
if (!this._expandableItems) {
return;
}
this._expandableItems.forEach((item: ExpandableItemComponent, i: number) => {
item.showItem(i === this.selectedIndex);
});
}
getButtonClass(index: number) {
return index === this.selectedIndex ? 'mat-raised-button' : 'mat-raised-button button-deselected';
}
}
...@@ -58,6 +58,11 @@ ...@@ -58,6 +58,11 @@
<td mat-cell *matCellDef="let row">{{row.roleType}}</td> <td mat-cell *matCellDef="let row">{{row.roleType}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="hasPermissionToReview">
<th mat-header-cell *matHeaderCellDef>{{ "membership.panel.label.permission.review" | translate }}</th>
<td mat-cell *matCellDef="let row">{{row.hasPermissionReview}}</td>
</ng-container>
<ng-container matColumnDef="memberOf"> <ng-container matColumnDef="memberOf">
<th mat-header-cell *matHeaderCellDef>{{ "membership.panel.label.member.of" | translate }}</th> <th mat-header-cell *matHeaderCellDef>{{ "membership.panel.label.member.of" | translate }}</th>
<td mat-cell *matCellDef="let row">{{row.memberOf}}</td> <td mat-cell *matCellDef="let row">{{row.memberOf}}</td>
......
...@@ -30,12 +30,14 @@ export class MembershipPanelComponent implements BeforeLeaveGuard { ...@@ -30,12 +30,14 @@ export class MembershipPanelComponent implements BeforeLeaveGuard {
pageSize: number = 10; pageSize: number = 10;
@Input() membershipType: MemberTypeEnum = MemberTypeEnum.DOMAIN; @Input() membershipType: MemberTypeEnum = MemberTypeEnum.DOMAIN;
private _domain: DomainRo; private _domain: DomainRo;
private _group: GroupRo; private _group: GroupRo;
private _resource: ResourceRo; private _resource: ResourceRo;
displayedColumns: string[] = ['username', 'fullName', 'roleType', 'memberOf']; _displayedColumns: string[] = ['username', 'fullName', 'roleType', 'memberOf'];
data: MemberRo[] = []; data: MemberRo[] = [];
selectedMember: MemberRo; selectedMember: MemberRo;
filter: any = {}; filter: any = {};
...@@ -77,6 +79,17 @@ export class MembershipPanelComponent implements BeforeLeaveGuard { ...@@ -77,6 +79,17 @@ export class MembershipPanelComponent implements BeforeLeaveGuard {
return this.resultsLength; return this.resultsLength;
} }
public get displayedColumns(): string[] {
switch (this.membershipType) {
case MemberTypeEnum.DOMAIN:
return ['username', 'fullName', 'roleType'];
case MemberTypeEnum.GROUP:
return ['username', 'fullName', 'roleType'];
case MemberTypeEnum.RESOURCE:
return ['username', 'fullName', 'roleType', 'hasPermissionToReview'];
}
}
@Input() set domain(value: DomainRo) { @Input() set domain(value: DomainRo) {
this._domain = value; this._domain = value;
if (!!value) { if (!!value) {
......
<document-edit-panel #reviewDocumentEditor
editorMode="REVIEW_EDITOR">
</document-edit-panel>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment