diff --git a/client/src/app/instance/search/components/detail/default-object.component.html b/client/src/app/instance/search/components/detail/default-object.component.html
deleted file mode 100644
index bc6843ae7d94023d1cd8b39b9c9c57631d17822f..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/default-object.component.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<div class="row justify-content-center">
-    <div class="col col-lg-10 col-xl-8 mt-4">
-        <app-object-data
-            [datasetSelected]="datasetSelected"
-            [outputFamilyList]="outputFamilyList"
-            [outputCategoryList]="outputCategoryList"
-            [attributeList]="attributeList"
-            [object]="object">
-        </app-object-data>
-    </div>
-</div>
diff --git a/client/src/app/instance/search/components/detail/default-object.component.spec.ts b/client/src/app/instance/search/components/detail/default-object.component.spec.ts
deleted file mode 100644
index 24698efed39c3aa1726a35003d06811c4100fe2f..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/default-object.component.spec.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-import { Component, Input } from '@angular/core';
-
-import { DefaultObjectComponent } from './default-object.component';
-import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
-
-describe('[Instance][Search][Component][Detail][Default] DefaultObjectComponent', () => {
-    @Component({ selector: 'app-object-data', template: '' })
-    class ObjectDataStubComponent {
-        @Input() datasetSelected: string;
-        @Input() outputFamilyList: OutputFamily[];
-        @Input() outputCategoryList: OutputCategory[];
-        @Input() attributeList: Attribute[];
-        @Input() object: any;
-    }
-
-    let component: DefaultObjectComponent;
-    let fixture: ComponentFixture<DefaultObjectComponent>;
-
-    beforeEach(waitForAsync(() => {
-        TestBed.configureTestingModule({
-            declarations: [
-                DefaultObjectComponent,
-                ObjectDataStubComponent
-            ]
-        });
-        fixture = TestBed.createComponent(DefaultObjectComponent);
-        component = fixture.componentInstance;
-    }));
-
-    it('should create the component', () => {
-        expect(component).toBeTruthy();
-    });
-});
diff --git a/client/src/app/instance/search/components/detail/default-object.component.ts b/client/src/app/instance/search/components/detail/default-object.component.ts
deleted file mode 100644
index b690b814ea75139b70aeb8457d44e465ebdd063c..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/default-object.component.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * 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 { Attribute, OutputFamily, OutputCategory } from 'src/app/metamodel/models';
-
-/**
- * @class
- * @classdesc Detail default object component.
- */
-@Component({
-    selector: 'app-default-object',
-    templateUrl: 'default-object.component.html',
-    changeDetection: ChangeDetectionStrategy.OnPush
-})
-export class DefaultObjectComponent {
-    @Input() datasetSelected: string;
-    @Input() outputFamilyList: OutputFamily[];
-    @Input() outputCategoryList: OutputCategory[];
-    @Input() attributeList: Attribute[];
-    @Input() object: any;
-}
diff --git a/client/src/app/instance/search/components/detail/index.ts b/client/src/app/instance/search/components/detail/index.ts
deleted file mode 100644
index 86a0c1e9c69b6eec1dd7fcaf5564e0f907c3ba38..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { ObjectDataComponent } from './object-data.component';
-import { DefaultObjectComponent } from './default-object.component';
-import { spectraComponents } from './spectra';
-
-export const detailsComponents = [
-    ObjectDataComponent,
-    DefaultObjectComponent,
-    spectraComponents
-];
diff --git a/client/src/app/instance/search/components/detail/object-data.component.html b/client/src/app/instance/search/components/detail/object-data.component.html
deleted file mode 100644
index e9411be0d29bfa4d8e4d63c8f8deae62fa374213..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/object-data.component.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<div *ngIf="getAttributeRa() && getAttributeDec()" class="row">
-    <div class="col-12">
-        <table class="table mb-1" aria-describedby="Object coordinates">
-            <tr>
-                <th scope="col">Alpha</th>
-                <th scope="col">Delta</th>
-                <th scope="col" class="text-center" rowspan="2"><img src="assets/cesam_anis80.png" alt="CeSAM logo" /></th>
-            </tr>
-            <tr>
-                <td>{{ object[getAttributeRa().label] }}</td>
-                <td>{{ object[getAttributeDec().label] }}</td>
-            </tr>
-        </table>
-        <hr class="mt-0 mb-4">
-    </div>
-</div>
-
-<!-- Accordion families -->
-<accordion [isAnimated]="true">
-    <accordion-group *ngFor="let family of outputFamilyList" #ag [isOpen]="true" class="pl-2">
-        <button class="btn btn-link btn-block clearfix pb-2" accordion-heading>
-            <span class="pull-left float-left text-primary">
-                {{ family.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>
-            </span>
-        </button>
-
-        <!-- Accordion categories -->
-        <accordion [isAnimated]="true">
-            <accordion-group *ngFor="let category of getCategoryByFamily(family.id)" #ag [isOpen]="true" class="pl-4">
-                <button class="btn btn-link btn-block clearfix pb-2" accordion-heading>
-                    <span class="pull-left float-left text-primary">
-                        {{ category.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>
-                    </span>
-                </button>
-
-                <!-- Output list -->
-                <div *ngFor="let attribute of getAttributesVisibleByCategory(category.id)" class="row pb-2">
-                    <div class="col-5 font-weight-bold">{{ attribute.form_label }}</div>
-                    <div class="col">{{ object[attribute.label] }}</div>
-                </div>
-            </accordion-group>
-        </accordion>
-    </accordion-group>
-</accordion>
diff --git a/client/src/app/instance/search/components/detail/object-data.component.spec.ts b/client/src/app/instance/search/components/detail/object-data.component.spec.ts
deleted file mode 100644
index cdc9ba295ddcb75021fd693e230c9a04b7275d0d..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/object-data.component.spec.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-
-import { AccordionModule } from 'ngx-bootstrap/accordion';
-
-import { ObjectDataComponent } from './object-data.component';
-import { AppConfigService } from '../../../../app-config.service';
-import { ATTRIBUTE_LIST, CATEGORY_LIST } from '../../../../../test-data';
-
-describe('[Instance][Search][Component][Detail] ObjectDataComponent', () => {
-    let component: ObjectDataComponent;
-    let fixture: ComponentFixture<ObjectDataComponent>;
-    let appConfigServiceStub = new AppConfigService();
-
-    beforeEach(waitForAsync(() => {
-        TestBed.configureTestingModule({
-            declarations: [ObjectDataComponent],
-            imports: [AccordionModule.forRoot()],
-            providers: [{ provide: AppConfigService, useValue: appConfigServiceStub }]
-        });
-        fixture = TestBed.createComponent(ObjectDataComponent);
-        component = fixture.componentInstance;
-    }));
-
-    it('should create the component', () => {
-        expect(component).toBeTruthy();
-    });
-
-    it('#getCategoryByFamily() should return categories for the given family', () => {
-        component.outputCategoryList = CATEGORY_LIST;
-        expect(component.getCategoryByFamily(1).length).toEqual(2);
-    });
-
-    it('#getAttributesVisibleByCategory() should return visible attributes for the given category', () => {
-        component.attributeList = ATTRIBUTE_LIST;
-        expect(component.getAttributesVisibleByCategory(1).length).toEqual(1);
-        expect(component.getAttributesVisibleByCategory(1)[0].id).toEqual(2);
-    });
-
-    it('#getAttributesVisible() should return visible attributes', () => {
-        component.attributeList = ATTRIBUTE_LIST;
-        expect(component.getAttributesVisible().length).toEqual(2);
-    });
-
-    it('#getDownloadHref() should return URL', () => {
-        appConfigServiceStub.apiUrl = 'http://test.com';
-        component.datasetSelected = 'myDataset';
-        expect(component.getDownloadHref('myAttributeLabel')).toEqual('http://test.com/download-file/myDataset/myAttributeLabel');
-    });
-});
diff --git a/client/src/app/instance/search/components/detail/object-data.component.ts b/client/src/app/instance/search/components/detail/object-data.component.ts
deleted file mode 100644
index 34068a6fed49ff8445dbbdee0cd78fae57ed0ed5..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/object-data.component.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * 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 { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
-import { getHost } from 'src/app/shared/utils';
-import { AppConfigService } from 'src/app/app-config.service';
-
-/**
- * @class
- * @classdesc Detail object data component.
- */
-@Component({
-    selector: 'app-object-data',
-    templateUrl: 'object-data.component.html',
-    changeDetection: ChangeDetectionStrategy.OnPush
-})
-export class ObjectDataComponent {
-    @Input() datasetSelected: string;
-    @Input() outputFamilyList: OutputFamily[];
-    @Input() outputCategoryList: OutputCategory[];
-    @Input() attributeList: Attribute[];
-    @Input() object: any;
-
-    constructor(private appConfig: AppConfigService) { }
-
-    /**
-     * Returns category list for the given output family ID.
-     *
-     * @param  {number} idFamily - The output family ID.
-     *
-     * @return OutputCategory[]
-     */
-    getCategoryByFamily(idFamily: number): OutputCategory[] {
-        return this.outputCategoryList
-            .filter(category => category.id_output_family === idFamily);
-    }
-
-    /**
-     * Returns attribute list for the given output category ID that are visible in detail page.
-     *
-     * @param  {number} idCategory - The output category ID.
-     *
-     * @return Attribute[]
-     */
-    getAttributesVisibleByCategory(idCategory: number): Attribute[] {
-        return this.attributeList
-            .filter(a => a.id_detail_output_category)
-            .filter(a => a.id_output_category === idCategory);
-    }
-
-    /**
-     * Returns attribute list that are visible in detail page.
-     *
-     * @return Attribute[]
-     */
-    getAttributesVisible(): Attribute[] {
-        return this.attributeList.filter(a => a.id_detail_output_category);
-    }
-
-    /**
-     * Returns URL where download object.
-     *
-     * @param  {string} attributeLabel - The attribute label.
-     *
-     * @return string
-     */
-    getDownloadHref(attributeLabel: string): string {
-        return `${getHost(this.appConfig.apiUrl)}/download-file/${this.datasetSelected}/${attributeLabel}`;
-    }
-
-    getAttributeRa() {
-        return this.attributeList[2];
-    }
-
-    getAttributeDec() {
-        return this.attributeList[3];
-    }
-}
diff --git a/client/src/app/instance/search/components/detail/spectra/index.ts b/client/src/app/instance/search/components/detail/spectra/index.ts
deleted file mode 100644
index 77b5e03935e6f4321da07852a1d56a460bc70c3a..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/spectra/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { SpectraObjectComponent } from "./spectra-object.component";
-import { SpectraGraphComponent } from "./graph/spectra-graph.component";
-
-export const spectraComponents = [
-    SpectraObjectComponent,
-    SpectraGraphComponent
-];
diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html
deleted file mode 100644
index 8e1360dc72b1e7d49099e2aa51a59a1ff270e996..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<div class="row">
-    <div *ngIf="getAttributeSpectraGraph()" class="col col-md-8 col-sm-12">
-        <div *ngIf="spectraIsLoading" id="div-spinner" class="text-center">
-            <span class="fas fa-circle-notch fa-spin fa-3x"></span>
-            <span class="sr-only">Loading...</span>
-        </div>
-        <app-spectra-graph *ngIf="spectraIsLoaded" [z]="getZ()" [spectraCSV]="spectraCSV"></app-spectra-graph>
-    </div>
-
-    <div [ngClass]="{'col-md-4 col-sm-12': getAttributeSpectraGraph()}" class="col mt-4">
-        <div *ngIf="getSpectra()" class="jumbotron row mb-3 p-4">
-            <div class="col-auto align-self-center">
-                <p>Download:</p>
-            </div>
-            <div class="w-100 d-block d-xl-none"></div>
-            <div class="col">
-                <div class="row justify-content-center">
-                    <div class="col-auto">
-                        <a [href]="getSpectra()" class="btn btn-lg btn-block dl-btn">
-                            Download SPECTRA archive
-                        </a>
-                    </div>
-                </div>
-            </div>
-        </div>
-
-        <app-object-data
-            [datasetSelected]="datasetSelected"
-            [outputFamilyList]="outputFamilyList"
-            [outputCategoryList]="outputCategoryList"
-            [attributeList]="attributeList"
-            [object]="object">
-        </app-object-data>
-    </div>
-</div>
diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss
deleted file mode 100644
index 260a2036246abdb58c05276b1a262e50360ac3f3..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * 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.
- */
-
-.dl-btn {
-    height: 80px;
-    display: inline-block;
-}
diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts
deleted file mode 100644
index 890caacf18ba43e6417ac904bdcb27099628aba1..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { Component, Input } from '@angular/core';
-
-import { SpectraObjectComponent } from './spectra-object.component';
-import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
-import { AppConfigService } from 'src/app/app-config.service';
-import { ATTRIBUTE_LIST, OBJECT_DETAIL } from 'src/test-data';
-
-describe('[Instance][Search][Component][Detail][Spectra] SpectraObjectComponent', () => {
-    @Component({ selector: 'app-spectra-graph', template: '' })
-    class SpectraGraphStubComponent {
-        @Input() z: number;
-        @Input() spectraCSV: string;
-    }
-
-    @Component({ selector: 'app-object-data', template: '' })
-    class ObjectDataStubComponent {
-        @Input() datasetSelected: string;
-        @Input() outputFamilyList: OutputFamily[];
-        @Input() outputCategoryList: OutputCategory[];
-        @Input() attributeList: Attribute[];
-        @Input() object: any;
-    }
-
-    let component: SpectraObjectComponent;
-    let fixture: ComponentFixture<SpectraObjectComponent>;
-    let appConfigServiceStub = new AppConfigService();
-
-    beforeEach(() => {
-        TestBed.configureTestingModule({
-            declarations: [
-                SpectraObjectComponent,
-                SpectraGraphStubComponent,
-                ObjectDataStubComponent
-            ],
-            providers: [{ provide: AppConfigService, useValue: appConfigServiceStub }]
-        });
-        fixture = TestBed.createComponent(SpectraObjectComponent);
-        component = fixture.componentInstance;
-    });
-
-    it('should create the component', () => {
-        expect(component).toBeTruthy();
-    });
-
-    it('#ngOnInit() should emit getSpectraCSV event if an attribute have spectra_graph renderer_detail', () => {
-        component.attributeList = ATTRIBUTE_LIST;
-        component.object = OBJECT_DETAIL;
-        component.getSpectraCSV.subscribe((event: string) => expect(event).toEqual('spec1d'));
-        component.ngOnInit();
-    });
-});
diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts
deleted file mode 100644
index aa64933c48da5a20a9374b134d2b41f8c542e2c1..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * 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, Output, EventEmitter, OnInit } from '@angular/core';
-
-import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
-import { getHost } from 'src/app/shared/utils';
-import { AppConfigService } from 'src/app/app-config.service';
-
-/**
- * @class
- * @classdesc Detail spectra object component.
- *
- * @implements OnInit
- */
-@Component({
-    selector: 'app-spectra-object',
-    templateUrl: 'spectra-object.component.html',
-    styleUrls: ['spectra-object.component.scss'],
-    changeDetection: ChangeDetectionStrategy.OnPush
-})
-export class SpectraObjectComponent implements OnInit {
-    @Input() datasetSelected: string;
-    @Input() outputFamilyList: OutputFamily[];
-    @Input() outputCategoryList: OutputCategory[];
-    @Input() attributeList: Attribute[];
-    @Input() object: any;
-    @Input() spectraIsLoading: boolean;
-    @Input() spectraIsLoaded: boolean;
-    @Input() spectraCSV: string;
-    @Output() getSpectraCSV: EventEmitter<string> = new EventEmitter();
-
-    constructor(private appConfig: AppConfigService) { }
-
-    ngOnInit(): void {
-        const attributeSpectraGraph = this.getAttributeSpectraGraph();
-        if (attributeSpectraGraph) {
-            Promise.resolve(null).then(() => this.getSpectraCSV.emit(this.object[attributeSpectraGraph.label]));
-        }
-    }
-
-    /**
-     * Returns spectra file URL.
-     *
-     * @return string
-     */
-    getSpectra(): string {
-        const spectraAttribute = this.attributeList[0];
-        return `${getHost(this.appConfig.apiUrl)}/download-file/${this.datasetSelected}/${this.object[spectraAttribute.label]}`;
-    }
-
-    /**
-     * Returns detail rendered spectra graph attribute.
-     *
-     * @return Attribute
-     */
-    getAttributeSpectraGraph(): Attribute {
-        return this.attributeList[1];
-    }
-
-    /**
-     * Returns Z.
-     *
-     * @return number
-     */
-    getZ(): number {
-        return 0;
-        // const spectraGraphRendererConfig = this.getAttributeSpectraGraph().renderer_detail_config as SpectraGraphRendererConfig;
-        // if (spectraGraphRendererConfig.z) {
-        //     const attributeZ = this.attributeList.find(attribute => attribute.id === spectraGraphRendererConfig.z);
-        //     return +this.object[attributeZ.label];
-        // } else {
-        //     return 0;
-        // }
-    }
-}
diff --git a/client/src/app/instance/search/components/index.ts b/client/src/app/instance/search/components/index.ts
index f4057d78828f281aaaf1903fdc286bdd24d240bd..9a0df624bd3563eecf4e0efb3ef5ab367ae7c861 100644
--- a/client/src/app/instance/search/components/index.ts
+++ b/client/src/app/instance/search/components/index.ts
@@ -4,7 +4,6 @@ import { datasetComponents } from './dataset';
 import { criteriaComponents } from './criteria';
 import { outputComponents } from './output';
 import { resultComponents } from './result';
-import { detailsComponents } from './detail';
 
 export const dummiesComponents = [
     ProgressBarComponent,
@@ -12,6 +11,5 @@ export const dummiesComponents = [
     datasetComponents,
     criteriaComponents,
     outputComponents,
-    resultComponents,
-    detailsComponents
+    resultComponents
 ];
\ No newline at end of file
diff --git a/client/src/app/instance/search/detail/components/detail-content.component.html b/client/src/app/instance/search/detail/components/detail-content.component.html
index daab406d8b2701a0898d8a6be4ed2e712f7af25e..b0961d8fb18ce48ec3ba35de925aa73c81ba1435 100644
--- a/client/src/app/instance/search/detail/components/detail-content.component.html
+++ b/client/src/app/instance/search/detail/components/detail-content.component.html
@@ -1 +1,5 @@
-<ngx-dynamic-hooks [content]="detailConfig.content" [context]="getContext()"></ngx-dynamic-hooks>
\ No newline at end of file
+<ngx-dynamic-hooks 
+    [content]="detailConfig.content"
+    [parsers]="getParsers()"
+    [context]="getContext()">
+</ngx-dynamic-hooks>
diff --git a/client/src/app/instance/search/detail/components/detail-content.component.ts b/client/src/app/instance/search/detail/components/detail-content.component.ts
index 4e1adf8332d5244eb2fc820c3e0be0d31375c744..ca7dfd6084994540ef89324a035ded66e5620c1f 100644
--- a/client/src/app/instance/search/detail/components/detail-content.component.ts
+++ b/client/src/app/instance/search/detail/components/detail-content.component.ts
@@ -7,9 +7,11 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input } from '@angular/core';
+import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
 
-import { DetailConfig, Attribute, OutputFamily, OutputCategory} from 'src/app/metamodel/models';
+import { DetailConfig, Dataset, Attribute, OutputFamily, OutputCategory } from 'src/app/metamodel/models';
+import { globalParsers } from 'src/app/shared/dynamic-content';
+import { componentParsers } from '../dynamic-content';
 
 /**
  * @class
@@ -17,18 +19,28 @@ import { DetailConfig, Attribute, OutputFamily, OutputCategory} from 'src/app/me
  */
 @Component({
     selector: 'app-detail-content',
-    templateUrl: 'detail-content.component.html'
+    templateUrl: 'detail-content.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
 })
 export class DetailContentComponent {
     @Input() detailConfig: DetailConfig;
     @Input() object: any;
+    @Input() datasetName: string;
     @Input() attributeList: Attribute[];
     @Input() outputFamilyList: OutputFamily[];
     @Input() outputCategoryList: OutputCategory[];
 
+    getParsers() {
+        return [
+            ...globalParsers,
+            ...componentParsers
+        ];
+    }
+
     getContext() {
         return {
             object: this.object,
+            datasetName: this.datasetName,
             attributeList: this.attributeList,
             outputFamilyList: this.outputFamilyList,
             outputCategoryList: this.outputCategoryList
diff --git a/client/src/app/instance/search/detail/containers/detail.component.html b/client/src/app/instance/search/detail/containers/detail.component.html
index 9fc60ad458ae38a7d942436ea49e260cb235ec21..22aab0c4e8a2418834b72ab031ef87715978381a 100644
--- a/client/src/app/instance/search/detail/containers/detail.component.html
+++ b/client/src/app/instance/search/detail/containers/detail.component.html
@@ -20,6 +20,7 @@
         <app-detail-content 
             [detailConfig]="detailConfig | async"
             [object]="object | async"
+            [datasetName]="datasetSelected | async"
             [attributeList]="attributeList | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async">
diff --git a/client/src/app/instance/search/detail/detail.module.ts b/client/src/app/instance/search/detail/detail.module.ts
index a23e0508d92267a54b2693335b43f0715e8c0e49..f272f91753733e577c6db6d053b75579258ccbda 100644
--- a/client/src/app/instance/search/detail/detail.module.ts
+++ b/client/src/app/instance/search/detail/detail.module.ts
@@ -10,9 +10,9 @@
 import { NgModule } from '@angular/core';
 
 import { SharedModule } from 'src/app/shared/shared.module';
-import { DynamicContentModule } from './dynamic-content/dynamic-content.module';
 import { DetailRoutingModule, routedComponents } from './detail-routing.module';
 import { dummiesComponents } from './components';
+import { hookParsers, dynamicComponents } from './dynamic-content';
 
 /**
  * @class
@@ -21,12 +21,18 @@ import { dummiesComponents } from './components';
 @NgModule({
     imports: [
         SharedModule,
-        DynamicContentModule,
         DetailRoutingModule
     ],
     declarations: [
         routedComponents,
-        dummiesComponents
+        dummiesComponents,
+        dynamicComponents
+    ],
+    entryComponents: [
+        dynamicComponents
+    ],
+    providers: [
+        hookParsers
     ]
 })
 export class DetailModule { }
diff --git a/client/src/app/instance/search/detail/dynamic-content/components/index.ts b/client/src/app/instance/search/detail/dynamic-content/components/index.ts
deleted file mode 100644
index ff4f0ea4d36285884f51a39661ccca14da7c36f0..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/detail/dynamic-content/components/index.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * 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 { DisplayObjectComponent } from './display-object.component';
-
-export const dummiesComponents = [
-    DisplayObjectComponent
-];
diff --git a/client/src/app/instance/search/detail/dynamic-content/components/display-object.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.html
similarity index 100%
rename from client/src/app/instance/search/detail/dynamic-content/components/display-object.component.html
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.html
diff --git a/client/src/app/instance/search/detail/dynamic-content/components/display-object.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts
similarity index 85%
rename from client/src/app/instance/search/detail/dynamic-content/components/display-object.component.ts
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts
index c290ab7ef375b140139d684585bc2ef5d30368ad..1c029c11508c6dbce4d80c0a89fb24e29e900430 100644
--- a/client/src/app/instance/search/detail/dynamic-content/components/display-object.component.ts
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts
@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input } from '@angular/core';
+import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
 
 import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
 
@@ -17,7 +17,8 @@ import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/model
  */
 @Component({
     selector: 'app-display-object',
-    templateUrl: 'display-object.component.html'
+    templateUrl: 'display-object.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
 })
 export class DisplayObjectComponent {
     @Input() object: any;
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..b779cc47211c89b6f36fd14b0fd435e532d3ec9d
--- /dev/null
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html
@@ -0,0 +1,11 @@
+<table class="table mb-1" aria-describedby="Object coordinates">
+    <tr>
+        <th scope="col">Alpha</th>
+        <th scope="col">Delta</th>
+        <th scope="col" class="text-center" rowspan="2"><img src="assets/cesam_anis80.png" alt="CeSAM logo" /></th>
+    </tr>
+    <tr>
+        <td>{{ object[getAttributeRa().label] }}</td>
+        <td>{{ object[getAttributeDec().label] }}</td>
+    </tr>
+</table>
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4715be9b5bc9e0fe6d765d52d4721117b1544da0
--- /dev/null
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { Attribute } from 'src/app/metamodel/models';
+
+/**
+ * @class
+ * @classdesc Display object component.
+ */
+@Component({
+    selector: 'app-display-ra-dec',
+    templateUrl: 'display-ra-dec.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class DisplayRaDecComponent {
+    @Input() object: any;
+    @Input() attributeList: Attribute[];
+    @Input() attributeRaId: number;
+    @Input() attributeDecId: number;
+
+    getAttributeRa() {
+        return this.attributeList.find(attribute => attribute.id === this.attributeRaId);
+    }
+
+    getAttributeDec() {
+        return this.attributeList.find(attribute => attribute.id === this.attributeDecId);
+    }
+}
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..f908a1e04a212c8fe72ca15abc8601591eabbf39
--- /dev/null
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html
@@ -0,0 +1 @@
+<app-spectra-graph *ngIf="spectraCSV | async as data" [z]="getZ()" [spectraCSV]="data"></app-spectra-graph>
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fcf7ffedf84bdb92861c0fe467e887250b31f964
--- /dev/null
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts
@@ -0,0 +1,47 @@
+/**
+ * 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 { HttpClient } from '@angular/common/http';
+
+import { Observable } from 'rxjs';
+
+import { Attribute } from 'src/app/metamodel/models';
+import { AppConfigService } from 'src/app/app-config.service';
+
+/**
+ * @class
+ * @classdesc Display spectra component.
+ */
+@Component({
+    selector: 'app-display-spectra',
+    templateUrl: 'display-spectra.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class DisplaySpectraComponent {
+    @Input() object: any;
+    @Input() datasetName: string;
+    @Input() attributeList: Attribute[];
+    @Input() attributeSpectraId: number;
+    @Input() attributeZId: number;
+
+    spectraCSV: Observable<string>;
+
+    constructor(private http: HttpClient, private config: AppConfigService) { }
+
+    ngOnInit() {
+        const spectraFile = this.object[this.attributeList.find(attribute => attribute.id === this.attributeSpectraId).label];
+        this.spectraCSV = this.http.get(`${this.config.servicesUrl}/spectra-to-csv/${this.datasetName}?filename=${spectraFile}`, { responseType: 'text' });
+    }
+
+    getZ() {
+        const z = this.object[this.attributeList.find(attribute => attribute.id === this.attributeZId).label];
+        return +z;
+    }
+}
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts
index 0a6b8f24206481483991135d430f1cd8d23a639b..8c84be9b710bc658c127711e99eadc76678a664e 100644
--- a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts
+++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts
@@ -1,5 +1,11 @@
-import { DynamicRouterLinkComponent } from './dynamic-router-link.component';
+import { DisplayObjectComponent } from './display-object.component';
+import { DisplayRaDecComponent } from './display-ra-dec.component';
+import { DisplaySpectraComponent } from './display-spectra.component';
+import { SpectraGraphComponent } from './spectra-graph/spectra-graph.component';
 
-export const DynamicComponents = [
-    DynamicRouterLinkComponent
+export const dynamicComponents = [
+    DisplayObjectComponent,
+    DisplayRaDecComponent,
+    DisplaySpectraComponent,
+    SpectraGraphComponent
 ];
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/point.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/point.ts
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/point.ts
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/point.ts
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/rays.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/rays.ts
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/rays.ts
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/rays.ts
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.html
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.html
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.html
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.scss b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.scss
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.scss
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.scss
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.ts
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.ts
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.ts
diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-type.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-type.ts
similarity index 100%
rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-type.ts
rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-type.ts
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-content.module.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-content.module.ts
deleted file mode 100644
index 8f4f27818c3c0ea4ef559d24a8a79de8f825e191..0000000000000000000000000000000000000000
--- a/client/src/app/instance/search/detail/dynamic-content/dynamic-content.module.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * 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 { NgModule } from '@angular/core';
-import { RouterModule } from '@angular/router';
-
-import { DynamicHooksModule, HookParserEntry } from 'ngx-dynamic-hooks';
-
-import { SharedModule } from 'src/app/shared/shared.module';
-import { hookParsers } from './parsers';
-import { DynamicComponents } from './dynamic-components';
-import { dummiesComponents } from './components';
-
-export const componentParsers: Array<HookParserEntry> = [
-    ...hookParsers,
-    ...DynamicComponents.map(component => {
-        return { component };
-    })
-];
-
-/**
- * @class
- * @classdesc Dynamic content module.
- */
-@NgModule({
-    imports: [
-        SharedModule,
-        RouterModule,
-        DynamicHooksModule.forRoot({
-            globalParsers: componentParsers
-        }),
-    ],
-    exports: [
-        DynamicHooksModule
-    ],
-    providers: [
-        hookParsers
-    ],
-    declarations: [
-        DynamicComponents,
-        dummiesComponents
-    ],
-    entryComponents: [
-        DynamicComponents
-    ]
-})
-export class DynamicContentModule { }
diff --git a/client/src/app/instance/search/detail/dynamic-content/index.ts b/client/src/app/instance/search/detail/dynamic-content/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8a58f220117ec5118c9ca18d1f0e91af6ee7015
--- /dev/null
+++ b/client/src/app/instance/search/detail/dynamic-content/index.ts
@@ -0,0 +1,14 @@
+import { HookParserEntry } from 'ngx-dynamic-hooks';
+
+import { hookParsers } from './parsers';
+import { dynamicComponents } from './dynamic-components';
+
+export const componentParsers: Array<HookParserEntry> = [
+    ...hookParsers,
+    ...dynamicComponents.map(component => {
+        return { component };
+    })
+];
+
+export { hookParsers } from './parsers';
+export { dynamicComponents } from './dynamic-components';
diff --git a/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts b/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts
index bac0c8f9072e6c66cbda86f139d047018dcba1ba..552c5a60f42b85a8d485439c9086f2c80778140f 100644
--- a/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts
+++ b/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts
@@ -1,5 +1,3 @@
-import { DynamicRouterLinkParser } from './dynamic-router-link-parser';
-
 export const hookParsers = [
-    DynamicRouterLinkParser
+    
 ];
diff --git a/client/src/app/instance/store/effects/detail.effects.ts b/client/src/app/instance/store/effects/detail.effects.ts
index ce166cfa21a9a9d2caeaa9e5234e3a97678cfd29..b032e8c86fd4bd96109197d1a9ff4d5635bbbfc2 100644
--- a/client/src/app/instance/store/effects/detail.effects.ts
+++ b/client/src/app/instance/store/effects/detail.effects.ts
@@ -27,7 +27,6 @@ import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
  */
 @Injectable()
 export class DetailEffects {
-
     /**
      * Calls actions to retrieve object.
      */
@@ -42,8 +41,7 @@ export class DetailEffects {
             mergeMap(([, datasetName, attributeList, id]) => this.detailService.retrieveObject(
                 datasetName,
                 attributeList.find(attribute => attribute.order_by).id,
-                id,
-                attributeList.filter(attribute => attribute.id_detail_output_category).map(attribute => attribute.id)
+                id
             ).pipe(
                 map(object => detailActions.retrieveObjectSuccess({ object: object[0] })),
                 catchError(() => of(detailActions.retrieveObjectFail()))
diff --git a/client/src/app/instance/store/services/detail.service.ts b/client/src/app/instance/store/services/detail.service.ts
index e9b644aa71907475302f8ffbc31187f4daa59ccd..eee2a6247e76bced3dff6964eccf3f89f4d84c40 100644
--- a/client/src/app/instance/store/services/detail.service.ts
+++ b/client/src/app/instance/store/services/detail.service.ts
@@ -32,8 +32,8 @@ export class DetailService {
      *
      * @return Observable<any[]>
      */
-    retrieveObject(dname: string, criterionId: number, objectSelected: string, outputList: number[]): Observable<any[]> {
-        const query = `${dname}?c=${criterionId}::eq::${objectSelected}&a=${outputList.join(';')}`;
+    retrieveObject(dname: string, criterionId: number, objectSelected: string): Observable<any[]> {
+        const query = `${dname}?c=${criterionId}::eq::${objectSelected}&a=all`;
         return this.http.get<any[]>(`${this.config.apiUrl}/search/${query}`);
     }
 
diff --git a/client/src/app/instance/webpage/dynamic-content/components/datatable.component.html b/client/src/app/instance/webpage/components/datatable.component.html
similarity index 100%
rename from client/src/app/instance/webpage/dynamic-content/components/datatable.component.html
rename to client/src/app/instance/webpage/components/datatable.component.html
diff --git a/client/src/app/instance/webpage/dynamic-content/components/datatable.component.ts b/client/src/app/instance/webpage/components/datatable.component.ts
similarity index 100%
rename from client/src/app/instance/webpage/dynamic-content/components/datatable.component.ts
rename to client/src/app/instance/webpage/components/datatable.component.ts
diff --git a/client/src/app/instance/webpage/components/index.ts b/client/src/app/instance/webpage/components/index.ts
index 28c122e3ead6c199771514aeb447141d7880c7a0..cdbd83740a4c940c54f8449fce573b7fd98019b1 100644
--- a/client/src/app/instance/webpage/components/index.ts
+++ b/client/src/app/instance/webpage/components/index.ts
@@ -1,5 +1,7 @@
 import { WebpageComponent } from './webpage-content.component';
+import { DatatableComponent } from './datatable.component';
 
 export const dummiesComponents = [
-    WebpageComponent
+    WebpageComponent,
+    DatatableComponent
 ];
diff --git a/client/src/app/instance/webpage/components/webpage-content.component.html b/client/src/app/instance/webpage/components/webpage-content.component.html
index 99c5e9a4f9b14ba3431047af7a8c746abf86c8b0..5fff195df3ec184143772fe509157449a25c0c0b 100644
--- a/client/src/app/instance/webpage/components/webpage-content.component.html
+++ b/client/src/app/instance/webpage/components/webpage-content.component.html
@@ -1 +1 @@
-<ngx-dynamic-hooks [content]="webpage.content"></ngx-dynamic-hooks>
\ No newline at end of file
+<ngx-dynamic-hooks [content]="webpage.content" [parsers]="getParsers()"></ngx-dynamic-hooks>
\ No newline at end of file
diff --git a/client/src/app/instance/webpage/components/webpage-content.component.ts b/client/src/app/instance/webpage/components/webpage-content.component.ts
index a8bfd9bbc62020da36e27f1b93e00eb397f52045..7559b9c51420858fc938a183b3b481c867ed4f29 100644
--- a/client/src/app/instance/webpage/components/webpage-content.component.ts
+++ b/client/src/app/instance/webpage/components/webpage-content.component.ts
@@ -7,9 +7,11 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input } from '@angular/core';
+import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
 
 import { Webpage } from 'src/app/metamodel/models';
+import { globalParsers } from 'src/app/shared/dynamic-content';
+import { componentParsers } from '../dynamic-content';
 
 /**
  * @class
@@ -17,8 +19,16 @@ import { Webpage } from 'src/app/metamodel/models';
  */
 @Component({
     selector: 'app-webpage-content',
-    templateUrl: 'webpage-content.component.html'
+    templateUrl: 'webpage-content.component.html',
+    changeDetection: ChangeDetectionStrategy.OnPush
 })
 export class WebpageComponent {
     @Input() webpage: Webpage;
+
+    getParsers() {
+        return [
+            ...globalParsers,
+            ...componentParsers
+        ];
+    }
 }
diff --git a/client/src/app/instance/webpage/dynamic-content/components/index.ts b/client/src/app/instance/webpage/dynamic-content/components/index.ts
deleted file mode 100644
index b3594ebb9a4ea93fe6a85fd9f3df57b631d27e0d..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/components/index.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * 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 { DatatableComponent } from './datatable.component';
-
-export const dummiesComponents = [
-    DatatableComponent
-];
diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.html b/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.html
deleted file mode 100644
index 2f43ac7ec15f1e5f671dbca64512d719766158a9..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<a *ngIf="isExternalLink()"
-    [href]="link"
-    [ngClass]="css"
-    [target]="target ? target : '_self'"
->
-    <ng-container *ngTemplateOutlet="contentTpl"></ng-container>
-</a>
-
-<a *ngIf="!isExternalLink()" 
-    [routerLink]="link"
-    [queryParams]="queryParams ? queryParams : {}" 
-    [fragment]="anchorFragment ? anchorFragment : null"
-    [ngClass]="css"
->
-    <ng-container *ngTemplateOutlet="contentTpl"></ng-container>
-</a>
-
-<ng-template #contentTpl><ng-content></ng-content></ng-template>
diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.scss b/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.scss
deleted file mode 100644
index 1f0440ee0e66b2f7ee73998e14e352af81a61627..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-:host {
-    display: inline;
-}
\ No newline at end of file
diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.ts b/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.ts
deleted file mode 100644
index d0e20e09d5bd91c394084aba899ed450e398f04f..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/dynamic-components/dynamic-router-link.component.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Component, Input } from '@angular/core';
-
-@Component({
-    selector: 'app-dynamic-router-link',
-    templateUrl: 'dynamic-router-link.component.html',
-    styleUrls: [ 'dynamic-router-link.component.scss' ]
-})
-export class DynamicRouterLinkComponent {
-    @Input() link: string;
-    @Input() queryParams: {[key: string]: any};
-    @Input() anchorFragment: string;
-    @Input() css: string;
-    @Input() target: string;
-
-    isExternalLink() {
-        return this.link.startsWith('http');
-    }
-}
diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts b/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts
index 81f64b144b7758770edc2f0a2f79810bedc1f3b0..36671afce11b25c1cb064a8d3851b24b431cf5d4 100644
--- a/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts
+++ b/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts
@@ -1,7 +1,5 @@
-import { DynamicRouterLinkComponent } from './dynamic-router-link.component';
 import { DatasetSampleComponent } from './dataset-sample.component';
 
-export const DynamicComponents = [
-    DynamicRouterLinkComponent,
+export const dynamicComponents = [
     DatasetSampleComponent
 ];
diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-content.module.ts b/client/src/app/instance/webpage/dynamic-content/dynamic-content.module.ts
deleted file mode 100644
index 8f4f27818c3c0ea4ef559d24a8a79de8f825e191..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/dynamic-content.module.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * 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 { NgModule } from '@angular/core';
-import { RouterModule } from '@angular/router';
-
-import { DynamicHooksModule, HookParserEntry } from 'ngx-dynamic-hooks';
-
-import { SharedModule } from 'src/app/shared/shared.module';
-import { hookParsers } from './parsers';
-import { DynamicComponents } from './dynamic-components';
-import { dummiesComponents } from './components';
-
-export const componentParsers: Array<HookParserEntry> = [
-    ...hookParsers,
-    ...DynamicComponents.map(component => {
-        return { component };
-    })
-];
-
-/**
- * @class
- * @classdesc Dynamic content module.
- */
-@NgModule({
-    imports: [
-        SharedModule,
-        RouterModule,
-        DynamicHooksModule.forRoot({
-            globalParsers: componentParsers
-        }),
-    ],
-    exports: [
-        DynamicHooksModule
-    ],
-    providers: [
-        hookParsers
-    ],
-    declarations: [
-        DynamicComponents,
-        dummiesComponents
-    ],
-    entryComponents: [
-        DynamicComponents
-    ]
-})
-export class DynamicContentModule { }
diff --git a/client/src/app/instance/webpage/dynamic-content/index.ts b/client/src/app/instance/webpage/dynamic-content/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8a58f220117ec5118c9ca18d1f0e91af6ee7015
--- /dev/null
+++ b/client/src/app/instance/webpage/dynamic-content/index.ts
@@ -0,0 +1,14 @@
+import { HookParserEntry } from 'ngx-dynamic-hooks';
+
+import { hookParsers } from './parsers';
+import { dynamicComponents } from './dynamic-components';
+
+export const componentParsers: Array<HookParserEntry> = [
+    ...hookParsers,
+    ...dynamicComponents.map(component => {
+        return { component };
+    })
+];
+
+export { hookParsers } from './parsers';
+export { dynamicComponents } from './dynamic-components';
diff --git a/client/src/app/instance/webpage/dynamic-content/parsers/dynamic-router-link-parser.ts b/client/src/app/instance/webpage/dynamic-content/parsers/dynamic-router-link-parser.ts
deleted file mode 100644
index cb543c79b8a96b1d49c935f44f88045eef4ee3d9..0000000000000000000000000000000000000000
--- a/client/src/app/instance/webpage/dynamic-content/parsers/dynamic-router-link-parser.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import { Injectable } from '@angular/core';
-import { HookParser, HookPosition, HookValue, HookComponentData, HookBindings, HookFinder } from 'ngx-dynamic-hooks';
-
-import { DynamicRouterLinkComponent } from '../dynamic-components/dynamic-router-link.component';
-
-@Injectable()
-export class DynamicRouterLinkParser implements HookParser {
-    linkOpeningTagRegex: RegExp;
-    linkClosingTagRegex: RegExp;
-    hrefAttrRegex: RegExp;
-    classAttrRegex: RegExp;
-    targetAttrRegex: RegExp;
-
-    constructor(private hookFinder: HookFinder) {
-        const hrefAttr = '\\s+href\=\\"([^\\"]*?)\\"';
-        const anyOtherAttr = '\\s+[a-zA-Z]+\\=\\"[^\\"]*?\\"';
-        const linkOpeningTag = '\\<a(?:' + anyOtherAttr + ')*?' + hrefAttr + '(?:' + anyOtherAttr + ')*?\\>';
-
-        // Transform into proper regex objects and save for later
-        this.linkOpeningTagRegex = new RegExp(linkOpeningTag, 'gim');
-        this.linkClosingTagRegex = new RegExp('<\\/a>',  'gim');
-        this.hrefAttrRegex = new RegExp(hrefAttr, 'im');
-        this.classAttrRegex = new RegExp('\\s+class\=\\"([^\\"]*?)\\"', 'im');
-        this.targetAttrRegex = new RegExp('\\s+target\=\\"([^\\"]*?)\\"', 'im')
-    }
-
-    public findHooks(content: string, context: any): Array<HookPosition> {
-        // With the regexes we prepared, we can simply use findEnclosingHooks() to retrieve
-        // the HookPositions of all internal <a>-elements from the content string
-        return this.hookFinder.findEnclosingHooks(content, this.linkOpeningTagRegex, this.linkClosingTagRegex);
-    }
-
-    public loadComponent(hookId: number, hookValue: HookValue, context: any, childNodes: Array<Element>): HookComponentData {
-        // Simply return the component class here
-        return {
-            component: DynamicRouterLinkComponent
-        };
-    }
-
-    public getBindings(hookId: number, hookValue: HookValue, context: any): HookBindings {
-        // We can reuse the hrefAttrRegex here as its first capture group is the relative part of the url, 
-        // e.g. '/jedi/windu' from 'https://www.mysite.com/jedi/windu', which is what we need
-        const hrefAttrMatch = hookValue.openingTag.match(this.hrefAttrRegex);
-        let link = hrefAttrMatch[1];
-
-        // The relative part of the link may still contain the query string and the 
-        // anchor fragment, so we need to split it up accordingly
-        const anchorFragmentSplit = link.split('#');
-        link = anchorFragmentSplit[0];
-        const anchorFragment = anchorFragmentSplit.length > 1 ? anchorFragmentSplit[1] : null;
-
-        const queryParamsSplit = link.split('?');
-        link = queryParamsSplit[0];
-        const queryParams = queryParamsSplit.length > 1 ? this.parseQueryString(queryParamsSplit[1]) : {};
-
-        // Select css part
-        let css = null;
-        const classAttrMatch = hookValue.openingTag.match(this.classAttrRegex);
-        if (classAttrMatch) {
-            css = classAttrMatch[1];
-        }
-
-        // Select target part
-        let target = null;
-        const targetAttrMatch = hookValue.openingTag.match(this.targetAttrRegex);
-        if (targetAttrMatch) {
-            target = targetAttrMatch[1];
-        }
-
-        // Give all of these to our DynamicRouterLinkComponent as inputs and we're done!
-        return {
-            inputs: {
-                link,
-                queryParams: queryParams,
-                anchorFragment: anchorFragment,
-                css,
-                target
-            }
-        };
-    }
-
-    /**
-     * A helper function that transforms a query string into a QueryParams object
-     * Approach by Wolfgang Kuehn @ https://stackoverflow.com/a/8649003/3099523
-     *
-     * @param queryParamString - The queryString to parse
-     */
-    private parseQueryString(queryParamString: string): {[key: string]: any} {
-        return JSON.parse('{"' + 
-            decodeURI(queryParamString)
-            .replace(/"/g, '\\"')
-            .replace(/&/g, '","')
-            .replace(/=/g, '":"') + 
-        '"}');
-    }
-}
diff --git a/client/src/app/instance/webpage/dynamic-content/parsers/index.ts b/client/src/app/instance/webpage/dynamic-content/parsers/index.ts
index bac0c8f9072e6c66cbda86f139d047018dcba1ba..552c5a60f42b85a8d485439c9086f2c80778140f 100644
--- a/client/src/app/instance/webpage/dynamic-content/parsers/index.ts
+++ b/client/src/app/instance/webpage/dynamic-content/parsers/index.ts
@@ -1,5 +1,3 @@
-import { DynamicRouterLinkParser } from './dynamic-router-link-parser';
-
 export const hookParsers = [
-    DynamicRouterLinkParser
+    
 ];
diff --git a/client/src/app/instance/webpage/webpage.module.ts b/client/src/app/instance/webpage/webpage.module.ts
index e88ace7bcff38b64d22ddfa53cb089147f545aba..86a7baca4e2077dd36eda7b4a4eba995a96a4b8f 100644
--- a/client/src/app/instance/webpage/webpage.module.ts
+++ b/client/src/app/instance/webpage/webpage.module.ts
@@ -10,9 +10,9 @@
 import { NgModule } from '@angular/core';
 
 import { SharedModule } from 'src/app/shared/shared.module';
-import { DynamicContentModule } from './dynamic-content/dynamic-content.module';
 import { WebpageRoutingModule, routedComponents } from './webpage-routing.module';
 import { dummiesComponents } from './components';
+import { hookParsers, dynamicComponents } from './dynamic-content';
 
 /**
  * @class
@@ -21,12 +21,18 @@ import { dummiesComponents } from './components';
 @NgModule({
     imports: [
         SharedModule,
-        DynamicContentModule,
         WebpageRoutingModule,
     ],
     declarations: [
         routedComponents,
-        dummiesComponents
+        dummiesComponents,
+        dynamicComponents
+    ],
+    entryComponents: [
+        dynamicComponents
+    ],
+    providers: [
+        hookParsers
     ]
 })
 export class WebpageModule { }
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.html b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.html
similarity index 100%
rename from client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.html
rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.html
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.scss b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.scss
similarity index 100%
rename from client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.scss
rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.scss
diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.ts b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.ts
similarity index 100%
rename from client/src/app/instance/search/detail/dynamic-content/dynamic-components/dynamic-router-link.component.ts
rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.ts
diff --git a/client/src/app/shared/dynamic-content/dynamic-components/index.ts b/client/src/app/shared/dynamic-content/dynamic-components/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..376e8a427ccae25fc2bd6090b24f59785feb858a
--- /dev/null
+++ b/client/src/app/shared/dynamic-content/dynamic-components/index.ts
@@ -0,0 +1,5 @@
+import { DynamicRouterLinkComponent } from './dynamic-router-link.component';
+
+export const dynamicComponents = [
+    DynamicRouterLinkComponent
+];
diff --git a/client/src/app/shared/dynamic-content/index.ts b/client/src/app/shared/dynamic-content/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..98122e3a81ef2561c55476df774861dfda839d67
--- /dev/null
+++ b/client/src/app/shared/dynamic-content/index.ts
@@ -0,0 +1,14 @@
+import { HookParserEntry } from 'ngx-dynamic-hooks';
+
+import { hookParsers } from './parsers';
+import { dynamicComponents } from './dynamic-components';
+
+export const globalParsers: Array<HookParserEntry> = [
+    ...hookParsers,
+    ...dynamicComponents.map(component => {
+        return { component };
+    })
+];
+
+export { hookParsers } from './parsers';
+export { dynamicComponents } from './dynamic-components';
diff --git a/client/src/app/instance/search/detail/dynamic-content/parsers/dynamic-router-link-parser.ts b/client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts
similarity index 99%
rename from client/src/app/instance/search/detail/dynamic-content/parsers/dynamic-router-link-parser.ts
rename to client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts
index cb543c79b8a96b1d49c935f44f88045eef4ee3d9..01b5fa6eaeea8bd6c29a5e2bdf326d822472159d 100644
--- a/client/src/app/instance/search/detail/dynamic-content/parsers/dynamic-router-link-parser.ts
+++ b/client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts
@@ -21,7 +21,7 @@ export class DynamicRouterLinkParser implements HookParser {
         this.linkClosingTagRegex = new RegExp('<\\/a>',  'gim');
         this.hrefAttrRegex = new RegExp(hrefAttr, 'im');
         this.classAttrRegex = new RegExp('\\s+class\=\\"([^\\"]*?)\\"', 'im');
-        this.targetAttrRegex = new RegExp('\\s+target\=\\"([^\\"]*?)\\"', 'im')
+        this.targetAttrRegex = new RegExp('\\s+target\=\\"([^\\"]*?)\\"', 'im');
     }
 
     public findHooks(content: string, context: any): Array<HookPosition> {
diff --git a/client/src/app/shared/dynamic-content/parsers/index.ts b/client/src/app/shared/dynamic-content/parsers/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bac0c8f9072e6c66cbda86f139d047018dcba1ba
--- /dev/null
+++ b/client/src/app/shared/dynamic-content/parsers/index.ts
@@ -0,0 +1,5 @@
+import { DynamicRouterLinkParser } from './dynamic-router-link-parser';
+
+export const hookParsers = [
+    DynamicRouterLinkParser
+];
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 5455dacaf03013492277fba8166c698db0219f76..750a89c0234ed6dca33bf93335087f5b2c6bc379 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -23,9 +23,11 @@ import { PaginationModule } from 'ngx-bootstrap/pagination';
 import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
 import { NgSelectModule } from '@ng-select/ng-select';
 import { NgxJsonViewerModule } from 'ngx-json-viewer';
+import { DynamicHooksModule } from 'ngx-dynamic-hooks';
 
 import { sharedComponents } from './components';
 import { sharedPipes } from './pipes';
+import { hookParsers, dynamicComponents } from './dynamic-content';
 
 /**
  * @class
@@ -34,7 +36,14 @@ import { sharedPipes } from './pipes';
 @NgModule({
     declarations: [
         sharedComponents,
-        sharedPipes
+        sharedPipes,
+        dynamicComponents
+    ],
+    entryComponents: [
+        dynamicComponents
+    ],
+    providers: [
+        hookParsers
     ],
     imports: [
         CommonModule,
@@ -51,7 +60,8 @@ import { sharedPipes } from './pipes';
         PaginationModule.forRoot(),
         ProgressbarModule.forRoot(),
         NgSelectModule,
-        NgxJsonViewerModule
+        NgxJsonViewerModule,
+        DynamicHooksModule.forRoot({}),
     ],
     exports: [
         CommonModule,
@@ -68,8 +78,10 @@ import { sharedPipes } from './pipes';
         ProgressbarModule,
         NgSelectModule,
         NgxJsonViewerModule,
+        DynamicHooksModule,
         sharedComponents,
-        sharedPipes
+        sharedPipes,
+        dynamicComponents
     ]
 })
 export class SharedModule { }
diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh
index 5118a6a2a21f233478ca4db8dc10bdee0c23860e..047335427c6b09f661a8d267da01d5ff09bd7449 100644
--- a/conf-dev/create-db.sh
+++ b/conf-dev/create-db.sh
@@ -43,6 +43,9 @@ curl -d '{"id":56,"name":"spec1d","label":"spec1d","form_label":"spec1d","descri
 curl -d '{"id":57,"name":"spec1dnoise","label":"spec1dnoise","form_label":"spec1dnoise","description":null,"primary_key":false,"output_display":570,"criteria_display":570,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":570,"selected":true,"order_by":false,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute
 curl -d '{"id":58,"name":"spec1dsky","label":"spec1dsky","form_label":"spec1dsky","description":null,"primary_key":false,"output_display":580,"criteria_display":580,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":580,"selected":true,"order_by":false,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute
 
+# Add vipers_dr2_w1 detail config
+curl -d '{"enabled":true,"content":"<div class=\"row\">\n    <div class=\"col col-md-8 col-sm-12\">\n        <app-display-spectra\n            [object]=\"context.object\"\n            [datasetName]=\"context.datasetName\"\n            [attributeList]=\"context.attributeList\"\n            [attributeSpectraId]=\"56\"\n            [attributeZId]=\"8\">\n        </app-display-spectra>\n    </div>\n    <div class=\"col col-md-4 col-sm-12\">\n        <app-display-ra-dec\n            [object]=\"context.object\"\n            [attributeList]=\"context.attributeList\"\n            [attributeRaId]=\"2\"\n            [attributeDecId]=\"3\">\n        </app-display-ra-dec>\n        <app-display-object \n            [object]=\"context.object\"\n            [attributeList]=\"context.attributeList\"\n            [outputFamilyList]=\"context.outputFamilyList\"\n            [outputCategoryList]=\"context.outputCategoryList\">\n        </app-display-object>\n    </div>\n</div>"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/detail-config
+
 # Add sp_cards attributes
 curl -d '{"label":"Card","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/criteria-family
 curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/output-family
@@ -74,6 +77,9 @@ curl -d '{"id":7,"name":"object_name","label":"object_name","form_label":"Object
 curl -d '{"id":8,"name":"fits_file","label":"fits_file","form_label":"fits_file","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":80,"selected":true,"order_by":false,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute
 curl -d '{"id":9,"name":"fits_png","label":"fits_png","form_label":"fits_png","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"image","renderer_config":{"type":"fits","display":"modal","width":"50","height":"50"},"detail_display":90,"selected":true,"order_by":false,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute
 
+# Add observations detail config
+curl -d '{"enabled":true,"content":"<div class=\"row justify-content-center\">\n    <div class=\"col col-lg-10 col-xl-8 mt-4\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <app-display-ra-dec\n                    [object]=\"context.object\"\n                    [attributeList]=\"context.attributeList\"\n                    [attributeRaId]=\"2\"\n                    [attributeDecId]=\"3\">\n                </app-display-ra-dec>\n            </div>\n        </div>\n\n        <app-display-object \n            [object]=\"context.object\"\n            [attributeList]=\"context.attributeList\"\n            [outputFamilyList]=\"context.outputFamilyList\"\n            [outputCategoryList]=\"context.outputCategoryList\">\n        </app-display-object>\n    </div>\n</div>"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/detail-config
+
 # Add vvds_f02_udeep attributes
 curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/criteria-family
 curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/output-family
@@ -112,4 +118,4 @@ curl -d '{"id":15,"name":"src_id","label":"src_id","form_label":"SRC ID","descri
 
 # Add webpages
 curl -d '{"label":"Default","icon":null,"display":10}' --header 'Content-Type: application/json' -X POST http://localhost/instance/default/webpage-family
-curl -d '{"label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<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=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\"></div><div class=\"col-md-8 order-md-1 text-justify pr-md-5\"><h2 class=\"mb-3\">Welcome to the ANIS default instance</h2><p class=\"lead\">This service provides several sub-services to interact with the database.<br>Here is a brief presentation of these sub-services:</p><ul class=\"lead\"><li><a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">/import/</a> =&gt; This sub-service allows you to import data L0, L1 or SR3/SR4</li><li>/export-rest =&gt; =&gt; This sub-service allows you to request and export data from the database in json format with a specific URL. To build this URL you could <a class=\"btn btn-warning\" href=\"../../search\">Go to search form</a></li></ul></div></div>"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage
+curl -d '{"label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<div class=\"row align-items-center jumbotron\">\n    <div class=\"col-6 col-md-4 order-md-2 mx-auto text-center\">\n        <img class=\"img-fluid mb-3 mb-md-0\" src=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\">\n   </div>\n   <div class=\"col-md-8 order-md-1 text-justify pr-md-5\">\n       <h2 class=\"mb-3\">Welcome to the ANIS default instance</h2>\n       <p class=\"lead\">\n           This service provides several sub-services to interact with the database.<br>\n           Here is a brief presentation of these sub-services:\n       </p>\n       <ul class=\"lead\">\n           <li>\n               <a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">\n                   /import/\n               </a> =&gt; This sub-service allows you to import data L0, L1 or SR3/SR4\n           </li>\n           <li>\n               /export-rest =&gt; =&gt; This sub-service allows you to request and export data \n               from the database in json format with a specific URL. To build this URL you could \n               <a class=\"btn btn-warning\" href=\"../../search\">\n                   Go to search form\n               </a>\n           </li>\n       </ul>\n   </div>\n</div>\n<app-dataset-sample\n    [datasetName]=\"'\''observations'\''\"\n    [sortingColumn]=\"1\"\n    [sortingDirection]=\"'\''d'\''\"\n    [nbItems]=\"5\">\n</app-dataset-sample>"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage