Commit a48ee2af authored by Christopher Keim's avatar Christopher Keim
Browse files

[TOB-127,21,406,74,315,52,92,354,391] feat: v0.9.0



[TOB-127] feat: Add components to display statement details

* Add back end calls for statement details
* Add component to display general statement information
* Add component to display geographic position
* Add component to display contribution status
* Add component to display statements inbox attachments
* Add component to display statements outbox attachments
* Add component to display linked statements
* Integrate details components in details page
* Integrate details components in form components
* Refresh process history on task change

[TOB-21] feat: Add functionality to manually redispatch statement email

* Add back end calls to redispatch statement email
* Add store actions and effect for redispatching statement email
* Integrate store into statement details page

[TOB-406] feat: Add statement search

* Extend back end API interface for search parameters
* Add component for search filters
* Add sorting buttons to statement table component
* Integrate statement search into search page

[TOB-74] feat: Add map to position search page

* Reorganize routing of search subpages
* Add directive to display leaflet popups
* Integrate leaflet map, markers and popups into position search page

[TOB-315] feat: Add search functionality to position search page

* Add back end calls for position search
* Add store effect for position search
* Integrate search component and store into position search page

[TOB-52] feat: Add GIS call to leaflet map

* Reorganize website configuration to separate config file
* Add back end calls to transform geographic positions
* Add store module for leaflet map
* Add store effecto to open GIS
* Integrate store module into map components
* Match leaflet styling to openk theme

[TOB-92] feat: Add upload functionality for consideration attachments

* Add component to display and upload consideration attachments
* Integrate component into details page

[TOB-354] feat: Add dockerfiles

[TOB-391] fix: Fix minor bugs

* Cancel rerouting of email when leaving mail page
* Prevent refetching of deleted emails
* Properly reset error messages in side menu
* Also perform contact search in new statement page when no mailid is provided
* Close drop downs on scroll
* Fix minor styling issues
Signed-off-by: Christopher Keim's avatarChristopher Keim <keim@develop-group.de>
parent c14146b0
......@@ -11,22 +11,22 @@
* SPDX-License-Identifier: EPL-2.0
-------------------------------------------------------------------------------->
<div *ngIf="appPredecessors?.length > 0" class="statements">
<div *ngIf="appParents?.length > 0" class="statements">
<span class="statements--titlebar">{{"shared.linkedStatements.precedingStatements" | translate}}</span>
<app-statement-table
[appColumns]="columns"
[appEntries]="appSuccessors"
[appEntries]="appParents"
[appOpenStatementInNewTab]="true"
[appStatementTypeOptions]="appStatementTypeOptions"
class="openk-table---last-row-without-border">
</app-statement-table>
</div>
<div *ngIf="appSuccessors?.length > 0" class="statements">
<div *ngIf="appChildren?.length > 0" class="statements">
<span class="statements--titlebar">{{"shared.linkedStatements.successiveStatements" | translate}}</span>
<app-statement-table
[appColumns]="columns"
[appEntries]="appSuccessors"
[appEntries]="appChildren"
[appOpenStatementInNewTab]="true"
[appStatementTypeOptions]="appStatementTypeOptions"
class="openk-table---last-row-without-border">
......
......@@ -11,10 +11,13 @@
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
@import "../../../../styles/openk.styles";
:host {
display: block;
width: 100%;
&:empty {
display: none;
}
}
.statements {
......@@ -24,4 +27,5 @@
.statements--titlebar {
margin-bottom: 0.5em;
font-weight: 600;
}
......@@ -13,8 +13,7 @@
import {async, ComponentFixture, TestBed} from "@angular/core/testing";
import {RouterTestingModule} from "@angular/router/testing";
import {I18nModule} from "../../../core/i18n";
import {LinkedStatementsModule} from "../linked-statements.module";
import {I18nModule} from "../../../../../core/i18n";
import {LinkedStatementsComponent} from "./linked-statements.component";
describe("LinkedStatementsComponent", () => {
......@@ -25,8 +24,7 @@ describe("LinkedStatementsComponent", () => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
I18nModule,
LinkedStatementsModule
I18nModule
]
}).compileComponents();
}));
......
......@@ -14,10 +14,10 @@
import {RouterTestingModule} from "@angular/router/testing";
import {number, withKnobs} from "@storybook/addon-knobs";
import {moduleMetadata, storiesOf} from "@storybook/angular";
import {I18nModule} from "../../../core/i18n";
import {createStatementModelMock} from "../../../test";
import {createSelectOptionsMock} from "../../../test/create-select-options.spec";
import {LinkedStatementsModule} from "../linked-statements.module";
import {I18nModule} from "../../../../../core/i18n";
import {createSelectOptionsMock, createStatementModelMock} from "../../../../../test";
import {StatementDetailsModule} from "../../../statement-details.module";
storiesOf("Shared", module)
.addDecorator(withKnobs)
......@@ -25,15 +25,15 @@ storiesOf("Shared", module)
imports: [
RouterTestingModule,
I18nModule,
LinkedStatementsModule
StatementDetailsModule
]
}))
.add("LinkedStatementsComponent", () => ({
.add("StatementDetailsLinkedStatementsComponent", () => ({
template: `
<div style="padding: 1em;">
<app-linked-statements
[appPredecessors]="entries.slice(0, numberOfRowsToDisplay)"
[appSuccessors]="entries.slice(0, numberOfRowsToDisplay)"
[appParents]="entries.slice(0, numberOfRowsToDisplay)"
[appChildren]="entries.slice(0, numberOfRowsToDisplay)"
[appStatementTypeOptions]="appStatementTypeOptions">
</app-linked-statements>
</div>
......
......@@ -12,8 +12,9 @@
********************************************************************************/
import {Component, Input} from "@angular/core";
import {ISelectOption} from "../../controls/select/model";
import {IStatementTableEntry, StatementTableComponent, TStatementTableColumns} from "../../layout/statement-table";
import {ISelectOption} from "../../../../../shared/controls/select/model";
import {StatementTableComponent, TStatementTableColumns} from "../../../../../shared/layout/statement-table/components";
import {IStatementTableEntry} from "../../../../../shared/layout/statement-table/model";
@Component({
selector: "app-linked-statements",
......@@ -23,10 +24,10 @@ import {IStatementTableEntry, StatementTableComponent, TStatementTableColumns} f
export class LinkedStatementsComponent {
@Input()
public appPredecessors: Array<IStatementTableEntry>;
public appParents: Array<IStatementTableEntry>;
@Input()
public appSuccessors: Array<IStatementTableEntry>;
public appChildren: Array<IStatementTableEntry>;
@Input()
public appStatementTypeOptions: ISelectOption<number>[];
......
<!-------------------------------------------------------------------------------
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
-------------------------------------------------------------------------------->
<app-collapsible
[(appCollapsed)]="appCollapsed"
[appTitle]="'details.linkedStatements.title' | translate">
<div *ngIf="(parents$ | async)?.length > 0 || (children$ | async)?.length > 0"
style="padding: 1em;">
<app-linked-statements
[appChildren]="children$ | async"
[appParents]="parents$ | async"
[appStatementTypeOptions]="statementTypeOptions$ | async">
</app-linked-statements>
</div>
<div *ngIf="!((parents$ | async)?.length > 0 || (children$ | async)?.length > 0)"
class="placeholder">
{{"details.linkedStatements.placeholder" | translate}}
</div>
</app-collapsible>
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
:host {
display: block;
width: 100%;
&:empty {
display: none;
}
}
.placeholder {
padding: 1em;
font-style: italic;
}
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {async, ComponentFixture, TestBed} from "@angular/core/testing";
import {provideMockStore} from "@ngrx/store/testing";
import {I18nModule} from "../../../../core/i18n";
import {StatementDetailsModule} from "../../statement-details.module";
import {StatementDetailsLinkedStatementsComponent} from "./statement-details-linked-statements.component";
describe("StatementDetailsLinkedStatementsComponent", () => {
let component: StatementDetailsLinkedStatementsComponent;
let fixture: ComponentFixture<StatementDetailsLinkedStatementsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StatementDetailsModule,
I18nModule
],
providers: [provideMockStore()]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StatementDetailsLinkedStatementsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {Component, Input} from "@angular/core";
import {select, Store} from "@ngrx/store";
import {statementTypesSelector} from "../../../../store/settings/selectors";
import {childrenStatementListSelector, parentStatementListSelector} from "../../../../store/statements/selectors";
/**
* This component the connected statements split up into two categories:
* Parents, meaning preceding statements and children, meaning following statements.
* Those lists cannot be modified in this display.
*/
@Component({
selector: "app-statement-details-linked-statements",
templateUrl: "./statement-details-linked-statements.component.html",
styleUrls: ["./statement-details-linked-statements.component.scss"]
})
export class StatementDetailsLinkedStatementsComponent {
@Input()
public appCollapsed = false;
public statementTypeOptions$ = this.store.pipe(select(statementTypesSelector));
public parents$ = this.store.pipe(select(parentStatementListSelector));
public children$ = this.store.pipe(select(childrenStatementListSelector));
public constructor(public store: Store) {
}
}
<!-------------------------------------------------------------------------------
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
-------------------------------------------------------------------------------->
<app-collapsible
[(appCollapsed)]="appCollapsed"
[appTitle]="'details.outbox.title' | translate">
<div *ngIf="(statementAttachment$ | async)?.length > 0 || (outboxAttachments$ | async)?.length > 0"
class="outbox-attachments">
<div *ngIf="(statementAttachment$ | async)?.length > 0"
class="outbox-attachments--statement"
style="margin-right: 0.5em;">
<app-attachment-display-list
(appDownload)="downloadAttachment($event)"
[appAttachments]="statementAttachment$ | async"
[appTagList]="[]"
[appTitle]="'details.outbox.statement' | translate"
class="outbox-attachments--statement">
</app-attachment-display-list>
</div>
<div class="outbox-attachments--statement">
<app-attachment-display-list
(appDownload)="downloadAttachment($event)"
[appAttachments]="outboxAttachments$ | async"
[appTagList]="[]"
[appTitle]="'details.outbox.attachments' | translate"
class="outbox-attachments--attachments">
</app-attachment-display-list>
</div>
</div>
<div *ngIf="!((statementAttachment$ | async)?.length > 0 || (outboxAttachments$ | async)?.length > 0)"
class="placeholder">
{{"details.outbox.placeholder" | translate}}
</div>
</app-collapsible>
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
@import "openk.styles";
:host {
display: block;
width: 100%;
&:empty {
display: none;
}
}
.placeholder {
padding: 1em;
font-style: italic;
}
.outbox-attachments {
padding: 1em;
display: flex;
flex-direction: row;
}
.outbox-attachments--statement {
display: inline-block;
flex: 1;
}
.outbox-attachments--attachments {
display: inline-block;
}
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {async, ComponentFixture, TestBed} from "@angular/core/testing";
import {Store} from "@ngrx/store";
import {provideMockStore} from "@ngrx/store/testing";
import {I18nModule} from "../../../../core/i18n";
import {startAttachmentDownloadAction} from "../../../../store/attachments/actions";
import {queryParamsIdSelector} from "../../../../store/root/selectors";
import {StatementDetailsModule} from "../../statement-details.module";
import {StatementDetailsOutboxComponent} from "./statement-details-outbox.component";
describe("StatementDetailsOutboxComponent", () => {
let component: StatementDetailsOutboxComponent;
let fixture: ComponentFixture<StatementDetailsOutboxComponent>;
let store: Store;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StatementDetailsModule,
I18nModule
],
providers: [
provideMockStore({
initialState: {},
selectors: [
{
selector: queryParamsIdSelector,
value: 19
}
]
})
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StatementDetailsOutboxComponent);
component = fixture.componentInstance;
store = fixture.componentRef.injector.get(Store);
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
it("should dispatch startAttachmentDownloadAction with correct attachmentId", async () => {
const dispatchSpy = spyOn(store, "dispatch");
await component.downloadAttachment(15);
expect(dispatchSpy).toHaveBeenCalledWith(startAttachmentDownloadAction({statementId: 19, attachmentId: 15}));
});
});
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {Component, Input} from "@angular/core";
import {select, Store} from "@ngrx/store";
import {take} from "rxjs/operators";
import {startAttachmentDownloadAction} from "../../../../store/attachments/actions";
import {getOutboxAttachments, getStatementPdfAttachment} from "../../../../store/attachments/selectors";
import {queryParamsIdSelector} from "../../../../store/root/selectors";
/**
* This component displays the statements attachments that are meant for the statement response (outbox)
* and the generated Statement.pdf that is also sent in the response,
* The files can be downloaded by pressing a button.
*/
@Component({
selector: "app-statement-details-outbox",
templateUrl: "./statement-details-outbox.component.html",
styleUrls: ["./statement-details-outbox.component.scss"]
})
export class StatementDetailsOutboxComponent {
@Input()
public appCollapsed = false;
public statementId$ = this.store.pipe(select(queryParamsIdSelector));
public statementAttachment$ = this.store.pipe(select(getStatementPdfAttachment));
public outboxAttachments$ = this.store.pipe(select(getOutboxAttachments));
public constructor(public store: Store) {
}
public async downloadAttachment(attachmentId: number) {
const statementId = await this.statementId$.pipe(take(1)).toPromise();
this.store.dispatch(startAttachmentDownloadAction({statementId, attachmentId}));
}
}
......@@ -89,7 +89,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
cssClass: "openk-danger"
},
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.editInfoData",
icon: "subject",
cssClass: "openk-success"
......@@ -106,7 +106,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
cssClass: "openk-info"
},
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.createNegativeStatement",
icon: "edit",
cssClass: "openk-info"
......@@ -114,7 +114,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
],
[EAPIProcessTaskDefinitionKey.ADD_WORK_FLOW_DATA]: [
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.editWorkflowData",
icon: "subject",
cssClass: "openk-info"
......@@ -122,7 +122,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
],
[EAPIProcessTaskDefinitionKey.CREATE_DRAFT]: [
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.createDraft",
icon: "edit",
cssClass: "openk-info"
......@@ -138,7 +138,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
],
[EAPIProcessTaskDefinitionKey.CHECK_AND_FORMULATE_RESPONSE]: [
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.completeDraft",
icon: "description",
cssClass: "openk-info"
......@@ -165,7 +165,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
[EAPIUserRoles.DIVISION_MEMBER]: {
[EAPIProcessTaskDefinitionKey.ENRICH_DRAFT]: [
{
emit: this.emitClaimTaskFatory(),
emit: this.emitClaimTaskFactory(),
label: "details.sideMenu.editDraft",
icon: "description",
cssClass: "openk-info"
......@@ -219,7 +219,7 @@ export class StatementDetailsSideMenuComponent implements OnChanges {
}));
}
private emitClaimTaskFatory() {
private emitClaimTaskFactory() {
return (task: IAPIProcessTask) => this.appDispatch.emit(claimTaskAction({
statementId: task?.statementId,
taskId: task?.taskId
......