[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 <keim@develop-group.de>
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2cf5c82
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,19 @@
+# ******************************************************************************
+# 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 v. 2.0 which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# SPDX-License-Identifier: EPL-2.0
+# ******************************************************************************
+
+FROM nginx:1.18-alpine
+
+COPY dist/statement-public-affairs /html-root
+
+COPY docker/buildDocker/default.conf /etc/nginx/conf.d/default.conf
+
diff --git a/README.md b/README.md
index 00f4205..82712e5 100644
--- a/README.md
+++ b/README.md
@@ -17,25 +17,42 @@
 ## Configuration
 
 The whole application can be configured via certain properties in
-the `./package.json`. The following options are available:
+file `./app.config.json`. Changes to these properties take only 
+effect after (re-)building the application.
 
-* `routes.spaFrontend`: Route on which the website is served
-* `routes.spaBackend`: Route on which the website's backend is served
-* `routes.portal`: Route on which the main portal is served
-* `routes.contactDataBase`: Route on which the contact data base module is served
+* `routes.spaBackend`: Route on which the website's backend is 
+served
+* `routes.portal`: Route on which the main portal is served 
+* `routes.contactDataBase`: Route on which the contact data base  
+module is served
+* `leaflet.urlTemplate`: URL template to the map tile server 
+required by [Leaflet](https://leafletjs.com)
+* `leaflet.attribution`: Attribution which is added to all 
+Leaflet maps
+* `leaflet.lat`/`leaflet.lng`/`leaflet.zoom`: Default coordinates
+and zoom level to which all leaflet maps are initially configured
+* `gis.urlTemplate`: URL template to the geographic information 
+system (GIS)
+* `gis.projectionFrom`: Coordinate projection used by the 
+configured Leaflet tile server
+* `gis.projectionTo`: Coordinate projection used in the 
+configured GIS
+* `nominatim.url`: URL to a [Nominatim](https://nominatim.org)
+geocoding service
+* `nominatim.searchQueryPrefix`: Prefix which is added automatically 
+to every [Nominatim](https://nominatim.org) search query
 
-Changes to these properties take only effect after rebuilding the
-application.
+The following key words are replaced in the given GIS URL template
+for each map view:
+* `{centerX}`, `{centerY}`: Center coordinates
+* `{northEastX}`, `{northEastY}`: North east boundary coordinates
+* `{northWestX}`, `{northWestY}`: North west boundary coordinates
+* `{southEastX}`, `{southEastY}`: South east boundary coordinates
+* `{southWestX}`, `{southWestY}`: South west boundary coordinates
+* `{user}`: User name
 
-Additionally, the following options can be used to configure all map views based 
-on [Leaflet](https://leafletjs.com):
-
-* `leaflet.templateUrl`: Route to the map tile server required by leaflet
-* `leaflet.attribution`: Attribution which is added to the leaflet map, e.g. 
-`&copy; <a>TileServer</a> contributors`
-* `leaflet.gis`: Route to a GIS system
-* `leaflet.lat`/`leaflet.lng`/`leaflet.zoom`: Default coordinates and zoom
-level to which all leaflet maps are initially configured
+All coordinates are transformed via a HTTP call to the back end.
+For all available projections, please visit [Proj4j](https://trac.osgeo.org/proj4j/). 
 
 ## Build
 
diff --git a/app.config.json b/app.config.json
new file mode 100644
index 0000000..e1ecf44
--- /dev/null
+++ b/app.config.json
@@ -0,0 +1,23 @@
+{
+  "gis": {
+    "urlTemplate": "http://localhost/Ext2GWS/GinPrjExt2GService.asmx/Coordinates?pLLX={southWestX}&pLLY={southWestY}&pURX={northEastX}&pURY={northEastY}&pReportName=TestName&pOSUser={user}&pLSNO=900",
+    "projectionFrom": "EPSG:4326",
+    "projectionTo": "EPSG:25832"
+  },
+  "leaflet": {
+    "urlTemplate": "http://localhost:4201/{s}/{z}/{x}/{y}.png",
+    "attribution": "&copy; <a href=\"http://localhost:4201/copyright\">Tile Server</a> contributors",
+    "lat": 49.87282103349044,
+    "lng": 8.651196956634523,
+    "zoom": 12
+  },
+  "nominatim": {
+    "url": "http://localhost:4202",
+    "searchQueryPrefix": "Germany"
+  },
+  "routes": {
+    "spaBackend": "/statementpaBE",
+    "portal": "/portalFE",
+    "contactDataBase": "/contactdatabase"
+  }
+}
diff --git a/docker/buildDocker/README.md b/docker/buildDocker/README.md
new file mode 100644
index 0000000..592b72e
--- /dev/null
+++ b/docker/buildDocker/README.md
@@ -0,0 +1,24 @@
+*******************************************************************************
+  Copyright (c) 2019 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 v. 2.0 which is available at
+  http://www.eclipse.org/legal/epl-2.0.
+
+  SPDX-License-Identifier: EPL-2.0
+*******************************************************************************
+
+# Nginx based docker image that contains the statement module frontend
+
+This docker configuration creates a nginx based reverse-proxy.
+It provides the statement module frontend at port 80.
+
+Please go to the root folder to build this docker image.
+
+## Configuration
+
+The nginx configuration can be found in the default.conf file.
+
diff --git a/docker/buildDocker/default.conf b/docker/buildDocker/default.conf
new file mode 100644
index 0000000..3ef2fa6
--- /dev/null
+++ b/docker/buildDocker/default.conf
@@ -0,0 +1,19 @@
+server {
+	listen 80 default_server;
+	listen [::]:80 default_server;
+
+	root /html-root;
+
+	index index.html;
+
+	server_name you.server.com;
+
+	location / {
+		try_files $uri $uri/ @rewrites;
+	}
+
+	location @rewrites {
+		rewrite ^(.+)$ /index.html last;
+	}
+
+}
diff --git a/docker/buildenv/Dockerfile b/docker/buildenv/Dockerfile
new file mode 100644
index 0000000..affd89b
--- /dev/null
+++ b/docker/buildenv/Dockerfile
@@ -0,0 +1,22 @@
+# ******************************************************************************
+# 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 v. 2.0 which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# SPDX-License-Identifier: EPL-2.0
+# ******************************************************************************
+
+FROM node:12-alpine
+
+RUN mkdir -p /buildenv/node_modules
+RUN mkdir -p /buildenv/root
+RUN npm install -g --silent @angular/cli
+RUN apk add openjdk8
+RUN ln -s /usr/lib/jvm/java-1.8-openjdk/bin/jar /usr/local/bin
+
+
diff --git a/docker/buildenv/README.md b/docker/buildenv/README.md
new file mode 100644
index 0000000..b0f7775
--- /dev/null
+++ b/docker/buildenv/README.md
@@ -0,0 +1,27 @@
+*******************************************************************************
+  Copyright (c) 2019 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 v. 2.0 which is available at
+  http://www.eclipse.org/legal/epl-2.0.
+
+  SPDX-License-Identifier: EPL-2.0
+*******************************************************************************
+
+# Build environment
+
+The 'build' script creates reproducable artifact builds.
+It uses an node based docker image.
+
+## Usage
+
+To build the artifact, run the compile script from the project base folder (where the package.json is located).
+
+The script deletes the target folder and then runs node build commands.
+
+After a successful build, the artifact is located in the 'dist' folder.
+
+
diff --git a/docker/buildenv/build b/docker/buildenv/build
new file mode 100755
index 0000000..e8ede8f
--- /dev/null
+++ b/docker/buildenv/build
@@ -0,0 +1,4 @@
+docker volume create --name node-modules
+
+docker run -it -v "$PWD":/buildenv/root -v node-modules:/buildenv/root/node_modules  -w /buildenv/root openk-node:12-alpine sh -c "npm install --silent && npm run build && npm run build:archive"
+
diff --git a/package-lock.json b/package-lock.json
index d972f7e..c1b2c07 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "openkonsequenz-statement-public-affairs",
-  "version": "0.8.0",
+  "version": "0.9.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index d4d2add..2d0c3be 100644
--- a/package.json
+++ b/package.json
@@ -1,26 +1,12 @@
 {
   "name": "openkonsequenz-statement-public-affairs",
-  "version": "0.8.0",
+  "version": "0.9.0",
   "description": "Statement Public Affairs",
   "license": "Eclipse Public License - v 2.0",
   "repository": {
     "type": "git",
     "url": "https://git.eclipse.org/r/plugins/gitiles/openk-usermodules/org.eclipse.openk-usermodules.statementPublicAffairs.frontend"
   },
-  "routes": {
-    "spaFrontend": "/statementpaFE",
-    "spaBackend": "/statementpaBE",
-    "portal": "/portalFE",
-    "contactDataBase": "/contactdatabase"
-  },
-  "leaflet": {
-    "urlTemplate": "https://localhost:4200/{s}/{z}/{x}/{y}.png",
-    "attribution": "&copy;",
-    "gis": "http://localhost:4200?X=##C_X##&Y=##C_Y##pLLX=##LL_X##&pLLY=##LL_Y##&pURX=##UR_X##&pURY=##UR_Y##&user=##OS_USER##",
-    "lat": 49.87282103349044,
-    "lng": 8.651196956634523,
-    "zoom": 12
-  },
   "scripts": {
     "-- Build ----------------": "",
     "build": "ng build --prod --base-href /statementpaFE/",
diff --git a/src/app/app-routing.module.spec.ts b/src/app/app-routing.module.spec.ts
index c9c28c3..aab37b5 100644
--- a/src/app/app-routing.module.spec.ts
+++ b/src/app/app-routing.module.spec.ts
@@ -85,7 +85,20 @@
     it("should navigate to /search", async () => {
         const isRoutingSuccessful = await callInZone(() => router.navigate(["search"]));
         expect(isRoutingSuccessful).toBeTruthy();
-        expect(location.path()).toBe("/search");
+        await Promise.resolve();
+        expect(location.path()).toBe("/search/list");
+    });
+
+    it("should navigate to /search/list", async () => {
+        const isRoutingSuccessful = await callInZone(() => router.navigate(["search", "list"]));
+        expect(isRoutingSuccessful).toBeTruthy();
+        expect(location.path()).toBe("/search/list");
+    });
+
+    it("should navigate to /search/map", async () => {
+        const isRoutingSuccessful = await callInZone(() => router.navigate(["search", "map"]));
+        expect(isRoutingSuccessful).toBeTruthy();
+        expect(location.path()).toBe("/search/map");
     });
 
     it("should navigate to /settings", async () => {
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index d88839b..8ac6768 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -20,8 +20,6 @@
 import {AppComponent} from "./app.component";
 import {CoreModule} from "./core";
 import {AppNavigationFrameModule} from "./features/navigation";
-import {LeafletModule} from "./shared/layout/leaflet";
-import {SideMenuRegistrationService} from "./shared/layout/side-menu/services";
 import {AppStoreModule} from "./store";
 
 @NgModule({
@@ -38,8 +36,6 @@
         AppStoreModule,
         AppNavigationFrameModule,
 
-        LeafletModule.for(SideMenuRegistrationService),
-
         // This import is only important for development; in production, nothing is imported.
         // ! This import must come after AppStoreModule in order make the NGRX Store Devtools available. !
         ...environment.imports
diff --git a/src/app/core/api/attachments/attachments-api.service.ts b/src/app/core/api/attachments/attachments-api.service.ts
index e0c2709..e6d4835 100644
--- a/src/app/core/api/attachments/attachments-api.service.ts
+++ b/src/app/core/api/attachments/attachments-api.service.ts
@@ -48,6 +48,16 @@
     }
 
     /**
+     * Uploads a new file for the statement with the given id and automatically sets the consideration tag on the attachment.
+     */
+    public postConsideration(statementId: number, file: File) {
+        const endPoint = `/statements/${statementId}/consideration`;
+        const formData = new FormData();
+        formData.append("attachment", file, file.name);
+        return this.httpClient.post<IAPIAttachmentModel>(urlJoin(this.baseUrl, endPoint), formData);
+    }
+
+    /**
      * Uploads a new file to the back end linked to a specific statement.
      */
     public deleteAttachment(statementId: number, taskId: string, attachmentId: number) {
diff --git a/src/app/features/search/components/search/index.ts b/src/app/core/api/geo/IAPIGeographicPositions.ts
similarity index 82%
copy from src/app/features/search/components/search/index.ts
copy to src/app/core/api/geo/IAPIGeographicPositions.ts
index 5eb9c7f..687b05a 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/core/api/geo/IAPIGeographicPositions.ts
@@ -11,4 +11,9 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export interface IAPIGeographicPositions {
+    [key: string]: {
+        x: number;
+        y: number;
+    };
+}
diff --git a/src/app/core/api/geo/geo-api.service.ts b/src/app/core/api/geo/geo-api.service.ts
new file mode 100644
index 0000000..700163b
--- /dev/null
+++ b/src/app/core/api/geo/geo-api.service.ts
@@ -0,0 +1,37 @@
+/********************************************************************************
+ * 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 {HttpClient} from "@angular/common/http";
+import {Inject, Injectable} from "@angular/core";
+import {Observable} from "rxjs";
+import {objectToHttpParams, urlJoin} from "../../../util/http";
+import {SPA_BACKEND_ROUTE} from "../../external-routes";
+import {IAPIGeographicPositions} from "./IAPIGeographicPositions";
+
+@Injectable({providedIn: "root"})
+export class GeoApiService {
+
+    public constructor(
+        protected readonly httpClient: HttpClient,
+        @Inject(SPA_BACKEND_ROUTE) protected readonly baseUrl: string
+    ) {
+
+    }
+
+    public transform(geographicPositions: IAPIGeographicPositions, from: string, to: string): Observable<IAPIGeographicPositions> {
+        const params = objectToHttpParams({from, to});
+        const endPoint = `/geo-coordinate-transform`;
+        return this.httpClient.post<IAPIGeographicPositions>(urlJoin(this.baseUrl, endPoint), geographicPositions, {params});
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/core/api/geo/index.ts
similarity index 87%
copy from src/app/features/search/components/search/index.ts
copy to src/app/core/api/geo/index.ts
index 5eb9c7f..9f1b524 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/core/api/geo/index.ts
@@ -11,4 +11,5 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./IAPIGeographicPositions";
+export * from "./geo-api.service";
diff --git a/src/app/core/api/index.ts b/src/app/core/api/index.ts
index ccbbf5f..491f529 100644
--- a/src/app/core/api/index.ts
+++ b/src/app/core/api/index.ts
@@ -14,6 +14,7 @@
 export * from "./attachments";
 export * from "./contacts";
 export * from "./core";
+export * from "./geo";
 export * from "./mail";
 export * from "./process";
 export * from "./settings";
diff --git a/src/app/core/api/mail/mail-api.service.ts b/src/app/core/api/mail/mail-api.service.ts
index 90962d3..a4654cd 100644
--- a/src/app/core/api/mail/mail-api.service.ts
+++ b/src/app/core/api/mail/mail-api.service.ts
@@ -70,12 +70,4 @@
         return this.httpClient.post<IAPIAttachmentModel[]>(urlJoin(this.baseUrl, endPoint), body);
     }
 
-    /**
-     * Re-sends the outgoing email for a statement.
-     */
-    public dispatchStatement(statementId: number, taskId: string) {
-        const endPoint = `/process/statements/${statementId}/task/${taskId}/maildispatch`;
-        return this.httpClient.post(urlJoin(this.baseUrl, endPoint), null);
-    }
-
 }
diff --git a/src/app/core/api/process/process-api.service.ts b/src/app/core/api/process/process-api.service.ts
index 78e1134..b57dced 100644
--- a/src/app/core/api/process/process-api.service.ts
+++ b/src/app/core/api/process/process-api.service.ts
@@ -80,4 +80,12 @@
         return this.httpClient.get(urlJoin(this.baseUrl, endPoint), {responseType: "text"});
     }
 
+    /**
+     * Re-sends the outgoing email for a statement.
+     */
+    public dispatchStatement(statementId: number, taskId: string) {
+        const endPoint = `/process/statements/${statementId}/task/${taskId}/mailandcomplete`;
+        return this.httpClient.post(urlJoin(this.baseUrl, endPoint), null);
+    }
+
 }
diff --git a/src/app/core/api/shared/IAPIPositionSearchOptions.ts b/src/app/core/api/shared/IAPIPositionSearchOptions.ts
new file mode 100644
index 0000000..51d1484
--- /dev/null
+++ b/src/app/core/api/shared/IAPIPositionSearchOptions.ts
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * 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
+ ********************************************************************************/
+
+/**
+ * Interface which represents the options for a paginated search in the back end data base.
+ */
+export interface IAPIPositionSearchOptions {
+
+    /**
+     * Key to filter the search by type. Only show results of chosen type.
+     */
+    typeId?: number;
+
+    /**
+     * Key for filtering by due date.
+     */
+    dueDateFrom?: string;
+
+    /**
+     * Key for filtering by due date.
+     */
+    dueDateTo?: string;
+
+}
+
diff --git a/src/app/core/api/shared/IAPISearchOptions.ts b/src/app/core/api/shared/IAPISearchOptions.ts
index 3489b18..93d07f8 100644
--- a/src/app/core/api/shared/IAPISearchOptions.ts
+++ b/src/app/core/api/shared/IAPISearchOptions.ts
@@ -36,5 +36,50 @@
      */
     sort?: string;
 
+    /**
+     * Key to filter the search by type. Only show results of chosen type.
+     */
+    typeId?: number;
+
+    /**
+     * Key to filter the search by state. Show statements that are either finished or not.
+     */
+    finished?: string;
+
+    /**
+     * Key to filter for statements that have been edited by the user.
+     */
+    editedByMe?: string;
+
+    /**
+     * Key for filtering by creation date.
+     */
+    creationDateFrom?: string;
+
+    /**
+     * Key for filtering by creation date.
+     */
+    creationDateTo?: string;
+
+    /**
+     * Key for filtering by due date.
+     */
+    dueDateFrom?: string;
+
+    /**
+     * Key for filtering by due date.
+     */
+    dueDateTo?: string;
+
+    /**
+     * Key for filtering by receipt date.
+     */
+    receiptDateFrom?: string;
+
+    /**
+     * Key for filtering by receipt date.
+     */
+    receiptDateTo?: string;
+
 }
 
diff --git a/src/app/core/api/shared/index.ts b/src/app/core/api/shared/index.ts
index 12dd624..e23cace 100644
--- a/src/app/core/api/shared/index.ts
+++ b/src/app/core/api/shared/index.ts
@@ -12,4 +12,5 @@
  ********************************************************************************/
 
 export * from "./IAPIPaginationResponse";
+export * from "./IAPIPositionSearchOptions";
 export * from "./IAPISearchOptions";
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/core/api/statements/IAPIPositionSearchStatementModel.ts
similarity index 76%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/core/api/statements/IAPIPositionSearchStatementModel.ts
index 4d2360d..8de60b7 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/core/api/statements/IAPIPositionSearchStatementModel.ts
@@ -11,17 +11,13 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+export interface IAPIPositionSearchStatementModel {
 
-:host {
-  width: 100%;
-}
+    id: number;
+    title: string;
+    position: string;
+    typeId: string;
+    dueDate: string;
+    finished: boolean;
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
-}
-
-.statements--titlebar {
-  margin-bottom: 0.5em;
 }
diff --git a/src/app/core/api/statements/index.ts b/src/app/core/api/statements/index.ts
index 491e3ec..91527b0 100644
--- a/src/app/core/api/statements/index.ts
+++ b/src/app/core/api/statements/index.ts
@@ -14,5 +14,6 @@
 export * from "./IAPICommentModel";
 export * from "./IAPIStatementModel";
 export * from "./IAPIWorkflowData";
+export * from "./IAPIPositionSearchStatementModel";
 
 export * from "./statements-api.service";
diff --git a/src/app/core/api/statements/statements-api.service.ts b/src/app/core/api/statements/statements-api.service.ts
index 05cb28d..d611a35 100644
--- a/src/app/core/api/statements/statements-api.service.ts
+++ b/src/app/core/api/statements/statements-api.service.ts
@@ -17,8 +17,10 @@
 import {SPA_BACKEND_ROUTE} from "../../external-routes";
 import {IAPIDepartmentGroups} from "../settings";
 import {IAPIPaginationResponse, IAPISearchOptions} from "../shared";
+import {IAPIPositionSearchOptions} from "../shared/IAPIPositionSearchOptions";
 import {IAPICommentModel} from "./IAPICommentModel";
 import {IAPIDashboardStatementModel} from "./IAPIDashboardStatementModel";
+import {IAPIPositionSearchStatementModel} from "./IAPIPositionSearchStatementModel";
 import {IAPISectorsModel} from "./IAPISectorsModel";
 import {IAPIPartialStatementModel, IAPIStatementModel} from "./IAPIStatementModel";
 import {IAPIWorkflowData} from "./IAPIWorkflowData";
@@ -55,6 +57,15 @@
     }
 
     /**
+     *
+     */
+    public getStatementPositionsSearch(searchOptions: IAPIPositionSearchOptions) {
+        const endPoint = `statementpositionsearch`;
+        const params = objectToHttpParams({...searchOptions});
+        return this.httpClient.get<IAPIPositionSearchStatementModel[]>(urlJoin(this.baseUrl, endPoint), {params});
+    }
+
+    /**
      * Fetches all basic details for a specific statement.
      * @param id Id of the statement to fetch.
      */
@@ -119,6 +130,15 @@
         return this.httpClient.get<number[]>(urlJoin(this.baseUrl, endPoint));
     }
 
+
+    /**
+     * Fetches the IDs of all children of a specific statement.
+     */
+    public getChildrenIds(statementId: number) {
+        const endPoint = `/process/statements/${statementId}/workflow/children`;
+        return this.httpClient.get<number[]>(urlJoin(this.baseUrl, endPoint));
+    }
+
     /**
      * Updates the IDs of all parents to specific statement in the back end data base.
      */
diff --git a/src/app/core/configuration/app-configuration.token.ts b/src/app/core/configuration/app-configuration.token.ts
new file mode 100644
index 0000000..5b5eeba
--- /dev/null
+++ b/src/app/core/configuration/app-configuration.token.ts
@@ -0,0 +1,44 @@
+/********************************************************************************
+ * 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 {InjectionToken} from "@angular/core";
+import {gis, leaflet, nominatim, routes} from "../../../../app.config.json";
+
+export interface IAppConfiguration {
+    gis: {
+        urlTemplate: string;
+        projectionFrom: string;
+        projectionTo: string;
+    };
+    leaflet: {
+        urlTemplate: string;
+        attribution?: string;
+        lat: number;
+        lng: number;
+        zoom: number;
+    };
+    nominatim: {
+        url: string;
+        searchQueryPrefix?: string;
+    };
+    routes: {
+        spaBackend: string;
+        portal: string;
+        contactDataBase: string;
+    };
+}
+
+export const APP_CONFIGURATION = new InjectionToken<IAppConfiguration>("App configuration object", {
+    providedIn: "root",
+    factory: () => ({gis, leaflet, nominatim, routes})
+});
diff --git a/src/app/features/search/components/search/index.ts b/src/app/core/configuration/index.ts
similarity index 92%
copy from src/app/features/search/components/search/index.ts
copy to src/app/core/configuration/index.ts
index 5eb9c7f..abeb879 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/core/configuration/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./app-configuration.token";
diff --git a/src/app/core/external-routes/contact-data-base-route.token.ts b/src/app/core/external-routes/contact-data-base-route.token.ts
index d0d9d47..33e992f 100644
--- a/src/app/core/external-routes/contact-data-base-route.token.ts
+++ b/src/app/core/external-routes/contact-data-base-route.token.ts
@@ -12,12 +12,13 @@
  ********************************************************************************/
 
 import {InjectionToken} from "@angular/core";
-import {environment} from "../../../environments/environment";
+import * as config from "../../../../app.config.json";
+import {IAppConfiguration} from "../configuration";
 
 /**
  * Injection token for the external route to the contact base module.
  */
 export const CONTACT_DATA_BASE_ROUTE = new InjectionToken<string>("External route to the contact data base module", {
     providedIn: "root",
-    factory: () => environment.routes.contactDataBase
+    factory: () => (config as IAppConfiguration).routes.contactDataBase
 });
diff --git a/src/app/core/external-routes/nominatim-route.token.ts b/src/app/core/external-routes/nominatim-route.token.ts
new file mode 100644
index 0000000..06202c8
--- /dev/null
+++ b/src/app/core/external-routes/nominatim-route.token.ts
@@ -0,0 +1,24 @@
+/********************************************************************************
+ * 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 {InjectionToken} from "@angular/core";
+import * as config from "../../../../app.config.json";
+import {IAppConfiguration} from "../configuration";
+
+/**
+ * Injection token for the external route to the backend server.
+ */
+export const NOMINATIM_ROUTE = new InjectionToken<string>("External route to nominatim geocoding service", {
+    providedIn: "root",
+    factory: () => (config as IAppConfiguration).nominatim.url
+});
diff --git a/src/app/core/external-routes/portal-route.token.ts b/src/app/core/external-routes/portal-route.token.ts
index d79a806..d6379e3 100644
--- a/src/app/core/external-routes/portal-route.token.ts
+++ b/src/app/core/external-routes/portal-route.token.ts
@@ -12,12 +12,13 @@
  ********************************************************************************/
 
 import {InjectionToken} from "@angular/core";
-import {environment} from "../../../environments/environment";
+import * as config from "../../../../app.config.json";
+import {IAppConfiguration} from "../configuration";
 
 /**
  * Injection token for the external route to the main portal.
  */
 export const PORTAL_ROUTE = new InjectionToken<string>("External route to entry portal", {
     providedIn: "root",
-    factory: () => environment.routes.portal
+    factory: () => (config as IAppConfiguration).routes.portal
 });
diff --git a/src/app/core/external-routes/spa-backend-route.token.ts b/src/app/core/external-routes/spa-backend-route.token.ts
index 578c2aa..fc14abb 100644
--- a/src/app/core/external-routes/spa-backend-route.token.ts
+++ b/src/app/core/external-routes/spa-backend-route.token.ts
@@ -12,12 +12,13 @@
  ********************************************************************************/
 
 import {InjectionToken} from "@angular/core";
-import {environment} from "../../../environments/environment";
+import * as config from "../../../../app.config.json";
+import {IAppConfiguration} from "../configuration";
 
 /**
  * Injection token for the external route to the backend server.
  */
 export const SPA_BACKEND_ROUTE = new InjectionToken<string>("Base url for back end", {
     providedIn: "root",
-    factory: () => environment.routes.spaBackend
+    factory: () => (config as IAppConfiguration).routes.spaBackend
 });
diff --git a/src/app/core/index.ts b/src/app/core/index.ts
index c5164a0..ecefda5 100644
--- a/src/app/core/index.ts
+++ b/src/app/core/index.ts
@@ -13,6 +13,7 @@
 
 export * from "./api";
 export * from "./auth";
+export * from "./configuration";
 export * from "./dom";
 export * from "./download";
 export * from "./external-routes";
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/attachments/index.ts
similarity index 90%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/attachments/index.ts
index 5eb9c7f..f44ee5e 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/attachments/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-attachments.component";
diff --git a/src/app/features/details/components/attachments/statement-details-attachments.component.html b/src/app/features/details/components/attachments/statement-details-attachments.component.html
new file mode 100644
index 0000000..2b66156
--- /dev/null
+++ b/src/app/features/details/components/attachments/statement-details-attachments.component.html
@@ -0,0 +1,77 @@
+<!-------------------------------------------------------------------------------
+ * 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.attachments.title' | translate">
+
+  <div *ngIf="(statementAttachments$| async)?.length > 0 || mailTextAttachment != null"
+       class="attachments">
+
+    <div *ngIf="mailTextAttachment"
+         class="attachments--email">
+      <app-attachment-display-list
+        (appDownload)="downloadAttachment($event)"
+        [appAttachments]="[mailTextAttachment]"
+        [appTagList]="[]"
+        [appTitle]="'details.attachments.email' | translate">
+      </app-attachment-display-list>
+    </div>
+
+    <div
+      *ngIf="(allAttachments$ | async)?.length > 0 || (statementAttachments$ | async)?.length > 0">
+      <div *ngIf="availableTags?.length > 0"
+           class="attachments--documents--filter-btns">
+        <button (click)="deselectAllTags()"
+                class="openk-button openk-button-rounded"
+                type="button">
+          <mat-icon>filter_list</mat-icon>
+        </button>
+
+        <ng-container *ngFor="let tag of availableTags">
+          <button (click)="toggleTag(tag)"
+                  [class.openk-info]="tag?.isSelected"
+                  class="openk-button openk-chip">
+            {{tag?.label}}
+          </button>
+        </ng-container>
+      </div>
+
+
+      <div class="attachments--documents--lists">
+        <app-attachment-display-list
+          (appDownload)="downloadAttachment($event)"
+          [appAttachments]="allAttachments"
+          [appTagList]="tags$ | async"
+          [appTitle]="'details.attachments.emailDocuments' | translate"
+          class="attachments--document--lists---half-size attachments--document--lists---space-between">
+        </app-attachment-display-list>
+
+        <app-attachment-display-list
+          (appDownload)="downloadAttachment($event)"
+          [appAttachments]="statementAttachments"
+          [appTagList]="tags$ | async"
+          [appTitle]="'Manuell hinzugefügte Anhänge'"
+          class="attachments--document--lists---half-size">
+        </app-attachment-display-list>
+      </div>
+
+    </div>
+  </div>
+
+  <div *ngIf="!((statementAttachments$| async)?.length > 0 || mailTextAttachment != null)"
+       class="placeholder">
+    {{"details.attachments.placeholder" | translate}}
+  </div>
+
+</app-collapsible>
diff --git a/src/app/features/details/components/attachments/statement-details-attachments.component.scss b/src/app/features/details/components/attachments/statement-details-attachments.component.scss
new file mode 100644
index 0000000..d100724
--- /dev/null
+++ b/src/app/features/details/components/attachments/statement-details-attachments.component.scss
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * 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;
+}
+
+.attachments {
+  padding: 1em;
+}
+
+.attachments--email {
+  display: inline-block;
+  margin-bottom: 0.5em;
+}
+
+.attachments--documents--filter-btns {
+  margin-bottom: 0.1em;
+}
+
+.attachments--documents--lists {
+  display: flex;
+  flex-direction: row;
+}
+
+.attachments--document--lists---half-size {
+  flex: 1;
+}
+
+.attachments--document--lists---space-between {
+  margin-right: 0.5em;
+}
+
+.openk-button-rounded {
+  font-size: 1.15em;
+  border: 0;
+  color: get-color($openk-info-palette);
+  margin-right: 0.25em;
+
+  &:not(.openk-info) {
+    background-color: transparent;
+  }
+
+  &:not(.openk-info):active,
+  &:not(.openk-info):focus,
+  &:not(.openk-info):hover {
+    background-color: $openk-background-highlight;
+  }
+}
+
+.openk-chip {
+  margin-right: 0.25em;
+}
diff --git a/src/app/features/details/components/attachments/statement-details-attachments.component.spec.ts b/src/app/features/details/components/attachments/statement-details-attachments.component.spec.ts
new file mode 100644
index 0000000..78958ea
--- /dev/null
+++ b/src/app/features/details/components/attachments/statement-details-attachments.component.spec.ts
@@ -0,0 +1,118 @@
+/********************************************************************************
+ * 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, IAPIAttachmentModel} from "../../../../core";
+import {IAttachmentControlValue, queryParamsIdSelector, startAttachmentDownloadAction} from "../../../../store";
+import {StatementDetailsModule} from "../../statement-details.module";
+import {StatementDetailsAttachmentsComponent} from "./statement-details-attachments.component";
+
+describe("StatementDetailsAttachmentsComponent", () => {
+    let component: StatementDetailsAttachmentsComponent;
+    let fixture: ComponentFixture<StatementDetailsAttachmentsComponent>;
+    let store: Store;
+
+    const attachments: IAttachmentControlValue[] = [
+        {name: "attachment1", tagIds: ["tag1", "email"]},
+        {name: "attachment2", tagIds: ["email", "tag3"]},
+        {name: "attachment3", tagIds: ["tag1", "tag2"]},
+        {name: "attachment4", tagIds: ["tag1", "tag2", "email"]}
+    ];
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                StatementDetailsModule,
+                I18nModule
+            ],
+            providers: [
+                provideMockStore({
+                    initialState: {},
+                    selectors: [
+                        {
+                            selector: queryParamsIdSelector,
+                            value: 19
+                        }
+                    ]
+                })
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(StatementDetailsAttachmentsComponent);
+        component = fixture.componentInstance;
+        store = fixture.componentRef.injector.get(Store);
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should return only the attachments containing at least one of the selected tags", () => {
+        component.availableTags = [
+            {label: "tag1", id: "tag1", isSelected: true},
+            {label: "tag2", id: "tag2", isSelected: true},
+            {label: "tag3", id: "tag3", isSelected: false}
+        ];
+
+        const result = component.filterBySelectedTags(attachments);
+        expect(result).toEqual([
+            {name: "attachment1", tagIds: ["tag1", "email"]},
+            {name: "attachment3", tagIds: ["tag1", "tag2"]},
+            {name: "attachment4", tagIds: ["tag1", "tag2", "email"]}
+        ]);
+    });
+
+    it("should select all available tags", () => {
+        component.availableTags = [
+            {label: "tag1", id: "tag1", isSelected: true},
+            {label: "tag2", id: "tag2", isSelected: false},
+            {label: "tag3", id: "tag3", isSelected: false}
+        ];
+        component.deselectAllTags();
+        expect(component.availableTags).toEqual([
+            {label: "tag1", id: "tag1", isSelected: false},
+            {label: "tag2", id: "tag2", isSelected: false},
+            {label: "tag3", id: "tag3", isSelected: false}
+        ]);
+    });
+
+    it("should toggle the tag state or set to given value", () => {
+        const tag = {label: "tag1", id: "tag1", isSelected: true};
+        component.toggleTag(tag);
+        expect(tag.isSelected).toBeFalse();
+        component.toggleTag(tag);
+        expect(tag.isSelected).toBeTrue();
+        component.toggleTag(tag, true);
+        expect(tag.isSelected).toBeTrue();
+    });
+
+    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}));
+    });
+
+    it("should only return the email attachments", () => {
+        const emailAttachments = component.filterForEmailAttachments(attachments as IAPIAttachmentModel[]);
+        expect(emailAttachments).toEqual([
+            {name: "attachment1", tagIds: ["tag1", "email"]},
+            {name: "attachment2", tagIds: ["email", "tag3"]},
+            {name: "attachment4", tagIds: ["tag1", "tag2", "email"]}
+        ] as IAPIAttachmentModel[]);
+    });
+});
diff --git a/src/app/features/details/components/attachments/statement-details-attachments.component.ts b/src/app/features/details/components/attachments/statement-details-attachments.component.ts
new file mode 100644
index 0000000..026f1d9
--- /dev/null
+++ b/src/app/features/details/components/attachments/statement-details-attachments.component.ts
@@ -0,0 +1,139 @@
+/********************************************************************************
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {select, Store} from "@ngrx/store";
+import {combineLatest, Subject} from "rxjs";
+import {filter, take, takeUntil} from "rxjs/operators";
+import {AUTO_SELECTED_TAGS, IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {startAttachmentDownloadAction} from "../../../../store/attachments/actions";
+import {IAttachmentControlValue} from "../../../../store/attachments/model";
+import {
+    getAllStatementAttachments,
+    getAttachmentControlValueSelector,
+    getFilteredAttachmentTagsSelector
+} from "../../../../store/attachments/selectors";
+import {queryParamsIdSelector} from "../../../../store/root/selectors";
+import {filterDistinctValues} from "../../../../util/store";
+import {getMailAttachment} from "../../../forms/attachments/util/mail-attachments.util";
+
+/**
+ * This component displays the list of attachments saved with the statement.
+ * It's split up into 3 different categories:
+ * mail-text, attachments manually added to the statement and the attachments copied from the initial email.
+ *
+ * The attachment lists can be filtered to only show attachments with specific tags.
+ * The available tags for filtering are all the used tags on the statements attachments.
+ */
+
+@Component({
+    selector: "app-statement-details-attachments",
+    templateUrl: "./statement-details-attachments.component.html",
+    styleUrls: ["./statement-details-attachments.component.scss"]
+})
+export class StatementDetailsAttachmentsComponent implements OnInit, OnDestroy {
+
+    @Input()
+    public appCollapsed = false;
+
+    public allAttachments$ = this.store.pipe(select(getAllStatementAttachments));
+
+    public allAttachments: IAttachmentControlValue[] = [];
+
+    public statementAttachments$ = this.store.pipe(select(getAttachmentControlValueSelector, {forbiddenTagIds: AUTO_SELECTED_TAGS}));
+
+    public statementAttachments: IAttachmentControlValue[] = [];
+
+    public availableTags: { label: string, id: string, isSelected: boolean }[] = [];
+
+    public tags$ = this.store.pipe(select(getFilteredAttachmentTagsSelector, {without: AUTO_SELECTED_TAGS}));
+
+    public statementId$ = this.store.pipe(select(queryParamsIdSelector));
+
+    public mailTextAttachment: IAPIAttachmentModel;
+
+    private destroy$ = new Subject();
+
+    public constructor(public store: Store) {
+    }
+
+    public ngOnInit() {
+        combineLatest([this.allAttachments$, this.tags$]).pipe(
+            takeUntil(this.destroy$)
+        ).subscribe(([attachments, tags]) => {
+            const allTags = filterDistinctValues(attachments.map((attachment) => attachment.tagIds).reduce((_, x) => x.concat(_), []));
+            this.availableTags = tags.filter((_) => allTags.find((a) => a === _.id))
+                .map((_) => ({..._, isSelected: false}));
+        });
+        this.statementAttachments$.pipe(
+            takeUntil(this.destroy$)
+        ).subscribe((attachments) => {
+            this.statementAttachments = this.filterBySelectedTags(attachments);
+        });
+        this.allAttachments$.pipe(
+            filter((attachments) => attachments != null)
+        ).subscribe(async (attachments) => {
+            const mailAttachments = this.filterForEmailAttachments(attachments);
+            this.mailTextAttachment = getMailAttachment(attachments);
+            this.allAttachments = this.filterBySelectedTags(mailAttachments);
+        });
+    }
+
+    public ngOnDestroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
+    public async toggleTag(tag, state?: boolean) {
+        tag.isSelected = state != null ? state : !tag.isSelected;
+        const sAttachments = await this.statementAttachments$.pipe(take(1)).toPromise();
+        this.statementAttachments = this.filterBySelectedTags(sAttachments);
+        const aAttachments = await this.allAttachments$.pipe(take(1)).toPromise();
+        const mailAttachments = this.filterForEmailAttachments(aAttachments);
+        this.allAttachments = this.filterBySelectedTags(mailAttachments);
+    }
+
+    public filterForEmailAttachments(attachments: IAPIAttachmentModel[]) {
+        return attachments.filter((attachment) => {
+            return attachment.tagIds.find((_) => _ === "email") != null &&
+                attachment.tagIds.find((_) => _ === "email-text") == null;
+        });
+    }
+
+    public deselectAllTags() {
+        for (const tag of this.availableTags) {
+            this.toggleTag(tag, false);
+        }
+    }
+
+    public async downloadAttachment(attachmentId: number) {
+        const statementId = await this.statementId$.pipe(take(1)).toPromise();
+        this.store.dispatch(startAttachmentDownloadAction({statementId, attachmentId}));
+    }
+
+    public filterBySelectedTags(attachments: IAttachmentControlValue[]) {
+        return attachments.filter((attachment) => {
+            const selectedTags = this.availableTags?.filter((_) => _.isSelected);
+            if (selectedTags?.length === 0) {
+                return true;
+            }
+            for (const tagId of attachment?.tagIds) {
+                const tagIsSelected = this.availableTags.find((_) => _.id === tagId)?.isSelected;
+                if (tagIsSelected) {
+                    return true;
+                }
+            }
+            return false;
+        });
+    }
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/considerations/index.ts
similarity index 89%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/considerations/index.ts
index 5eb9c7f..8dc78de 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/considerations/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-considerations.component";
diff --git a/src/app/features/details/components/considerations/statement-details-considerations.component.html b/src/app/features/details/components/considerations/statement-details-considerations.component.html
new file mode 100644
index 0000000..5ecd60c
--- /dev/null
+++ b/src/app/features/details/components/considerations/statement-details-considerations.component.html
@@ -0,0 +1,45 @@
+<!-------------------------------------------------------------------------------
+ * 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
+  *ngIf="appFinished"
+  [(appCollapsed)]="appCollapsed"
+  [appTitle]="'details.considerations.title' | translate">
+
+  <div *ngIf="((considerations$ | async)?.length > 0) || (isOfficialInCharge$ | async)"
+       class="attachments--files">
+    <app-attachment-display-list
+      (appDownload)="downloadAttachment($event)"
+      *ngIf="(considerations$ | async)?.length > 0"
+      [appAttachments]="considerations$ | async"
+      [appTitle]="'details.considerations.attachments' | translate"
+      class="attachments--document--lists---half-size">
+    </app-attachment-display-list>
+
+    <app-attachment-file-drop-form
+      *ngIf="isOfficialInCharge$ | async"
+      [appFormArrayName]="'considerations'"
+      [appFormGroup]="appFormGroup"
+      [appTitle]="'attachments.add' | translate"
+      class="attachments--container">
+      <button (click)="submit()" class="openk-button openk-success"
+              style="margin-left: 0.25em;">{{'details.considerations.upload' | translate}}</button>
+    </app-attachment-file-drop-form>
+  </div>
+
+  <div *ngIf="!(((considerations$ | async)?.length > 0) || (isOfficialInCharge$ | async))"
+       class="placeholder">
+    {{"details.considerations.placeholder" | translate}}
+  </div>
+
+</app-collapsible>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/details/components/considerations/statement-details-considerations.component.scss
similarity index 62%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/details/components/considerations/statement-details-considerations.component.scss
index 4d2360d..6bc3cc8 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/details/components/considerations/statement-details-considerations.component.scss
@@ -11,17 +11,34 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
 :host {
+  display: block;
   width: 100%;
+
+  &:empty {
+    display: none;
+  }
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
+.attachments--container {
+  min-height: 10em;
+  flex: 1;
 }
 
-.statements--titlebar {
-  margin-bottom: 0.5em;
+.attachments--document--lists---half-size {
+  flex: 1;
+  display: inline-block;
+  margin-right: 0.5em;
+}
+
+.attachments--files {
+  padding: 1em;
+  display: flex;
+}
+
+.placeholder {
+  padding: 1em;
+  font-style: italic;
 }
diff --git a/src/app/features/details/components/considerations/statement-details-considerations.component.spec.ts b/src/app/features/details/components/considerations/statement-details-considerations.component.spec.ts
new file mode 100644
index 0000000..3eadbdc
--- /dev/null
+++ b/src/app/features/details/components/considerations/statement-details-considerations.component.spec.ts
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * 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 {IAttachmentControlValue} from "../../../../store/attachments/model";
+import {setErrorAction} from "../../../../store/root/actions";
+import {queryParamsIdSelector} from "../../../../store/root/selectors";
+import {submitConsiderationFilesAction} from "../../../../store/statements/actions";
+import {StatementDetailsModule} from "../../statement-details.module";
+import {StatementDetailsConsiderationsComponent} from "./statement-details-considerations.component";
+
+describe("StatementDetailsConsiderationsComponent", () => {
+    let component: StatementDetailsConsiderationsComponent;
+    let fixture: ComponentFixture<StatementDetailsConsiderationsComponent>;
+    let store: Store;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                StatementDetailsModule,
+                I18nModule
+            ],
+            providers: [
+                provideMockStore({
+                    initialState: {},
+                    selectors: [
+                        {
+                            selector: queryParamsIdSelector,
+                            value: 19
+                        }
+                    ]
+                })
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(StatementDetailsConsiderationsComponent);
+        component = fixture.componentInstance;
+        store = fixture.componentRef.injector.get(Store);
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should dispatch submitConsiderationFilesAction on submitting with the current files from cache", async () => {
+        const dispatchSpy = spyOn(store, "dispatch");
+        const file: IAttachmentControlValue = {name: "file1", tagIds: []};
+        component.setValueForArray([file], "considerations");
+        await component.submit();
+        expect(dispatchSpy).toHaveBeenCalledWith(setErrorAction({statementId: 19, error: null}));
+        expect(dispatchSpy).toHaveBeenCalledWith(submitConsiderationFilesAction({
+            statementId: 19, value: [file]
+        }));
+    });
+
+    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}));
+    });
+});
diff --git a/src/app/features/details/components/considerations/statement-details-considerations.component.ts b/src/app/features/details/components/considerations/statement-details-considerations.component.ts
new file mode 100644
index 0000000..a79cd2e
--- /dev/null
+++ b/src/app/features/details/components/considerations/statement-details-considerations.component.ts
@@ -0,0 +1,89 @@
+/********************************************************************************
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {FormArray} from "@angular/forms";
+import {select, Store} from "@ngrx/store";
+import {delay, take, takeUntil} from "rxjs/operators";
+import {startAttachmentDownloadAction} from "../../../../store/attachments/actions";
+import {IAttachmentControlValue} from "../../../../store/attachments/model";
+import {getConsiderationAttachments, getStatementAttachmentCacheSelector} from "../../../../store/attachments/selectors";
+import {setErrorAction} from "../../../../store/root/actions";
+import {isOfficialInChargeSelector, queryParamsIdSelector} from "../../../../store/root/selectors";
+import {submitConsiderationFilesAction} from "../../../../store/statements/actions";
+import {statementLoadingSelector} from "../../../../store/statements/selectors";
+import {createFormGroup} from "../../../../util/forms";
+import {AbstractReactiveFormComponent} from "../../../forms/abstract";
+
+@Component({
+    selector: "app-statement-details-considerations",
+    templateUrl: "./statement-details-considerations.component.html",
+    styleUrls: ["./statement-details-considerations.component.scss"]
+})
+export class StatementDetailsConsiderationsComponent
+    extends AbstractReactiveFormComponent<{ considerations: IAttachmentControlValue[] }> implements OnInit, OnDestroy {
+
+    @Input()
+    public appCollapsed = false;
+
+    @Input()
+    public appFinished: boolean;
+
+    @Input()
+    public appFormGroup = createFormGroup<{ considerations: IAttachmentControlValue[] }>({
+        considerations: new FormArray([])
+    });
+
+    public isOfficialInCharge$ = this.store.pipe(select(isOfficialInChargeSelector));
+
+    public statementId$ = this.store.pipe(select(queryParamsIdSelector));
+
+    public considerations$ = this.store.pipe(select(getConsiderationAttachments));
+
+    public fileCache$ = this.store.pipe(select(getStatementAttachmentCacheSelector));
+
+    public isStatementLoading$ = this.store.pipe(select(statementLoadingSelector));
+
+    public constructor(public readonly store: Store) {
+        super();
+    }
+
+    public ngOnInit() {
+        this.fileCache$.pipe(delay(0), takeUntil(this.destroy$))
+            .subscribe((values) => this.setValueForArray(values, "considerations"));
+    }
+
+    public async submit() {
+        await this.clearErrors();
+        const statementId = await this.statementId$.pipe(take(1)).toPromise();
+        const value = this.getValue("considerations");
+        this.store.dispatch(submitConsiderationFilesAction({
+            statementId,
+            value
+        }));
+    }
+
+    public async downloadAttachment(attachmentId: number) {
+        const statementId = await this.statementId$.pipe(take(1)).toPromise();
+        this.store.dispatch(startAttachmentDownloadAction({statementId, attachmentId}));
+    }
+
+    private async clearErrors() {
+        const statementId = await this.statementId$.pipe(take(1)).toPromise();
+        const loading = await this.isStatementLoading$.pipe(take(1)).toPromise();
+        if (statementId != null && !loading) {
+            this.store.dispatch(setErrorAction({statementId, error: null}));
+        }
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/contributions/index.ts
similarity index 89%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/contributions/index.ts
index 5eb9c7f..42d5307 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/contributions/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-contributions.component";
diff --git a/src/app/features/details/components/contributions/statement-details-contributions.component.html b/src/app/features/details/components/contributions/statement-details-contributions.component.html
new file mode 100644
index 0000000..77ada97
--- /dev/null
+++ b/src/app/features/details/components/contributions/statement-details-contributions.component.html
@@ -0,0 +1,34 @@
+<!-------------------------------------------------------------------------------
+ * 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]="('statementEditorForm.container.contributionStatus' | translate)
+     + ' (' + (contributions$ | async)?.selected?.length + '/' + (requiredContributionOptions$ | async).length + ')'"
+  class="statement-details">
+
+  <app-select-group
+    *ngIf="(requiredContributionOptions$ | async)?.length > 0"
+    [appGroups]="requiredContributionGroups$ | async"
+    [appHideControls]="true"
+    [appOptions]="requiredContributionOptions$ | async"
+    [appValue]="contributions$ | async"
+    style="padding: 1em;">
+  </app-select-group>
+
+  <div *ngIf="!((requiredContributionOptions$ | async)?.length > 0)"
+       class="placeholder">
+    {{"details.contributions.placeholder" | translate}}
+  </div>
+
+</app-collapsible>
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/contributions/statement-details-contributions.component.scss
similarity index 80%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/contributions/statement-details-contributions.component.scss
index 5eb9c7f..8e1723d 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/contributions/statement-details-contributions.component.scss
@@ -11,4 +11,16 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+:host {
+  display: block;
+  width: 100%;
+
+  &:empty {
+    display: none;
+  }
+}
+
+.placeholder {
+  padding: 1em;
+  font-style: italic;
+}
diff --git a/src/app/features/details/components/contributions/statement-details-contributions.component.spec.ts b/src/app/features/details/components/contributions/statement-details-contributions.component.spec.ts
new file mode 100644
index 0000000..65b5fc2
--- /dev/null
+++ b/src/app/features/details/components/contributions/statement-details-contributions.component.spec.ts
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * 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 {StatementDetailsContributionsComponent} from "./statement-details-contributions.component";
+
+describe("StatementDetailsContributionsComponent", () => {
+    let component: StatementDetailsContributionsComponent;
+    let fixture: ComponentFixture<StatementDetailsContributionsComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                StatementDetailsModule,
+                I18nModule
+            ],
+            providers: [provideMockStore()]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(StatementDetailsContributionsComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/src/app/features/details/components/contributions/statement-details-contributions.component.ts b/src/app/features/details/components/contributions/statement-details-contributions.component.ts
new file mode 100644
index 0000000..68a0f83
--- /dev/null
+++ b/src/app/features/details/components/contributions/statement-details-contributions.component.ts
@@ -0,0 +1,46 @@
+/********************************************************************************
+ * 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 {
+    getContributionsSelector,
+    requiredContributionsGroupsSelector,
+    requiredContributionsOptionsSelector
+} from "../../../../store/statements/selectors";
+
+/**
+ * This component shows the current state of contributions of the statement. This display is purely visual. No editing possible.
+ */
+
+@Component({
+    selector: "app-statement-details-contributions",
+    templateUrl: "./statement-details-contributions.component.html",
+    styleUrls: ["./statement-details-contributions.component.scss"]
+})
+export class StatementDetailsContributionsComponent {
+
+    @Input()
+    public appCollapsed = false;
+
+    public requiredContributionOptions$ = this.store.pipe(select(requiredContributionsOptionsSelector));
+
+    public requiredContributionGroups$ = this.store.pipe(select(requiredContributionsGroupsSelector));
+
+    public contributions$ = this.store.pipe(select(getContributionsSelector));
+
+    public constructor(public store: Store) {
+
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/geographic-position/index.ts
similarity index 89%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/geographic-position/index.ts
index 5eb9c7f..fc00319 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/geographic-position/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-geographic-position.component";
diff --git a/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.html b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.html
new file mode 100644
index 0000000..928dde4
--- /dev/null
+++ b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.html
@@ -0,0 +1,37 @@
+<!-------------------------------------------------------------------------------
+ * 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]="'Geographische Position'">
+
+  <div *ngIf="(geographicPosition$ | async) != null"
+       class="map">
+
+    <app-leaflet-map
+      (appOpenGis)="openGis($event)"
+      [appCenter]="geographicPosition$ | async">
+
+      <ng-container [appLeafletMarker]="geographicPosition$ | async">
+      </ng-container>
+
+    </app-leaflet-map>
+
+  </div>
+
+  <div *ngIf="!((geographicPosition$ | async) != null)"
+       class="placeholder">
+    {{"details.geoPositions.placeholder" | translate}}
+  </div>
+
+</app-collapsible>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.scss
similarity index 73%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/details/components/geographic-position/statement-details-geographic-position.component.scss
index 4d2360d..d94ab9c 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.scss
@@ -11,17 +11,25 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
 :host {
+  display: block;
   width: 100%;
+
+  &:empty {
+    display: none;
+  }
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
+.placeholder {
+  padding: 1em;
+  font-style: italic;
 }
 
-.statements--titlebar {
-  margin-bottom: 0.5em;
+.map {
+  width: 100%;
+  height: 30em;
+  padding: 1em;
+  box-sizing: border-box;
 }
diff --git a/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.spec.ts b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.spec.ts
new file mode 100644
index 0000000..9be77b7
--- /dev/null
+++ b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.spec.ts
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * 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 {MockStore, provideMockStore} from "@ngrx/store/testing";
+import {I18nModule} from "../../../../core/i18n";
+import {ILeafletBounds} from "../../../../shared/leaflet/directives/leaflet";
+import {openGisAction} from "../../../../store/geo/actions";
+import {userNameSelector} from "../../../../store/root/selectors";
+import {StatementDetailsModule} from "../../statement-details.module";
+import {StatementDetailsGeographicPositionComponent} from "./statement-details-geographic-position.component";
+
+describe("StatementDetailsGeographicPositionComponent", () => {
+    const user = "userName";
+
+    let component: StatementDetailsGeographicPositionComponent;
+    let fixture: ComponentFixture<StatementDetailsGeographicPositionComponent>;
+    let store: MockStore;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                StatementDetailsModule,
+                I18nModule
+            ],
+            providers: [
+                provideMockStore({
+                    selectors: [{selector: userNameSelector, value: user}]
+                })
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(StatementDetailsGeographicPositionComponent);
+        store = TestBed.inject(MockStore);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should open GIS", () => {
+        spyOn(store, "dispatch");
+        const bounds = {} as ILeafletBounds;
+        component.openGis(bounds);
+        expect(store.dispatch).toHaveBeenCalledWith(openGisAction({bounds, user}));
+    });
+
+});
diff --git a/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.ts b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.ts
new file mode 100644
index 0000000..d249aaa
--- /dev/null
+++ b/src/app/features/details/components/geographic-position/statement-details-geographic-position.component.ts
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * 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 {ILeafletBounds} from "../../../../shared/leaflet";
+import {openGisAction, statementGeographicPositionSelector, userNameSelector} from "../../../../store";
+
+/**
+ * This component displays the statements coordinates on a map using leaflet.
+ * No editing of the set coordinates is possible.
+ */
+
+@Component({
+    selector: "app-statement-details-geographic-position",
+    templateUrl: "./statement-details-geographic-position.component.html",
+    styleUrls: ["./statement-details-geographic-position.component.scss"]
+})
+export class StatementDetailsGeographicPositionComponent {
+
+    @Input()
+    public appCollapsed = false;
+
+    public geographicPosition$ = this.store.pipe(select(statementGeographicPositionSelector));
+
+    public userName$ = this.store.pipe(select(userNameSelector));
+
+    public constructor(public store: Store) {
+
+    }
+
+    public openGis(bounds: ILeafletBounds) {
+        this.userName$.pipe(take(1)).subscribe((user) => {
+            this.store.dispatch(openGisAction({bounds, user}));
+        });
+    }
+
+}
diff --git a/src/app/features/details/components/index.ts b/src/app/features/details/components/index.ts
index afadae7..d62a2b3 100644
--- a/src/app/features/details/components/index.ts
+++ b/src/app/features/details/components/index.ts
@@ -11,6 +11,12 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
+export * from "./attachments";
+export * from "./contributions";
+export * from "./geographic-position";
+export * from "./information";
+export * from "./linked-statements";
+export * from "./process-information";
+
 export * from "./statement-details";
 export * from "./side-menu";
-export * from "./process-information";
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/information/index.ts
similarity index 90%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/information/index.ts
index 5eb9c7f..b5b3679 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/information/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-information.component";
diff --git a/src/app/features/details/components/information/statement-details-information.component.html b/src/app/features/details/components/information/statement-details-information.component.html
new file mode 100644
index 0000000..a94d7a7
--- /dev/null
+++ b/src/app/features/details/components/information/statement-details-information.component.html
@@ -0,0 +1,60 @@
+<!-------------------------------------------------------------------------------
+ * 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]="'Allgemeine Informationen'">
+
+  <div class="information">
+
+    <div class="information-display-container">
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.title" | translate}}</span>
+      <span>{{appStatementInfo?.title}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.typeId" | translate}}</span>
+      <span>{{statementType}}</span>
+      <span
+        class="information--identifiers--key">{{"statementInformationForm.controls.creationDate" | translate}}</span>
+      <span>{{(appStatementInfo?.creationDate | appMomentPipe)?.format(timeFormat)}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.receiptDate" | translate}}</span>
+      <span>{{(appStatementInfo?.receiptDate | appMomentPipe)?.format(timeFormat)}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.dueDate" | translate}}</span>
+      <span>{{(appStatementInfo?.dueDate | appMomentPipe)?.format(timeFormat)}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.city" | translate}}</span>
+      <span>{{appStatementInfo?.city}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.district" | translate}}</span>
+      <span>{{appStatementInfo?.district}}</span>
+      <span class="information--identifiers--key">{{"statementInformationForm.controls.sectors" | translate}}</span>
+      <span>
+        {{(sectors$ | async | sector : appStatementInfo?.city : appStatementInfo?.district) ?
+        (sectors$ | async | sector : appStatementInfo?.city : appStatementInfo?.district) :
+        "shared.sectors.none" | translate}}
+      </span>
+      <span *ngIf="appStatementInfo?.customerReference"
+            class="information--identifiers--key">{{"statementInformationForm.controls.customerReference" | translate}}</span>
+      <span *ngIf="appStatementInfo?.customerReference">{{appStatementInfo?.customerReference}}</span>
+    </div>
+
+    <div class="information--contact-details">
+      <span class="information--identifiers--key">{{"statementInformationForm.container.contact" | translate}}</span>
+      <div class="information--identifiers">
+        <span>{{appContactInfo?.company}}</span>
+        <span>{{appContactInfo?.firstName}} {{appContactInfo?.lastName}}</span>
+        <span>{{appContactInfo?.street}} {{appContactInfo?.houseNumber}}</span>
+        <span>{{appContactInfo?.postCode}} {{appContactInfo?.community}} {{appContactInfo?.communitySuffix}}</span>
+        <span>{{appContactInfo?.email}}</span>
+      </div>
+    </div>
+
+  </div>
+
+</app-collapsible>
diff --git a/src/app/features/details/components/information/statement-details-information.component.scss b/src/app/features/details/components/information/statement-details-information.component.scss
new file mode 100644
index 0000000..535cd5c
--- /dev/null
+++ b/src/app/features/details/components/information/statement-details-information.component.scss
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * 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;
+  }
+}
+
+.information {
+  display: flex;
+  flex-direction: row;
+  padding: 1em;
+  overflow: auto;
+}
+
+.information-display-container {
+  display: grid;
+  grid-template-columns: max-content auto;
+  grid-column-gap: 0.5em;
+  margin-right: 0.5em;
+  min-width: 20em;
+  flex: 1;
+
+  > * {
+    margin-bottom: 0.1em;
+  }
+}
+
+.information--identifiers {
+  display: flex;
+  flex-direction: column;
+  margin-right: 1em;
+  margin-left: 1em;
+
+  > * {
+    margin-bottom: 0.1em;
+  }
+}
+
+.information--identifiers--key {
+  font-weight: 600;
+  margin-bottom: 0.1em;
+}
+
+.information--contact-details {
+  display: flex;
+  flex-direction: column;
+  flex: 1;
+}
diff --git a/src/app/features/details/components/information/statement-details-information.component.spec.ts b/src/app/features/details/components/information/statement-details-information.component.spec.ts
new file mode 100644
index 0000000..dcf161f
--- /dev/null
+++ b/src/app/features/details/components/information/statement-details-information.component.spec.ts
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * 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 {StatementDetailsInformationComponent} from "./statement-details-information.component";
+
+describe("StatementDetailsInformationComponent", () => {
+    let component: StatementDetailsInformationComponent;
+    let fixture: ComponentFixture<StatementDetailsInformationComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                StatementDetailsModule,
+                I18nModule
+            ],
+            providers: [provideMockStore()]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(StatementDetailsInformationComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/src/app/features/details/components/information/statement-details-information.component.stories.ts b/src/app/features/details/components/information/statement-details-information.component.stories.ts
new file mode 100644
index 0000000..cf14a38
--- /dev/null
+++ b/src/app/features/details/components/information/statement-details-information.component.stories.ts
@@ -0,0 +1,38 @@
+/********************************************************************************
+ * 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 {provideMockStore} from "@ngrx/store/testing";
+import {withKnobs} from "@storybook/addon-knobs";
+import {moduleMetadata, storiesOf} from "@storybook/angular";
+import {I18nModule} from "../../../../core/i18n";
+import {StatementDetailsModule} from "../../statement-details.module";
+
+storiesOf("Features / Forms / Details", module)
+    .addDecorator(withKnobs)
+    .addDecorator(moduleMetadata({
+        providers: [
+            provideMockStore()
+        ],
+        imports: [
+            I18nModule,
+            StatementDetailsModule
+        ]
+    }))
+    .add("StatementDetailsInformationComponent", () => ({
+        template: `
+            <app-statement-details-information>
+            </app-statement-details-information>
+        `,
+        props: {}
+    }));
diff --git a/src/app/features/details/components/information/statement-details-information.component.ts b/src/app/features/details/components/information/statement-details-information.component.ts
new file mode 100644
index 0000000..1b5d600
--- /dev/null
+++ b/src/app/features/details/components/information/statement-details-information.component.ts
@@ -0,0 +1,72 @@
+/********************************************************************************
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {select, Store} from "@ngrx/store";
+import {Observable, Subject} from "rxjs";
+import {takeUntil} from "rxjs/operators";
+import {IAPIContactPersonDetails} from "../../../../core/api/contacts/IAPIContactPersonDetails";
+import {IAPIStatementModel} from "../../../../core/api/statements";
+import {IAPISectorsModel} from "../../../../core/api/statements/IAPISectorsModel";
+import {statementTypesSelector} from "../../../../store/settings/selectors";
+import {getStatementSectorsSelector} from "../../../../store/statements/selectors";
+import {momentFormatDisplayNumeric} from "../../../../util/moment";
+
+/**
+ * This component displays the general information saved to a statement.
+ */
+
+@Component({
+    selector: "app-statement-details-information",
+    templateUrl: "./statement-details-information.component.html",
+    styleUrls: ["./statement-details-information.component.scss"]
+})
+export class StatementDetailsInformationComponent implements OnInit, OnDestroy {
+
+    @Input()
+    public appCollapsed = false;
+
+    @Input()
+    public appStatementInfo: IAPIStatementModel;
+
+    @Input()
+    public appContactInfo: IAPIContactPersonDetails;
+
+    public statementTypeOptions$ = this.store.pipe(select(statementTypesSelector));
+
+    public statementType: string;
+
+    public sectors$: Observable<IAPISectorsModel> = this.store.pipe(select(getStatementSectorsSelector));
+
+    public timeFormat = momentFormatDisplayNumeric;
+
+    private destroy$ = new Subject();
+
+    public constructor(public store: Store) {
+
+    }
+
+    public ngOnInit() {
+        this.statementTypeOptions$.pipe(
+            takeUntil(this.destroy$)
+        ).subscribe((typeOptions) => {
+            this.statementType = typeOptions.find((_) => _?.value === this.appStatementInfo?.typeId)?.label;
+        });
+    }
+
+    public ngOnDestroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/linked-statements/index.ts
similarity index 89%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/linked-statements/index.ts
index 5eb9c7f..7657824 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/linked-statements/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./statement-details-linked-statements.component";
diff --git a/src/app/shared/linked-statements/linked-statements/index.ts b/src/app/features/details/components/linked-statements/linked-statements/index.ts
similarity index 100%
rename from src/app/shared/linked-statements/linked-statements/index.ts
rename to src/app/features/details/components/linked-statements/linked-statements/index.ts
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.html b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.html
similarity index 86%
rename from src/app/shared/linked-statements/linked-statements/linked-statements.component.html
rename to src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.html
index 680e9c6..fdbc353 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.html
+++ b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.html
@@ -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">
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.scss
similarity index 90%
rename from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
rename to src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.scss
index 4d2360d..82a69c6 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.scss
@@ -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;
 }
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.spec.ts b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.spec.ts
similarity index 88%
rename from src/app/shared/linked-statements/linked-statements/linked-statements.component.spec.ts
rename to src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.spec.ts
index 9c7ed3b..4b27146 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.spec.ts
+++ b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.spec.ts
@@ -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 @@
         TestBed.configureTestingModule({
             imports: [
                 RouterTestingModule,
-                I18nModule,
-                LinkedStatementsModule
+                I18nModule
             ]
         }).compileComponents();
     }));
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.stories.ts b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.stories.ts
similarity index 75%
rename from src/app/shared/linked-statements/linked-statements/linked-statements.component.stories.ts
rename to src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.stories.ts
index f86ce60..d2bfda1 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.stories.ts
+++ b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.stories.ts
@@ -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 @@
         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>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.ts b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.ts
similarity index 72%
rename from src/app/shared/linked-statements/linked-statements/linked-statements.component.ts
rename to src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.ts
index e46b191..00f8705 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.ts
+++ b/src/app/features/details/components/linked-statements/linked-statements/linked-statements.component.ts
@@ -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 @@
 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>[];
diff --git a/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.html b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.html
new file mode 100644
index 0000000..0489be5
--- /dev/null
+++ b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.html
@@ -0,0 +1,32 @@
+<!-------------------------------------------------------------------------------
+ * 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>
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.scss
similarity index 80%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/details/components/linked-statements/statement-details-linked-statements.component.scss
index 5eb9c7f..8e1723d 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.scss
@@ -11,4 +11,16 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+:host {
+  display: block;
+  width: 100%;
+
+  &:empty {
+    display: none;
+  }
+}
+
+.placeholder {
+  padding: 1em;
+  font-style: italic;
+}
diff --git a/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.spec.ts b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.spec.ts
new file mode 100644
index 0000000..49ad5b8
--- /dev/null
+++ b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.spec.ts
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * 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();
+    });
+});
diff --git a/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.ts b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.ts
new file mode 100644
index 0000000..ef15d54
--- /dev/null
+++ b/src/app/features/details/components/linked-statements/statement-details-linked-statements.component.ts
@@ -0,0 +1,44 @@
+/********************************************************************************
+ * 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) {
+    }
+
+}
diff --git a/src/app/features/details/components/outbox/statement-details-outbox.component.html b/src/app/features/details/components/outbox/statement-details-outbox.component.html
new file mode 100644
index 0000000..8b163f0
--- /dev/null
+++ b/src/app/features/details/components/outbox/statement-details-outbox.component.html
@@ -0,0 +1,48 @@
+<!-------------------------------------------------------------------------------
+ * 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>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/details/components/outbox/statement-details-outbox.component.scss
similarity index 63%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/details/components/outbox/statement-details-outbox.component.scss
index 4d2360d..aa3464f 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/details/components/outbox/statement-details-outbox.component.scss
@@ -11,17 +11,34 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
 :host {
+  display: block;
   width: 100%;
+
+  &:empty {
+    display: none;
+  }
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
+.placeholder {
+  padding: 1em;
+  font-style: italic;
 }
 
-.statements--titlebar {
-  margin-bottom: 0.5em;
+
+.outbox-attachments {
+  padding: 1em;
+  display: flex;
+  flex-direction: row;
+}
+
+.outbox-attachments--statement {
+  display: inline-block;
+  flex: 1;
+}
+
+.outbox-attachments--attachments {
+  display: inline-block;
 }
diff --git a/src/app/features/details/components/outbox/statement-details-outbox.component.spec.ts b/src/app/features/details/components/outbox/statement-details-outbox.component.spec.ts
new file mode 100644
index 0000000..346d190
--- /dev/null
+++ b/src/app/features/details/components/outbox/statement-details-outbox.component.spec.ts
@@ -0,0 +1,64 @@
+/********************************************************************************
+ * 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}));
+    });
+});
diff --git a/src/app/features/details/components/outbox/statement-details-outbox.component.ts b/src/app/features/details/components/outbox/statement-details-outbox.component.ts
new file mode 100644
index 0000000..a2e3b12
--- /dev/null
+++ b/src/app/features/details/components/outbox/statement-details-outbox.component.ts
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * 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}));
+    }
+
+}
diff --git a/src/app/features/details/components/side-menu/statement-details-side-menu.component.ts b/src/app/features/details/components/side-menu/statement-details-side-menu.component.ts
index d5fcb0e..9988172 100644
--- a/src/app/features/details/components/side-menu/statement-details-side-menu.component.ts
+++ b/src/app/features/details/components/side-menu/statement-details-side-menu.component.ts
@@ -89,7 +89,7 @@
                     cssClass: "openk-danger"
                 },
                 {
-                    emit: this.emitClaimTaskFatory(),
+                    emit: this.emitClaimTaskFactory(),
                     label: "details.sideMenu.editInfoData",
                     icon: "subject",
                     cssClass: "openk-success"
@@ -106,7 +106,7 @@
                     cssClass: "openk-info"
                 },
                 {
-                    emit: this.emitClaimTaskFatory(),
+                    emit: this.emitClaimTaskFactory(),
                     label: "details.sideMenu.createNegativeStatement",
                     icon: "edit",
                     cssClass: "openk-info"
@@ -114,7 +114,7 @@
             ],
             [EAPIProcessTaskDefinitionKey.ADD_WORK_FLOW_DATA]: [
                 {
-                    emit: this.emitClaimTaskFatory(),
+                    emit: this.emitClaimTaskFactory(),
                     label: "details.sideMenu.editWorkflowData",
                     icon: "subject",
                     cssClass: "openk-info"
@@ -122,7 +122,7 @@
             ],
             [EAPIProcessTaskDefinitionKey.CREATE_DRAFT]: [
                 {
-                    emit: this.emitClaimTaskFatory(),
+                    emit: this.emitClaimTaskFactory(),
                     label: "details.sideMenu.createDraft",
                     icon: "edit",
                     cssClass: "openk-info"
@@ -138,7 +138,7 @@
             ],
             [EAPIProcessTaskDefinitionKey.CHECK_AND_FORMULATE_RESPONSE]: [
                 {
-                    emit: this.emitClaimTaskFatory(),
+                    emit: this.emitClaimTaskFactory(),
                     label: "details.sideMenu.completeDraft",
                     icon: "description",
                     cssClass: "openk-info"
@@ -165,7 +165,7 @@
         [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 @@
         }));
     }
 
-    private emitClaimTaskFatory() {
+    private emitClaimTaskFactory() {
         return (task: IAPIProcessTask) => this.appDispatch.emit(claimTaskAction({
             statementId: task?.statementId,
             taskId: task?.taskId
diff --git a/src/app/features/details/components/statement-details/statement-details.component.html b/src/app/features/details/components/statement-details/statement-details.component.html
index 0a0b6d9..00a2a34 100644
--- a/src/app/features/details/components/statement-details/statement-details.component.html
+++ b/src/app/features/details/components/statement-details/statement-details.component.html
@@ -20,7 +20,7 @@
 </div>
 
 <app-statement-details-side-menu
-  (appDispatch)="store.dispatch($event)"
+  (appDispatch)="clearErrors(); store.dispatch($event)"
   [appUserName]="userName$ | async"
   [appLoading]="isStatementLoading$ | async"
   [appTasks]="tasks$ | async"
@@ -29,42 +29,41 @@
 </app-statement-details-side-menu>
 
 <ng-container *ngIf="(statement$ | async) != null">
-  <app-collapsible
-    [appCollapsed]="true"
-    [appTitle]="'Allgemeine Informationen'"
-    class="statement-details">
 
-    <div class="statement-details-content">
-      <div *ngFor="let obj of (statement$ | async) | objToArray">
-        <div *ngFor="let detail of obj.value | objToArray">
-          {{detail?.key}}: {{detail?.value | json}}
-        </div>
-      </div>
-    </div>
-  </app-collapsible>
-
-  <app-collapsible
-    [appCollapsed]="true"
-    [appTitle]="'Eingangsdokumente'"
+  <app-statement-details-information
+    [appContactInfo]="(statement$ | async)?.contactInfo"
+    [appStatementInfo]="(statement$ | async)?.info"
     class="statement-details">
-    <div class="placeholder">Not yet implemented.</div>
-  </app-collapsible>
+  </app-statement-details-information>
 
-  <app-collapsible
-    [appCollapsed]="true"
-    [appTitle]="'Betroffene Fachbereiche'"
+  <app-statement-details-geographic-position
     class="statement-details">
-    <div class="placeholder">Not yet implemented.</div>
-  </app-collapsible>
+  </app-statement-details-geographic-position>
+
+  <app-statement-details-attachments
+    class="statement-details">
+  </app-statement-details-attachments>
+
+  <app-statement-details-contributions
+    class="statement-details">
+  </app-statement-details-contributions>
+
+  <app-statement-details-outbox
+    class="statement-details">
+  </app-statement-details-outbox>
+
+  <app-statement-details-considerations
+    [appFinished]="(statement$ | async)?.info?.finished"
+    class="statement-details">
+  </app-statement-details-considerations>
 
   <app-comments-form
     class="statement-details"
     [appCollapsed]="true">
-
   </app-comments-form>
 
   <app-collapsible
-    [appCollapsed]="true"
+    [appCollapsed]="false"
     [appTitle]="'Prozessinformationen'"
     class="statement-details">
     <app-process-information
@@ -78,11 +77,8 @@
     </app-process-information>
   </app-collapsible>
 
-  <app-collapsible
-    [appCollapsed]="true"
-    [appTitle]="'Verknüpfte Vorgänge'"
+  <app-statement-details-linked-statements
     class="statement-details">
-    <div class="placeholder"> Not yet implemented.</div>
-  </app-collapsible>
+  </app-statement-details-linked-statements>
 
 </ng-container>
diff --git a/src/app/features/details/components/statement-details/statement-details.component.spec.ts b/src/app/features/details/components/statement-details/statement-details.component.spec.ts
index 3232592..8aed7a5 100644
--- a/src/app/features/details/components/statement-details/statement-details.component.spec.ts
+++ b/src/app/features/details/components/statement-details/statement-details.component.spec.ts
@@ -17,13 +17,7 @@
 import {MockStore, provideMockStore} from "@ngrx/store/testing";
 import {I18nModule} from "../../../../core/i18n";
 import {CardModule} from "../../../../shared/layout/card";
-import {
-    addCommentAction,
-    claimTaskAction,
-    deleteCommentAction,
-    fetchStatementDetailsAction,
-    queryParamsIdSelector
-} from "../../../../store";
+import {addCommentAction, deleteCommentAction, fetchStatementDetailsAction, queryParamsIdSelector} from "../../../../store";
 import {StatementDetailsComponent} from "./statement-details.component";
 
 describe("StatementDetailsComponent", () => {
@@ -56,16 +50,6 @@
         component.ngOnDestroy();
     });
 
-    it("should dispatch edit action", () => {
-        const dispatchSpy = spyOn(mockStore, "dispatch");
-        component.editTask({statementId: 1, taskId: "9"} as any, {negative: true});
-        expect(dispatchSpy).toHaveBeenCalledWith(claimTaskAction({
-            statementId: 1,
-            taskId: "9",
-            options: {negative: true}
-        }));
-    });
-
     it("should dispatch add comment action", async () => {
         const dispatchSpy = spyOn(mockStore, "dispatch");
 
diff --git a/src/app/features/details/components/statement-details/statement-details.component.ts b/src/app/features/details/components/statement-details/statement-details.component.ts
index 322432a..b43fe9c 100644
--- a/src/app/features/details/components/statement-details/statement-details.component.ts
+++ b/src/app/features/details/components/statement-details/statement-details.component.ts
@@ -13,19 +13,19 @@
 
 import {Component, OnDestroy, OnInit} from "@angular/core";
 import {select, Store} from "@ngrx/store";
-import {Observable, Subscription} from "rxjs";
-import {filter, take} from "rxjs/operators";
-import {IAPIProcessTask} from "../../../../core/api/process";
+import {combineLatest, Observable, Subject} from "rxjs";
+import {filter, take, takeUntil, withLatestFrom} from "rxjs/operators";
 import {
     addCommentAction,
-    claimTaskAction,
     currentActivityIds,
     deleteCommentAction,
     fetchStatementDetailsAction,
     getStatementErrorSelector,
     historySelector,
+    IStatementEntity,
     IStatementErrorEntity,
     processDiagramSelector,
+    processLoadingSelector,
     processNameSelector,
     processVersionSelector,
     queryParamsIdSelector,
@@ -47,7 +47,7 @@
 
     public statementId$ = this.store.pipe(select(queryParamsIdSelector));
 
-    public statement$ = this.store.pipe(select(statementSelector));
+    public statement$: Observable<IStatementEntity> = this.store.pipe(select(statementSelector));
 
     public title$ = this.store.pipe(select(statementTitleSelector));
 
@@ -71,34 +71,37 @@
 
     public appError$: Observable<IStatementErrorEntity> = this.store.pipe(select(getStatementErrorSelector));
 
-    private subscription: Subscription;
+    public tasksLoading$ = this.store.pipe(select(processLoadingSelector));
+
+    private destroy$ = new Subject();
 
     public constructor(public readonly store: Store) {
 
     }
 
     public ngOnInit(): void {
-        this.subscription = this.statementId$
-            .pipe(filter((statementId) => statementId != null))
+        this.statementId$
+            .pipe(
+                filter((statementId) => statementId != null),
+                takeUntil(this.destroy$)
+            )
             .subscribe((statementId) => this.store.dispatch(fetchStatementDetailsAction({statementId})));
+
+        this.tasksLoading$.pipe(
+            filter((tasks) => tasks === false),
+            withLatestFrom(this.statementId$),
+            takeUntil(this.destroy$)
+        ).subscribe(([loading, statementId]) => {
+            this.store.dispatch(fetchStatementDetailsAction({statementId}));
+        });
     }
 
     public async ngOnDestroy() {
-        if (this.subscription != null) {
-            this.subscription.unsubscribe();
-            this.subscription = null;
-        }
+        this.destroy$.next();
+        this.destroy$.complete();
         await this.clearErrors();
     }
 
-    public editTask(task: IAPIProcessTask, options?: any) {
-        this.store.dispatch(claimTaskAction({
-            statementId: task?.statementId,
-            taskId: task?.taskId,
-            options
-        }));
-    }
-
     public async addComment(text: string) {
         const statementId = await this.statementId$.pipe(take(1)).toPromise();
         this.store.dispatch(addCommentAction({statementId, text}));
@@ -109,12 +112,11 @@
         this.store.dispatch(deleteCommentAction({statementId, commentId}));
     }
 
-    private async clearErrors() {
-        const statementId = await this.statementId$.pipe(take(1)).toPromise();
-        const loading = await this.isStatementLoading$.pipe(take(1)).toPromise();
-        if (statementId != null && !loading) {
-            this.store.dispatch(setErrorAction({statementId, error: null}));
-        }
+    public clearErrors() {
+        combineLatest([this.statementId$, this.isStatementLoading$]).pipe(
+            take(1),
+            filter(([statementId, loading]) => statementId != null && !loading)
+        ).subscribe(([statementId]) => this.store.dispatch(setErrorAction({statementId, error: null})));
     }
 
 }
diff --git a/src/app/features/details/statement-details.module.ts b/src/app/features/details/statement-details.module.ts
index 13a1b6f..f370e1b 100644
--- a/src/app/features/details/statement-details.module.ts
+++ b/src/app/features/details/statement-details.module.ts
@@ -19,19 +19,32 @@
 import {RouterModule} from "@angular/router";
 import {TranslateModule} from "@ngx-translate/core";
 import {DateControlModule} from "../../shared/controls/date-control";
+import {SelectModule} from "../../shared/controls/select";
 import {ActionButtonModule} from "../../shared/layout/action-button";
 import {CardModule} from "../../shared/layout/card";
 import {CollapsibleModule} from "../../shared/layout/collapsible";
 import {SideMenuModule} from "../../shared/layout/side-menu";
+import {StatementTableModule} from "../../shared/layout/statement-table";
+import {LeafletModule} from "../../shared/leaflet";
 import {SharedPipesModule} from "../../shared/pipes";
+import {AttachmentsFormModule} from "../forms/attachments";
 import {CommentsFormModule} from "../forms/comments";
+import {StatementInformationFormModule} from "../forms/statement-information";
 import {
     ProcessDiagramComponent,
     ProcessHistoryComponent,
     ProcessInformationComponent,
+    StatementDetailsAttachmentsComponent,
     StatementDetailsComponent,
+    StatementDetailsContributionsComponent,
+    StatementDetailsGeographicPositionComponent,
+    StatementDetailsInformationComponent,
+    StatementDetailsLinkedStatementsComponent,
     StatementDetailsSideMenuComponent
 } from "./components";
+import {StatementDetailsConsiderationsComponent} from "./components/considerations";
+import {LinkedStatementsComponent} from "./components/linked-statements/linked-statements";
+import {StatementDetailsOutboxComponent} from "./components/outbox/statement-details-outbox.component";
 import {BpmnDirective} from "./directives";
 import {GetProcessHistoryEntriesPipe} from "./pipes";
 
@@ -50,7 +63,12 @@
         CollapsibleModule,
         CommentsFormModule,
         SideMenuModule,
-        ActionButtonModule
+        ActionButtonModule,
+        LeafletModule,
+        AttachmentsFormModule,
+        StatementInformationFormModule,
+        SelectModule,
+        StatementTableModule
     ],
     declarations: [
         StatementDetailsComponent,
@@ -59,7 +77,15 @@
         ProcessInformationComponent,
         BpmnDirective,
         StatementDetailsSideMenuComponent,
-        GetProcessHistoryEntriesPipe
+        GetProcessHistoryEntriesPipe,
+        StatementDetailsAttachmentsComponent,
+        StatementDetailsContributionsComponent,
+        StatementDetailsGeographicPositionComponent,
+        StatementDetailsInformationComponent,
+        StatementDetailsLinkedStatementsComponent,
+        StatementDetailsOutboxComponent,
+        LinkedStatementsComponent,
+        StatementDetailsConsiderationsComponent
     ],
     exports: [
         StatementDetailsComponent,
@@ -68,7 +94,15 @@
         ProcessInformationComponent,
         BpmnDirective,
         StatementDetailsSideMenuComponent,
-        GetProcessHistoryEntriesPipe
+        GetProcessHistoryEntriesPipe,
+        StatementDetailsAttachmentsComponent,
+        StatementDetailsContributionsComponent,
+        StatementDetailsGeographicPositionComponent,
+        StatementDetailsInformationComponent,
+        StatementDetailsLinkedStatementsComponent,
+        StatementDetailsOutboxComponent,
+        LinkedStatementsComponent,
+        StatementDetailsConsiderationsComponent
     ]
 })
 export class StatementDetailsModule {
diff --git a/src/app/features/forms/attachments/attachments-form.module.ts b/src/app/features/forms/attachments/attachments-form.module.ts
index 3d0cd18..fdab4e6 100644
--- a/src/app/features/forms/attachments/attachments-form.module.ts
+++ b/src/app/features/forms/attachments/attachments-form.module.ts
@@ -21,7 +21,11 @@
 import {FileDropModule} from "../../../shared/layout/file-drop";
 import {SharedPipesModule} from "../../../shared/pipes";
 import {AttachmentControlComponent, AttachmentListFormComponent, AttachmentsFormGroupComponent} from "./components";
+import {AttachmentDisplayListComponent} from "./components/attachment-display";
 import {AttachmentFileDropFormComponent} from "./components/attachment-file-drop-form";
+import {GetEmailTextAttachmentPipe} from "./pipes/get-email-text-attachment.pipe";
+import {GetMailAttachmentsPipe} from "./pipes/get-mail-attachments.pipe";
+
 
 @NgModule({
     imports: [
@@ -39,13 +43,19 @@
         AttachmentsFormGroupComponent,
         AttachmentControlComponent,
         AttachmentFileDropFormComponent,
-        AttachmentListFormComponent
+        AttachmentListFormComponent,
+        GetEmailTextAttachmentPipe,
+        AttachmentDisplayListComponent,
+        GetMailAttachmentsPipe
     ],
     exports: [
         AttachmentsFormGroupComponent,
         AttachmentControlComponent,
         AttachmentFileDropFormComponent,
-        AttachmentListFormComponent
+        AttachmentListFormComponent,
+        AttachmentDisplayListComponent,
+        GetEmailTextAttachmentPipe,
+        GetMailAttachmentsPipe
     ]
 })
 export class AttachmentsFormModule {
diff --git a/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.html b/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.html
index dae9ae5..74a3bb7 100644
--- a/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.html
+++ b/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.html
@@ -57,14 +57,14 @@
   <button (click)="toggleTag(tag?.id, appValue?.tagIds?.indexOf(tag?.id) > - 1)"
           *ngIf="!appHideNotUsedTags || appValue?.tagIds?.length > 0 && appValue.tagIds.indexOf(tag?.id) > -1"
           [class.openk-info]="appValue?.tagIds?.length > 0 && appValue.tagIds.indexOf(tag?.id) > -1"
-          [disabled]="appDisabled"
+          [disabled]="appDisabled || !appEditableTags"
           class="openk-button openk-chip">
     {{tag?.label}}
   </button>
 </ng-container>
 
 <button (click)="appHideNotUsedTags = !appHideNotUsedTags"
-        *ngIf="appTagList?.length > 0"
+        *ngIf="appTagList?.length > 0 && appEditableTags"
         [class.tag-toggle---plus]="appHideNotUsedTags"
         [disabled]="appDisabled"
         class="openk-button openk-button-rounded tag-toggle"
diff --git a/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.ts b/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.ts
index dbd4e7b..926da4f 100644
--- a/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.ts
+++ b/src/app/features/forms/attachments/components/attachment-control/attachment-control.component.ts
@@ -58,6 +58,9 @@
     @Input()
     public appHideNotUsedTags: boolean;
 
+    @Input()
+    public appEditableTags = true;
+
     public toggleSelection(isSelected: boolean) {
         if (this.appDisabled) {
             return;
diff --git a/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.html b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.html
new file mode 100644
index 0000000..aa911c3
--- /dev/null
+++ b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.html
@@ -0,0 +1,31 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<span class="title">
+  {{appTitle}}
+</span>
+<div class="attachment-list">
+  <app-attachment-control
+    (appDownloadAttachment)="appDownload.emit(att?.id)"
+    *ngFor="let att of appAttachments"
+    [appEditableTags]="false"
+    [appHideNotUsedTags]="true"
+    [appIsDownloadable]="true"
+    [appIsSelectable]="false"
+    [appTagList]="appTagList"
+    [appValue]="att"
+    class="attachment-list--control">
+  </app-attachment-control>
+  <span *ngIf="appAttachments?.length <= 0"
+        class="attachment-list--placeholder">{{"details.attachments.noResult" | translate}}</span>
+</div>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.scss
similarity index 71%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.scss
index 4d2360d..bc6c2e4 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.scss
@@ -11,17 +11,21 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
-:host {
-  width: 100%;
+.title {
+  font-weight: 600;
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
+.attachment-list {
+  margin-top: 0.25em;
 }
 
-.statements--titlebar {
-  margin-bottom: 0.5em;
+.attachment-list--placeholder {
+  font-size: smaller;
+}
+
+.attachment-list--control {
+  box-sizing: border-box;
+  width: fit-content;
 }
diff --git a/src/app/features/search/components/search/search.component.spec.ts b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.spec.ts
similarity index 62%
copy from src/app/features/search/components/search/search.component.spec.ts
copy to src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.spec.ts
index ec7b1b3..7db6bac 100644
--- a/src/app/features/search/components/search/search.component.spec.ts
+++ b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.spec.ts
@@ -12,20 +12,25 @@
  ********************************************************************************/
 
 import {async, ComponentFixture, TestBed} from "@angular/core/testing";
-import {SearchComponent} from "./search.component";
+import {I18nModule} from "../../../../../core/i18n";
+import {AttachmentsFormModule} from "../../attachments-form.module";
+import {AttachmentDisplayListComponent} from "./attachment-display-list.component";
 
-describe("SearchComponent", () => {
-    let component: SearchComponent;
-    let fixture: ComponentFixture<SearchComponent>;
+describe("AttachmentDisplayListComponent", () => {
+    let component: AttachmentDisplayListComponent;
+    let fixture: ComponentFixture<AttachmentDisplayListComponent>;
 
     beforeEach(async(() => {
         TestBed.configureTestingModule({
-            declarations: [SearchComponent]
+            imports: [
+                I18nModule,
+                AttachmentsFormModule
+            ]
         }).compileComponents();
     }));
 
     beforeEach(() => {
-        fixture = TestBed.createComponent(SearchComponent);
+        fixture = TestBed.createComponent(AttachmentDisplayListComponent);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
@@ -33,4 +38,5 @@
     it("should create", () => {
         expect(component).toBeTruthy();
     });
+
 });
diff --git a/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.stories.ts b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.stories.ts
new file mode 100644
index 0000000..5c0eeff
--- /dev/null
+++ b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.stories.ts
@@ -0,0 +1,33 @@
+/********************************************************************************
+ * 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 {withKnobs} from "@storybook/addon-knobs";
+import {moduleMetadata, storiesOf} from "@storybook/angular";
+import {I18nModule} from "../../../../../core/i18n";
+import {AttachmentsFormModule} from "../../attachments-form.module";
+
+storiesOf("Features / Forms / Attachments", module)
+    .addDecorator(withKnobs)
+    .addDecorator(moduleMetadata({
+        imports: [
+            I18nModule,
+            AttachmentsFormModule
+        ]
+    }))
+    .add("AttachmentDisplayListComponent", () => ({
+        template: `
+            <app-attachment-display-list style="margin: 1em; box-sizing: border-box">
+            </app-attachment-display-list>
+        `,
+        props: {}
+    }));
diff --git a/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.ts b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.ts
new file mode 100644
index 0000000..fe9ca5d
--- /dev/null
+++ b/src/app/features/forms/attachments/components/attachment-display/attachment-display-list.component.ts
@@ -0,0 +1,37 @@
+/********************************************************************************
+ * 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, EventEmitter, Input, Output} from "@angular/core";
+import {IAPIAttachmentTag} from "../../../../../core/api/attachments";
+import {IAttachmentControlValue} from "../../../../../store/attachments/model";
+
+@Component({
+    selector: "app-attachment-display-list",
+    templateUrl: "./attachment-display-list.component.html",
+    styleUrls: ["./attachment-display-list.component.scss"]
+})
+export class AttachmentDisplayListComponent {
+
+    @Input()
+    public appTitle: string;
+
+    @Input()
+    public appAttachments: IAttachmentControlValue[] = [];
+
+    @Input()
+    public appTagList: IAPIAttachmentTag[] = [];
+
+    @Output()
+    public appDownload = new EventEmitter<number>();
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/forms/attachments/components/attachment-display/index.ts
similarity index 91%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/forms/attachments/components/attachment-display/index.ts
index 5eb9c7f..497d713 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/forms/attachments/components/attachment-display/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./attachment-display-list.component";
diff --git a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.html b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.html
index 004e315..7013ed7 100644
--- a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.html
+++ b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.html
@@ -13,7 +13,7 @@
 
 <ng-container [formGroup]="appFormGroup">
 
-  <label>
+  <label class="file-drop--title">
     {{appTitle}}
   </label>
 
@@ -32,17 +32,19 @@
       [appTagList]="appTagList"
       [formControlName]="i"
       class="file-drop--control">
-
     </app-attachment-control>
 
   </app-file-drop>
 
-  <button (click)="fileDropComponent.openDialog()"
-          [disabled]="fileDropComponent.appDisabled"
-          class="openk-button attachments--select-file-button">
-    <mat-icon>attach_file</mat-icon>
-    {{"attachments.selectFile" | translate }}
-  </button>
+  <div class="attachments--select-file-button">
+    <button (click)="fileDropComponent.openDialog()"
+            [disabled]="fileDropComponent.appDisabled"
+            class="openk-button">
+      <mat-icon class="attachments--select-file-button--icon">attach_file</mat-icon>
+      {{"attachments.selectFile" | translate }}
+    </button>
+    <ng-content></ng-content>
+  </div>
 
 </ng-container>
 
diff --git a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.scss b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.scss
index 0383056..ff18d7d 100644
--- a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.scss
+++ b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.scss
@@ -23,6 +23,10 @@
   margin: 0.25em 0 0.5em 0;
 }
 
+.file-drop--title {
+  font-weight: 600;
+}
+
 .file-drop--control {
   font-size: small;
   width: 100%;
@@ -40,3 +44,9 @@
 .attachments--select-file-button {
   margin-left: auto;
 }
+
+.attachments--select-file-button--icon {
+  height: initial;
+  width: initial;
+  font-size: 1em;
+}
diff --git a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.ts b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.ts
index 50aba7b..b400e9c 100644
--- a/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.ts
+++ b/src/app/features/forms/attachments/components/attachment-file-drop-form/attachment-file-drop-form.component.ts
@@ -37,7 +37,7 @@
     public appFormGroup = createAttachmentForm();
 
     @Input()
-    public appFormArrayName: keyof IAttachmentFormValue = "add";
+    public appFormArrayName: keyof IAttachmentFormValue | "considerations" = "add";
 
     public addControlForFiles(files: File[]) {
         arrayJoin(files).forEach((file) => {
diff --git a/src/app/features/forms/attachments/components/attachments-form-group.component.scss b/src/app/features/forms/attachments/components/attachments-form-group.component.scss
index 6713a69..5ba0f61 100644
--- a/src/app/features/forms/attachments/components/attachments-form-group.component.scss
+++ b/src/app/features/forms/attachments/components/attachments-form-group.component.scss
@@ -23,19 +23,19 @@
 .attachments {
   display: flex;
   flex-direction: row;
+  padding: 1em;
 }
 
 .attachments--files {
-  padding: 0.5em;
   box-sizing: border-box;
   overflow: auto;
   flex: 1;
 }
 
 .attachments--email {
-  padding: 0.5em;
   box-sizing: border-box;
   flex: 1;
+  margin-right: 0.5em;
 }
 
 .attachments---half-size {
diff --git a/src/app/features/forms/attachments/components/attachments-form-group.component.ts b/src/app/features/forms/attachments/components/attachments-form-group.component.ts
index 69753f1..5508298 100644
--- a/src/app/features/forms/attachments/components/attachments-form-group.component.ts
+++ b/src/app/features/forms/attachments/components/attachments-form-group.component.ts
@@ -11,10 +11,10 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from "@angular/core";
+import {Component, Input, OnDestroy, OnInit} from "@angular/core";
 import {select, Store} from "@ngrx/store";
-import {BehaviorSubject, combineLatest} from "rxjs";
-import {delay, filter, switchMap, take, takeUntil} from "rxjs/operators";
+import {combineLatest, Observable} from "rxjs";
+import {delay, filter, take, takeUntil} from "rxjs/operators";
 import {AUTO_SELECTED_TAGS, IAPIAttachmentModel} from "../../../../core/api/attachments";
 import {IAPIEmailAttachmentModel, IAPIEmailModel} from "../../../../core/api/mail";
 import {
@@ -25,6 +25,7 @@
     getAttachmentControlValueSelector,
     getFilteredAttachmentTagsSelector,
     getStatementAttachmentCacheSelector,
+    IAttachmentControlValue,
     IAttachmentFormValue,
     queryParamsIdSelector,
     startAttachmentDownloadAction
@@ -33,6 +34,7 @@
 import {getSelectedEmailSelector, getStatementMailSelector} from "../../../../store/mail/selectors";
 import {arrayJoin} from "../../../../util/store";
 import {AbstractReactiveFormComponent} from "../../abstract";
+import {getMailAttachment, getMailAttachments} from "../util/mail-attachments.util";
 
 @Component({
     selector: "app-attachments-form-group",
@@ -41,16 +43,16 @@
 })
 export class AttachmentsFormGroupComponent
     extends AbstractReactiveFormComponent<IAttachmentFormValue>
-    implements OnInit, OnChanges, OnDestroy {
+    implements OnInit, OnDestroy {
 
     @Input()
     public appAutoTagIds: string[];
 
     @Input()
-    public appForbiddenTagIds: string[];
+    public appForbiddenTagIds: string[] = [];
 
     @Input()
-    public appRestrictedTagIds: string[];
+    public appRestrictedTagIds: string[] = [];
 
     @Input()
     public appWithoutTagControl: boolean;
@@ -78,7 +80,7 @@
 
     public statementMail$ = this.store.pipe(select(getStatementMailSelector));
 
-    public attachments$ = this.store.pipe(select(getAttachmentControlValueSelector, {}));
+    public attachments$: Observable<IAttachmentControlValue[]>;
 
     public allAttachments$ = this.store.pipe(select(getAllStatementAttachments));
 
@@ -86,20 +88,15 @@
 
     public tagList$ = this.store.pipe(select(getFilteredAttachmentTagsSelector, {without: AUTO_SELECTED_TAGS}));
 
-    private attachmentProps$ = new BehaviorSubject<{ restrictedTagIds: string[], forbiddenTagIds: string[] }>({
-        restrictedTagIds: [],
-        forbiddenTagIds: []
-    });
-
     public constructor(public store: Store) {
         super();
     }
 
     public ngOnInit() {
-        this.attachments$ = this.attachmentProps$.pipe(
-            switchMap((props) => this.store.pipe(
-                select(getAttachmentControlValueSelector, props)
-            ))
+
+        this.attachments$ = this.store.pipe(
+            select(getAttachmentControlValueSelector,
+                {forbiddenTagIds: this.appForbiddenTagIds, restrictedTagIds: this.appRestrictedTagIds})
         );
 
         this.attachments$.pipe(delay(0), takeUntil(this.destroy$))
@@ -121,16 +118,6 @@
         this.store.dispatch(fetchAttachmentTagsAction());
     }
 
-    public ngOnChanges(changes: SimpleChanges) {
-        const keys: Array<keyof AttachmentsFormGroupComponent> = ["appRestrictedTagIds", "appForbiddenTagIds"];
-        if (keys.some((_) => changes[_] != null)) {
-            this.attachmentProps$.next({
-                restrictedTagIds: this.appRestrictedTagIds,
-                forbiddenTagIds: this.appForbiddenTagIds
-            });
-        }
-    }
-
     public ngOnDestroy() {
         this.statementId$.pipe(take(1))
             .subscribe((statementId) => this.store.dispatch(clearAttachmentCacheAction({statementId})));
@@ -151,28 +138,13 @@
     }
 
     public setMailTextAttachmentValue(attachments: IAPIAttachmentModel[], isNewStatement: boolean) {
-        const mailTextAttachmentId = attachments.find((_) =>
-            _.name === "mailText.txt" && _.tagIds && _.tagIds.length === 2
-            && _.tagIds[0] === "email" && _.tagIds[1] === "email-text")?.id;
+        const mailTextAttachmentId = getMailAttachment(attachments)?.id;
 
         this.appFormGroup.patchValue({mailTextAttachmentId, transferMailText: mailTextAttachmentId != null || isNewStatement});
     }
 
     public setMailAttachmentValues(attachments: IAPIAttachmentModel[], emailAttachments: IAPIEmailAttachmentModel[]) {
-        const mergedAttachmentLists = emailAttachments.map((emailAttachment) => {
-            const emailAttachmentFromAttachmentsArray = attachments.find((attachment) =>
-                attachment.name === emailAttachment.name && attachment.tagIds.find((_) => _ === "email") != null);
-
-            const isSelected = emailAttachmentFromAttachmentsArray != null || this.appForNewStatement;
-
-            const tagIds = emailAttachmentFromAttachmentsArray?.tagIds;
-
-            return {
-                ...(emailAttachmentFromAttachmentsArray ? emailAttachmentFromAttachmentsArray : emailAttachment),
-                isSelected,
-                tagIds: arrayJoin(tagIds)
-            };
-        });
+        const mergedAttachmentLists = getMailAttachments(attachments, emailAttachments, this.appForNewStatement);
         this.setValueForArray(mergedAttachmentLists, "email");
     }
 
diff --git a/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.spec.ts b/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.spec.ts
new file mode 100644
index 0000000..f5c3890
--- /dev/null
+++ b/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.spec.ts
@@ -0,0 +1,50 @@
+/********************************************************************************
+ * 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 {IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {IAPIEmailModel} from "../../../../core/api/mail";
+import {GetEmailTextAttachmentPipe} from "./get-email-text-attachment.pipe";
+
+describe("GetEmailTextAttachmentPipe", () => {
+
+    const pipe = new GetEmailTextAttachmentPipe();
+
+    describe("transform", () => {
+
+        it("should return the mail text attachment with name set to mail subject", () => {
+
+            const mail: IAPIEmailModel = {
+                subject: "subject",
+                from: "from"
+            } as IAPIEmailModel;
+            const attachments: IAPIAttachmentModel[] = [
+                {name: "attachment1", tagIds: []},
+                {name: "attachment2", tagIds: []},
+                {name: "mailText.txt", tagIds: ["email", "email-text"]}
+            ] as IAPIAttachmentModel[];
+
+            const mailTextAttachment = pipe.transform(attachments, mail);
+            expect(mailTextAttachment).toEqual({...attachments[2], name: `"${mail.subject}" (${mail.from})`});
+
+        });
+
+        it("should return null if no mail text attachment was found", () => {
+            let mailTextAttachment = pipe.transform(null, null);
+            expect(mailTextAttachment).toEqual(null);
+
+            mailTextAttachment = pipe.transform([], null);
+            expect(mailTextAttachment).toEqual(null);
+        });
+    });
+});
+
diff --git a/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.ts b/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.ts
new file mode 100644
index 0000000..28beec6
--- /dev/null
+++ b/src/app/features/forms/attachments/pipes/get-email-text-attachment.pipe.ts
@@ -0,0 +1,37 @@
+/********************************************************************************
+ * 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 {Pipe, PipeTransform} from "@angular/core";
+import {IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {IAPIEmailModel} from "../../../../core/api/mail";
+import {getMailAttachment} from "../util/mail-attachments.util";
+
+@Pipe({
+    name: "appGetEmailTextAttachment"
+})
+export class GetEmailTextAttachmentPipe implements PipeTransform {
+
+    public transform(attachments: IAPIAttachmentModel[], mail: IAPIEmailModel): IAPIAttachmentModel {
+        const mailTextAttachment = getMailAttachment(attachments);
+
+        if (!mailTextAttachment) {
+            return null;
+        }
+        const name = mail ? `"${mail.subject}" (${mail.from})` : mailTextAttachment.name;
+        return {
+            ...mailTextAttachment,
+            name
+        };
+    }
+
+}
diff --git a/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.spec.ts b/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.spec.ts
new file mode 100644
index 0000000..e4057fd
--- /dev/null
+++ b/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.spec.ts
@@ -0,0 +1,50 @@
+/********************************************************************************
+ * 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 {IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {IAPIEmailAttachmentModel} from "../../../../core/api/mail";
+import {GetMailAttachmentsPipe} from "./get-mail-attachments.pipe";
+
+describe("GetMailAttachmentsPipe", () => {
+
+    const pipe = new GetMailAttachmentsPipe();
+
+    describe("transform", () => {
+
+        it("should return an empty array if called with empty lists", () => {
+            let result = pipe.transform(null, null);
+            expect(result).toEqual([]);
+            result = pipe.transform([], []);
+            expect(result).toEqual([]);
+        });
+
+        it("should return list of mail attachments with selected being the ones already in statement attachments", () => {
+            const attachments: IAPIAttachmentModel[] = [
+                {name: "attachment1", tagIds: []},
+                {name: "attachment2", tagIds: ["email"]},
+                {name: "mailText.txt", tagIds: ["email", "email-text"]}
+            ] as IAPIAttachmentModel[];
+            const emailAttachments: IAPIEmailAttachmentModel[] = [
+                {name: "attachment2"},
+                {name: "attachment3"}
+            ] as IAPIEmailAttachmentModel[];
+            const result = pipe.transform(attachments, emailAttachments);
+            expect(result).toEqual([
+                {name: "attachment2", tagIds: ["email"], isSelected: true},
+                {name: "attachment3", tagIds: [], isSelected: false}
+            ]);
+        });
+    });
+});
+
diff --git a/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.ts b/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.ts
new file mode 100644
index 0000000..6da6c31
--- /dev/null
+++ b/src/app/features/forms/attachments/pipes/get-mail-attachments.pipe.ts
@@ -0,0 +1,28 @@
+/********************************************************************************
+ * 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 {Pipe, PipeTransform} from "@angular/core";
+import {IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {IAPIEmailAttachmentModel} from "../../../../core/api/mail";
+import {getMailAttachments} from "../util/mail-attachments.util";
+
+@Pipe({
+    name: "appGetMailAttachments"
+})
+export class GetMailAttachmentsPipe implements PipeTransform {
+
+    public transform(attachments: IAPIAttachmentModel[], emailAttachments: IAPIEmailAttachmentModel[], isNewStatement?: boolean) {
+        return getMailAttachments(attachments, emailAttachments, isNewStatement);
+    }
+
+}
diff --git a/src/app/features/forms/attachments/util/mail-attachments.util.ts b/src/app/features/forms/attachments/util/mail-attachments.util.ts
new file mode 100644
index 0000000..9836228
--- /dev/null
+++ b/src/app/features/forms/attachments/util/mail-attachments.util.ts
@@ -0,0 +1,52 @@
+/********************************************************************************
+ * 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 {IAPIAttachmentModel} from "../../../../core/api/attachments";
+import {IAPIEmailAttachmentModel} from "../../../../core/api/mail";
+import {IAttachmentControlValue} from "../../../../store/attachments/model";
+import {arrayJoin} from "../../../../util/store";
+
+/**
+ * Given the list of statement attachments and the list of the statement attachments of an email,
+ * this function returns a list of the attachment objects to the email attachment with tag "email".
+ * isSelected is set if email attachment is already in the list of statement attachments or for a new statement. (default value)
+ */
+export function getMailAttachments(
+    statementAttachments: IAttachmentControlValue[], emailAttachments: IAPIEmailAttachmentModel[], isNewStatement: boolean = false) {
+    return arrayJoin(emailAttachments).map((emailAttachment) => {
+        const emailAttachmentFromAttachmentsArray = arrayJoin(statementAttachments).find((attachment) =>
+            attachment.name === emailAttachment.name && attachment.tagIds.find((_) => _ === "email") != null);
+
+        const isSelected = (emailAttachmentFromAttachmentsArray != null) || isNewStatement;
+
+        const tagIds = emailAttachmentFromAttachmentsArray?.tagIds;
+
+        return {
+            ...(emailAttachmentFromAttachmentsArray ? emailAttachmentFromAttachmentsArray : emailAttachment),
+            isSelected,
+            tagIds: arrayJoin(tagIds)
+        };
+    });
+}
+
+/**
+ * Returns the email text attachment from the list of attachments.
+ */
+export function getMailAttachment(attachments: IAPIAttachmentModel[]): IAPIAttachmentModel {
+    return arrayJoin(attachments).find((_) =>
+        _.name === "mailText.txt" &&
+        _.tagIds.length === 2 &&
+        _.tagIds.find((tagId) => tagId === "email-text") != null &&
+        _.tagIds.find((tagId) => tagId === "email") != null
+    );
+}
diff --git a/src/app/features/forms/comments/components/comments-form/comments-form.component.ts b/src/app/features/forms/comments/components/comments-form/comments-form.component.ts
index a5a380c..af647cd 100644
--- a/src/app/features/forms/comments/components/comments-form/comments-form.component.ts
+++ b/src/app/features/forms/comments/components/comments-form/comments-form.component.ts
@@ -28,7 +28,7 @@
 export class CommentsFormComponent {
 
     @Input()
-    public appCollapsed: boolean;
+    public appCollapsed = false;
 
     @Input()
     public appCommentsToShow = 5;
diff --git a/src/app/features/forms/statement-editor/components/arrangement-form-group/arrangement-form-group.component.html b/src/app/features/forms/statement-editor/components/arrangement-form-group/arrangement-form-group.component.html
index 6e8ffc0..774dc97 100644
--- a/src/app/features/forms/statement-editor/components/arrangement-form-group/arrangement-form-group.component.html
+++ b/src/app/features/forms/statement-editor/components/arrangement-form-group/arrangement-form-group.component.html
@@ -14,7 +14,7 @@
 <mat-drawer-container [formGroup]="appFormGroup"
                       [hasBackdrop]="false"
                       class="editor--arrangement">
-  <mat-drawer-content class="editor--arangement--content">
+  <mat-drawer-content cdkScrollable class="editor--arangement--content">
     <div #cdkDropListRef="cdkDropList"
          (cdkDropListDropped)="drop($event)"
          [cdkDropListConnectedTo]="textBlockSelectComponent.dropList"
diff --git a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.html b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.html
index 754c9a8..fa2ac29 100644
--- a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.html
+++ b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.html
@@ -32,19 +32,36 @@
   [appUserRoles]="userRoles$ | async">
 </app-statement-editor-side-menu>
 
+<app-statement-details-information
+  [appContactInfo]="(statement$ | async)?.contactInfo"
+  [appStatementInfo]="(statement$ | async)?.info"
+  [appCollapsed]="true"
+  class="statement-details">
+</app-statement-details-information>
+
+<app-statement-details-attachments
+  [appCollapsed]="true"
+  class="statement-details">
+</app-statement-details-attachments>
+
 <app-collapsible
-  *ngIf="showContributions$ | async"
   [appTitle]="('statementEditorForm.container.contributionStatus' | translate)
-     + ' (' + (selectedContributionsCount$ | async) + '/' + (requiredContributionOptions$ | async).length + ')'"
+     + ' (' + (selectedContributionsCount$ | async) + '/' + (requiredContributionOptions$ | async)?.length + ')'"
   [formGroup]="appFormGroup">
 
   <app-select-group
+    *ngIf="(showContributions$ | async) && (requiredContributionOptions$ | async)?.length > 0"
     [appGroups]="requiredContributionGroups$ | async"
     [appOptions]="requiredContributionOptions$ | async"
     [formControlName]="'contributions'"
     style="padding: 1em;">
   </app-select-group>
 
+  <div *ngIf="!((showContributions$ | async) && (requiredContributionOptions$ | async)?.length > 0)"
+       class="placeholder">
+    {{"statementEditorForm.contributions.placeholder" | translate}}
+  </div>
+
 </app-collapsible>
 
 <app-collapsible
diff --git a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.scss b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.scss
index a0ee48e..29e28d3 100644
--- a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.scss
+++ b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.scss
@@ -16,12 +16,19 @@
 :host {
   display: flex;
   flex-flow: column;
+  max-width: 70em;
+  margin: 0 auto;
 
   & > * {
     margin-bottom: 1em;
   }
 }
 
+.placeholder {
+  padding: 1em;
+  font-style: italic;
+}
+
 .pdf-overlay {
   position: absolute;
   top: 0;
diff --git a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.ts b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.ts
index 8919b3a..683b3b7 100644
--- a/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.ts
+++ b/src/app/features/forms/statement-editor/components/statement-editor-form/statement-editor-form.component.ts
@@ -14,7 +14,7 @@
 import {Component, OnDestroy, OnInit} from "@angular/core";
 import {FormArray} from "@angular/forms";
 import {select, Store} from "@ngrx/store";
-import {defer, Observable} from "rxjs";
+import {combineLatest, defer, Observable} from "rxjs";
 import {filter, map, skip, switchMap, take, takeUntil} from "rxjs/operators";
 import {
     EAPIProcessTaskDefinitionKey,
@@ -34,6 +34,7 @@
     getStatementStaticTextReplacementsSelector,
     getStatementTextBlockGroupsForCurrentTaskSelector,
     IStatementEditorFormValue,
+    IStatementEntity,
     IStatementErrorEntity,
     queryParamsIdSelector,
     requiredContributionsGroupsSelector,
@@ -41,6 +42,7 @@
     setErrorAction,
     statementFileSelector,
     statementLoadingSelector,
+    statementSelector,
     submitStatementEditorFormAction,
     taskSelector,
     updateStatementEntityAction,
@@ -71,6 +73,8 @@
 
     public statementId$ = this.store.pipe(select(queryParamsIdSelector));
 
+    public statement$: Observable<IStatementEntity> = this.store.pipe(select(statementSelector));
+
     public showContributions$ = defer(() => this.task$).pipe(
         map((task) => task?.taskDefinitionKey),
         map((taskDefinitionKey) => {
@@ -123,13 +127,13 @@
     public async ngOnInit() {
         this.updateForm();
         this.fetchTextArrangement();
-        await this.deleteStatementFile();
+        this.deleteStatementFile();
     }
 
-    public async ngOnDestroy() {
+    public ngOnDestroy() {
         super.ngOnDestroy();
-        await this.deleteStatementFile();
-        await this.clearErrors();
+        this.deleteStatementFile();
+        this.clearErrors();
     }
 
     public setArrangementErrors(errors: IAPITextArrangementErrorModel[]) {
@@ -199,12 +203,13 @@
         }
     }
 
-    private async deleteStatementFile() {
-        const file = await this.file$.pipe(take(1)).toPromise();
-        if (file != null) {
-            const statementId = await this.statementId$.pipe(take(1)).toPromise();
+    private deleteStatementFile() {
+        combineLatest([this.statementId$, this.file$]).pipe(
+            take(1),
+            filter(([statementId, file]) => statementId != null && file != null)
+        ).subscribe(([statementId]) => {
             this.store.dispatch(updateStatementEntityAction({statementId, entity: {file: null}}));
-        }
+        });
     }
 
     private fetchTextArrangement() {
@@ -233,12 +238,16 @@
         ).subscribe((errors) => this.setArrangementErrors(errors));
     }
 
-    private async clearErrors() {
-        const statementId = await this.statementId$.pipe(take(1)).toPromise();
-        const loading = await this.isStatementLoading$.pipe(take(1)).toPromise();
-        if (statementId != null && !loading) {
-            this.store.dispatch(setErrorAction({statementId, error: null}));
-        }
+    private clearErrors() {
+        combineLatest([this.task$, this.isStatementLoading$]).pipe(
+            take(1),
+            filter(([task, loading]) => task?.statementId != null && !loading)
+        ).subscribe(([task]) => {
+            this.store.dispatch(setErrorAction({
+                statementId: task.statementId,
+                error: null
+            }));
+        });
     }
 
 }
diff --git a/src/app/features/forms/statement-editor/statement-editor.module.ts b/src/app/features/forms/statement-editor/statement-editor.module.ts
index 31cd96b..2e14aea 100644
--- a/src/app/features/forms/statement-editor/statement-editor.module.ts
+++ b/src/app/features/forms/statement-editor/statement-editor.module.ts
@@ -27,6 +27,7 @@
 import {SharedPipesModule} from "../../../shared/pipes";
 import {TextBlockModule} from "../../../shared/text-block";
 import {CombineBlockdataTextPipe} from "../../../shared/text-block/pipes/combine-blockdata-text/combine-blockdata-text.pipe";
+import {StatementDetailsModule} from "../../details";
 import {AttachmentsFormModule} from "../attachments";
 import {
     ArrangementFormGroupComponent,
@@ -54,7 +55,8 @@
         ActionButtonModule,
         TranslateModule,
         FilePreviewModule,
-        SelectModule
+        SelectModule,
+        StatementDetailsModule
     ],
     declarations: [
         StatementEditorFormComponent,
diff --git a/src/app/features/forms/statement-information/components/general-information-form-group/general-information-form-group.component.html b/src/app/features/forms/statement-information/components/general-information-form-group/general-information-form-group.component.html
index b1c2361..4930e22 100644
--- a/src/app/features/forms/statement-information/components/general-information-form-group/general-information-form-group.component.html
+++ b/src/app/features/forms/statement-information/components/general-information-form-group/general-information-form-group.component.html
@@ -71,15 +71,15 @@
 
   <div class="form-group-container form-group-container--sectors">
     <ng-container
-      *ngIf="(appSectors | sector: appFormGroup.value) != null">
+      *ngIf="(appSectors | sector: appFormGroup.value?.city : appFormGroup.value.district) != null">
       <span class="form-group-container--sectors--label">
         {{("shared.sectors.available" | translate)}}
       </span>
       <span class="form-group-container--sectors--label---italic">
-        {{(appSectors | sector: appFormGroup.value)}}
+        {{(appSectors | sector: appFormGroup.value?.city : appFormGroup.value.district)}}
       </span>
     </ng-container>
-    <span *ngIf="(appSectors | sector: appFormGroup.value ) == null"
+    <span *ngIf="(appSectors | sector: appFormGroup.value?.city : appFormGroup.value.district ) == null"
           class="form-group-container--sectors--label">
       {{"shared.sectors.none" | translate}}
     </span>
diff --git a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.html b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.html
index a9dc6a3..9892565 100644
--- a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.html
+++ b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.html
@@ -45,7 +45,8 @@
       [appEntries]="contactSearchContent$ | async"
       [appIsLoading]="(contactLoading$ | async)?.searching || (contactLoading$ | async)?.fetching"
       [appMessage]="'contacts.selectContact' | translate"
-      [appPageSize]="(contactSearch$ | async)?.totalPages"
+      [appPageSize]="(contactSearch$ | async)?.size"
+      [appTotalPages]="(contactSearch$ | async)?.totalPages"
       [appPage]="(contactSearch$ | async)?.number"
       [formControlName]="'contactId'"
       [appSearch]="initialSearchText"
diff --git a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.spec.ts b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.spec.ts
index b4429f0..dc19e55 100644
--- a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.spec.ts
+++ b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.spec.ts
@@ -192,7 +192,7 @@
         expect(dispatchSpy).toHaveBeenCalledWith(startContactSearchAction({options}));
 
         options.page = 19;
-        component.changePage(options.page);
+        component.changePage({page: options.page, size: options.size});
         expect(dispatchSpy).toHaveBeenCalledWith(startContactSearchAction({options}));
     });
 
diff --git a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.ts b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.ts
index 34c88c6..cb7e40d 100644
--- a/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.ts
+++ b/src/app/features/forms/statement-information/components/statement-information-form/statement-information-form.component.ts
@@ -115,6 +115,13 @@
 
         this.appError$ = this.store.pipe(select(this.appForNewStatement ? getStatementErrorForNewSelector : getStatementErrorSelector));
 
+        this.statementMailId$.pipe(
+            takeUntil(this.destroy$)
+        ).subscribe(async (mId) => {
+            const statementId = (await this.task$.pipe(take(1)).toPromise())?.statementId;
+            this.store.dispatch(fetchEmailAction({mailId: mId, statementId}));
+        });
+
         let mailId = await this.queryParamsMailId$.pipe(take(1)).toPromise();
         if (!mailId) {
             mailId = await this.statementMailId$.pipe(take(1)).toPromise();
@@ -122,17 +129,18 @@
         this.mailId = mailId;
 
         if (this.appForNewStatement) {
-            await this.clearErrors();
+            this.clearErrors(true);
             await this.setInitialValue();
             this.store.dispatch(fetchSettingsAction());
-        } else {
-            this.appFormGroup.markAllAsTouched();
-        }
-
-        if (this.mailId) {
-            await this.setEmailValues(mailId);
+            if (this.mailId) {
+                await this.setEmailValues(mailId);
+                this.appFormGroup.markAllAsTouched();
+            } else {
+                this.search("");
+            }
         } else {
             this.search("");
+            this.appFormGroup.markAllAsTouched();
         }
 
         this.updateForm();
@@ -141,15 +149,13 @@
         this.value$.pipe(takeUntil(this.destroy$)).subscribe(async () => {
             const errorMessage = await this.appError$.pipe(take(1)).toPromise();
             if (this.appFormGroup.valid && errorMessage === EErrorCode.MISSING_FORM_DATA) {
-                return this.clearErrors();
+                return this.clearErrors(true);
             }
         });
     }
 
-    public async ngOnDestroy() {
-        if (!await this.isStatementLoading$.pipe(take(1)).toPromise()) {
-            await this.clearErrors();
-        }
+    public ngOnDestroy() {
+        this.clearErrors();
     }
 
     public openContactDataBaseModule() {
@@ -158,24 +164,30 @@
 
     public search(searchText?: string) {
         this.searchText = searchText;
-        this.changePage(0);
+        this.changePage({page: 0, size: this.searchSize});
     }
 
-    public changePage(page: number) {
+    public changePage(newPage: { page: number, size: number }) {
+        this.searchSize = newPage?.size ? newPage.size : 10;
         const options: IAPISearchOptions = {
             q: this.searchText == null ? "" : this.searchText,
-            page: page == null ? 0 : page,
+            page: newPage?.page == null ? 0 : newPage.page,
             size: this.searchSize
         };
         this.store.dispatch(startContactSearchAction({options}));
     }
 
-    public async clearErrors() {
-        const task = await this.task$.pipe(take(1)).toPromise();
-        this.store.dispatch(setErrorAction({
-            statementId: this.appForNewStatement ? "new" : task?.statementId,
-            error: null
-        }));
+    public clearErrors(force?: boolean) {
+        combineLatest([this.task$, this.isStatementLoading$]).pipe(
+            take(1),
+            filter(([task]) => this.appForNewStatement || task?.statementId != null),
+            filter(([task, loading]) => force || !loading)
+        ).subscribe(([task]) => {
+            this.store.dispatch(setErrorAction({
+                statementId: this.appForNewStatement ? "new" : task?.statementId,
+                error: null
+            }));
+        });
     }
 
     public async submit(responsible?: boolean) {
@@ -188,7 +200,7 @@
                 error: EErrorCode.MISSING_FORM_DATA
             }));
         } else {
-            await this.clearErrors();
+            this.clearErrors(true);
             return this.store.dispatch(submitStatementInformationFormAction(
                 this.appForNewStatement ? {
                     new: true,
@@ -282,7 +294,7 @@
         ).subscribe(async ([contactId, task]) => {
             const errorMessage = (await this.appError$.pipe(take(1)).toPromise())?.errorMessage;
             if (errorMessage === EErrorCode.FAILED_LOADING_CONTACT) {
-                await this.clearErrors();
+                this.clearErrors(true);
             }
             const statementId = this.appForNewStatement ? "new" : task?.statementId;
             this.store.dispatch(fetchContactDetailsAction({contactId, statementId}));
diff --git a/src/app/features/forms/statement-information/pipes/sector.pipe.spec.ts b/src/app/features/forms/statement-information/pipes/sector.pipe.spec.ts
index e53135a..d6be931 100644
--- a/src/app/features/forms/statement-information/pipes/sector.pipe.spec.ts
+++ b/src/app/features/forms/statement-information/pipes/sector.pipe.spec.ts
@@ -27,19 +27,19 @@
                 ]
             };
 
-            let result = pipe.transform(sectors, {city: "", district: ""});
+            let result = pipe.transform(sectors, "", "");
             expect(result).toEqual(undefined);
             expect(result).toBeFalsy();
 
-            result = pipe.transform(sectors, null);
+            result = pipe.transform(sectors, null, null);
             expect(result).toEqual(undefined);
             expect(result).toBeFalsy();
 
-            result = pipe.transform(sectors, {city: "Stadt", district: "Straße"});
+            result = pipe.transform(sectors, "Stadt", "Straße");
             expect(result).toEqual(undefined);
             expect(result).toBeFalsy();
 
-            result = pipe.transform(sectors, {city: "Ort", district: "Ortsteil"});
+            result = pipe.transform(sectors, "Ort", "Ortsteil");
             expect(result).toEqual(" Strom, Gas, Beleuchtung");
         });
     });
diff --git a/src/app/features/forms/statement-information/pipes/sector.pipe.ts b/src/app/features/forms/statement-information/pipes/sector.pipe.ts
index b0d72f9..4ba7481 100644
--- a/src/app/features/forms/statement-information/pipes/sector.pipe.ts
+++ b/src/app/features/forms/statement-information/pipes/sector.pipe.ts
@@ -13,16 +13,15 @@
 
 import {Pipe, PipeTransform} from "@angular/core";
 import {IAPISectorsModel} from "../../../../core/api/statements/IAPISectorsModel";
-import {IStatementInformationFormValue} from "../../../../store/statements/model";
 
 @Pipe({
     name: "sector"
 })
 export class SectorPipe implements PipeTransform {
-    transform(sectors: IAPISectorsModel, args?: Partial<IStatementInformationFormValue>): any {
+    transform(sectors: IAPISectorsModel, city: string, district: string): any {
 
-        if (sectors && args?.city && args.district) {
-            return sectors[args.city + "#" + args.district]?.map((_) => " " + _).toString();
+        if (sectors && city && district) {
+            return sectors[city + "#" + district]?.map((_) => " " + _).toString();
         } else {
             return undefined;
         }
diff --git a/src/app/features/forms/workflow-data/components/workflow-data-form.component.html b/src/app/features/forms/workflow-data/components/workflow-data-form.component.html
index 657543a..d7c7f3b 100644
--- a/src/app/features/forms/workflow-data/components/workflow-data-form.component.html
+++ b/src/app/features/forms/workflow-data/components/workflow-data-form.component.html
@@ -22,27 +22,23 @@
 
 <ng-container [formGroup]="appFormGroup">
 
-  <app-collapsible
+  <app-statement-details-information
     [appCollapsed]="true"
-    [appTitle]="'workflowDataForm.container.general' | translate">
+    [appContactInfo]="(statement$ | async)?.contactInfo"
+    [appStatementInfo]="(statement$ | async)?.info"
+    class="statement-details">
+  </app-statement-details-information>
 
-    <div style="padding: 1em;"> Not yet implemented.</div>
-
-  </app-collapsible>
-
-  <app-collapsible
+  <app-statement-details-attachments
     [appCollapsed]="true"
-    [appTitle]="'workflowDataForm.container.inboxAttachments' | translate">
-
-    <div style="padding: 1em;"> Not yet implemented.</div>
-
-  </app-collapsible>
+    class="statement-details">
+  </app-statement-details-attachments>
 
   <app-collapsible
     [appTitle]="'workflowDataForm.container.geographicPosition' | translate">
 
     <app-map-select
-      [appActionButtonLabel]="'shared.map.openGIS' | translate"
+      (appOpenGis)="openGis($event)"
       [appCenter]="'leaflet.defaultView' | translate"
       [formControlName]="'geographicPosition'"
       class="geographic-position">
diff --git a/src/app/features/forms/workflow-data/components/workflow-data-form.component.scss b/src/app/features/forms/workflow-data/components/workflow-data-form.component.scss
index 467dba9..d14e2ee 100644
--- a/src/app/features/forms/workflow-data/components/workflow-data-form.component.scss
+++ b/src/app/features/forms/workflow-data/components/workflow-data-form.component.scss
@@ -16,6 +16,8 @@
 :host {
   display: block;
   width: 100%;
+  max-width: 70em;
+  margin: 0 auto;
 
   & > * {
     margin-bottom: 1em;
@@ -31,6 +33,7 @@
 }
 
 .geographic-position {
+  box-sizing: border-box;
   padding: 1em;
   height: 30em;
 }
diff --git a/src/app/features/forms/workflow-data/components/workflow-data-form.component.spec.ts b/src/app/features/forms/workflow-data/components/workflow-data-form.component.spec.ts
index 7964991..cedcdd3 100644
--- a/src/app/features/forms/workflow-data/components/workflow-data-form.component.spec.ts
+++ b/src/app/features/forms/workflow-data/components/workflow-data-form.component.spec.ts
@@ -16,19 +16,29 @@
 import {RouterTestingModule} from "@angular/router/testing";
 import {MockStore, provideMockStore} from "@ngrx/store/testing";
 import {I18nModule, IAPISearchOptions} from "../../../../core";
-import {IWorkflowFormValue, startStatementSearchAction, submitWorkflowDataFormAction, taskSelector} from "../../../../store";
+import {ILeafletBounds} from "../../../../shared/leaflet";
+import {
+    IWorkflowFormValue,
+    openGisAction,
+    startStatementSearchAction,
+    submitWorkflowDataFormAction,
+    taskSelector,
+    userNameSelector
+} from "../../../../store";
 import {WorkflowDataFormModule} from "../workflow-data-form.module";
 import {WorkflowDataFormComponent} from "./workflow-data-form.component";
 
 describe("WorkflowDataFormComponent", () => {
 
+    const user = "userName";
+
     const initialState = {
         statements: {},
         process: {},
         settings: {}
     };
 
-    let mockStore: MockStore;
+    let store: MockStore;
     let component: WorkflowDataFormComponent;
     let fixture: ComponentFixture<WorkflowDataFormComponent>;
 
@@ -40,14 +50,17 @@
                 RouterTestingModule
             ],
             providers: [
-                provideMockStore({initialState})
+                provideMockStore({
+                    initialState,
+                    selectors: [{selector: userNameSelector, value: user}]
+                })
             ]
         }).compileComponents();
     }));
 
     beforeEach(() => {
         fixture = TestBed.createComponent(WorkflowDataFormComponent);
-        mockStore = fixture.componentRef.injector.get(MockStore);
+        store = fixture.componentRef.injector.get(MockStore);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
@@ -57,8 +70,8 @@
     });
 
     it("should dispatch submit workflow form action", async () => {
-        mockStore.overrideSelector(taskSelector, {statementId: 1, taskId: "19"} as any);
-        const dispatchSpy = spyOn(mockStore, "dispatch");
+        store.overrideSelector(taskSelector, {statementId: 1, taskId: "19"} as any);
+        const dispatchSpy = spyOn(store, "dispatch");
         const value: IWorkflowFormValue = {
             geographicPosition: "1919",
             departments: {
@@ -86,10 +99,17 @@
     });
 
     it("should dispatch search statements action", () => {
-        const dispatchSpy = spyOn(mockStore, "dispatch");
+        const dispatchSpy = spyOn(store, "dispatch");
         const options: IAPISearchOptions = {q: ""};
         component.search(options);
         expect(dispatchSpy).toHaveBeenCalledWith(startStatementSearchAction({options}));
     });
 
+    it("should open GIS", () => {
+        spyOn(store, "dispatch");
+        const bounds = {} as ILeafletBounds;
+        component.openGis(bounds);
+        expect(store.dispatch).toHaveBeenCalledWith(openGisAction({bounds, user}));
+    });
+
 });
diff --git a/src/app/features/forms/workflow-data/components/workflow-data-form.component.ts b/src/app/features/forms/workflow-data/components/workflow-data-form.component.ts
index f119b47..e0b4122 100644
--- a/src/app/features/forms/workflow-data/components/workflow-data-form.component.ts
+++ b/src/app/features/forms/workflow-data/components/workflow-data-form.component.ts
@@ -11,26 +11,32 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-import {Component, OnDestroy, OnInit} from "@angular/core";
+import {Component, Inject, OnDestroy, OnInit} from "@angular/core";
 import {select, Store} from "@ngrx/store";
-import {Observable} from "rxjs";
-import {distinctUntilChanged, take, takeUntil} from "rxjs/operators";
-import {IAPISearchOptions} from "../../../../core/api";
+import {combineLatest, Observable, Subscription} from "rxjs";
+import {distinctUntilChanged, filter, take, takeUntil} from "rxjs/operators";
+import {APP_CONFIGURATION, IAPISearchOptions, IAppConfiguration} from "../../../../core";
+import {ILeafletBounds, latLngZoomToString} from "../../../../shared/leaflet";
 import {
     createWorkflowForm,
     departmentGroupsSelector,
     departmentOptionsSelector,
+    fetchStatementDetailsAction,
     getSearchContentStatementsSelector,
     getStatementErrorSelector,
+    IStatementEntity,
     IStatementErrorEntity,
     IWorkflowFormValue,
+    openGisAction,
     queryParamsIdSelector,
     setErrorAction,
     startStatementSearchAction,
     statementLoadingSelector,
+    statementSelector,
     statementTypesSelector,
     submitWorkflowDataFormAction,
     taskSelector,
+    userNameSelector,
     workflowFormValueSelector
 } from "../../../../store";
 import {AbstractReactiveFormComponent} from "../../abstract";
@@ -62,22 +68,37 @@
 
     private form$ = this.store.pipe(select(workflowFormValueSelector));
 
-    public constructor(public store: Store) {
+    public statement$: Observable<IStatementEntity> = this.store.pipe(select(statementSelector));
+
+    public userName$ = this.store.pipe(select(userNameSelector));
+
+    public subscription: Subscription;
+
+    private defaultGeographicPosition = latLngZoomToString(this.configuration.leaflet, this.configuration.leaflet.zoom);
+
+    public constructor(public store: Store, @Inject(APP_CONFIGURATION) public configuration: IAppConfiguration) {
         super();
     }
 
     public async ngOnInit() {
         this.updateForm();
         this.task$.pipe(takeUntil(this.destroy$)).subscribe(() => this.search({q: ""}));
+        this.subscription = this.statementId$
+            .pipe(filter((statementId) => statementId != null))
+            .subscribe((statementId) => this.store.dispatch(fetchStatementDetailsAction({statementId})));
     }
 
-    public async ngOnDestroy() {
+    public ngOnDestroy() {
         super.ngOnDestroy();
+        if (this.subscription != null) {
+            this.subscription.unsubscribe();
+            this.subscription = null;
+        }
         return this.clearErrors();
     }
 
     public async submit(completeTask?: boolean) {
-        await this.clearErrors();
+        this.clearErrors();
         const task = await this.task$.pipe(take(1)).toPromise();
         this.store.dispatch(submitWorkflowDataFormAction({
             statementId: task.statementId,
@@ -91,18 +112,33 @@
         this.store.dispatch(startStatementSearchAction({options}));
     }
 
-    private async clearErrors() {
-        const statementId = await this.statementId$.pipe(take(1)).toPromise();
-        const loading = await this.isStatementLoading$.pipe(take(1)).toPromise();
-        if (statementId != null && !loading) {
-            this.store.dispatch(setErrorAction({statementId, error: null}));
-        }
+    public openGis(bounds: ILeafletBounds) {
+        this.userName$.pipe(take(1)).subscribe((user) => {
+            this.store.dispatch(openGisAction({bounds, user}));
+        });
+    }
+
+    public clearErrors() {
+        combineLatest([this.task$, this.isStatementLoading$]).pipe(
+            take(1),
+            filter(([task, loading]) => task?.statementId != null && !loading)
+        ).subscribe(([task]) => {
+            this.store.dispatch(setErrorAction({
+                statementId: task.statementId,
+                error: null
+            }));
+        });
     }
 
     private updateForm() {
         this.isStatementLoading$.pipe(takeUntil(this.destroy$), distinctUntilChanged())
             .subscribe((loading) => loading ? this.appFormGroup.disable() : this.appFormGroup.enable());
-        this.form$.pipe(takeUntil(this.destroy$)).subscribe((value) => this.patchValue(value));
+        this.form$.pipe(takeUntil(this.destroy$)).subscribe((value) => {
+            this.patchValue({
+                ...value,
+                geographicPosition: value.geographicPosition == null ? this.defaultGeographicPosition : value.geographicPosition,
+            });
+        });
     }
 
 
diff --git a/src/app/features/forms/workflow-data/workflow-data-form.module.ts b/src/app/features/forms/workflow-data/workflow-data-form.module.ts
index d9c9f43..b03fc0e 100644
--- a/src/app/features/forms/workflow-data/workflow-data-form.module.ts
+++ b/src/app/features/forms/workflow-data/workflow-data-form.module.ts
@@ -22,6 +22,7 @@
 import {ActionButtonModule} from "../../../shared/layout/action-button";
 import {CollapsibleModule} from "../../../shared/layout/collapsible";
 import {SideMenuModule} from "../../../shared/layout/side-menu";
+import {StatementDetailsModule} from "../../details";
 import {WorkflowDataFormComponent, WorkflowDataSideMenuComponent} from "./components";
 
 @NgModule({
@@ -36,7 +37,8 @@
         StatementSelectModule,
         SideMenuModule,
         ActionButtonModule,
-        MapSelectModule
+        MapSelectModule,
+        StatementDetailsModule
     ],
     declarations: [
         WorkflowDataFormComponent,
diff --git a/src/app/features/mail/components/mail-details/mail-details.component.scss b/src/app/features/mail/components/mail-details/mail-details.component.scss
index 4485712..7d5e8b8 100644
--- a/src/app/features/mail/components/mail-details/mail-details.component.scss
+++ b/src/app/features/mail/components/mail-details/mail-details.component.scss
@@ -44,7 +44,7 @@
 
 .email--content--attachments--btn {
   border: 0;
-  padding: 0.1em 0 0.1em 0.5em;
+  margin: 0.1em 0 0.1em 0.5em;
 
   &:not(.openk-info) {
     background-color: transparent;
diff --git a/src/app/features/mail/components/mail/mail.component.html b/src/app/features/mail/components/mail/mail.component.html
index 0735fcf..c2ba35c 100644
--- a/src/app/features/mail/components/mail/mail.component.html
+++ b/src/app/features/mail/components/mail/mail.component.html
@@ -14,7 +14,7 @@
 <app-mail-inbox
   (appFetch)="fetchInbox()"
   *appSideMenu="'top'; left: true; style: { padding: '0' }"
-  [appLoading]="(loading$ | async)?.fetchingInbox"
+  [appLoading]="(loading$ | async) != null"
   [appMails]="(emailInbox$ | async)"
   [appSelectedMailId]="(selectedEmailId$ | async)">
 </app-mail-inbox>
@@ -23,6 +23,7 @@
   (appDownloadAttachment)="downloadAttachment($event?.mailId, $event?.name)"
   (appRemoveFromInbox)="remove($event)"
   [appEmail]="selectedEmail$ | async"
-  [appDeleting]="(loading$ | async)?.deleting"
   [appHideControls]="(loading$ | async) != null ||  (emailInbox$ | async)?.indexOf(selectedEmail$ | async) === -1">
 </app-mail-details>
+
+
diff --git a/src/app/features/mail/components/mail/mail.component.ts b/src/app/features/mail/components/mail/mail.component.ts
index edd300e..714793f 100644
--- a/src/app/features/mail/components/mail/mail.component.ts
+++ b/src/app/features/mail/components/mail/mail.component.ts
@@ -14,8 +14,8 @@
 import {Component, OnDestroy, OnInit} from "@angular/core";
 import {Router} from "@angular/router";
 import {select, Store} from "@ngrx/store";
-import {Subject} from "rxjs";
-import {concatMap, filter, map, switchMap, take, takeUntil} from "rxjs/operators";
+import {combineLatest, Subject} from "rxjs";
+import {distinctUntilChanged, filter, map, takeUntil, withLatestFrom} from "rxjs/operators";
 import {
     deleteEmailFromInboxAction,
     downloadEmailAttachmentAction,
@@ -24,7 +24,6 @@
 } from "../../../../store/mail/actions";
 import {getEmailInboxSelector, getEmailLoadingSelector, getSelectedEmailSelector} from "../../../../store/mail/selectors";
 import {queryParamsMailIdSelector} from "../../../../store/root/selectors";
-import {arrayJoin} from "../../../../util/store";
 
 @Component({
     selector: "app-mail",
@@ -37,7 +36,7 @@
 
     public emailInbox$ = this.store.pipe(select(getEmailInboxSelector));
 
-    public selectedEmailId$ = this.store.pipe(select(queryParamsMailIdSelector));
+    public selectedEmailId$ = this.store.pipe(select(queryParamsMailIdSelector)).pipe(distinctUntilChanged());
 
     public selectedEmail$ = this.store.pipe(select(getSelectedEmailSelector));
 
@@ -52,36 +51,22 @@
 
     public ngOnInit() {
         this.fetchInbox();
+
+        // Automatically fetch selected emails which are not part of the inbox
         this.selectedEmailId$.pipe(
-            concatMap((id) => {
-                return this.emailInbox$.pipe(
-                    filter((_) => arrayJoin(_).length <= 0),
-                    take(1),
-                    map((mails) => {
-                        return mails.find((_) => _.identifier === id) == null ? id : null;
-                    })
-                );
-            }),
+            filter((mailId) => mailId != null),
+            withLatestFrom(this.emailInbox$),
+            filter(([mailId, inbox]) => !inbox.some((mail) => mail.identifier === mailId)),
             takeUntil(this.destroy$)
-        ).subscribe((mailId) => this.fetch(mailId));
+        ).subscribe(([mailId]) => this.fetch(mailId));
 
-        this.selectedEmailId$.pipe(
-            takeUntil(this.destroy$),
-            filter((id) => id == null),
-            switchMap(() => {
-                return this.emailInbox$.pipe(
-                    map((mails) => {
-                        return mails[0]?.identifier;
-                    }),
-                    filter((id) => id != null),
-                        take(1)
-                    );
-                },
-            )
-        ).subscribe((id) => {
-            this.router.navigate(["mail"], {queryParams: {mailId: id}});
-        });
-
+        // Automatically navigate to the first inbox item if no email is selected
+        combineLatest([this.selectedEmailId$, this.emailInbox$]).pipe(
+            filter(([mailId]) => mailId == null),
+            map(([_, inbox]) => inbox[0]?.identifier),
+            filter((firstMailId) => firstMailId != null),
+            takeUntil(this.destroy$)
+        ).subscribe((firstMailId) => this.selectMail(firstMailId));
     }
 
     public ngOnDestroy() {
@@ -89,7 +74,7 @@
         this.destroy$.complete();
     }
 
-    public async fetchInbox() {
+    public fetchInbox() {
         this.store.dispatch(fetchEmailInboxAction());
     }
 
@@ -102,7 +87,11 @@
     }
 
     public remove(mailId: string) {
-        this.store.dispatch(deleteEmailFromInboxAction({mailId, navigateTo: "mail"}));
+        this.store.dispatch(deleteEmailFromInboxAction({mailId}));
+    }
+
+    public selectMail(mailId: string) {
+        return this.router.navigate([], {queryParams: {mailId}, replaceUrl: true});
     }
 
 }
diff --git a/src/app/features/navigation/components/nav-header/nav-header.component.ts b/src/app/features/navigation/components/nav-header/nav-header.component.ts
index b6c7282..9a927cd 100644
--- a/src/app/features/navigation/components/nav-header/nav-header.component.ts
+++ b/src/app/features/navigation/components/nav-header/nav-header.component.ts
@@ -57,10 +57,15 @@
         },
         {
             icon: "find_in_page",
-            link: "/search",
+            link: "/search/list",
             tooltip: "core.header.search"
         },
         {
+            icon: "map",
+            link: "/search/map",
+            tooltip: "core.header.searchMap"
+        },
+        {
             icon: "email",
             link: "/mail",
             tooltip: "core.header.mail",
diff --git a/src/app/features/search/components/date-filter/date-filter.component.html b/src/app/features/search/components/date-filter/date-filter.component.html
new file mode 100644
index 0000000..76fb14e
--- /dev/null
+++ b/src/app/features/search/components/date-filter/date-filter.component.html
@@ -0,0 +1,28 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<div class="date-filter">
+  <button
+    (click)="appActive = !appActive; appValueChange.emit(dueDateFromSelect.value)"
+    [class.openk-info]="appActive"
+    class="openk-button openk-chip date-filter--button">
+    {{appTitle}}
+  </button>
+  <div>
+    <app-date-control
+      #dueDateFromSelect
+      (appValueChange)="emitNewValue(dueDateFromSelect.value)"
+      class="openk-info">
+    </app-date-control>
+  </div>
+</div>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/search/components/date-filter/date-filter.component.scss
similarity index 71%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/search/components/date-filter/date-filter.component.scss
index 4d2360d..1230d15 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/search/components/date-filter/date-filter.component.scss
@@ -11,17 +11,17 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
-:host {
-  width: 100%;
+.date-filter {
+  display: flex;
+  align-items: center;
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
-}
-
-.statements--titlebar {
-  margin-bottom: 0.5em;
+.date-filter--button {
+  margin-right: 0.5em;
+  height: 2em;
+  width: 11em;
+  font-size: small;
+  border-color: get-color($openk-info-palette, 500);
 }
diff --git a/src/app/features/search/components/date-filter/date-filter.component.spec.ts b/src/app/features/search/components/date-filter/date-filter.component.spec.ts
new file mode 100644
index 0000000..af52b2a
--- /dev/null
+++ b/src/app/features/search/components/date-filter/date-filter.component.spec.ts
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * 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 {I18nModule} from "../../../../core/i18n";
+import {SearchModule} from "../../search.module";
+import {DateFilterComponent} from "./date-filter.component";
+
+describe("DateFilterComponent", () => {
+    let component: DateFilterComponent;
+    let fixture: ComponentFixture<DateFilterComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                SearchModule,
+                I18nModule
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(DateFilterComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should emit appValueChange only if filter is active", () => {
+        spyOn(component.appValueChange, "emit").and.callThrough();
+        const date = new Date();
+        component.emitNewValue(date);
+        expect(component.appValueChange.emit).not.toHaveBeenCalled();
+        component.appActive = true;
+        component.emitNewValue(date);
+        expect(component.appValueChange.emit).toHaveBeenCalledWith(date);
+    });
+});
diff --git a/src/app/features/search/components/date-filter/date-filter.component.ts b/src/app/features/search/components/date-filter/date-filter.component.ts
new file mode 100644
index 0000000..569c760
--- /dev/null
+++ b/src/app/features/search/components/date-filter/date-filter.component.ts
@@ -0,0 +1,38 @@
+/********************************************************************************
+ * 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, EventEmitter, Input, Output} from "@angular/core";
+
+@Component({
+    selector: "app-date-filter",
+    templateUrl: "./date-filter.component.html",
+    styleUrls: ["./date-filter.component.scss"]
+})
+export class DateFilterComponent {
+
+    @Input()
+    public appActive: boolean;
+
+    @Input()
+    public appTitle: string;
+
+    @Output()
+    public appValueChange = new EventEmitter<Date>();
+
+    public emitNewValue(value: Date) {
+        if (this.appActive) {
+            this.appValueChange.emit(value);
+        }
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/search/components/date-filter/index.ts
similarity index 93%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/search/components/date-filter/index.ts
index 5eb9c7f..8d5201f 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/search/components/date-filter/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./date-filter.component";
diff --git a/src/app/features/search/components/index.ts b/src/app/features/search/components/index.ts
index 990bb42..f868c39 100644
--- a/src/app/features/search/components/index.ts
+++ b/src/app/features/search/components/index.ts
@@ -11,4 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search";
+export * from "./search-filter";
+export * from "./search-statements";
+export * from "./position-search";
+export * from "./date-filter";
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/search/components/position-search/index.ts
similarity index 92%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/search/components/position-search/index.ts
index 5eb9c7f..16b6eaa 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/search/components/position-search/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./position-search.component";
diff --git a/src/app/features/search/components/position-search/position-search.component.html b/src/app/features/search/components/position-search/position-search.component.html
new file mode 100644
index 0000000..a934642
--- /dev/null
+++ b/src/app/features/search/components/position-search/position-search.component.html
@@ -0,0 +1,47 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<div class="search-filters">
+  <app-search-filter
+    (appValueChange)="search($event)"
+    [appFilters]="filtersToShow"
+    [appLoading]="statementLoading$ | async"
+    [appShowSearch]="false"
+    [appStatementTypeOptions]="statementTypeOptions$ | async">
+  </app-search-filter>
+</div>
+
+<app-leaflet-map (appCenterChange)="changeCenter($event)"
+                 (appClick)="selected = null"
+                 (appOpenGis)="openGis($event)"
+                 (appPopupClose)="selected = null"
+                 [appCenter]="coord$ | async"
+                 class="search-map">
+
+  <ng-container *ngFor="let entry of searchContent$ | async; trackBy: trackById">
+    <ng-container *ngIf="entry?.position != null"
+                  (appClick)="selected = entry"
+                  [appLeafletMarker]="entry.position">
+    </ng-container>
+  </ng-container>
+
+  <a *appLeafletPopup="selected?.position; data: selected"
+     [queryParams]="{ id: selected?.id }"
+     [routerLink]="'/details'"
+     class="popup">
+    <ng-container *ngIf="selected != null">
+      ID {{selected.id}}: {{selected.title}}
+    </ng-container>
+  </a>
+
+</app-leaflet-map>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/search/components/position-search/position-search.component.scss
similarity index 68%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/search/components/position-search/position-search.component.scss
index 4d2360d..155644f 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/search/components/position-search/position-search.component.scss
@@ -11,17 +11,28 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
 
 :host {
-  width: 100%;
+  display: flex;
+  flex-flow: column;
+  padding: 1em 1em 0.5em 1em;
+  min-height: 100%;
+  box-sizing: border-box;
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
-}
-
-.statements--titlebar {
+.search-filters {
+  display: flex;
+  flex-flow: row;
   margin-bottom: 0.5em;
 }
+
+.search-map {
+  width: 100%;
+  flex: 1 1 100%;
+}
+
+.popup {
+  line-height: 1;
+  display: inline-block;
+}
diff --git a/src/app/features/search/components/position-search/position-search.component.spec.ts b/src/app/features/search/components/position-search/position-search.component.spec.ts
new file mode 100644
index 0000000..eeec9c8
--- /dev/null
+++ b/src/app/features/search/components/position-search/position-search.component.spec.ts
@@ -0,0 +1,82 @@
+/********************************************************************************
+ * 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 {Router} from "@angular/router";
+import {RouterTestingModule} from "@angular/router/testing";
+import {MockStore, provideMockStore} from "@ngrx/store/testing";
+import {IAPIPositionSearchStatementModel} from "../../../../core";
+import {I18nModule} from "../../../../core/i18n";
+import {ILeafletBounds} from "../../../../shared/leaflet";
+import {openGisAction, startStatementPositionSearchAction, userNameSelector} from "../../../../store";
+import {SearchModule} from "../../search.module";
+import {PositionSearchComponent} from "./position-search.component";
+
+describe("PositionSearchComponent", () => {
+
+    const user = "userName";
+
+    let component: PositionSearchComponent;
+    let store: MockStore;
+    let router: Router;
+    let fixture: ComponentFixture<PositionSearchComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                SearchModule,
+                I18nModule,
+                RouterTestingModule
+            ],
+            providers: [provideMockStore({
+                selectors: [{selector: userNameSelector, value: user}]
+            })]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(PositionSearchComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        spyOn(store, "dispatch").and.callThrough();
+        router = TestBed.inject(Router);
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should start search after init", () => {
+        expect(store.dispatch).toHaveBeenCalledWith(startStatementPositionSearchAction({options: {}}));
+    });
+
+    it("should track by ID", () => {
+        expect(component.trackById(0, {...{} as IAPIPositionSearchStatementModel, id: 19})).toBe(19);
+        expect(component.trackById(0, {} as IAPIPositionSearchStatementModel)).not.toBeDefined();
+        expect(component.trackById(0, null)).not.toBeDefined();
+    });
+
+    it("should change center coordinates in url", () => {
+        spyOn(router, "navigate");
+        component.changeCenter("1,2,3");
+        expect(router.navigate).toHaveBeenCalledWith([], {queryParams: {coord: "1,2,3"}, replaceUrl: true});
+    });
+
+    it("should open GIS", () => {
+        const bounds = {} as ILeafletBounds;
+        component.openGis(bounds);
+        expect(store.dispatch).toHaveBeenCalledWith(openGisAction({bounds, user}));
+    });
+
+});
diff --git a/src/app/features/search/components/position-search/position-search.component.ts b/src/app/features/search/components/position-search/position-search.component.ts
new file mode 100644
index 0000000..9a4d1f1
--- /dev/null
+++ b/src/app/features/search/components/position-search/position-search.component.ts
@@ -0,0 +1,85 @@
+/********************************************************************************
+ * 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, OnInit} from "@angular/core";
+import {Router} from "@angular/router";
+import {select, Store} from "@ngrx/store";
+import {take} from "rxjs/operators";
+import {IAPIPositionSearchOptions, IAPIPositionSearchStatementModel} from "../../../../core";
+import {ILeafletBounds} from "../../../../shared/leaflet";
+import {
+    getStatementPositionSearchSelector,
+    openGisAction,
+    queryParamsCoordSelector,
+    startStatementPositionSearchAction,
+    statementLoadingSelector,
+    statementTypesSelector,
+    userNameSelector
+} from "../../../../store";
+import {IFilterToDisplay} from "../search-filter";
+
+@Component({
+    selector: "app-position-search",
+    templateUrl: "./position-search.component.html",
+    styleUrls: ["./position-search.component.scss"]
+})
+export class PositionSearchComponent implements OnInit {
+
+    public coord$ = this.store.pipe(select(queryParamsCoordSelector), take(1));
+
+    public searchContent$ = this.store.pipe(select(getStatementPositionSearchSelector));
+
+    public statementLoading$ = this.store.pipe(select(statementLoadingSelector));
+
+    public statementTypeOptions$ = this.store.pipe(select(statementTypesSelector));
+
+    public userName$ = this.store.pipe(select(userNameSelector));
+
+
+    public filtersToShow: IFilterToDisplay = {
+        filterForType: false,
+        dueDateFrom: false,
+        dueDateTo: false
+    };
+
+    public selected: IAPIPositionSearchStatementModel;
+
+    public trackById = trackById;
+
+    public constructor(public store: Store, public router: Router) {
+
+    }
+
+    public ngOnInit() {
+        this.search({});
+    }
+
+    public search(options: IAPIPositionSearchOptions) {
+        this.store.dispatch(startStatementPositionSearchAction({options}));
+    }
+
+    public changeCenter(latLngZoom: string) {
+        this.router.navigate([], {queryParams: {coord: latLngZoom}, replaceUrl: true});
+    }
+
+    public openGis(bounds: ILeafletBounds) {
+        this.userName$.pipe(take(1)).subscribe((user) => {
+            this.store.dispatch(openGisAction({bounds, user}));
+        });
+    }
+
+}
+
+function trackById(index, entry: IAPIPositionSearchStatementModel) {
+    return entry?.id;
+}
diff --git a/src/app/features/search/components/search/search.component.ts b/src/app/features/search/components/search-filter/IFilterToDisplay.ts
similarity index 66%
rename from src/app/features/search/components/search/search.component.ts
rename to src/app/features/search/components/search-filter/IFilterToDisplay.ts
index 27f29f1..203b033 100644
--- a/src/app/features/search/components/search/search.component.ts
+++ b/src/app/features/search/components/search-filter/IFilterToDisplay.ts
@@ -11,13 +11,14 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-import {Component} from "@angular/core";
-
-@Component({
-    selector: "app-search",
-    templateUrl: "./search.component.html",
-    styleUrls: ["./search.component.scss"]
-})
-export class SearchComponent {
-
+export interface IFilterToDisplay {
+    filterForType?: boolean;
+    status?: boolean;
+    editedByMe?: boolean;
+    dueDateFrom?: boolean;
+    dueDateTo?: boolean;
+    creationDateFrom?: boolean;
+    creationDateTo?: boolean;
+    receiptDateFrom?: boolean;
+    receiptDateTo?: boolean;
 }
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/search/components/search-filter/index.ts
similarity index 87%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/search/components/search-filter/index.ts
index 5eb9c7f..da57faa 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/search/components/search-filter/index.ts
@@ -11,4 +11,5 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./search-filter.component";
+export * from "./IFilterToDisplay";
diff --git a/src/app/features/search/components/search-filter/search-filter.component.html b/src/app/features/search/components/search-filter/search-filter.component.html
new file mode 100644
index 0000000..37c2735
--- /dev/null
+++ b/src/app/features/search/components/search-filter/search-filter.component.html
@@ -0,0 +1,147 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<div *ngIf="appShowSearch" class="filters--searchbar">
+  <span class="filters--searchbar--text">{{"search.title" | translate}}</span>
+  <app-searchbar
+    (appSearch)="searchByString($event)"
+    [appIsLoading]="appLoading"
+    [appPlaceholder]="'search.executeSearch' | translate"
+    class="filters--searchbar--input">
+  </app-searchbar>
+
+  <ng-content></ng-content>
+</div>
+
+<div class="filters">
+
+  <button (click)="disableAllFilters()"
+          class="openk-button openk-button-rounded"
+          type="button">
+    <mat-icon>filter_list</mat-icon>
+  </button>
+
+  <div class="all-filters">
+    <div *ngIf="appFilters.filterForType != null || appFilters.editedByMe != null || appFilters.status != null"
+         class="filters--row">
+      <div class="filter-group filter-group---stacked">
+        <button
+          (click)="appFilters.filterForType = !appFilters.filterForType; setSearchParams('typeId', typeSelect.appValue, appFilters.filterForType); emitSearch()"
+          [class.openk-info]="appFilters.filterForType"
+          class="openk-button openk-chip filters--btn filters--btn---margin">
+          {{"search.type" | translate}}
+        </button>
+        <div class="filters--type-select-width">
+          <app-select #typeSelect
+                      (appValueChange)="setSearchParams('typeId', typeSelect.appValue, appFilters.filterForType);
+                      appFilters.filterForType ? emitSearch() : null"
+                      [appDisabled]="appStatementTypeOptions?.length == null || appStatementTypeOptions.length === 0"
+                      [appOptions]="appStatementTypeOptions"
+                      [appPlaceholder]="typeSelect.appDisabled ? ('search.noData' | translate) : ''"
+                      [appValue]="appStatementTypeOptions ? appStatementTypeOptions[0]?.value : undefined"
+                      class="openk-info filters--select--input-width">
+          </app-select>
+        </div>
+      </div>
+      <div *ngIf="appFilters.status != null"
+           class="filter-group filter-group---stacked">
+        <button
+          (click)="appFilters.status = !appFilters.status;
+          setSearchParams('finished', statusSelect.appValue, appFilters.status); emitSearch()"
+          [class.openk-info]="appFilters.status"
+          class="openk-button openk-chip filters--btn filters--btn---margin">
+          Status
+        </button>
+        <div class="filters--finished-select-width">
+          <app-select #statusSelect
+                      (appValueChange)="setSearchParams('finished', statusSelect.appValue, appFilters.status);
+                      appFilters.status ? emitSearch() : null"
+                      [appOptions]="finishedOptions$ | async"
+                      [appValue]="(finishedOptions$ | async)?.length > 0 ? (finishedOptions$ | async)[0].value : statusSelect.appValue"
+                      class="openk-info filters--select--input-width">
+          </app-select>
+        </div>
+      </div>
+      <div *ngIf="appFilters.editedByMe != null"
+           class="filter-group filter-group---stacked">
+        <button
+          (click)="appFilters.editedByMe = !appFilters.editedByMe; setParamsBoolean('editedByMe', appFilters.editedByMe ? appFilters.editedByMe : undefined)"
+          *ngIf="appFilters.editedByMe != null"
+          [class.openk-info]="appFilters.editedByMe"
+          class="openk-button openk-chip filters--btn">
+          {{"search.editedByMe" | translate}}
+        </button>
+      </div>
+    </div>
+    <div class="filters--date-selects">
+      <div *ngIf="appFilters.creationDateFrom != null || appFilters.creationDateTo != null"
+           class="filter-group filter-group---stacked">
+        <div class="filters--date-selects--block">
+          <app-date-filter
+            #creationDateFrom
+            (appValueChange)="setSearchParamsDate('creationDateFrom', $event, creationDateFrom.appActive)"
+            *ngIf="appFilters.creationDateFrom != null"
+            [appActive]="appFilters.creationDateFrom"
+            [appTitle]="'search.creationDateFrom' | translate">
+          </app-date-filter>
+          <app-date-filter
+            #creationDateTo
+            (appValueChange)="setSearchParamsDate('creationDateTo', $event, creationDateTo.appActive)"
+            *ngIf="appFilters.creationDateTo != null"
+            [appActive]="appFilters.creationDateTo"
+            [appTitle]="'search.creationDateTo' | translate">
+          </app-date-filter>
+        </div>
+      </div>
+      <div *ngIf="appFilters.dueDateFrom != null || appFilters.dueDateTo != null"
+           class="filter-group filter-group---stacked">
+        <div class="filters--date-selects--block">
+          <app-date-filter
+            #dueDateFrom
+            (appValueChange)="setSearchParamsDate('dueDateFrom', $event, dueDateFrom.appActive)"
+            *ngIf="appFilters.dueDateFrom != null"
+            [appActive]="appFilters.dueDateFrom"
+            [appTitle]="'search.dueDateFrom' | translate">
+          </app-date-filter>
+          <app-date-filter
+            #dueDateTo
+            (appValueChange)="setSearchParamsDate('dueDateTo', $event, dueDateTo.appActive)"
+            *ngIf="appFilters.dueDateTo != null"
+            [appActive]="appFilters.dueDateTo"
+            [appTitle]="'search.dueDateTo' | translate">
+          </app-date-filter>
+        </div>
+      </div>
+      <div *ngIf="appFilters.receiptDateFrom != null || appFilters.receiptDateTo != null"
+           class="filter-group filter-group---stacked">
+        <div class="filters--date-selects--block">
+          <app-date-filter
+            #receiptDateFrom
+            (appValueChange)="setSearchParamsDate('receiptDateFrom', $event, receiptDateFrom.appActive)"
+            *ngIf="appFilters.receiptDateFrom != null"
+            [appActive]="appFilters.receiptDateFrom"
+            [appTitle]="'search.receiptDateFrom' | translate">
+          </app-date-filter>
+          <app-date-filter
+            #receiptDateTo
+            (appValueChange)="setSearchParamsDate('receiptDateTo', $event, receiptDateTo.appActive)"
+            *ngIf="appFilters.receiptDateTo != null"
+            [appActive]="appFilters.receiptDateTo"
+            [appTitle]="'search.receiptDateTo' | translate">
+          </app-date-filter>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
diff --git a/src/app/features/search/components/search-filter/search-filter.component.scss b/src/app/features/search/components/search-filter/search-filter.component.scss
new file mode 100644
index 0000000..6dae64d
--- /dev/null
+++ b/src/app/features/search/components/search-filter/search-filter.component.scss
@@ -0,0 +1,133 @@
+/********************************************************************************
+ * 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%;
+}
+
+.filters--searchbar {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-bottom: 1em;
+  width: 100%;
+}
+
+.filters--searchbar--text {
+  margin-right: 0.5em;
+  min-width: 2.9em;
+}
+
+.filters--searchbar--input {
+  flex: 1;
+  max-width: 42.85em;
+}
+
+.filters {
+  display: flex;
+  flex-direction: row;
+}
+
+.filters--row {
+  display: inline-flex;
+  align-items: center;
+  box-sizing: border-box;
+  flex-wrap: wrap;
+}
+
+.filters--btn {
+  min-width: 6em;
+  font-size: small;
+  border-color: get-color($openk-info-palette, 500);
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+
+.filters--btn---margin {
+  margin-right: 0.5em;
+}
+
+.filters--type-select-width {
+  width: 12em;
+}
+
+.filters--finished-select-width {
+  width: 8em;
+}
+
+.filters--select--input-width {
+  width: 100%;
+}
+
+.filters--date-selects {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+}
+
+.filters--date-selects--block {
+  display: flex;
+  flex-direction: column;
+
+  :first-child {
+    margin-bottom: 0.2em;
+  }
+}
+
+.openk-button-rounded {
+  font-size: 1.5em;
+  border: 0;
+  color: get-color($openk-info-palette);
+  margin-right: 0.25em;
+  min-width: 2em;
+
+  &:not(.openk-info) {
+    background-color: transparent;
+  }
+
+  &:not(.openk-info):active,
+  &:not(.openk-info):focus,
+  &:not(.openk-info):hover {
+    background-color: $openk-background-highlight;
+  }
+}
+
+.openk-chip {
+  height: 2em;
+}
+
+.filter-group {
+  background-color: $openk-background-highlight;
+  padding: 0.3em;
+  border-radius: 6px;
+  border: 1px solid $openk-form-border;
+  display: inline-flex;
+  align-items: center;
+  box-sizing: border-box;
+  height: 100%;
+  margin-right: 0.5em;
+}
+
+.filter-group---stacked {
+  height: initial;
+  margin-bottom: 0.5em;
+}
+
+.all-filters {
+  display: flex;
+  flex-direction: column;
+
+}
diff --git a/src/app/features/search/components/search-filter/search-filter.component.spec.ts b/src/app/features/search/components/search-filter/search-filter.component.spec.ts
new file mode 100644
index 0000000..ac06435
--- /dev/null
+++ b/src/app/features/search/components/search-filter/search-filter.component.spec.ts
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * 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 {queryParamsIdSelector} from "../../../../store/root/selectors";
+import {SearchModule} from "../../search.module";
+import {SearchFilterComponent} from "./search-filter.component";
+
+describe("SearchFilterComponent", () => {
+    let component: SearchFilterComponent;
+    let fixture: ComponentFixture<SearchFilterComponent>;
+    let store: Store;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                SearchModule,
+                I18nModule
+            ],
+            providers: [
+                provideMockStore({
+                    initialState: {},
+                    selectors: [
+                        {
+                            selector: queryParamsIdSelector,
+                            value: 19
+                        }
+                    ]
+                })
+            ]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(SearchFilterComponent);
+        component = fixture.componentInstance;
+        store = fixture.componentRef.injector.get(Store);
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should set all filter active status to false on disableAllFilters", () => {
+        component.appFilters = {
+            status: false,
+            editedByMe: true,
+            dueDateFrom: false,
+            dueDateTo: false
+        };
+        component.disableAllFilters();
+        expect(component.appFilters).toEqual({
+            status: false,
+            editedByMe: false,
+            dueDateFrom: false,
+            dueDateTo: false
+        });
+    });
+
+    it("should set the search parameter q and emit onValueChange", () => {
+        spyOn(component.appValueChange, "emit").and.callThrough();
+        component.searchByString("test");
+        expect(component.appValueChange.emit).toHaveBeenCalledWith({q: "test"});
+    });
+
+    it("should set search parameter and not emit", () => {
+        component.appFilters = {
+            filterForType: false
+        };
+        spyOn(component.appValueChange, "emit").and.callThrough();
+        component.setSearchParams("typeId", 2, true);
+        expect(component.appValueChange.emit).not.toHaveBeenCalled();
+        expect(component.appValue).toEqual({
+            q: "",
+            typeId: 2
+        });
+        component.setSearchParams("typeId", 2, false);
+        expect(component.appValue).toEqual({q: "", typeId: undefined});
+    });
+});
diff --git a/src/app/features/search/components/search-filter/search-filter.component.stories.ts b/src/app/features/search/components/search-filter/search-filter.component.stories.ts
new file mode 100644
index 0000000..6b9e6ba
--- /dev/null
+++ b/src/app/features/search/components/search-filter/search-filter.component.stories.ts
@@ -0,0 +1,32 @@
+/********************************************************************************
+ * 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 {withKnobs} from "@storybook/addon-knobs";
+import {moduleMetadata, storiesOf} from "@storybook/angular";
+import {I18nModule} from "../../../../core";
+import {SearchModule} from "../../search.module";
+import {SearchFilterComponent} from "./search-filter.component";
+
+storiesOf("Features / search", module)
+    .addDecorator(withKnobs)
+    .addDecorator(moduleMetadata({
+        declarations: [],
+        imports: [
+            I18nModule,
+            SearchModule
+        ]
+    }))
+    .add("SearchFilterComponent", () => ({
+        component: SearchFilterComponent,
+        props: {}
+    }));
diff --git a/src/app/features/search/components/search-filter/search-filter.component.ts b/src/app/features/search/components/search-filter/search-filter.component.ts
new file mode 100644
index 0000000..d407dcc
--- /dev/null
+++ b/src/app/features/search/components/search-filter/search-filter.component.ts
@@ -0,0 +1,130 @@
+/********************************************************************************
+ * 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, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {TranslateService} from "@ngx-translate/core";
+import {Observable} from "rxjs";
+import {map} from "rxjs/operators";
+import {IAPISearchOptions} from "../../../../core/api/shared";
+import {AbstractControlValueAccessorComponent} from "../../../../shared/controls/common";
+import {ISelectOption} from "../../../../shared/controls/select/model";
+import {momentFormatInternal, parseMomentToString} from "../../../../util/moment";
+import {IFilterToDisplay} from "./IFilterToDisplay";
+
+/**
+ * This component displays a selection of filters and generates search parameters.
+ * Those search parameters can be used in the backend calls to filter the list of all statements for e.g. specific keywords or date ranges.
+ * The displayed filters and their state are set by the input property appFilters.
+ *  E.g.
+ *  {
+ *      status: true,
+ *      editedByMe: false
+ *  }
+ *  only displays the filter dropdown for status (finished/not finished) and the toggle for editedByMe state.
+ *  The initial value for the filter button for status is true.
+ *  That means the filter is active with the default value (first value in drop down)
+ */
+
+@Component({
+    selector: "app-search-filter",
+    templateUrl: "./search-filter.component.html",
+    styleUrls: ["./search-filter.component.scss"]
+})
+export class SearchFilterComponent extends AbstractControlValueAccessorComponent<IAPISearchOptions> implements OnInit {
+
+    @Input()
+    public appLoading: boolean;
+
+    @Input()
+    public appStatementTypeOptions: ISelectOption<number>[];
+
+    @Input()
+    public appShowSearch = true;
+
+    @Output()
+    public appFilterParams = new EventEmitter<IAPISearchOptions>();
+
+    @Input()
+    public appFilters: IFilterToDisplay = {
+        filterForType: false,
+        status: false,
+        editedByMe: false,
+        dueDateFrom: false,
+        dueDateTo: false,
+        creationDateFrom: false,
+        creationDateTo: false,
+        receiptDateFrom: false,
+        receiptDateTo: false
+    };
+
+    public finishedOptions$: Observable<ISelectOption[]> = this.translateService.get(["search.open", "search.finished"]).pipe(
+        map((value) => {
+            return [
+                {
+                    label: value["search.open"],
+                    value: false
+                },
+                {
+                    label: value["search.finished"],
+                    value: true
+                }
+            ];
+        })
+    );
+
+    public constructor(public readonly translateService: TranslateService) {
+        super();
+    }
+
+    public ngOnInit() {
+        this.writeValue({
+            q: this.appShowSearch ? "" : undefined
+        }, true);
+    }
+
+    public searchByString(q: string) {
+        this.writeValue({...this.appValue, q}, true);
+    }
+
+    public setSearchParams(label: string, value: string | number, filterActive: boolean) {
+        const newValue = {...this.appValue};
+        newValue[label] = filterActive ? value : undefined;
+        this.writeValue(newValue);
+    }
+
+    public setSearchParamsDate(label: string, value: Date, filterActive: boolean) {
+        const newValue = {...this.appValue};
+        newValue[label] = filterActive ? parseMomentToString(value, momentFormatInternal, momentFormatInternal) : undefined;
+        this.appFilters[label] = filterActive;
+        this.writeValue(newValue, true);
+    }
+
+    public setParamsBoolean(label: string, value: boolean) {
+        const newValue = {...this.appValue};
+        newValue[label] = value;
+        this.writeValue(newValue, true);
+    }
+
+    public emitSearch() {
+        this.appValueChange.emit(this.appValue);
+    }
+
+    public disableAllFilters() {
+        for (const key of Object.keys(this.appFilters)) {
+            this.appFilters[key] = false;
+        }
+        this.writeValue({q: undefined}, true);
+    }
+
+}
+
diff --git a/src/app/features/search/components/search/index.ts b/src/app/features/search/components/search-statements/index.ts
similarity index 92%
copy from src/app/features/search/components/search/index.ts
copy to src/app/features/search/components/search-statements/index.ts
index 5eb9c7f..aa947a3 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/features/search/components/search-statements/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./search-statements.component";
diff --git a/src/app/features/search/components/search-statements/search-statements.component.html b/src/app/features/search/components/search-statements/search-statements.component.html
new file mode 100644
index 0000000..518a4a0
--- /dev/null
+++ b/src/app/features/search/components/search-statements/search-statements.component.html
@@ -0,0 +1,37 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<div class="search-filters">
+  <app-search-filter
+    (appValueChange)="addToSearchParams($event)"
+    [appLoading]="statementLoading$ | async"
+    [appStatementTypeOptions]="statementTypeOptions$ | async">
+  </app-search-filter>
+</div>
+
+<app-statement-table
+  (appSort)="sort($event?.label, $event?.direction)"
+  [appColumns]="columns"
+  [appEntries]="searchContent$ | async"
+  [appIsSortable]="true"
+  [appStatementTypeOptions]="statementTypeOptions$ | async"
+  class="openk-table---last-row-without-border search-list">
+</app-statement-table>
+
+<app-pagination-counter
+  (appPageChange)="changePage($event?.page, $event?.size)"
+  [appDisabled]="statementLoading$ | async"
+  [appPageSize]="(searchInfo$ | async)?.size"
+  [appPage]="(searchInfo$ | async)?.currentPage"
+  [appTotalPages]="(searchInfo$ | async)?.totalPages">
+</app-pagination-counter>
diff --git a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss b/src/app/features/search/components/search-statements/search-statements.component.scss
similarity index 72%
copy from src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
copy to src/app/features/search/components/search-statements/search-statements.component.scss
index 4d2360d..2d673ee 100644
--- a/src/app/shared/linked-statements/linked-statements/linked-statements.component.scss
+++ b/src/app/features/search/components/search-statements/search-statements.component.scss
@@ -11,17 +11,23 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-@import "../../../../styles/openk.styles";
+@import "openk.styles";
+
 
 :host {
+  position: relative;
+  display: block;
   width: 100%;
+  box-sizing: border-box;
+  padding: 1em;
 }
 
-.statements {
-  margin-bottom: 1em;
-  display: grid;
+.search-list {
+  min-height: 5.3125em;
+  background: get-color($openk-default-palette);
 }
 
-.statements--titlebar {
+.search-filters {
   margin-bottom: 0.5em;
+  display: flex;
 }
diff --git a/src/app/features/search/components/search-statements/search-statements.component.spec.ts b/src/app/features/search/components/search-statements/search-statements.component.spec.ts
new file mode 100644
index 0000000..c9f3032
--- /dev/null
+++ b/src/app/features/search/components/search-statements/search-statements.component.spec.ts
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * 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 {RouterTestingModule} from "@angular/router/testing";
+import {MockStore, provideMockStore} from "@ngrx/store/testing";
+import {I18nModule} from "../../../../core/i18n";
+import {startStatementSearchAction} from "../../../../store/statements/actions";
+import {SearchModule} from "../../search.module";
+import {SearchStatementsComponent} from "./search-statements.component";
+
+describe("SearchComponent", () => {
+    let component: SearchStatementsComponent;
+    let fixture: ComponentFixture<SearchStatementsComponent>;
+    let store: MockStore;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [
+                SearchModule,
+                I18nModule,
+                RouterTestingModule
+            ],
+            providers: [provideMockStore()]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(SearchStatementsComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        spyOn(store, "dispatch").and.callThrough();
+        fixture.detectChanges();
+    });
+
+    it("should create", () => {
+        expect(component).toBeTruthy();
+    });
+
+    it("should start search after init", () => {
+        expect(store.dispatch).toHaveBeenCalledWith(startStatementSearchAction({options: component.searchParams}));
+    });
+
+    it("should add parameters to search", () => {
+        component.addToSearchParams({q: "", typeId: 19});
+        expect(store.dispatch).toHaveBeenCalledWith(startStatementSearchAction({
+            options: {...component.searchParams, q: "", typeId: 19}
+        }));
+    });
+
+    it("should sort list", () => {
+        component.sort("id", "asc");
+        expect(store.dispatch).toHaveBeenCalledWith(startStatementSearchAction({
+            options: {...component.searchParams, sort: "id,asc"}
+        }));
+    });
+
+    it("should change page", () => {
+        component.changePage(19, 1919);
+        expect(store.dispatch).toHaveBeenCalledWith(startStatementSearchAction({
+            options: {...component.searchParams, page: 19, size: 1919}
+        }));
+    });
+
+});
diff --git a/src/app/features/search/components/search-statements/search-statements.component.ts b/src/app/features/search/components/search-statements/search-statements.component.ts
new file mode 100644
index 0000000..90579db
--- /dev/null
+++ b/src/app/features/search/components/search-statements/search-statements.component.ts
@@ -0,0 +1,86 @@
+/********************************************************************************
+ * 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, OnInit} from "@angular/core";
+import {select, Store} from "@ngrx/store";
+import {IAPISearchOptions} from "../../../../core/api/shared";
+import {StatementTableComponent} from "../../../../shared/layout/statement-table/components";
+import {statementTypesSelector} from "../../../../store/settings/selectors";
+import {startStatementSearchAction} from "../../../../store/statements/actions";
+import {statementLoadingSelector} from "../../../../store/statements/selectors";
+import {getSearchContentInfoSelector, getSearchContentStatementsSelector} from "../../../../store/statements/selectors/search";
+
+/**
+ * This component display a list of statements. A keyword search and filters can be applied to the list of statements.
+ * The list can also be sorted by clicking on specific header column to sort for.
+ * Pagination and sorting will be added to the query parameters for the search calls to the backend.
+ */
+
+@Component({
+    selector: "app-search-statements",
+    templateUrl: "./search-statements.component.html",
+    styleUrls: ["./search-statements.component.scss"]
+})
+export class SearchStatementsComponent implements OnInit {
+
+    public columns = [...StatementTableComponent.SEARCH_COLUMNS];
+
+    public statementTypeOptions$ = this.store.pipe(select(statementTypesSelector));
+
+    public searchContent$ = this.store.pipe(select(getSearchContentStatementsSelector));
+
+    public searchInfo$ = this.store.pipe(select(getSearchContentInfoSelector));
+
+    public statementLoading$ = this.store.pipe(select(statementLoadingSelector));
+
+    public pageSize = 10;
+
+    public baseSearchParams: IAPISearchOptions = {
+        q: "",
+        size: this.pageSize,
+        page: 0
+    };
+
+    public searchParams: IAPISearchOptions = {...this.baseSearchParams};
+
+    public sortParam: string;
+
+    public constructor(public store: Store) {
+
+    }
+
+    public ngOnInit() {
+        this.search();
+    }
+
+    public search() {
+        this.store.dispatch(startStatementSearchAction({options: this.searchParams}));
+    }
+
+    public sort(label: string, direction: "asc" | "desc") {
+        this.sortParam = `${label},${direction}`;
+        this.searchParams = {...this.searchParams, sort: this.sortParam};
+        this.search();
+    }
+
+    public addToSearchParams(additionalParams: IAPISearchOptions) {
+        this.searchParams = {...this.baseSearchParams, ...additionalParams, sort: this.sortParam, size: this.pageSize};
+        this.search();
+    }
+
+    public changePage(page: number, size: number) {
+        this.searchParams = {...this.searchParams, page, size};
+        this.pageSize = size;
+        this.search();
+    }
+}
diff --git a/src/app/features/search/components/search/search.component.html b/src/app/features/search/components/search/search.component.html
deleted file mode 100644
index 0bc2dce..0000000
--- a/src/app/features/search/components/search/search.component.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-------------------------------------------------------------------------------
- * 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
- -------------------------------------------------------------------------------->
-
-<div style="padding: 1em;">
-  Not yet implemented.
-</div>
diff --git a/src/app/features/search/index.ts b/src/app/features/search/index.ts
index cfd6650..5ea4030 100644
--- a/src/app/features/search/index.ts
+++ b/src/app/features/search/index.ts
@@ -12,3 +12,4 @@
  ********************************************************************************/
 
 export * from "./search.module";
+export * from "./components";
diff --git a/src/app/features/search/search-routing.module.ts b/src/app/features/search/search-routing.module.ts
index 6d938a9..e3d5b7c 100644
--- a/src/app/features/search/search-routing.module.ts
+++ b/src/app/features/search/search-routing.module.ts
@@ -13,14 +13,24 @@
 
 import {NgModule} from "@angular/core";
 import {RouterModule, Routes} from "@angular/router";
-import {SearchComponent} from "./components";
+import {PositionSearchComponent, SearchStatementsComponent} from "./components";
 import {SearchModule} from "./search.module";
 
 const routes: Routes = [
     {
         path: "",
         pathMatch: "full",
-        component: SearchComponent
+        redirectTo: "list"
+    },
+    {
+        path: "list",
+        pathMatch: "full",
+        component: SearchStatementsComponent
+    },
+    {
+        path: "map",
+        pathMatch: "full",
+        component: PositionSearchComponent
     }
 ];
 
diff --git a/src/app/features/search/search.module.ts b/src/app/features/search/search.module.ts
index 9e594b1..937ca93 100644
--- a/src/app/features/search/search.module.ts
+++ b/src/app/features/search/search.module.ts
@@ -13,17 +13,44 @@
 
 import {CommonModule} from "@angular/common";
 import {NgModule} from "@angular/core";
-import {SearchComponent} from "./components";
+import {MatIconModule} from "@angular/material/icon";
+import {RouterModule} from "@angular/router";
+import {TranslateModule} from "@ngx-translate/core";
+import {DateControlModule} from "../../shared/controls/date-control";
+import {SelectModule} from "../../shared/controls/select";
+import {PaginationCounterModule} from "../../shared/layout/pagination-counter";
+import {SearchbarModule} from "../../shared/layout/searchbar";
+import {StatementTableModule} from "../../shared/layout/statement-table";
+import {LeafletModule} from "../../shared/leaflet";
+import {DateFilterComponent} from "./components/date-filter";
+import {PositionSearchComponent} from "./components/position-search";
+import {SearchFilterComponent} from "./components/search-filter";
+import {SearchStatementsComponent} from "./components/search-statements";
 
 @NgModule({
     imports: [
-        CommonModule
+        CommonModule,
+        StatementTableModule,
+        PaginationCounterModule,
+        SearchbarModule,
+        SelectModule,
+        DateControlModule,
+        TranslateModule,
+        MatIconModule,
+        RouterModule,
+        LeafletModule
     ],
     declarations: [
-        SearchComponent
+        SearchFilterComponent,
+        DateFilterComponent,
+        SearchStatementsComponent,
+        PositionSearchComponent
     ],
     exports: [
-        SearchComponent
+        SearchFilterComponent,
+        DateFilterComponent,
+        SearchStatementsComponent,
+        PositionSearchComponent
     ]
 })
 export class SearchModule {
diff --git a/src/app/shared/controls/contact-select/contact-select.component.html b/src/app/shared/controls/contact-select/contact-select.component.html
index a045f94..84f4d4a 100644
--- a/src/app/shared/controls/contact-select/contact-select.component.html
+++ b/src/app/shared/controls/contact-select/contact-select.component.html
@@ -42,9 +42,9 @@
 
         <app-pagination-counter
           (appPageChange)="appPageChange.emit($event)"
-          *ngIf="appPageSize >= 2"
           [appDisabled]="appDisabled || appIsLoading"
           [appPageSize]="appPageSize"
+          [appTotalPages]="appTotalPages"
           [appPage]="appPage">
         </app-pagination-counter>
       </div>
diff --git a/src/app/shared/controls/contact-select/contact-select.component.scss b/src/app/shared/controls/contact-select/contact-select.component.scss
index a28ef31..7df646c 100644
--- a/src/app/shared/controls/contact-select/contact-select.component.scss
+++ b/src/app/shared/controls/contact-select/contact-select.component.scss
@@ -56,10 +56,11 @@
   display: flex;
   flex-direction: row;
   justify-content: space-between;
+  align-items: flex-start;
 }
 
 .contacts--selection--list--box--info--button {
-  margin-top: 1em;
+  margin-top: 0.5em;
 }
 
 .contacts--details {
diff --git a/src/app/shared/controls/contact-select/contact-select.component.ts b/src/app/shared/controls/contact-select/contact-select.component.ts
index e916aae..3dcc299 100644
--- a/src/app/shared/controls/contact-select/contact-select.component.ts
+++ b/src/app/shared/controls/contact-select/contact-select.component.ts
@@ -47,14 +47,17 @@
     public appMessage: string;
 
     @Output()
-    public appPageChange = new EventEmitter<number>();
+    public appPageChange = new EventEmitter<{ page: number, size: number }>();
 
     @Input()
-    public appPageSize: number;
+    public appTotalPages: number;
 
     @Input()
     public appSearch: string;
 
+    @Input()
+    public appPageSize: number;
+
     @Output()
     public appSearchChange = new EventEmitter<string>();
 
diff --git a/src/app/shared/controls/map-select/components/map-select.component.html b/src/app/shared/controls/map-select/components/map-select.component.html
index 0b9644a..21b71a7 100644
--- a/src/app/shared/controls/map-select/components/map-select.component.html
+++ b/src/app/shared/controls/map-select/components/map-select.component.html
@@ -11,29 +11,15 @@
  * SPDX-License-Identifier: EPL-2.0
  -------------------------------------------------------------------------------->
 
-<div class="map">
-  <div #appLeaflet="appLeaflet"
-       (appLatLngZoomChange)="select($event)"
-       [appDisabled]="appDisabled"
-       [appView]="appValue | stringToLatLngZoom"
-       appLeaflet
-       class="map--leaflet">
+<app-leaflet-map
+  (appCenterChange)="select($event)"
+  (appOpenGis)="appOpenGis.emit($event)"
+  [appCenter]="appValue"
+  [appDisabled]="appDisabled"
+  [appSubCaption]="appSubCaption"
+  class="map">
 
-    <ng-container appLeafletCenterMarker>
-    </ng-container>
+  <ng-container appLeafletCenterMarker>
+  </ng-container>
 
-  </div>
-
-  <app-action-button
-    (appClick)="appActionButtonClick.emit(appLeaflet.getBounds())"
-    *ngIf="appActionButtonLabel"
-    [appDisabled]="appDisabled"
-    [appIcon]="'my_location'"
-    class="map--action-button openk-info">
-    {{appActionButtonLabel}}
-  </app-action-button>
-</div>
-
-<label *ngIf="appSubCaption" class="sub-caption">
-  {{appSubCaption}}
-</label>
+</app-leaflet-map>
diff --git a/src/app/shared/controls/map-select/components/map-select.component.scss b/src/app/shared/controls/map-select/components/map-select.component.scss
index d45e610..7e59f1f 100644
--- a/src/app/shared/controls/map-select/components/map-select.component.scss
+++ b/src/app/shared/controls/map-select/components/map-select.component.scss
@@ -14,42 +14,7 @@
 @import "openk.styles";
 
 :host {
-  width: 100%;
-  height: 100%;
-  box-sizing: border-box;
-
-  display: flex;
-  flex-flow: column;
-}
-
-.map {
-  flex: 1 1 100%;
-  width: 100%;
-  box-sizing: border-box;
-  border: 1px solid $openk-form-border;
-  position: relative;
-  overflow: hidden;
-}
-
-.map--leaflet {
-  width: 100%;
-  height: 100%;
-}
-
-.map--action-button {
   display: block;
-  width: fit-content;
-  height: fit-content;
-  position: absolute;
-  bottom: 10px;
-  left: 10px;
-  z-index: 1000;
-}
-
-.sub-caption {
-  color: $openk-form-border;
-  margin-top: 0.5em;
-  margin-left: auto;
-  font-size: smaller;
-  font-style: italic;
+  width: 100%;
+  height: 100%;
 }
diff --git a/src/app/shared/controls/map-select/components/map-select.component.spec.ts b/src/app/shared/controls/map-select/components/map-select.component.spec.ts
index f57df21..dd5e766 100644
--- a/src/app/shared/controls/map-select/components/map-select.component.spec.ts
+++ b/src/app/shared/controls/map-select/components/map-select.component.spec.ts
@@ -12,6 +12,7 @@
  ********************************************************************************/
 
 import {async, ComponentFixture, TestBed} from "@angular/core/testing";
+import {I18nModule} from "../../../../core";
 import {MapSelectModule} from "../map-select.module";
 import {MapSelectComponent} from "./map-select.component";
 
@@ -21,7 +22,7 @@
 
     beforeEach(async(() => {
         TestBed.configureTestingModule({
-            imports: [MapSelectModule]
+            imports: [MapSelectModule, I18nModule]
         }).compileComponents();
     }));
 
diff --git a/src/app/shared/controls/map-select/components/map-select.component.ts b/src/app/shared/controls/map-select/components/map-select.component.ts
index f408006..9c8759d 100644
--- a/src/app/shared/controls/map-select/components/map-select.component.ts
+++ b/src/app/shared/controls/map-select/components/map-select.component.ts
@@ -13,7 +13,7 @@
 
 import {Component, EventEmitter, forwardRef, Input, Output} from "@angular/core";
 import {NG_VALUE_ACCESSOR} from "@angular/forms";
-import {ILeafletBounds} from "../../../layout/leaflet";
+import {ILeafletBounds} from "../../../leaflet";
 import {AbstractControlValueAccessorComponent} from "../../common";
 
 @Component({
@@ -36,11 +36,8 @@
     @Input()
     public appSubCaption: string;
 
-    @Input()
-    public appActionButtonLabel: string;
-
     @Output()
-    public appActionButtonClick = new EventEmitter<ILeafletBounds>();
+    public appOpenGis = new EventEmitter<ILeafletBounds>();
 
     public select(value: string) {
         // Note that this.appValue should not be changed here:
diff --git a/src/app/shared/controls/map-select/map-select.module.ts b/src/app/shared/controls/map-select/map-select.module.ts
index 8a22296..278693d 100644
--- a/src/app/shared/controls/map-select/map-select.module.ts
+++ b/src/app/shared/controls/map-select/map-select.module.ts
@@ -14,7 +14,7 @@
 import {CommonModule} from "@angular/common";
 import {NgModule} from "@angular/core";
 import {ActionButtonModule} from "../../layout/action-button";
-import {LeafletModule} from "../../layout/leaflet";
+import {LeafletModule} from "../../leaflet";
 import {MapSelectComponent} from "./components";
 
 @NgModule({
diff --git a/src/app/shared/controls/select/components/select-group/select-group.component.scss b/src/app/shared/controls/select/components/select-group/select-group.component.scss
index b07ef7e..40af940 100644
--- a/src/app/shared/controls/select/components/select-group/select-group.component.scss
+++ b/src/app/shared/controls/select/components/select-group/select-group.component.scss
@@ -18,7 +18,7 @@
 }
 
 .select-group-title {
-  font-weight: bold;
+  font-weight: 600;
   margin-top: 0.5em;
 
   &:first-child {
diff --git a/src/app/shared/controls/select/components/select/select.component.scss b/src/app/shared/controls/select/components/select/select.component.scss
index 305eef4..307fa14 100644
--- a/src/app/shared/controls/select/components/select/select.component.scss
+++ b/src/app/shared/controls/select/components/select/select.component.scss
@@ -103,6 +103,13 @@
   box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1);
 }
 
+@supports (-moz-appearance:none) {
+
+  .select-options {
+    overflow-y: scroll;
+  }
+}
+
 .select-options---static-size {
   display: flex;
   flex-flow: column nowrap;
diff --git a/src/app/shared/layout/collapsible/collapsible.component.ts b/src/app/shared/layout/collapsible/collapsible.component.ts
index 6e3e19d..72fef31 100644
--- a/src/app/shared/layout/collapsible/collapsible.component.ts
+++ b/src/app/shared/layout/collapsible/collapsible.component.ts
@@ -48,7 +48,7 @@
     public appTitle: string;
 
     /**
-     * If set, the template is rendered is rendered in the header part of the container
+     * If set, the template is rendered in the header part of the container
      */
     @Input()
     public appHeaderTemplateRef: TemplateRef<any>;
diff --git a/src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.ts b/src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.ts
deleted file mode 100644
index 62fcaae..0000000
--- a/src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/********************************************************************************
- * 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 {AfterViewInit, Directive, ElementRef, HostBinding, Inject, Input, NgZone, OnDestroy, OnInit, Optional, Output} from "@angular/core";
-import {InvalidateSizeOptions, LatLngLiteral, LeafletEvent, LeafletMouseEvent, Map, TileLayer} from "leaflet";
-import {defer, Observable, of, pipe} from "rxjs";
-import {debounceTime, distinctUntilChanged, map, switchMap, takeUntil, throttleTime} from "rxjs/operators";
-import {runInZone, runOutsideZone} from "../../../../../util/rxjs";
-import {ILeafletConfiguration, LEAFLET_CONFIGURATION_TOKEN, LEAFLET_RESIZE_TOKEN} from "../../leaflet-configuration.token";
-import {fromLeafletEvent, latLngZoomToString} from "../../util";
-
-export interface ILeafletBounds {
-    northWest: LatLngLiteral;
-    northEast: LatLngLiteral;
-    southEast: LatLngLiteral;
-    southWest: LatLngLiteral;
-    center: LatLngLiteral;
-    zoom: number;
-}
-
-@Directive({
-    selector: "[appLeaflet]",
-    exportAs: "appLeaflet"
-})
-export class LeafletDirective implements OnInit, OnDestroy, AfterViewInit {
-
-    @HostBinding("class.no-pointer-events")
-    @HostBinding("class.disable")
-    @Input()
-    public appDisabled: boolean;
-
-    @Output()
-    public appLatLngZoomChange = defer(() => this.on("move zoom", true)).pipe(
-        debounceTime(10),
-        map(() => latLngZoomToString(this.leaflet.getCenter(), this.leaflet.getZoom())),
-        distinctUntilChanged(),
-        runInZone(this.ngZone)
-    );
-
-    @Output()
-    public appClick = defer(() => this.on<LeafletMouseEvent>("click"));
-
-    @Output()
-    public appUnload$ = defer(() => this.on("unload"));
-
-    public readonly leaflet: Map;
-
-    public constructor(
-        public readonly elementRef: ElementRef<HTMLElement>,
-        public readonly ngZone: NgZone,
-        @Inject(LEAFLET_CONFIGURATION_TOKEN) public readonly configuration: ILeafletConfiguration,
-        @Optional() @Inject(LEAFLET_RESIZE_TOKEN) public resize$: Observable<any>
-    ) {
-        this.leaflet = this.ngZone.runOutsideAngular(() => {
-            const tileLayer = new TileLayer(this.configuration.urlTemplate, {
-                attribution: this.configuration.attribution
-            });
-            const result = new Map(this.elementRef.nativeElement, {layers: [tileLayer]});
-            result.setView({lat: configuration.lat, lng: configuration.lng}, configuration.zoom);
-            return result;
-        });
-    }
-
-    @Input()
-    public set appView(value: { lat: number, lng: number, zoom: number }) {
-        if (value != null) {
-            this.ngZone.runOutsideAngular(() => this.leaflet.setView(value, value.zoom));
-        }
-    }
-
-    public ngOnInit() {
-        if (this.resize$ instanceof Observable) {
-            this.resize$.pipe(throttleTime(10), takeUntil(this.appUnload$))
-                .subscribe((_) => this.invalidateSize());
-        }
-    }
-
-    public ngAfterViewInit() {
-        setTimeout(() => this.invalidateSize());
-    }
-
-    public ngOnDestroy() {
-        this.ngZone.runOutsideAngular(() => this.leaflet.remove());
-    }
-
-    public getBounds(): ILeafletBounds {
-        return this.ngZone.runOutsideAngular(() => {
-            const bounds = this.leaflet.getBounds();
-            const zoom = this.leaflet.getZoom();
-            const result = {
-                northWest: bounds.getNorthWest(),
-                northEast: bounds.getNorthEast(),
-                southEast: bounds.getSouthEast(),
-                southWest: bounds.getSouthWest(),
-                center: bounds.getCenter(),
-                zoom
-            };
-            return this.ngZone.run(() => result);
-        });
-    }
-
-    public invalidateSize(options?: boolean | InvalidateSizeOptions) {
-        this.ngZone.runOutsideAngular(() => this.leaflet.invalidateSize(options));
-    }
-
-    public on<T extends LeafletEvent>(type: string, outsideZone?: boolean): Observable<T> {
-        return of(type).pipe(
-            runOutsideZone(this.ngZone),
-            switchMap((_) => fromLeafletEvent<T>(this.leaflet, type)),
-            outsideZone ? pipe() : runInZone(this.ngZone)
-        );
-    }
-
-}
diff --git a/src/app/shared/layout/leaflet/leaflet.module.ts b/src/app/shared/layout/leaflet/leaflet.module.ts
deleted file mode 100644
index f817b70..0000000
--- a/src/app/shared/layout/leaflet/leaflet.module.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/********************************************************************************
- * 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 {CommonModule} from "@angular/common";
-import {ModuleWithProviders, NgModule, Type} from "@angular/core";
-import {Observable} from "rxjs";
-import {LeafletCenterMarkerDirective, LeafletDirective, LeafletMarkerDirective} from "./directives";
-import {LEAFLET_RESIZE_TOKEN} from "./leaflet-configuration.token";
-import {StringToLatLngZoomPipe} from "./pipes";
-
-@NgModule({
-    imports: [
-        CommonModule
-    ],
-    declarations: [
-        LeafletCenterMarkerDirective,
-        LeafletDirective,
-        LeafletMarkerDirective,
-        StringToLatLngZoomPipe
-    ],
-    exports: [
-        LeafletCenterMarkerDirective,
-        LeafletDirective,
-        LeafletMarkerDirective,
-        StringToLatLngZoomPipe
-    ]
-})
-export class LeafletModule {
-
-    public static for<T extends { resize$: Observable<any> }>(resizeService: Type<T>): ModuleWithProviders {
-        return {
-            ngModule: LeafletModule,
-            providers: [
-                {
-                    provide: LEAFLET_RESIZE_TOKEN,
-                    useFactory: (service: T) => service.resize$,
-                    deps: [resizeService]
-                }
-            ]
-        };
-    }
-
-}
diff --git a/src/app/shared/layout/pagination-counter/pagination-counter.component.html b/src/app/shared/layout/pagination-counter/pagination-counter.component.html
index c599d92..c001e58 100644
--- a/src/app/shared/layout/pagination-counter/pagination-counter.component.html
+++ b/src/app/shared/layout/pagination-counter/pagination-counter.component.html
@@ -11,21 +11,30 @@
  * SPDX-License-Identifier: EPL-2.0
  -------------------------------------------------------------------------------->
 
-<div *ngIf="appPageSize > 0" class="page-info">
-  <button (click)="getPreviousPage()"
-          [class.openk-button-disabled]="!(appPage > 0)"
-          [disabled]="appDisabled || !(appPage > 0)"
-          class="openk-button openk-info page-info--button">
-    <mat-icon class="page-info--button--icon">keyboard_arrow_left</mat-icon>
-  </button>
-  <span
-    [class.disabled]="appDisabled"
-    class="page-info--text">
-    {{appPage == null ? 1 : appPage + 1}} / {{appPageSize}}
-  </span>
-  <button (click)="getNextPage()"
-          [disabled]="appDisabled || appPage >= appPageSize - 1"
-          class="openk-button openk-info page-info--button">
-    <mat-icon class="page-info--button--icon">keyboard_arrow_right</mat-icon>
-  </button>
-</div>
+<app-select #pageSizeSelect
+            (appValueChange)="appPageSize = $event; appPageChange.emit({page: 0, size: $event});"
+            [appDisabled]="appDisabled"
+            [appOptions]="appPageSizeOptions"
+            [appValue]="appPageSize"
+            [title]="'shared.pagination.size' | translate"
+            class="page-size-select">
+</app-select>
+
+<button (click)="getPreviousPage(pageSizeSelect.appValue)"
+        [class.openk-button-disabled]="!(appPage > 0)"
+        [disabled]="appDisabled || !(appPage > 0)"
+        class="openk-button openk-info page-info--button">
+  <mat-icon class="page-info--button--icon">keyboard_arrow_left</mat-icon>
+</button>
+
+<span
+  [class.disabled]="appDisabled"
+  class="page-info--text">
+    {{appPage == null ? 1 : appPage + 1}} / {{appTotalPages === 0 ? 1 : appTotalPages}}
+</span>
+
+<button (click)="getNextPage(pageSizeSelect.appValue)"
+        [disabled]="appDisabled || appPage >= appTotalPages - 1"
+        class="openk-button openk-info page-info--button">
+  <mat-icon class="page-info--button--icon">keyboard_arrow_right</mat-icon>
+</button>
diff --git a/src/app/shared/layout/pagination-counter/pagination-counter.component.scss b/src/app/shared/layout/pagination-counter/pagination-counter.component.scss
index e6268bb..134a731 100644
--- a/src/app/shared/layout/pagination-counter/pagination-counter.component.scss
+++ b/src/app/shared/layout/pagination-counter/pagination-counter.component.scss
@@ -11,9 +11,11 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-.page-info {
+:host {
   display: flex;
   justify-content: flex-end;
+  align-items: center;
+  padding-top: 0.2em;
 }
 
 .page-info--button {
@@ -33,3 +35,9 @@
   pointer-events: none;
   opacity: 0.6;
 }
+
+.page-size-select {
+  width: 5.5em;
+  font-size: 0.66em;
+}
+
diff --git a/src/app/shared/layout/pagination-counter/pagination-counter.component.spec.ts b/src/app/shared/layout/pagination-counter/pagination-counter.component.spec.ts
index 464321f..71b2a87 100644
--- a/src/app/shared/layout/pagination-counter/pagination-counter.component.spec.ts
+++ b/src/app/shared/layout/pagination-counter/pagination-counter.component.spec.ts
@@ -12,6 +12,7 @@
  ********************************************************************************/
 
 import {async, ComponentFixture, TestBed} from "@angular/core/testing";
+import {I18nModule} from "../../../core/i18n";
 import {PaginationCounterComponent} from "./pagination-counter.component";
 import {PaginationCounterModule} from "./pagination-counter.module";
 
@@ -22,7 +23,8 @@
     beforeEach(async(() => {
         TestBed.configureTestingModule({
             imports: [
-                PaginationCounterModule
+                PaginationCounterModule,
+                I18nModule
             ]
         }).compileComponents();
     }));
@@ -40,9 +42,9 @@
     it("should emit appPageChange with the correct page number", () => {
         component.appPage = 3;
         spyOn(component.appPageChange, "emit").and.callThrough();
-        component.getNextPage();
-        expect(component.appPageChange.emit).toHaveBeenCalledWith(4);
-        component.getPreviousPage();
-        expect(component.appPageChange.emit).toHaveBeenCalledWith(2);
+        component.getNextPage(10);
+        expect(component.appPageChange.emit).toHaveBeenCalledWith({page: 4, size: 10});
+        component.getPreviousPage(10);
+        expect(component.appPageChange.emit).toHaveBeenCalledWith({page: 2, size: 10});
     });
 });
diff --git a/src/app/shared/layout/pagination-counter/pagination-counter.component.ts b/src/app/shared/layout/pagination-counter/pagination-counter.component.ts
index 0e89738..c502026 100644
--- a/src/app/shared/layout/pagination-counter/pagination-counter.component.ts
+++ b/src/app/shared/layout/pagination-counter/pagination-counter.component.ts
@@ -12,6 +12,7 @@
  ********************************************************************************/
 
 import {Component, EventEmitter, Input, Output} from "@angular/core";
+import {ISelectOption} from "../../controls/select/model";
 
 @Component({
     selector: "app-pagination-counter",
@@ -27,17 +28,29 @@
     public appPage: number;
 
     @Input()
-    public appPageSize: number;
+    public appPageSizeOptions: ISelectOption[] = [
+        {label: "10", value: 10},
+        {label: "25", value: 25},
+        {label: "50", value: 50}
+    ];
+
+    @Input()
+    public appPageSize = this.appPageSizeOptions[0].value;
+
+    @Input()
+    public appTotalPages: number;
 
     @Output()
-    public appPageChange = new EventEmitter<number>();
+    public appPageChange = new EventEmitter<{ page: number, size: number }>();
 
-    public getPreviousPage() {
-        this.appPageChange.emit(this.appPage - 1);
+    public getPreviousPage(pageSize: number) {
+        this.appPageSize = pageSize;
+        this.appPageChange.emit({page: this.appPage - 1, size: this.appPageSize});
     }
 
-    public getNextPage() {
-        this.appPageChange.emit(this.appPage + 1);
+    public getNextPage(pageSize: number) {
+        this.appPageSize = pageSize;
+        this.appPageChange.emit({page: this.appPage + 1, size: this.appPageSize});
     }
 
 }
diff --git a/src/app/shared/layout/pagination-counter/pagination-counter.module.ts b/src/app/shared/layout/pagination-counter/pagination-counter.module.ts
index c440039..15adbe7 100644
--- a/src/app/shared/layout/pagination-counter/pagination-counter.module.ts
+++ b/src/app/shared/layout/pagination-counter/pagination-counter.module.ts
@@ -14,12 +14,16 @@
 import {CommonModule} from "@angular/common";
 import {NgModule} from "@angular/core";
 import {MatIconModule} from "@angular/material/icon";
+import {TranslateModule} from "@ngx-translate/core";
+import {SelectModule} from "../../controls/select";
 import {PaginationCounterComponent} from "./pagination-counter.component";
 
 @NgModule({
     imports: [
         CommonModule,
-        MatIconModule
+        MatIconModule,
+        SelectModule,
+        TranslateModule
     ],
     exports: [
         PaginationCounterComponent
diff --git a/src/app/shared/layout/side-menu/components/side-menu-container/side-menu-container.component.html b/src/app/shared/layout/side-menu/components/side-menu-container/side-menu-container.component.html
index 98df1f0..59bb656 100644
--- a/src/app/shared/layout/side-menu/components/side-menu-container/side-menu-container.component.html
+++ b/src/app/shared/layout/side-menu/components/side-menu-container/side-menu-container.component.html
@@ -60,7 +60,7 @@
 </ng-container>
 
 <div class="main-content main-content---without-scroll">
-  <div class="main-content">
+  <div cdkScrollable class="main-content">
     <ng-content></ng-content>
   </div>
 </div>
diff --git a/src/app/shared/layout/side-menu/side-menu.module.ts b/src/app/shared/layout/side-menu/side-menu.module.ts
index 778b5aa..bbb5ec4 100644
--- a/src/app/shared/layout/side-menu/side-menu.module.ts
+++ b/src/app/shared/layout/side-menu/side-menu.module.ts
@@ -11,6 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
+import {CdkScrollableModule} from "@angular/cdk/scrolling";
 import {CommonModule} from "@angular/common";
 import {NgModule} from "@angular/core";
 import {MatIconModule} from "@angular/material/icon";
@@ -24,7 +25,8 @@
         CommonModule,
         ProgressSpinnerModule,
         MatIconModule,
-        TranslateModule
+        TranslateModule,
+        CdkScrollableModule
     ],
     declarations: [
         SideMenuContainerComponent,
diff --git a/src/app/shared/layout/statement-table/components/statement-table.component.html b/src/app/shared/layout/statement-table/components/statement-table.component.html
index 6e3b9bb..55a9f89 100644
--- a/src/app/shared/layout/statement-table/components/statement-table.component.html
+++ b/src/app/shared/layout/statement-table/components/statement-table.component.html
@@ -46,12 +46,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="id">
+  <ng-container *ngIf="'id'; let label" cdkColumnDef="id">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--id"
         scope="col">
-      {{"shared.statementTable.id" | translate}}
+      <div class="statement-table--header statement-table--header---right">
+        {{"shared.statementTable.id" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="openk-no-whitespace-wrap statement-table--id">
@@ -65,12 +75,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="title">
+  <ng-container *ngIf="'title'; let label" cdkColumnDef="title">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--title"
         scope="col">
-      {{"shared.statementTable.title" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.title" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="statement-table--title">
@@ -78,12 +98,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="city">
+  <ng-container *ngIf="'city'; let label" cdkColumnDef="city">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--city"
         scope="col">
-      {{"shared.statementTable.city" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.city" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="statement-table--city">
@@ -91,12 +121,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="district">
+  <ng-container *ngIf="'district'; let label" cdkColumnDef="district">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--district"
         scope="col">
-      {{"shared.statementTable.district" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.district" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="statement-table--district">
@@ -104,12 +144,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="type">
-    <th *cdkHeaderCellDef="let statementHeader"
+  <ng-container *ngIf="'typeId'; let label" cdkColumnDef="type">
+    <th (click)="click(label, sorting[label])"
+        *cdkHeaderCellDef="let statementHeader;"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--type"
         scope="col">
-      {{"shared.statementTable.statementType" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.statementType" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="openk-no-whitespace-wrap statement-table--type">
@@ -117,12 +167,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="creationDate">
+  <ng-container *ngIf="'creationDate'; let label" cdkColumnDef="creationDate">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--date"
         scope="col">
-      {{"shared.statementTable.creationDate" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.creationDate" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="openk-no-whitespace-wrap statement-table--date">
@@ -130,12 +190,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="receiptDate">
+  <ng-container *ngIf="'receiptDate'; let label" cdkColumnDef="receiptDate">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--date"
         scope="col">
-      {{"shared.statementTable.receiptDate" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.receiptDate" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="openk-no-whitespace-wrap statement-table--date">
@@ -143,12 +213,22 @@
     </td>
   </ng-container>
 
-  <ng-container cdkColumnDef="dueDate">
+  <ng-container *ngIf="'dueDate'; let label" cdkColumnDef="dueDate">
     <th *cdkHeaderCellDef="let statementHeader"
+        (click)="click(label, sorting[label])"
+        [class.cursor-pointer]="appIsSortable"
         cdk-header-cell
         class="statement-table--date"
         scope="col">
-      {{"shared.statementTable.dueDate" | translate}}
+      <div class="statement-table--header">
+        {{"shared.statementTable.dueDate" | translate}}
+        <mat-icon
+          *ngIf="sorting[label]"
+          [class.statement-table--header--icon---rotate]="sorting[label] ==='asc'"
+          class="statement-table--header--icon">
+          play_arrow
+        </mat-icon>
+      </div>
     </th>
     <td *cdkCellDef="let statement" cdk-cell
         class="openk-no-whitespace-wrap statement-table--date">
diff --git a/src/app/shared/layout/statement-table/components/statement-table.component.scss b/src/app/shared/layout/statement-table/components/statement-table.component.scss
index 9304f8d..50c12ba 100644
--- a/src/app/shared/layout/statement-table/components/statement-table.component.scss
+++ b/src/app/shared/layout/statement-table/components/statement-table.component.scss
@@ -73,7 +73,7 @@
 }
 
 .statement-table--id {
-  width: 1em;
+  width: 2em;
   text-align: right;
 }
 
@@ -132,3 +132,26 @@
 .statement-table--button {
   font-size: 0.7em;
 }
+
+.statement-table--header {
+  display: flex;
+  align-items: center;
+  line-height: 1;
+}
+
+.statement-table--header---right {
+  justify-content: flex-end;
+}
+
+.statement-table--header--icon {
+  width: initial;
+  height: initial;
+  font-size: 1em;
+  transform: rotate(90deg);
+  line-height: 1;
+  transition: transform 100ms ease-in-out;
+}
+
+.statement-table--header--icon---rotate {
+  transform: rotate(270deg);
+}
diff --git a/src/app/shared/layout/statement-table/components/statement-table.component.spec.ts b/src/app/shared/layout/statement-table/components/statement-table.component.spec.ts
index 8e675ec..d68eddd 100644
--- a/src/app/shared/layout/statement-table/components/statement-table.component.spec.ts
+++ b/src/app/shared/layout/statement-table/components/statement-table.component.spec.ts
@@ -54,4 +54,5 @@
         expect(component.trackBy(1919, {...{} as IStatementTableEntry})).not.toBeDefined();
         expect(component.trackBy(1919, {...{} as IStatementTableEntry, id: 19})).toBe(19);
     });
+
 });
diff --git a/src/app/shared/layout/statement-table/components/statement-table.component.ts b/src/app/shared/layout/statement-table/components/statement-table.component.ts
index c569bd4..5a89f2b 100644
--- a/src/app/shared/layout/statement-table/components/statement-table.component.ts
+++ b/src/app/shared/layout/statement-table/components/statement-table.component.ts
@@ -101,9 +101,17 @@
     @Input()
     public appTimeDisplayFormat: string = momentFormatDisplayNumeric;
 
+    @Input()
+    public appIsSortable: boolean;
+
+    @Output()
+    public appSort: EventEmitter<{ label: string, direction: "asc" | "desc" }> = new EventEmitter();
+
     @Output()
     public appSelect: EventEmitter<{ id: number, value: boolean }> = new EventEmitter();
 
+    public sorting: { [x: string]: "asc" | "desc" } = {};
+
     public trackBy(index: number, entry: IStatementTableEntry) {
         return entry?.id;
     }
@@ -116,4 +124,13 @@
         this.appSelect.emit({id, value: false});
     }
 
+    public click(label: string, direction: "asc" | "desc") {
+        if (this.appIsSortable) {
+            direction = direction == null ? "asc" : (direction === "asc" ? "desc" : "asc");
+            this.appSort.emit({label, direction});
+            this.sorting = {};
+            this.sorting[label] = direction;
+        }
+    }
+
 }
diff --git a/src/app/features/search/components/search/index.ts b/src/app/shared/leaflet/components/index.ts
similarity index 92%
copy from src/app/features/search/components/search/index.ts
copy to src/app/shared/leaflet/components/index.ts
index 5eb9c7f..9f971c2 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/shared/leaflet/components/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./leaflet-map.component";
diff --git a/src/app/shared/leaflet/components/leaflet-map.component.html b/src/app/shared/leaflet/components/leaflet-map.component.html
new file mode 100644
index 0000000..d71960e
--- /dev/null
+++ b/src/app/shared/leaflet/components/leaflet-map.component.html
@@ -0,0 +1,38 @@
+<!-------------------------------------------------------------------------------
+ * 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
+ -------------------------------------------------------------------------------->
+
+<div class="map">
+  <div #appLeaflet="appLeaflet"
+       (appClick)="appClick.emit($event)"
+       (appPopupClose)="appPopupClose.emit($event)"
+       (appLatLngZoomChange)="appCenterChange.emit($event)"
+       [appCenter]="appCenter | stringToLatLngZoom"
+       [appDisabled]="appDisabled"
+       appLeaflet
+       class="map--leaflet">
+
+    <ng-content></ng-content>
+
+  </div>
+
+  <app-action-button
+    (appClick)="appOpenGis.emit(appLeaflet.getBounds())"
+    [appIcon]="'my_location'"
+    class="map--button openk-info">
+    {{'shared.map.openGIS' | translate}}
+  </app-action-button>
+</div>
+
+<label *ngIf="appSubCaption" class="sub-caption">
+  {{appSubCaption}}
+</label>
diff --git a/src/app/shared/leaflet/components/leaflet-map.component.scss b/src/app/shared/leaflet/components/leaflet-map.component.scss
new file mode 100644
index 0000000..e8e1a36
--- /dev/null
+++ b/src/app/shared/leaflet/components/leaflet-map.component.scss
@@ -0,0 +1,53 @@
+/********************************************************************************
+ * 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 {
+  width: 100%;
+  height: 100%;
+
+  display: flex;
+  flex-flow: column;
+}
+
+.map {
+  height: 100%;
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+  box-sizing: border-box;
+  border: 1px solid $openk-form-border;
+}
+
+.map--leaflet {
+  width: 100%;
+  height: 100%;
+}
+
+.map--button {
+  display: block;
+  width: fit-content;
+  height: fit-content;
+  position: absolute;
+  bottom: 10px;
+  left: 10px;
+  z-index: 1000;
+}
+
+.sub-caption {
+  color: $openk-form-border;
+  margin-left: auto;
+  font-size: smaller;
+  font-style: italic;
+}
diff --git a/src/app/features/search/components/search/search.component.spec.ts b/src/app/shared/leaflet/components/leaflet-map.component.spec.ts
similarity index 69%
rename from src/app/features/search/components/search/search.component.spec.ts
rename to src/app/shared/leaflet/components/leaflet-map.component.spec.ts
index ec7b1b3..f839910 100644
--- a/src/app/features/search/components/search/search.component.spec.ts
+++ b/src/app/shared/leaflet/components/leaflet-map.component.spec.ts
@@ -12,20 +12,22 @@
  ********************************************************************************/
 
 import {async, ComponentFixture, TestBed} from "@angular/core/testing";
-import {SearchComponent} from "./search.component";
+import {I18nModule} from "../../../core/i18n";
+import {LeafletModule} from "../leaflet.module";
+import {LeafletMapComponent} from "./leaflet-map.component";
 
-describe("SearchComponent", () => {
-    let component: SearchComponent;
-    let fixture: ComponentFixture<SearchComponent>;
+describe("LeafletMapComponent", () => {
+    let component: LeafletMapComponent;
+    let fixture: ComponentFixture<LeafletMapComponent>;
 
     beforeEach(async(() => {
         TestBed.configureTestingModule({
-            declarations: [SearchComponent]
+            imports: [LeafletModule, I18nModule]
         }).compileComponents();
     }));
 
     beforeEach(() => {
-        fixture = TestBed.createComponent(SearchComponent);
+        fixture = TestBed.createComponent(LeafletMapComponent);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
diff --git a/src/app/shared/leaflet/components/leaflet-map.component.ts b/src/app/shared/leaflet/components/leaflet-map.component.ts
new file mode 100644
index 0000000..53e8e48
--- /dev/null
+++ b/src/app/shared/leaflet/components/leaflet-map.component.ts
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * 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, EventEmitter, forwardRef, Input, NgZone, Output, ViewChild} from "@angular/core";
+import {LeafletMouseEvent, PopupEvent} from "leaflet";
+import {ILeafletBounds, LeafletDirective, LeafletHandler} from "../directives";
+
+@Component({
+    selector: "app-leaflet-map",
+    templateUrl: "./leaflet-map.component.html",
+    styleUrls: ["./leaflet-map.component.scss"],
+    providers: [
+        {
+            provide: LeafletHandler,
+            useExisting: forwardRef(() => LeafletMapComponent)
+        }
+    ]
+})
+export class LeafletMapComponent extends LeafletHandler {
+
+    @Input()
+    public appDisabled: boolean;
+
+    @Input()
+    public appCenter: string;
+
+    @Output()
+    public appClick = new EventEmitter<LeafletMouseEvent>();
+
+    @Output()
+    public appPopupClose = new EventEmitter<PopupEvent>();
+
+    @Output()
+    public appCenterChange = new EventEmitter<string>();
+
+    @Input()
+    public appSubCaption: string;
+
+    @Output()
+    public appOpenGis = new EventEmitter<ILeafletBounds>();
+
+    @ViewChild(LeafletDirective, {static: true})
+    public leafletDirective: LeafletDirective;
+
+    public constructor(public readonly ngZone: NgZone) {
+        super();
+    }
+
+    public get instance() {
+        return this.leafletDirective.instance;
+    }
+
+}
diff --git a/src/app/shared/layout/leaflet/directives/center-marker/index.ts b/src/app/shared/leaflet/directives/center-marker/index.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/directives/center-marker/index.ts
rename to src/app/shared/leaflet/directives/center-marker/index.ts
diff --git a/src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts b/src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts
similarity index 96%
rename from src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts
rename to src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts
index 1da4d1b..6922af1 100644
--- a/src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts
+++ b/src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.spec.ts
@@ -47,7 +47,7 @@
         const center = new LatLng(latLng.lat, latLng.lng);
         const move$ = new Subject<any>();
         const setLatLngSpy = spyOn(directive.marker, "setLatLng").and.callThrough();
-        spyOn(directive.leafletDirective.leaflet, "getCenter").and.returnValue(center);
+        spyOn(directive.leafletHandler.instance, "getCenter").and.returnValue(center);
         spyOn(directive, "on").and.returnValue(move$.asObservable());
         directive.ngOnInit();
         move$.next();
diff --git a/src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.ts b/src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.ts
similarity index 80%
rename from src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.ts
rename to src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.ts
index 9fa22aa..9db8965 100644
--- a/src/app/shared/layout/leaflet/directives/center-marker/leaflet-center-marker.directive.ts
+++ b/src/app/shared/leaflet/directives/center-marker/leaflet-center-marker.directive.ts
@@ -14,9 +14,9 @@
 import {Directive, Inject, NgZone, OnDestroy, OnInit} from "@angular/core";
 import {merge, of, Subject} from "rxjs";
 import {takeUntil} from "rxjs/operators";
-import {runOutsideZone} from "../../../../../util/rxjs";
+import {runOutsideZone} from "../../../../util/rxjs";
 import {ILeafletConfiguration, LEAFLET_CONFIGURATION_TOKEN} from "../../leaflet-configuration.token";
-import {LeafletDirective} from "../leaflet";
+import {LeafletHandler} from "../leaflet";
 import {AbstractLeafletMarkerDirective} from "../marker/abstract-leaflet-marker.directive";
 
 @Directive({
@@ -29,16 +29,16 @@
 
     public constructor(
         ngZone: NgZone,
-        leafletDirective: LeafletDirective,
+        leafletHandler: LeafletHandler,
         @Inject(LEAFLET_CONFIGURATION_TOKEN) configuration: ILeafletConfiguration,
     ) {
-        super(ngZone, leafletDirective, configuration);
+        super(ngZone, leafletHandler, configuration);
     }
 
-    public ngOnInit() {
-        merge(of(null), this.leafletDirective.on("move", true))
+    public async ngOnInit() {
+        merge(of(null), this.leafletHandler.on("move", true))
             .pipe(takeUntil(this.destroy$), runOutsideZone(this.ngZone))
-            .subscribe(() => this.setLatLng(this.leafletDirective.leaflet.getCenter()));
+            .subscribe(() => this.setLatLng(this.leafletHandler.instance.getCenter()));
     }
 
     public ngOnDestroy() {
diff --git a/src/app/shared/layout/leaflet/directives/index.ts b/src/app/shared/leaflet/directives/index.ts
similarity index 96%
rename from src/app/shared/layout/leaflet/directives/index.ts
rename to src/app/shared/leaflet/directives/index.ts
index 34d7752..d2be228 100644
--- a/src/app/shared/layout/leaflet/directives/index.ts
+++ b/src/app/shared/leaflet/directives/index.ts
@@ -14,3 +14,4 @@
 export * from "./center-marker";
 export * from "./leaflet";
 export * from "./marker";
+export * from "./popup";
diff --git a/src/app/shared/leaflet/directives/leaflet/LeafletHandler.ts b/src/app/shared/leaflet/directives/leaflet/LeafletHandler.ts
new file mode 100644
index 0000000..3b55f0e
--- /dev/null
+++ b/src/app/shared/leaflet/directives/leaflet/LeafletHandler.ts
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * 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 {NgZone} from "@angular/core";
+import {LeafletEvent, Map} from "leaflet";
+import {Observable, of, pipe} from "rxjs";
+import {switchMap} from "rxjs/operators";
+import {runInZone, runOutsideZone} from "../../../../util/rxjs";
+import {fromLeafletEvent} from "../../util";
+
+export abstract class LeafletHandler {
+
+    public abstract readonly instance: Map;
+
+    public abstract readonly ngZone: NgZone;
+
+    public on<T extends LeafletEvent>(type: string, outsideZone?: boolean): Observable<T> {
+        return of(type).pipe(
+            runOutsideZone(this.ngZone),
+            switchMap((_) => fromLeafletEvent<T>(this.instance, type)),
+            outsideZone ? pipe() : runInZone(this.ngZone)
+        );
+    }
+
+}
diff --git a/src/app/shared/layout/leaflet/directives/leaflet/index.ts b/src/app/shared/leaflet/directives/leaflet/index.ts
similarity index 94%
rename from src/app/shared/layout/leaflet/directives/leaflet/index.ts
rename to src/app/shared/leaflet/directives/leaflet/index.ts
index 6ecc261..d6c1b2f 100644
--- a/src/app/shared/layout/leaflet/directives/leaflet/index.ts
+++ b/src/app/shared/leaflet/directives/leaflet/index.ts
@@ -12,3 +12,4 @@
  ********************************************************************************/
 
 export * from "./leaflet.directive";
+export * from "./LeafletHandler";
diff --git a/src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.spec.ts b/src/app/shared/leaflet/directives/leaflet/leaflet.directive.spec.ts
similarity index 72%
rename from src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.spec.ts
rename to src/app/shared/leaflet/directives/leaflet/leaflet.directive.spec.ts
index 3e85b17..ddf71fc 100644
--- a/src/app/shared/layout/leaflet/directives/leaflet/leaflet.directive.spec.ts
+++ b/src/app/shared/leaflet/directives/leaflet/leaflet.directive.spec.ts
@@ -45,18 +45,37 @@
         directive = component.directive;
     });
 
-    it("should", () => {
+    it("should set center and zoom", () => {
         const latLngZoom: LatLngLiteral & { zoom: number } = {
             lat: 52.520008,
             lng: 13.404954,
             zoom: 13
         };
 
-        directive.appView = null;
-        directive.appView = latLngZoom;
-        expect(directive.leaflet.getCenter().lat).toBe(latLngZoom.lat);
-        expect(directive.leaflet.getCenter().lng).toBe(latLngZoom.lng);
-        expect(directive.leaflet.getZoom()).toBe(latLngZoom.zoom);
+        directive.appCenter = null;
+        directive.appCenter = latLngZoom;
+        expect(directive.instance.getCenter().lat).toBe(latLngZoom.lat);
+        expect(directive.instance.getCenter().lng).toBe(latLngZoom.lng);
+        expect(directive.instance.getZoom()).toBe(latLngZoom.zoom);
+    });
+
+    it("should disable/enable all leaflet controls", () => {
+        const handlers = [
+            directive.instance.dragging,
+            directive.instance.touchZoom,
+            directive.instance.doubleClickZoom,
+            directive.instance.scrollWheelZoom,
+            directive.instance.boxZoom,
+            directive.instance.keyboard
+        ];
+        handlers.forEach((handler) => spyOn(handler, "disable"));
+        handlers.forEach((handler) => spyOn(handler, "enable"));
+
+        directive.appDisabled = true;
+        handlers.forEach((handler) => expect(handler.disable).toHaveBeenCalled());
+
+        directive.appDisabled = false;
+        handlers.forEach((handler) => expect(handler.enable).toHaveBeenCalled());
     });
 
     it("should invalidate size on resize", () => {
@@ -85,12 +104,19 @@
 
         onSpy.calls.reset();
         subscription = directive.appLatLngZoomChange.subscribe();
-        expect(onSpy).toHaveBeenCalledWith("move zoom", true);
+        expect(onSpy).toHaveBeenCalledWith("moveend zoomend", true);
         event$.next();
         tick(10);
         subscription.unsubscribe();
 
         onSpy.calls.reset();
+        subscription = directive.appPopupClose.subscribe();
+        expect(onSpy).toHaveBeenCalledWith("popupclose");
+        event$.next();
+        tick(0);
+        subscription.unsubscribe();
+
+        onSpy.calls.reset();
         subscription = directive.appClick.subscribe();
         expect(onSpy).toHaveBeenCalledWith("click");
         subscription.unsubscribe();
diff --git a/src/app/shared/leaflet/directives/leaflet/leaflet.directive.ts b/src/app/shared/leaflet/directives/leaflet/leaflet.directive.ts
new file mode 100644
index 0000000..bbcc73d
--- /dev/null
+++ b/src/app/shared/leaflet/directives/leaflet/leaflet.directive.ts
@@ -0,0 +1,135 @@
+/********************************************************************************
+ * 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 {AfterViewInit, Directive, ElementRef, forwardRef, Inject, Input, NgZone, OnDestroy, OnInit, Optional, Output} from "@angular/core";
+import {InvalidateSizeOptions, LatLngLiteral, LeafletMouseEvent, Map, PopupEvent, TileLayer} from "leaflet";
+import {defer, Observable} from "rxjs";
+import {debounceTime, delay, map, takeUntil, throttleTime} from "rxjs/operators";
+import {runInZone} from "../../../../util/rxjs";
+import {ILeafletConfiguration, LEAFLET_CONFIGURATION_TOKEN, LEAFLET_RESIZE_TOKEN} from "../../leaflet-configuration.token";
+import {latLngZoomToString} from "../../util";
+import {LeafletHandler} from "./LeafletHandler";
+
+export interface ILeafletBounds {
+    northWest: LatLngLiteral;
+    northEast: LatLngLiteral;
+    southEast: LatLngLiteral;
+    southWest: LatLngLiteral;
+    center: LatLngLiteral;
+    zoom: number;
+}
+
+@Directive({
+    selector: "[appLeaflet]",
+    exportAs: "appLeaflet",
+    providers: [
+        {
+            provide: LeafletHandler,
+            useExisting: forwardRef(() => LeafletDirective)
+        }
+    ]
+})
+export class LeafletDirective extends LeafletHandler implements OnInit, OnDestroy, AfterViewInit {
+
+    public readonly instance: Map;
+
+    @Output()
+    public appClick = defer(() => this.on<LeafletMouseEvent>("click"));
+
+    @Output()
+    public appPopupClose = defer(() => this.on<PopupEvent>("popupclose")).pipe(delay(0));
+
+    @Output()
+    public appUnload$ = defer(() => this.on("unload"));
+
+    @Output()
+    public appLatLngZoomChange = defer(() => this.on("moveend zoomend", true)).pipe(
+        debounceTime(10),
+        map(() => latLngZoomToString(this.instance.getCenter(), this.instance.getZoom())),
+        runInZone(this.ngZone)
+    );
+
+    public constructor(
+        public readonly elementRef: ElementRef<HTMLElement>,
+        public readonly ngZone: NgZone,
+        @Inject(LEAFLET_CONFIGURATION_TOKEN) public readonly configuration: ILeafletConfiguration,
+        @Optional() @Inject(LEAFLET_RESIZE_TOKEN) public resize$: Observable<any>
+    ) {
+        super();
+        this.instance = this.ngZone.runOutsideAngular(() => {
+            const tileLayer = new TileLayer(this.configuration.urlTemplate, {
+                attribution: this.configuration.attribution
+            });
+            const result = new Map(this.elementRef.nativeElement, {layers: [tileLayer]});
+            result.setView({lat: configuration.lat, lng: configuration.lng}, configuration.zoom);
+            return result;
+        });
+    }
+
+    @Input()
+    public set appCenter(value: { lat: number, lng: number, zoom: number }) {
+        if (value != null) {
+            this.ngZone.runOutsideAngular(() => this.instance.setView(value, value.zoom));
+        }
+    }
+
+    @Input()
+    public set appDisabled(value: boolean) {
+        const handlers = [
+            this.instance.dragging,
+            this.instance.touchZoom,
+            this.instance.doubleClickZoom,
+            this.instance.scrollWheelZoom,
+            this.instance.boxZoom,
+            this.instance.keyboard
+        ];
+        handlers.forEach((handler) => value ? handler.disable() : handler.enable());
+        value ? this.instance.removeControl(this.instance.zoomControl) : this.instance.addControl(this.instance.zoomControl);
+    }
+
+    public ngOnInit() {
+        if (this.resize$ instanceof Observable) {
+            this.resize$.pipe(throttleTime(10), takeUntil(this.appUnload$))
+                .subscribe((_) => this.invalidateSize());
+        }
+    }
+
+    public ngAfterViewInit() {
+        setTimeout(() => this.invalidateSize());
+    }
+
+    public ngOnDestroy() {
+        this.ngZone.runOutsideAngular(() => this.instance.remove());
+    }
+
+    public getBounds(): ILeafletBounds {
+        return this.ngZone.runOutsideAngular(() => {
+            const bounds = this.instance.getBounds();
+            const zoom = this.instance.getZoom();
+            const result: ILeafletBounds = {
+                northWest: bounds.getNorthWest(),
+                northEast: bounds.getNorthEast(),
+                southEast: bounds.getSouthEast(),
+                southWest: bounds.getSouthWest(),
+                center: bounds.getCenter(),
+                zoom
+            };
+            return this.ngZone.run(() => result);
+        });
+    }
+
+    public invalidateSize(options?: boolean | InvalidateSizeOptions) {
+        this.ngZone.runOutsideAngular(() => this.instance.invalidateSize(options));
+    }
+
+}
diff --git a/src/app/shared/layout/leaflet/directives/marker/abstract-leaflet-marker.directive.ts b/src/app/shared/leaflet/directives/marker/abstract-leaflet-marker.directive.ts
similarity index 87%
rename from src/app/shared/layout/leaflet/directives/marker/abstract-leaflet-marker.directive.ts
rename to src/app/shared/leaflet/directives/marker/abstract-leaflet-marker.directive.ts
index e51a197..b2ed655 100644
--- a/src/app/shared/layout/leaflet/directives/marker/abstract-leaflet-marker.directive.ts
+++ b/src/app/shared/leaflet/directives/marker/abstract-leaflet-marker.directive.ts
@@ -15,10 +15,10 @@
 import {DivIcon, LatLngLiteral, LeafletEvent, LeafletMouseEvent, Marker} from "leaflet";
 import {defer, Observable, of, pipe} from "rxjs";
 import {switchMap} from "rxjs/operators";
-import {runInZone, runOutsideZone} from "../../../../../util/rxjs";
+import {runInZone, runOutsideZone} from "../../../../util/rxjs";
 import {ILeafletConfiguration, LEAFLET_CONFIGURATION_TOKEN} from "../../leaflet-configuration.token";
 import {fromLeafletEvent} from "../../util";
-import {LeafletDirective} from "../leaflet";
+import {LeafletHandler} from "../leaflet";
 
 
 @Directive({})
@@ -33,7 +33,7 @@
 
     public constructor(
         public readonly ngZone: NgZone,
-        public readonly leafletDirective: LeafletDirective,
+        public readonly leafletHandler: LeafletHandler,
         @Inject(LEAFLET_CONFIGURATION_TOKEN) public readonly configuration: ILeafletConfiguration,
     ) {
 
@@ -53,9 +53,9 @@
 
     protected setLatLng(value?: LatLngLiteral): boolean {
         return this.ngZone.runOutsideAngular(() => {
-            if (Number.isFinite(value?.lat) && Number.isFinite(value?.lng)) {
+            if (value != null && Number.isFinite(value.lat) && Number.isFinite(value.lng)) {
                 this.marker.setLatLng(value);
-                this.marker.addTo(this.leafletDirective.leaflet);
+                this.marker.addTo(this.leafletHandler.instance);
                 return true;
             }
             return false;
diff --git a/src/app/shared/layout/leaflet/directives/marker/index.ts b/src/app/shared/leaflet/directives/marker/index.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/directives/marker/index.ts
rename to src/app/shared/leaflet/directives/marker/index.ts
diff --git a/src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.spec.ts b/src/app/shared/leaflet/directives/marker/leaflet-marker.directive.spec.ts
similarity index 94%
rename from src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.spec.ts
rename to src/app/shared/leaflet/directives/marker/leaflet-marker.directive.spec.ts
index c5b474c..24f654f 100644
--- a/src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.spec.ts
+++ b/src/app/shared/leaflet/directives/marker/leaflet-marker.directive.spec.ts
@@ -50,6 +50,10 @@
         expect(directive.marker.getLatLng().lat).toEqual(latLng.lat);
         expect(directive.marker.getLatLng().lng).toEqual(latLng.lng);
 
+        directive.appLeafletMarker = "1,2,12";
+        expect(directive.marker.getLatLng().lat).toEqual(1);
+        expect(directive.marker.getLatLng().lng).toEqual(2);
+
         directive.appLeafletMarker = {lat: 1, lng: null};
         expect(removeSpy).toHaveBeenCalled();
         directive.appLeafletMarker = {lat: null, lng: 2};
diff --git a/src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.ts b/src/app/shared/leaflet/directives/marker/leaflet-marker.directive.ts
similarity index 78%
rename from src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.ts
rename to src/app/shared/leaflet/directives/marker/leaflet-marker.directive.ts
index 9ea0814..8b40418 100644
--- a/src/app/shared/layout/leaflet/directives/marker/leaflet-marker.directive.ts
+++ b/src/app/shared/leaflet/directives/marker/leaflet-marker.directive.ts
@@ -14,7 +14,8 @@
 import {Directive, Inject, Input, NgZone} from "@angular/core";
 import {LatLngLiteral} from "leaflet";
 import {ILeafletConfiguration, LEAFLET_CONFIGURATION_TOKEN} from "../../leaflet-configuration.token";
-import {LeafletDirective} from "../leaflet";
+import {stringToLatLngZoom} from "../../util";
+import {LeafletHandler} from "../leaflet";
 import {AbstractLeafletMarkerDirective} from "./abstract-leaflet-marker.directive";
 
 @Directive({
@@ -25,15 +26,15 @@
 
     public constructor(
         ngZone: NgZone,
-        leafletDirective: LeafletDirective,
+        leafletHandler: LeafletHandler,
         @Inject(LEAFLET_CONFIGURATION_TOKEN) configuration: ILeafletConfiguration,
     ) {
-        super(ngZone, leafletDirective, configuration);
+        super(ngZone, leafletHandler, configuration);
     }
 
     @Input()
-    public set appLeafletMarker(value: LatLngLiteral) {
-        const isSet = this.setLatLng(value);
+    public set appLeafletMarker(value: LatLngLiteral | string) {
+        const isSet = this.setLatLng(typeof value === "string" ? stringToLatLngZoom(value) : value);
         if (!isSet) {
             this.remove();
         }
diff --git a/src/app/features/search/components/search/index.ts b/src/app/shared/leaflet/directives/popup/index.ts
similarity index 92%
copy from src/app/features/search/components/search/index.ts
copy to src/app/shared/leaflet/directives/popup/index.ts
index 5eb9c7f..09e6c2a 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/shared/leaflet/directives/popup/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./leaflet-popup.directive";
diff --git a/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.spec.ts b/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.spec.ts
new file mode 100644
index 0000000..fc8d984
--- /dev/null
+++ b/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.spec.ts
@@ -0,0 +1,109 @@
+/********************************************************************************
+ * 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
+ ********************************************************************************/
+
+/********************************************************************************
+ * 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, ViewChild} from "@angular/core";
+import {async, ComponentFixture, TestBed} from "@angular/core/testing";
+import {LeafletModule} from "../../leaflet.module";
+import {LeafletPopupDirective} from "./leaflet-popup.directive";
+
+describe("LeafletPopupDirective", () => {
+
+    const latLngZoom = "49.87774673189807,8.651438355445864,17";
+
+    let component: LeafletPopupSpecComponent;
+    let fixture: ComponentFixture<LeafletPopupSpecComponent>;
+    let directive: LeafletPopupDirective;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [LeafletModule],
+            declarations: [LeafletPopupSpecComponent]
+        }).compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(LeafletPopupSpecComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+        directive = component.directive;
+    });
+
+    it("should create", () => {
+        expect(directive).toBeDefined();
+    });
+
+    it("should open/close popup on input", () => {
+        const openOnSpy = spyOn(directive.popup, "openOn");
+        const removeFromSpy = spyOn(directive.popup, "removeFrom");
+
+        openOnSpy.calls.reset();
+        removeFromSpy.calls.reset();
+        directive.appLeafletPopup = latLngZoom;
+        fixture.detectChanges();
+        expect(openOnSpy).toHaveBeenCalledWith(directive.leafletHandler.instance);
+        expect(removeFromSpy).not.toHaveBeenCalled();
+
+        openOnSpy.calls.reset();
+        removeFromSpy.calls.reset();
+        directive.appLeafletPopup = null;
+        fixture.detectChanges();
+        expect(removeFromSpy).toHaveBeenCalledWith(directive.leafletHandler.instance);
+        expect(openOnSpy).not.toHaveBeenCalled();
+    });
+
+    it("should update popup on data changes", () => {
+        const updateViewSpy = spyOn(directive, "updateView");
+        updateViewSpy.calls.reset();
+        component.data = {id: 19};
+        fixture.detectChanges();
+        expect(updateViewSpy).toHaveBeenCalled();
+
+        updateViewSpy.calls.reset();
+        component.coordinates = latLngZoom;
+        fixture.detectChanges();
+        expect(updateViewSpy).not.toHaveBeenCalled();
+    });
+
+});
+
+@Component({
+    selector: "app-leaflet-popup-spec",
+    template: `
+        <div appLeaflet>
+            <div *appLeafletPopup="coordinates; data: data"></div>
+        </div>
+    `
+})
+class LeafletPopupSpecComponent {
+
+    public coordinates: string;
+
+    public data: any = {};
+
+    @ViewChild(LeafletPopupDirective, {static: true})
+    public directive: LeafletPopupDirective;
+
+}
diff --git a/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.ts b/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.ts
new file mode 100644
index 0000000..e02030c
--- /dev/null
+++ b/src/app/shared/leaflet/directives/popup/leaflet-popup.directive.ts
@@ -0,0 +1,97 @@
+/********************************************************************************
+ * 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 {Directive, EmbeddedViewRef, Input, NgZone, OnChanges, OnDestroy, SimpleChanges, TemplateRef} from "@angular/core";
+import {LatLngExpression, Popup} from "leaflet";
+import {stringToLatLngZoom} from "../../util";
+import {LeafletHandler} from "../leaflet";
+
+/**
+ * This structural directive renders an Angular template as a popup in a leaflet map instance.
+ * Since leaflet is running outside Angular's zone, change detection must be either triggered manually via the updateView method or
+ * by providing an input for appLeafletPopupData which is then tracked by Angular itself.
+ *
+ * The popup is only rendered if proper coordinates are provided via the input appLeafletPopup.
+ */
+@Directive({selector: "[appLeafletPopup]"})
+export class LeafletPopupDirective implements OnChanges, OnDestroy {
+
+    /**
+     * Data object which is tracked by Angular and updates the view.
+     */
+    @Input()
+    public appLeafletPopupData: any;
+
+    public readonly embeddedViewRef: EmbeddedViewRef<any>;
+
+    public readonly popup: Popup = new Popup({closeOnClick: false, offset: [0.25, -11]});
+
+    public constructor(
+        public readonly templateRef: TemplateRef<any>,
+        public readonly ngZone: NgZone,
+        public readonly leafletHandler: LeafletHandler
+    ) {
+        this.embeddedViewRef = this.templateRef.createEmbeddedView({});
+        this.embeddedViewRef.detectChanges();
+        const content = this.embeddedViewRef.rootNodes[0];
+        this.ngZone.run(() => this.popup.setContent(content));
+    }
+
+    /**
+     * If proper coordinates are provided, the leaflet popup instance is opened and set to the given coordinates.
+     * Otherwise, the popup is removed from the map.
+     */
+    @Input()
+    public set appLeafletPopup(latLngZoom: string) {
+        const position = stringToLatLngZoom(latLngZoom);
+        if (position == null) {
+            this.close();
+        } else {
+            this.setLatLng(position);
+            this.open();
+        }
+    }
+
+    public ngOnDestroy() {
+        this.close();
+        this.embeddedViewRef.destroy();
+    }
+
+    public ngOnChanges(changes: SimpleChanges) {
+        const updateOn: Array<keyof LeafletPopupDirective> = ["appLeafletPopupData"];
+        if (updateOn.some((key) => changes[key] != null)) {
+            this.updateView();
+        }
+    }
+
+    /**
+     * Triggers the change detection for the embedded view provided by the template ref and updates also the leaflet popup instance.
+     */
+    public updateView() {
+        this.embeddedViewRef.detectChanges();
+        this.ngZone.runOutsideAngular(() => this.popup.update());
+    }
+
+    public close() {
+        this.ngZone.runOutsideAngular(() => this.popup.removeFrom(this.leafletHandler.instance));
+    }
+
+    public open() {
+        this.ngZone.runOutsideAngular(() => this.popup.openOn(this.leafletHandler.instance));
+    }
+
+    public setLatLng(latLng: LatLngExpression) {
+        this.ngZone.runOutsideAngular(() => this.popup.setLatLng(latLng));
+    }
+
+}
diff --git a/src/app/shared/layout/leaflet/index.ts b/src/app/shared/leaflet/index.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/index.ts
rename to src/app/shared/leaflet/index.ts
diff --git a/src/app/shared/layout/leaflet/leaflet-configuration.token.ts b/src/app/shared/leaflet/leaflet-configuration.token.ts
similarity index 70%
rename from src/app/shared/layout/leaflet/leaflet-configuration.token.ts
rename to src/app/shared/leaflet/leaflet-configuration.token.ts
index ea60f4b..0ef5cd1 100644
--- a/src/app/shared/layout/leaflet/leaflet-configuration.token.ts
+++ b/src/app/shared/leaflet/leaflet-configuration.token.ts
@@ -13,27 +13,10 @@
 
 import {InjectionToken} from "@angular/core";
 import {Observable} from "rxjs";
-import {environment} from "../../../../environments/environment";
+import {IAppConfiguration} from "../../core";
 
-export interface ILeafletConfiguration {
-
-    urlTemplate: string;
-
-    attribution?: string;
-
-    gis: string;
-
-    lat: number;
-
-    lng: number;
-
-    zoom: number;
-
-}
+export type ILeafletConfiguration = IAppConfiguration["leaflet"];
 
 export const LEAFLET_RESIZE_TOKEN = new InjectionToken<Observable<any>>("Leaflet resize observable");
 
-export const LEAFLET_CONFIGURATION_TOKEN = new InjectionToken<ILeafletConfiguration>("Leaflet configuration", {
-    providedIn: "root",
-    factory: () => environment.leaflet
-});
+export const LEAFLET_CONFIGURATION_TOKEN = new InjectionToken<ILeafletConfiguration>("Leaflet configuration");
diff --git a/src/app/shared/leaflet/leaflet.module.ts b/src/app/shared/leaflet/leaflet.module.ts
new file mode 100644
index 0000000..5625400
--- /dev/null
+++ b/src/app/shared/leaflet/leaflet.module.ts
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * 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 {CommonModule} from "@angular/common";
+import {NgModule} from "@angular/core";
+import {TranslateModule} from "@ngx-translate/core";
+import {APP_CONFIGURATION, IAppConfiguration} from "../../core/configuration";
+import {ActionButtonModule} from "../layout/action-button";
+import {SideMenuRegistrationService} from "../layout/side-menu/services";
+import {LeafletMapComponent} from "./components";
+import {LeafletCenterMarkerDirective, LeafletDirective, LeafletMarkerDirective, LeafletPopupDirective} from "./directives";
+import {LEAFLET_CONFIGURATION_TOKEN, LEAFLET_RESIZE_TOKEN} from "./leaflet-configuration.token";
+import {StringToLatLngZoomPipe} from "./pipes";
+
+@NgModule({
+    imports: [
+        CommonModule,
+        ActionButtonModule,
+        TranslateModule
+    ],
+    declarations: [
+        LeafletCenterMarkerDirective,
+        LeafletDirective,
+        LeafletMarkerDirective,
+        LeafletPopupDirective,
+        LeafletMapComponent,
+        StringToLatLngZoomPipe
+    ],
+    exports: [
+        LeafletCenterMarkerDirective,
+        LeafletDirective,
+        LeafletMarkerDirective,
+        LeafletPopupDirective,
+        LeafletMapComponent,
+        StringToLatLngZoomPipe
+    ],
+    providers: [
+        {
+            provide: LEAFLET_CONFIGURATION_TOKEN,
+            useFactory: (config: IAppConfiguration) => config.leaflet,
+            deps: [APP_CONFIGURATION]
+        },
+        {
+            provide: LEAFLET_RESIZE_TOKEN,
+            useFactory: (service: SideMenuRegistrationService) => service.resize$,
+            deps: [SideMenuRegistrationService]
+        }
+    ]
+})
+export class LeafletModule {
+
+}
diff --git a/src/app/shared/layout/leaflet/pipes/index.ts b/src/app/shared/leaflet/pipes/index.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/pipes/index.ts
rename to src/app/shared/leaflet/pipes/index.ts
diff --git a/src/app/shared/layout/leaflet/pipes/string-to-lat-lng-zoom.pipe.spec.ts b/src/app/shared/leaflet/pipes/string-to-lat-lng-zoom.pipe.spec.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/pipes/string-to-lat-lng-zoom.pipe.spec.ts
rename to src/app/shared/leaflet/pipes/string-to-lat-lng-zoom.pipe.spec.ts
diff --git a/src/app/shared/layout/leaflet/pipes/string-to-lat-lng-zoom.pipe.ts b/src/app/shared/leaflet/pipes/string-to-lat-lng-zoom.pipe.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/pipes/string-to-lat-lng-zoom.pipe.ts
rename to src/app/shared/leaflet/pipes/string-to-lat-lng-zoom.pipe.ts
diff --git a/src/app/shared/layout/leaflet/util/index.ts b/src/app/shared/leaflet/util/index.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/util/index.ts
rename to src/app/shared/leaflet/util/index.ts
diff --git a/src/app/shared/layout/leaflet/util/leaflet.util.spec.ts b/src/app/shared/leaflet/util/leaflet.util.spec.ts
similarity index 100%
rename from src/app/shared/layout/leaflet/util/leaflet.util.spec.ts
rename to src/app/shared/leaflet/util/leaflet.util.spec.ts
diff --git a/src/app/shared/layout/leaflet/util/leaflet.util.ts b/src/app/shared/leaflet/util/leaflet.util.ts
similarity index 79%
rename from src/app/shared/layout/leaflet/util/leaflet.util.ts
rename to src/app/shared/leaflet/util/leaflet.util.ts
index 2df3ef7..eff0886 100644
--- a/src/app/shared/layout/leaflet/util/leaflet.util.ts
+++ b/src/app/shared/leaflet/util/leaflet.util.ts
@@ -12,23 +12,19 @@
  ********************************************************************************/
 
 import {Evented, LatLngLiteral, LeafletEvent} from "leaflet";
-import {Observable} from "rxjs";
+import {EMPTY, fromEventPattern, Observable} from "rxjs";
+import {NodeEventHandler} from "rxjs/internal/observable/fromEvent";
 
 /**
  * Creates an observable for specific leaflet map events.
  */
 export function fromLeafletEvent<T extends LeafletEvent>(leafletMap: Evented, type: string): Observable<T> {
-    return new Observable<T>((subscriber) => {
-        if (leafletMap == null) {
-            subscriber.complete();
-            return;
-        }
-        const next = (e) => subscriber.next(e);
-        leafletMap.on(type, next);
-        subscriber.add(() => {
-            leafletMap.off(type, next);
-        });
-    });
+    if (leafletMap == null) {
+        return EMPTY;
+    }
+    const addHandler = (handler: NodeEventHandler) => leafletMap.on(type, handler);
+    const removeHandler = (handler: NodeEventHandler) => leafletMap.off(type, handler);
+    return fromEventPattern<T>(addHandler, removeHandler);
 }
 
 /**
diff --git a/src/app/shared/linked-statements/index.ts b/src/app/shared/linked-statements/index.ts
deleted file mode 100644
index ef4c339..0000000
--- a/src/app/shared/linked-statements/index.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/********************************************************************************
- * 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
- ********************************************************************************/
-
-export * from "./linked-statements.module";
diff --git a/src/app/shared/linked-statements/linked-statements.module.ts b/src/app/shared/linked-statements/linked-statements.module.ts
deleted file mode 100644
index 3869a3f..0000000
--- a/src/app/shared/linked-statements/linked-statements.module.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/********************************************************************************
- * 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 {CommonModule} from "@angular/common";
-import {NgModule} from "@angular/core";
-import {MatIconModule} from "@angular/material/icon";
-import {TranslateModule} from "@ngx-translate/core";
-import {SearchbarModule} from "../layout/searchbar";
-import {StatementTableModule} from "../layout/statement-table";
-import {LinkedStatementsComponent} from "./linked-statements";
-
-@NgModule({
-    imports: [
-        CommonModule,
-        MatIconModule,
-        TranslateModule,
-        StatementTableModule,
-        SearchbarModule
-    ],
-    declarations: [
-        LinkedStatementsComponent,
-    ],
-    exports: [
-        LinkedStatementsComponent
-    ]
-})
-export class LinkedStatementsModule {
-
-}
diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts
index 013dafb..cc16b58 100644
--- a/src/app/store/app-store.module.ts
+++ b/src/app/store/app-store.module.ts
@@ -17,6 +17,7 @@
 import {ToastModule} from "primeng/toast";
 import {AttachmentsStoreModule} from "./attachments";
 import {ContactsStoreModule} from "./contacts";
+import {GeoStoreModule} from "./geo";
 import {MailStoreModule} from "./mail";
 import {ProcessStoreModule} from "./process";
 import {RootStoreModule} from "./root";
@@ -25,20 +26,20 @@
 
 @NgModule({
     imports: [
-        AttachmentsStoreModule,
         RootStoreModule,
-        SettingsStoreModule,
-        ProcessStoreModule,
-        StatementsStoreModule,
+        AttachmentsStoreModule,
         ContactsStoreModule,
+        GeoStoreModule,
+        MailStoreModule,
+        ProcessStoreModule,
+        SettingsStoreModule,
+        StatementsStoreModule,
+
         ToastModule,
-        ButtonModule,
-        MailStoreModule
+        ButtonModule
     ],
     providers: [
-        MessageService,
-        ContactsStoreModule,
-        MailStoreModule
+        MessageService
     ]
 })
 export class AppStoreModule {
diff --git a/src/app/store/attachments/attachments-store.module.ts b/src/app/store/attachments/attachments-store.module.ts
index 895c2f9..8b95c07 100644
--- a/src/app/store/attachments/attachments-store.module.ts
+++ b/src/app/store/attachments/attachments-store.module.ts
@@ -17,6 +17,7 @@
 import {ATTACHMENTS_NAME, ATTACHMENTS_REDUCER} from "./attachments-reducers.token";
 import {FetchAttachmentsEffect, SubmitAttachmentsEffect} from "./effects";
 import {AttachmentDownloadEffect} from "./effects/download";
+import {SubmitConsiderationsEffect} from "./effects/submit/submit-considerations.effect";
 
 @NgModule({
     imports: [
@@ -24,7 +25,8 @@
         EffectsModule.forFeature([
             AttachmentDownloadEffect,
             FetchAttachmentsEffect,
-            SubmitAttachmentsEffect
+            SubmitAttachmentsEffect,
+            SubmitConsiderationsEffect
         ])
     ]
 })
diff --git a/src/app/store/attachments/effects/submit/submit-considerations.effect.ts b/src/app/store/attachments/effects/submit/submit-considerations.effect.ts
new file mode 100644
index 0000000..df309f5
--- /dev/null
+++ b/src/app/store/attachments/effects/submit/submit-considerations.effect.ts
@@ -0,0 +1,102 @@
+/********************************************************************************
+ * 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 {Injectable} from "@angular/core";
+import {Actions, createEffect, ofType} from "@ngrx/effects";
+import {Action} from "@ngrx/store";
+import {concat, EMPTY, Observable, of, throwError} from "rxjs";
+import {catchError, endWith, filter, map, mergeMap, startWith, switchMap} from "rxjs/operators";
+import {AttachmentsApiService} from "../../../../core/api/attachments";
+import {arrayJoin, endWithObservable, ignoreError} from "../../../../util";
+import {setErrorAction} from "../../../root/actions";
+import {EErrorCode} from "../../../root/model";
+import {setStatementLoadingAction, submitConsiderationFilesAction} from "../../../statements/actions";
+import {addAttachmentEntityAction, setAttachmentCacheAction} from "../../actions";
+import {IAttachmentControlValue, IAttachmentError} from "../../model";
+import {FetchAttachmentsEffect} from "../fetch";
+
+@Injectable({providedIn: "root"})
+export class SubmitConsiderationsEffect {
+
+    public submit$ = createEffect(() => this.actions.pipe(
+        ofType(submitConsiderationFilesAction),
+        switchMap((action) => {
+            return this.submit(action.statementId, action.value).pipe(
+                ignoreError()
+            );
+        })
+    ));
+
+    public constructor(
+        public readonly actions: Actions,
+        public readonly attachmentsApiService: AttachmentsApiService,
+        public readonly fetchAttachmentsEffect: FetchAttachmentsEffect
+    ) {
+
+    }
+
+
+    public submit(
+        statementId: number,
+        value: IAttachmentControlValue[]
+    ): Observable<Action> {
+        const errors: IAttachmentError[] = [];
+
+        return concat(
+            this.addConsiderations(statementId, value, errors),
+            this.fetchAttachmentsEffect.fetchAttachments(statementId)
+        ).pipe(
+            endWithObservable(() => {
+                const lastError = errors.reverse()[0];
+                return lastError == null ? EMPTY : concat(
+                    of(setErrorAction({statementId, error: lastError.message})),
+                    throwError(lastError.error)
+                );
+            }),
+            startWith(setStatementLoadingAction({loading: {submittingConsiderationFiles: true}})),
+            endWith(setStatementLoadingAction({loading: {submittingConsiderationFiles: false}}))
+        );
+    }
+
+    public addConsiderations(
+        statementId: number,
+        considerations: IAttachmentControlValue[],
+        errors: IAttachmentError[] = []
+    ): Observable<Action> {
+        const items: IAttachmentControlValue[] = [];
+        return of(...arrayJoin(considerations)).pipe(
+            filter((item) => item?.file instanceof File),
+            mergeMap((item) => {
+                return this.addSingleConsiderationFile(statementId, item.file).pipe(
+                    catchError((error) => {
+                        items.push(item);
+                        errors.push({statementId, attachment: item, error, message: EErrorCode.FAILED_FILE_UPLOAD});
+                        return EMPTY;
+                    })
+                );
+            }, 2),
+            startWith(setAttachmentCacheAction({statementId, items: considerations})),
+            endWithObservable(() => of(setAttachmentCacheAction({statementId, items})))
+        );
+    }
+
+    private addSingleConsiderationFile(
+        statementId: number,
+        file: File
+    ): Observable<Action> {
+        return this.attachmentsApiService.postConsideration(statementId, file).pipe(
+            map((entity) => addAttachmentEntityAction({statementId, entity}))
+        );
+    }
+
+}
diff --git a/src/app/store/attachments/selectors/attachments.selectors.spec.ts b/src/app/store/attachments/selectors/attachments.selectors.spec.ts
index 5d7dab3..e53dc34 100644
--- a/src/app/store/attachments/selectors/attachments.selectors.spec.ts
+++ b/src/app/store/attachments/selectors/attachments.selectors.spec.ts
@@ -11,13 +11,15 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-import {IAPIAttachmentTag} from "../../../core/api/attachments";
+import {IAPIAttachmentModel, IAPIAttachmentTag} from "../../../core/api/attachments";
 import {createAttachmentFileMock, createAttachmentModelMock} from "../../../test";
 import {IAttachmentsStoreState} from "../model";
 import {
     getAttachmentControlValueSelector,
     getFilteredAttachmentTagsSelector,
-    getStatementAttachmentsSelector
+    getOutboxAttachments,
+    getStatementAttachmentsSelector,
+    getStatementPdfAttachment
 } from "./attachments.selectors";
 
 describe("attachmentsSelectors", () => {
@@ -66,4 +68,24 @@
             .toEqual([{id: 19, name: "name", tagIds: [], isSelected: true}]);
     });
 
+    it("getOutboxAttachments", () => {
+        const projector = getOutboxAttachments.projector;
+        const input: IAPIAttachmentModel[] = [
+            {id: 19, name: "name", tagIds: ["outbox"]}, {id: 20, name: "name", tagIds: []}
+        ] as IAPIAttachmentModel[];
+        const expectedResult = [{id: 19, name: "name", tagIds: ["outbox"]}] as IAPIAttachmentModel[];
+        expect(projector(input))
+            .toEqual(expectedResult);
+    });
+
+    it("getStatementPdfAttachment", () => {
+        const projector = getStatementPdfAttachment.projector;
+        const input: IAPIAttachmentModel[] = [
+            {id: 19, name: "name", tagIds: ["statement"]}, {id: 20, name: "name", tagIds: []}
+        ] as IAPIAttachmentModel[];
+        const expectedResult = [{id: 19, name: "name", tagIds: ["statement"]}] as IAPIAttachmentModel[];
+        expect(projector(input))
+            .toEqual(expectedResult);
+    });
+
 });
diff --git a/src/app/store/attachments/selectors/attachments.selectors.ts b/src/app/store/attachments/selectors/attachments.selectors.ts
index 59ae2dc..db627c3 100644
--- a/src/app/store/attachments/selectors/attachments.selectors.ts
+++ b/src/app/store/attachments/selectors/attachments.selectors.ts
@@ -93,6 +93,29 @@
     }
 );
 
+export const getOutboxAttachments = createSelector(
+    getAllStatementAttachments,
+    (attachments) => {
+        return arrayJoin(attachments).filter((attachment) =>
+            attachment?.tagIds.some((_) => _ === "outbox") && attachment?.tagIds?.length === 1);
+    }
+);
+
+export const getConsiderationAttachments = createSelector(
+    getAllStatementAttachments,
+    (attachments) => {
+        return arrayJoin(attachments).filter((attachment) =>
+            attachment?.tagIds.some((_) => _ === "consideration") && attachment?.tagIds?.length === 1);
+    }
+);
+
+export const getStatementPdfAttachment = createSelector(
+    getAllStatementAttachments,
+    (attachments) => {
+        return arrayJoin(attachments).filter((attachment) => attachment?.tagIds.some((_) => _ === "statement"));
+    }
+);
+
 export const getStatementAttachmentCacheSelector = createSelector(
     getStatementAttachmentCacheEntitiesSelector,
     queryParamsIdSelector,
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/actions/geo.actions.ts
similarity index 70%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/actions/geo.actions.ts
index 5eb9c7f..9c1a7f8 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/actions/geo.actions.ts
@@ -11,4 +11,10 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+import {createAction, props} from "@ngrx/store";
+import {ILeafletBounds} from "../../../shared/leaflet";
+
+export const openGisAction = createAction(
+    "[Map] Open GIS",
+    props<{ bounds: ILeafletBounds, user: string }>()
+);
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/actions/index.ts
similarity index 93%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/actions/index.ts
index 5eb9c7f..df868cc 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/actions/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./geo.actions";
diff --git a/src/app/features/search/components/search/search.component.scss b/src/app/store/geo/effects/index.ts
similarity index 94%
rename from src/app/features/search/components/search/search.component.scss
rename to src/app/store/geo/effects/index.ts
index 06db89a..1cfc850 100644
--- a/src/app/features/search/components/search/search.component.scss
+++ b/src/app/store/geo/effects/index.ts
@@ -11,3 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
+export * from "./open-gis";
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/effects/open-gis/index.ts
similarity index 93%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/effects/open-gis/index.ts
index 5eb9c7f..66752fd 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/effects/open-gis/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./open-gis.effect";
diff --git a/src/app/store/geo/effects/open-gis/open-gis.effect.spec.ts b/src/app/store/geo/effects/open-gis/open-gis.effect.spec.ts
new file mode 100644
index 0000000..c33cff7
--- /dev/null
+++ b/src/app/store/geo/effects/open-gis/open-gis.effect.spec.ts
@@ -0,0 +1,127 @@
+/********************************************************************************
+ * 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 {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
+import {TestBed} from "@angular/core/testing";
+import {provideMockActions} from "@ngrx/effects/testing";
+import {Action} from "@ngrx/store";
+import {LatLngLiteral} from "leaflet";
+import {Observable, Subject, Subscription} from "rxjs";
+import {IAPIGeographicPositions, SPA_BACKEND_ROUTE, WINDOW} from "../../../../core";
+import {ILeafletBounds} from "../../../../shared/leaflet";
+import {openGisAction} from "../../actions";
+import {OpenGisEffect} from "./open-gis.effect";
+
+describe("OpenGisEffect", () => {
+    const bounds: ILeafletBounds = {
+        center: createLatLngMock(),
+        northEast: createLatLngMock(),
+        northWest: createLatLngMock(),
+        southEast: createLatLngMock(),
+        southWest: createLatLngMock(),
+        zoom: 13
+    };
+    const user = "userName";
+    const gisTemplateUrl = "http://localhost2200/Coordinates?" +
+        "pLLX={southWestX}&pLLY={southWestY}&" +
+        "pURX={northEastX}&pURY={northEastY}&" +
+        "pCX={centerX}&pCY={centerY}&" +
+        "user={user}";
+
+    const geographicPositions: IAPIGeographicPositions = {
+        southWest: {x: bounds.southWest.lng, y: bounds.southWest.lat},
+        northEast: {x: bounds.northEast.lng, y: bounds.northEast.lat},
+        center: {x: bounds.center.lng, y: bounds.center.lat}
+    };
+    const gisUrl = "http://localhost2200/Coordinates?" +
+        `pLLX=${geographicPositions.southWest.x}&pLLY=${geographicPositions.southWest.y}&` +
+        `pURX=${geographicPositions.northEast.x}&pURY=${geographicPositions.northEast.y}&` +
+        `pCX=${geographicPositions.center.x}&pCY=${geographicPositions.center.y}&` +
+        `user=${user}`;
+
+    let actions$: Observable<Action>;
+    let httpTestingController: HttpTestingController;
+    let effect: OpenGisEffect;
+    let subscription: Subscription;
+
+    beforeEach(async () => {
+        TestBed.configureTestingModule({
+            imports: [
+                HttpClientTestingModule
+            ],
+            providers: [
+                provideMockActions(() => actions$),
+                {
+                    provide: SPA_BACKEND_ROUTE,
+                    useValue: "/"
+                },
+                {
+                    provide: WINDOW,
+                    useValue: ({
+                        open(url?: string, target?: string, features?: string, replace?: boolean) {
+                        }
+                    })
+                }
+            ]
+        });
+        effect = TestBed.inject(OpenGisEffect);
+        effect.gisUrlTemplate = gisTemplateUrl;
+        httpTestingController = TestBed.inject(HttpTestingController);
+    });
+
+    afterEach(() => {
+        if (subscription != null) {
+            subscription.unsubscribe();
+        }
+    });
+
+    it("should open GIS in new window", () => {
+        const results: Action[] = [];
+        const spy = spyOn(effect.window, "open");
+        const actionSubject = new Subject<Action>();
+        actions$ = actionSubject;
+
+        subscription = effect.open$.subscribe((_) => results.push(_));
+
+        actionSubject.next(openGisAction({bounds, user}));
+        expectTransformRequest(geographicPositions);
+        expect(spy).toHaveBeenCalledWith(gisUrl, "_blank");
+        expect(results).toEqual([]);
+        httpTestingController.verify();
+    });
+
+    it("should not call back end if no transform is required", () => {
+        subscription = effect.transform({}).subscribe();
+        httpTestingController.verify();
+    });
+
+    it("should extract geographic positions from bounds", () => {
+        expect(effect.extractGeographicPositionFromBounds(bounds)).toEqual(geographicPositions);
+        expect(effect.extractGeographicPositionFromBounds({} as any)).toEqual({});
+    });
+
+    function expectTransformRequest(body: IAPIGeographicPositions) {
+        const endPoint = `/geo-coordinate-transform?from=${effect.projectionFrom}&to=${effect.projectionTo}`;
+        const request = httpTestingController.expectOne(endPoint);
+        expect(request.request.method).toBe("POST");
+        request.flush(body);
+    }
+
+});
+
+function createLatLngMock(): LatLngLiteral {
+    return {
+        lat: 4 + Math.random() * 10,
+        lng: 4 + Math.random() * 10
+    };
+}
diff --git a/src/app/store/geo/effects/open-gis/open-gis.effect.ts b/src/app/store/geo/effects/open-gis/open-gis.effect.ts
new file mode 100644
index 0000000..19da54f
--- /dev/null
+++ b/src/app/store/geo/effects/open-gis/open-gis.effect.ts
@@ -0,0 +1,118 @@
+/********************************************************************************
+ * 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 {Inject, Injectable} from "@angular/core";
+import {Actions, createEffect, ofType} from "@ngrx/effects";
+import {Action} from "@ngrx/store";
+import {EMPTY, Observable, of} from "rxjs";
+import {exhaustMap, ignoreElements, switchMap} from "rxjs/operators";
+import {APP_CONFIGURATION, GeoApiService, IAPIGeographicPositions, IAppConfiguration, WINDOW} from "../../../../core";
+import {ILeafletBounds} from "../../../../shared/leaflet";
+import {catchErrorTo} from "../../../../util/rxjs";
+import {EErrorCode, setErrorAction} from "../../../root";
+import {openGisAction} from "../../actions";
+
+@Injectable({providedIn: "root"})
+export class OpenGisEffect {
+
+    public open$ = createEffect(() => this.actions.pipe(
+        ofType(openGisAction),
+        exhaustMap((action) => this.openGis(action.bounds, action.user))
+    ));
+
+    /**
+     * URL Template to connect with GIS.
+     */
+    public gisUrlTemplate = this.configuration.gis.urlTemplate;
+
+    /**
+     * Expected projection format for the given Leaflet coordinates.
+     */
+    public projectionFrom = this.configuration.gis.projectionFrom;
+
+    /**
+     * Expected projection required for the GIS.
+     */
+    public projectionTo = this.configuration.gis.projectionTo;
+
+    /**
+     * Search parameter keys which are transformed in the GIS URL template.
+     */
+    public coordinateKeys: Array<keyof ILeafletBounds> = ["center", "northEast", "northWest", "southEast", "southWest"];
+
+    public constructor(
+        public actions: Actions,
+        public geoApiService: GeoApiService,
+        @Inject(WINDOW) public window: Window,
+        @Inject(APP_CONFIGURATION) public configuration: IAppConfiguration
+    ) {
+
+    }
+
+    public openGis(bounds: ILeafletBounds, user: string): Observable<Action> {
+        return of(bounds).pipe(
+            switchMap(() => this.transform(this.extractGeographicPositionFromBounds(bounds))),
+            switchMap((geographicPositions) => {
+                const gisUrl = this.generateUrl(geographicPositions, user);
+                this.window.open(gisUrl, "_blank");
+                return EMPTY;
+            }),
+            ignoreElements(),
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED}))
+        );
+    }
+
+    /**
+     * Extract all required geographic positions from the given Leaflet bounds.
+     */
+    public extractGeographicPositionFromBounds(bounds: ILeafletBounds): IAPIGeographicPositions {
+        const geographicPositions: IAPIGeographicPositions = {};
+        this.coordinateKeys.forEach((key) => {
+            const value = bounds[key];
+            if (typeof value !== "object") {
+                return;
+            }
+            const tokens = [`{${key}X}`, `{${key}Y}`];
+            if (tokens.some((token) => this.gisUrlTemplate.indexOf(token) > -1)) {
+                geographicPositions[key] = {
+                    x: value.lng,
+                    y: value.lat
+                };
+            }
+        });
+        return geographicPositions;
+    }
+
+    /**
+     * Transforms a set of geographic positions via an API back end call.
+     */
+    public transform(geographicPositions: IAPIGeographicPositions): Observable<IAPIGeographicPositions> {
+        return Object.keys(geographicPositions).length > 0 ?
+            this.geoApiService.transform(geographicPositions, this.projectionFrom, this.projectionTo) :
+            of(geographicPositions);
+    }
+
+    /**
+     * Generate the URL to the GIS with a set of given geographic positions.
+     */
+    public generateUrl(geographicPositions: IAPIGeographicPositions, user: string) {
+        let result = this.gisUrlTemplate;
+        Object.entries(geographicPositions).forEach(([key, value]) => {
+            result = result.replace(new RegExp(`{${key}X}`, "g"), "" + value.x);
+            result = result.replace(new RegExp(`{${key}Y}`, "g"), "" + value.y);
+        });
+        result = result.replace(new RegExp(`{user}`, "g"), user);
+        return result;
+    }
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/geo-reducers.token.ts
similarity index 63%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/geo-reducers.token.ts
index 5eb9c7f..a1453d3 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/geo-reducers.token.ts
@@ -11,4 +11,13 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+import {InjectionToken} from "@angular/core";
+import {ActionReducerMap} from "@ngrx/store";
+import {IGeoStoreState} from "./model";
+
+export const GEO_NAME = "geo";
+
+export const GEO_REDUCERS = new InjectionToken<ActionReducerMap<IGeoStoreState>>("Geo store reducer", {
+    providedIn: "root",
+    factory: () => ({})
+});
diff --git a/src/app/store/geo/geo-store.module.ts b/src/app/store/geo/geo-store.module.ts
new file mode 100644
index 0000000..1253f7d
--- /dev/null
+++ b/src/app/store/geo/geo-store.module.ts
@@ -0,0 +1,30 @@
+/********************************************************************************
+ * 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 {NgModule} from "@angular/core";
+import {EffectsModule} from "@ngrx/effects";
+import {StoreModule} from "@ngrx/store";
+import {OpenGisEffect} from "./effects";
+import {GEO_NAME, GEO_REDUCERS} from "./geo-reducers.token";
+
+@NgModule({
+    imports: [
+        StoreModule.forFeature(GEO_NAME, GEO_REDUCERS),
+        EffectsModule.forFeature([
+            OpenGisEffect
+        ])
+    ]
+})
+export class GeoStoreModule {
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/index.ts
similarity index 86%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/index.ts
index 5eb9c7f..5b5ab49 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/index.ts
@@ -11,4 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./actions";
+export * from "./model";
+
+export * from "./geo-store.module";
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/model/IGeoStoreState.ts
similarity index 90%
copy from src/app/features/search/components/search/index.ts
copy to src/app/store/geo/model/IGeoStoreState.ts
index 5eb9c7f..c4a0812 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/model/IGeoStoreState.ts
@@ -11,4 +11,8 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export interface IGeoStoreState {
+
+    loading?: any;
+
+}
diff --git a/src/app/features/search/components/search/index.ts b/src/app/store/geo/model/index.ts
similarity index 93%
rename from src/app/features/search/components/search/index.ts
rename to src/app/store/geo/model/index.ts
index 5eb9c7f..ba18e63 100644
--- a/src/app/features/search/components/search/index.ts
+++ b/src/app/store/geo/model/index.ts
@@ -11,4 +11,4 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-export * from "./search.component";
+export * from "./IGeoStoreState";
diff --git a/src/app/store/index.ts b/src/app/store/index.ts
index 0044745..9de1c49 100644
--- a/src/app/store/index.ts
+++ b/src/app/store/index.ts
@@ -13,6 +13,8 @@
 
 export * from "./attachments";
 export * from "./contacts";
+export * from "./geo";
+export * from "./mail";
 export * from "./process";
 export * from "./root";
 export * from "./settings";
diff --git a/src/app/store/mail/actions/mail.actions.ts b/src/app/store/mail/actions/mail.actions.ts
index 8bde645..31314b6 100644
--- a/src/app/store/mail/actions/mail.actions.ts
+++ b/src/app/store/mail/actions/mail.actions.ts
@@ -26,7 +26,7 @@
 
 export const deleteEmailFromInboxAction = createAction(
     "[Email] Delete email from inbox",
-    props<{ mailId: string, navigateTo?: string }>()
+    props<{ mailId: string }>()
 );
 
 export const downloadEmailAttachmentAction = createAction(
diff --git a/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.spec.ts b/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.spec.ts
index 6abb45d..370af82 100644
--- a/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.spec.ts
+++ b/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.spec.ts
@@ -13,6 +13,7 @@
 
 import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
 import {TestBed} from "@angular/core/testing";
+import {ActivatedRoute, Params} from "@angular/router";
 import {RouterTestingModule} from "@angular/router/testing";
 import {provideMockActions} from "@ngrx/effects/testing";
 import {Action} from "@ngrx/store";
@@ -24,6 +25,7 @@
 describe("DeleteEmailFromInboxEffect", () => {
 
     let actions$: Observable<Action>;
+    let queryParams: Params;
     let httpTestingController: HttpTestingController;
     let effect: DeleteEmailFromInboxEffect;
     let subscription: Subscription;
@@ -39,11 +41,16 @@
                 {
                     provide: SPA_BACKEND_ROUTE,
                     useValue: "/"
+                },
+                {
+                    provide: ActivatedRoute,
+                    useValue: {snapshot: {queryParams: {}}}
                 }
             ]
         });
         effect = TestBed.inject(DeleteEmailFromInboxEffect);
         httpTestingController = TestBed.inject(HttpTestingController);
+        queryParams = TestBed.inject(ActivatedRoute).snapshot.queryParams;
     });
 
     afterEach(() => {
@@ -61,7 +68,7 @@
         subscription = effect.delete$.subscribe((_) => results.push(_));
 
         actionSubject.next(deleteEmailFromInboxAction({mailId}));
-        expect(spy).toHaveBeenCalledWith(mailId, undefined);
+        expect(spy).toHaveBeenCalledWith(mailId);
         spy.calls.reset();
 
         actionSubject.next(deleteEmailFromInboxAction({mailId: null}));
@@ -74,10 +81,17 @@
         const mailId = "<Mail19>";
         const results: Action[] = [];
 
+        queryParams.mailId = mailId;
+        const navigationPromise = Promise.resolve(true);
+        const navigateSpy = spyOn(effect.router, "navigate").and.returnValue(navigationPromise);
+        navigateSpy.calls.reset();
         subscription = effect.delete(mailId).subscribe((_) => results.push(_));
+
         expectDeleteMailFromInboxRequest(mailId);
+        await navigationPromise; // Wait for navigation to finish
 
         expect(subscription.closed).toBeTrue();
+        expect(navigateSpy).toHaveBeenCalled();
         expect(results).toEqual([
             setEmailLoadingStateAction({loading: {deleting: true}}),
             deleteEmailEntityAction({mailId}),
diff --git a/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.ts b/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.ts
index 2b937b3..b5fc123 100644
--- a/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.ts
+++ b/src/app/store/mail/effects/delete/delete-email-from-inbox.effect.ts
@@ -12,13 +12,15 @@
  ********************************************************************************/
 
 import {Injectable} from "@angular/core";
-import {Router} from "@angular/router";
+import {ActivatedRoute, Router} from "@angular/router";
 import {Actions, createEffect, ofType} from "@ngrx/effects";
 import {Action} from "@ngrx/store";
-import {EMPTY, Observable} from "rxjs";
-import {catchError, endWith, filter, map, mergeMap, startWith} from "rxjs/operators";
+import {concat, EMPTY, from, Observable} from "rxjs";
+import {endWith, filter, ignoreElements, map, mergeMap, startWith} from "rxjs/operators";
 import {MailApiService} from "../../../../core";
-import {endWithObservable, ignoreError} from "../../../../util/rxjs";
+import {catchErrorTo} from "../../../../util/rxjs";
+import {setErrorAction} from "../../../root/actions";
+import {EErrorCode} from "../../../root/model";
 import {deleteEmailEntityAction, deleteEmailFromInboxAction, setEmailLoadingStateAction} from "../../actions";
 
 @Injectable({providedIn: "root"})
@@ -27,35 +29,45 @@
     public delete$ = createEffect(() => this.actions.pipe(
         ofType(deleteEmailFromInboxAction),
         filter((action) => action.mailId != null),
-        mergeMap((action) => this.delete(action.mailId, action.navigateTo))
+        mergeMap((action) => this.delete(action.mailId))
     ));
 
     public constructor(
         public readonly actions: Actions,
         public readonly mailApiService: MailApiService,
+        public readonly activatedRoute: ActivatedRoute,
         public readonly router: Router
     ) {
 
     }
 
-    public delete(mailId: string, navigateTo?: string): Observable<Action> {
-        let error = false;
-        return this.mailApiService.deleteInboxEmail(mailId).pipe(
-            map(() => deleteEmailEntityAction({mailId})),
+    public delete(mailId: string): Observable<Action> {
+        return concat(
+            this.deleteEmailFromInbox(mailId),
+            this.removeQueryParam(mailId)
+        ).pipe(
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
             startWith(setEmailLoadingStateAction({loading: {deleting: true}})),
-            catchError(() => {
-                error = true;
-                return EMPTY;
-            }),
-            ignoreError(),
-            endWith((setEmailLoadingStateAction({loading: {deleting: false}}))),
-            endWithObservable(() => {
-                if (navigateTo && !error) {
-                    this.router.navigate(["mail"]);
-                }
-                return EMPTY;
-            })
+            endWith((setEmailLoadingStateAction({loading: {deleting: false}})))
         );
     }
 
+    public deleteEmailFromInbox(mailId: string): Observable<Action> {
+        return this.mailApiService.deleteInboxEmail(mailId).pipe(
+            map(() => deleteEmailEntityAction({mailId}))
+        );
+    }
+
+    public removeQueryParam(mailId: string): Observable<never> {
+        if (this.activatedRoute.snapshot.queryParams.mailId !== mailId) {
+            return EMPTY;
+        }
+        const navigatePromise = this.router.navigate([], {
+            queryParams: {mailId: null},
+            queryParamsHandling: "merge",
+            replaceUrl: true
+        });
+        return from(navigatePromise).pipe(ignoreElements());
+    }
+
 }
diff --git a/src/app/store/process/effects/process-task.effect.ts b/src/app/store/process/effects/process-task.effect.ts
index 2078a99..39cdc55 100644
--- a/src/app/store/process/effects/process-task.effect.ts
+++ b/src/app/store/process/effects/process-task.effect.ts
@@ -23,6 +23,7 @@
 import {arrayJoin} from "../../../util/store";
 import {setErrorAction} from "../../root/actions";
 import {EErrorCode} from "../../root/model";
+import {sendStatementViaMailAction} from "../../statements/actions";
 import {
     claimAndCompleteTask,
     claimTaskAction,
@@ -55,6 +56,15 @@
         ))
     ));
 
+    public claimAndSend$ = createEffect(() => this.actions.pipe(
+        ofType(sendStatementViaMailAction),
+        switchMap((action) => this.claimAndSend(action.statementId, action.taskId).pipe(
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
+            startWith(setProcessLoadingAction({statementId: action.statementId, loading: true})),
+            endWith(setProcessLoadingAction({statementId: action.statementId, loading: false}))
+        ))
+    ));
+
     public completeTask$ = createEffect(() => this.actions.pipe(
         ofType(completeTaskAction),
         exhaustMap((action) => this.completeTask(action.statementId, action.taskId, action.variables, action.claimNext).pipe(
@@ -103,6 +113,30 @@
         );
     }
 
+    public claimAndSend(
+        statementId: number,
+        taskId: string
+    ): Observable<Action> {
+        return this.claimTask(statementId, taskId).pipe(
+            throwAfterActionType(setErrorAction),
+            endWithObservable(() => concat(
+                this.sendMailAndComplete(statementId, taskId),
+                this.fetchTasks(statementId))
+            ),
+            ignoreError()
+        );
+    }
+
+    public sendMailAndComplete(statementId: number, taskId: string): Observable<Action> {
+        return this.processApiService.dispatchStatement(statementId, taskId).pipe(
+            map(() => deleteTaskAction({statementId, taskId})),
+            catchError(() => this.processApiService.unclaimStatementTask(statementId, taskId).pipe(
+                map(() => setErrorAction({statementId, error: EErrorCode.COULD_NOT_SEND_MAIL})),
+                catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED}))
+            ))
+        );
+    }
+
     public completeTask(
         statementId: number,
         taskId: string,
@@ -171,7 +205,7 @@
     ): Observable<IAPIProcessTask> {
         let taskId: string;
         return claimNext == null || claimNext === false ? EMPTY : this.getNextTask(statementId, claimNext).pipe(
-            switchMap((_taskId) => this.processApiService.claimStatementTask(statementId, taskId = _taskId)),
+            switchMap((_taskId) => _taskId ? this.processApiService.claimStatementTask(statementId, taskId = _taskId) : EMPTY),
             endWithObservable(() => navigate ? this.navigateTo(statementId, taskId) : EMPTY)
         );
     }
diff --git a/src/app/store/root/model/EErrorCode.ts b/src/app/store/root/model/EErrorCode.ts
index f5cbecc..02a601c 100644
--- a/src/app/store/root/model/EErrorCode.ts
+++ b/src/app/store/root/model/EErrorCode.ts
@@ -21,5 +21,6 @@
     FAILED_FILE_UPLOAD = "shared.errorMessages.failedFileUpload",
     FAILED_MAIL_TRANSFER = "shared.errorMessages.failedMailTransfer",
     INVALID_TEXT_ARRANGEMENT = "shared.errorMessages.invalidTextArrangement",
-    COULD_NOT_LOAD_MAIL_DATA = "shared.errorMessages.couldNotLoadMailData"
+    COULD_NOT_LOAD_MAIL_DATA = "shared.errorMessages.couldNotLoadMailData",
+    COULD_NOT_SEND_MAIL = "shared.errorMessages.couldNotSendMail"
 }
diff --git a/src/app/store/root/selectors/query-params.selectors.ts b/src/app/store/root/selectors/query-params.selectors.ts
index 242e71a..f547563 100644
--- a/src/app/store/root/selectors/query-params.selectors.ts
+++ b/src/app/store/root/selectors/query-params.selectors.ts
@@ -11,9 +11,25 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
+import {Params} from "@angular/router";
 import {createSelector} from "@ngrx/store";
 import {rootStateSelector} from "./root.selectors";
 
+function selectQueryParamString(key: string) {
+    return (state: Params): string => state == null ? undefined : state[key];
+}
+
+function selectQueryParamInt(key: string) {
+    return (state: Params): number => {
+        if (state == null || state[key] == null) {
+            return undefined;
+        }
+        const result = typeof state[key] === "string" ? parseInt(state[key], 10) : state[key];
+        return Number.isInteger(result) ? result : undefined;
+    };
+}
+
+
 export const queryParamsSelector = createSelector(
     rootStateSelector,
     (state) => state.queryParams
@@ -21,21 +37,20 @@
 
 export const queryParamsIdSelector = createSelector(
     queryParamsSelector,
-    (state): number => {
-        if (state == null || state.id == null) {
-            return undefined;
-        }
-        const id = typeof state.id === "string" ? parseInt(state.id, 10) : state.id;
-        return Number.isInteger(id) ? id : undefined;
-    }
+    selectQueryParamInt("id")
 );
 
 export const queryParamsTaskIdSelector = createSelector(
     queryParamsSelector,
-    (state): string => state?.taskId
+    selectQueryParamString("taskId")
 );
 
 export const queryParamsMailIdSelector = createSelector(
     queryParamsSelector,
-    (state): string => state?.mailId
+    selectQueryParamString("mailId")
+);
+
+export const queryParamsCoordSelector = createSelector(
+    queryParamsSelector,
+    selectQueryParamString("coord")
 );
diff --git a/src/app/store/statements/actions/fetch.actions.ts b/src/app/store/statements/actions/fetch.actions.ts
index ecbf621..d0d1b1a 100644
--- a/src/app/store/statements/actions/fetch.actions.ts
+++ b/src/app/store/statements/actions/fetch.actions.ts
@@ -20,6 +20,11 @@
     props<{ statementId: number; withConfiguration?: boolean }>()
 );
 
+export const fetchProcessStateInfo = createAction(
+    "[Details] Fetch process history",
+    props<{ statementId: number; }>()
+);
+
 export const updateStatementEntityAction = createAction(
     "[API] Update statement entity",
     props<{ statementId: number, entity: IStatementEntity }>()
diff --git a/src/app/store/statements/actions/search.actions.ts b/src/app/store/statements/actions/search.actions.ts
index 2b51abe..1b1550a 100644
--- a/src/app/store/statements/actions/search.actions.ts
+++ b/src/app/store/statements/actions/search.actions.ts
@@ -12,7 +12,8 @@
  ********************************************************************************/
 
 import {createAction, props} from "@ngrx/store";
-import {IAPIPaginationResponse, IAPISearchOptions, IAPIStatementModel} from "../../../core";
+import {IAPIPaginationResponse, IAPIPositionSearchStatementModel, IAPISearchOptions, IAPIStatementModel} from "../../../core";
+import {IAPIPositionSearchOptions} from "../../../core/api/shared/IAPIPositionSearchOptions";
 
 export const startStatementSearchAction = createAction(
     "[Dashboard/Edit/List] Start search for statements",
@@ -23,3 +24,13 @@
     "[API] Set search results for statements",
     props<{ results: IAPIPaginationResponse<IAPIStatementModel> }>()
 );
+
+export const startStatementPositionSearchAction = createAction(
+    "[PositionSearch] Start search for statement positions",
+    props<{ options: IAPIPositionSearchOptions }>()
+);
+
+export const setStatementPositionSearchResultAction = createAction(
+    "[API] Set search results for statement positions",
+    props<{ results: IAPIPositionSearchStatementModel[] }>()
+);
diff --git a/src/app/store/statements/actions/submit.actions.ts b/src/app/store/statements/actions/submit.actions.ts
index 3975538..003026a 100644
--- a/src/app/store/statements/actions/submit.actions.ts
+++ b/src/app/store/statements/actions/submit.actions.ts
@@ -14,6 +14,7 @@
 import {createAction, props} from "@ngrx/store";
 import {EAPIProcessTaskDefinitionKey, TCompleteTaskVariable} from "../../../core/api/process";
 import {IAPITextArrangementItemModel} from "../../../core/api/text";
+import {IAttachmentControlValue} from "../../attachments/model";
 import {IStatementEditorFormValue, IStatementInformationFormValue, IWorkflowFormValue} from "../model";
 
 /**
@@ -74,6 +75,13 @@
     }>()
 );
 
+export const submitConsiderationFilesAction = createAction(
+    "[Edit] Submit considerations",
+    props<{
+        statementId: number,
+        value: IAttachmentControlValue[]
+    }>()
+);
 
 export const sendStatementViaMailAction = createAction(
     "[Details] Resend statement via email",
diff --git a/src/app/store/statements/effects/fetch-statement-details/fetch-statement-details.effect.ts b/src/app/store/statements/effects/fetch-statement-details/fetch-statement-details.effect.ts
index e9c8d46..12646e4 100644
--- a/src/app/store/statements/effects/fetch-statement-details/fetch-statement-details.effect.ts
+++ b/src/app/store/statements/effects/fetch-statement-details/fetch-statement-details.effect.ts
@@ -15,8 +15,8 @@
 import {Actions, createEffect, ofType} from "@ngrx/effects";
 import {Action} from "@ngrx/store";
 import {EMPTY, merge, Observable, of} from "rxjs";
-import {filter, map, retry, startWith, switchMap} from "rxjs/operators";
-import {ProcessApiService, SettingsApiService, StatementsApiService} from "../../../../core";
+import {endWith, filter, map, retry, startWith, switchMap} from "rxjs/operators";
+import {ContactsApiService, ProcessApiService, SettingsApiService, StatementsApiService} from "../../../../core";
 import {catchErrorTo} from "../../../../util/rxjs";
 import {arrayJoin} from "../../../../util/store";
 import {fetchAttachmentsAction} from "../../../attachments/actions";
@@ -26,7 +26,9 @@
 import {EErrorCode} from "../../../root/model";
 import {
     fetchCommentsAction,
+    fetchProcessStateInfo,
     fetchStatementDetailsAction,
+    setStatementLoadingAction,
     updateStatementConfigurationAction,
     updateStatementEntityAction,
     updateStatementInfoAction
@@ -38,7 +40,22 @@
     public readonly fetchStatementDetails$ = createEffect(() => this.actions.pipe(
         ofType(fetchStatementDetailsAction),
         filter((action) => action.statementId != null),
-        switchMap((action) => this.fetchStatementDetails(action.statementId))
+        switchMap((action) => this.fetchStatementDetails(action.statementId).pipe(
+            startWith(setStatementLoadingAction({loading: {fetchingStatementDetails: true}})),
+            endWith(setStatementLoadingAction({loading: {fetchingStatementDetails: false}})),
+        ))
+    ));
+
+    public readonly fetchStatementHistory$ = createEffect(() => this.actions.pipe(
+        ofType(fetchProcessStateInfo),
+        filter((action) => action.statementId != null),
+        switchMap((action) => merge<Action>(
+            this.fetchHistory(action.statementId),
+            this.fetchDiagram(action.statementId)
+        ).pipe(
+            startWith(setStatementLoadingAction({loading: {fetchingStatementDetails: true}})),
+            endWith(setStatementLoadingAction({loading: {fetchingStatementDetails: false}})),
+        ))
     ));
 
     public constructor(
@@ -46,7 +63,8 @@
         private readonly statementsApiService: StatementsApiService,
         private readonly processApiService: ProcessApiService,
         private readonly settingsApiService: SettingsApiService,
-        private readonly taskEffect: ProcessTaskEffect
+        private readonly taskEffect: ProcessTaskEffect,
+        private readonly contactsApiService: ContactsApiService
     ) {
 
     }
@@ -65,7 +83,9 @@
                     of(fetchAttachmentsAction({statementId})),
                     of(fetchCommentsAction({statementId})),
                     withoutConfiguration ? EMPTY : this.fetchConfiguration(statementId),
-                    this.fetchSectors(statementId)
+                    this.fetchSectors(statementId),
+                    this.fetchStatementContact(statementId),
+                    this.fetchChildren(statementId)
                 ).pipe(
                     startWith(updateStatementEntityAction({statementId, entity: {info}}))
                 );
@@ -78,20 +98,34 @@
         return this.statementsApiService.getParentIds(statementId).pipe(
             retry(2),
             switchMap((parentIds) => {
-                parentIds = arrayJoin(parentIds);
-                const fetchParentsInfo$ = this.statementsApiService.getStatements(...parentIds).pipe(
-                    map((items) => updateStatementInfoAction({items})),
-                    retry(2),
-                    catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
-                );
-                return merge(
-                    of(updateStatementEntityAction({statementId, entity: {parentIds}})),
-                    parentIds.length === 0 ? EMPTY : fetchParentsInfo$
-                );
+                return this.getStatementsByIds(parentIds, statementId, true);
             })
         );
     }
 
+    public fetchChildren(statementId: number) {
+        return this.statementsApiService.getChildrenIds(statementId).pipe(
+            retry(2),
+            switchMap((parentIds) => {
+                return this.getStatementsByIds(parentIds, statementId, false);
+            })
+        );
+    }
+
+    public getStatementsByIds(ids: number[], statementId: number, parents: boolean) {
+        ids = arrayJoin(ids);
+        const fetchStatementInfo$ = this.statementsApiService.getStatements(...ids).pipe(
+            map((items) => updateStatementInfoAction({items})),
+            retry(2),
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
+        );
+        return merge(
+            parents ? of(updateStatementEntityAction({statementId, entity: {parentIds: ids}})) :
+                of(updateStatementEntityAction({statementId, entity: {childrenIds: ids}})),
+            ids.length === 0 ? EMPTY : fetchStatementInfo$
+        );
+    }
+
     public fetchWorkflowData(statementId: number) {
         return this.statementsApiService.getWorkflowData(statementId).pipe(
             retry(2),
@@ -140,4 +174,12 @@
         );
     }
 
+    public fetchStatementContact(statementId: number) {
+        return this.contactsApiService.getStatementsContact(statementId).pipe(
+            map((contactInfo) => updateStatementEntityAction({statementId, entity: {contactInfo}})),
+            retry(2),
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
+        );
+    }
+
 }
diff --git a/src/app/store/statements/effects/search/index.ts b/src/app/store/statements/effects/search/index.ts
index 589e408..6825d40 100644
--- a/src/app/store/statements/effects/search/index.ts
+++ b/src/app/store/statements/effects/search/index.ts
@@ -12,3 +12,4 @@
  ********************************************************************************/
 
 export * from "./search-statements.effect";
+export * from "./search-statement-positions.effect";
diff --git a/src/app/store/statements/effects/search/search-statement-positions.effect.ts b/src/app/store/statements/effects/search/search-statement-positions.effect.ts
new file mode 100644
index 0000000..43987db
--- /dev/null
+++ b/src/app/store/statements/effects/search/search-statement-positions.effect.ts
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * 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 {Injectable} from "@angular/core";
+import {Actions, createEffect, ofType} from "@ngrx/effects";
+import {Action} from "@ngrx/store";
+import {Observable, of} from "rxjs";
+import {concatMap, debounceTime, endWith, filter, startWith, switchMap} from "rxjs/operators";
+import {StatementsApiService} from "../../../../core";
+import {IAPIPositionSearchOptions} from "../../../../core/api/shared/IAPIPositionSearchOptions";
+import {catchErrorTo} from "../../../../util/rxjs";
+import {setErrorAction} from "../../../root/actions";
+import {EErrorCode} from "../../../root/model";
+import {setStatementLoadingAction, setStatementPositionSearchResultAction, startStatementPositionSearchAction} from "../../actions";
+
+@Injectable({providedIn: "root"})
+export class SearchStatementPositionsEffect {
+
+    public search$ = createEffect(() => this.actions.pipe(
+        ofType(startStatementPositionSearchAction),
+        debounceTime(200),
+        concatMap((action) => this.search(action.options))
+    ));
+
+    public constructor(
+        private readonly actions: Actions,
+        private readonly statementsApiService: StatementsApiService
+    ) {
+
+    }
+
+    public search(options: IAPIPositionSearchOptions): Observable<Action> {
+        return this.statementsApiService.getStatementPositionsSearch(options).pipe(
+            filter((results) => Array.isArray(results)),
+            switchMap((results) => {
+                return of(
+                    setStatementPositionSearchResultAction({results})
+                );
+            }),
+            catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED})),
+            startWith(setStatementLoadingAction({loading: {positionSearch: true}})),
+            endWith(setStatementLoadingAction({loading: {positionSearch: false}}))
+        );
+    }
+
+}
diff --git a/src/app/store/statements/model/IStatementEntity.ts b/src/app/store/statements/model/IStatementEntity.ts
index e614b23..1a654b9 100644
--- a/src/app/store/statements/model/IStatementEntity.ts
+++ b/src/app/store/statements/model/IStatementEntity.ts
@@ -11,6 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
+import {IAPIContactPersonDetails} from "../../../core/api/contacts/IAPIContactPersonDetails";
 import {IAPIProcessTask} from "../../../core/api/process";
 import {IAPIDepartmentGroups} from "../../../core/api/settings";
 import {IAPICommentModel, IAPIStatementModel, IAPIWorkflowData} from "../../../core/api/statements";
@@ -26,6 +27,8 @@
 
     parentIds?: number[];
 
+    childrenIds?: number[];
+
     comments?: IAPICommentModel[];
 
     arrangement?: IAPITextArrangementItemModel[];
@@ -42,6 +45,8 @@
 
     completedForMyDepartment?: boolean;
 
+    contactInfo?: IAPIContactPersonDetails;
+
 }
 
 export interface IStatementEntityWithTasks extends IStatementEntity {
diff --git a/src/app/store/statements/model/IStatementLoadingEntity.ts b/src/app/store/statements/model/IStatementLoadingEntity.ts
index 59343a7..e952f63 100644
--- a/src/app/store/statements/model/IStatementLoadingEntity.ts
+++ b/src/app/store/statements/model/IStatementLoadingEntity.ts
@@ -15,6 +15,8 @@
 
     search?: boolean;
 
+    positionSearch?: boolean;
+
     fetchingDashboardStatements?: boolean;
 
     submittingStatementInformation?: boolean;
@@ -23,4 +25,8 @@
 
     submittingStatementEditorForm?: boolean;
 
+    submittingConsiderationFiles?: boolean;
+
+    fetchingStatementDetails?: boolean;
+
 }
diff --git a/src/app/store/statements/model/IStatementsStoreState.ts b/src/app/store/statements/model/IStatementsStoreState.ts
index 5eb56d8..b0f66bd 100644
--- a/src/app/store/statements/model/IStatementsStoreState.ts
+++ b/src/app/store/statements/model/IStatementsStoreState.ts
@@ -11,7 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 
-import {IAPIPaginationResponse} from "../../../core";
+import {IAPIPaginationResponse, IAPIPositionSearchStatementModel} from "../../../core";
 import {TStoreEntities} from "../../../util/store";
 import {IStatementConfigurationEntity} from "./IStatementConfigurationEntity";
 import {IStatementEntity} from "./IStatementEntity";
@@ -30,4 +30,6 @@
 
     loading?: IStatementLoadingEntity;
 
+    positions?: IAPIPositionSearchStatementModel[];
+
 }
diff --git a/src/app/store/statements/reducers/search/statement-positions-search.reducer.ts b/src/app/store/statements/reducers/search/statement-positions-search.reducer.ts
new file mode 100644
index 0000000..d412157
--- /dev/null
+++ b/src/app/store/statements/reducers/search/statement-positions-search.reducer.ts
@@ -0,0 +1,25 @@
+/********************************************************************************
+ * 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 {createReducer, on} from "@ngrx/store";
+import {IAPIPositionSearchStatementModel} from "../../../../core/api/statements";
+import {arrayJoin} from "../../../../util/store";
+import {setStatementPositionSearchResultAction} from "../../actions";
+
+export const statementPositionsSearchReducer = createReducer<IAPIPositionSearchStatementModel[]>(
+    undefined,
+    on(setStatementPositionSearchResultAction, (state, action) => {
+        return arrayJoin(action.results)
+            .filter((statement: any) => statement?.id != null);
+    })
+);
diff --git a/src/app/store/statements/selectors/list/statement-list.selectors.ts b/src/app/store/statements/selectors/list/statement-list.selectors.ts
index d362118..187e2d2 100644
--- a/src/app/store/statements/selectors/list/statement-list.selectors.ts
+++ b/src/app/store/statements/selectors/list/statement-list.selectors.ts
@@ -17,7 +17,7 @@
 import {processStateSelector} from "../../../process/selectors";
 import {userRolesSelector} from "../../../root/selectors";
 import {IStatementEntityWithTasks} from "../../model";
-import {statementEntitiesSelector} from "../statement.selectors";
+import {statementChildrenIdsSelector, statementEntitiesSelector, statementParentIdsSelector} from "../statement.selectors";
 
 export const statementListSelector = createSelector(
     statementEntitiesSelector,
@@ -28,6 +28,22 @@
     }
 );
 
+export const parentStatementListSelector = createSelector(
+    statementParentIdsSelector,
+    statementListSelector,
+    (ids, statements) => {
+        return arrayJoin(statements).filter((_) => arrayJoin(ids).find((id) => id === _.id) != null);
+    }
+);
+
+export const childrenStatementListSelector = createSelector(
+    statementChildrenIdsSelector,
+    statementListSelector,
+    (ids, statements) => {
+        return arrayJoin(statements).filter((_) => arrayJoin(ids).find((id) => id === _.id) != null);
+    }
+);
+
 export const finishedStatementListSelector = createSelector(
     statementListSelector,
     (list) => list.filter((statement) => statement.finished)
diff --git a/src/app/store/statements/selectors/search/statement-search.selectors.ts b/src/app/store/statements/selectors/search/statement-search.selectors.ts
index d88147f..adc9428 100644
--- a/src/app/store/statements/selectors/search/statement-search.selectors.ts
+++ b/src/app/store/statements/selectors/search/statement-search.selectors.ts
@@ -27,3 +27,14 @@
         return [];
     }
 );
+
+export const getSearchContentInfoSelector = createSelector(
+    getStatementSearchSelector,
+    (search) => {
+        return {
+            totalPages: search?.totalPages,
+            currentPage: search?.number,
+            size: search?.size
+        };
+    }
+);
diff --git a/src/app/store/statements/selectors/statement.selectors.ts b/src/app/store/statements/selectors/statement.selectors.ts
index 04810f8..3143a40 100644
--- a/src/app/store/statements/selectors/statement.selectors.ts
+++ b/src/app/store/statements/selectors/statement.selectors.ts
@@ -42,6 +42,11 @@
     selectPropertyProjector("workflow")
 );
 
+export const statementGeographicPositionSelector = createSelector(
+    statementWorkflowSelector,
+    selectPropertyProjector("geoPosition")
+);
+
 export const statementContributionsSelector = createSelector(
     statementSelector,
     selectPropertyProjector("contributions")
@@ -52,6 +57,11 @@
     selectArrayProjector("parentIds", [])
 );
 
+export const statementChildrenIdsSelector = createSelector(
+    statementSelector,
+    selectArrayProjector("childrenIds", [])
+);
+
 export const statementCommentsSelector = createSelector(
     statementSelector,
     selectArrayProjector("comments", [])
diff --git a/src/app/store/statements/selectors/statements-store-state.selectors.ts b/src/app/store/statements/selectors/statements-store-state.selectors.ts
index 746f49f..9dca721 100644
--- a/src/app/store/statements/selectors/statements-store-state.selectors.ts
+++ b/src/app/store/statements/selectors/statements-store-state.selectors.ts
@@ -25,6 +25,11 @@
     selectPropertyProjector("search")
 );
 
+export const getStatementPositionSearchSelector = createSelector(
+    statementsStoreStateSelector,
+    selectPropertyProjector("positions")
+);
+
 export const getStatementLoadingSelector = createSelector(
     statementsStoreStateSelector,
     selectPropertyProjector("loading", {})
diff --git a/src/app/store/statements/statements-reducers.token.ts b/src/app/store/statements/statements-reducers.token.ts
index 5bf5ac6..071408f 100644
--- a/src/app/store/statements/statements-reducers.token.ts
+++ b/src/app/store/statements/statements-reducers.token.ts
@@ -21,6 +21,7 @@
     statementLoadingReducer,
     statementSearchReducer
 } from "./reducers";
+import {statementPositionsSearchReducer} from "./reducers/search/statement-positions-search.reducer";
 
 export const STATEMENTS_NAME = "statements";
 
@@ -31,6 +32,7 @@
         entities: statementEntitiesReducer,
         error: statementErrorReducer,
         search: statementSearchReducer,
+        positions: statementPositionsSearchReducer,
         loading: statementLoadingReducer
     })
 });
diff --git a/src/app/store/statements/statements-store.module.ts b/src/app/store/statements/statements-store.module.ts
index a8880fc..093e803 100644
--- a/src/app/store/statements/statements-store.module.ts
+++ b/src/app/store/statements/statements-store.module.ts
@@ -19,6 +19,7 @@
     CompileStatementArrangementEffect,
     FetchStatementDetailsEffect,
     FetchTextArrangementEffect,
+    SearchStatementPositionsEffect,
     SearchStatementsEffect,
     SubmitStatementInformationFormEffect,
     SubmitWorkflowFormEffect,
@@ -37,6 +38,7 @@
             FetchStatementDetailsEffect,
             FetchTextArrangementEffect,
             SearchStatementsEffect,
+            SearchStatementPositionsEffect,
             SubmitStatementEditorFormEffect,
             SubmitStatementInformationFormEffect,
             SubmitWorkflowFormEffect,
diff --git a/src/assets/i18n/de.i18.json b/src/assets/i18n/de.i18.json
index d12efee..3b1bd96 100644
--- a/src/assets/i18n/de.i18.json
+++ b/src/assets/i18n/de.i18.json
@@ -7,7 +7,8 @@
     "submitting": "Daten werden übertragen...",
     "header": {
       "home": "Übersicht",
-      "search": "Stellungnahme suchen",
+      "search": "Stellungnahme suchen (Liste)",
+      "searchMap": "Stellungnahme suchen (Karte)",
       "mail": "Posteingang",
       "new": "Neue Stellungnahme anlegen",
       "settings": "Einstellungen",
@@ -82,6 +83,36 @@
       "completeIssue": "Vorgang manuell abschließen",
       "disapprove": "Nachbearbeitung anstoßen",
       "approve": "Stellungnahme genehmigen"
+    },
+    "attachments": {
+      "title": "Eingangsdokumente",
+      "filter": "Filter",
+      "noResult": "Keine Anhänge vorhanden.",
+      "emailDocuments": "Email-Dokumente",
+      "email": "Email",
+      "placeholder": "Es sind keine Anhänge zu der Stellungnahme vorhanden."
+    },
+    "outbox": {
+      "title": "Ausgangsdokumente",
+      "statement": "Stellungnahme",
+      "attachments": "Anhänge",
+      "placeholder": "Es sind keine Anhänge zu der Stellungnahme vorhanden."
+    },
+    "considerations": {
+      "title": "Abwägungsergebnis",
+      "attachments": "Dokumente",
+      "upload": "Hochladen",
+      "placeholder": "Es sind keine Abwägungsergebnisse zu der Stellungnahme vorhanden."
+    },
+    "contributions": {
+      "placeholder": "Es wurden keine Fachbereiche zur Bearbeitung ausgewählt."
+    },
+    "geoPositions": {
+      "placeholder": "Es wurde keine Position zu der Stellungnahme hinterlegt."
+    },
+    "linkedStatements": {
+      "title": "Verknüpfte Vorgänge",
+      "placeholder": "Es gibt keine verlinkten Stellungnahmen."
     }
   },
   "edit": {
@@ -152,7 +183,8 @@
       "city": "Ort:",
       "district": "Ortsteil:",
       "typeId": "Art des Vorgangs:",
-      "customerReference": "Referenzzeichen:"
+      "customerReference": "Referenzzeichen:",
+      "sectors": "Betroffene Sparten:"
     }
   },
   "workflowDataForm": {
@@ -189,9 +221,15 @@
       "contributionStatus": "Bearbeitungsstatus der Fachbereiche",
       "draft": "Entwurf der Stellungnahme",
       "attachments": "Anhänge für den Versand"
+    },
+    "contributions": {
+      "placeholder": "Es gibt keine verlinkten Stellungnahmen."
     }
   },
   "shared": {
+    "pagination": {
+      "size": "Einträge pro Seite"
+    },
     "map": {
       "openGIS": "Im GIS öffnen"
     },
@@ -234,6 +272,7 @@
       "failedMailTransfer": "Beim Transferieren der Email ist ein Fehler aufgetreten. Bitte prüfen Sie Ihre Auswahl und versuchen Sie es erneut.",
       "invalidTextArrangement": "Die Zusammenstellung der Stellungnahme weist Fehler auf. Bitte prüfen Sie die Auswahl an Textbausteinen.",
       "couldNotLoadMailData": "Die Daten der ausgewählten Email konnten nicht geladen werden. Eventuell besteht ein Problem mit der Verbindung zum Mail-Server. Bitte versuchen Sie es nocheinmal oder kontaktieren Sie den Support.",
+      "couldNotSendMail": "Die Email konnte nicht an die hinterlegte Email-Adresse verschickt werden. Bitte prüfen Sie die Kontaktinformationen oder versenden Sie die Stellungnahme manuell.",
       "noAccessToContactModule": "Der Zugriff auf das Kontaktstammdatenmodul ist nicht möglich. Bitte kontaktieren Sie den Support."
     }
   },
@@ -260,5 +299,20 @@
     "at": "vom:",
     "inbox": "Email Eingang",
     "attachments": "Anhänge"
+  },
+  "search": {
+    "title": "Suche",
+    "executeSearch": "Nach Stellungnahmen suchen...",
+    "type": "Vorgangstyp",
+    "noData": "Keine Daten verfügbar...",
+    "creationDateFrom": "Erstellungsdatum von:",
+    "creationDateTo": "Erstellungsdatum bis:",
+    "receiptDateFrom": "Eingang von:",
+    "receiptDateTo": "Eingang bis:",
+    "dueDateFrom": "Frist von:",
+    "dueDateTo": "Frist bis:",
+    "finished": "Abgeschlossen",
+    "open": "Offen",
+    "editedByMe": "Eigene Vorgänge"
   }
 }
diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts
index 66dc98e..549464f 100644
--- a/src/environments/environment.prod.ts
+++ b/src/environments/environment.prod.ts
@@ -16,7 +16,5 @@
 export const environment = {
     production: true,
     version: npm.version,
-    routes: {...npm.routes},
-    leaflet: {...npm.leaflet},
     imports: []
 };
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 99596a3..2e28e37 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -21,8 +21,6 @@
 export const environment = {
     production: false,
     version: npm.version + "dev",
-    routes: {...npm.routes},
-    leaflet: {...npm.leaflet},
     imports: [
         StoreDevtoolsModule.instrument({maxAge: 50, logOnly: false})
     ]
diff --git a/src/theme/leaflet/_leaflet.theme.scss b/src/theme/leaflet/_leaflet.theme.scss
index f810012..06feb1f 100644
--- a/src/theme/leaflet/_leaflet.theme.scss
+++ b/src/theme/leaflet/_leaflet.theme.scss
@@ -32,3 +32,7 @@
     content: "place";
   }
 }
+
+.leaflet-popup-content-wrapper {
+  @include rounded-border-mixin();
+}