diff --git a/client/.gitlab-ci.yml b/client/.gitlab-ci.yml
index f803db047618684ee122a8bb17322c98f4d9dd8f..471927d9567a05ac6c960c17f1ee9be770595e96 100644
--- a/client/.gitlab-ci.yml
+++ b/client/.gitlab-ci.yml
@@ -4,6 +4,7 @@ stages:
     - sonar
     - build
     - dockerize
+    - deploy
 
 variables:
     VERSION: "3.7.0"
@@ -81,3 +82,17 @@ dockerize:
         - docker pull $CI_REGISTRY/anis/anis-next/client:latest || true
         - docker build --cache-from $CI_REGISTRY/anis/anis-next/client:latest -t $CI_REGISTRY/anis/anis-next/client:latest .
         - docker push $CI_REGISTRY/anis/anis-next/client:latest
+
+deploy:
+    image: alpine
+    stage: deploy
+    variables:
+        GIT_STRATEGY: none
+    cache: {}
+    dependencies: []
+    script:
+        - apk add --update curl
+        - curl -XPOST $DEV_WEBHOOK_CLIENT
+    only:
+        refs:
+            - develop
\ No newline at end of file
diff --git a/client/src/app/admin/admin-auth.guard.ts b/client/src/app/admin/admin-auth.guard.ts
index 02ac7a5e6dea1d5f36f8abb33b1a912d2c75d9e5..2658bb975516deac79518857d4d126a3636efdbf 100644
--- a/client/src/app/admin/admin-auth.guard.ts
+++ b/client/src/app/admin/admin-auth.guard.ts
@@ -9,8 +9,8 @@
 
 import { Injectable } from '@angular/core';
 import { CanActivate, Router } from '@angular/router';
-import { Store, select } from '@ngrx/store';
 
+import { Store, select } from '@ngrx/store';
 import { combineLatest, Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 
diff --git a/client/src/app/admin/components/dataset/dataset-form.component.html b/client/src/app/admin/components/dataset/dataset-form.component.html
index 1fd269376ba2d3fa1a15e3bc7343f840f0644f8b..de298ce4182901d61df57cfe5f9b24183f0192ad 100644
--- a/client/src/app/admin/components/dataset/dataset-form.component.html
+++ b/client/src/app/admin/components/dataset/dataset-form.component.html
@@ -45,7 +45,7 @@
                 [rootDirectory]="rootDirectory"
                 [rootDirectoryIsLoading]="rootDirectoryIsLoading"
                 [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
-                (loadRootDirectory)="loadRootDirectory.emit($event)">
+                (loadRootDirectory)="onChangeDataPath($event)">
             </app-data-path-form-control>
             <div class="form-group">
                 <label for="display">Display</label>
@@ -60,6 +60,7 @@
                 <label class="custom-control-label" for="private"><i class="fas fa-lock"></i> Private</label>
             </div>
         </accordion-group>
+        <app-info-survey-form-group [form]="infoSurveyFormGroup"></app-info-survey-form-group>
         <app-image-form-group [form]="imageFormGroup" [isDisabled]="isNewDataset"></app-image-form-group>
         <app-cone-search-form-group [form]="coneSearchFormGroup" [isDisabled]="isNewDataset" [attributeList]="attributeList"></app-cone-search-form-group>
         <app-download-form-group [form]="downloadFormGroup"></app-download-form-group>
diff --git a/client/src/app/admin/components/dataset/dataset-form.component.ts b/client/src/app/admin/components/dataset/dataset-form.component.ts
index bf60f446235962f3101a7f97409400fb74196efd..db9f0b6f2a2c5335dddb6786d640081e0372482f 100644
--- a/client/src/app/admin/components/dataset/dataset-form.component.ts
+++ b/client/src/app/admin/components/dataset/dataset-form.component.ts
@@ -10,13 +10,14 @@
 import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';
 import { FormGroup, FormControl, Validators } from '@angular/forms';
 
-import { Dataset, Survey, DatasetFamily, FileInfo, Attribute } from 'src/app/metamodel/models';
+import { Instance, Dataset, Survey, DatasetFamily, FileInfo, Attribute } from 'src/app/metamodel/models';
 
 @Component({
     selector: 'app-dataset-form',
     templateUrl: 'dataset-form.component.html'
 })
 export class DatasetFormComponent implements OnInit, OnChanges {
+    @Input() instance: Instance;
     @Input() dataset: Dataset;
     @Input() surveyList: Survey[];
     @Input() tableListIsLoading: boolean;
@@ -34,6 +35,11 @@ export class DatasetFormComponent implements OnInit, OnChanges {
 
     public isNewDataset = true;
 
+    public infoSurveyFormGroup = new FormGroup({
+        survey_enabled: new FormControl(false),
+        survey_label: new FormControl('More about this survey', [Validators.required])
+    });
+
     public imageFormGroup = new FormGroup({
 
     });
@@ -90,6 +96,7 @@ export class DatasetFormComponent implements OnInit, OnChanges {
         display: new FormControl('', [Validators.required]),
         public: new FormControl('', [Validators.required]),
         config: new FormGroup({
+            survey: this.infoSurveyFormGroup,
             cone_search: this.coneSearchFormGroup,
             download: this.downloadFormGroup,
             summary: this.summaryFormGroup,
@@ -137,4 +144,8 @@ export class DatasetFormComponent implements OnInit, OnChanges {
             this.changeSurvey.emit(this.surveyList.find(survey => survey.name === surveyName).id_database);
         }
     }
+
+    onChangeDataPath(path: string) {
+        this.loadRootDirectory.emit(this.instance.data_path + path);
+    }
 }
diff --git a/client/src/app/admin/components/dataset/index.ts b/client/src/app/admin/components/dataset/index.ts
index da36d39910a4ed5d8a212d899df6302795d74c8c..aad69881885c74aa8e385059e914a4ab6d0ed481 100644
--- a/client/src/app/admin/components/dataset/index.ts
+++ b/client/src/app/admin/components/dataset/index.ts
@@ -9,7 +9,7 @@
 
 import { DatasetCardComponent } from './dataset-card.component';
 import { DatasetFormComponent } from './dataset-form.component';
-import { DataPathFormControlComponent } from './data-path-form-control.component';
+import { InfoSurveyFormGroupComponent } from './info-survey-form-group.component';
 import { ImageFormGroupComponent } from './image-form-group.component';
 import { ConeSearchFormGroupComponent } from './cone-search-form-group.component';
 import { DownloadFormGroupComponent } from './download-form-group.component';
@@ -21,7 +21,7 @@ import { DatatableFormGroupComponent } from './datatable-form-group.component';
 export const datasetComponents = [
     DatasetCardComponent,
     DatasetFormComponent,
-    DataPathFormControlComponent,
+    InfoSurveyFormGroupComponent,
     ImageFormGroupComponent,
     ConeSearchFormGroupComponent,
     DownloadFormGroupComponent,
diff --git a/client/src/app/admin/components/dataset/info-survey-form-group.component.html b/client/src/app/admin/components/dataset/info-survey-form-group.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..df4f4f612c48f2d84f72299ed58d689b96c60b64
--- /dev/null
+++ b/client/src/app/admin/components/dataset/info-survey-form-group.component.html
@@ -0,0 +1,12 @@
+<form [formGroup]="form" novalidate>
+    <accordion-group heading="Info survey">
+        <div class="custom-control custom-switch">
+            <input class="custom-control-input" type="checkbox" id="survey_enabled" name="survey_enabled" formControlName="survey_enabled">
+            <label class="custom-control-label" for="survey_enabled">Enabled</label>
+        </div>
+        <div class="form-group">
+            <label for="survey_label">Label</label>
+            <input type="text" class="form-control" id="survey_label" name="survey_label" formControlName="survey_label">
+        </div>
+    </accordion-group>
+</form>
\ No newline at end of file
diff --git a/client/src/app/admin/components/dataset/info-survey-form-group.component.ts b/client/src/app/admin/components/dataset/info-survey-form-group.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9e2ae468b15fcca7274e0c5d3791610f7f3d584c
--- /dev/null
+++ b/client/src/app/admin/components/dataset/info-survey-form-group.component.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+@Component({
+    selector: 'app-info-survey-form-group',
+    templateUrl: 'info-survey-form-group.component.html'
+})
+export class InfoSurveyFormGroupComponent {
+    @Input() form: FormGroup;
+}
diff --git a/client/src/app/admin/components/instance/design-form-group.component.html b/client/src/app/admin/components/instance/design-form-group.component.html
index be9ed62b499b9719d3d299e38ec3f022c400efa8..7acdef818abaf83e53e31bbf92d84e168bc120ef 100644
--- a/client/src/app/admin/components/instance/design-form-group.component.html
+++ b/client/src/app/admin/components/instance/design-form-group.component.html
@@ -1,16 +1,34 @@
 <form [formGroup]="form" novalidate>
     <accordion-group heading="Design">
-
         <div class="form-row">
             <div class="form-group col-md-6">
-                <label for="design_color_picker">Color picker</label>
+                <label for="design_color_picker">Instance color (picker)</label>
                 <input class="form-control" type="color" id="design_color_picker" [value]="form.value.design_color" formControlName="design_color">
             </div>
             <div class="form-group col-md-6">
-                <label for="design_color_input">Color value</label>
+                <label for="design_color_input">Instance color (value)</label>
                 <input type="text" class="form-control" id="design_color_input" [value]="form.value.design_color" formControlName="design_color">
             </div>
         </div>
-
+        <app-file-select-form-control
+            [form]="form"
+            [disabled]="dataPathEmpty"
+            [controlName]="'design_logo'"
+            [controlLabel]="'Logo'"
+            [rootDirectory]="rootDirectory"
+            [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+            [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+            (loadRootDirectory)="loadRootDirectory.emit($event)">
+        </app-file-select-form-control>
+        <app-file-select-form-control
+            [form]="form"
+            [disabled]="dataPathEmpty"
+            [controlName]="'design_favicon'"
+            [controlLabel]="'Favicon'"
+            [rootDirectory]="rootDirectory"
+            [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+            [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+            (loadRootDirectory)="loadRootDirectory.emit($event)">
+        </app-file-select-form-control>
     </accordion-group>
 </form>
diff --git a/client/src/app/admin/components/instance/design-form-group.component.ts b/client/src/app/admin/components/instance/design-form-group.component.ts
index 2c84d3c1c0e368851efaa05701fbfee90e03b1f9..aa233db08a9269146caae2d9a77fbc74de94596b 100644
--- a/client/src/app/admin/components/instance/design-form-group.component.ts
+++ b/client/src/app/admin/components/instance/design-form-group.component.ts
@@ -7,13 +7,20 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input } from '@angular/core';
+import { Component, Input, Output, EventEmitter } from '@angular/core';
 import { FormGroup } from '@angular/forms';
 
+import { FileInfo } from 'src/app/metamodel/models';
+
 @Component({
     selector: 'app-design-form-group',
     templateUrl: 'design-form-group.component.html'
 })
 export class DesignFormGroupComponent {
     @Input() form: FormGroup;
+    @Input() dataPathEmpty: boolean;
+    @Input() rootDirectory: FileInfo[];
+    @Input() rootDirectoryIsLoading: boolean;
+    @Input() rootDirectoryIsLoaded: boolean;
+    @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter();
 }
diff --git a/client/src/app/admin/components/instance/documentation-form-group.component.html b/client/src/app/admin/components/instance/documentation-form-group.component.html
index 43949bec841aef071475600ecf28745d50fb0a4f..4af970bf0aaff013360b5a39392a01d3e5961b80 100644
--- a/client/src/app/admin/components/instance/documentation-form-group.component.html
+++ b/client/src/app/admin/components/instance/documentation-form-group.component.html
@@ -1,8 +1,12 @@
 <form [formGroup]="form" novalidate>
     <accordion-group heading="Documentation">
-        <div class="custom-control custom-switch">
-            <input class="custom-control-input" type="checkbox" id="documentation_allowed" name="documentation_allowed" formControlName="documentation_allowed">
+        <div class="custom-control custom-switch mb-2">
+            <input class="custom-control-input" type="checkbox" id="documentation_allowed" name="documentation_allowed" formControlName="documentation_allowed" (change)="checkDisableDocumentationAllowed()">
             <label class="custom-control-label" for="documentation_allowed">Documentation allowed</label>
         </div>
+        <div class="form-group">
+            <label for="documentation_label">Label</label>
+            <input type="text" class="form-control" id="documentation_label" formControlName="documentation_label">
+        </div>
     </accordion-group>
 </form>
\ No newline at end of file
diff --git a/client/src/app/admin/components/instance/documentation-form-group.component.ts b/client/src/app/admin/components/instance/documentation-form-group.component.ts
index 5e69fa7e73d3621dbc284c060087619149fefe44..3355e39992fb470a29080bde244c33f9df32b144 100644
--- a/client/src/app/admin/components/instance/documentation-form-group.component.ts
+++ b/client/src/app/admin/components/instance/documentation-form-group.component.ts
@@ -16,4 +16,12 @@ import { FormGroup } from '@angular/forms';
 })
 export class DocumentationFormGroupComponent {
     @Input() form: FormGroup;
+
+    checkDisableDocumentationAllowed() {
+        if (this.form.controls.documentation_allowed.value) {
+            this.form.controls.documentation_label.enable();
+        } else {
+            this.form.controls.documentation_label.disable();
+        }
+    }
 }
diff --git a/client/src/app/admin/components/instance/home-form-group.component.html b/client/src/app/admin/components/instance/home-form-group.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..8ceb5c69277bd6f0727c0f481f0aa61f49d6bf33
--- /dev/null
+++ b/client/src/app/admin/components/instance/home-form-group.component.html
@@ -0,0 +1,25 @@
+<form [formGroup]="form" novalidate>
+    <accordion-group heading="Home">
+        <div class="form-group">
+            <label for="home_component">Component</label>
+            <select class="form-control" name="home_component" formControlName="home_component">
+                <option value="WelcomeComponent">WelcomeComponent</option>
+            </select>
+        </div>
+        <div formGroupName="home_config">
+            <div class="form-group">
+                <label for="home_component_text">Text</label>
+                <textarea class="form-control" id="home_component_text" formControlName="home_component_text" rows="3"></textarea>
+            </div>
+            <app-file-select-form-control
+                [form]="getHomeConfigFormGroup()"
+                [controlName]="'home_component_logo'"
+                [controlLabel]="'Logo'"
+                [rootDirectory]="rootDirectory"
+                [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+                [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+                (loadRootDirectory)="loadRootDirectory.emit($event)">
+            </app-file-select-form-control>
+        </div>
+    </accordion-group>
+</form>
diff --git a/client/src/app/admin/components/instance/home-form-group.component.ts b/client/src/app/admin/components/instance/home-form-group.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..df09361e62d91271ad60b5ec0b94579deeebfd48
--- /dev/null
+++ b/client/src/app/admin/components/instance/home-form-group.component.ts
@@ -0,0 +1,29 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+import { FileInfo } from 'src/app/metamodel/models';
+
+@Component({
+    selector: 'app-home-form-group',
+    templateUrl: 'home-form-group.component.html'
+})
+export class HomeFormGroupComponent {
+    @Input() form: FormGroup;
+    @Input() rootDirectory: FileInfo[];
+    @Input() rootDirectoryIsLoading: boolean;
+    @Input() rootDirectoryIsLoaded: boolean;
+    @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter();
+
+    getHomeConfigFormGroup() {
+        return this.form.controls.home_config as FormGroup;
+    }
+}
diff --git a/client/src/app/admin/components/instance/index.ts b/client/src/app/admin/components/instance/index.ts
index 47997603644fc0f5c165dc8aad02983b360ae23d..f3c08b32be425bd190195ef569961e962ca9a188 100644
--- a/client/src/app/admin/components/instance/index.ts
+++ b/client/src/app/admin/components/instance/index.ts
@@ -11,6 +11,7 @@ import { InstanceCardComponent } from './instance-card.component';
 import { InstanceButtonsComponent } from './instance-buttons.component';
 import { InstanceFormComponent } from './instance-form.component';
 import { DesignFormGroupComponent } from './design-form-group.component';
+import { HomeFormGroupComponent } from './home-form-group.component';
 import { SearchFormGroupComponent } from './search-form-group.component';
 import { DocumentationFormGroupComponent } from './documentation-form-group.component';
 
@@ -19,6 +20,7 @@ export const instanceComponents = [
     InstanceButtonsComponent,
     InstanceFormComponent,
     DesignFormGroupComponent,
+    HomeFormGroupComponent,
     SearchFormGroupComponent,
     DocumentationFormGroupComponent
 ];
diff --git a/client/src/app/admin/components/instance/instance-card.component.html b/client/src/app/admin/components/instance/instance-card.component.html
index e1fd448d4941c2e475df22c2b701002011bd379e..9c9aa4fa036fb5da6a51b7fd7368e7cff0745579 100644
--- a/client/src/app/admin/components/instance/instance-card.component.html
+++ b/client/src/app/admin/components/instance/instance-card.component.html
@@ -4,7 +4,6 @@
         <ul class="card-text list-unstyled pl-4">
             <li>Dataset families: <span class="badge badge-secondary">{{ instance.nb_dataset_families }}</span></li>
             <li>Datasets: <span class="badge badge-secondary">{{ instance.nb_datasets }}</span></li>
-            <li><a target="blank" href="{{instance.client_url}}">{{instance.client_url}}</a></li>
         </ul>
     </div>
     <div class="card-footer bg-transparent text-right">
diff --git a/client/src/app/admin/components/instance/instance-form.component.html b/client/src/app/admin/components/instance/instance-form.component.html
index abf027b3ad2fc6e116075cf6d9897837fa4a37bc..bf9b591dfd0280ef119cdb89144d90c5f7247af5 100644
--- a/client/src/app/admin/components/instance/instance-form.component.html
+++ b/client/src/app/admin/components/instance/instance-form.component.html
@@ -3,18 +3,35 @@
         <accordion-group heading="General information" [isOpen]="true">
             <div class="form-group">
                 <label for="name">Name</label>
-                <input id="name" type="text" class="form-control" id="name" name="name" formControlName="name">
+                <input type="text" class="form-control" id="name" name="name" formControlName="name">
             </div>
             <div class="form-group">
                 <label for="label">Label</label>
-                <input id="label" type="text" class="form-control" id="label" name="label" formControlName="label">
-            </div>
-            <div class="form-group">
-                <label for="client_url">Client URL</label>
-                <input id="client_url" type="text" class="form-control" id="client_url" name="client_url" formControlName="client_url">
+                <input type="text" class="form-control" id="label" name="label" formControlName="label">
             </div>
+            <app-data-path-form-control
+                [form]="form"
+                [rootDirectory]="rootDirectory"
+                [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+                [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+                (loadRootDirectory)="loadRootDirectory.emit($event)">
+            </app-data-path-form-control>
         </accordion-group>
-        <app-design-form-group [form]="designFormGroup"></app-design-form-group>
+        <app-design-form-group 
+            [form]="designFormGroup"
+            [dataPathEmpty]="isDataPathEmpty()"
+            [rootDirectory]="rootDirectory"
+            [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+            [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+            (loadRootDirectory)="onChangeSelectFile($event)">
+        </app-design-form-group>
+        <app-home-form-group
+            [form]="homeFormGroup"
+            [rootDirectory]="rootDirectory"
+            [rootDirectoryIsLoading]="rootDirectoryIsLoading"
+            [rootDirectoryIsLoaded]="rootDirectoryIsLoaded"
+            (loadRootDirectory)="onChangeSelectFile($event)">
+        </app-home-form-group>
         <app-search-form-group [form]="searchFormGroup"></app-search-form-group>
         <app-documentation-form-group [form]="documentationFormGroup"></app-documentation-form-group>
     </accordion>
diff --git a/client/src/app/admin/components/instance/instance-form.component.ts b/client/src/app/admin/components/instance/instance-form.component.ts
index 1463bfa2ef850b440bc79fc8d76c7a515bb94242..7ff24f3c62be53b8583e0328b4fec06f86ebd9db 100644
--- a/client/src/app/admin/components/instance/instance-form.component.ts
+++ b/client/src/app/admin/components/instance/instance-form.component.ts
@@ -10,7 +10,7 @@
 import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
 import { FormGroup, FormControl, Validators } from '@angular/forms';
 
-import { Instance } from 'src/app/metamodel/models';
+import { Instance, FileInfo } from 'src/app/metamodel/models';
 
 @Component({
     selector: 'app-instance-form',
@@ -18,28 +18,48 @@ import { Instance } from 'src/app/metamodel/models';
 })
 export class InstanceFormComponent implements OnInit {
     @Input() instance: Instance;
+    @Input() rootDirectory: FileInfo[];
+    @Input() rootDirectoryIsLoading: boolean;
+    @Input() rootDirectoryIsLoaded: boolean;
+    @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter();
     @Output() onSubmit: EventEmitter<Instance> = new EventEmitter();
 
     public designFormGroup = new FormGroup({
-        design_color: new FormControl('', [Validators.required])
+        design_color: new FormControl('#7AC29A', [Validators.required]),
+        design_logo: new FormControl(''),
+        design_favicon: new FormControl('')
+    });
+
+    public homeFormGroup = new FormGroup({
+        home_component: new FormControl('WelcomeComponent', [Validators.required]),
+        home_config: new FormGroup({
+            home_component_text: new FormControl(`AstroNomical Information System is a generic web tool aimed 
+at facilitating and homogenizing the implementation of astronomical data. It allows 
+the fast implementation of a project data exchange platform in a dedicated information system.`, [Validators.required]),
+            home_component_logo: new FormControl('home_component_logo.png', [Validators.required])
+        })
     });
 
     public searchFormGroup = new FormGroup({
         search_by_criteria_allowed: new FormControl(true),
+        search_by_criteria_label: new FormControl({value: 'Search', disabled: false}),
         search_multiple_allowed: new FormControl(false),
+        search_multiple_label: new FormControl({value: 'Search multiple', disabled: true}),
         search_multiple_all_datasets_selected: new FormControl({value: false, disabled: true})
     });
 
     public documentationFormGroup = new FormGroup({
-        documentation_allowed: new FormControl(false)
+        documentation_allowed: new FormControl(false),
+        documentation_label: new FormControl({value: 'Documentation', disabled: true})
     });
 
     public form = new FormGroup({
         name: new FormControl('', [Validators.required]),
         label: new FormControl('', [Validators.required]),
-        client_url: new FormControl('', [Validators.required]),
+        data_path: new FormControl(''),
         config: new FormGroup({
             design: this.designFormGroup,
+            home: this.homeFormGroup,
             search: this.searchFormGroup,
             documentation: this.documentationFormGroup
         })
@@ -48,12 +68,28 @@ export class InstanceFormComponent implements OnInit {
     ngOnInit() {
         if (this.instance) {
             this.form.patchValue(this.instance);
+            this.form.controls.name.disable();
             if (this.searchFormGroup.controls.search_multiple_allowed.value) {
+                this.searchFormGroup.controls.search_multiple_label.enable();
                 this.searchFormGroup.controls.search_multiple_all_datasets_selected.enable();
             }
+            if (this.searchFormGroup.controls.search_by_criteria_allowed.value) {
+                this.searchFormGroup.controls.search_by_criteria_label.enable();
+            }
+            if (this.documentationFormGroup.controls.documentation_allowed.value) {
+                this.documentationFormGroup.controls.documentation_label.enable();
+            }
         }
     }
 
+    onChangeSelectFile(path: string) {
+        this.loadRootDirectory.emit(this.form.controls.data_path.value + path);
+    }
+
+    isDataPathEmpty() {
+        return this.form.controls.data_path.value == '';
+    }
+
     submit() {
         if (this.instance) {
             this.onSubmit.emit({
diff --git a/client/src/app/admin/components/instance/search-form-group.component.html b/client/src/app/admin/components/instance/search-form-group.component.html
index 4caf2ca71094ea702d08103fad8bfd4b1c586c6b..1c12343c9f1747b887de2f015f3ad760a90bf962 100644
--- a/client/src/app/admin/components/instance/search-form-group.component.html
+++ b/client/src/app/admin/components/instance/search-form-group.component.html
@@ -1,13 +1,21 @@
 <form [formGroup]="form" novalidate>
     <accordion-group heading="Search">
-        <div class="custom-control custom-switch">
-            <input class="custom-control-input" type="checkbox" id="search_by_criteria_allowed" name="search_by_criteria_allowed" formControlName="search_by_criteria_allowed">
+        <div class="custom-control custom-switch mb-2">
+            <input class="custom-control-input" type="checkbox" id="search_by_criteria_allowed" name="search_by_criteria_allowed" formControlName="search_by_criteria_allowed" (change)="checkDisableSearchByCriteriaAllowed()">
             <label class="custom-control-label" for="search_by_criteria_allowed">Classic search allowed</label>
         </div>
-        <div class="custom-control custom-switch">
+        <div class="form-group">
+            <label for="search_by_criteria_label">Label</label>
+            <input type="text" class="form-control" id="search_by_criteria_label" formControlName="search_by_criteria_label">
+        </div>
+        <div class="custom-control custom-switch mb-2">
             <input class="custom-control-input" type="checkbox" id="search_multiple_allowed" name="search_multiple_allowed" formControlName="search_multiple_allowed" (change)="checkDisableAllDatasetsSelected()">
             <label class="custom-control-label" for="search_multiple_allowed">Search multiple allowed</label>
         </div>
+        <div class="form-group">
+            <label for="search_multiple_label">Label</label>
+            <input type="text" class="form-control" id="search_multiple_label" formControlName="search_multiple_label">
+        </div>
         <div class="custom-control custom-switch">
             <input class="custom-control-input"
                 type="checkbox"
diff --git a/client/src/app/admin/components/instance/search-form-group.component.ts b/client/src/app/admin/components/instance/search-form-group.component.ts
index 3751aa37e05eab0c2bc390501882e1e88940e59b..4a96c1bfed521b6097ff19b9ee355bde36f22cb2 100644
--- a/client/src/app/admin/components/instance/search-form-group.component.ts
+++ b/client/src/app/admin/components/instance/search-form-group.component.ts
@@ -17,10 +17,20 @@ import { FormGroup } from '@angular/forms';
 export class SearchFormGroupComponent {
     @Input() form: FormGroup;
 
+    checkDisableSearchByCriteriaAllowed() {
+        if (this.form.controls.search_by_criteria_allowed.value) {
+            this.form.controls.search_by_criteria_label.enable();
+        } else {
+            this.form.controls.search_by_criteria_label.disable();
+        }
+    }
+
     checkDisableAllDatasetsSelected() {
         if (this.form.controls.search_multiple_allowed.value) {
+            this.form.controls.search_multiple_label.enable();
             this.form.controls.search_multiple_all_datasets_selected.enable();
         } else {
+            this.form.controls.search_multiple_label.disable();
             this.form.controls.search_multiple_all_datasets_selected.setValue(false);
             this.form.controls.search_multiple_all_datasets_selected.disable();
         }
diff --git a/client/src/app/admin/components/dataset/data-path-form-control.component.html b/client/src/app/admin/components/shared/data-path-form-control.component.html
similarity index 100%
rename from client/src/app/admin/components/dataset/data-path-form-control.component.html
rename to client/src/app/admin/components/shared/data-path-form-control.component.html
diff --git a/client/src/app/admin/components/dataset/data-path-form-control.component.ts b/client/src/app/admin/components/shared/data-path-form-control.component.ts
similarity index 98%
rename from client/src/app/admin/components/dataset/data-path-form-control.component.ts
rename to client/src/app/admin/components/shared/data-path-form-control.component.ts
index 2ca19b2342670c2b7733ae960159abde94a84328..00675df16e4ebf6163c7c1a71ab98ad6e53bfee1 100644
--- a/client/src/app/admin/components/dataset/data-path-form-control.component.ts
+++ b/client/src/app/admin/components/shared/data-path-form-control.component.ts
@@ -58,6 +58,7 @@ export class DataPathFormControlComponent {
 
     selectDirectory() {
         this.form.controls.data_path.setValue(this.fileExplorerPath);
+        this.form.markAsDirty();
         this.modalRef.hide();
     }
 }
diff --git a/client/src/app/admin/components/shared/file-select-form-control.component.html b/client/src/app/admin/components/shared/file-select-form-control.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..c288526eec2f32f327f15cc0ed067c7f559720d4
--- /dev/null
+++ b/client/src/app/admin/components/shared/file-select-form-control.component.html
@@ -0,0 +1,60 @@
+<form [formGroup]="form" novalidate>
+    <div class="form-group">
+        <label for="{{ controlName }}">{{ controlLabel }}</label>
+        <div class="input-group mb-3">
+            <div class="input-group-prepend">
+                <button [disabled]="disabled" (click)="openModal(template); $event.stopPropagation()" class="btn btn-outline-secondary" type="button">
+                    <i class="fas fa-folder-open"></i>
+                </button>
+            </div>
+            <input type="text" class="form-control" id="{{ controlName }}" name="{{ controlName }}" formControlName="{{ controlName }}">
+        </div>
+    </div>
+</form>
+
+<ng-template #template>
+    <div class="modal-header">
+        <h4 class="modal-title pull-left">ANIS file explorer</h4>
+    </div>
+    <div>
+        <app-spinner *ngIf="rootDirectoryIsLoading"></app-spinner>
+
+        <p class="ml-3 mt-3">
+            <i class="far fa-folder"></i>
+            {{ fileExplorerPath }}
+        </p>
+        <div *ngIf="rootDirectoryIsLoaded" class="table-responsive">
+            <table class="table table-hover">
+                <thead>
+                    <tr>
+                        <th></th>
+                        <th scope="col">Name</th>
+                        <th scope="col">Size</th>
+                        <th scope="col">MimeType</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr *ngFor="let fileInfo of rootDirectory" 
+                        (click)="click(fileInfo)" 
+                        [class.table-active]="checkFileSelected(fileInfo)"
+                        [class.pointer]="fileInfo.name !== '.'">
+                        <td>
+                            <span *ngIf="fileInfo.type === 'dir'"><i class="far fa-folder"></i></span>
+                            <span *ngIf="fileInfo.type === 'file'"><i class="far fa-file"></i></span>
+                        </td>
+                        <td class="align-middle">
+                            {{ fileInfo.name }}
+                        </td>
+                        <td class="align-middle">{{ fileInfo.size | formatFileSize: false }}</td>
+                        <td class="align-middle">{{ fileInfo.mimetype }}</td>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+    <div class="modal-footer">
+        <button (click)="modalRef.hide()" class="btn btn-danger">Cancel</button>
+        &nbsp;
+        <button [disabled]="!fileSelected" (click)="selectFile()" class="btn btn-primary">Select this file</button>
+    </div>
+</ng-template>
diff --git a/client/src/app/admin/components/shared/file-select-form-control.component.ts b/client/src/app/admin/components/shared/file-select-form-control.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7192d97fb8f10cbcb41c1294247e93e290e3b920
--- /dev/null
+++ b/client/src/app/admin/components/shared/file-select-form-control.component.ts
@@ -0,0 +1,93 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input, Output, TemplateRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+import { BsModalService } from 'ngx-bootstrap/modal';
+import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
+
+import { FileInfo } from 'src/app/metamodel/models';
+
+@Component({
+    selector: 'app-file-select-form-control',
+    templateUrl: 'file-select-form-control.component.html'
+})
+export class FileSelectFormControlComponent implements OnChanges {
+    @Input() form: FormGroup;
+    @Input() disabled: boolean = false;
+    @Input() controlName: string;
+    @Input() controlLabel: string;
+    @Input() rootDirectory: FileInfo[];
+    @Input() rootDirectoryIsLoading: boolean;
+    @Input() rootDirectoryIsLoaded: boolean;
+    @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter();
+
+    modalRef: BsModalRef;
+    fileExplorerPath = '';
+    fileSelected = null;
+
+    constructor(private modalService: BsModalService) { }
+
+    ngOnChanges(changes: SimpleChanges) {
+        if (changes.disabled && changes.disabled.currentValue) {
+            this.form.controls[this.controlName].disable();
+        }
+
+        if (changes.disabled && !changes.disabled.currentValue) {
+            this.form.controls[this.controlName].enable();
+        }
+    }
+
+    openModal(template: TemplateRef<any>) {
+        const lastIndexOf = this.form.controls[this.controlName].value.lastIndexOf("/");
+        this.fileExplorerPath = this.form.controls[this.controlName].value.substr(0, lastIndexOf);
+        if (!this.fileExplorerPath) {
+            this.fileExplorerPath = '';
+        }
+        this.modalRef = this.modalService.show(template);
+        this.loadRootDirectory.emit(this.fileExplorerPath);
+    }
+
+    click(fileInfo: FileInfo): void {
+        if (fileInfo.name === '.') {
+            return;
+        }
+
+        if (fileInfo.type === 'file') {
+            this.fileSelected = this.buildFilePath(fileInfo);
+            return;
+        }
+
+        if (fileInfo.name === '..') {
+            this.fileExplorerPath = this.fileExplorerPath.substr(0, this.fileExplorerPath.lastIndexOf("/"));
+        } else {
+            this.fileExplorerPath += '/' + fileInfo.name;
+        }
+        this.loadRootDirectory.emit(this.fileExplorerPath);
+    }
+
+    buildFilePath(fileInfo: FileInfo) {
+        let fileSelected = '';
+        if (this.fileExplorerPath !== '') {
+            fileSelected += this.fileExplorerPath + '/';
+        }
+        return fileSelected + fileInfo.name;
+    }
+
+    checkFileSelected(fileInfo: FileInfo) {
+        return this.buildFilePath(fileInfo) === this.fileSelected;
+    }
+
+    selectFile() {
+        this.form.controls[this.controlName].setValue(this.fileSelected);
+        this.form.markAsDirty();
+        this.modalRef.hide();
+    }
+}
diff --git a/client/src/app/admin/components/shared/index.ts b/client/src/app/admin/components/shared/index.ts
index 1e09eb0c9517cf076350a3a58196ce92e343e564..90937726cad9c4f7e83fc44b7506b46ab1ee1c6e 100644
--- a/client/src/app/admin/components/shared/index.ts
+++ b/client/src/app/admin/components/shared/index.ts
@@ -7,8 +7,12 @@
  * file that was distributed with this source code.
  */
 
-import { DeleteBtnComponent } from "./delete-btn.component";
+import { DeleteBtnComponent } from './delete-btn.component';
+import { DataPathFormControlComponent } from './data-path-form-control.component';
+import { FileSelectFormControlComponent } from './file-select-form-control.component';
 
 export const sharedComponents = [
-    DeleteBtnComponent
+    DeleteBtnComponent,
+    DataPathFormControlComponent,
+    FileSelectFormControlComponent
 ];
diff --git a/client/src/app/admin/containers/dataset/edit-dataset.component.html b/client/src/app/admin/containers/dataset/edit-dataset.component.html
index cded4c68c26e75fb31c2dbda1bb123dd46afdd3b..bc6e45c008f33fdf7a0920dd85986f68ccd97312 100644
--- a/client/src/app/admin/containers/dataset/edit-dataset.component.html
+++ b/client/src/app/admin/containers/dataset/edit-dataset.component.html
@@ -5,8 +5,8 @@
                 <a routerLink="/admin/instance-list">Instances</a>
             </li>
             <li class="breadcrumb-item active" aria-current="page">
-                <a routerLink="/admin/configure-instance/{{ instanceSelected | async }}">
-                    Configure instance {{ instanceSelected | async }}
+                <a routerLink="/admin/configure-instance/{{ (instance | async).name }}">
+                    Configure instance {{ (instance | async).name }}
                 </a>
             </li>
             <li class="breadcrumb-item active" aria-current="page">Edit dataset {{ datasetSelected | async }}</li>
@@ -26,6 +26,7 @@
         && (datasetFamilyListIsLoaded | async)" class="row">
         <div class="col-12">
             <app-dataset-form
+                [instance]="instance | async"
                 [dataset]="datasetList | async | datasetByName:(datasetSelected | async)"
                 [surveyList]="surveyList | async"
                 [tableListIsLoading]="tableListIsLoading | async"
@@ -44,7 +45,7 @@
                     <i class="fa fa-database"></i> Update dataset information
                 </button>
                 &nbsp;
-                <a routerLink="/admin/configure-instance/{{instanceSelected | async}}" type="button" class="btn btn-danger">Cancel</a>
+                <a routerLink="/admin/configure-instance/{{ (instance | async).name }}" type="button" class="btn btn-danger">Cancel</a>
             </app-dataset-form>
         </div>
     </div>
diff --git a/client/src/app/admin/containers/dataset/edit-dataset.component.ts b/client/src/app/admin/containers/dataset/edit-dataset.component.ts
index ff37287e413592da229589c438a5a7d58a02a73d..a816c37aef2efbdfbf8846c463288bee305e851e 100644
--- a/client/src/app/admin/containers/dataset/edit-dataset.component.ts
+++ b/client/src/app/admin/containers/dataset/edit-dataset.component.ts
@@ -13,7 +13,7 @@ import { ActivatedRoute } from '@angular/router';
 import { Observable } from 'rxjs';
 import { Store } from '@ngrx/store';
 
-import { Survey, DatasetFamily, Dataset, Attribute, FileInfo } from 'src/app/metamodel/models';
+import { Instance, Survey, DatasetFamily, Dataset, Attribute, FileInfo } from 'src/app/metamodel/models';
 import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
 import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
 import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
@@ -31,7 +31,7 @@ import * as rootDirectorySelector from 'src/app/metamodel/selectors/root-directo
     templateUrl: 'edit-dataset.component.html'
 })
 export class EditDatasetComponent implements OnInit {
-    public instanceSelected: Observable<string>;
+    public instance: Observable<Instance>;
     public datasetSelected: Observable<string>;
     public datasetList: Observable<Dataset[]>;
     public datasetListIsLoading: Observable<boolean>;
@@ -53,7 +53,7 @@ export class EditDatasetComponent implements OnInit {
     public rootDirectoryIsLoaded: Observable<boolean>;
 
     constructor(private store: Store<{ }>, private route: ActivatedRoute) {
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
+        this.instance = store.select(instanceSelector.selectInstanceByRouteName);
         this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
         this.datasetList = store.select(datasetSelector.selectAllDatasets);
         this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
diff --git a/client/src/app/admin/containers/dataset/new-dataset.component.html b/client/src/app/admin/containers/dataset/new-dataset.component.html
index 9d43f2a4fcb8b824554fe1e975d14180c31f27de..ee7e59deb9b1429ce8ca8e11b1caa2f5bc74f5c5 100644
--- a/client/src/app/admin/containers/dataset/new-dataset.component.html
+++ b/client/src/app/admin/containers/dataset/new-dataset.component.html
@@ -5,8 +5,8 @@
                 <a routerLink="/admin/instance-list">Instances</a>
             </li>
             <li class="breadcrumb-item active" aria-current="page">
-                <a routerLink="/admin/configure-instance/{{ instanceSelected | async }}">
-                    Configure instance {{ instanceSelected | async }}
+                <a routerLink="/admin/configure-instance/{{ (instance | async).name }}">
+                    Configure instance {{ (instance | async).name }}
                 </a>
             </li>
             <li class="breadcrumb-item active" aria-current="page">New dataset</li>
@@ -20,6 +20,7 @@
     <div *ngIf="(surveyListIsLoaded | async) && (datasetFamilyListIsLoaded | async)" class="row">
         <div class="col-12">
             <app-dataset-form
+                [instance]="instance | async"
                 [surveyList]="surveyList | async"
                 [tableListIsLoading]="tableListIsLoading | async"
                 [tableListIsLoaded]="tableListIsLoaded | async"
@@ -37,7 +38,7 @@
                     <i class="fa fa-database"></i> Add new dataset
                 </button>
                 &nbsp;
-                <a routerLink="/admin/configure-instance/{{instanceSelected | async}}" type="button" class="btn btn-danger">Cancel</a>
+                <a routerLink="/admin/configure-instance/{{ (instance | async).name }}" type="button" class="btn btn-danger">Cancel</a>
             </app-dataset-form>
         </div>
     </div>
diff --git a/client/src/app/admin/containers/dataset/new-dataset.component.ts b/client/src/app/admin/containers/dataset/new-dataset.component.ts
index 3bf1f9f9d848111b204887eb85ddd094c2e8ac5e..a9de9b2f2c37f518eefce4740a8b8117782f75d8 100644
--- a/client/src/app/admin/containers/dataset/new-dataset.component.ts
+++ b/client/src/app/admin/containers/dataset/new-dataset.component.ts
@@ -14,7 +14,7 @@ import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { Store } from '@ngrx/store';
 
-import { Survey, DatasetFamily, Dataset, FileInfo } from 'src/app/metamodel/models';
+import { Instance, Survey, DatasetFamily, Dataset, FileInfo } from 'src/app/metamodel/models';
 import * as surveySelector from 'src/app/metamodel/selectors/survey.selector';
 import * as tableActions from 'src/app/metamodel/actions/table.actions';
 import * as tableSelector from 'src/app/metamodel/selectors/table.selector';
@@ -29,7 +29,7 @@ import * as rootDirectorySelector from 'src/app/metamodel/selectors/root-directo
     templateUrl: 'new-dataset.component.html'
 })
 export class NewDatasetComponent implements OnInit {
-    public instanceSelected: Observable<string>;
+    public instance: Observable<Instance>;
     public surveyListIsLoading: Observable<boolean>;
     public surveyListIsLoaded: Observable<boolean>;
     public surveyList: Observable<Survey[]>;
@@ -45,7 +45,7 @@ export class NewDatasetComponent implements OnInit {
     public rootDirectoryIsLoaded: Observable<boolean>;
 
     constructor(private store: Store<{ }>, private route: ActivatedRoute) {
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
+        this.instance = store.select(instanceSelector.selectInstanceByRouteName);
         this.surveyListIsLoading = store.select(surveySelector.selectSurveyListIsLoading);
         this.surveyListIsLoaded = store.select(surveySelector.selectSurveyListIsLoaded);
         this.surveyList = store.select(surveySelector.selectAllSurveys);
diff --git a/client/src/app/admin/containers/group/edit-group.component.html b/client/src/app/admin/containers/group/edit-group.component.html
index b568405ac87aed23f56fb2fce53ba8d7dcd0ed28..ef2c6413537669c3cd83a10c655598d4b639cb8c 100644
--- a/client/src/app/admin/containers/group/edit-group.component.html
+++ b/client/src/app/admin/containers/group/edit-group.component.html
@@ -2,17 +2,17 @@
     <nav aria-label="breadcrumb">
         <ol class="breadcrumb">
             <li class="breadcrumb-item">
-                <a routerLink="/instance-list">
+                <a routerLink="/admin/instance-list">
                     Instances
                 </a>
             </li>
             <li class="breadcrumb-item">
-                <a routerLink="/configure-instance/{{ instanceName | async }}">
+                <a routerLink="/admin//configure-instance/{{ instanceName | async }}">
                     Configure instance {{ instanceName | async }}
                 </a>
             </li>
             <li class="breadcrumb-item" aria-current="page">
-                <a routerLink="/configure-instance/{{ instanceName | async }}/group">
+                <a routerLink="/admin/configure-instance/{{ instanceName | async }}/group">
                     Groups
                 </a>
             </li>
diff --git a/client/src/app/admin/containers/instance/edit-instance.component.html b/client/src/app/admin/containers/instance/edit-instance.component.html
index 8db55ccca330f28e87bf795e46e36488f6adeeaa..cdd51e099a38c6ae296a0598b5d7691bcbc654da 100644
--- a/client/src/app/admin/containers/instance/edit-instance.component.html
+++ b/client/src/app/admin/containers/instance/edit-instance.component.html
@@ -10,7 +10,14 @@
 <div class="container">
     <div class="row">
         <div class="col-12">
-            <app-instance-form [instance]="instance | async" (onSubmit)="editInstance($event)" #formInstance>
+            <app-instance-form 
+                [instance]="instance | async"
+                [rootDirectory]="rootDirectory | async"
+                [rootDirectoryIsLoading]="rootDirectoryIsLoading | async"
+                [rootDirectoryIsLoaded]="rootDirectoryIsLoaded | async"
+                (loadRootDirectory)="loadRootDirectory($event)"
+                (onSubmit)="editInstance($event)"
+                #formInstance>
                 <button [disabled]="!formInstance.form.valid || formInstance.form.pristine" type="submit" class="btn btn-primary">
                     <span class="fa fa-database"></span> Update instance information
                 </button>
diff --git a/client/src/app/admin/containers/instance/edit-instance.component.ts b/client/src/app/admin/containers/instance/edit-instance.component.ts
index e26d6aa6da8962e82f56f01b61f1548cf27d7676..278e28cb6c2d8d583151cbf1373708acb58b937b 100644
--- a/client/src/app/admin/containers/instance/edit-instance.component.ts
+++ b/client/src/app/admin/containers/instance/edit-instance.component.ts
@@ -12,9 +12,11 @@ import { Component } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
 
-import { Instance } from 'src/app/metamodel/models';
+import { Instance, FileInfo } from 'src/app/metamodel/models';
 import * as instanceActions from 'src/app/metamodel/actions/instance.actions';
 import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as rootDirectoryActions from 'src/app/metamodel/actions/root-directory.actions';
+import * as rootDirectorySelector from 'src/app/metamodel/selectors/root-directory.selector';
 
 @Component({
     selector: 'app-edit-instance',
@@ -22,12 +24,22 @@ import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector
 })
 export class EditInstanceComponent {
     public instance: Observable<Instance>;
+    public rootDirectory: Observable<FileInfo[]>;
+    public rootDirectoryIsLoading: Observable<boolean>;
+    public rootDirectoryIsLoaded: Observable<boolean>;
 
     constructor(private store: Store<{ }>) {
         this.instance = store.select(instanceSelector.selectInstanceByRouteName);
+        this.rootDirectory = store.select(rootDirectorySelector.selectAllFileInfo);
+        this.rootDirectoryIsLoading = store.select(rootDirectorySelector.selectRootDirectoryIsLoading);
+        this.rootDirectoryIsLoaded = store.select(rootDirectorySelector.selectRootDirectoryIsLoaded);
     }
 
     editInstance(instance: Instance) {
         this.store.dispatch(instanceActions.editInstance({ instance }));
     }
+
+    loadRootDirectory(path: string) {
+        this.store.dispatch(rootDirectoryActions.loadRootDirectory({ path }));
+    }
 }
diff --git a/client/src/app/admin/containers/instance/new-instance.component.html b/client/src/app/admin/containers/instance/new-instance.component.html
index 3025b2d9246cf1ca41de390cb7df4a610a0a7c84..58d637cd740c2a2e9a1e67cefdc99ee0dab098c1 100644
--- a/client/src/app/admin/containers/instance/new-instance.component.html
+++ b/client/src/app/admin/containers/instance/new-instance.component.html
@@ -10,7 +10,13 @@
 <div class="container">
     <div class="row">
         <div class="col-12">
-            <app-instance-form (onSubmit)="addNewInstance($event)" #formInstance>
+            <app-instance-form
+                [rootDirectory]="rootDirectory | async"
+                [rootDirectoryIsLoading]="rootDirectoryIsLoading | async"
+                [rootDirectoryIsLoaded]="rootDirectoryIsLoaded | async"
+                (loadRootDirectory)="loadRootDirectory($event)"
+                (onSubmit)="addNewInstance($event)" 
+                #formInstance>
                 <button [disabled]="!formInstance.form.valid || formInstance.form.pristine" type="submit" class="btn btn-primary">
                     <span class="fa fa-database"></span> Add the new instance
                 </button>
diff --git a/client/src/app/admin/containers/instance/new-instance.component.ts b/client/src/app/admin/containers/instance/new-instance.component.ts
index abe0ab1936d78603e17a52fba962678110bc2b34..9c3383cf43af6ed532228bf34897d3d1b3d57333 100644
--- a/client/src/app/admin/containers/instance/new-instance.component.ts
+++ b/client/src/app/admin/containers/instance/new-instance.component.ts
@@ -10,17 +10,33 @@
 import { Component } from '@angular/core';
 import { Store } from '@ngrx/store';
 
-import { Instance } from 'src/app/metamodel/models';
-import * as instanceActions from 'src/app/metamodel/actions/instance.actions'
+import { Observable } from 'rxjs';
+
+import { Instance, FileInfo } from 'src/app/metamodel/models';
+import * as instanceActions from 'src/app/metamodel/actions/instance.actions';
+import * as rootDirectoryActions from 'src/app/metamodel/actions/root-directory.actions';
+import * as rootDirectorySelector from 'src/app/metamodel/selectors/root-directory.selector';
 
 @Component({
     selector: 'app-new-instance',
     templateUrl: 'new-instance.component.html'
 })
 export class NewInstanceComponent {
-    constructor(private store: Store<{ }>) { }
+    public rootDirectory: Observable<FileInfo[]>;
+    public rootDirectoryIsLoading: Observable<boolean>;
+    public rootDirectoryIsLoaded: Observable<boolean>;
+
+    constructor(private store: Store<{ }>) {
+        this.rootDirectory = store.select(rootDirectorySelector.selectAllFileInfo);
+        this.rootDirectoryIsLoading = store.select(rootDirectorySelector.selectRootDirectoryIsLoading);
+        this.rootDirectoryIsLoaded = store.select(rootDirectorySelector.selectRootDirectoryIsLoaded);
+    }
 
     addNewInstance(instance: Instance) {
         this.store.dispatch(instanceActions.addInstance({ instance }));
     }
+
+    loadRootDirectory(path: string) {
+        this.store.dispatch(rootDirectoryActions.loadRootDirectory({ path }));
+    }
 }
diff --git a/client/src/app/app-init.ts b/client/src/app/app-init.ts
index b3dc042681bc40d7d903a4e8585e2349fdff7613..6b9241ee9afd93090d03991dda756a79062137d4 100644
--- a/client/src/app/app-init.ts
+++ b/client/src/app/app-init.ts
@@ -7,12 +7,15 @@ import { Store } from '@ngrx/store';
 import { AppConfigService } from './app-config.service';
 import { initializeKeycloak } from 'src/app/auth/init.keycloak';
 
+import { environment } from 'src/environments/environment';
+
 function appInit(http: HttpClient, appConfigService: AppConfigService, keycloak: KeycloakService, store: Store<{ }>) {
     return () => {
-        return http.get('/assets/app.config.json')
+        return http.get(`${environment.apiUrl}/client-settings`)
             .toPromise()
             .then(data => {
                 Object.assign(appConfigService, data);
+                appConfigService.apiUrl = environment.apiUrl;
                 return appConfigService;
             })
             .then(appConfigService => {
diff --git a/client/src/app/app.reducer.ts b/client/src/app/app.reducer.ts
index d35a1319b646cc92f2b6057c6d6f54a421ffff2f..26c5ea0d66124663115b3bbbe53feb956c53fa28 100644
--- a/client/src/app/app.reducer.ts
+++ b/client/src/app/app.reducer.ts
@@ -10,6 +10,8 @@
 import { ActionReducerMap, ActionReducer, MetaReducer } from '@ngrx/store'; 
 import { RouterReducerState, routerReducer } from '@ngrx/router-store';
 
+import { environment } from 'src/environments/environment';
+
 export interface State {
     router: RouterReducerState;
 }
@@ -31,5 +33,7 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
         return nextState;
     };
 }
- 
-export const metaReducers: MetaReducer<any>[] = [debug];
+
+export const metaReducers: MetaReducer<any>[] = !environment.production
+    ? [debug]
+    : [];
diff --git a/client/src/app/auth/auth.actions.ts b/client/src/app/auth/auth.actions.ts
index 52da0604574a5b963966ee9e99312cf229c29d91..429574a4716d4c1db8670e584eed302f148fa37f 100644
--- a/client/src/app/auth/auth.actions.ts
+++ b/client/src/app/auth/auth.actions.ts
@@ -15,5 +15,5 @@ export const login = createAction('[Auth] Login');
 export const logout = createAction('[Auth] Logout');
 export const authSuccess = createAction('[Auth] Auth Success');
 export const loadUserProfileSuccess = createAction('[Auth] Load User Profile Success', props<{ userProfile: UserProfile }>());
-export const loadUserRoleSuccess = createAction('[Auth] Load User Roles Success', props<{ userRoles: string[] }>());
+export const loadUserRolesSuccess = createAction('[Auth] Load User Roles Success', props<{ userRoles: string[] }>());
 export const openEditProfile = createAction('[Auth] Edit Profile');
diff --git a/client/src/app/auth/auth.effects.ts b/client/src/app/auth/auth.effects.ts
index 69cefb0e2b4f468564a02cdcbafb631a22113e7f..bdb76a950fa0644e54dba3b9add95f7061e884bd 100644
--- a/client/src/app/auth/auth.effects.ts
+++ b/client/src/app/auth/auth.effects.ts
@@ -10,7 +10,7 @@
 import { Injectable } from '@angular/core';
 import { Actions, createEffect, ofType } from '@ngrx/effects';
 import { from } from 'rxjs';
-import { tap, switchMap } from 'rxjs/operators';
+import { tap, switchMap, withLatestFrom } from 'rxjs/operators';
 
 import { KeycloakService } from 'keycloak-angular';
 
@@ -51,7 +51,7 @@ export class AuthEffects {
                 .pipe(
                     switchMap(userProfile => [
                         authActions.loadUserProfileSuccess({ userProfile }),
-                        authActions.loadUserRoleSuccess({ userRoles: this.keycloak.getUserRoles() })
+                        authActions.loadUserRolesSuccess({ userRoles: this.keycloak.getUserRoles() }),
                     ])
                 )
             )
diff --git a/client/src/app/auth/auth.reducer.ts b/client/src/app/auth/auth.reducer.ts
index d0805affc1d7dfeb02d4b6f6c2cc2bf728c401c5..a516f9c9c9056ed0f26ded6a598f88a91a7f198b 100644
--- a/client/src/app/auth/auth.reducer.ts
+++ b/client/src/app/auth/auth.reducer.ts
@@ -34,7 +34,7 @@ export const authReducer = createReducer(
         ...state,
         userProfile
     })),
-    on(authActions.loadUserRoleSuccess, (state, { userRoles }) => ({
+    on(authActions.loadUserRolesSuccess, (state, { userRoles }) => ({
         ...state,
         userRoles
     }))
diff --git a/client/src/app/auth/init.keycloak.ts b/client/src/app/auth/init.keycloak.ts
index a5186253c05dd947ef3c8518fce6652ea60ced12..34ee8d9f7490c1d5f046dd676996fa9d50e97894 100644
--- a/client/src/app/auth/init.keycloak.ts
+++ b/client/src/app/auth/init.keycloak.ts
@@ -21,9 +21,15 @@ export function initializeKeycloak(keycloak: KeycloakService, store: Store<{ }>,
     }
 
     from(keycloak.keycloakEvents$).subscribe(event => {
+        if (event.type === KeycloakEventType.OnAuthLogout) {
+            store.dispatch(keycloakActions.logout());
+        }
         if (event.type === KeycloakEventType.OnAuthSuccess) {
             store.dispatch(keycloakActions.authSuccess());
         }
+        if (event.type === KeycloakEventType.OnAuthRefreshError) {
+            store.dispatch(keycloakActions.login());
+        }
     })
 
     let silentCheckSsoRedirectUri = window.location.origin;
@@ -42,6 +48,7 @@ export function initializeKeycloak(keycloak: KeycloakService, store: Store<{ }>,
             onLoad: 'check-sso',
             silentCheckSsoRedirectUri
         },
-        loadUserProfileAtStartUp: true
+        loadUserProfileAtStartUp: true,
+        bearerExcludedUrls: ['https://cdsweb.u-strasbg.fr/']
     });
 }
diff --git a/client/src/app/instance/documentation/components/dataset-by-family.component.spec.ts b/client/src/app/instance/documentation/components/dataset-by-family.component.spec.ts
index 823eca11f37fc14bef55b5be2ba7208ef9e84840..0f2d8314abde7e7dcfbed4c1bb3c53ddc171ea32 100644
--- a/client/src/app/instance/documentation/components/dataset-by-family.component.spec.ts
+++ b/client/src/app/instance/documentation/components/dataset-by-family.component.spec.ts
@@ -18,8 +18,13 @@ const DATASET_LIST: Dataset[] = [
         survey_name: 'mySurvey',
         id_dataset_family: 1,
         public: true,
+        full_data_path: '/data/path1',
         config: {
             images: ['image1'],
+            survey: {
+                survey_enabled: true,
+                survey_label: 'More about this survey'
+            },
             cone_search: {
                 cone_search_enabled: true,
                 cone_search_opened: true,
@@ -67,8 +72,13 @@ const DATASET_LIST: Dataset[] = [
         survey_name: 'mySurvey',
         id_dataset_family: 1,
         public: true,
+        full_data_path: '/data/path2',
         config: {
             images: ['image1'],
+            survey: {
+                survey_enabled: true,
+                survey_label: 'More about this survey'
+            },
             cone_search: {
                 cone_search_enabled: true,
                 cone_search_opened: true,
diff --git a/client/src/app/instance/documentation/components/dataset-card-doc.component.spec.ts b/client/src/app/instance/documentation/components/dataset-card-doc.component.spec.ts
index 7911b704f2e874d514ddb9d1873f003ac379160a..0140dddacee3b1f1aa33a8903f29bdd97cc2553b 100644
--- a/client/src/app/instance/documentation/components/dataset-card-doc.component.spec.ts
+++ b/client/src/app/instance/documentation/components/dataset-card-doc.component.spec.ts
@@ -21,12 +21,17 @@ const DATASET: Dataset = {
     label: 'my dataset',
     description: 'This is my dataset',
     display: 1,
-    data_path: 'path',
+    data_path: '/path',
     survey_name: 'mySurvey',
     id_dataset_family: 1,
     public: true,
+    full_data_path: '/data/path',
     config: {
         images: ['image1'],
+        survey: {
+            survey_enabled: true,
+            survey_label: 'More about this survey'
+        },
         cone_search: {
             cone_search_enabled: true,
             cone_search_opened: true,
diff --git a/client/src/app/instance/home/components/index.ts b/client/src/app/instance/home/components/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8973b374e7bfb09e0ded7e6230d0170a6e266273
--- /dev/null
+++ b/client/src/app/instance/home/components/index.ts
@@ -0,0 +1,5 @@
+import { WelcomeComponent } from './welcome.component';
+
+export const dummiesComponents = [
+    WelcomeComponent
+];
diff --git a/client/src/app/instance/home/components/welcome.component.html b/client/src/app/instance/home/components/welcome.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..0a1998a5e06ccdbaad4f020318d91cef1380d552
--- /dev/null
+++ b/client/src/app/instance/home/components/welcome.component.html
@@ -0,0 +1,6 @@
+<div class="row align-items-center jumbotron">
+    <div class="col-6 col-md-4 order-md-2 mx-auto text-center">
+        <img class="img-fluid mb-3 mb-md-0" src="{{ getLogoSrc() }}" alt="">
+    </div>
+    <div class="col-md-8 order-md-1 text-justify pr-md-5" [innerHtml]="instance.config.home.home_config.home_component_text"></div>
+</div>
\ No newline at end of file
diff --git a/client/src/app/instance/home/home.component.scss b/client/src/app/instance/home/components/welcome.component.scss
similarity index 80%
rename from client/src/app/instance/home/home.component.scss
rename to client/src/app/instance/home/components/welcome.component.scss
index ec44a92b7518f17d66bcacdaab53031f36bdc18b..0a76fe2eca34d1a78330bf489fa2c6547fb46071 100644
--- a/client/src/app/instance/home/home.component.scss
+++ b/client/src/app/instance/home/components/welcome.component.scss
@@ -7,11 +7,6 @@
  * file that was distributed with this source code.
  */
 
- div.jumbotron h1 {
-    font-weight: bold;
-    letter-spacing: 8px;
-}
-
 div.jumbotron p {
     line-height: 35px;
 }
diff --git a/client/src/app/instance/home/components/welcome.component.ts b/client/src/app/instance/home/components/welcome.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96095b046138fb3951c76efa333f8e50b0a29f4e
--- /dev/null
+++ b/client/src/app/instance/home/components/welcome.component.ts
@@ -0,0 +1,30 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input } from '@angular/core';
+
+import { Instance } from 'src/app/metamodel/models';
+
+/**
+ * @class
+ * @classdesc Home container.
+ */
+@Component({
+    selector: 'app-welcome',
+    styleUrls: ['welcome.component.scss'],
+    templateUrl: 'welcome.component.html'
+})
+export class WelcomeComponent {
+    @Input() instance: Instance;
+    @Input() apiUrl: string;
+
+    getLogoSrc() {
+        return `${this.apiUrl}/download-instance-file/${this.instance.name}/${this.instance.config.home.home_config.home_component_logo}`;
+    }
+}
diff --git a/client/src/app/instance/home/home.component.html b/client/src/app/instance/home/home.component.html
index 9454b1e1567473c2f52c18b0db098e6087065d30..96b9457fbe7b3a811f4c17a53931bf9fe3ab32ce 100644
--- a/client/src/app/instance/home/home.component.html
+++ b/client/src/app/instance/home/home.component.html
@@ -1,20 +1,3 @@
 <div class="container">
-    <div class="row align-items-center jumbotron">
-        <div class="col-6 col-md-4 order-md-2 mx-auto text-center">
-            <img class="img-fluid mb-3 mb-md-0" src="assets/anis_v3_logo300.png" alt="">
-        </div>
-        <div class="col-md-8 order-md-1 text-justify pr-md-5">
-            <h1 class="mb-3">ANIS</h1>
-            <p class="lead">
-                AstroNomical Information System is a generic web tool aimed at facilitating and homogenizing the
-                implementation of astronomical data.
-                It allows the fast implementation of a project data exchange platform in a dedicated information
-                system.
-            </p>
-            <p class="lead">
-                ANIS provides services like searching, displaying images and spectroscopic data and
-                downloading catalogues.
-            </p>
-        </div>
-    </div>
+    <app-welcome [instance]="instance | async" [apiUrl]="getApiUrl()"></app-welcome>
 </div>
diff --git a/client/src/app/instance/home/home.component.ts b/client/src/app/instance/home/home.component.ts
index 7182ca06f7a64c23d9dcf467147e20347119baa0..e120190feec76ac65ffa83c733ea33a83c327a4a 100644
--- a/client/src/app/instance/home/home.component.ts
+++ b/client/src/app/instance/home/home.component.ts
@@ -9,13 +9,29 @@
 
 import { Component } from '@angular/core';
 
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import { Instance } from 'src/app/metamodel/models';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { AppConfigService } from 'src/app/app-config.service';
+
 /**
  * @class
  * @classdesc Home container.
  */
 @Component({
     selector: 'app-home',
-    styleUrls: ['home.component.scss'],
     templateUrl: 'home.component.html'
 })
-export class HomeComponent { }
+export class HomeComponent {
+    public instance: Observable<Instance>;
+
+    constructor(private store: Store<{ }>, private config: AppConfigService) {
+        this.instance = this.store.select(instanceSelector.selectInstanceByRouteName);
+    }
+
+    getApiUrl() {
+        return this.config.apiUrl;
+    }
+}
diff --git a/client/src/app/instance/home/home.module.ts b/client/src/app/instance/home/home.module.ts
index 96c4a89bef72e24cb60e9b1d8df619cce10867e7..0859f9d1d45bb11bc68c64553fafe1b5961d8ef3 100644
--- a/client/src/app/instance/home/home.module.ts
+++ b/client/src/app/instance/home/home.module.ts
@@ -11,6 +11,7 @@ import { NgModule } from '@angular/core';
 
 import { SharedModule } from 'src/app/shared/shared.module';
 import { HomeRoutingModule, routedComponents } from './home-routing.module';
+import { dummiesComponents } from './components';
 
 /**
  * @class
@@ -21,6 +22,9 @@ import { HomeRoutingModule, routedComponents } from './home-routing.module';
         SharedModule,
         HomeRoutingModule
     ],
-    declarations: [routedComponents]
+    declarations: [
+        routedComponents,
+        dummiesComponents
+    ]
 })
 export class HomeModule { }
diff --git a/client/src/app/instance/instance-routing.module.ts b/client/src/app/instance/instance-routing.module.ts
index 03c0e21f5b879295d917d7152162fc4e94e73988..53ae1296d4a2648f295956697e42626368d31be5 100644
--- a/client/src/app/instance/instance-routing.module.ts
+++ b/client/src/app/instance/instance-routing.module.ts
@@ -18,6 +18,7 @@ const routes: Routes = [
             { path: '', redirectTo: 'home', pathMatch: 'full' },
             { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
             { path: 'search', loadChildren: () => import('./search/search.module').then(m => m.SearchModule) },
+            { path: 'search-multiple', loadChildren: () => import('./search-multiple/search-multiple.module').then(m => m.SearchMultipleModule) },
             { path: 'documentation', loadChildren: () => import('./documentation/documentation.module').then(m => m.DocumentationModule) }
         ]
     }
diff --git a/client/src/app/instance/instance.component.html b/client/src/app/instance/instance.component.html
index acd9b3df900a6771327d87a05dd6b10e734800fb..ef03a4e2a31e4b464ad0ca7c12ac0d95aa5ea0c8 100644
--- a/client/src/app/instance/instance.component.html
+++ b/client/src/app/instance/instance.component.html
@@ -5,6 +5,7 @@
         [userProfile]="userProfile | async"
         [baseHref]="getBaseHref()"
         [authenticationEnabled]="getAuthenticationEnabled()"
+        [apiUrl]="getApiUrl()"
         [instance]="instance | async"
         (login)="login()"
         (logout)="logout()"
diff --git a/client/src/app/instance/instance.component.ts b/client/src/app/instance/instance.component.ts
index b433bd32845d2904c6a6efe0e5c67c60ad4090bb..fa981f4b2c09c1d62b2d27f7ee1c1917a6ca8db7 100644
--- a/client/src/app/instance/instance.component.ts
+++ b/client/src/app/instance/instance.component.ts
@@ -31,6 +31,7 @@ import { AppConfigService } from 'src/app/app-config.service';
  */
 export class InstanceComponent implements OnInit, OnDestroy {
     public favIcon: HTMLLinkElement = document.querySelector('#favicon');
+    public title: HTMLLinkElement = document.querySelector('#title');
     public links = [
         { label: 'Home', icon: 'fas fa-home', routerLink: 'home' }
     ];
@@ -54,15 +55,18 @@ export class InstanceComponent implements OnInit, OnDestroy {
         Promise.resolve(null).then(() => this.store.dispatch(surveyActions.loadSurveyList()));
         this.instanceSubscription = this.instance.subscribe(instance => {
             if (instance.config.search.search_by_criteria_allowed) {
-                this.links.push({ label: 'Search', icon: 'fas fa-search', routerLink: 'search' });
+                this.links.push({ label: instance.config.search.search_by_criteria_label, icon: 'fas fa-search', routerLink: 'search' });
             }
             if (instance.config.search.search_multiple_allowed) {
-                this.links.push({ label: 'Search multiple', icon: 'fas fa-search-plus', routerLink: 'search-multiple' });
+                this.links.push({ label: instance.config.search.search_multiple_label, icon: 'fas fa-search-plus', routerLink: 'search-multiple' });
             }
             if (instance.config.documentation.documentation_allowed) {
-                this.links.push({ label: 'Documentation', icon: 'fas fa-question', routerLink: 'documentation' });
+                this.links.push({ label: instance.config.documentation.documentation_label, icon: 'fas fa-question', routerLink: 'documentation' });
             }
-            this.favIcon.href = `assets/${instance.name}-favicon.ico`;
+            if (instance.config.design.design_favicon !== '') {
+                this.favIcon.href = `${this.config.apiUrl}/download-instance-file/${instance.name}/${instance.config.design.design_favicon}`;
+            }
+            this.title.innerHTML = instance.label;
         })
     }
 
@@ -74,6 +78,10 @@ export class InstanceComponent implements OnInit, OnDestroy {
         return this.config.authenticationEnabled;
     }
 
+    getApiUrl() {
+        return this.config.apiUrl;
+    }
+
     login(): void {
         this.store.dispatch(authActions.login());
     }
diff --git a/client/src/app/instance/instance.reducer.ts b/client/src/app/instance/instance.reducer.ts
index 76e651beb8b286a870569e434a9c274b4ba1369a..d14c08ae52efefef8b043088ae0b74cddbb1a44d 100644
--- a/client/src/app/instance/instance.reducer.ts
+++ b/client/src/app/instance/instance.reducer.ts
@@ -11,12 +11,14 @@ import { combineReducers, createFeatureSelector } from '@ngrx/store';
 
 import { RouterReducerState } from 'src/app/custom-route-serializer';
 import * as search from './store/reducers/search.reducer';
+import * as searchMultiple from './store/reducers/search-multiple.reducer';
 import * as samp from './store/reducers/samp.reducer';
 import * as coneSearch from './store/reducers/cone-search.reducer';
 import * as detail from './store/reducers/detail.reducer';
 
 export interface State {
     search: search.State,
+    searchMultiple: searchMultiple.State,
     samp: samp.State,
     coneSearch: coneSearch.State
     detail: detail.State
@@ -24,6 +26,7 @@ export interface State {
 
 const reducers = {
     search: search.searchReducer,
+    searchMultiple: searchMultiple.searchMultipleReducer,
     samp: samp.sampReducer,
     coneSearch: coneSearch.coneSearchReducer,
     detail: detail.detailReducer
diff --git a/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.html b/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..4395a45c9d7adad1d8ebe8fa6598b3c3f90f6fee
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.html
@@ -0,0 +1,13 @@
+<div class="row">
+    <div *ngFor="let datasetFamily of getDatasetFamilyList()" class="col-12 col-lg-6 col-xl-4 my-3 text-center">
+        <app-datasets-by-family
+            [datasetFamily]="datasetFamily"
+            [datasetList]="getDatasetsByFamily(datasetFamily.id)"
+            [surveyList]="surveyList"
+            [selectedDatasets]="selectedDatasets"
+            [isAllSelected]="getIsAllSelected(datasetFamily.id)"
+            [isAllUnselected]="getIsAllUnselected(datasetFamily.id)"
+            (updateSelectedDatasets)="updateSelectedDatasets.emit($event)">
+        </app-datasets-by-family>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.ts b/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f01569abfd679097f564b04a1563c52806e6957e
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/dataset-list.component.ts
@@ -0,0 +1,82 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
+
+import { Dataset, DatasetFamily, Survey } from 'src/app/metamodel/models';
+
+@Component({
+    selector: 'app-dataset-list',
+    templateUrl: 'dataset-list.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
+})
+/**
+ * @class
+ * @classdesc Search multiple dataset list component.
+ */
+export class DatasetListComponent {
+    @Input() datasetFamilyList: DatasetFamily[];
+    @Input() datasetList: Dataset[];
+    @Input() surveyList: Survey[];
+    @Input() selectedDatasets: string[];
+    @Output() updateSelectedDatasets: EventEmitter<string[]> = new EventEmitter();
+
+    /**
+     * Returns dataset family list sorted by display, that contains datasets with cone search enabled.
+     *
+     * @return Family[]
+     */
+    getDatasetFamilyList(): DatasetFamily[] {
+        const familyId: number[] = [];
+        this.datasetList.forEach(d => {
+            if (!familyId.includes(d.id_dataset_family)) {
+                familyId.push(d.id_dataset_family);
+            }
+        });
+        return this.datasetFamilyList
+            .filter(f => familyId.includes(f.id));
+    }
+
+    /**
+     * Returns dataset list that belongs to the given ID family.
+     *
+     * @param  {number} familyId - The dataset family ID.
+     *
+     * @return Dataset[]
+     */
+    getDatasetsByFamily(familyId: number): Dataset[] {
+        return this.datasetList.filter(d => d.id_dataset_family === familyId);
+    }
+
+    /**
+     * Checks if all datasets that belongs to the given dataset family ID are selected.
+     *
+     * @param  {number} familyId - The dataset family ID.
+     *
+     * @return boolean
+     */
+    getIsAllSelected(familyId: number): boolean {
+        const datasetListName = this.getDatasetsByFamily(familyId).map(d => d.name);
+        const filteredSelectedDatasets = this.selectedDatasets.filter(name => datasetListName.indexOf(name) > -1);
+        return datasetListName.length === filteredSelectedDatasets.length;
+    }
+
+    /**
+     * Checks if none of datasets that belongs to the given dataset family ID are selected.
+     *
+     * @param  {number} familyId - The dataset family ID.
+     *
+     * @return boolean
+     */
+    getIsAllUnselected(familyId: number): boolean {
+        const datasetListName = this.getDatasetsByFamily(familyId).map(d => d.name);
+        const filteredSelectedDatasets = this.selectedDatasets.filter(name => datasetListName.indexOf(name) > -1);
+        return filteredSelectedDatasets.length === 0;
+    }
+}
diff --git a/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.html b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..c0ab965e6bdb4d3cabde7446155f1f95ae62490d
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.html
@@ -0,0 +1,43 @@
+<p class="mb-3"><em>{{ datasetFamily.label }}</em></p>
+<div class="row mb-1">
+    <div class="col pr-1">
+        <button (click)="selectAll()" [disabled]="isAllSelected"
+            class="btn btn-sm btn-block btn-outline-secondary letter-spacing">
+            Select All
+        </button>
+    </div>
+    <div class="col pl-1">
+        <button (click)="unselectAll()" [disabled]="isAllUnselected"
+            class="btn btn-sm btn-block btn-outline-secondary letter-spacing">
+            Unselect All
+        </button>
+    </div>
+</div>
+<div class="selectbox p-0">
+    <div *ngFor="let dataset of datasetList">
+        <div *ngIf="isSelected(dataset.name)">
+            <button class="btn btn-block text-left py-1 m-0 rounded-0" (click)="toggleSelection(dataset.name)">
+                <span class="fas fa-fw fa-check-square theme-color"></span>
+                {{ dataset.label }}
+                <span [tooltip]="datasetInfo" placement="right" containerClass="custom-tooltip right-tooltip">
+                    <span class="far fa-question-circle fa-xs"></span>
+                </span>
+            </button>
+        </div>
+        <div *ngIf="!isSelected(dataset.name)">
+            <button class="btn btn-block text-left py-1 m-0 rounded-0" (click)="toggleSelection(dataset.name)">
+                <span class="far fa-fw fa-square text-secondary"></span>
+                {{ dataset.label }}
+                <span [tooltip]="datasetInfo" placement="right" containerClass="custom-tooltip right-tooltip">
+                    <span class="far fa-question-circle fa-xs"></span>
+                </span>
+            </button>
+        </div>
+
+        <ng-template #datasetInfo class="text-left">
+            {{ dataset.description }}
+            <br><br>
+            {{ getSurveyDescription(dataset.survey_name) }}
+        </ng-template>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.scss b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..14afb86a712e88c6595f1578648cb2b5c8040dbb
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.scss
@@ -0,0 +1,27 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+.selectbox {
+    height: 200px;
+    overflow-y: auto;
+    border: 1px solid #ced4da;
+    border-radius: .25rem;
+}
+
+.letter-spacing {
+    letter-spacing: 2px;
+}
+
+.selectbox button:hover {
+    background-color: #ECECEC;
+}
+
+.selectbox button:focus {
+    box-shadow: none;
+}
diff --git a/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.ts b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8a1a260c5e72f0f86b46ee6910c9e76f1bfe5976
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/datasets-by-family.component.ts
@@ -0,0 +1,96 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
+
+import { Dataset, DatasetFamily, Survey } from 'src/app/metamodel/models';
+
+@Component({
+    selector: 'app-datasets-by-family',
+    templateUrl: 'datasets-by-family.component.html',
+    styleUrls: ['datasets-by-family.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+    encapsulation: ViewEncapsulation.None
+})
+/**
+ * @class
+ * @classdesc Search multiple datasets by family component.
+ */
+export class DatasetsByFamilyComponent {
+    @Input() datasetFamily: DatasetFamily;
+    @Input() datasetList: Dataset[];
+    @Input() surveyList: Survey[];
+    @Input() selectedDatasets: string[];
+    @Input() isAllSelected: boolean;
+    @Input() isAllUnselected: boolean;
+    @Output() updateSelectedDatasets: EventEmitter<string[]> = new EventEmitter();
+
+    /**
+     * Checks if dataset is selected fot the given dataset name.
+     *
+     * @param  {string} dname - The dataset name.
+     *
+     * @return boolean
+     */
+    isSelected(dname: string): boolean {
+        return this.selectedDatasets.filter(i => i === dname).length > 0;
+    }
+
+    /**
+     * Emits event to update dataset list selection with the given updated selected dataset name list.
+     *
+     * @param  {string} dname - The dataset name.
+     */
+    toggleSelection(dname: string): void {
+        const clonedSelectedDatasets = [...this.selectedDatasets];
+        const index = clonedSelectedDatasets.indexOf(dname);
+        if (index > -1) {
+            clonedSelectedDatasets.splice(index, 1);
+        } else {
+            clonedSelectedDatasets.push(dname);
+        }
+        this.updateSelectedDatasets.emit(clonedSelectedDatasets);
+    }
+
+    /**
+     * Emits event to update dataset list selection with all datasets names.
+     */
+    selectAll(): void {
+        const clonedSelectedDatasets = [...this.selectedDatasets];
+        const datasetListName = this.datasetList.map(d => d.name);
+        datasetListName.filter(name => clonedSelectedDatasets.indexOf(name) === -1).forEach(name => {
+            clonedSelectedDatasets.push(name);
+        });
+        this.updateSelectedDatasets.emit(clonedSelectedDatasets);
+    }
+
+    /**
+     * Emits event to update dataset list selection with no datasets names.
+     */
+    unselectAll(): void {
+        const clonedSelectedDatasets = [...this.selectedDatasets];
+        const datasetListName = this.datasetList.map(d => d.name);
+        datasetListName.filter(name => clonedSelectedDatasets.indexOf(name) > -1).forEach(name => {
+            const index = clonedSelectedDatasets.indexOf(name);
+            clonedSelectedDatasets.splice(index, 1);
+        });
+        this.updateSelectedDatasets.emit(clonedSelectedDatasets);
+    }
+
+    /**
+     * Returns survey description of the given survey name.
+     *
+     * @param  {string} surveyName - The survey name.
+     *
+     * @return string
+     */
+    getSurveyDescription(surveyName: string): string {
+        return this.surveyList.find(p => p.name === surveyName).description;
+    }
+}
diff --git a/client/src/app/instance/search-multiple/components/datasets/index.ts b/client/src/app/instance/search-multiple/components/datasets/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..730e87c6c191b0313c5f71920538f3374fe5245f
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/datasets/index.ts
@@ -0,0 +1,7 @@
+import { DatasetListComponent } from './dataset-list.component';
+import { DatasetsByFamilyComponent } from './datasets-by-family.component';
+
+export const datasetsComponents = [
+    DatasetListComponent,
+    DatasetsByFamilyComponent
+];
diff --git a/client/src/app/instance/search-multiple/components/index.ts b/client/src/app/instance/search-multiple/components/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53355e402864869e82505c5ac93da6e6c7da61ec
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/index.ts
@@ -0,0 +1,11 @@
+import { ProgressBarMultipleComponent } from './progress-bar-multiple.component';
+import { SummaryMultipleComponent } from './summary-multiple.component';
+import { datasetsComponents } from './datasets';
+import { resultComponents } from './result';
+
+export const dummiesComponents = [
+    ProgressBarMultipleComponent,
+    SummaryMultipleComponent,
+    datasetsComponents,
+    resultComponents
+];
diff --git a/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.html b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..7ac8fc5b28b1f1ba5aea2ee70bc3f431787446ef
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.html
@@ -0,0 +1,58 @@
+<div class="row text-center">
+    <div class="col">
+        <h1>Search around a position in multiple datasets</h1>
+        <p class="text-muted">Fill RA & DEC position, select datasets and display the result.</p>
+    </div>
+</div>
+<div class="progress-navigation">
+    <div class="progress progress-with-circle">
+        <div class="progress-bar" 
+            [ngClass]="getStepClass()"
+            [ngStyle]="{'background-color': instance.config.design.design_color }" 
+            role="progressbar" 
+            aria-valuenow="1" 
+            aria-valuemin="1" 
+            aria-valuemax="4">
+        </div>
+    </div>
+    <ul class="nav nav-pills">
+        <li class="nav-item checked" [ngClass]="{'active': currentStep === 'position'}">
+            <a class="nav-link" [ngStyle]="getNavItemAStyle('position', true)" routerLink="/instance/{{ instance.name }}/search-multiple/position" [queryParams]="queryParams" data-toggle="tab">
+                <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('position', true)">
+                    <span class="fas fa-drafting-compass"></span>
+                </div>
+                Position
+            </a>
+        </li>
+
+        <li class="nav-item" [ngClass]="{'active': currentStep === 'datasets', 'checked': datasetsStepChecked}">
+            <a *ngIf="coneSearch" class="nav-link" [ngStyle]="getNavItemAStyle('datasets', datasetsStepChecked)" routerLink="/instance/{{ instance.name }}/search-multiple/datasets" [queryParams]="queryParams" data-toggle="tab">
+                <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('datasets', datasetsStepChecked)">
+                    <span class="fas fa-book"></span>
+                </div>
+                Datasets
+            </a>
+            <a *ngIf="!coneSearch" class="nav-link disabled" [ngStyle]="getNavItemAStyle('datasets', datasetsStepChecked)" data-toggle="tab">
+                <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('datasets', datasetsStepChecked)">
+                    <span class="fas fa-book"></span>
+                </div>
+                Datasets
+            </a>
+        </li>
+
+        <li class="nav-item" [ngClass]="{'active': currentStep === 'result', 'checked': resultStepChecked}">
+            <a *ngIf="coneSearch && selectedDatasets.length > 0" class="nav-link" [ngStyle]="getNavItemAStyle('result', resultStepChecked)" routerLink="/instance/{{ instance.name }}/search-multiple/result" [queryParams]="queryParams" data-toggle="tab">
+                <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('result', resultStepChecked)">
+                    <span class="fas fa-table"></span>
+                </div>
+                Result
+            </a>
+            <a *ngIf="!coneSearch || selectedDatasets.length < 1" class="nav-link disabled" [ngStyle]="getNavItemAStyle('result', resultStepChecked)" data-toggle="tab">
+                <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('result', resultStepChecked)">
+                    <span class="fas fa-table"></span>
+                </div>
+                Result
+            </a>
+        </li>
+    </ul>
+</div>
diff --git a/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.scss b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..0cf6548626fcaec4468e60ae9b438a7349060294
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.scss
@@ -0,0 +1,107 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+.progress-navigation {
+    position: relative;
+    height: 125px;
+    margin-top: 15px;
+}
+
+.progress-with-circle {
+    position: relative;
+    top: 40px;
+    z-index: 50;
+    height: 4px;
+}
+
+.progress-bar {
+    box-shadow: none;
+    -webkit-transition: width .3s ease;
+    -o-transition: width .3s ease;
+    transition: width .3s ease;
+}
+
+.nav-pills {
+    background-color: #F3F2EE;
+    position: absolute;
+    width: 100%;
+    height: 4px;
+    top: 40px;
+    text-align: center;
+}
+
+.nav-pills li a {
+    padding: 0;
+    max-width: 78px;
+    margin: 0 auto;
+    color: rgba(0, 0, 0, 0.2);
+    border-radius: 50%;
+    position: relative;
+    top: -32px;
+    z-index: 100;
+}
+
+.icon-circle {
+    font-size: 20px;
+    border: 3px solid #E9ECEF;
+    text-align: center;
+    border-radius: 50%;
+    color: rgba(0, 0, 0, 0.2);
+    font-weight: 600;
+    width: 70px;
+    height: 70px;
+    background-color: #FFFFFF;
+    margin: 0 auto;
+    position: relative;
+    top: -2px;
+}
+
+.nav-item {
+    width: 33%;
+}
+
+.nav-item.active a {
+    background-color: transparent;
+}
+
+.nav-item.active .icon-circle {
+    color: white !important;
+}
+
+.nav-link.disabled {
+    cursor: not-allowed;
+}
+
+.icon-circle svg {
+    position: absolute;
+    z-index: 1;
+    left: 22px;
+    right: 0;
+    top: 23px;
+}
+
+.positionStep {
+    width: 15%;
+}
+
+.datasetsStep {
+    width: 48%;
+}
+
+.resultStep {
+    width: 100%;
+}
+
+.btn-clear-form span {
+    display: none;
+}
+
+.btn-clear-form:hover span {
+    display: inline;
+}
diff --git a/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.ts b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ece4925478828db29a2a9df8e097e3287ca2900e
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/progress-bar-multiple.component.ts
@@ -0,0 +1,75 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
+
+import { Instance } from 'src/app/metamodel/models';
+import { ConeSearch, SearchMultipleQueryParams } from 'src/app/instance/store/models';
+
+@Component({
+    selector: 'app-progress-bar-multiple',
+    templateUrl: 'progress-bar-multiple.component.html',
+    styleUrls: ['progress-bar-multiple.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush
+})
+/**
+ * @class
+ * @classdesc Search multiple progress bar component.
+ */
+export class ProgressBarMultipleComponent {
+    @Input() instance: Instance;
+    @Input() currentStep: string;
+    @Input() positionStepChecked: boolean;
+    @Input() datasetsStepChecked: boolean;
+    @Input() resultStepChecked: boolean;
+    @Input() coneSearch: ConeSearch;
+    @Input() selectedDatasets: string[];
+    @Input() queryParams: SearchMultipleQueryParams;
+
+    /**
+     * Returns step class that match to the current step.
+     *
+     * @return string
+     */
+    getStepClass(): string {
+        switch (this.currentStep) {
+            case 'position':
+                return 'positionStep';
+            case 'datasets':
+                return 'datasetsStep';
+            case 'result':
+                return 'resultStep';
+            default:
+                return 'positionStep';
+        }
+    }
+
+    getNavItemAStyle(currentStep: string, checked: boolean) {
+        if (this.currentStep === currentStep || checked) {
+            return {
+                'color': this.instance.config.design.design_color
+            }
+        } else {
+            return null;
+        }
+    }
+
+    getNavItemIconCircleStyle(currentStep: string, checked: boolean) {
+        let style = {};
+        if (this.currentStep === currentStep) {
+            style['border-color'] = this.instance.config.design.design_color;
+            style['background-color'] = this.instance.config.design.design_color;
+        }
+        if (checked) {
+            style['border-color'] = this.instance.config.design.design_color;
+            style['color'] = this.instance.config.design.design_color;
+        }
+        return style;
+    }
+}
diff --git a/client/src/app/instance/search-multiple/components/result/index.ts b/client/src/app/instance/search-multiple/components/result/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73ec101031c08b3bdd8c58d04fed9afcb762ddac
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/result/index.ts
@@ -0,0 +1,5 @@
+import { OverviewComponent } from './overview.component';
+
+export const resultComponents = [
+    OverviewComponent
+];
diff --git a/client/src/app/instance/search-multiple/components/result/overview.component.html b/client/src/app/instance/search-multiple/components/result/overview.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..91b90040c64e0fa910f1e502ff2d7c33d34a5be1
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/result/overview.component.html
@@ -0,0 +1,75 @@
+<div class="jumbotron mb-5 py-4">
+    <div *ngIf="getTotalObject() === 0">
+        <div class="">
+            <h2 class="font-weight-bold">No results.</h2>
+        </div>
+        <hr class="my-4">
+        <div class="row justify-content-around">
+            <div class="col-auto border-right">
+                <span class="title">Cone search</span>
+                <ul class="list-unstyled pl-3">
+                    <li>RA = {{ coneSearch.ra }}°</li>
+                    <li>DEC = {{ coneSearch.dec }}°</li>
+                    <li>radius = {{ coneSearch.radius }} arcsecond</li>
+                </ul>
+            </div>
+            <div *ngFor="let datasetFamily of getSortedDatasetFamilyList()" class="col-auto">
+                <span class="title">{{ datasetFamily.label }}</span>
+                <ul class="list-unstyled pl-3">
+                    <li *ngFor="let dataset of getSelectedDatasetsByFamily(datasetFamily.id)" >
+                        {{ dataset.label }} <span class="badge badge-pill badge-light text-danger">0</span>
+                    </li>
+                </ul>
+            </div>
+        </div>
+        <hr class="my-4">
+        <div class="text-center">
+            <a routerLink="/instance/{{ instanceSelected }}/search-multiple/position" class="btn btn-lg btn-outline-primary">
+                <span class="fas fa-undo"></span> Try something else
+            </a>
+        </div>
+    </div>
+
+    <div *ngIf="getTotalObject() > 0">
+        <div class="lead">
+            Found
+            <span class="font-weight-bold">{{ getTotalObject() }}</span>
+            <span *ngIf="getTotalObject() > 1; else object"> objects</span>
+            <ng-template #object> object</ng-template>
+            in
+            <span class="font-weight-bold">{{ getTotalDatasets() }}</span>
+            <span *ngIf="getTotalDatasets() > 1; else dataset"> datasets</span>
+            <ng-template #dataset> dataset</ng-template>.
+        </div>
+        <hr class="my-4">
+        <div class="row justify-content-around">
+            <div class="col-auto border-right">
+                <span class="title">Cone search</span>
+                <ul class="list-unstyled pl-3">
+                    <li>RA = {{ coneSearch.ra }}°</li>
+                    <li>DEC = {{ coneSearch.dec }}°</li>
+                    <li>radius = {{ coneSearch.radius }} arcsecond</li>
+                </ul>
+            </div>
+            <div *ngFor="let datasetFamily of getSortedDatasetFamilyList()" class="col-auto">
+                <span class="title">{{ datasetFamily.label }}</span>
+                <ul class="list-unstyled pl-3">
+                    <li *ngFor="let dataset of getSelectedDatasetsByFamily(datasetFamily.id)" >
+                        {{ dataset.label }}
+                        <span class="badge badge-pill badge-light" [ngClass]="{'text-primary': getCountByDataset(dataset.name) !== 0}">
+                            {{ getCountByDataset(dataset.name) }}
+                        </span>
+                        <span *ngIf="getCountByDataset(dataset.name) < 2"> object found</span>
+                        <span *ngIf="getCountByDataset(dataset.name) > 1"> objects found</span>
+                        <hr *ngIf="getCountByDataset(dataset.name) > 0" class="my-4">
+                        <div *ngIf="getCountByDataset(dataset.name) > 0" class="text-center">
+                            <a routerLink="/instance/{{ instanceSelected }}/search/result/{{ dataset.name }}" [queryParams]="getCsQueryParams()"  class="btn btn-outline-primary">
+                                <span class="fas fa-forward"></span> Go to result
+                            </a>
+                        </div>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/components/result/overview.component.ts b/client/src/app/instance/search-multiple/components/result/overview.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e85af4d2feed7f641e352c6f5a998a7a596899c8
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/result/overview.component.ts
@@ -0,0 +1,94 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, Input } from '@angular/core';
+
+import { DatasetFamily, Dataset } from 'src/app/metamodel/models';
+import { ConeSearch, SearchMultipleDatasetLength, SearchMultipleQueryParams } from 'src/app/instance/store/models';
+
+@Component({
+    selector: 'app-overview',
+    templateUrl: 'overview.component.html'
+})
+export class OverviewComponent {
+    @Input() instanceSelected: string;
+    @Input() datasetFamilyList: DatasetFamily[];
+    @Input() datasetList: Dataset[];
+    @Input() coneSearch: ConeSearch;
+    @Input() selectedDatasets: string[];
+    @Input() dataLength: SearchMultipleDatasetLength[];
+    @Input() queryParams: SearchMultipleQueryParams;
+
+    /**
+     * Returns total amount of results for all datasets.
+     *
+     * @return number
+     */
+    getTotalObject(): number {
+        return this.dataLength
+            .filter(datasetLength => datasetLength.length > 0)
+            .reduce((sum, datasetLength) => sum + datasetLength.length, 0);
+    }
+
+    /**
+     * Returns total number of datasets with results.
+     *
+     * @return number
+     */
+    getTotalDatasets(): number {
+        return this.dataLength.filter(datasetLength => datasetLength.length > 0).length;
+    }
+
+    /**
+     * Returns dataset families sorted by display, that contains selected datasets.
+     *
+     * @return Family[]
+     */
+    getSortedDatasetFamilyList(): DatasetFamily[] {
+        let datasetFamiliesWithSelectedDataset: DatasetFamily[] = [];
+        this.selectedDatasets.forEach(dname => {
+            const dataset: Dataset = this.datasetList.find(d => d.name === dname);
+            const datasetFamily: DatasetFamily = this.datasetFamilyList.find(f => f.id === dataset.id_dataset_family);
+            if (!datasetFamiliesWithSelectedDataset.includes(datasetFamily)) {
+                datasetFamiliesWithSelectedDataset.push(datasetFamily);
+            }
+        });
+        return datasetFamiliesWithSelectedDataset;
+    }
+
+    /**
+     * Returns selected dataset list for the given dataset family ID.
+     *
+     * @param  {number} familyId - The family ID.
+     *
+     * @return Dataset[]
+     */
+    getSelectedDatasetsByFamily(familyId: number): Dataset[] {
+        return this.datasetList
+            .filter(d => d.id_dataset_family === familyId)
+            .filter(d => this.selectedDatasets.includes(d.name));
+    }
+
+    /**
+     * Returns the result number for the given dataset name.
+     *
+     * @param  {string} dname - The dataset name.
+     *
+     * @return number
+     */
+    getCountByDataset(dname: string): number {
+        return this.dataLength.find(datasetLength => datasetLength.datasetName === dname).length;
+    }
+
+    getCsQueryParams() {
+        return {
+            cs: `${this.coneSearch.ra}:${this.coneSearch.dec}:${this.coneSearch.radius}`
+        }
+    }
+}
diff --git a/client/src/app/instance/search-multiple/components/summary-multiple.component.html b/client/src/app/instance/search-multiple/components/summary-multiple.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..3d60496597bb4fde521dab330da270201431178a
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/summary-multiple.component.html
@@ -0,0 +1,59 @@
+<div class="border rounded">
+    <p class="lead text-center border-bottom bg-light py-3">Search summary</p>
+
+    <!-- Position -->
+    <p class="text-center font-italic">
+        Position
+    </p>
+    <span *ngIf="coneSearch" class="pl-5">
+        Cone search:
+        <ul class="ml-3 pl-5 list-unstyled">
+            <li>RA = {{ coneSearch.ra }}°</li>
+            <li>DEC = {{ coneSearch.dec }}°</li>
+            <li>radius = {{ coneSearch.radius }} arcsecond</li>
+        </ul>
+    </span>
+    <p *ngIf="!coneSearch" class="pl-5 text-danger font-weight-bold">
+        Not valid position!
+    </p>
+    <hr>
+
+    <!-- Dataset List -->
+    <p class="text-center font-italic">
+        Datasets
+    </p>
+    <div>
+        <p *ngIf="selectedDatasets.length < 1" class="pl-5 text-danger font-weight-bold">
+            At least 1 dataset required!
+        </p>
+        <div *ngIf="selectedDatasets.length > 0">
+            <!-- Accordion Dataset families -->
+            <accordion [isAnimated]="true">
+                <accordion-group *ngFor="let datasetFamily of getDatasetFamilyList()" #ag panelClass="abstract-accordion" [isOpen]="accordionFamilyIsOpen" class="pl-5">
+                    <button class="btn btn-link btn-block clearfix pb-1 text-primary" accordion-heading>
+                        <div class="pull-left float-left">
+                            {{ datasetFamily.label }}
+                            &nbsp;
+                            <span *ngIf="ag.isOpen">
+                                <span class="fas fa-chevron-up"></span>
+                            </span>
+                            <span *ngIf="!ag.isOpen">
+                                <span class="fas fa-chevron-down"></span>
+                            </span>
+                        </div>
+                    </button>
+
+                    <!-- Selected Datasets -->
+                    <ul *ngIf="getSelectedDatasetsByFamily(datasetFamily.id).length > 0; else noDataset" class="mb-0 pl-4 list-unstyled">
+                        <li *ngFor="let dataset of getSelectedDatasetsByFamily(datasetFamily.id)" class="pb-1">
+                            {{ dataset.label }}
+                        </li>
+                    </ul>
+                    <ng-template #noDataset>
+                        <p class="mb-1 pl-4">No selected dataset</p>
+                    </ng-template>
+                </accordion-group>
+            </accordion>
+        </div>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/components/summary-multiple.component.scss b/client/src/app/instance/search-multiple/components/summary-multiple.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..c837d14e1ce994aeb0857803139aaad3fd7f8d6d
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/summary-multiple.component.scss
@@ -0,0 +1,12 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+li>span {
+    cursor: pointer;
+}
diff --git a/client/src/app/instance/search-multiple/components/summary-multiple.component.ts b/client/src/app/instance/search-multiple/components/summary-multiple.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..790fcd5c75c8862f0dab3bef3ff867edc4c7a361
--- /dev/null
+++ b/client/src/app/instance/search-multiple/components/summary-multiple.component.ts
@@ -0,0 +1,64 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+
+import { SearchMultipleQueryParams, ConeSearch } from 'src/app/instance/store/models';
+import { Dataset, DatasetFamily } from 'src/app/metamodel/models';
+
+@Component({
+    selector: 'app-summary-multiple',
+    templateUrl: 'summary-multiple.component.html',
+    styleUrls: ['summary-multiple.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+/**
+ * @class
+ * @classdesc Search multiple summary component.
+ */
+export class SummaryMultipleComponent {
+    @Input() currentStep: string;
+    @Input() coneSearch: ConeSearch;
+    @Input() selectedDatasets: string[];
+    @Input() queryParams: SearchMultipleQueryParams;
+    @Input() datasetFamilyList: DatasetFamily[];
+    @Input() datasetList: Dataset[];
+
+    accordionFamilyIsOpen = true;
+
+    /**
+     * Returns dataset families sorted by display, that contains datasets with cone search enabled.
+     *
+     * @return Family[]
+     */
+    getDatasetFamilyList(): DatasetFamily[] {
+        const familiesId: number[] = [];
+        this.datasetList.forEach(d => {
+            if (!familiesId.includes(d.id_dataset_family)) {
+                familiesId.push(d.id_dataset_family);
+            }
+        });
+        return this.datasetFamilyList
+            .filter(f => familiesId.includes(f.id))
+            //.sort(sortByDisplay);
+    }
+
+    /**
+     * Returns dataset list for the given dataset family ID.
+     *
+     * @param  {number} familyId - The family ID.
+     *
+     * @return Dataset[]
+     */
+    getSelectedDatasetsByFamily(familyId: number): Dataset[] {
+        return this.datasetList
+            .filter(d => d.id_dataset_family === familyId)
+            .filter(d => this.selectedDatasets.includes(d.name));
+    }
+}
diff --git a/client/src/app/instance/search-multiple/containers/abstract-search-multiple.component.ts b/client/src/app/instance/search-multiple/containers/abstract-search-multiple.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d8bbadd476b404c8b20a43d728284d0423c3a67f
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/abstract-search-multiple.component.ts
@@ -0,0 +1,58 @@
+import { Directive, OnDestroy, OnInit } from '@angular/core';
+
+import { Store } from '@ngrx/store';
+import { Observable, Subscription } from 'rxjs';
+
+import { Dataset, DatasetFamily } from 'src/app/metamodel/models';
+import { ConeSearch, SearchMultipleQueryParams } from '../../store/models';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as datasetFamilySelector from 'src/app/metamodel/selectors/dataset-family.selector';
+import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
+import * as searchMultipleActions from '../../store/actions/search-multiple.actions';
+import * as searchMultipleSelector from 'src/app/instance/store/selectors/search-multiple.selector';
+import * as coneSearchSelector from 'src/app/instance/store/selectors/cone-search.selector';
+
+@Directive()
+export abstract class AbstractSearchMultipleComponent implements OnInit, OnDestroy {
+    public pristine: Observable<boolean>;
+    public instanceSelected: Observable<string>;
+    public datasetFamilyListIsLoading: Observable<boolean>;
+    public datasetFamilyListIsLoaded: Observable<boolean>;
+    public datasetFamilyList: Observable<DatasetFamily[]>;
+    public datasetListIsLoading: Observable<boolean>;
+    public datasetListIsLoaded: Observable<boolean>;
+    public datasetList: Observable<Dataset[]>;
+    public currentStep: Observable<string>;
+    public selectedDatasets: Observable<string[]>;
+    public coneSearch: Observable<ConeSearch>;
+    public queryParams: Observable<SearchMultipleQueryParams>;
+
+    private datasetListSubscription: Subscription;
+
+    constructor(protected store: Store<{ }>) {
+        this.pristine = this.store.select(searchMultipleSelector.selectPristine);
+        this.instanceSelected = this.store.select(instanceSelector.selectInstanceNameByRoute);
+        this.datasetFamilyListIsLoading = store.select(datasetFamilySelector.selectDatasetFamilyListIsLoading);
+        this.datasetFamilyListIsLoaded = store.select(datasetFamilySelector.selectDatasetFamilyListIsLoaded);
+        this.datasetFamilyList = store.select(datasetFamilySelector.selectAllDatasetFamilies);
+        this.datasetListIsLoading = this.store.select(datasetSelector.selectDatasetListIsLoading);
+        this.datasetListIsLoaded = this.store.select(datasetSelector.selectDatasetListIsLoaded);
+        this.datasetList = this.store.select(datasetSelector.selectAllConeSearchDatasets);
+        this.currentStep = this.store.select(searchMultipleSelector.selectCurrentStep)
+        this.selectedDatasets = this.store.select(searchMultipleSelector.selectSelectedDatasets);
+        this.coneSearch = this.store.select(coneSearchSelector.selectConeSearch);
+        this.queryParams = this.store.select(searchMultipleSelector.selectQueryParams);
+    }
+    
+    ngOnInit() {
+        this.datasetListSubscription = this.datasetListIsLoaded.subscribe(datasetListIsLoaded =>  {
+            if (datasetListIsLoaded) {
+                Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.initSearch()));
+            }
+        })
+    }
+
+    ngOnDestroy() {
+        this.datasetListSubscription.unsubscribe();
+    }
+}
diff --git a/client/src/app/instance/search-multiple/containers/datasets.component.html b/client/src/app/instance/search-multiple/containers/datasets.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..6c030e4a4f8ca0b8ec8d5ce94b654778d7baf1f0
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/datasets.component.html
@@ -0,0 +1,44 @@
+<app-spinner *ngIf="(datasetFamilyListIsLoading | async) || (datasetListIsLoading | async) || (surveyListIsLoading | async)">
+</app-spinner>
+
+<div *ngIf="(datasetFamilyListIsLoaded | async) && (datasetListIsLoaded | async) && (surveyListIsLoaded | async)" class="row mt-4">
+    <div class="col-12 col-md-8 col-lg-9">
+        <div class="border rounded my-2">
+            <p class="border-bottom bg-light text-primary mb-0 py-4 pl-4">Datasets</p>
+            <div class="px-3">
+                <app-dataset-list
+                    [surveyList]="surveyList | async"
+                    [datasetFamilyList]="datasetFamilyList | async"
+                    [datasetList]="datasetList | async"
+                    [selectedDatasets]="selectedDatasets | async"
+                    (updateSelectedDatasets)="updateSelectedDatasets($event)">
+                </app-dataset-list>
+            </div>
+        </div>
+    </div>
+    <div class="col-12 col-md-4 col-lg-3 pt-2">
+        <app-summary-multiple
+            [currentStep]="currentStep | async"
+            [coneSearch]="coneSearch | async"
+            [selectedDatasets]="selectedDatasets | async"
+            [queryParams]="queryParams | async"
+            [datasetFamilyList]="datasetFamilyList | async"
+            [datasetList]="datasetList | async">
+        </app-summary-multiple>
+    </div>
+</div>
+
+<div class="row mt-5 justify-content-between">
+    <div class="col">
+        <a routerLink="/instance/{{ instanceSelected | async }}/search-multiple/position" [queryParams]="queryParams | async" 
+            class="btn btn-outline-secondary">
+            <span class="fas fa-arrow-left"></span> Position
+        </a>
+    </div>
+    <div *ngIf="(selectedDatasets | async).length > 0" class="col col-auto">
+        <a routerLink="/instance/{{ instanceSelected | async }}/search-multiple/result" [queryParams]="queryParams | async"
+            class="btn btn-outline-primary">
+            Result <span class="fas fa-arrow-right"></span>
+        </a>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/containers/datasets.component.ts b/client/src/app/instance/search-multiple/containers/datasets.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b990465122fc275552cdd57367d0299df39bccc
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/datasets.component.ts
@@ -0,0 +1,45 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component } from '@angular/core';
+
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import { Survey } from 'src/app/metamodel/models';
+import { AbstractSearchMultipleComponent } from './abstract-search-multiple.component';
+import * as searchMultipleActions from '../../store/actions/search-multiple.actions';
+import * as surveySelector from 'src/app/metamodel/selectors/survey.selector';
+
+@Component({
+    selector: 'app-datasets',
+    templateUrl: 'datasets.component.html'
+})
+export class DatasetsComponent extends AbstractSearchMultipleComponent {
+    public surveyListIsLoading: Observable<boolean>;
+    public surveyListIsLoaded: Observable<boolean>;
+    public surveyList: Observable<Survey[]>;
+
+    constructor(protected store: Store<{ }>) {
+        super(store);
+        this.surveyListIsLoading = store.select(surveySelector.selectSurveyListIsLoading);
+        this.surveyListIsLoaded = store.select(surveySelector.selectSurveyListIsLoaded);
+        this.surveyList = store.select(surveySelector.selectAllSurveys);
+    }
+
+    ngOnInit() {
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.changeStep({ step: 'datasets' })));
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.checkDatasets()));
+        super.ngOnInit();
+    }
+
+    updateSelectedDatasets(selectedDatasets: string[]) {
+        this.store.dispatch(searchMultipleActions.updateSelectedDatasets({ selectedDatasets }));
+    }
+}
diff --git a/client/src/app/instance/search-multiple/containers/position.component.html b/client/src/app/instance/search-multiple/containers/position.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..c12f7eee58be2fcc472afa3b853db897c874d433
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/position.component.html
@@ -0,0 +1,47 @@
+<app-spinner *ngIf="(pristine | async) || (datasetFamilyListIsLoading | async) || (datasetListIsLoading | async)">
+</app-spinner>
+
+<div *ngIf="!(pristine | async) && (datasetFamilyListIsLoaded | async) && (datasetListIsLoaded | async)" class="row mt-4">
+    <div class="col-12 col-md-8 col-lg-9">
+        <div class="border rounded my-2">
+            <p class="border-bottom bg-light text-primary mb-0 py-4 pl-4">Cone Search</p>
+            <div class="row p-4">
+                <div class="col">
+                    <app-cone-search
+                        [coneSearch]="coneSearch | async"
+                        [resolver]="resolver | async"
+                        [resolverIsLoading]="resolverIsLoading | async"
+                        [resolverIsLoaded]="resolverIsLoaded | async"
+                        (retrieveCoordinates)="retrieveCoordinates($event)" #cs>
+                    </app-cone-search>
+                </div>
+                <div class="col-2 text-center align-self-end">
+                    <button class="btn btn-outline-success" *ngIf="!(coneSearch | async)" [hidden]="cs.form.invalid" (click)="addConeSearch(cs.getConeSearch())">
+                        <span class="fas fa-plus fa-fw"></span>
+                    </button>
+                    <button class="btn btn-outline-danger" *ngIf="coneSearch | async" (click)="deleteConeSearch()">
+                        <span class="fa fa-times fa-fw"></span>
+                    </button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="col-12 col-md-4 col-lg-3 pt-2">
+        <app-summary-multiple
+            [currentStep]="currentStep | async"
+            [coneSearch]="coneSearch | async"
+            [selectedDatasets]="selectedDatasets | async"
+            [queryParams]="queryParams | async"
+            [datasetFamilyList]="datasetFamilyList | async"
+            [datasetList]="datasetList | async">
+        </app-summary-multiple>
+    </div>
+</div>
+
+<div *ngIf="coneSearch | async" class="row mt-5 justify-content-end">
+    <div class="col col-auto">
+        <a routerLink="/instance/{{ instanceSelected | async }}/search-multiple/datasets" [queryParams]="queryParams | async"
+            class="btn btn-outline-primary">Datasets <span class="fas fa-arrow-right"></span>
+        </a>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/containers/position.component.ts b/client/src/app/instance/search-multiple/containers/position.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dea597950d3f0c527909d7059537152eda0c00f8
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/position.component.ts
@@ -0,0 +1,53 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component } from '@angular/core';
+
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import { AbstractSearchMultipleComponent } from './abstract-search-multiple.component';
+import { Resolver, ConeSearch } from '../../store/models';
+import * as searchMultipleActions from '../../store/actions/search-multiple.actions';
+import * as coneSearchActions from '../../store/actions/cone-search.actions';
+import * as coneSearchSelector from '../../store/selectors/cone-search.selector';
+
+@Component({
+    selector: 'app-position',
+    templateUrl: 'position.component.html'
+})
+export class PositionComponent extends AbstractSearchMultipleComponent {
+    public resolver: Observable<Resolver>;
+    public resolverIsLoading: Observable<boolean>;
+    public resolverIsLoaded: Observable<boolean>;
+
+    constructor(protected store: Store<{ }>) {
+        super(store);
+        this.resolver = this.store.select(coneSearchSelector.selectResolver);
+        this.resolverIsLoading = this.store.select(coneSearchSelector.selectResolverIsLoading);
+        this.resolverIsLoaded = this.store.select(coneSearchSelector.selectResolverIsLoaded);
+    }
+
+    ngOnInit() {
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.changeStep({ step: 'position' })));
+        super.ngOnInit();
+    }
+
+    addConeSearch(coneSearch: ConeSearch): void {
+        this.store.dispatch(coneSearchActions.addConeSearch({ coneSearch }));
+    }
+
+    deleteConeSearch(): void {
+        this.store.dispatch(coneSearchActions.deleteConeSearch());
+    }
+
+    retrieveCoordinates(name: string): void {
+        this.store.dispatch(coneSearchActions.retrieveCoordinates({ name }));
+    }
+}
diff --git a/client/src/app/instance/search-multiple/containers/result-multiple.component.html b/client/src/app/instance/search-multiple/containers/result-multiple.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..258f1567d2d3f55ae3fba8ef57b014824078f4a8
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/result-multiple.component.html
@@ -0,0 +1,41 @@
+<app-spinner *ngIf="(datasetFamilyListIsLoading | async) || (datasetListIsLoading | async) || (dataLengthIsLoading | async)">
+</app-spinner>
+
+<div *ngIf="(datasetFamilyListIsLoaded | async) && (datasetListIsLoaded | async) || (dataLengthIsLoaded | async)" class="row mt-4">
+    <div class="col-12">
+        <app-overview
+            [instanceSelected]="instanceSelected | async"
+            [datasetFamilyList]="datasetFamilyList | async"
+            [datasetList]="datasetList | async"
+            [coneSearch]="coneSearch | async"
+            [selectedDatasets]="selectedDatasets | async"
+            [dataLength]="dataLength | async"
+            [queryParams]="queryParams | async">
+        </app-overview>
+        <!--
+        <app-datasets-result
+            [datasetsCountIsLoaded]="datasetsCountIsLoaded | async"
+            [datasetFamilyList]="datasetFamilyList | async"
+            [datasetList]="datasetList | async"
+            [coneSearch]="coneSearch | async"
+            [selectedDatasets]="selectedDatasets | async"
+            [datasetsCount]="datasetsCount | async"
+            [datasetsWithAttributeList]="datasetsWithAttributeList | async"
+            [allAttributeList]="allAttributeList | async"
+            [datasetsWithData]="datasetsWithData | async"
+            [allData]="allData | async"
+            [selectedData]="selectedData | async"
+            (retrieveMeta)="retrieveMeta($event)"
+            (retrieveData)="retrieveData($event)"
+            (updateSelectedData)="updateSelectedData($event)">
+        </app-datasets-result> -->
+    </div>
+</div>
+<div class="row mt-5 justify-content-between">
+    <div class="col">
+        <a routerLink="/instance/{{ instanceSelected | async }}/search-multiple/datasets" [queryParams]="queryParams | async" 
+            class="btn btn-outline-secondary">
+            <span class="fas fa-arrow-left"></span> Datasets
+        </a>
+    </div>
+</div>
diff --git a/client/src/app/instance/search-multiple/containers/result-multiple.component.ts b/client/src/app/instance/search-multiple/containers/result-multiple.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e4d66b40fbfcad6aabcededb30c6f628554f20d
--- /dev/null
+++ b/client/src/app/instance/search-multiple/containers/result-multiple.component.ts
@@ -0,0 +1,60 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component } from '@angular/core';
+
+import { Observable, Subscription } from 'rxjs';
+import { Store } from '@ngrx/store';
+
+import { SearchMultipleDatasetLength, SearchMultipleDatasetData } from '../../store/models';
+import { AbstractSearchMultipleComponent } from './abstract-search-multiple.component';
+import * as searchMultipleActions from '../../store/actions/search-multiple.actions';
+import * as searchMultipleSelector from 'src/app/instance/store/selectors/search-multiple.selector';
+
+@Component({
+    selector: 'app-result-multiple',
+    templateUrl: 'result-multiple.component.html'
+})
+export class ResultMultipleComponent extends AbstractSearchMultipleComponent {
+    public dataLength: Observable<SearchMultipleDatasetLength[]>;
+    public dataLengthIsLoading: Observable<boolean>;
+    public dataLengthIsLoaded: Observable<boolean>;
+    public data: Observable<SearchMultipleDatasetData[]>;
+    public dataIsLoading: Observable<boolean>;
+    public dataIsLoaded: Observable<boolean>;
+
+    private pristineSubscription: Subscription;
+
+    constructor(protected store: Store<{ }>) {
+        super(store);
+        this.dataLength = this.store.select(searchMultipleSelector.selectDataLength);
+        this.dataLengthIsLoading = this.store.select(searchMultipleSelector.selectDataLengthIsLoading);
+        this.dataLengthIsLoaded = this.store.select(searchMultipleSelector.selectDataLengthIsLoaded);
+        this.data = this.store.select(searchMultipleSelector.selectData);
+        this.dataIsLoading = this.store.select(searchMultipleSelector.selectDataIsLoading);
+        this.dataIsLoaded = this.store.select(searchMultipleSelector.selectDataIsLoaded);
+    }
+
+    ngOnInit() {
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.changeStep({ step: 'result' })));
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.checkDatasets()));
+        Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.checkResult()));
+        super.ngOnInit();
+        this.pristineSubscription = this.pristine.subscribe(pristine => {
+            if (!pristine) {
+                Promise.resolve(null).then(() => this.store.dispatch(searchMultipleActions.retrieveDataLength()));
+            }
+        });
+    }
+
+    ngOnDestroy() {
+        this.pristineSubscription.unsubscribe();
+        super.ngOnDestroy();
+    }
+}
diff --git a/client/src/app/instance/search-multiple/search-multiple-routing.module.ts b/client/src/app/instance/search-multiple/search-multiple-routing.module.ts
index 4438a68664b0e8e931aabab371af2a8841fc845f..a3590eb28c7d96bbd48addb36fa15a9d00c3ff0b 100644
--- a/client/src/app/instance/search-multiple/search-multiple-routing.module.ts
+++ b/client/src/app/instance/search-multiple/search-multiple-routing.module.ts
@@ -10,10 +10,20 @@
 import { NgModule } from '@angular/core';
 import { Routes, RouterModule } from '@angular/router';
 
-//import { SearchMultipleComponent } from './search-multiple.component';
+import { SearchMultipleComponent } from './search-multiple.component';
+import { PositionComponent } from './containers/position.component';
+import { DatasetsComponent } from './containers/datasets.component';
+import { ResultMultipleComponent } from './containers/result-multiple.component';
 
 const routes: Routes = [
-    //{ path: '', component: SearchMultipleComponent }
+    {
+        path: '', component: SearchMultipleComponent, children: [
+            { path: '', redirectTo: 'position', pathMatch: 'full' },
+            { path: 'position', component: PositionComponent },
+            { path: 'datasets', component: DatasetsComponent },
+            { path: 'result', component: ResultMultipleComponent }
+        ]
+    }
 ];
 
 @NgModule({
@@ -23,5 +33,8 @@ const routes: Routes = [
 export class SearchMultipleRoutingModule { }
 
 export const routedComponents = [
-    //SearchMultipleComponent
+    SearchMultipleComponent,
+    PositionComponent,
+    DatasetsComponent,
+    ResultMultipleComponent
 ];
diff --git a/client/src/app/instance/search-multiple/search-multiple.component.html b/client/src/app/instance/search-multiple/search-multiple.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..7f7342be55b65395e810bc751799628776dea30e
--- /dev/null
+++ b/client/src/app/instance/search-multiple/search-multiple.component.html
@@ -0,0 +1,13 @@
+<div class="mx-1 mx-sm-5 px-1 px-sm-5">
+    <app-progress-bar-multiple
+        [instance]="instance | async"
+        [currentStep]="currentStep | async"
+        [positionStepChecked]="positionStepChecked | async"
+        [datasetsStepChecked]="datasetsStepChecked | async"
+        [resultStepChecked]="resultStepChecked | async"
+        [coneSearch]="coneSearch | async"
+        [selectedDatasets]="selectedDatasets | async"
+        [queryParams]="queryParams | async">
+    </app-progress-bar-multiple>
+    <router-outlet></router-outlet>
+</div>
diff --git a/client/src/app/instance/search-multiple/search-multiple.component.ts b/client/src/app/instance/search-multiple/search-multiple.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b0d2b7b88a44d5099b04b2455761c63191ecc8da
--- /dev/null
+++ b/client/src/app/instance/search-multiple/search-multiple.component.ts
@@ -0,0 +1,49 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Component, } from '@angular/core';
+
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import { ConeSearch, SearchMultipleQueryParams } from '../store/models';
+import { Instance } from 'src/app/metamodel/models';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as searchMultipleSelector from '../store/selectors/search-multiple.selector';
+import * as coneSearchSelector from '../store/selectors/cone-search.selector';
+
+@Component({
+    selector: 'app-search-multiple',
+    templateUrl: 'search-multiple.component.html'
+})
+/**
+ * @class
+ * @classdesc Search multiple container.
+ */
+export class SearchMultipleComponent {
+    public instance: Observable<Instance>;
+    public currentStep: Observable<string>;
+    public positionStepChecked: Observable<boolean>;
+    public datasetsStepChecked: Observable<boolean>;
+    public resultStepChecked: Observable<boolean>;
+    public coneSearch: Observable<ConeSearch>;
+    public selectedDatasets: Observable<string[]>;
+    public queryParams: Observable<SearchMultipleQueryParams>;
+
+    constructor(private store: Store<{ }>) {
+        this.instance = this.store.select(instanceSelector.selectInstanceByRouteName);
+        this.currentStep = this.store.select(searchMultipleSelector.selectCurrentStep);
+        this.positionStepChecked = this.store.select(searchMultipleSelector.selectPositionStepChecked);
+        this.datasetsStepChecked = this.store.select(searchMultipleSelector.selectDatasetsStepChecked);
+        this.resultStepChecked = this.store.select(searchMultipleSelector.selectResultStepChecked);
+        this.coneSearch = this.store.select(coneSearchSelector.selectConeSearch);
+        this.selectedDatasets = this.store.select(searchMultipleSelector.selectSelectedDatasets);
+        this.queryParams = this.store.select(searchMultipleSelector.selectQueryParams);
+    }
+}
diff --git a/client/src/app/instance/search-multiple/search-multiple.module.ts b/client/src/app/instance/search-multiple/search-multiple.module.ts
index 6368aaf5ac0eed7e0f4be27e5839c470efd21e25..f309487d7a04e1e064c428c6a1303379f093d57d 100644
--- a/client/src/app/instance/search-multiple/search-multiple.module.ts
+++ b/client/src/app/instance/search-multiple/search-multiple.module.ts
@@ -10,13 +10,19 @@
 import { NgModule } from '@angular/core';
 
 import { SharedModule } from 'src/app/shared/shared.module';
+import { SharedSearchModule } from '../shared-search/shared-search.module';
 import { SearchMultipleRoutingModule, routedComponents } from './search-multiple-routing.module';
+import { dummiesComponents } from './components';
 
 @NgModule({
     imports: [
         SharedModule,
+        SharedSearchModule,
         SearchMultipleRoutingModule
     ],
-    declarations: [routedComponents]
+    declarations: [
+        routedComponents,
+        dummiesComponents
+    ]
 })
 export class SearchMultipleModule { }
diff --git a/client/src/app/instance/search/components/criteria/cone-search-tab.component.html b/client/src/app/instance/search/components/criteria/cone-search-tab.component.html
index ea951c32bd3106f1c745ad5e18876c73d592bad5..f3ec7c1649ba70a4fb2d5a3c4ae111451c49fd15 100644
--- a/client/src/app/instance/search/components/criteria/cone-search-tab.component.html
+++ b/client/src/app/instance/search/components/criteria/cone-search-tab.component.html
@@ -19,8 +19,6 @@
                     [resolver]="resolver"
                     [resolverIsLoading]="resolverIsLoading"
                     [resolverIsLoaded]="resolverIsLoaded"
-                    (addConeSearch)="addConeSearch.emit($event)"
-                    (deleteConeSearch)="deleteConeSearch.emit()"
                     (retrieveCoordinates)="retrieveCoordinates.emit($event)" #cs>
                 </app-cone-search>
             </div>
diff --git a/client/src/app/instance/search/components/criteria/criteria-by-family.component.html b/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
index dd9b10ecfa1ba5ad05f4bef58d948d7eb59a8165..08f385e6d3361791bd67c7e2ae7f2ec88dfddbea 100644
--- a/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
+++ b/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
@@ -1,4 +1,4 @@
-<div *ngFor="let attribute of getAttributeListSortedByDisplay()">
+<div *ngFor="let attribute of attributeList">
     <div [ngSwitch]="attribute.search_type">
         <div *ngSwitchCase="'field'">
             <app-field class="criteria" 
diff --git a/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts b/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
index ed525e72ea70a3f5e38775b170ccf2811cb12dcd..b249169a910b240ef5c848f78f9bc37cbfa6ad79 100644
--- a/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
+++ b/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
@@ -29,16 +29,6 @@ export class CriteriaByFamilyComponent {
 
     advancedForm = false;
 
-    /**
-     * Returns attribute list sorted by criteria display.
-     *
-     * @return Attribute[]
-     */
-    getAttributeListSortedByDisplay(): Attribute[] {
-        return this.attributeList
-            .sort((a, b) => a.criteria_display - b.criteria_display);
-    }
-
     /**
      * Returns options for the given attribute ID.
      *
diff --git a/client/src/app/instance/search/components/dataset/dataset-card.component.html b/client/src/app/instance/search/components/dataset/dataset-card.component.html
index 190c9bc953e14a62ffc4528a79053ed03dece876..07daf796a9f9c039bfa6c6f3594d250604c57646 100644
--- a/client/src/app/instance/search/components/dataset/dataset-card.component.html
+++ b/client/src/app/instance/search/components/dataset/dataset-card.component.html
@@ -10,7 +10,7 @@
                 <div class="row">
                     <p class="my-3">{{ dataset.description }}</p>
                 </div>
-                <div class="row">
+                <div *ngIf="dataset.config.survey.survey_enabled" class="row">
                     <button class="btn btn-link p-0" 
                         popover="{{ survey.description }}" 
                         popoverTitle="{{ survey.label }}"
@@ -18,7 +18,7 @@
                         [outsideClick]="true" 
                         triggers="mouseenter:mouseleave">
                         <small>
-                            More about {{ survey.label }} survey <span class="fas fa-question-circle"></span>
+                            {{ dataset.config.survey.survey_label }} <span class="fas fa-question-circle"></span>
                         </small>
                     </button>
                 </div>
diff --git a/client/src/app/instance/search/components/output/output-by-category.component.html b/client/src/app/instance/search/components/output/output-by-category.component.html
index 7888b9a0acb076a724a631a25a3ef7095f667414..9ffecf619e406e41644270f2d15cbd97c0639770 100644
--- a/client/src/app/instance/search/components/output/output-by-category.component.html
+++ b/client/src/app/instance/search/components/output/output-by-category.component.html
@@ -14,7 +14,7 @@
     </div>
 </div>
 <div class="selectbox p-0">
-    <div *ngFor="let attribute of getAttributeListSortedByDisplay()">
+    <div *ngFor="let attribute of attributeList">
         <div *ngIf="isSelected(attribute.id)">
             <button class="btn btn-block text-left py-1 m-0 rounded-0" (click)="toggleSelection(attribute.id)">
                 <span class="fas fa-fw fa-check-square" [ngStyle]="{ 'color': designColor }"></span> {{ attribute.form_label }}
diff --git a/client/src/app/instance/search/components/output/output-by-category.component.ts b/client/src/app/instance/search/components/output/output-by-category.component.ts
index 3cfd66d0ad7da4de3456540fb4f15bf210fad09a..830f1495803575e40d45722c797581fa68ec7e56 100644
--- a/client/src/app/instance/search/components/output/output-by-category.component.ts
+++ b/client/src/app/instance/search/components/output/output-by-category.component.ts
@@ -30,16 +30,6 @@ export class OutputByCategoryComponent {
     @Input() isAllUnselected: boolean;
     @Output() change: EventEmitter<number[]> = new EventEmitter();
 
-    /**
-     * Returns output list sorted by output display.
-     *
-     * @return Attribute[]
-     */
-    getAttributeListSortedByDisplay(): Attribute[] {
-        return this.attributeList
-            .sort((a, b) => a.output_display - b.output_display);
-    }
-
     /**
      * Checks if the given output ID is selected.
      *
diff --git a/client/src/app/instance/search/components/output/output-by-family.component.ts b/client/src/app/instance/search/components/output/output-by-family.component.ts
index 23ff1ee0def5dc3eab3841d656115303b1e3f9c5..331058f4052dcfda301b16856e7c8527164b96ce 100644
--- a/client/src/app/instance/search/components/output/output-by-family.component.ts
+++ b/client/src/app/instance/search/components/output/output-by-family.component.ts
@@ -89,7 +89,6 @@ export class OutputByFamilyComponent {
         this.change.emit(
             this.attributeList
                 .filter(a => clonedOutputList.indexOf(a.id) > -1)
-                .sort((a, b) => a.output_display - b.output_display)
                 .map(a => a.id)
         );
     }
diff --git a/client/src/app/instance/search/components/result/download.component.html b/client/src/app/instance/search/components/result/download.component.html
index 4f9d94496d025ae285d6bd9a7c30ad0e1db42fe8..5fc5683f29b4555db3b7c386b4ac69443785314b 100644
--- a/client/src/app/instance/search/components/result/download.component.html
+++ b/client/src/app/instance/search/components/result/download.component.html
@@ -18,15 +18,15 @@
                     <p>Download results just here:</p>
                 </div>
                 <div class="col">
-                    <a *ngIf="getConfigDownloadResultFormat('download_csv')" [href]="getUrl('csv')" class="btn btn-outline-primary" title="Download results in CSV format">
+                    <a *ngIf="getConfigDownloadResultFormat('download_csv')" [href]="getUrl('csv')" (click)="click($event, getUrl('csv'), 'csv')" class="btn btn-outline-primary" title="Download results in CSV format">
                         <i class="fas fa-file-csv"></i> CSV
                     </a>
                     &nbsp;
-                    <a *ngIf="getConfigDownloadResultFormat('download_ascii')" [href]="getUrl('ascii')" target="_blank" class="btn btn-outline-primary" title="Download results in ASCII format">
+                    <a *ngIf="getConfigDownloadResultFormat('download_ascii')" [href]="getUrl('ascii')" (click)="click($event, getUrl('ascii'), 'txt')" class="btn btn-outline-primary" title="Download results in ASCII format">
                         <i class="fas fa-file"></i> ASCII
                     </a>
                     &nbsp;
-                    <a *ngIf="getConfigDownloadResultFormat('download_vo')" [href]="getUrl('votable')" target="_blank" class="btn btn-outline-primary" title="Download results in VO format">
+                    <a *ngIf="getConfigDownloadResultFormat('download_vo')" [href]="getUrl('votable')" (click)="click($event, getUrl('votable'), 'xml')" class="btn btn-outline-primary" title="Download results in VO format">
                         <i class="fas fa-file"></i> VOtable
                     </a>
                     &nbsp;
@@ -41,7 +41,7 @@
                     <p>Download archive files just here:</p>
                 </div>
                 <div class="col">
-                    <a [href]="getUrlArchive()" class="btn btn-outline-primary" title="Download an archive with all files">
+                    <a [href]="getUrlArchive()" (click)="click($event, getUrlArchive(), 'zip')" class="btn btn-outline-primary" title="Download an archive with all files">
                         <i class="fas fa-archive"></i> Files archive
                     </a>
                 </div>
diff --git a/client/src/app/instance/search/components/result/download.component.ts b/client/src/app/instance/search/components/result/download.component.ts
index 10607d8459b2b922a870567a800cd031fd3d4578..b0498b150edd0e4fb3b223875692fd6063aac658 100644
--- a/client/src/app/instance/search/components/result/download.component.ts
+++ b/client/src/app/instance/search/components/result/download.component.ts
@@ -8,6 +8,7 @@
  */
 
 import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
 
 import { Criterion, ConeSearch, criterionToString } from '../../../store/models';
 import { Dataset } from 'src/app/metamodel/models';
@@ -34,7 +35,7 @@ export class DownloadComponent {
     @Input() sampRegistered: boolean;
     @Output() broadcast: EventEmitter<string> = new EventEmitter();
 
-    constructor(private appConfig: AppConfigService) { }
+    constructor(private appConfig: AppConfigService, private http: HttpClient) { }
 
     isDownloadActivated(): boolean {
         const dataset = this.datasetList.find(dataset => dataset.name === this.datasetSelected);
@@ -91,4 +92,17 @@ export class DownloadComponent {
     broadcastVotable(): void {
         this.broadcast.emit(this.getUrl('votable'));
     }
+
+    click(event, href, extension) {
+        event.preventDefault();
+
+        this.http.get(href, {responseType: "blob"}).subscribe(
+            data => {
+                let downloadLink = document.createElement('a');
+                downloadLink.href = window.URL.createObjectURL(data);
+                downloadLink.setAttribute('download', `${this.datasetSelected}.${extension}`);
+                downloadLink.click();
+            }
+        );
+    }
 }
diff --git a/client/src/app/instance/search/components/summary.component.ts b/client/src/app/instance/search/components/summary.component.ts
index 3e76c6275872536dca5f00257e2969ea611ad3b3..10170ce92de91aa238a7afd542a5e2ddc565fe4a 100644
--- a/client/src/app/instance/search/components/summary.component.ts
+++ b/client/src/app/instance/search/components/summary.component.ts
@@ -88,9 +88,7 @@ export class SummaryComponent {
      * @return Category[]
      */
     getCategoryByFamilySortedByDisplay(idFamily: number): OutputCategory[] {
-        return this.outputCategoryList
-            .filter(category => category.id_output_family === idFamily)
-            //.sort(sortByDisplay);
+        return this.outputCategoryList.filter(category => category.id_output_family === idFamily)
     }
 
     /**
@@ -102,8 +100,6 @@ export class SummaryComponent {
      */
     getSelectedOutputByCategory(idCategory: number): Attribute[] {
         const outputListByCategory = this.attributeList.filter(attribute => attribute.id_output_category === idCategory);
-        return outputListByCategory
-            .filter(attribute => this.outputList.includes(attribute.id))
-            .sort((a, b) => a.output_display - b.output_display);
+        return outputListByCategory.filter(attribute => this.outputList.includes(attribute.id));
     }
 }
diff --git a/client/src/app/instance/search/containers/criteria.component.html b/client/src/app/instance/search/containers/criteria.component.html
index 8ff2d1d903ea462d493393f6efa68700811f4265..d21e4e515041a80ba8e2b672cabea8260dedde89 100644
--- a/client/src/app/instance/search/containers/criteria.component.html
+++ b/client/src/app/instance/search/containers/criteria.component.html
@@ -19,7 +19,7 @@
             (retrieveCoordinates)="retrieveCoordinates($event)">
         </app-cone-search-tab>
         <app-criteria-tabs 
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByCriteriaDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [criteriaList]="criteriaList | async"
             (addCriterion)="addCriterion($event)" 
@@ -32,7 +32,7 @@
             [currentStep]="currentStep | async"
             [datasetSelected]="datasetSelected | async"
             [datasetList]="datasetList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/dataset.component.html b/client/src/app/instance/search/containers/dataset.component.html
index 77107988152d7cafa0de1aee2c1d0172768d3afd..3b0dd7da561982ad3c9797ac4d436daf82e5c08a 100644
--- a/client/src/app/instance/search/containers/dataset.component.html
+++ b/client/src/app/instance/search/containers/dataset.component.html
@@ -30,7 +30,7 @@
                 [currentStep]="currentStep | async"
                 [datasetSelected]="datasetSelected | async"
                 [datasetList]="datasetList | async"
-                [attributeList]="attributeList | async"
+                [attributeList]="attributeList | async | sortByOutputDisplay"
                 [criteriaFamilyList]="criteriaFamilyList | async"
                 [outputFamilyList]="outputFamilyList | async"
                 [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/output.component.html b/client/src/app/instance/search/containers/output.component.html
index db66948c6961e8d968487796e09c4723027f6337..8133aecab64ed999ecbcd3096ef522fe9783bac3 100644
--- a/client/src/app/instance/search/containers/output.component.html
+++ b/client/src/app/instance/search/containers/output.component.html
@@ -8,7 +8,7 @@
     && (outputCategoryListIsLoaded | async)" class="row mt-4">
     <div class="col-12 col-md-8 col-lg-9">
         <app-output-tabs 
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [outputFamilyList]="outputFamilyList | async" 
             [outputCategoryList]="outputCategoryList | async"
             [outputList]="outputList | async"
@@ -22,7 +22,7 @@
             [currentStep]="currentStep | async"
             [datasetSelected]="datasetSelected | async"
             [datasetList]="datasetList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html
index d9b4fdbf2a8260fc9d97ecb02df3294d25a04e9f..052cf4ed64375604dfdd2b3e57adeb0509ff5205 100644
--- a/client/src/app/instance/search/containers/result.component.html
+++ b/client/src/app/instance/search/containers/result.component.html
@@ -38,7 +38,7 @@
             <app-reminder
                 [datasetSelected]="datasetSelected | async"
                 [datasetList]="datasetList | async"
-                [attributeList]="attributeList | async"
+                [attributeList]="attributeList | async | sortByOutputDisplay"
                 [criteriaFamilyList]="criteriaFamilyList | async"
                 [outputFamilyList]="outputFamilyList | async"
                 [outputCategoryList]="outputCategoryList | async"
@@ -74,7 +74,7 @@
                 [datasetSelected]="datasetSelected | async"
                 [instance]="instance | async"
                 [datasetList]="datasetList | async"
-                [attributeList]="attributeList | async"
+                [attributeList]="attributeList | async | sortByOutputDisplay"
                 [outputList]="outputList | async"
                 [queryParams]="queryParams | async"
                 [dataLength]="dataLength | async"
diff --git a/client/src/app/instance/search/containers/result.component.ts b/client/src/app/instance/search/containers/result.component.ts
index 82f65348ed3b1cd56878cb116aa9eaae9053fec9..f62ca538ed8b10b2a94be5d2b5e3778e92907a22 100644
--- a/client/src/app/instance/search/containers/result.component.ts
+++ b/client/src/app/instance/search/containers/result.component.ts
@@ -68,7 +68,7 @@ export class ResultComponent extends AbstractSearchComponent {
             if (!pristine) {
                 Promise.resolve(null).then(() => this.store.dispatch(searchActions.retrieveDataLength()));
             }
-        })
+        });
     }
 
     sampRegister() {
diff --git a/client/src/app/instance/search/pipes/index.ts b/client/src/app/instance/search/pipes/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dd9b75775430c5435ec14b392378948d3f3f9629
--- /dev/null
+++ b/client/src/app/instance/search/pipes/index.ts
@@ -0,0 +1,16 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { SortByCriteriaDisplay } from './sort-by-criteria-display';
+import { SortByOutputDisplay } from './sort-by-output-display';
+
+export const searchPipes = [
+    SortByCriteriaDisplay,
+    SortByOutputDisplay
+];
\ No newline at end of file
diff --git a/client/src/app/instance/search/pipes/sort-by-criteria-display.ts b/client/src/app/instance/search/pipes/sort-by-criteria-display.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c6c8bd4a8ce5b6830be220ed0f33c5a0807133b9
--- /dev/null
+++ b/client/src/app/instance/search/pipes/sort-by-criteria-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByCriteriaDisplay'})
+export class SortByCriteriaDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.criteria_display - b.criteria_display);
+    }
+}
diff --git a/client/src/app/instance/search/pipes/sort-by-output-display.ts b/client/src/app/instance/search/pipes/sort-by-output-display.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cfd308029821814d55f3a88641d1cf2ff3e06803
--- /dev/null
+++ b/client/src/app/instance/search/pipes/sort-by-output-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByOutputDisplay'})
+export class SortByOutputDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.output_display - b.output_display);
+    }
+}
diff --git a/client/src/app/instance/search/search.module.ts b/client/src/app/instance/search/search.module.ts
index 63eef0ff7d627926da0f1dd73535176b9bd1a303..0d25c4b7aa49df21fdd55d7bdf27e4bf458d2402 100644
--- a/client/src/app/instance/search/search.module.ts
+++ b/client/src/app/instance/search/search.module.ts
@@ -13,6 +13,7 @@ import { SharedModule } from 'src/app/shared/shared.module';
 import { SharedSearchModule } from '../shared-search/shared-search.module';
 import { SearchRoutingModule, routedComponents } from './search-routing.module';
 import { dummiesComponents } from './components';
+import { searchPipes } from './pipes';
 
 @NgModule({
     imports: [
@@ -22,7 +23,8 @@ import { dummiesComponents } from './components';
     ],
     declarations: [
         routedComponents,
-        dummiesComponents
+        dummiesComponents,
+        searchPipes
     ]
 })
 export class SearchModule { }
diff --git a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts
index 59de49ada64fd52e4fcd09720480a1bb8d2daf7d..0bd90e12c4ef706ddd60ccb4bf6a151e8ea2eb6e 100644
--- a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts
+++ b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts
@@ -26,8 +26,6 @@ export class ConeSearchComponent implements OnChanges {
     @Input() resolver: Resolver;
     @Input() resolverIsLoading: boolean;
     @Input() resolverIsLoaded: boolean;
-    @Output() addConeSearch: EventEmitter<ConeSearch> = new EventEmitter();
-    @Output() deleteConeSearch: EventEmitter<{ }> = new EventEmitter();
     @Output() retrieveCoordinates: EventEmitter<string> = new EventEmitter();
 
     public form = new FormGroup({
diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.html b/client/src/app/instance/shared-search/components/datatable/datatable.component.html
index 7b7ee23a3405f901e1183f30f59c9dbbbfeceefc..ecb7f5726a7055b7592d8fc099ca53845d04bb19 100644
--- a/client/src/app/instance/shared-search/components/datatable/datatable.component.html
+++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.html
@@ -40,7 +40,7 @@
                     </button>
                 </td>
                 <td *ngFor="let attribute of getOutputList()" class="align-middle">
-                    <div [ngSwitch]="attribute.renderer">
+                    <div *ngIf="datum[attribute.label]" [ngSwitch]="attribute.renderer">
                         <div *ngSwitchCase="'detail'">
                             <app-detail-renderer
                                 [value]="datum[attribute.label]"
@@ -61,6 +61,7 @@
                             <app-download-renderer
                                 [value]="datum[attribute.label]"
                                 [datasetName]="dataset.name"
+                                [datasetPublic]="dataset.public"
                                 [config]="getRendererConfig(attribute)">
                             </app-download-renderer>
                         </div>
diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
index 1e90851ca9be53f1a232c612002eb5a8ae64981f..08038733980a47f874e9665701321a37fb373204 100644
--- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
+++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
@@ -85,8 +85,7 @@ export class DatatableComponent implements OnInit {
      */
     getOutputList(): Attribute[] {
         return this.attributeList
-            .filter(a => this.outputList.includes(a.id))
-            .sort((a, b) => a.output_display - b.output_display);
+            .filter(a => this.outputList.includes(a.id));
     }
 
     /**
diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.html b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.html
index aef5f0ea9282018d805f76a7cd788e1921333b61..ad2ae4dd7e841767556c40e6e838c75b69eb9608 100644
--- a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.html
+++ b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.html
@@ -1,4 +1,4 @@
-<a [href]="getHref()" [ngClass]="{'btn btn-outline-primary btn-sm': (config.display=='text-button' || config.display=='icon-button' || config.display=='icon-text-btn')}">
+<a [href]="getHref()" (click)="click($event)" [ngClass]="{'btn btn-outline-primary btn-sm': (config.display=='text-button' || config.display=='icon-button' || config.display=='icon-text-btn')}">
     <span *ngIf="config.display === 'icon-button' || config.display === 'icon-text-btn'" class="{{config.icon}}"></span>
     <span *ngIf="config.display === 'icon-text-btn'">&nbsp;</span>
     <span *ngIf="config.display !== 'icon-button'">{{ getText() }}</span>
diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
index 19bcc38572ede27f043ee814f2f330d76eabeb25..56475b8e0d2615e254096a12f551caaa5338b4b9 100644
--- a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
+++ b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
@@ -8,6 +8,7 @@
  */
 
 import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
 
 import { DownloadRendererConfig } from 'src/app/metamodel/models/renderers/download-renderer-config.model';
 import { getHost } from 'src/app/shared/utils';
@@ -25,9 +26,10 @@ import { AppConfigService } from 'src/app/app-config.service';
 export class DownloadRendererComponent {
     @Input() value: string;
     @Input() datasetName: string;
+    @Input() datasetPublic: boolean;
     @Input() config: DownloadRendererConfig;
 
-    constructor(private appConfig: AppConfigService) { }
+    constructor(private appConfig: AppConfigService, private http: HttpClient) { }
 
     /**
      * Returns link href.
@@ -46,4 +48,20 @@ export class DownloadRendererComponent {
     getText(): string {
         return this.config.text.replace('$value', this.value.toString());
     }
+
+    click(event) {
+        event.preventDefault();
+
+        const href = this.getHref();
+        this.http.get(href, {responseType: "blob"}).subscribe(
+            data => {
+                const filename = href.substring(href.lastIndexOf('/') + 1);
+
+                let downloadLink = document.createElement('a');
+                downloadLink.href = window.URL.createObjectURL(data);
+                downloadLink.setAttribute('download', filename);
+                downloadLink.click();
+            }
+        );
+    }
 }
diff --git a/client/src/app/instance/shared-search/detail/components/object-data.component.ts b/client/src/app/instance/shared-search/detail/components/object-data.component.ts
index 16de054ffd8348a0701382356e74f9412523540e..943dab66734787e4e0d44e4933d0ade6e51c7b0f 100644
--- a/client/src/app/instance/shared-search/detail/components/object-data.component.ts
+++ b/client/src/app/instance/shared-search/detail/components/object-data.component.ts
@@ -40,8 +40,7 @@ export class ObjectDataComponent {
      */
     getCategoryByFamilySortedByDisplay(idFamily: number): OutputCategory[] {
         return this.outputCategoryList
-            .filter(category => category.id_output_family === idFamily)
-            //.sort(sortByDisplay);
+            .filter(category => category.id_output_family === idFamily);
     }
 
     /**
@@ -54,8 +53,7 @@ export class ObjectDataComponent {
     getAttributesVisibleByCategory(idCategory: number): Attribute[] {
         return this.attributeList
             .filter(a => a.detail)
-            .filter(a => a.id_output_category === idCategory)
-            .sort((a, b) => a.display_detail - b.display_detail);
+            .filter(a => a.id_output_category === idCategory);
     }
 
     /**
@@ -64,9 +62,7 @@ export class ObjectDataComponent {
      * @return Attribute[]
      */
     getAttributesVisible(): Attribute[] {
-        return this.attributeList
-            .filter(a => a.detail)
-            .sort((a, b) => a.display_detail - b.display_detail);
+        return this.attributeList.filter(a => a.detail);
     }
 
     /**
diff --git a/client/src/app/instance/shared-search/detail/containers/detail.component.html b/client/src/app/instance/shared-search/detail/containers/detail.component.html
index 2899b8cf78fc9f670a81366d3efd8b049e074bc6..a17e8166574a26436d058f1db8718f1aad2c5a03 100644
--- a/client/src/app/instance/shared-search/detail/containers/detail.component.html
+++ b/client/src/app/instance/shared-search/detail/containers/detail.component.html
@@ -16,7 +16,7 @@
             [datasetSelected]="datasetSelected | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByDetailDisplay"
             [object]="object | async"
             [spectraCSV]="spectraCSV | async"
             [spectraIsLoading]="spectraIsLoading | async"
@@ -27,7 +27,7 @@
             [datasetSelected]="datasetSelected | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByDetailDisplay"
             [object]="object | async">
         </app-default-object>
     </div>
diff --git a/client/src/app/instance/shared-search/detail/detail.module.ts b/client/src/app/instance/shared-search/detail/detail.module.ts
index d9d97c4f5c9ae69ff1a5b6a85b6b71836f2f1767..af987eed26912d826161994901356c3edf6cd762 100644
--- a/client/src/app/instance/shared-search/detail/detail.module.ts
+++ b/client/src/app/instance/shared-search/detail/detail.module.ts
@@ -12,6 +12,7 @@ import { NgModule } from '@angular/core';
 import { SharedModule } from 'src/app/shared/shared.module';
 import { DetailComponent } from './containers/detail.component';
 import { dummiesComponents } from './components';
+import { detailPipes } from './pipes';
 
 @NgModule({
     imports: [
@@ -19,7 +20,8 @@ import { dummiesComponents } from './components';
     ],
     declarations: [
         DetailComponent,
-        dummiesComponents
+        dummiesComponents,
+        detailPipes
     ]
 })
 export class DetailModule { }
diff --git a/client/src/app/instance/shared-search/detail/pipes/index.ts b/client/src/app/instance/shared-search/detail/pipes/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a42bb61221d4720af663e83ca2f4413405bc688d
--- /dev/null
+++ b/client/src/app/instance/shared-search/detail/pipes/index.ts
@@ -0,0 +1,5 @@
+import { SortByDetailDisplay } from './sort-by-detail-display';
+
+export const detailPipes = [
+    SortByDetailDisplay
+];
diff --git a/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts b/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dd17a7ca46d072c91e36aa534811d4ae89a2ada4
--- /dev/null
+++ b/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByDetailDisplay'})
+export class SortByDetailDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.display_detail - b.display_detail);
+    }
+}
diff --git a/client/src/app/instance/store/actions/search-multiple.actions.ts b/client/src/app/instance/store/actions/search-multiple.actions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..87d20074517eeb51f87b1895a8c81f6d9a5161a8
--- /dev/null
+++ b/client/src/app/instance/store/actions/search-multiple.actions.ts
@@ -0,0 +1,26 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createAction, props } from '@ngrx/store';
+
+import { SearchMultipleDatasetLength, SearchMultipleDatasetData } from '../models';
+
+export const initSearch = createAction('[Search Multiple] Init Search');
+export const restartSearch = createAction('[Search Multiple] Restart Search');
+export const markAsDirty = createAction('[Search Multiple] Mark As Dirty');
+export const changeStep = createAction('[Search Multiple] Change Step', props<{ step: string }>());
+export const checkDatasets = createAction('[Search Multiple] Check Datasets');
+export const checkResult = createAction('[Search Multiple] Check Result');
+export const updateSelectedDatasets = createAction('[Search Multiple] Update Selected Datasets', props<{ selectedDatasets: string[] }>());
+export const retrieveDataLength = createAction('[Search Multiple] Retrieve Data Length');
+export const retrieveDataLengthSuccess = createAction('[Search Multiple] Retrieve Data Length Success', props<{ dataLength: SearchMultipleDatasetLength[] }>());
+export const retrieveDataLengthFail = createAction('[Search Multiple] Retrieve Data Length Fail');
+export const retrieveData = createAction('[Search Multiple] Retrieve Data');
+export const retrieveDataSuccess = createAction('[Search Multiple] Retrieve Data Success', props<{ data: SearchMultipleDatasetData[] }>());
+export const retrieveDataFail = createAction('[Search Multiple] Retrieve Data Fail');
diff --git a/client/src/app/instance/store/effects/index.ts b/client/src/app/instance/store/effects/index.ts
index 132bb177b9768dd206195f68ed2d2eef1ca6a8fd..582dd51102f0f5b76cdf2db4ff4fd0e3e36307b6 100644
--- a/client/src/app/instance/store/effects/index.ts
+++ b/client/src/app/instance/store/effects/index.ts
@@ -1,11 +1,13 @@
 import { SampEffects } from './samp.effects';
 import { SearchEffects } from './search.effects';
+import { SearchMultipleEffects } from './search-multiple.effects';
 import { ConeSearchEffects } from './cone-search.effects';
 import { DetailEffects } from './detail.effects';
 
 export const instanceEffects = [
     SampEffects,
     SearchEffects,
+    SearchMultipleEffects,
     ConeSearchEffects,
     DetailEffects
 ];
diff --git a/client/src/app/instance/store/effects/search-multiple.effects.ts b/client/src/app/instance/store/effects/search-multiple.effects.ts
new file mode 100644
index 0000000000000000000000000000000000000000..84382d44732bfb1c719f7d0cbaa96e4326c693a3
--- /dev/null
+++ b/client/src/app/instance/store/effects/search-multiple.effects.ts
@@ -0,0 +1,132 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Injectable } from '@angular/core';
+
+import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
+import { Store, Action } from '@ngrx/store';
+import { forkJoin, of } from 'rxjs';
+import { map, tap, mergeMap, catchError } from 'rxjs/operators';
+import { ToastrService } from 'ngx-toastr';
+
+import { SearchMultipleDatasetLength } from '../models';
+import { SearchService } from '../services/search.service';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
+import * as searchMultipleActions from '../actions/search-multiple.actions';
+import * as searchMultipleSelector from '../selectors/search-multiple.selector';
+import * as coneSearchActions from '../actions/cone-search.actions';
+import * as coneSearchSelector from '../selectors/cone-search.selector';
+
+@Injectable()
+export class SearchMultipleEffects {
+    initSearch$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(searchMultipleActions.initSearch),
+            concatLatestFrom(() => [
+                this.store.select(searchMultipleSelector.selectPristine),
+                this.store.select(coneSearchSelector.selectConeSearchByRoute),
+                this.store.select(searchMultipleSelector.selectSelectedDatasetsByRoute),
+                this.store.select(instanceSelector.selectInstanceByRouteName),
+                this.store.select(datasetSelector.selectAllConeSearchDatasets)
+            ]),
+            mergeMap(([action, pristine, coneSearchByRoute, selectedDatasetsByRoute, instance, datasetList]) => {
+                if (!pristine && !coneSearchByRoute) {
+                    // Restart search
+                    return [
+                        coneSearchActions.deleteConeSearch(),
+                        searchMultipleActions.restartSearch()
+                    ];
+                }
+
+                if (!pristine) {
+                    // Default form parameters already loaded or no dataset selected
+                    return of({ type: '[No Action] Load Default Form Parameters' });
+                }
+
+                let actions: Action[] = [
+                    searchMultipleActions.markAsDirty()
+                ];
+
+                // Update cone search
+                if (coneSearchByRoute) {
+                    const params = coneSearchByRoute.split(':');
+                    const coneSearch = {
+                        ra: +params[0],
+                        dec: +params[1],
+                        radius: +params[2]
+                    };
+                    actions.push(coneSearchActions.addConeSearch({ coneSearch }));
+                }
+
+                // Update selected datasets
+                if (selectedDatasetsByRoute) {
+                    // Build output list with the URL query parameters (a)
+                    const selectedDatasets = selectedDatasetsByRoute.split(';');
+                    actions.push(
+                        searchMultipleActions.updateSelectedDatasets({ selectedDatasets }),
+                        searchMultipleActions.checkDatasets()
+                    );
+                } else if (instance.config.search.search_multiple_all_datasets_selected) {
+                    const selectedDatasets = datasetList.map(dataset => dataset.name);
+                    actions.push(
+                        searchMultipleActions.updateSelectedDatasets({ selectedDatasets })
+                    );
+                }
+
+                // Returns actions and mark the form as dirty
+                return actions;
+            })
+        )
+    );
+
+    restartSearch$ = createEffect(() => 
+        this.actions$.pipe(
+            ofType(searchMultipleActions.restartSearch),
+            map(() => searchMultipleActions.initSearch())
+        )
+    );
+
+    retrieveDataLength$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(searchMultipleActions.retrieveDataLength),
+            concatLatestFrom(() => [
+                this.store.select(searchMultipleSelector.selectSelectedDatasets),
+                this.store.select(coneSearchSelector.selectConeSearch)
+            ]),
+            mergeMap(([action, selectedDatasets, coneSearch]) => {
+                const queries = selectedDatasets.map(datasetName => this.searchService.retrieveDataLength(
+                    `${datasetName}?a=count&cs=${coneSearch.ra}:${coneSearch.dec}:${coneSearch.radius}`
+                ).pipe(
+                    map((response: { nb: number }[]) => ({ datasetName, length: response[0].nb }))
+                ));
+
+                return forkJoin(queries)
+                    .pipe(
+                        map((response: SearchMultipleDatasetLength[]) => searchMultipleActions.retrieveDataLengthSuccess({ dataLength: response })),
+                        catchError(() => of(searchMultipleActions.retrieveDataLengthFail()))
+                    )
+            })
+        )
+    );
+
+    retrieveDataLengthFail$ = createEffect(() => 
+        this.actions$.pipe(
+            ofType(searchMultipleActions.retrieveDataLengthFail),
+            tap(() => this.toastr.error('Loading Failed', 'The search multiple data length loading failed'))
+        ), { dispatch: false}
+    );
+
+    constructor(
+        private actions$: Actions,
+        private searchService: SearchService,
+        private store: Store<{ }>,
+        private toastr: ToastrService
+    ) {}
+}
diff --git a/client/src/app/instance/store/models/index.ts b/client/src/app/instance/store/models/index.ts
index c471d6929ad3c505f8a5a9386d3d6f716d49e750..962eede1ad19a550541f007ee3155525a696c59c 100644
--- a/client/src/app/instance/store/models/index.ts
+++ b/client/src/app/instance/store/models/index.ts
@@ -1,6 +1,9 @@
 export * from './criterion.model';
 export * from './search-query-params.model';
+export * from './search-multiple-query-params.model';
 export * from './criterion';
 export * from './pagination.model';
 export * from './cone-search.model';
 export * from './resolver.model';
+export * from './search-multiple-dataset-length';
+export * from './search-multiple-dataset-data';
diff --git a/client/src/app/instance/store/models/search-multiple-dataset-data.ts b/client/src/app/instance/store/models/search-multiple-dataset-data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fa25ed88176093d7840cdd984c476aed52b25ed3
--- /dev/null
+++ b/client/src/app/instance/store/models/search-multiple-dataset-data.ts
@@ -0,0 +1,13 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+export interface SearchMultipleDatasetData {
+    datasetName: string;
+    data: any[];
+}
diff --git a/client/src/app/instance/store/models/search-multiple-dataset-length.ts b/client/src/app/instance/store/models/search-multiple-dataset-length.ts
new file mode 100644
index 0000000000000000000000000000000000000000..75961a0d5c68acd8878099d32715c9a4c9143242
--- /dev/null
+++ b/client/src/app/instance/store/models/search-multiple-dataset-length.ts
@@ -0,0 +1,13 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+export interface SearchMultipleDatasetLength {
+    datasetName: string;
+    length: number;
+}
diff --git a/client/src/app/instance/store/models/search-multiple-query-params.model.ts b/client/src/app/instance/store/models/search-multiple-query-params.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9e4cd67b1047b0288bf8fcfabe5c895f41a1713a
--- /dev/null
+++ b/client/src/app/instance/store/models/search-multiple-query-params.model.ts
@@ -0,0 +1,18 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Interface for search multiple query parameters.
+ *
+ * @interface SearchMultipleQueryParams
+ */
+export interface SearchMultipleQueryParams {
+    cs?: string;
+    d?: string;
+}
diff --git a/client/src/app/instance/store/reducers/search-multiple.reducer.ts b/client/src/app/instance/store/reducers/search-multiple.reducer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bd73fbba1df15c2853d55d21157e8a7f30fb1dbb
--- /dev/null
+++ b/client/src/app/instance/store/reducers/search-multiple.reducer.ts
@@ -0,0 +1,114 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createReducer, on } from '@ngrx/store';
+
+import { SearchMultipleDatasetLength, SearchMultipleDatasetData } from '../models';
+import * as searchMultipleActions from '../actions/search-multiple.actions';
+
+export interface State {
+    pristine: boolean;
+    currentStep: string;
+    positionStepChecked: boolean;
+    datasetsStepChecked: boolean;
+    resultStepChecked: boolean;
+    selectedDatasets: string[];
+    dataLengthIsLoading: boolean;
+    dataLengthIsLoaded: boolean;
+    dataLength: SearchMultipleDatasetLength[];
+    dataIsLoading: boolean;
+    dataIsLoaded: boolean;
+    data: SearchMultipleDatasetData[];
+}
+
+export const initialState: State = {
+    pristine: true,
+    currentStep: null,
+    positionStepChecked: false,
+    datasetsStepChecked: false,
+    resultStepChecked: false,
+    selectedDatasets: [],
+    dataLengthIsLoading: false,
+    dataLengthIsLoaded: false,
+    dataLength: [],
+    dataIsLoading: false,
+    dataIsLoaded: false,
+    data: []
+};
+
+export const searchMultipleReducer = createReducer(
+    initialState,
+    on(searchMultipleActions.restartSearch, () => ({
+        ...initialState,
+        currentStep: 'position'
+    })),
+    on(searchMultipleActions.changeStep, (state, { step }) => ({
+        ...state,
+        currentStep: step
+    })),
+    on(searchMultipleActions.markAsDirty, state => ({
+        ...state,
+        pristine: false
+    })),
+    on(searchMultipleActions.checkDatasets, state => ({
+        ...state,
+        datasetsStepChecked: true
+    })),
+    on(searchMultipleActions.checkResult, state => ({
+        ...state,
+        resultStepChecked: true
+    })),
+    on(searchMultipleActions.updateSelectedDatasets, (state, { selectedDatasets }) => ({
+        ...state,
+        selectedDatasets
+    })),
+    on(searchMultipleActions.retrieveDataLength, state => ({
+        ...state,
+        dataLengthIsLoading: true,
+        dataLengthIsLoaded: false
+    })),
+    on(searchMultipleActions.retrieveDataLengthSuccess, (state, { dataLength }) => ({
+        ...state,
+        dataLength,
+        dataLengthIsLoading: false,
+        dataLengthIsLoaded: true
+    })),
+    on(searchMultipleActions.retrieveDataLengthFail, state => ({
+        ...state,
+        dataLengthIsLoading: false
+    })),
+    on(searchMultipleActions.retrieveData, state => ({
+        ...state,
+        dataIsLoading: true,
+        dataIsLoaded: false
+    })),
+    on(searchMultipleActions.retrieveDataSuccess, (state, { data }) => ({
+        ...state,
+        data,
+        dataIsLoading: false,
+        dataIsLoaded: true
+    })),
+    on(searchMultipleActions.retrieveDataFail, state => ({
+        ...state,
+        dataIsLoading: false
+    }))
+);
+
+export const selectPristine = (state: State) => state.pristine;
+export const selectCurrentStep = (state: State) => state.currentStep;
+export const selectPositionStepChecked = (state: State) => state.positionStepChecked;
+export const selectDatasetsStepChecked = (state: State) => state.datasetsStepChecked;
+export const selectResultStepChecked = (state: State) => state.resultStepChecked;
+export const selectSelectedDatasets = (state: State) => state.selectedDatasets;
+export const selectDataLengthIsLoading = (state: State) => state.dataLengthIsLoading;
+export const selectDataLengthIsLoaded = (state: State) => state.dataLengthIsLoaded;
+export const selectDataLength = (state: State) => state.dataLength;
+export const selectDataIsLoading = (state: State) => state.dataIsLoading;
+export const selectDataIsLoaded = (state: State) => state.dataIsLoaded;
+export const selectData = (state: State) => state.data;
diff --git a/client/src/app/instance/store/selectors/search-multiple.selector.ts b/client/src/app/instance/store/selectors/search-multiple.selector.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61ae2e99501760bef036054717ac11ad5408ad42
--- /dev/null
+++ b/client/src/app/instance/store/selectors/search-multiple.selector.ts
@@ -0,0 +1,108 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createSelector } from '@ngrx/store';
+
+import { SearchMultipleQueryParams, ConeSearch } from '../models';
+import * as reducer from '../../instance.reducer';
+import * as fromSearchMultiple from '../reducers/search-multiple.reducer';
+import * as coneSearchSelector from './cone-search.selector';
+
+export const selectSearchMultipleState = createSelector(
+    reducer.getInstanceState,
+    (state: reducer.State) => state.searchMultiple
+);
+
+export const selectPristine = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectPristine
+);
+
+export const selectCurrentStep = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectCurrentStep
+);
+
+export const selectPositionStepChecked = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectPositionStepChecked
+);
+
+export const selectDatasetsStepChecked = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDatasetsStepChecked
+);
+
+export const selectResultStepChecked = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectResultStepChecked
+);
+
+export const selectSelectedDatasets = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectSelectedDatasets
+);
+
+export const selectDataLengthIsLoading = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDataLengthIsLoading
+);
+
+export const selectDataLengthIsLoaded = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDataLengthIsLoaded
+);
+
+export const selectDataLength = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDataLength
+);
+
+export const selectDataIsLoading = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDataIsLoading
+);
+
+export const selectDataIsLoaded = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectDataIsLoaded
+);
+
+export const selectData = createSelector(
+    selectSearchMultipleState,
+    fromSearchMultiple.selectData
+);
+
+export const selectQueryParams = createSelector(
+    coneSearchSelector.selectConeSearch,
+    selectSelectedDatasets,
+    (
+        coneSearch: ConeSearch,
+        selectedDatasets: string[]) => {
+        let queryParams: SearchMultipleQueryParams = { };
+        if (coneSearch) {
+            queryParams = {
+                ...queryParams,
+                cs: coneSearch.ra + ':' + coneSearch.dec + ':' + coneSearch.radius
+            };
+        }
+        if (selectedDatasets.length > 0) {
+            queryParams = {
+                ...queryParams,
+                d: selectedDatasets.join(';')
+            };
+        }
+        return queryParams;
+    }
+);
+
+export const selectSelectedDatasetsByRoute = createSelector(
+    reducer.selectRouterState,
+    router => router.state.queryParams.d as string
+);
diff --git a/client/src/app/metamodel/effects/database.effects.ts b/client/src/app/metamodel/effects/database.effects.ts
index 968712fcd7bee8b3e00bab06778feb756528d544..39c20f7e43a15f87707f3d31cfbd924ba21ffbf7 100644
--- a/client/src/app/metamodel/effects/database.effects.ts
+++ b/client/src/app/metamodel/effects/database.effects.ts
@@ -48,7 +48,7 @@ export class DatabaseEffects {
         this.actions$.pipe(
             ofType(databaseActions.addDatabaseSuccess),
             tap(() => {
-                this.router.navigate(['/admin/survey/database-list']);
+                this.router.navigate(['/admin/database-list']);
                 this.toastr.success('Database successfully added', 'The new database was added into the database')
             })
         ), { dispatch: false}
@@ -77,7 +77,7 @@ export class DatabaseEffects {
         this.actions$.pipe(
             ofType(databaseActions.editDatabaseSuccess),
             tap(() => {
-                this.router.navigate(['/admin/survey/database-list']);
+                this.router.navigate(['/admin/database-list']);
                 this.toastr.success('Database successfully edited', 'The existing database has been edited into the database')
             })
         ), { dispatch: false}
diff --git a/client/src/app/metamodel/effects/survey.effects.ts b/client/src/app/metamodel/effects/survey.effects.ts
index 7d876b5ac2fa0d0f8d87b9b13483e732daddbd76..fae21756b32a5bee17d13544db6304a07707e25b 100644
--- a/client/src/app/metamodel/effects/survey.effects.ts
+++ b/client/src/app/metamodel/effects/survey.effects.ts
@@ -48,7 +48,7 @@ export class SurveyEffects {
         this.actions$.pipe(
             ofType(surveyActions.addSurveySuccess),
             tap(() => {
-                this.router.navigate(['/admin/survey/survey-list']);
+                this.router.navigate(['/admin/survey-list']);
                 this.toastr.success('Survey successfully added', 'The new survey was added into the database')
             })
         ), { dispatch: false}
@@ -77,7 +77,7 @@ export class SurveyEffects {
         this.actions$.pipe(
             ofType(surveyActions.editSurveySuccess),
             tap(() => {
-                this.router.navigate(['/admin/survey/survey-list']);
+                this.router.navigate(['/admin/survey-list']);
                 this.toastr.success('Survey successfully edited', 'The existing survey has been edited into the database')
             })
         ), { dispatch: false}
diff --git a/client/src/app/metamodel/models/dataset.model.ts b/client/src/app/metamodel/models/dataset.model.ts
index 03221eecfc307180f9416fc5c911c55b60e0c0cf..22e73074318ab24c91fdb32836dd9c3834c8a1ea 100644
--- a/client/src/app/metamodel/models/dataset.model.ts
+++ b/client/src/app/metamodel/models/dataset.model.ts
@@ -17,8 +17,13 @@ export interface Dataset {
     survey_name: string;
     id_dataset_family: number;
     public: boolean;
+    full_data_path: string;
     config: {
         images: any[],
+        survey: {
+            survey_enabled: boolean;
+            survey_label: string;
+        },
         cone_search: {
             cone_search_enabled: boolean;
             cone_search_opened: boolean;
diff --git a/client/src/app/metamodel/models/instance.model.ts b/client/src/app/metamodel/models/instance.model.ts
index 006bdc1d3d058f9280a3dff2af46f549d3ce2515..c50e7bc234b97659b9b950b118669774f02ee582 100644
--- a/client/src/app/metamodel/models/instance.model.ts
+++ b/client/src/app/metamodel/models/instance.model.ts
@@ -10,18 +10,31 @@
 export interface Instance {
     name: string;
     label: string;
-    client_url: string;
+    data_path: string;
     config: {
         design: {
-            design_color: string
+            design_color: string;
+            design_background_color: string;
+            design_logo: string;
+            design_favicon: string;
+        };
+        home: {
+            home_component: string;
+            home_config: {
+                home_component_text: string;
+                home_component_logo: string;
+            };
         };
         search: {
             search_by_criteria_allowed: boolean;
+            search_by_criteria_label: string;
             search_multiple_allowed: boolean;
+            search_multiple_label: string;
             search_multiple_all_datasets_selected: boolean;
         };
         documentation: {
             documentation_allowed: boolean;
+            documentation_label: string;
         };
     };
     nb_dataset_families: number;
diff --git a/client/src/app/metamodel/reducers/criteria-family.reducer.ts b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
index 6e153b79fbc7e84d420a323e75bc956468fa7eed..76ccaae48cbaa1e8d6b28da6f878b495756734d6 100644
--- a/client/src/app/metamodel/reducers/criteria-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<CriteriaFamily> {
     criteriaFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<CriteriaFamily> = createEntityAdapter<CriteriaFamily>();
+export const adapter: EntityAdapter<CriteriaFamily> = createEntityAdapter<CriteriaFamily>({
+    selectId: (criteriaFamily: CriteriaFamily) => criteriaFamily.id,
+    sortComparer: (a: CriteriaFamily, b: CriteriaFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     criteriaFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/dataset-family.reducer.ts b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
index dcbb9101dc1634f8283d58fab399dda6070a7367..923f88374e7b4211d4dd156554d7fa239bce8aa8 100644
--- a/client/src/app/metamodel/reducers/dataset-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<DatasetFamily> {
     datasetFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<DatasetFamily> = createEntityAdapter<DatasetFamily>();
+export const adapter: EntityAdapter<DatasetFamily> = createEntityAdapter<DatasetFamily>({
+    selectId: (datasetFamily: DatasetFamily) => datasetFamily.id,
+    sortComparer: (a: DatasetFamily, b: DatasetFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     datasetFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/dataset.reducer.ts b/client/src/app/metamodel/reducers/dataset.reducer.ts
index 82ba8ca599df9f7a99946e20eaaa279756eb4f43..becb9691e69c08353c027083fad1b096dcc8f522 100644
--- a/client/src/app/metamodel/reducers/dataset.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset.reducer.ts
@@ -20,7 +20,7 @@ export interface State extends EntityState<Dataset> {
 
 export const adapter: EntityAdapter<Dataset> = createEntityAdapter<Dataset>({
     selectId: (dataset: Dataset) => dataset.name,
-    sortComparer: (a: Dataset, b: Dataset) => a.name.localeCompare(b.name)
+    sortComparer: (a: Dataset, b: Dataset) => a.display - b.display
 });
 
 export const initialState: State = adapter.getInitialState({
diff --git a/client/src/app/metamodel/reducers/output-category.reducer.ts b/client/src/app/metamodel/reducers/output-category.reducer.ts
index 11ef8e7b16f781292d0dd99caee4af8d0f2139aa..ddbed47415434fee7336a5e45078c8557d1b956e 100644
--- a/client/src/app/metamodel/reducers/output-category.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-category.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<OutputCategory> {
     outputCategoryListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<OutputCategory> = createEntityAdapter<OutputCategory>();
+export const adapter: EntityAdapter<OutputCategory> = createEntityAdapter<OutputCategory>({
+    selectId: (outputCategory: OutputCategory) => outputCategory.id,
+    sortComparer: (a: OutputCategory, b: OutputCategory) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     outputCategoryListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/output-family.reducer.ts b/client/src/app/metamodel/reducers/output-family.reducer.ts
index ab02f1e9ecffafaf1675c5ed7ba015c8537bf79b..cb7c5f6b38320c69a2542149313eaae47467d41a 100644
--- a/client/src/app/metamodel/reducers/output-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<OutputFamily> {
     outputFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<OutputFamily> = createEntityAdapter<OutputFamily>();
+export const adapter: EntityAdapter<OutputFamily> = createEntityAdapter<OutputFamily>({
+    selectId: (outputFamily: OutputFamily) => outputFamily.id,
+    sortComparer: (a: OutputFamily, b: OutputFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     outputFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/select-option.reducer.ts b/client/src/app/metamodel/reducers/select-option.reducer.ts
index 13690b294c29adcfe1be595b218b60159f152c6f..f63ffbd5c6f5c2cdc84386301784731bd29fb681 100644
--- a/client/src/app/metamodel/reducers/select-option.reducer.ts
+++ b/client/src/app/metamodel/reducers/select-option.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<SelectOption> {
     selectOptionListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<SelectOption> = createEntityAdapter<SelectOption>();
+export const adapter: EntityAdapter<SelectOption> = createEntityAdapter<SelectOption>({
+    selectId: (selectOption: SelectOption) => selectOption.id,
+    sortComparer: (a: SelectOption, b: SelectOption) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     selectOptionListIsLoading: false,
diff --git a/client/src/app/metamodel/selectors/dataset.selector.ts b/client/src/app/metamodel/selectors/dataset.selector.ts
index 71294e9175bcb756fcbef983db7288edc3a18da3..d456b9e12640f2340cb11dd66d80c6edea60fb35 100644
--- a/client/src/app/metamodel/selectors/dataset.selector.ts
+++ b/client/src/app/metamodel/selectors/dataset.selector.ts
@@ -57,3 +57,8 @@ export const selectDatasetNameByRoute = createSelector(
     reducer.selectRouterState,
     router => router.state.params.dname as string
 );
+
+export const selectAllConeSearchDatasets = createSelector(
+    selectAllDatasets,
+    datasetList => datasetList.filter(dataset => dataset.config.cone_search.cone_search_enabled)
+);
\ No newline at end of file
diff --git a/client/src/app/metamodel/services/root-directory.service.ts b/client/src/app/metamodel/services/root-directory.service.ts
index d173f00d10b99e3872109fac4823c225a2a5a674..56da1e927f274fa55c0195dd792b2ddfcf3a7a5e 100644
--- a/client/src/app/metamodel/services/root-directory.service.ts
+++ b/client/src/app/metamodel/services/root-directory.service.ts
@@ -20,6 +20,6 @@ export class RootDirectoryService {
     constructor(private http: HttpClient, private config: AppConfigService) { }
 
     retrieveRootDirectory(path: string): Observable<FileInfo[]> {
-        return this.http.get<FileInfo[]>(this.config.apiUrl + '/file-explorer/' + path);
+        return this.http.get<FileInfo[]>(this.config.apiUrl + '/file-explorer' + path);
     }
 }
diff --git a/client/src/app/shared/components/navbar.component.html b/client/src/app/shared/components/navbar.component.html
index 14be398008e56c8ba1ee9dcd4dc86ad31579cd08..6213927093e79526d7ccd9dc4ea7b77d689c2297 100644
--- a/client/src/app/shared/components/navbar.component.html
+++ b/client/src/app/shared/components/navbar.component.html
@@ -5,7 +5,7 @@
     </a>
 
     <a *ngIf="instance" routerLink="/instance/{{ instance.name }}" class="navbar-brand">
-        <img  src="assets/{{ instance.name }}-logo.png" alt="Instance logo" />
+        <img src="{{ getLogoHref() }}" alt="Instance logo" />
     </a>
 
     <!-- Right Navigation -->
@@ -64,7 +64,7 @@
             </li>
             <li *ngIf="isAuthenticated" class="divider dropdown-divider"></li>
             <li *ngFor="let link of links" role="menuitem">
-                <a class="dropdown-item" routerLink="link.routerLink">
+                <a class="dropdown-item" [routerLink]="link.routerLink">
                     <span [ngClass]="link.icon" class="fa-fw"></span> {{ link.label }}
                 </a>
             </li>
diff --git a/client/src/app/shared/components/navbar.component.ts b/client/src/app/shared/components/navbar.component.ts
index 51379dea9a1831eda3124f85f8f8e6a0e5c0c009..fcbb7457ba7d2b29291c36278c8d2781827c0f8e 100644
--- a/client/src/app/shared/components/navbar.component.ts
+++ b/client/src/app/shared/components/navbar.component.ts
@@ -24,8 +24,17 @@ export class NavbarComponent {
     @Input() userProfile: UserProfile = null;
     @Input() baseHref: string;
     @Input() authenticationEnabled: boolean;
+    @Input() apiUrl: string;
     @Input() instance: Instance;
     @Output() login: EventEmitter<any> = new EventEmitter();
     @Output() logout: EventEmitter<any> = new EventEmitter();
     @Output() openEditProfile: EventEmitter<any> = new EventEmitter();
+
+    getLogoHref() {
+        if (this.instance.config.design.design_logo) {
+            return `${this.apiUrl}/download-instance-file/${this.instance.name}/${this.instance.config.design.design_logo}`;
+        } else {
+            return 'assets/cesam_anis40.png';
+        }
+    }
 }
diff --git a/client/src/assets/app.config.json b/client/src/assets/app.config.json
deleted file mode 100644
index 69f72dd76e9f151588ed89265dd996fff407414e..0000000000000000000000000000000000000000
--- a/client/src/assets/app.config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "apiUrl": "http://localhost:8080",
-    "servicesUrl": "http://localhost:5000",
-    "baseHref": "/",
-    "authenticationEnabled": false,
-    "ssoAuthUrl": "http://localhost:8180/auth",
-    "ssoRealm": "anis",
-    "ssoClientId": "anis-client",
-    "adminRole": "anis_admin"
-}
\ No newline at end of file
diff --git a/client/src/environments/environment.prod.ts b/client/src/environments/environment.prod.ts
index 5d0833162027e2147e99e72a1a94bb7d3cb62843..5506fedd9829d17697569af187d24a95a4184af4 100644
--- a/client/src/environments/environment.prod.ts
+++ b/client/src/environments/environment.prod.ts
@@ -1,3 +1,4 @@
 export const environment = {
-    production: true
+    production: true,
+    apiUrl: "/server"
 };
diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts
index 458476a4df52c64d1a2abee43c6cb91d87abad77..0a202e32320026491d3fdbf7ea375cea6ac5a2cf 100644
--- a/client/src/environments/environment.ts
+++ b/client/src/environments/environment.ts
@@ -3,7 +3,8 @@
 // The list of file replacements can be found in `angular.json`.
 
 export const environment = {
-    production: false
+    production: false,
+    apiUrl: "http://localhost:8080"
 };
 
 /*
diff --git a/client/src/index.html b/client/src/index.html
index 82bcb25eaef1535bfdf72649fd25b94976825b6e..341e647c598a2d83fd0db94f9716cf1086d3fef6 100644
--- a/client/src/index.html
+++ b/client/src/index.html
@@ -2,7 +2,7 @@
 <html lang="en" class="h-100">
 <head>
   <meta charset="utf-8">
-  <title>Anis - Client</title>
+  <title id="title">Anis - Client</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" id="favicon" type="image/x-icon" href="favicon.ico">
diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh
index 464504e5a199237a333cf52dd96c6e720fd1ffbd..e328444a2e7b4e12657874b10532967869eb797c 100644
--- a/conf-dev/create-db.sh
+++ b/conf-dev/create-db.sh
@@ -59,7 +59,7 @@ curl -d '{"label":"Spectra graph","value":"spectra_graph","display":20,"select_n
 curl -d '{"label":"Test","dbname":"anis_test","dbtype":"pdo_pgsql","dbhost":"db","dbport":5432,"dblogin":"anis","dbpassword":"anis"}' --header 'Content-Type: application/json' -X POST http://localhost/database
 
 # Add default instance
-curl -d '{"name":"default","label":"Default instance","client_url":"http://localhost:4200","config":{"design":{"design_color":"#7AC29A"},"search":{"search_by_criteria_allowed":true,"search_multiple_allowed":false,"search_multiple_all_datasets_selected":false},"documentation":{"documentation_allowed":false}}}' --header 'Content-Type: application/json' -X POST http://localhost/instance
+curl -d '{"name":"default","label":"Default instance","data_path":"\/DEFAULT","config":{"design":{"design_color":"#7AC29A","design_logo":"logo.png","design_favicon":"favicon.ico"},"home":{"home_component":"WelcomeComponent","home_config":{"home_component_text":"AstroNomical Information System","home_component_logo":"home_component_logo.png"}},"search":{"search_by_criteria_allowed":true,"search_by_criteria_label":"Search","search_multiple_allowed":false,"search_multiple_label":"Search multiple","search_multiple_all_datasets_selected":false},"documentation":{"documentation_allowed":false,"documentation_label":"Documentation"}}}' --header 'Content-Type: application/json' -X POST http://localhost/instance
 
 # Add ANIS, SVOM and IRIS surveys
 curl -d '{"name":"anis_survey","label":"ANIS survey","description":"Survey used for testing","link":"https://anis.lam.fr","manager":"F. Agneray","id_database":1}' --header 'Content-Type: application/json' -X POST http://localhost/survey
@@ -72,10 +72,10 @@ curl -d '{"label":"SVOM dataset family","display":20,"opened":true}' --header 'C
 curl -d '{"label":"IRiS dataset family","display":30,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/instance/default/dataset-family
 
 # Add datasets
-curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":10,"data_path":"\/ASPIC\/VIPERS_DR2","config":{"images":[],"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"anis_survey"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/1/dataset
-curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":20,"data_path":"","config":{"images":[],"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"svom"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/2/dataset
-curl -d '{"name":"observations","table_ref":"v_observation","label":"IRiS obs","description":"IRiS observations","display":10,"data_path":"\/IRIS\/observations","config":{"images":[],"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"iris"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/3/dataset
-curl -d '{"name":"vvds_f02_udeep","table_ref":"aspic_vvds_f02_udeep","label":"VVDS2h Ultra Deep","description":"VVDS2h Ultra Deep","display":20,"data_path":"","config":{"images":[],"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"anis_survey"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/1/dataset
+curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":10,"data_path":"\/ASPIC\/VIPERS_DR2","config":{"images":[],"survey":{"survey_enabled":true,"survey_label":"More about this survey"},"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"anis_survey"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/1/dataset
+curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":20,"data_path":"","config":{"images":[],"survey":{"survey_enabled":true,"survey_label":"More about this survey"},"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"svom"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/2/dataset
+curl -d '{"name":"observations","table_ref":"v_observation","label":"IRiS obs","description":"IRiS observations","display":10,"data_path":"\/IRIS\/observations","config":{"images":[],"survey":{"survey_enabled":true,"survey_label":"More about this survey"},"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"iris"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/3/dataset
+curl -d '{"name":"vvds_f02_udeep","table_ref":"aspic_vvds_f02_udeep","label":"VVDS2h Ultra Deep","description":"VVDS2h Ultra Deep","display":20,"data_path":"","config":{"images":[],"survey":{"survey_enabled":true,"survey_label":"More about this survey"},"cone_search":{"cone_search_enabled":false,"cone_search_opened":true,"cone_search_column_ra":null,"cone_search_column_dec":null,"cone_search_plot_enabled":false,"cone_search_sdss_enabled":true,"cone_search_sdss_display":10,"cone_search_background":[]},"download":{"download_enabled":true,"download_opened":false,"download_csv":true,"download_ascii":true,"download_vo":false,"download_archive":true},"summary":{"summary_enabled":true,"summary_opened":false},"server_link":{"server_link_enabled":false,"server_link_opened":false},"samp":{"samp_enabled":false,"samp_opened":false},"datatable":{"datatable_enabled":true,"datatable_opened":false,"datatable_selectable_rows":false}},"public":true,"survey_name":"anis_survey"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset-family/1/dataset
 
 # Add vipers_dr2_w1 attributes
 curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/criteria-family
diff --git a/conf-dev/public_key b/conf-dev/public_key
index ebb23d4c7bfdc0bec2e326b8df170f22e3412c5d..3c3ba0e8be160eac8c137f66f4bfb969137c8c04 100644
--- a/conf-dev/public_key
+++ b/conf-dev/public_key
@@ -1,3 +1,3 @@
 -----BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi5V9FJj0dI/2TRDWoZzSKDa8l5N81sCQUunZaEuyBx3EW5cDioL2ktdc3LCB5u+rVQzYD6c3b24eLbgwgYx8AQ03GXW63TkuUy7oEA1XtBicNX/IO51ITUCeUJfJpUI+iGDEK4EmeVBiaVUTrQ8L/SMTQUcRPESNwaRmFov9kkNDiPaNQpAzbSillJLdQG9oOIKDpqjXW+ZOBct1J//+8+f0vHibbDt2HacFrq2z2ahv10ESnxqtnzjMMcn0e/IDIiolsQpcCpEwaBBqJ6axUiKReJBXU/IsFn/GtemLwPo/MpthjIi1rfqPvtin25ecR9VAWRW0bLdqztnMsfJ3oQIDAQAB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1fucBQK34tl8Gx/fefATnpWqW5PVlwMYcJAqgWvmtwNm9ZW/S5HNZZfjW1S9BOJLfudCM83WHrAwGixgHKI310YXg+6BI9qn2Gnge1GC3JtKZx6UdcxZFAYmlhY0QGL5QxGR58DkEj6l/FDrwAHyVkC5sLqDMiYsqO7CA1uJLtF8yUrCyHvI4TR+kk5ZSM94/osg6eGxGSYA89u+qhG5tz5YCFgiRUNxuAEucsz8XiEfNVAz5kdYgsR4+LtmqECfczpwcJrAu7yDxs3rQPjBqFdGqEehALHX9vq71VEYe5Id2P7ddik3byHa0a21Q0RuVhMYwGrLiMLJCXqxE1YMuwIDAQAB
 -----END PUBLIC KEY-----
diff --git a/docker-compose.yml b/docker-compose.yml
index bc9bd7b06cecef4ee1d3fbb01266056a56649ce1..ee412b76725a54d72cfad75ec8636d000a5842f9 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -29,6 +29,11 @@ services:
             LOGGER_NAME: "anis-metamodel"
             LOGGER_PATH: "php://stderr"
             LOGGER_LEVEL: "debug"
+            SERVICES_URL: "http://localhost:5000"
+            BASE_HREF: "/"
+            SSO_AUTH_URL: "http://localhost:8180/auth"
+            SSO_REALM: "anis"
+            SSO_CLIENT_ID: "anis-client"
             TOKEN_ENABLED: 0
             TOKEN_PUBLIC_KEY_FILE: /mnt/public_key
             TOKEN_ADMIN_ROLE: anis_admin
diff --git a/server/.gitlab-ci.yml b/server/.gitlab-ci.yml
index 11df89cf2a14fa312773d1a46deb0614a7433e07..5cdac1406a6deb72933c05f83c0fc7d48dcf8af6 100644
--- a/server/.gitlab-ci.yml
+++ b/server/.gitlab-ci.yml
@@ -3,6 +3,7 @@ stages:
   - test
   - sonar
   - dockerize
+  - deploy
 
 variables:
     VERSION: "3.7"
@@ -70,3 +71,17 @@ dockerize:
         - docker pull $CI_REGISTRY/anis/anis-next/server:latest || true
         - docker build --cache-from $CI_REGISTRY/anis/anis-next/server:latest -t $CI_REGISTRY/anis/anis-next/server:latest .
         - docker push $CI_REGISTRY/anis/anis-next/server:latest
+
+deploy:
+    image: alpine
+    stage: deploy
+    variables:
+        GIT_STRATEGY: none
+    cache: {}
+    dependencies: []
+    script:
+        - apk add --update curl
+        - curl -XPOST $DEV_WEBHOOK_SERVER
+    only:
+        refs:
+            - develop
\ No newline at end of file
diff --git a/server/app/dependencies.php b/server/app/dependencies.php
index 1406024f2a5e62027beefb897ee7d817b7c58436..2ba1d1681c1f8c71cb792a2c0ff90614ef782108 100644
--- a/server/app/dependencies.php
+++ b/server/app/dependencies.php
@@ -56,6 +56,10 @@ $container->set('App\Action\RootAction', function () {
     return new App\Action\RootAction();
 });
 
+$container->set('App\Action\ClientSettingsAction', function (ContainerInterface $c) {
+    return new App\Action\ClientSettingsAction($c->get(SETTINGS));
+});
+
 $container->set('App\Action\SelectListAction', function (ContainerInterface $c) {
     return new App\Action\SelectListAction($c->get('em'));
 });
@@ -218,6 +222,10 @@ $container->set('App\Action\DatasetFileExplorerAction', function (ContainerInter
     return new App\Action\DatasetFileExplorerAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
 });
 
+$container->set('App\Action\DownloadInstanceFileAction', function (ContainerInterface $c) {
+    return new App\Action\DownloadInstanceFileAction($c->get('em'), $c->get('settings')['data_path']);
+});
+
 $container->set('App\Action\DownloadFileAction', function (ContainerInterface $c) {
     return new App\Action\DownloadFileAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
 });
diff --git a/server/app/routes.php b/server/app/routes.php
index 76ef14eeea4541d2b41b0776c498bac4e4054dc6..42b9479b79dc9da018607214cc06690a32bfe7dc 100644
--- a/server/app/routes.php
+++ b/server/app/routes.php
@@ -13,6 +13,7 @@ declare(strict_types=1);
 use Slim\Routing\RouteCollectorProxy;
 
 $app->get('/', App\Action\RootAction::class);
+$app->get('/client-settings', App\Action\ClientSettingsAction::class);
 
 $app->group('', function (RouteCollectorProxy $group) {
     $group->map([OPTIONS, GET, POST], '/select', App\Action\SelectListAction::class);
@@ -69,4 +70,5 @@ $app->group('', function (RouteCollectorProxy $group) {
 $app->get('/search/{dname}', App\Action\SearchAction::class);
 $app->get('/archive/{dname}', App\Action\ArchiveAction::class);
 $app->get('/dataset-file-explorer/{dname}[{fpath:.*}]', App\Action\DatasetFileExplorerAction::class);
+$app->get('/download-instance-file/{iname}/[{fpath:.*}]', App\Action\DownloadInstanceFileAction::class);
 $app->get('/download-file/{dname}/[{fpath:.*}]', App\Action\DownloadFileAction::class);
diff --git a/server/app/settings.php b/server/app/settings.php
index a37c755705f852b00796fabacbd0b66aaf054099..f018b5675ac88559c6948d89061be79ee73f8acb 100644
--- a/server/app/settings.php
+++ b/server/app/settings.php
@@ -31,8 +31,14 @@ return [
         'path' => getenv('LOGGER_PATH'),
         'level' => getenv('LOGGER_LEVEL')
     ],
+    'services_url' => getenv('SERVICES_URL'),
+    'base_href' => getenv('BASE_HREF'),
+    'sso' => [
+        'auth_url' => getenv('SSO_AUTH_URL'),
+        'realm' => getenv('SSO_REALM'),
+        'client_id' => getenv('SSO_CLIENT_ID')
+    ],
     'token' => [
-        //'issuer' => getenv('TOKEN_ISSUER'),
         'enabled' => getenv('TOKEN_ENABLED'),
         'public_key_file' => getenv('TOKEN_PUBLIC_KEY_FILE'),
         'admin_role' => getenv('TOKEN_ADMIN_ROLE')
diff --git a/server/doctrine-proxy/__CG__AppEntityInstance.php b/server/doctrine-proxy/__CG__AppEntityInstance.php
index 31548dc0c004bfdcb349fc852549eb52f57781be..b971ab686cd1cbd46df3c1149c130ab3998ad7bc 100644
--- a/server/doctrine-proxy/__CG__AppEntityInstance.php
+++ b/server/doctrine-proxy/__CG__AppEntityInstance.php
@@ -66,10 +66,10 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
     public function __sleep()
     {
         if ($this->__isInitialized__) {
-            return ['__isInitialized__', 'name', 'label', 'clientUrl', 'config', 'datasetFamilies'];
+            return ['__isInitialized__', 'name', 'label', 'dataPath', 'config', 'datasetFamilies'];
         }
 
-        return ['__isInitialized__', 'name', 'label', 'clientUrl', 'config', 'datasetFamilies'];
+        return ['__isInitialized__', 'name', 'label', 'dataPath', 'config', 'datasetFamilies'];
     }
 
     /**
@@ -216,23 +216,23 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
     /**
      * {@inheritDoc}
      */
-    public function getClientUrl()
+    public function getDataPath()
     {
 
-        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getClientUrl', []);
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDataPath', []);
 
-        return parent::getClientUrl();
+        return parent::getDataPath();
     }
 
     /**
      * {@inheritDoc}
      */
-    public function setClientUrl($clientUrl)
+    public function setDataPath($dataPath)
     {
 
-        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setClientUrl', [$clientUrl]);
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDataPath', [$dataPath]);
 
-        return parent::setClientUrl($clientUrl);
+        return parent::setDataPath($dataPath);
     }
 
     /**
diff --git a/server/src/Action/ClientSettingsAction.php b/server/src/Action/ClientSettingsAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..1018ac39d0a8853cd63592936b6a385b00218ac8
--- /dev/null
+++ b/server/src/Action/ClientSettingsAction.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of Anis Server.
+ *
+ * (c) Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+declare(strict_types=1);
+
+namespace App\Action;
+
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Client settings action
+ *
+ * @author François Agneray <francois.agneray@lam.fr>
+ * @package App\Action
+ */
+final class ClientSettingsAction
+{
+    /**
+     * The ANIS settings array
+     *
+     * @var array
+     */
+    private $settings;
+
+    public function __construct($settings)
+    {
+        $this->settings = $settings;
+    }
+
+    /**
+     * This action indicates that the service is responding
+     *
+     * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
+     * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
+     * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response
+    {
+        $payload = json_encode(array(
+            'servicesUrl' => $this->settings['services_url'],
+            'baseHref' => $this->settings['base_href'],
+            'authenticationEnabled' => boolval($this->settings['token']['enabled']),
+            'ssoAuthUrl' => $this->settings['sso']['auth_url'],
+            'ssoRealm' => $this->settings['sso']['realm'],
+            'ssoClientId' => $this->settings['sso']['client_id'],
+            'adminRole' => $this->settings['token']['admin_role']
+        ));
+        $response->getBody()->write($payload);
+        return $response;
+    }
+}
diff --git a/server/src/Action/DatasetFileExplorerAction.php b/server/src/Action/DatasetFileExplorerAction.php
index 91a925ebd2d3d175766973730f9fb21e39b04285..33a17d3c616638e9958fe529dfd7275c7e545feb 100644
--- a/server/src/Action/DatasetFileExplorerAction.php
+++ b/server/src/Action/DatasetFileExplorerAction.php
@@ -84,8 +84,9 @@ final class DatasetFileExplorerAction extends AbstractAction
             $this->verifyDatasetAuthorization($request, $dataset->getName(), $this->settings['admin_role']);
         }
 
-        $path = $this->dataPath . $dataset->getDataPath();
-
+        // Dataset data_path
+        $path = $this->dataPath . $dataset->getFullDataPath();
+        
         if (array_key_exists('fpath', $args)) {
             $path .= DIRECTORY_SEPARATOR . $args['fpath'];
         }
diff --git a/server/src/Action/DownloadFileAction.php b/server/src/Action/DownloadFileAction.php
index 21736352b6905e071acfe11efcc1897da4da51e9..4d3b3d5739a0b472f5f58cd581dabff516073ac9 100644
--- a/server/src/Action/DownloadFileAction.php
+++ b/server/src/Action/DownloadFileAction.php
@@ -85,7 +85,7 @@ final class DownloadFileAction extends AbstractAction
         }
 
         // Search the file
-        $filePath = $this->dataPath . $dataset->getDataPath() . DIRECTORY_SEPARATOR . $args['fpath'];
+        $filePath = $this->dataPath . $dataset->getFullDataPath() . DIRECTORY_SEPARATOR . $args['fpath'];
 
         // If the file not found 404
         if (!file_exists($filePath)) {
diff --git a/server/src/Action/DownloadInstanceFileAction.php b/server/src/Action/DownloadInstanceFileAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..b9eed921ce2185d22804943fa4031843e4cecb55
--- /dev/null
+++ b/server/src/Action/DownloadInstanceFileAction.php
@@ -0,0 +1,93 @@
+<?php
+
+/*
+ * This file is part of Anis Server.
+ *
+ * (c) Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+declare(strict_types=1);
+
+namespace App\Action;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use Doctrine\ORM\EntityManagerInterface;
+use Slim\Exception\HttpNotFoundException;
+use Nyholm\Psr7\Factory\Psr17Factory;
+
+/**
+ * @author François Agneray <francois.agneray@lam.fr>
+ * @package App\Action
+ */
+final class DownloadInstanceFileAction extends AbstractAction
+{
+    /**
+     * Contains anis-server data path
+     *
+     * @var string
+     */
+    private $dataPath;
+
+    /**
+     * Create the classe before call __invoke to execute the action
+     *
+     * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
+     * @param string                 $dataPath Contains anis-server data path
+     */
+    public function __construct(EntityManagerInterface $em, string $dataPath)
+    {
+        parent::__construct($em);
+        $this->dataPath = $dataPath;
+    }
+
+    /**
+     * `GET` Returns the file found
+     *
+     * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
+     * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
+     * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response
+    {
+        if ($request->getMethod() === OPTIONS) {
+            return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
+        }
+
+        // Search the correct instance with primary key
+        $instanceName = $args['iname'];
+        $instance = $this->em->find('App\Entity\Instance', $instanceName);
+
+        // If dataset is not found 404
+        if (is_null($instance)) {
+            throw new HttpNotFoundException(
+                $request,
+                'Instance with name ' . $instanceName . ' is not found'
+            );
+        }
+
+        // Search the file
+        $filePath = $this->dataPath . $instance->getDataPath() . DIRECTORY_SEPARATOR . $args['fpath'];
+
+        // If the file not found 404
+        if (!file_exists($filePath)) {
+            throw new HttpNotFoundException(
+                $request,
+                'File with path ' . $args['fpath'] . ' is not found for the instance ' . $instanceName
+            );
+        }
+
+        // If the file found so stream it
+        $psr17Factory = new Psr17Factory();
+        $stream = $psr17Factory->createStreamFromFile($filePath, 'r');
+
+        return $response->withBody($stream)
+            ->withHeader('Content-Disposition', 'attachment; filename=' . basename($filePath) . ';')
+            ->withHeader('Content-Type', mime_content_type($filePath))
+            ->withHeader('Content-Length', filesize($filePath));
+    }
+}
diff --git a/server/src/Action/InstanceAction.php b/server/src/Action/InstanceAction.php
index d6596c946d2807b5afb508d591877f609244f696..82442eb8881917e3e9b2c9292758a7c513ec383c 100644
--- a/server/src/Action/InstanceAction.php
+++ b/server/src/Action/InstanceAction.php
@@ -60,7 +60,7 @@ final class InstanceAction extends AbstractAction
             $parsedBody = $request->getParsedBody();
 
             // If mandatories empty fields 400
-            foreach (array('label') as $a) {
+            foreach (array('label', 'data_path') as $a) {
                 if ($this->isEmptyField($a, $parsedBody)) {
                     throw new HttpBadRequestException(
                         $request,
@@ -93,12 +93,8 @@ final class InstanceAction extends AbstractAction
     private function editInstance(Instance $instance, array $parsedBody): void
     {
         $instance->setLabel($parsedBody['label']);
-        if (!$this->isEmptyField('client_url', $parsedBody)) {
-            $instance->setClientUrl($parsedBody['client_url']);
-        } else {
-            $instance->setClientUrl(null);
-        }
         $instance->setConfig($parsedBody['config']);
+        $instance->setDataPath($parsedBody['data_path']);
         $this->em->flush();
     }
 }
diff --git a/server/src/Action/InstanceListAction.php b/server/src/Action/InstanceListAction.php
index ba42f865b198abb1a3b8b6691a4e8d44da2e2de0..9e226441a04659f0e18a5ae2b3ce00c08ef3c6a6 100644
--- a/server/src/Action/InstanceListAction.php
+++ b/server/src/Action/InstanceListAction.php
@@ -48,7 +48,7 @@ final class InstanceListAction extends AbstractAction
             $parsedBody = $request->getParsedBody();
 
             // To work this action needs user information to update
-            foreach (array('name', 'label') as $a) {
+            foreach (array('name', 'label', 'data_path') as $a) {
                 if ($this->isEmptyField($a, $parsedBody)) {
                     throw new HttpBadRequestException(
                         $request,
@@ -76,10 +76,8 @@ final class InstanceListAction extends AbstractAction
     private function postInstance(array $parsedBody): Instance
     {
         $instance = new Instance($parsedBody['name'], $parsedBody['label']);
-        if (!$this->isEmptyField('client_url', $parsedBody)) {
-            $instance->setClientUrl($parsedBody['client_url']);
-        }
         $instance->setConfig($parsedBody['config']);
+        $instance->setDataPath($parsedBody['data_path']);
 
         $this->em->persist($instance);
         $this->em->flush();
diff --git a/server/src/Entity/Dataset.php b/server/src/Entity/Dataset.php
index 45fec28a6bde0e364183fd5093294bde3c59793c..676fe3599d07bf993cda62a9482dd7a658becba0 100644
--- a/server/src/Entity/Dataset.php
+++ b/server/src/Entity/Dataset.php
@@ -209,6 +209,11 @@ class Dataset implements \JsonSerializable
         return $this->attributes;
     }
 
+    public function getFullDataPath()
+    {
+        return $this->getDatasetFamily()->getInstance()->getDataPath() . $this->getDataPath();
+    }
+
     public function jsonSerialize()
     {
         return [
@@ -221,7 +226,8 @@ class Dataset implements \JsonSerializable
             'config' => $this->getConfig(),
             'public' => $this->getPublic(),
             'survey_name' => $this->getSurvey()->getName(),
-            'id_dataset_family' => $this->getDatasetFamily()->getId()
+            'id_dataset_family' => $this->getDatasetFamily()->getId(),
+            'full_data_path' => $this->getFullDataPath()
         ];
     }
 }
diff --git a/server/src/Entity/Instance.php b/server/src/Entity/Instance.php
index 1e6ac070c1b050f681991a8d7268caba8184b32a..d95670e1f5ddbf8e1bb5eb7daf2eb1a584c7e566 100644
--- a/server/src/Entity/Instance.php
+++ b/server/src/Entity/Instance.php
@@ -41,9 +41,9 @@ class Instance implements \JsonSerializable
     /**
      * @var string
      *
-     * @Column(type="string", name="client_url", nullable=true)
+     * @Column(type="string", name="data_path", nullable=true)
      */
-    protected $clientUrl;
+    protected $dataPath;
 
     /**
      * @var string
@@ -81,14 +81,14 @@ class Instance implements \JsonSerializable
         $this->label = $label;
     }
 
-    public function getClientUrl()
+    public function getDataPath()
     {
-        return $this->clientUrl;
+        return $this->dataPath;
     }
 
-    public function setClientUrl($clientUrl)
+    public function setDataPath($dataPath)
     {
-        $this->clientUrl = $clientUrl;
+        $this->dataPath = $dataPath;
     }
 
     public function getConfig()
@@ -120,7 +120,7 @@ class Instance implements \JsonSerializable
         return [
             'name' => $this->getName(),
             'label' => $this->getLabel(),
-            'client_url' => $this->getClientUrl(),
+            'data_path' => $this->getDataPath(),
             'config' => $this->getConfig(),
             'nb_dataset_families' => count($this->getDatasetFamilies()),
             'nb_datasets' => $this->getNbDatasets()
diff --git a/server/src/Middleware/AuthorizationMiddleware.php b/server/src/Middleware/AuthorizationMiddleware.php
index b17c9aaae73870f3e428a0648a8ecfefeb8df4db..82b5b4e040383a817331333364af1065016b4012 100644
--- a/server/src/Middleware/AuthorizationMiddleware.php
+++ b/server/src/Middleware/AuthorizationMiddleware.php
@@ -57,15 +57,20 @@ final class AuthorizationMiddleware implements MiddlewareInterface
     {
         if (
             $request->getMethod() === OPTIONS
-            || !$request->hasHeader('Authorization')
+            || (!$request->hasHeader('Authorization') && !array_key_exists('token', $request->getQueryParams()))
             || !boolval($this->settings['enabled'])
         ) {
             return $handler->handle($request);
         }
 
         // Get token string from Authorizarion header
-        $bearer = $request->getHeader('Authorization');
-        $data = explode(' ', $bearer[0]);
+        if ($request->hasHeader('Authorization')) {
+            $bearer = $request->getHeader('Authorization')[0];
+        } else {
+            $bearer = 'Bearer ' . $request->getQueryParams()['token'];
+        }
+
+        $data = explode(' ', $bearer);
         if ($data[0] !== 'Bearer') {
             return $this->getUnauthorizedResponse(
                 'HTTP 401: Authorization must contain a string with the following format -> Bearer JWT'
@@ -89,12 +94,12 @@ final class AuthorizationMiddleware implements MiddlewareInterface
      *
      * @return Response
      */
-    private function getUnauthorizedResponse(string $message): Response
+    private function getUnauthorizedResponse(string $message): NyholmResponse
     {
         $resonse = new NyholmResponse();
         $resonse->getBody()->write(json_encode(array(
             'message' => $message
         )));
-        return $resonse->withStatus(401);
+        return $resonse->withStatus(401)->withHeader('Access-Control-Allow-Origin', '*');
     }
 }
diff --git a/server/src/Middleware/RouteGuardMiddleware.php b/server/src/Middleware/RouteGuardMiddleware.php
index 89bcf705156f828afd46505f4999603424b70b45..a9ba0e56e36a9f2578e18d1b145776f245f09642 100644
--- a/server/src/Middleware/RouteGuardMiddleware.php
+++ b/server/src/Middleware/RouteGuardMiddleware.php
@@ -102,6 +102,6 @@ final class RouteGuardMiddleware implements MiddlewareInterface
         $resonse->getBody()->write(json_encode(array(
             'message' => $message
         )));
-        return $resonse->withStatus($code);
+        return $resonse->withStatus($code)->withHeader('Access-Control-Allow-Origin', '*');
     }
 }
diff --git a/server/tests/Action/DatasetListActionTest.php b/server/tests/Action/DatasetListActionTest.php
index 3b34d4e20c67f7f3ad8e7285487c5f1090e6f1ff..51a5a343ceb1d6b63fc53ac3346fd35117c183df 100644
--- a/server/tests/Action/DatasetListActionTest.php
+++ b/server/tests/Action/DatasetListActionTest.php
@@ -21,6 +21,7 @@ use Doctrine\ORM\EntityManager;
 use Doctrine\Persistence\ObjectRepository;
 use App\Entity\Survey;
 use App\Entity\DatasetFamily;
+use App\Entity\Instance;
 
 final class DatasetListActionTest extends TestCase
 {
@@ -91,7 +92,9 @@ final class DatasetListActionTest extends TestCase
 
     public function testAddANewDataset(): void
     {
+        $instance = $this->createMock(Instance::class);
         $datasetFamily = $this->createMock(DatasetFamily::class);
+        $datasetFamily->method('getInstance')->willReturn($instance);
         $survey = $this->createMock(Survey::class);
         $this->entityManager->method('find')->willReturnOnConsecutiveCalls($datasetFamily, $survey);
 
diff --git a/server/tests/Action/InstanceActionTest.php b/server/tests/Action/InstanceActionTest.php
index a6c2a0ce106cd1b704a0e21bc1ff02eee76d43cb..5b717a3a2dd358c5e8b38e160f66b430c55a6870 100644
--- a/server/tests/Action/InstanceActionTest.php
+++ b/server/tests/Action/InstanceActionTest.php
@@ -78,7 +78,7 @@ final class InstanceActionTest extends TestCase
 
         $fields = array(
             'label' => 'AspiC',
-            'client_url' => 'http://aspic.lam.fr',
+            'data_path' => '/DEFAULT',
             'config' => '{}'
         );
 
diff --git a/server/tests/Action/InstanceListActionTest.php b/server/tests/Action/InstanceListActionTest.php
index 84ec13d8eaa930c6fcab76cc2679b26966335ffe..81c86466500f8515caccb29bbd7de4cb70e3a11e 100644
--- a/server/tests/Action/InstanceListActionTest.php
+++ b/server/tests/Action/InstanceListActionTest.php
@@ -63,7 +63,7 @@ final class InstanceListActionTest extends TestCase
         $fields = array(
             'name' => 'aspic',
             'label' => 'Aspic',
-            'client_url' => 'http://cesam.lam.fr/aspic',
+            'data_path' => '/DEFAULT',
             'config' => '{}'
         );
 
diff --git a/services/.gitlab-ci.yml b/services/.gitlab-ci.yml
index 38f978456fbe7706e1ad8a1e9a650756a6bc4f05..4bfe6473df99eef1ae1f2c6c0752f7ab3184c581 100644
--- a/services/.gitlab-ci.yml
+++ b/services/.gitlab-ci.yml
@@ -1,5 +1,6 @@
 stages:
     - dockerize
+    - deploy
 
 variables:
     VERSION: "3.7"
@@ -15,3 +16,17 @@ dockerize:
         - docker pull $CI_REGISTRY/anis/anis-next/services:latest || true
         - docker build --cache-from $CI_REGISTRY/anis/anis-next/services:latest -t $CI_REGISTRY/anis/anis-next/services:latest .
         - docker push $CI_REGISTRY/anis/anis-next/services:latest
+
+deploy:
+    image: alpine
+    stage: deploy
+    variables:
+        GIT_STRATEGY: none
+    cache: {}
+    dependencies: []
+    script:
+        - apk add --update curl
+        - curl -XPOST $DEV_WEBHOOK_SERVICES
+    only:
+        refs:
+            - develop
\ No newline at end of file
diff --git a/services/src/app.py b/services/src/app.py
index 8b31a4c3ad5ce53f17964296257ba9cd226d5736..742b8598afb46e0031c58ecff27949390eec2873 100644
--- a/services/src/app.py
+++ b/services/src/app.py
@@ -163,7 +163,7 @@ def spectra_to_csv(dname):
 
     try:
         file_path = utils.get_file_path(dname, filename)
-        csv = spectra.spectra_to_csv(file_path)
+        csv = spectra.spectra_to_csv(file_path, filename)
     except utils.DatasetNotFound as e:
         return {"message": str(e)}, 404
     except utils.FileForbidden as e:
diff --git a/services/src/spectra.py b/services/src/spectra.py
index 1fefa25b5056af9dcfa46f20bdcda4741f99e98a..fab05092be39c3f612fc107b96b3efc30ca9ae51 100644
--- a/services/src/spectra.py
+++ b/services/src/spectra.py
@@ -9,8 +9,8 @@ from spectra_strategies import GamaDR2AATStrategy
 from spectra_strategies import GamaDR2LTStrategy
 from spectra_strategies import ZCosmosBrightDr3Strategy
 
-def spectra_to_csv(filename):
-    hdulist = fits.open(filename)
+def spectra_to_csv(file_path, filename):
+    hdulist = fits.open(file_path)
 
     if(filename.count('6dF') > 0):
         solver = StrategySolver(SixdFStrategy())
diff --git a/services/src/utils.py b/services/src/utils.py
index ae8d5ce85665147c0fadb9f2a28dafc6417df3af..ff51fcdc92a73d8cd751f4f54d4b731972035c3e 100644
--- a/services/src/utils.py
+++ b/services/src/utils.py
@@ -28,7 +28,7 @@ def get_dataset(dname):
 def get_file_path(dname, filename):
     data_path = os.environ["DATA_PATH"]
     dataset = get_dataset(dname)
-    dataset_data_path = dataset["data_path"]
+    dataset_data_path = dataset["full_data_path"]
     file_path = data_path + dataset_data_path + '/' + filename
 
     if ('..' in filename):