From cab5e52a739de4f1d7e4148bdea7923e3959730b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr>
Date: Fri, 23 Sep 2022 18:03:24 +0200
Subject: [PATCH] #74 => done

---
 client/src/app/admin/admin.component.ts       |  8 ++-
 .../components/instance-form.component.html   | 40 +++++++++--
 .../components/instance-form.component.ts     |  3 +
 .../app/core/containers/app.component.html    |  2 +-
 .../app/instance/instance.component.spec.ts   |  3 +
 client/src/app/instance/instance.component.ts |  6 ++
 .../components/progress-bar.component.spec.ts |  6 ++
 .../effects/search-multiple.effects.spec.ts   |  6 ++
 .../app/metamodel/models/instance.model.ts    |  3 +
 .../containers/portal-home.component.ts       |  8 ++-
 client/src/test-data.ts                       |  9 +++
 .../__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 +
 17 files changed, 227 insertions(+), 9 deletions(-)

diff --git a/client/src/app/admin/admin.component.ts b/client/src/app/admin/admin.component.ts
index 875b1663..beb1b7cf 100644
--- a/client/src/app/admin/admin.component.ts
+++ b/client/src/app/admin/admin.component.ts
@@ -17,6 +17,7 @@ import * as authActions from 'src/app/auth/auth.actions';
 import * as authSelector from 'src/app/auth/auth.selector';
 import * as databaseActions from 'src/app/metamodel/actions/database.actions';
 import { AppConfigService } from 'src/app/app-config.service';
+import { StyleService } from 'src/app/shared/services/style.service';
 
 @Component({
     selector: 'app-admin',
@@ -34,7 +35,7 @@ export class AdminComponent implements OnInit {
     public isAuthenticated: Observable<boolean>;
     public userProfile: Observable<UserProfile>;
 
-    constructor(private store: Store<{ }>, private config: AppConfigService) {
+    constructor(private store: Store<{ }>, private config: AppConfigService, private style: StyleService) {
         this.isAuthenticated = store.select(authSelector.selectIsAuthenticated);
         this.userProfile = store.select(authSelector.selectUserProfile);
     }
@@ -43,6 +44,11 @@ export class AdminComponent implements OnInit {
         this.favIcon.href = 'favicon.ico';
         this.body.style.backgroundColor = 'white';
         Promise.resolve(null).then(() => this.store.dispatch(databaseActions.loadDatabaseList()));
+        this.style.setStyles('.footer', {
+            'background-color': '#F8F9FA',
+            'border-top': 'none',
+            'color': 'black',
+        });
     }
 
     getAuthenticationEnabled() {
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 ad91ad5d..c9a4f4b8 100644
--- a/client/src/app/admin/instance/components/instance-form.component.html
+++ b/client/src/app/admin/instance/components/instance-form.component.html
@@ -59,7 +59,7 @@
                 <label class="custom-control-label" for="private"><span class="fas fa-lock"></span> Private</label>
             </div>
         </accordion-group>
-        <accordion-group heading="Design general" [isOpen]="true">
+        <accordion-group heading="Design general" [isOpen]="false">
             <app-path-select-form-control
                 [form]="form"
                 [disabled]="isFilesPathEmpty()"
@@ -103,7 +103,7 @@
                 (loadDirectory)="onChangeFileSelect($event)">
             </app-path-select-form-control>
         </accordion-group>
-        <accordion-group heading="Design navbar" [isOpen]="true">
+        <accordion-group heading="Design navbar" [isOpen]="false">
             <app-path-select-form-control
                 [form]="form"
                 [disabled]="isFilesPathEmpty()"
@@ -146,7 +146,39 @@
                 </div>
             </div>
         </accordion-group>
-        <accordion-group heading="Design family" [isOpen]="true">
+        <accordion-group heading="Design footer" [isOpen]="false">
+            <div class="form-row">
+                <div class="form-group col-md-6">
+                    <label for="footer_background_color_picker">Footer background color (picker)</label>
+                    <input class="form-control" type="color" id="footer_background_color_picker" [value]="form.value.footer_background_color" formControlName="footer_background_color">
+                </div>
+                <div class="form-group col-md-6">
+                    <label for="footer_background_color_input">Footer background color (value)</label>
+                    <input type="text" class="form-control" id="footer_background_color_input" [value]="form.value.footer_background_color" formControlName="footer_background_color">
+                </div>
+            </div>
+            <div class="form-row">
+                <div class="form-group col-md-6">
+                    <label for="footer_border_top_color_picker">Footer border top color (picker)</label>
+                    <input class="form-control" type="color" id="footer_border_top_color_picker" [value]="form.value.footer_border_top_color" formControlName="footer_border_top_color">
+                </div>
+                <div class="form-group col-md-6">
+                    <label for="footer_border_top_color_input">Footer border top color (value)</label>
+                    <input type="text" class="form-control" id="footer_border_top_color_input" [value]="form.value.footer_border_top_color" formControlName="footer_border_top_color">
+                </div>
+            </div>
+            <div class="form-row">
+                <div class="form-group col-md-6">
+                    <label for="footer_text_color_picker">Footer text color (picker)</label>
+                    <input class="form-control" type="color" id="footer_text_color_picker" [value]="form.value.footer_text_color" formControlName="footer_text_color">
+                </div>
+                <div class="form-group col-md-6">
+                    <label for="footer_text_color_input">Footer text color (value)</label>
+                    <input type="text" class="form-control" id="footer_text_color_input" [value]="form.value.footer_text_color" formControlName="footer_text_color">
+                </div>
+            </div>
+        </accordion-group>
+        <accordion-group heading="Design family" [isOpen]="false">
             <div class="form-row">
                 <div class="form-group col-md-6">
                     <label for="family_border_color_picker">Family border color (picker)</label>
@@ -192,7 +224,7 @@
                 </div>
             </div>
         </accordion-group>
-        <accordion-group heading="Functionalities" [isOpen]="true">
+        <accordion-group heading="Functionalities" [isOpen]="false">
             <div class="custom-control custom-switch mb-2">
                 <input class="custom-control-input" type="checkbox" id="samp_enabled" name="samp_enabled" formControlName="samp_enabled">
                 <label class="custom-control-label" for="samp_enabled">Samp enabled</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 8402d7f0..d25d7ebf 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,9 @@ export class InstanceFormComponent implements OnInit {
         navbar_background_color: new UntypedFormControl('#F8F9FA'),
         navbar_border_bottom_color: new UntypedFormControl('#DEE2E6'),
         navbar_color_href: new UntypedFormControl('#000000'),
+        footer_background_color: new UntypedFormControl('#F8F9FA'),
+        footer_border_top_color: new UntypedFormControl('#DEE2E6'),
+        footer_text_color: new UntypedFormControl('#000000'),
         family_border_color: new UntypedFormControl('#DFDFDF'),
         family_header_background_color: new UntypedFormControl('#F7F7F7'),
         family_title_color: new UntypedFormControl('#007BFF'),
diff --git a/client/src/app/core/containers/app.component.html b/client/src/app/core/containers/app.component.html
index 860bf595..3cd4c5e0 100644
--- a/client/src/app/core/containers/app.component.html
+++ b/client/src/app/core/containers/app.component.html
@@ -3,7 +3,7 @@
     <span class="sr-only">Loading...</span>
 </div>
 <router-outlet *ngIf="(instanceListIsLoaded | async) && (instanceGroupListIsLoaded | async)"></router-outlet>
-<footer class="footer mt-auto bg-light">
+<footer class="footer mt-auto">
     <div class="container my-3">
         <div class="row justify-content-center font-weight-bold mb-1">
             &copy; ANIS 2014 - {{ year }}
diff --git a/client/src/app/instance/instance.component.spec.ts b/client/src/app/instance/instance.component.spec.ts
index 8aadba40..64face0c 100644
--- a/client/src/app/instance/instance.component.spec.ts
+++ b/client/src/app/instance/instance.component.spec.ts
@@ -93,6 +93,9 @@ describe('[Instance] InstanceComponent', () => {
             navbar_background_color: '#F8F9FA',
             navbar_border_bottom_color: '#DEE2E6',
             navbar_color_href: '#000000',
+            footer_background_color: '#F8F9FA',
+            footer_border_top_color: '#DEE2E6',
+            footer_text_color: '#000000',
             family_border_color: '#DFDFDF',
             family_header_background_color: '#F7F7F7',
             family_title_color: '#007BFF',
diff --git a/client/src/app/instance/instance.component.ts b/client/src/app/instance/instance.component.ts
index 90fb704a..49c7c518 100644
--- a/client/src/app/instance/instance.component.ts
+++ b/client/src/app/instance/instance.component.ts
@@ -105,6 +105,12 @@ export class InstanceComponent implements OnInit, OnDestroy {
                         'border': 'none'
                     });
 
+                    this.style.setStyles('.footer', {
+                        'background-color': instance.footer_background_color,
+                        'border-top': `1px solid ${instance.footer_border_top_color}`,
+                        'color': instance.footer_text_color,
+                    });
+
                     this.style.setStyle('.panel.card.custom-accordion', 'border-color', instance.family_border_color);
                     this.style.setStyle('.custom-accordion .panel-heading', 'background-color', instance.family_header_background_color);
                     this.style.setStyle('.custom-accordion .panel-heading .btn-link', 'color', instance.family_title_color);
diff --git a/client/src/app/instance/search/components/progress-bar.component.spec.ts b/client/src/app/instance/search/components/progress-bar.component.spec.ts
index e12050d3..03c3eed8 100644
--- a/client/src/app/instance/search/components/progress-bar.component.spec.ts
+++ b/client/src/app/instance/search/components/progress-bar.component.spec.ts
@@ -66,6 +66,9 @@ describe('[Instance][Search][Component] ProgressBarComponent', () => {
             navbar_background_color: '#F8F9FA',
             navbar_border_bottom_color: '#DEE2E6',
             navbar_color_href: '#000000',
+            footer_background_color: '#F8F9FA',
+            footer_border_top_color: '#DEE2E6',
+            footer_text_color: '#000000',
             family_border_color: '#DFDFDF',
             family_header_background_color: '#F7F7F7',
             family_title_color: '#007BFF',
@@ -109,6 +112,9 @@ describe('[Instance][Search][Component] ProgressBarComponent', () => {
             navbar_background_color: '#F8F9FA',
             navbar_border_bottom_color: '#DEE2E6',
             navbar_color_href: '#000000',
+            footer_background_color: '#F8F9FA',
+            footer_border_top_color: '#DEE2E6',
+            footer_text_color: '#000000',
             family_border_color: '#DFDFDF',
             family_header_background_color: '#F7F7F7',
             family_title_color: '#007BFF',
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 165b72cc..caed7faf 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
@@ -148,6 +148,9 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     navbar_background_color: '#F8F9FA',
                     navbar_border_bottom_color: '#DEE2E6',
                     navbar_color_href: '#000000',
+                    footer_background_color: '#F8F9FA',
+                    footer_border_top_color: '#DEE2E6',
+                    footer_text_color: '#000000',
                     family_border_color: '#DFDFDF',
                     family_header_background_color: '#F7F7F7',
                     family_title_color: '#007BFF',
@@ -234,6 +237,9 @@ describe('[Instance][Store] SearchMultipleEffects', () => {
                     navbar_background_color: '#F8F9FA',
                     navbar_border_bottom_color: '#DEE2E6',
                     navbar_color_href: '#000000',
+                    footer_background_color: '#F8F9FA',
+                    footer_border_top_color: '#DEE2E6',
+                    footer_text_color: '#000000',
                     family_border_color: '#DFDFDF',
                     family_header_background_color: '#F7F7F7',
                     family_title_color: '#007BFF',
diff --git a/client/src/app/metamodel/models/instance.model.ts b/client/src/app/metamodel/models/instance.model.ts
index de2d5f2f..c39be4e7 100644
--- a/client/src/app/metamodel/models/instance.model.ts
+++ b/client/src/app/metamodel/models/instance.model.ts
@@ -31,6 +31,9 @@ export interface Instance {
     navbar_background_color: string;
     navbar_border_bottom_color: string;
     navbar_color_href: string;
+    footer_background_color: string;
+    footer_border_top_color: string;
+    footer_text_color: string;
     family_border_color: string;
     family_header_background_color: string;
     family_title_color: string;
diff --git a/client/src/app/portal/containers/portal-home.component.ts b/client/src/app/portal/containers/portal-home.component.ts
index 7de17948..92b94a2d 100644
--- a/client/src/app/portal/containers/portal-home.component.ts
+++ b/client/src/app/portal/containers/portal-home.component.ts
@@ -19,6 +19,7 @@ import * as authSelector from 'src/app/auth/auth.selector';
 import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
 import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-group.selector';
 import { AppConfigService } from 'src/app/app-config.service';
+import { StyleService } from 'src/app/shared/services/style.service';
 
 /**
  * @class
@@ -41,7 +42,7 @@ export class PortalHomeComponent implements OnInit {
     public instanceGroupList: Observable<InstanceGroup[]>;
     public userRolesSubscription: Subscription;
 
-    constructor(private store: Store<{ }>, private config: AppConfigService) {
+    constructor(private store: Store<{ }>, private config: AppConfigService, private style: StyleService) {
         this.isAuthenticated = store.select(authSelector.selectIsAuthenticated);
         this.userProfile = store.select(authSelector.selectUserProfile);
         this.userRoles = store.select(authSelector.selectUserRoles);
@@ -52,6 +53,11 @@ export class PortalHomeComponent implements OnInit {
     ngOnInit() {
         this.favIcon.href = 'favicon.ico';
         this.body.style.backgroundColor = 'white';
+        this.style.setStyles('.footer', {
+            'background-color': '#F8F9FA',
+            'border-top': 'none',
+            'color': 'black',
+        });
     }
 
     /**
diff --git a/client/src/test-data.ts b/client/src/test-data.ts
index bfb46685..e8f4951f 100644
--- a/client/src/test-data.ts
+++ b/client/src/test-data.ts
@@ -63,6 +63,9 @@ export const INSTANCE_LIST: Instance[] = [
         navbar_background_color: '#F8F9FA',
         navbar_border_bottom_color: '#DEE2E6',
         navbar_color_href: '#000000',
+        footer_background_color: '#F8F9FA',
+        footer_border_top_color: '#DEE2E6',
+        footer_text_color: '#000000',
         family_border_color: '#DFDFDF',
         family_header_background_color: '#F7F7F7',
         family_title_color: '#007BFF',
@@ -100,6 +103,9 @@ export const INSTANCE_LIST: Instance[] = [
         navbar_background_color: '#F8F9FA',
         navbar_border_bottom_color: '#DEE2E6',
         navbar_color_href: '#000000',
+        footer_background_color: '#F8F9FA',
+        footer_border_top_color: '#DEE2E6',
+        footer_text_color: '#000000',
         family_border_color: '#DFDFDF',
         family_header_background_color: '#F7F7F7',
         family_title_color: '#007BFF',
@@ -139,6 +145,9 @@ export const INSTANCE: Instance = {
     navbar_background_color: '#F8F9FA',
     navbar_border_bottom_color: '#DEE2E6',
     navbar_color_href: '#000000',
+    footer_background_color: '#F8F9FA',
+    footer_border_top_color: '#DEE2E6',
+    footer_text_color: '#000000',
     family_border_color: '#DFDFDF',
     family_header_background_color: '#F7F7F7',
     family_title_color: '#007BFF',
diff --git a/server/doctrine-proxy/__CG__AppEntityInstance.php b/server/doctrine-proxy/__CG__AppEntityInstance.php
index ea18298b..afab6be2 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', 'designColor', 'designBackgroundColor', 'designLogo', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
+            return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'designColor', 'designBackgroundColor', 'designLogo', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
         }
 
-        return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'designColor', 'designBackgroundColor', 'designLogo', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
+        return ['__isInitialized__', 'name', 'label', 'description', 'scientificManager', 'instrument', 'wavelengthDomain', 'display', 'dataPath', 'filesPath', 'public', 'portalLogo', 'designColor', 'designBackgroundColor', 'designLogo', 'designFavicon', 'navbarBackgroundColor', 'navbarBorderBottomColor', 'navbarColorHref', 'footerBackgroundColor', 'footerBorderTopColor', 'footerTextColor', 'familyBorderColor', 'familyHeaderBackgroundColor', 'familyTitleColor', 'familyTitleBold', 'familyColor', 'sampEnabled', 'backToPortal', 'userMenuEnabled', 'searchByCriteriaAllowed', 'searchByCriteriaLabel', 'searchMultipleAllowed', 'searchMultipleLabel', 'searchMultipleAllDatasetsSelected', 'documentationAllowed', 'documentationLabel', 'datasetFamilies'];
     }
 
     /**
@@ -566,6 +566,72 @@ class Instance extends \App\Entity\Instance implements \Doctrine\ORM\Proxy\Proxy
         return parent::setNavbarColorHref($navbarColorHref);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function getFooterBackgroundColor()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getFooterBackgroundColor', []);
+
+        return parent::getFooterBackgroundColor();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setFooterBackgroundColor($footerBackgroundColor)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setFooterBackgroundColor', [$footerBackgroundColor]);
+
+        return parent::setFooterBackgroundColor($footerBackgroundColor);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getFooterBorderTopColor()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getFooterBorderTopColor', []);
+
+        return parent::getFooterBorderTopColor();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setFooterBorderTopColor($footerBorderTopColor)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setFooterBorderTopColor', [$footerBorderTopColor]);
+
+        return parent::setFooterBorderTopColor($footerBorderTopColor);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getFooterTextColor()
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getFooterTextColor', []);
+
+        return parent::getFooterTextColor();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setFooterTextColor($footerTextColor)
+    {
+
+        $this->__initializer__ && $this->__initializer__->__invoke($this, 'setFooterTextColor', [$footerTextColor]);
+
+        return parent::setFooterTextColor($footerTextColor);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/server/src/Action/InstanceAction.php b/server/src/Action/InstanceAction.php
index 52ef946e..ef904656 100644
--- a/server/src/Action/InstanceAction.php
+++ b/server/src/Action/InstanceAction.php
@@ -81,6 +81,9 @@ final class InstanceAction extends AbstractAction
                 'navbar_background_color',
                 'navbar_border_bottom_color',
                 'navbar_color_href',
+                'footer_background_color',
+                'footer_border_top_color',
+                'footer_text_color',
                 'family_border_color',
                 'family_header_background_color',
                 'family_title_color',
@@ -148,6 +151,9 @@ final class InstanceAction extends AbstractAction
         $instance->setNavbarBackgroundColor($parsedBody['navbar_background_color']);
         $instance->setNavbarBorderBottomColor($parsedBody['navbar_border_bottom_color']);
         $instance->setNavbarColorHref($parsedBody['navbar_color_href']);
+        $instance->setFooterBackgroundColor($parsedBody['footer_background_color']);
+        $instance->setFooterBorderTopColor($parsedBody['footer_border_top_color']);
+        $instance->setFooterTextColor($parsedBody['footer_text_color']);
         $instance->setFamilyBorderColor($parsedBody['family_border_color']);
         $instance->setFamilyHeaderBackgroundColor($parsedBody['family_header_background_color']);
         $instance->setFamilyTitleColor($parsedBody['family_title_color']);
diff --git a/server/src/Action/InstanceListAction.php b/server/src/Action/InstanceListAction.php
index 34f9cee5..e151e73b 100644
--- a/server/src/Action/InstanceListAction.php
+++ b/server/src/Action/InstanceListAction.php
@@ -81,6 +81,9 @@ final class InstanceListAction extends AbstractAction
                 'navbar_background_color',
                 'navbar_border_bottom_color',
                 'navbar_color_href',
+                'footer_background_color',
+                'footer_border_top_color',
+                'footer_text_color',
                 'family_border_color',
                 'family_header_background_color',
                 'family_title_color',
@@ -142,6 +145,9 @@ final class InstanceListAction extends AbstractAction
         $instance->setNavbarBackgroundColor($parsedBody['navbar_background_color']);
         $instance->setNavbarBorderBottomColor($parsedBody['navbar_border_bottom_color']);
         $instance->setNavbarColorHref($parsedBody['navbar_color_href']);
+        $instance->setFooterBackgroundColor($parsedBody['footer_background_color']);
+        $instance->setFooterBorderTopColor($parsedBody['footer_border_top_color']);
+        $instance->setFooterTextColor($parsedBody['footer_text_color']);
         $instance->setFamilyBorderColor($parsedBody['family_border_color']);
         $instance->setFamilyHeaderBackgroundColor($parsedBody['family_header_background_color']);
         $instance->setFamilyTitleColor($parsedBody['family_title_color']);
diff --git a/server/src/Entity/Instance.php b/server/src/Entity/Instance.php
index 17becc0a..f3e4a3e0 100644
--- a/server/src/Entity/Instance.php
+++ b/server/src/Entity/Instance.php
@@ -150,6 +150,27 @@ class Instance implements \JsonSerializable
      */
     protected $navbarColorHref;
 
+    /**
+     * @var string
+     *
+     * @Column(type="string", name="footer_background_color", nullable=false, options={"default" : "#F8F9FA"})
+     */
+    protected $footerBackgroundColor;
+
+    /**
+     * @var string
+     *
+     * @Column(type="string", name="footer_border_top_color", nullable=false, options={"default" : "#DEE2E6"})
+     */
+    protected $footerBorderTopColor;
+
+    /**
+     * @var string
+     *
+     * @Column(type="string", name="footer_text_color", nullable=false, options={"default" : "#000000"})
+     */
+    protected $footerTextColor;
+
     /**
      * @var string
      *
@@ -444,6 +465,36 @@ class Instance implements \JsonSerializable
         $this->navbarColorHref = $navbarColorHref;
     }
 
+    public function getFooterBackgroundColor()
+    {
+        return $this->footerBackgroundColor;
+    }
+
+    public function setFooterBackgroundColor($footerBackgroundColor)
+    {
+        $this->footerBackgroundColor = $footerBackgroundColor;
+    }
+
+    public function getFooterBorderTopColor()
+    {
+        return $this->footerBorderTopColor;
+    }
+
+    public function setFooterBorderTopColor($footerBorderTopColor)
+    {
+        $this->footerBorderTopColor = $footerBorderTopColor;
+    }
+
+    public function getFooterTextColor()
+    {
+        return $this->footerTextColor;
+    }
+
+    public function setFooterTextColor($footerTextColor)
+    {
+        $this->footerTextColor = $footerTextColor;
+    }
+
     public function getFamilyBorderColor()
     {
         return $this->familyBorderColor;
@@ -629,6 +680,9 @@ class Instance implements \JsonSerializable
             'navbar_background_color' => $this->getNavbarBackgroundColor(),
             'navbar_border_bottom_color' => $this->getNavbarBorderBottomColor(),
             'navbar_color_href' => $this->getNavbarColorHref(),
+            'footer_background_color' => $this->getFooterBackgroundColor(),
+            'footer_border_top_color' => $this->getFooterBorderTopColor(),
+            'footer_text_color' => $this->getFooterTextColor(),
             'family_border_color' => $this->getFamilyBorderColor(),
             'family_header_background_color' => $this->getFamilyHeaderBackgroundColor(),
             'family_title_color' => $this->getFamilyTitleColor(),
diff --git a/server/tests/Action/InstanceActionTest.php b/server/tests/Action/InstanceActionTest.php
index eee2914e..8e1525f1 100644
--- a/server/tests/Action/InstanceActionTest.php
+++ b/server/tests/Action/InstanceActionTest.php
@@ -95,6 +95,9 @@ final class InstanceActionTest extends TestCase
             'navbar_background_color' => '#F8F9FA',
             'navbar_border_bottom_color' => '#DEE2E6',
             'navbar_color_href' => '#000000',
+            'footer_background_color' => '#F8F9FA',
+            'footer_border_top_color' => '#DEE2E6',
+            'footer_text_color' => '#000000',
             'family_border_color' => '#DFDFDF',
             'family_header_background_color' => '#F7F7F7',
             'family_title_color' => '#007BFF',
diff --git a/server/tests/Action/InstanceListActionTest.php b/server/tests/Action/InstanceListActionTest.php
index 21a2ec5e..685e0baa 100644
--- a/server/tests/Action/InstanceListActionTest.php
+++ b/server/tests/Action/InstanceListActionTest.php
@@ -79,6 +79,9 @@ final class InstanceListActionTest extends TestCase
             'navbar_background_color' => '#F8F9FA',
             'navbar_border_bottom_color' => '#DEE2E6',
             'navbar_color_href' => '#000000',
+            'footer_background_color' => '#F8F9FA',
+            'footer_border_top_color' => '#DEE2E6',
+            'footer_text_color' => '#000000',
             'family_border_color' => '#DFDFDF',
             'family_header_background_color' => '#F7F7F7',
             'family_title_color' => '#007BFF',
-- 
GitLab