From ee93803239ff0e22d91de2841eec309aca453fc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr>
Date: Wed, 26 Oct 2022 14:44:50 +0200
Subject: [PATCH] #89 => Add link and link hover

---
 .../components/instance-form.component.html   | 24 +++++++
 .../components/instance-form.component.ts     |  3 +
 .../app/instance/instance-style.service.ts    | 30 +++++++-
 .../app/instance/instance.component.spec.ts   |  4 +-
 .../result/datatable.component.html           | 16 ++---
 .../result/datatable.component.scss           |  4 +-
 .../effects/search-multiple.effects.spec.ts   |  8 ++-
 .../app/metamodel/models/instance.model.ts    |  3 +
 client/src/test-data.ts                       | 12 +++-
 conf-dev/create-db.sh                         |  2 +-
 .../__CG__AppEntityInstance.php               | 70 ++++++++++++++++++-
 server/src/Action/InstanceAction.php          |  6 ++
 server/src/Action/InstanceListAction.php      |  6 ++
 server/src/Entity/Instance.php                | 54 ++++++++++++++
 server/tests/Action/InstanceActionTest.php    |  3 +
 .../tests/Action/InstanceListActionTest.php   |  3 +
 16 files changed, 228 insertions(+), 20 deletions(-)

diff --git a/client/src/app/admin/instance/components/instance-form.component.html b/client/src/app/admin/instance/components/instance-form.component.html
index 22cb6593..639e4552 100644
--- a/client/src/app/admin/instance/components/instance-form.component.html
+++ b/client/src/app/admin/instance/components/instance-form.component.html
@@ -105,6 +105,26 @@
                 <label for="design_font_family">Instance font family</label>
                 <input type="text" class="form-control" id="design_font_family" name="design_font_family" formControlName="design_font_family">
             </div>
+            <div class="form-row">
+                <div class="form-group col-md-6">
+                    <label for="design_link_color_picker">Instance link color (picker)</label>
+                    <input class="form-control" type="color" id="design_link_color_picker" [value]="form.value.design_link_color" formControlName="design_link_color">
+                </div>
+                <div class="form-group col-md-6">
+                    <label for="design_link_color_input">Instance link color (value)</label>
+                    <input type="text" class="form-control" id="design_link_color_input" [value]="form.value.design_link_color" formControlName="design_link_color">
+                </div>
+            </div>
+            <div class="form-row">
+                <div class="form-group col-md-6">
+                    <label for="design_link_hover_color_picker">Instance link hover color (picker)</label>
+                    <input class="form-control" type="color" id="design_link_hover_color_picker" [value]="form.value.design_link_hover_color" formControlName="design_link_hover_color">
+                </div>
+                <div class="form-group col-md-6">
+                    <label for="design_link_hover_color_input">Instance link hover color (value)</label>
+                    <input type="text" class="form-control" id="design_link_hover_color_input" [value]="form.value.design_link_hover_color" formControlName="design_link_hover_color">
+                </div>
+            </div>
             <app-path-select-form-control
                 [form]="form"
                 [disabled]="isFilesPathEmpty()"
@@ -626,6 +646,10 @@
                 <input class="custom-control-input" type="checkbox" id="result_datatable_bordered" name="result_datatable_bordered" formControlName="result_datatable_bordered">
                 <label class="custom-control-label" for="result_datatable_bordered">Result datatable bordered</label>
             </div>
+            <div class="custom-control custom-switch mb-2">
+                <input class="custom-control-input" type="checkbox" id="result_datatable_bordered_radius" name="result_datatable_bordered_radius" formControlName="result_datatable_bordered_radius">
+                <label class="custom-control-label" for="result_datatable_bordered_radius">Result datatable bordered radius</label>
+            </div>
             <div class="form-row">
                 <div class="form-group col-md-6">
                     <label for="result_datatable_border_color_picker">Result datatable border color (picker)</label>
diff --git a/client/src/app/admin/instance/components/instance-form.component.ts b/client/src/app/admin/instance/components/instance-form.component.ts
index ed202323..f07001c7 100644
--- a/client/src/app/admin/instance/components/instance-form.component.ts
+++ b/client/src/app/admin/instance/components/instance-form.component.ts
@@ -44,6 +44,8 @@ export class InstanceFormComponent implements OnInit {
         design_background_color: new UntypedFormControl('#FFFFFF', [Validators.required]),
         design_text_color: new UntypedFormControl('#212529'),
         design_font_family: new UntypedFormControl('Roboto, sans-serif'),
+        design_link_color: new UntypedFormControl('#007BFF'),
+        design_link_hover_color: new UntypedFormControl('#0056B3'),
         design_logo: new UntypedFormControl(''),
         design_logo_href: new UntypedFormControl(null),
         design_favicon: new UntypedFormControl(''),
@@ -100,6 +102,7 @@ export class InstanceFormComponent implements OnInit {
         result_datatable_actions_btn_hover_color: new UntypedFormControl('#0069D9'),
         result_datatable_actions_btn_text_color: new UntypedFormControl('#FFFFFF'),
         result_datatable_bordered: new UntypedFormControl(true),
+        result_datatable_bordered_radius: new UntypedFormControl(false),
         result_datatable_border_color: new UntypedFormControl('#DEE2E6'),
         result_datatable_header_background_color: new UntypedFormControl('#FFFFFF'),
         result_datatable_header_text_color: new UntypedFormControl('#000000'),
diff --git a/client/src/app/instance/instance-style.service.ts b/client/src/app/instance/instance-style.service.ts
index 4921bc1b..cb82548b 100644
--- a/client/src/app/instance/instance-style.service.ts
+++ b/client/src/app/instance/instance-style.service.ts
@@ -28,6 +28,8 @@ export class InstanceStyleService {
             'color': instance.design_text_color,
             'font-family': instance.design_font_family
         });
+        this.style.setStyle('.instance-main a', 'color', instance.design_link_color);
+        this.style.setStyle('.instance-main a:hover', 'color', instance.design_link_hover_color);
     }
 
     private navbarStyle(instance: Instance) {
@@ -67,7 +69,7 @@ export class InstanceStyleService {
         this.style.setStyle('.progress-navigation .progress.progress-with-circle', 'background-color', instance.progress_bar_color);
         this.style.setStyle('.progress-navigation .progress.progress-with-circle .progress-bar', 'background-color', instance.progress_bar_active_color);
         this.style.setStyle('.progress-navigation .nav-link, .progress-navigation .nav-link.disabled', 'color', instance.progress_bar_text_color);
-        this.style.setStyle('.progress-navigation .nav-link, .progress-navigation .nav-link.disabled', 'color', instance.progress_bar_text_color);
+        this.style.setStyle('.progress-navigation .nav-link:hover', 'color', instance.progress_bar_text_color);
         this.style.setStyle('.progress-navigation .nav-item.checked .nav-link, .progress-navigation.nav-item.active .nav-link', 'color', instance.progress_bar_active_color);
         this.style.setStyles('.progress-navigation .nav-item .icon-circle', {
             'border-color': instance.progress_bar_color,
@@ -178,10 +180,36 @@ export class InstanceStyleService {
         if (instance.result_datatable_bordered) {
             this.style.setStyle('#datatable.table-bordered th, #datatable.table-bordered td', 'border', `1px solid ${instance.result_datatable_border_color}`);
             this.style.setStyle('#datatable.table-bordered thead th', 'border-bottom', `2px solid ${instance.result_datatable_border_color}`);
+            if (instance.result_datatable_bordered_radius) {
+                this.style.setStyles('.datatable-responsive.table-responsive', {
+                    'border-top-left-radius': '0.3rem',
+                    'border-top-right-radius': '0.3rem',
+                });
+            }
         } else {
             this.style.setStyle('#datatable.table th, #datatable.table td', 'border-top', `1px solid ${instance.result_datatable_border_color}`);
             this.style.setStyle('#datatable.table thead th', 'border-bottom', `2px solid ${instance.result_datatable_border_color}`);
         }
+
+        this.style.setStyles('#datatable.table thead tr', {
+            'background-color': instance.result_datatable_header_background_color,
+            'color': instance.result_datatable_header_text_color
+        });
+        this.style.setStyles('#datatable.table thead tr .column-sorted', {
+            'color': instance.result_datatable_sorted_active_color,
+            'background-color': instance.result_datatable_header_background_color
+        });
+        this.style.setStyle('#datatable.table thead tr .click-to-sort .unsorted', 'color', instance.result_datatable_sorted_color);
+        this.style.setStyles('#datatable.table thead tr .click-to-sort .on-hover', {
+            'color': instance.result_datatable_sorted_color,
+            'background-color': instance.result_datatable_header_background_color
+        });
+        this.style.setStyles('#datatable.table tbody tr', {
+            'background-color': instance.result_datatable_rows_background_color,
+            'color': instance.result_datatable_rows_text_color
+        });
+        this.style.setStyle('#datatable.table tbody tr.datum-selected-in-plot', 'background-color', instance.result_datatable_rows_selected_color);
+        this.style.setStyle('#datatable.table tbody tr .checked', 'color', instance.result_datatable_rows_selected_color);
         
         this.style.setStyle('#datatable.table a', 'color', instance.result_datatable_link_color);
         this.style.setStyle('#datatable.table a', 'text-decoration', 'none');
diff --git a/client/src/app/instance/instance.component.spec.ts b/client/src/app/instance/instance.component.spec.ts
index fba62ed8..33dc7866 100644
--- a/client/src/app/instance/instance.component.spec.ts
+++ b/client/src/app/instance/instance.component.spec.ts
@@ -90,6 +90,8 @@ describe('[Instance] InstanceComponent', () => {
             design_background_color: 'darker green',
             design_text_color: '#212529',
             design_font_family: 'Roboto, sans-serif',
+            design_link_color: '#007BFF',
+            design_link_hover_color: '#0056B3',
             design_logo: '/path/to/logo',
             design_logo_href: null,
             design_favicon: '/path/to/favicon',
@@ -146,6 +148,7 @@ describe('[Instance] InstanceComponent', () => {
             result_datatable_actions_btn_hover_color: '#0069D9',
             result_datatable_actions_btn_text_color: '#FFFFFF',
             result_datatable_bordered: true,
+            result_datatable_bordered_radius: false,
             result_datatable_border_color: '#DEE2E6',
             result_datatable_header_background_color: '#FFFFFF',
             result_datatable_header_text_color: '#000000',
@@ -156,7 +159,6 @@ describe('[Instance] InstanceComponent', () => {
             result_datatable_link_color: '#007BFF',
             result_datatable_link_hover_color: '#0056B3',
             result_datatable_rows_selected_color: '#7AC29A',
-            result_datatable_pagination_text_color: '#212529',
             samp_enabled: true,
             back_to_portal: true,
             user_menu_enabled: true,
diff --git a/client/src/app/instance/search/components/result/datatable.component.html b/client/src/app/instance/search/components/result/datatable.component.html
index 04eadde0..c3a26ca6 100644
--- a/client/src/app/instance/search/components/result/datatable.component.html
+++ b/client/src/app/instance/search/components/result/datatable.component.html
@@ -1,14 +1,14 @@
 <app-spinner *ngIf="dataIsLoading"></app-spinner>
 
-<div class="table-responsive" *ngIf="dataIsLoaded">
+<div class="datatable-responsive table-responsive" *ngIf="dataIsLoaded">
     <table id="datatable" class="table table-hover" [ngClass]="{'table-bordered': instance.result_datatable_bordered}" aria-describedby="List of results">
         <thead>
-            <tr [ngStyle]="{ 'background-color': instance.result_datatable_header_background_color, 'color': instance.result_datatable_header_text_color }">
+            <tr>
                 <th *ngIf="dataset.datatable_selectable_rows" scope="col" class="select">#</th>
                 <th *ngFor="let attribute of getOutputList()" scope="col" draggable="true" class="datatable-title">
                     <app-attribute-label [label]="attribute.label" [description]="attribute.description"></app-attribute-label>
                     &nbsp;
-                    <span *ngIf="attribute.id === sortedCol && attribute.order_by" class="pl-2" class="clickable" (click)="sort(attribute.id)" [ngStyle]="{ 'color': instance.result_datatable_sorted_active_color, 'background-color': instance.result_datatable_header_background_color }">
+                    <span *ngIf="attribute.id === sortedCol && attribute.order_by" class="pl-2 clickable column-sorted" (click)="sort(attribute.id)">
                         <span [ngClass]="{'active': sortedOrder === 'a', 'inactive': sortedOrder === 'd'}">
                             <span class="fas fa-fw fa-sort-amount-down-alt"></span>
                         </span>
@@ -16,11 +16,11 @@
                             <span class="fas fa-fw fa-sort-amount-up"></span>
                         </span>
                     </span>
-                    <span *ngIf="attribute.id !== sortedCol && attribute.order_by" class="pl-2" class="clickable" (click)="sort(attribute.id)">
-                        <span class="unsorted" [ngStyle]="{ 'color': instance.result_datatable_sorted_color }">
+                    <span *ngIf="attribute.id !== sortedCol && attribute.order_by" class="pl-2 clickable click-to-sort" (click)="sort(attribute.id)">
+                        <span class="unsorted">
                             <span class="fas fa-fw fa-arrows-alt-v"></span>
                         </span>
-                        <span class="on-hover" [ngStyle]="{ 'color': instance.result_datatable_sorted_color, 'background-color': instance.result_datatable_header_background_color }">
+                        <span class="on-hover">
                             <span class="fas fa-fw fa-sort-amount-down-alt"></span>
                         </span>
                     </span>
@@ -28,7 +28,7 @@
             </tr>
         </thead>
         <tbody>
-            <tr *ngFor="let datum of data" [ngStyle]="{'background-color': datumSelectedInPlot(datum) ? instance.result_datatable_rows_selected_color : instance.result_datatable_rows_background_color, 'color': instance.result_datatable_rows_text_color }">
+            <tr *ngFor="let datum of data" [ngClass]="{'datum-selected-in-plot': datumSelectedInPlot(datum)}">
                 <td *ngIf="dataset.datatable_selectable_rows" class="data-selected align-middle"
                     (click)="toggleSelection(datum)">
                     <button class="btn btn-block text-left p-0 m-0">
@@ -36,7 +36,7 @@
                             <span class="far fa-square fa-lg text-secondary"></span>
                         </span>
                         <span *ngIf="isSelected(datum)">
-                            <span class="fas fa-check-square fa-lg" [ngStyle]="{ 'color': instance.result_datatable_rows_selected_color }"></span>
+                            <span class="fas fa-check-square fa-lg checked"></span>
                         </span>
                     </button>
                 </td>
diff --git a/client/src/app/instance/search/components/result/datatable.component.scss b/client/src/app/instance/search/components/result/datatable.component.scss
index 57929e93..e93df406 100644
--- a/client/src/app/instance/search/components/result/datatable.component.scss
+++ b/client/src/app/instance/search/components/result/datatable.component.scss
@@ -17,11 +17,11 @@ table th:not(.select) {
 }
 
 .over-left {
-    border-left: 3px dotted #666;
+    border-left: 3px dotted #666 !important;
 }
 
 .over-right {
-    border-right: 3px dotted #666;
+    border-right: 3px dotted #666 !important;
 }
 
 .data-selected {
diff --git a/client/src/app/instance/store/effects/search-multiple.effects.spec.ts b/client/src/app/instance/store/effects/search-multiple.effects.spec.ts
index e3d66344..ae33ddc9 100644
--- a/client/src/app/instance/store/effects/search-multiple.effects.spec.ts
+++ b/client/src/app/instance/store/effects/search-multiple.effects.spec.ts
@@ -145,6 +145,8 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     design_background_color: 'darker green',
                     design_text_color: '#212529',
                     design_font_family: 'Roboto, sans-serif',
+                    design_link_color: '#007BFF',
+                    design_link_hover_color: '#0056B3',
                     design_logo: 'path/to/logo',
                     design_logo_href: null,
                     design_favicon: 'path/to/favicon',
@@ -201,6 +203,7 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     result_datatable_actions_btn_hover_color: '#0069D9',
                     result_datatable_actions_btn_text_color: '#FFFFFF',
                     result_datatable_bordered: true,
+                    result_datatable_bordered_radius: false,
                     result_datatable_border_color: '#DEE2E6',
                     result_datatable_header_background_color: '#FFFFFF',
                     result_datatable_header_text_color: '#000000',
@@ -211,7 +214,6 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     result_datatable_link_color: '#007BFF',
                     result_datatable_link_hover_color: '#0056B3',
                     result_datatable_rows_selected_color: '#7AC29A',
-                    result_datatable_pagination_text_color: '#212529',
                     samp_enabled: true,
                     back_to_portal: true,
                     user_menu_enabled: true,
@@ -290,6 +292,8 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     design_background_color: 'darker green',
                     design_text_color: '#212529',
                     design_font_family: 'Roboto, sans-serif',
+                    design_link_color: '#007BFF',
+                    design_link_hover_color: '#0056B3',
                     design_logo: 'path/to/logo',
                     design_logo_href: null,
                     design_favicon: 'path/to/favicon',
@@ -346,6 +350,7 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     result_datatable_actions_btn_hover_color: '#0069D9',
                     result_datatable_actions_btn_text_color: '#FFFFFF',
                     result_datatable_bordered: true,
+                    result_datatable_bordered_radius: false,
                     result_datatable_border_color: '#DEE2E6',
                     result_datatable_header_background_color: '#FFFFFF',
                     result_datatable_header_text_color: '#000000',
@@ -356,7 +361,6 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     result_datatable_link_color: '#007BFF',
                     result_datatable_link_hover_color: '#0056B3',
                     result_datatable_rows_selected_color: '#7AC29A',
-                    result_datatable_pagination_text_color: '#212529',
                     samp_enabled: true,
                     back_to_portal: true,
                     user_menu_enabled: true,
diff --git a/client/src/app/metamodel/models/instance.model.ts b/client/src/app/metamodel/models/instance.model.ts
index 1fe2d57e..e0f089c0 100644
--- a/client/src/app/metamodel/models/instance.model.ts
+++ b/client/src/app/metamodel/models/instance.model.ts
@@ -30,6 +30,8 @@ export interface Instance {
     design_background_color: string;
     design_text_color: string;
     design_font_family: string;
+    design_link_color: string;
+    design_link_hover_color: string;
     design_logo: string;
     design_logo_href: string;
     design_favicon: string;
@@ -86,6 +88,7 @@ export interface Instance {
     result_datatable_actions_btn_hover_color: string;
     result_datatable_actions_btn_text_color: string;
     result_datatable_bordered: boolean;
+    result_datatable_bordered_radius: boolean;
     result_datatable_border_color: string;
     result_datatable_header_background_color: string;
     result_datatable_header_text_color: string;
diff --git a/client/src/test-data.ts b/client/src/test-data.ts
index 0eda3461..4d7c1a58 100644
--- a/client/src/test-data.ts
+++ b/client/src/test-data.ts
@@ -60,6 +60,8 @@ export const INSTANCE_LIST: Instance[] = [
         design_background_color: 'darker green',
         design_text_color: '#212529',
         design_font_family: 'Roboto, sans-serif',
+        design_link_color: '#007BFF',
+        design_link_hover_color: '#0056B3',
         design_logo: 'path/to/logo',
         design_logo_href: null,
         design_favicon: 'path/to/favicon',
@@ -116,6 +118,7 @@ export const INSTANCE_LIST: Instance[] = [
         result_datatable_actions_btn_hover_color: '#0069D9',
         result_datatable_actions_btn_text_color: '#FFFFFF',
         result_datatable_bordered: true,
+        result_datatable_bordered_radius: false,
         result_datatable_border_color: '#DEE2E6',
         result_datatable_header_background_color: '#FFFFFF',
         result_datatable_header_text_color: '#000000',
@@ -126,7 +129,6 @@ export const INSTANCE_LIST: Instance[] = [
         result_datatable_link_color: '#007BFF',
         result_datatable_link_hover_color: '#0056B3',
         result_datatable_rows_selected_color: '#7AC29A',
-        result_datatable_pagination_text_color: '#212529',
         samp_enabled: true,
         back_to_portal: true,
         user_menu_enabled: true,
@@ -156,6 +158,8 @@ export const INSTANCE_LIST: Instance[] = [
         design_background_color: 'darker green',
         design_text_color: '#212529',
         design_font_family: 'Roboto, sans-serif',
+        design_link_color: '#007BFF',
+        design_link_hover_color: '#0056B3',
         design_logo: 'path/to/logo',
         design_logo_href: null,
         design_favicon: 'path/to/favicon',
@@ -212,6 +216,7 @@ export const INSTANCE_LIST: Instance[] = [
         result_datatable_actions_btn_hover_color: '#0069D9',
         result_datatable_actions_btn_text_color: '#FFFFFF',
         result_datatable_bordered: true,
+        result_datatable_bordered_radius: false,
         result_datatable_border_color: '#DEE2E6',
         result_datatable_header_background_color: '#FFFFFF',
         result_datatable_header_text_color: '#000000',
@@ -222,7 +227,6 @@ export const INSTANCE_LIST: Instance[] = [
         result_datatable_link_color: '#007BFF',
         result_datatable_link_hover_color: '#0056B3',
         result_datatable_rows_selected_color: '#7AC29A',
-        result_datatable_pagination_text_color: '#212529',
         samp_enabled: true,
         back_to_portal: true,
         user_menu_enabled: true,
@@ -254,6 +258,8 @@ export const INSTANCE: Instance = {
     design_background_color: 'darker green',
     design_text_color: '#212529',
     design_font_family: 'Roboto, sans-serif',
+    design_link_color: '#007BFF',
+    design_link_hover_color: '#0056B3',
     design_logo: '/path/to/logo',
     design_logo_href: null,
     design_favicon: '/path/to/favicon',
@@ -310,6 +316,7 @@ export const INSTANCE: Instance = {
     result_datatable_actions_btn_hover_color: '#0069D9',
     result_datatable_actions_btn_text_color: '#FFFFFF',
     result_datatable_bordered: true,
+    result_datatable_bordered_radius: false,
     result_datatable_border_color: '#DEE2E6',
     result_datatable_header_background_color: '#FFFFFF',
     result_datatable_header_text_color: '#000000',
@@ -320,7 +327,6 @@ export const INSTANCE: Instance = {
     result_datatable_link_color: '#007BFF',
     result_datatable_link_hover_color: '#0056B3',
     result_datatable_rows_selected_color: '#7AC29A',
-    result_datatable_pagination_text_color: '#212529',
     samp_enabled: true,
     back_to_portal: true,
     user_menu_enabled: true,
diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh
index fddad6b1..8ea46295 100644
--- a/conf-dev/create-db.sh
+++ b/conf-dev/create-db.sh
@@ -8,7 +8,7 @@ set -e
 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","description":"Instance for the test","scientific_manager":"M. Durand","instrument":"Multiple","wavelength_domain":"Visible imaging / Spectroscopy","display":10,"data_path":"\/DEFAULT","files_path":"\/INSTANCE_FILES","public":true,"portal_logo":"","portal_color":"#7AC29A","design_background_color":"#FFFFFF","design_text_color":"#212529","design_font_family":"Roboto, sans-serif","design_logo":"/logo.png","design_logo_href":null,"design_favicon":"/favicon.ico","navbar_background_color":"#F8F9FA","navbar_border_bottom_color":"#DEE2E6","navbar_color_href":"#000000","navbar_font_family":"Roboto, sans-serif","navbar_sign_in_btn_color":"#28A745","navbar_user_btn_color":"#7AC29A","footer_background_color":"#F8F9FA","footer_border_top_color":"#DEE2E6","footer_text_color":"#000000","footer_logos":[{"href":"http:\/\/lam.fr","title":"Laboratoire d'\''Astrophysique de Marseille","file":"\/logo_lam_s.png","display":20},{"href":"http:\/\/www.univ-amu.fr","title":"Aix*Marseille Universit\u00e9","file":"\/logo_amu_s.png","display":30},{"href":"http:\/\/anis.lam.fr","title":"AstroNomical Information System","file":"\/cesam_anis40.png","display":50},{"href":"http:\/\/cesam.lam.fr","title":"Centre de donn\u00e9es Astrophysique de Marseille","file":"\/logo_cesam_s.png","display":10},{"href":"http:\/\/www.insu.cnrs.fr","title":"Institut National des Sciences de l'\''Univers","file":"\/logo_insu_s.png","display":40}],"family_border_color":"#DFDFDF","family_header_background_color":"#F7F7F7","family_title_color":"#007BFF","family_title_bold":false,"family_background_color":"#FFFFFF","family_text_color":"#212529","progress_bar_title":"Dataset search","progress_bar_title_color":"#000000","progress_bar_subtitle":"Select a dataset, add criteria, select output columns and display the result.","progress_bar_subtitle_color":"#6C757D","progress_bar_step_dataset_title":"Dataset selection","progress_bar_step_criteria_title":"Search criteria","progress_bar_step_output_title":"Output columns","progress_bar_step_result_title":"Result table","progress_bar_color":"#E9ECEF","progress_bar_active_color":"#7AC29A","progress_bar_circle_color":"#FFFFFF","progress_bar_circle_icon_color":"#CCCCCC","progress_bar_circle_icon_active_color":"#FFFFFF","progress_bar_text_color":"#91B2BF","search_next_btn_color":"#007BFF","search_next_btn_hover_color":"#007BFF","search_next_btn_hover_text_color":"#FFFFFF","search_back_btn_color":"#6C757D","search_back_btn_hover_color":"#6C757D","search_back_btn_hover_text_color":"#FFFFFF","dataset_select_btn_color":"#6C757D","dataset_select_btn_hover_color":"#6C757D","dataset_select_btn_hover_text_color":"#FFFFFF","dataset_selected_icon_color":"#28A745","search_info_background_color":"#E9ECEF","search_info_text_color":"#000000","search_info_help_enabled":true,"search_criterion_background_color":"#7AC29A","search_criterion_text_color":"#000000","result_download_btn_color":"#007BFF","result_download_btn_hover_color":"#0069D9","result_download_btn_text_color":"#FFFFFF","output_columns_selected_color":"#7AC29A","result_datatable_actions_btn_color":"#007BFF","result_datatable_actions_btn_hover_color":"#0069D9","result_datatable_actions_btn_text_color":"#FFFFFF","result_datatable_bordered":true,"result_datatable_border_color":"#DEE2E6","result_datatable_header_background_color":"#FFFFFF","result_datatable_header_text_color":"#000000","result_datatable_rows_background_color":"#FFFFFF","result_datatable_rows_text_color":"#000000","result_datatable_sorted_color":"#C5C5C5","result_datatable_sorted_active_color":"#000000","result_datatable_link_color":"#007BFF","result_datatable_link_hover_color":"#0056B3","result_datatable_rows_selected_color":"#7AC29A","samp_enabled":true,"back_to_portal":true,"user_menu_enabled":true,"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_allowed":false,"documentation_label":"Documentation"}' --header 'Content-Type: application/json' -X POST http://localhost/instance
+curl -d '{"name":"default","label":"Default instance","description":"Instance for the test","scientific_manager":"M. Durand","instrument":"Multiple","wavelength_domain":"Visible imaging / Spectroscopy","display":10,"data_path":"\/DEFAULT","files_path":"\/INSTANCE_FILES","public":true,"portal_logo":"","portal_color":"#7AC29A","design_background_color":"#FFFFFF","design_text_color":"#212529","design_font_family":"Roboto, sans-serif","design_link_color":"#007BFF","design_link_hover_color":"#0056B3","design_logo":"/logo.png","design_logo_href":null,"design_favicon":"/favicon.ico","navbar_background_color":"#F8F9FA","navbar_border_bottom_color":"#DEE2E6","navbar_color_href":"#000000","navbar_font_family":"Roboto, sans-serif","navbar_sign_in_btn_color":"#28A745","navbar_user_btn_color":"#7AC29A","footer_background_color":"#F8F9FA","footer_border_top_color":"#DEE2E6","footer_text_color":"#000000","footer_logos":[{"href":"http:\/\/lam.fr","title":"Laboratoire d'\''Astrophysique de Marseille","file":"\/logo_lam_s.png","display":20},{"href":"http:\/\/www.univ-amu.fr","title":"Aix*Marseille Universit\u00e9","file":"\/logo_amu_s.png","display":30},{"href":"http:\/\/anis.lam.fr","title":"AstroNomical Information System","file":"\/cesam_anis40.png","display":50},{"href":"http:\/\/cesam.lam.fr","title":"Centre de donn\u00e9es Astrophysique de Marseille","file":"\/logo_cesam_s.png","display":10},{"href":"http:\/\/www.insu.cnrs.fr","title":"Institut National des Sciences de l'\''Univers","file":"\/logo_insu_s.png","display":40}],"family_border_color":"#DFDFDF","family_header_background_color":"#F7F7F7","family_title_color":"#007BFF","family_title_bold":false,"family_background_color":"#FFFFFF","family_text_color":"#212529","progress_bar_title":"Dataset search","progress_bar_title_color":"#000000","progress_bar_subtitle":"Select a dataset, add criteria, select output columns and display the result.","progress_bar_subtitle_color":"#6C757D","progress_bar_step_dataset_title":"Dataset selection","progress_bar_step_criteria_title":"Search criteria","progress_bar_step_output_title":"Output columns","progress_bar_step_result_title":"Result table","progress_bar_color":"#E9ECEF","progress_bar_active_color":"#7AC29A","progress_bar_circle_color":"#FFFFFF","progress_bar_circle_icon_color":"#CCCCCC","progress_bar_circle_icon_active_color":"#FFFFFF","progress_bar_text_color":"#91B2BF","search_next_btn_color":"#007BFF","search_next_btn_hover_color":"#007BFF","search_next_btn_hover_text_color":"#FFFFFF","search_back_btn_color":"#6C757D","search_back_btn_hover_color":"#6C757D","search_back_btn_hover_text_color":"#FFFFFF","dataset_select_btn_color":"#6C757D","dataset_select_btn_hover_color":"#6C757D","dataset_select_btn_hover_text_color":"#FFFFFF","dataset_selected_icon_color":"#28A745","search_info_background_color":"#E9ECEF","search_info_text_color":"#000000","search_info_help_enabled":true,"search_criterion_background_color":"#7AC29A","search_criterion_text_color":"#000000","result_download_btn_color":"#007BFF","result_download_btn_hover_color":"#0069D9","result_download_btn_text_color":"#FFFFFF","output_columns_selected_color":"#7AC29A","result_datatable_actions_btn_color":"#007BFF","result_datatable_actions_btn_hover_color":"#0069D9","result_datatable_actions_btn_text_color":"#FFFFFF","result_datatable_bordered":true,"result_datatable_bordered_radius":false,"result_datatable_border_color":"#DEE2E6","result_datatable_header_background_color":"#FFFFFF","result_datatable_header_text_color":"#000000","result_datatable_rows_background_color":"#FFFFFF","result_datatable_rows_text_color":"#000000","result_datatable_sorted_color":"#C5C5C5","result_datatable_sorted_active_color":"#000000","result_datatable_link_color":"#007BFF","result_datatable_link_hover_color":"#0056B3","result_datatable_rows_selected_color":"#7AC29A","samp_enabled":true,"back_to_portal":true,"user_menu_enabled":true,"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_allowed":false,"documentation_label":"Documentation"}' --header 'Content-Type: application/json' -X POST http://localhost/instance
 
 # Add dataset families
 curl -d '{"label":"Default dataset family","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/instance/default/dataset-family
diff --git a/server/doctrine-proxy/__CG__AppEntityInstance.php b/server/doctrine-proxy/__CG__AppEntityInstance.php
index 4e9a62ba..8f28e31f 100644
--- a/server/doctrine-proxy/__CG__AppEntityInstance.php
+++ b/server/doctrine-proxy/__CG__AppEntityInstance.php
@@ -67,10 +67,10 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
     public function __sleep()
     {
         if ($this->__isInitialized__) {
-            return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'portalColor', 'designBackgroundColor', 'designTextColor', 'designFontFamily', 'designLogo', 'designLogoHref', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'navbarFontFamily', 'navbarSignInBtnColor', 'navbarUserBtnColor', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'footerLogos', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyBackgroundColor', 'familyTextColor', 'progressBarTitle', 'progressBarTitleColor', 'progressBarSubtitle', 'progressBarSubtitleColor', 'progressBarStepDatasetTitle', 'progressBarStepCriteriaTitle', 'progressBarStepOutputTitle', 'progressBarStepResultTitle', 'progressBarColor', 'progressBarActiveColor', 'progressBarCircleColor', 'progressBarCircleIconColor', 'progressBarCircleIconActiveColor', 'progressBarTextColor', 'searchNextBtnColor', 'searchNextBtnHoverColor', 'searchNextBtnHoverTextColor', 'searchBackBtnColor', 'searchBackBtnHoverColor', 'searchBackBtnHoverTextColor', 'searchInfoBackgroundColor', 'searchInfoTextColor', 'searchInfoHelpEnabled', 'datasetSelectBtnColor', 'datasetSelectBtnHoverColor', 'datasetSelectBtnHoverTextColor', 'datasetSelectedIconColor', 'searchCriterionBackgroundColor', 'searchCriterionTextColor', 'outputColumnsSelectedColor', 'resultDownloadBtnColor', 'resultDownloadBtnHoverColor', 'resultDownloadBtnTextColor', 'resultDatatableActionsBtnColor', 'resultDatatableActionsBtnHoverColor', 'resultDatatableActionsBtnTextColor', 'resultDatatableBordered', 'resultDatatableBorderColor', 'resultDatatableHeaderBackgroundColor', 'resultDatatableHeaderTextColor', 'resultDatatableRowsBackgroundColor', 'resultDatatableRowsTextColor', 'resultDatatableSortedColor', 'resultDatatableSortedActiveColor', 'resultDatatableLinkColor', 'resultDatatableLinkHoverColor', 'resultDatatableRowsSelectedColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
+            return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'portalColor', 'designBackgroundColor', 'designTextColor', 'designFontFamily', 'designLinkColor', 'designLinkHoverColor', 'designLogo', 'designLogoHref', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'navbarFontFamily', 'navbarSignInBtnColor', 'navbarUserBtnColor', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'footerLogos', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyBackgroundColor', 'familyTextColor', 'progressBarTitle', 'progressBarTitleColor', 'progressBarSubtitle', 'progressBarSubtitleColor', 'progressBarStepDatasetTitle', 'progressBarStepCriteriaTitle', 'progressBarStepOutputTitle', 'progressBarStepResultTitle', 'progressBarColor', 'progressBarActiveColor', 'progressBarCircleColor', 'progressBarCircleIconColor', 'progressBarCircleIconActiveColor', 'progressBarTextColor', 'searchNextBtnColor', 'searchNextBtnHoverColor', 'searchNextBtnHoverTextColor', 'searchBackBtnColor', 'searchBackBtnHoverColor', 'searchBackBtnHoverTextColor', 'searchInfoBackgroundColor', 'searchInfoTextColor', 'searchInfoHelpEnabled', 'datasetSelectBtnColor', 'datasetSelectBtnHoverColor', 'datasetSelectBtnHoverTextColor', 'datasetSelectedIconColor', 'searchCriterionBackgroundColor', 'searchCriterionTextColor', 'outputColumnsSelectedColor', 'resultDownloadBtnColor', 'resultDownloadBtnHoverColor', 'resultDownloadBtnTextColor', 'resultDatatableActionsBtnColor', 'resultDatatableActionsBtnHoverColor', 'resultDatatableActionsBtnTextColor', 'resultDatatableBordered', 'resultDatatableBorderedRadius', 'resultDatatableBorderColor', 'resultDatatableHeaderBackgroundColor', 'resultDatatableHeaderTextColor', 'resultDatatableRowsBackgroundColor', 'resultDatatableRowsTextColor', 'resultDatatableSortedColor', 'resultDatatableSortedActiveColor', 'resultDatatableLinkColor', 'resultDatatableLinkHoverColor', 'resultDatatableRowsSelectedColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
         }
 
-        return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'portalColor', 'designBackgroundColor', 'designTextColor', 'designFontFamily', 'designLogo', 'designLogoHref', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'navbarFontFamily', 'navbarSignInBtnColor', 'navbarUserBtnColor', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'footerLogos', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyBackgroundColor', 'familyTextColor', 'progressBarTitle', 'progressBarTitleColor', 'progressBarSubtitle', 'progressBarSubtitleColor', 'progressBarStepDatasetTitle', 'progressBarStepCriteriaTitle', 'progressBarStepOutputTitle', 'progressBarStepResultTitle', 'progressBarColor', 'progressBarActiveColor', 'progressBarCircleColor', 'progressBarCircleIconColor', 'progressBarCircleIconActiveColor', 'progressBarTextColor', 'searchNextBtnColor', 'searchNextBtnHoverColor', 'searchNextBtnHoverTextColor', 'searchBackBtnColor', 'searchBackBtnHoverColor', 'searchBackBtnHoverTextColor', 'searchInfoBackgroundColor', 'searchInfoTextColor', 'searchInfoHelpEnabled', 'datasetSelectBtnColor', 'datasetSelectBtnHoverColor', 'datasetSelectBtnHoverTextColor', 'datasetSelectedIconColor', 'searchCriterionBackgroundColor', 'searchCriterionTextColor', 'outputColumnsSelectedColor', 'resultDownloadBtnColor', 'resultDownloadBtnHoverColor', 'resultDownloadBtnTextColor', 'resultDatatableActionsBtnColor', 'resultDatatableActionsBtnHoverColor', 'resultDatatableActionsBtnTextColor', 'resultDatatableBordered', 'resultDatatableBorderColor', 'resultDatatableHeaderBackgroundColor', 'resultDatatableHeaderTextColor', 'resultDatatableRowsBackgroundColor', 'resultDatatableRowsTextColor', 'resultDatatableSortedColor', 'resultDatatableSortedActiveColor', 'resultDatatableLinkColor', 'resultDatatableLinkHoverColor', 'resultDatatableRowsSelectedColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
+        return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'portalColor', 'designBackgroundColor', 'designTextColor', 'designFontFamily', 'designLinkColor', 'designLinkHoverColor', 'designLogo', 'designLogoHref', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'navbarFontFamily', 'navbarSignInBtnColor', 'navbarUserBtnColor', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'footerLogos', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyBackgroundColor', 'familyTextColor', 'progressBarTitle', 'progressBarTitleColor', 'progressBarSubtitle', 'progressBarSubtitleColor', 'progressBarStepDatasetTitle', 'progressBarStepCriteriaTitle', 'progressBarStepOutputTitle', 'progressBarStepResultTitle', 'progressBarColor', 'progressBarActiveColor', 'progressBarCircleColor', 'progressBarCircleIconColor', 'progressBarCircleIconActiveColor', 'progressBarTextColor', 'searchNextBtnColor', 'searchNextBtnHoverColor', 'searchNextBtnHoverTextColor', 'searchBackBtnColor', 'searchBackBtnHoverColor', 'searchBackBtnHoverTextColor', 'searchInfoBackgroundColor', 'searchInfoTextColor', 'searchInfoHelpEnabled', 'datasetSelectBtnColor', 'datasetSelectBtnHoverColor', 'datasetSelectBtnHoverTextColor', 'datasetSelectedIconColor', 'searchCriterionBackgroundColor', 'searchCriterionTextColor', 'outputColumnsSelectedColor', 'resultDownloadBtnColor', 'resultDownloadBtnHoverColor', 'resultDownloadBtnTextColor', 'resultDatatableActionsBtnColor', 'resultDatatableActionsBtnHoverColor', 'resultDatatableActionsBtnTextColor', 'resultDatatableBordered', 'resultDatatableBorderedRadius', 'resultDatatableBorderColor', 'resultDatatableHeaderBackgroundColor', 'resultDatatableHeaderTextColor', 'resultDatatableRowsBackgroundColor', 'resultDatatableRowsTextColor', 'resultDatatableSortedColor', 'resultDatatableSortedActiveColor', 'resultDatatableLinkColor', 'resultDatatableLinkHoverColor', 'resultDatatableRowsSelectedColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
     }
 
     /**
@@ -500,6 +500,50 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
         return parent::setDesignFontFamily($designFontFamily);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function getDesignLinkColor()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDesignLinkColor', []);
+
+        return parent::getDesignLinkColor();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setDesignLinkColor($designLinkColor)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDesignLinkColor', [$designLinkColor]);
+
+        return parent::setDesignLinkColor($designLinkColor);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getDesignLinkHoverColor()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDesignLinkHoverColor', []);
+
+        return parent::getDesignLinkHoverColor();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setDesignLinkHoverColor($designLinkHoverColor)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDesignLinkHoverColor', [$designLinkHoverColor]);
+
+        return parent::setDesignLinkHoverColor($designLinkHoverColor);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -1732,6 +1776,28 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
         return parent::setResultDatatableBordered($resultDatatableBordered);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function getResultDatatableBorderedRadius()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getResultDatatableBorderedRadius', []);
+
+        return parent::getResultDatatableBorderedRadius();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setResultDatatableBorderedRadius($resultDatatableBorderedRadius)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setResultDatatableBorderedRadius', [$resultDatatableBorderedRadius]);
+
+        return parent::setResultDatatableBorderedRadius($resultDatatableBorderedRadius);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/server/src/Action/InstanceAction.php b/server/src/Action/InstanceAction.php
index 79e8235b..fadf521d 100644
--- a/server/src/Action/InstanceAction.php
+++ b/server/src/Action/InstanceAction.php
@@ -78,6 +78,8 @@ final class InstanceAction extends AbstractAction
                 'design_background_color',
                 'design_text_color',
                 'design_font_family',
+                'design_link_color',
+                'design_link_hover_color',
                 'design_logo',
                 'design_logo_href',
                 'design_favicon',
@@ -134,6 +136,7 @@ final class InstanceAction extends AbstractAction
                 'result_datatable_actions_btn_hover_color',
                 'result_datatable_actions_btn_text_color',
                 'result_datatable_bordered',
+                'result_datatable_bordered_radius',
                 'result_datatable_border_color',
                 'result_datatable_header_background_color',
                 'result_datatable_header_text_color',
@@ -203,6 +206,8 @@ final class InstanceAction extends AbstractAction
         $instance->setDesignBackgroundColor($parsedBody['design_background_color']);
         $instance->setDesignTextColor($parsedBody['design_text_color']);
         $instance->setDesignFontFamily($parsedBody['design_font_family']);
+        $instance->setDesignLinkColor($parsedBody['design_link_color']);
+        $instance->setDesignLinkHoverColor($parsedBody['design_link_hover_color']);
         $instance->setDesignLogo($parsedBody['design_logo']);
         $instance->setDesignLogoHref($parsedBody['design_logo_href']);
         $instance->setDesignFavicon($parsedBody['design_favicon']);
@@ -259,6 +264,7 @@ final class InstanceAction extends AbstractAction
         $instance->setResultDatatableActionsBtnHoverColor($parsedBody['result_datatable_actions_btn_hover_color']);
         $instance->setResultDatatableActionsBtnTextColor($parsedBody['result_datatable_actions_btn_text_color']);
         $instance->setResultDatatableBordered($parsedBody['result_datatable_bordered']);
+        $instance->setResultDatatableBorderedRadius($parsedBody['result_datatable_bordered_radius']);
         $instance->setResultDatatableBorderColor($parsedBody['result_datatable_border_color']);
         $instance->setResultDatatableHeaderBackgroundColor($parsedBody['result_datatable_header_background_color']);
         $instance->setResultDatatableHeaderTextColor($parsedBody['result_datatable_header_text_color']);
diff --git a/server/src/Action/InstanceListAction.php b/server/src/Action/InstanceListAction.php
index 1f993cd3..ccb7e42f 100644
--- a/server/src/Action/InstanceListAction.php
+++ b/server/src/Action/InstanceListAction.php
@@ -78,6 +78,8 @@ final class InstanceListAction extends AbstractAction
                 'design_background_color',
                 'design_text_color',
                 'design_font_family',
+                'design_link_color',
+                'design_link_hover_color',
                 'design_logo',
                 'design_logo_href',
                 'design_favicon',
@@ -134,6 +136,7 @@ final class InstanceListAction extends AbstractAction
                 'result_datatable_actions_btn_hover_color',
                 'result_datatable_actions_btn_text_color',
                 'result_datatable_bordered',
+                'result_datatable_bordered_radius',
                 'result_datatable_border_color',
                 'result_datatable_header_background_color',
                 'result_datatable_header_text_color',
@@ -197,6 +200,8 @@ final class InstanceListAction extends AbstractAction
         $instance->setDesignBackgroundColor($parsedBody['design_background_color']);
         $instance->setDesignTextColor($parsedBody['design_text_color']);
         $instance->setDesignFontFamily($parsedBody['design_font_family']);
+        $instance->setDesignLinkColor($parsedBody['design_link_color']);
+        $instance->setDesignLinkHoverColor($parsedBody['design_link_hover_color']);
         $instance->setDesignLogo($parsedBody['design_logo']);
         $instance->setDesignLogoHref($parsedBody['design_logo_href']);
         $instance->setDesignFavicon($parsedBody['design_favicon']);
@@ -253,6 +258,7 @@ final class InstanceListAction extends AbstractAction
         $instance->setResultDatatableActionsBtnHoverColor($parsedBody['result_datatable_actions_btn_hover_color']);
         $instance->setResultDatatableActionsBtnTextColor($parsedBody['result_datatable_actions_btn_text_color']);
         $instance->setResultDatatableBordered($parsedBody['result_datatable_bordered']);
+        $instance->setResultDatatableBorderedRadius($parsedBody['result_datatable_bordered_radius']);
         $instance->setResultDatatableBorderColor($parsedBody['result_datatable_border_color']);
         $instance->setResultDatatableHeaderBackgroundColor($parsedBody['result_datatable_header_background_color']);
         $instance->setResultDatatableHeaderTextColor($parsedBody['result_datatable_header_text_color']);
diff --git a/server/src/Entity/Instance.php b/server/src/Entity/Instance.php
index 2956b603..369b9472 100644
--- a/server/src/Entity/Instance.php
+++ b/server/src/Entity/Instance.php
@@ -129,6 +129,20 @@ class Instance implements \JsonSerializable
      */
     protected $designFontFamily;
 
+    /**
+     * @var string
+     *
+     * @Column(type="string", name="design_link_color", nullable=false, options={"default" : "#007BFF"})
+     */
+    protected $designLinkColor;
+
+    /**
+     * @var string
+     *
+     * @Column(type="string", name="design_link_hover_color", nullable=false, options={"default" : "#0056B3"})
+     */
+    protected $designLinkHoverColor;
+
     /**
      * @var string
      *
@@ -545,6 +559,13 @@ class Instance implements \JsonSerializable
      */
     protected $resultDatatableBordered;
 
+    /**
+     * @var bool
+     *
+     * @Column(type="boolean", name="result_datatable_bordered_radius", nullable=false, options={"default" : false})
+     */
+    protected $resultDatatableBorderedRadius;
+
     /**
      * @var string
      *
@@ -858,6 +879,26 @@ class Instance implements \JsonSerializable
         $this->designFontFamily = $designFontFamily;
     }
 
+    public function getDesignLinkColor()
+    {
+        return $this->designLinkColor;
+    }
+
+    public function setDesignLinkColor($designLinkColor)
+    {
+        $this->designLinkColor = $designLinkColor;
+    }
+
+    public function getDesignLinkHoverColor()
+    {
+        return $this->designLinkHoverColor;
+    }
+
+    public function setDesignLinkHoverColor($designLinkHoverColor)
+    {
+        $this->designLinkHoverColor = $designLinkHoverColor;
+    }
+
     public function getDesignLogo()
     {
         return $this->designLogo;
@@ -1418,6 +1459,16 @@ class Instance implements \JsonSerializable
         $this->resultDatatableBordered = $resultDatatableBordered;
     }
 
+    public function getResultDatatableBorderedRadius()
+    {
+        return $this->resultDatatableBorderedRadius;
+    }
+
+    public function setResultDatatableBorderedRadius($resultDatatableBorderedRadius)
+    {
+        $this->resultDatatableBorderedRadius = $resultDatatableBorderedRadius;
+    }
+
     public function getResultDatatableBorderColor()
     {
         return $this->resultDatatableBorderColor;
@@ -1650,6 +1701,8 @@ class Instance implements \JsonSerializable
             'design_background_color' => $this->getDesignBackgroundColor(),
             'design_text_color' => $this->getDesignTextColor(),
             'design_font_family' => $this->getDesignFontFamily(),
+            'design_link_color' => $this->getDesignLinkColor(),
+            'design_link_hover_color' => $this->getDesignLinkHoverColor(),
             'design_logo' => $this->getDesignLogo(),
             'design_logo_href' => $this->getDesignLogoHref(),
             'design_favicon' => $this->getDesignFavicon(),
@@ -1706,6 +1759,7 @@ class Instance implements \JsonSerializable
             'result_datatable_actions_btn_hover_color' => $this->getResultDatatableActionsBtnHoverColor(),
             'result_datatable_actions_btn_text_color' => $this->getResultDatatableActionsBtnTextColor(),
             'result_datatable_bordered' => $this->getResultDatatableBordered(),
+            'result_datatable_bordered_radius' => $this->getResultDatatableBorderedRadius(),
             'result_datatable_border_color' => $this->getResultDatatableBorderColor(),
             'result_datatable_header_background_color' => $this->getResultDatatableHeaderBackgroundColor(),
             'result_datatable_header_text_color' => $this->getResultDatatableHeaderTextColor(),
diff --git a/server/tests/Action/InstanceActionTest.php b/server/tests/Action/InstanceActionTest.php
index 35af3e72..66941e6d 100644
--- a/server/tests/Action/InstanceActionTest.php
+++ b/server/tests/Action/InstanceActionTest.php
@@ -92,6 +92,8 @@ final class InstanceActionTest extends TestCase
             'design_background_color' => '#FFFFFF',
             'design_text_color' => '#212529',
             'design_font_family' => 'Roboto, sans-serif',
+            'design_link_color' => '#007BFF',
+            'design_link_hover_color' => '#0056B3',
             'design_logo' => 'logo.png',
             'design_logo_href' => null,
             'design_favicon' => 'favicon.ico',
@@ -148,6 +150,7 @@ final class InstanceActionTest extends TestCase
             'result_datatable_actions_btn_hover_color' => '#0069D9',
             'result_datatable_actions_btn_text_color' => '#FFFFFF',
             'result_datatable_bordered' => true,
+            'result_datatable_bordered_radius' => false,
             'result_datatable_border_color' => '#DEE2E6',
             'result_datatable_header_background_color' => '#FFFFFF',
             'result_datatable_header_text_color' => '#000000',
diff --git a/server/tests/Action/InstanceListActionTest.php b/server/tests/Action/InstanceListActionTest.php
index 6b427cc0..1549b4a2 100644
--- a/server/tests/Action/InstanceListActionTest.php
+++ b/server/tests/Action/InstanceListActionTest.php
@@ -76,6 +76,8 @@ final class InstanceListActionTest extends TestCase
             'design_background_color' => '#FFFFFF',
             'design_text_color' => '#212529',
             'design_font_family' => 'Roboto, sans-serif',
+            'design_link_color' => '#007BFF',
+            'design_link_hover_color' => '#0056B3',
             'design_logo' => 'logo.png',
             'design_logo_href' => null,
             'design_favicon' => 'favicon.ico',
@@ -132,6 +134,7 @@ final class InstanceListActionTest extends TestCase
             'result_datatable_actions_btn_hover_color' => '#0069D9',
             'result_datatable_actions_btn_text_color' => '#FFFFFF',
             'result_datatable_bordered' => true,
+            'result_datatable_bordered_radius' => false,
             'result_datatable_border_color' => '#DEE2E6',
             'result_datatable_header_background_color' => '#FFFFFF',
             'result_datatable_header_text_color' => '#000000',
-- 
GitLab