From dab7c1363cb8d8cf5389f904175db5098eddf3fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr>
Date: Tue, 7 Sep 2021 19:00:42 +0200
Subject: [PATCH] Fixed bug: order by display (metamodel)

---
 .../criteria-by-family.component.html         |  2 +-
 .../criteria/criteria-by-family.component.ts  | 10 ----------
 .../output/output-by-category.component.html  |  2 +-
 .../output/output-by-category.component.ts    | 10 ----------
 .../output/output-by-family.component.ts      |  1 -
 .../search/components/summary.component.ts    |  8 ++------
 .../search/containers/criteria.component.html |  4 ++--
 .../search/containers/dataset.component.html  |  2 +-
 .../search/containers/output.component.html   |  4 ++--
 .../search/containers/result.component.html   |  2 +-
 client/src/app/instance/search/pipes/index.ts | 16 ++++++++++++++++
 .../search/pipes/sort-by-criteria-display.ts  | 19 +++++++++++++++++++
 .../search/pipes/sort-by-output-display.ts    | 19 +++++++++++++++++++
 .../src/app/instance/search/search.module.ts  |  4 +++-
 .../datatable/datatable.component.ts          |  3 +--
 .../components/object-data.component.ts       | 10 +++-------
 .../detail/containers/detail.component.html   |  4 ++--
 .../shared-search/detail/detail.module.ts     |  4 +++-
 .../shared-search/detail/pipes/index.ts       |  5 +++++
 .../detail/pipes/sort-by-detail-display.ts    | 19 +++++++++++++++++++
 .../reducers/criteria-family.reducer.ts       |  5 ++++-
 .../reducers/dataset-family.reducer.ts        |  5 ++++-
 .../app/metamodel/reducers/dataset.reducer.ts |  2 +-
 .../reducers/output-category.reducer.ts       |  5 ++++-
 .../reducers/output-family.reducer.ts         |  5 ++++-
 .../reducers/select-option.reducer.ts         |  5 ++++-
 26 files changed, 121 insertions(+), 54 deletions(-)
 create mode 100644 client/src/app/instance/search/pipes/index.ts
 create mode 100644 client/src/app/instance/search/pipes/sort-by-criteria-display.ts
 create mode 100644 client/src/app/instance/search/pipes/sort-by-output-display.ts
 create mode 100644 client/src/app/instance/shared-search/detail/pipes/index.ts
 create mode 100644 client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts

diff --git a/client/src/app/instance/search/components/criteria/criteria-by-family.component.html b/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
index dd9b10ec..08f385e6 100644
--- a/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
+++ b/client/src/app/instance/search/components/criteria/criteria-by-family.component.html
@@ -1,4 +1,4 @@
-<div *ngFor="let attribute of getAttributeListSortedByDisplay()">
+<div *ngFor="let attribute of attributeList">
     <div [ngSwitch]="attribute.search_type">
         <div *ngSwitchCase="'field'">
             <app-field class="criteria" 
diff --git a/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts b/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
index ed525e72..b249169a 100644
--- a/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
+++ b/client/src/app/instance/search/components/criteria/criteria-by-family.component.ts
@@ -29,16 +29,6 @@ export class CriteriaByFamilyComponent {
 
     advancedForm = false;
 
-    /**
-     * Returns attribute list sorted by criteria display.
-     *
-     * @return Attribute[]
-     */
-    getAttributeListSortedByDisplay(): Attribute[] {
-        return this.attributeList
-            .sort((a, b) => a.criteria_display - b.criteria_display);
-    }
-
     /**
      * Returns options for the given attribute ID.
      *
diff --git a/client/src/app/instance/search/components/output/output-by-category.component.html b/client/src/app/instance/search/components/output/output-by-category.component.html
index 7888b9a0..9ffecf61 100644
--- a/client/src/app/instance/search/components/output/output-by-category.component.html
+++ b/client/src/app/instance/search/components/output/output-by-category.component.html
@@ -14,7 +14,7 @@
     </div>
 </div>
 <div class="selectbox p-0">
-    <div *ngFor="let attribute of getAttributeListSortedByDisplay()">
+    <div *ngFor="let attribute of attributeList">
         <div *ngIf="isSelected(attribute.id)">
             <button class="btn btn-block text-left py-1 m-0 rounded-0" (click)="toggleSelection(attribute.id)">
                 <span class="fas fa-fw fa-check-square" [ngStyle]="{ 'color': designColor }"></span> {{ attribute.form_label }}
diff --git a/client/src/app/instance/search/components/output/output-by-category.component.ts b/client/src/app/instance/search/components/output/output-by-category.component.ts
index 3cfd66d0..830f1495 100644
--- a/client/src/app/instance/search/components/output/output-by-category.component.ts
+++ b/client/src/app/instance/search/components/output/output-by-category.component.ts
@@ -30,16 +30,6 @@ export class OutputByCategoryComponent {
     @Input() isAllUnselected: boolean;
     @Output() change: EventEmitter<number[]> = new EventEmitter();
 
-    /**
-     * Returns output list sorted by output display.
-     *
-     * @return Attribute[]
-     */
-    getAttributeListSortedByDisplay(): Attribute[] {
-        return this.attributeList
-            .sort((a, b) => a.output_display - b.output_display);
-    }
-
     /**
      * Checks if the given output ID is selected.
      *
diff --git a/client/src/app/instance/search/components/output/output-by-family.component.ts b/client/src/app/instance/search/components/output/output-by-family.component.ts
index 23ff1ee0..331058f4 100644
--- a/client/src/app/instance/search/components/output/output-by-family.component.ts
+++ b/client/src/app/instance/search/components/output/output-by-family.component.ts
@@ -89,7 +89,6 @@ export class OutputByFamilyComponent {
         this.change.emit(
             this.attributeList
                 .filter(a => clonedOutputList.indexOf(a.id) > -1)
-                .sort((a, b) => a.output_display - b.output_display)
                 .map(a => a.id)
         );
     }
diff --git a/client/src/app/instance/search/components/summary.component.ts b/client/src/app/instance/search/components/summary.component.ts
index 3e76c627..10170ce9 100644
--- a/client/src/app/instance/search/components/summary.component.ts
+++ b/client/src/app/instance/search/components/summary.component.ts
@@ -88,9 +88,7 @@ export class SummaryComponent {
      * @return Category[]
      */
     getCategoryByFamilySortedByDisplay(idFamily: number): OutputCategory[] {
-        return this.outputCategoryList
-            .filter(category => category.id_output_family === idFamily)
-            //.sort(sortByDisplay);
+        return this.outputCategoryList.filter(category => category.id_output_family === idFamily)
     }
 
     /**
@@ -102,8 +100,6 @@ export class SummaryComponent {
      */
     getSelectedOutputByCategory(idCategory: number): Attribute[] {
         const outputListByCategory = this.attributeList.filter(attribute => attribute.id_output_category === idCategory);
-        return outputListByCategory
-            .filter(attribute => this.outputList.includes(attribute.id))
-            .sort((a, b) => a.output_display - b.output_display);
+        return outputListByCategory.filter(attribute => this.outputList.includes(attribute.id));
     }
 }
diff --git a/client/src/app/instance/search/containers/criteria.component.html b/client/src/app/instance/search/containers/criteria.component.html
index 8ff2d1d9..d21e4e51 100644
--- a/client/src/app/instance/search/containers/criteria.component.html
+++ b/client/src/app/instance/search/containers/criteria.component.html
@@ -19,7 +19,7 @@
             (retrieveCoordinates)="retrieveCoordinates($event)">
         </app-cone-search-tab>
         <app-criteria-tabs 
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByCriteriaDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [criteriaList]="criteriaList | async"
             (addCriterion)="addCriterion($event)" 
@@ -32,7 +32,7 @@
             [currentStep]="currentStep | async"
             [datasetSelected]="datasetSelected | async"
             [datasetList]="datasetList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/dataset.component.html b/client/src/app/instance/search/containers/dataset.component.html
index 77107988..3b0dd7da 100644
--- a/client/src/app/instance/search/containers/dataset.component.html
+++ b/client/src/app/instance/search/containers/dataset.component.html
@@ -30,7 +30,7 @@
                 [currentStep]="currentStep | async"
                 [datasetSelected]="datasetSelected | async"
                 [datasetList]="datasetList | async"
-                [attributeList]="attributeList | async"
+                [attributeList]="attributeList | async | sortByOutputDisplay"
                 [criteriaFamilyList]="criteriaFamilyList | async"
                 [outputFamilyList]="outputFamilyList | async"
                 [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/output.component.html b/client/src/app/instance/search/containers/output.component.html
index db66948c..8133aeca 100644
--- a/client/src/app/instance/search/containers/output.component.html
+++ b/client/src/app/instance/search/containers/output.component.html
@@ -8,7 +8,7 @@
     && (outputCategoryListIsLoaded | async)" class="row mt-4">
     <div class="col-12 col-md-8 col-lg-9">
         <app-output-tabs 
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [outputFamilyList]="outputFamilyList | async" 
             [outputCategoryList]="outputCategoryList | async"
             [outputList]="outputList | async"
@@ -22,7 +22,7 @@
             [currentStep]="currentStep | async"
             [datasetSelected]="datasetSelected | async"
             [datasetList]="datasetList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByOutputDisplay"
             [criteriaFamilyList]="criteriaFamilyList | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html
index a350d6ef..acf54c83 100644
--- a/client/src/app/instance/search/containers/result.component.html
+++ b/client/src/app/instance/search/containers/result.component.html
@@ -38,7 +38,7 @@
             <app-reminder
                 [datasetSelected]="datasetSelected | async"
                 [datasetList]="datasetList | async"
-                [attributeList]="attributeList | async"
+                [attributeList]="attributeList | async | sortByOutputDisplay"
                 [criteriaFamilyList]="criteriaFamilyList | async"
                 [outputFamilyList]="outputFamilyList | async"
                 [outputCategoryList]="outputCategoryList | async"
diff --git a/client/src/app/instance/search/pipes/index.ts b/client/src/app/instance/search/pipes/index.ts
new file mode 100644
index 00000000..dd9b7577
--- /dev/null
+++ b/client/src/app/instance/search/pipes/index.ts
@@ -0,0 +1,16 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { SortByCriteriaDisplay } from './sort-by-criteria-display';
+import { SortByOutputDisplay } from './sort-by-output-display';
+
+export const searchPipes = [
+    SortByCriteriaDisplay,
+    SortByOutputDisplay
+];
\ No newline at end of file
diff --git a/client/src/app/instance/search/pipes/sort-by-criteria-display.ts b/client/src/app/instance/search/pipes/sort-by-criteria-display.ts
new file mode 100644
index 00000000..c6c8bd4a
--- /dev/null
+++ b/client/src/app/instance/search/pipes/sort-by-criteria-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByCriteriaDisplay'})
+export class SortByCriteriaDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.criteria_display - b.criteria_display);
+    }
+}
diff --git a/client/src/app/instance/search/pipes/sort-by-output-display.ts b/client/src/app/instance/search/pipes/sort-by-output-display.ts
new file mode 100644
index 00000000..cfd30802
--- /dev/null
+++ b/client/src/app/instance/search/pipes/sort-by-output-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByOutputDisplay'})
+export class SortByOutputDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.output_display - b.output_display);
+    }
+}
diff --git a/client/src/app/instance/search/search.module.ts b/client/src/app/instance/search/search.module.ts
index 63eef0ff..0d25c4b7 100644
--- a/client/src/app/instance/search/search.module.ts
+++ b/client/src/app/instance/search/search.module.ts
@@ -13,6 +13,7 @@ import { SharedModule } from 'src/app/shared/shared.module';
 import { SharedSearchModule } from '../shared-search/shared-search.module';
 import { SearchRoutingModule, routedComponents } from './search-routing.module';
 import { dummiesComponents } from './components';
+import { searchPipes } from './pipes';
 
 @NgModule({
     imports: [
@@ -22,7 +23,8 @@ import { dummiesComponents } from './components';
     ],
     declarations: [
         routedComponents,
-        dummiesComponents
+        dummiesComponents,
+        searchPipes
     ]
 })
 export class SearchModule { }
diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
index 83c362b7..91b185a5 100644
--- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
+++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
@@ -86,8 +86,7 @@ export class DatatableComponent implements OnInit {
      */
     getOutputList(): Attribute[] {
         return this.attributeList
-            .filter(a => this.outputList.includes(a.id))
-            .sort((a, b) => a.output_display - b.output_display);
+            .filter(a => this.outputList.includes(a.id));
     }
 
     /**
diff --git a/client/src/app/instance/shared-search/detail/components/object-data.component.ts b/client/src/app/instance/shared-search/detail/components/object-data.component.ts
index 16de054f..943dab66 100644
--- a/client/src/app/instance/shared-search/detail/components/object-data.component.ts
+++ b/client/src/app/instance/shared-search/detail/components/object-data.component.ts
@@ -40,8 +40,7 @@ export class ObjectDataComponent {
      */
     getCategoryByFamilySortedByDisplay(idFamily: number): OutputCategory[] {
         return this.outputCategoryList
-            .filter(category => category.id_output_family === idFamily)
-            //.sort(sortByDisplay);
+            .filter(category => category.id_output_family === idFamily);
     }
 
     /**
@@ -54,8 +53,7 @@ export class ObjectDataComponent {
     getAttributesVisibleByCategory(idCategory: number): Attribute[] {
         return this.attributeList
             .filter(a => a.detail)
-            .filter(a => a.id_output_category === idCategory)
-            .sort((a, b) => a.display_detail - b.display_detail);
+            .filter(a => a.id_output_category === idCategory);
     }
 
     /**
@@ -64,9 +62,7 @@ export class ObjectDataComponent {
      * @return Attribute[]
      */
     getAttributesVisible(): Attribute[] {
-        return this.attributeList
-            .filter(a => a.detail)
-            .sort((a, b) => a.display_detail - b.display_detail);
+        return this.attributeList.filter(a => a.detail);
     }
 
     /**
diff --git a/client/src/app/instance/shared-search/detail/containers/detail.component.html b/client/src/app/instance/shared-search/detail/containers/detail.component.html
index 2899b8cf..a17e8166 100644
--- a/client/src/app/instance/shared-search/detail/containers/detail.component.html
+++ b/client/src/app/instance/shared-search/detail/containers/detail.component.html
@@ -16,7 +16,7 @@
             [datasetSelected]="datasetSelected | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByDetailDisplay"
             [object]="object | async"
             [spectraCSV]="spectraCSV | async"
             [spectraIsLoading]="spectraIsLoading | async"
@@ -27,7 +27,7 @@
             [datasetSelected]="datasetSelected | async"
             [outputFamilyList]="outputFamilyList | async"
             [outputCategoryList]="outputCategoryList | async"
-            [attributeList]="attributeList | async"
+            [attributeList]="attributeList | async | sortByDetailDisplay"
             [object]="object | async">
         </app-default-object>
     </div>
diff --git a/client/src/app/instance/shared-search/detail/detail.module.ts b/client/src/app/instance/shared-search/detail/detail.module.ts
index d9d97c4f..af987eed 100644
--- a/client/src/app/instance/shared-search/detail/detail.module.ts
+++ b/client/src/app/instance/shared-search/detail/detail.module.ts
@@ -12,6 +12,7 @@ import { NgModule } from '@angular/core';
 import { SharedModule } from 'src/app/shared/shared.module';
 import { DetailComponent } from './containers/detail.component';
 import { dummiesComponents } from './components';
+import { detailPipes } from './pipes';
 
 @NgModule({
     imports: [
@@ -19,7 +20,8 @@ import { dummiesComponents } from './components';
     ],
     declarations: [
         DetailComponent,
-        dummiesComponents
+        dummiesComponents,
+        detailPipes
     ]
 })
 export class DetailModule { }
diff --git a/client/src/app/instance/shared-search/detail/pipes/index.ts b/client/src/app/instance/shared-search/detail/pipes/index.ts
new file mode 100644
index 00000000..a42bb612
--- /dev/null
+++ b/client/src/app/instance/shared-search/detail/pipes/index.ts
@@ -0,0 +1,5 @@
+import { SortByDetailDisplay } from './sort-by-detail-display';
+
+export const detailPipes = [
+    SortByDetailDisplay
+];
diff --git a/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts b/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts
new file mode 100644
index 00000000..dd17a7ca
--- /dev/null
+++ b/client/src/app/instance/shared-search/detail/pipes/sort-by-detail-display.ts
@@ -0,0 +1,19 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+import { Attribute } from 'src/app/metamodel/models';
+
+@Pipe({name: 'sortByDetailDisplay'})
+export class SortByDetailDisplay implements PipeTransform {
+    transform(attributeList: Attribute[]): Attribute[] {
+        return [...attributeList].sort((a: Attribute, b: Attribute) => a.display_detail - b.display_detail);
+    }
+}
diff --git a/client/src/app/metamodel/reducers/criteria-family.reducer.ts b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
index 6e153b79..76ccaae4 100644
--- a/client/src/app/metamodel/reducers/criteria-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<CriteriaFamily> {
     criteriaFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<CriteriaFamily> = createEntityAdapter<CriteriaFamily>();
+export const adapter: EntityAdapter<CriteriaFamily> = createEntityAdapter<CriteriaFamily>({
+    selectId: (criteriaFamily: CriteriaFamily) => criteriaFamily.id,
+    sortComparer: (a: CriteriaFamily, b: CriteriaFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     criteriaFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/dataset-family.reducer.ts b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
index dcbb9101..923f8837 100644
--- a/client/src/app/metamodel/reducers/dataset-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<DatasetFamily> {
     datasetFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<DatasetFamily> = createEntityAdapter<DatasetFamily>();
+export const adapter: EntityAdapter<DatasetFamily> = createEntityAdapter<DatasetFamily>({
+    selectId: (datasetFamily: DatasetFamily) => datasetFamily.id,
+    sortComparer: (a: DatasetFamily, b: DatasetFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     datasetFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/dataset.reducer.ts b/client/src/app/metamodel/reducers/dataset.reducer.ts
index 82ba8ca5..becb9691 100644
--- a/client/src/app/metamodel/reducers/dataset.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset.reducer.ts
@@ -20,7 +20,7 @@ export interface State extends EntityState<Dataset> {
 
 export const adapter: EntityAdapter<Dataset> = createEntityAdapter<Dataset>({
     selectId: (dataset: Dataset) => dataset.name,
-    sortComparer: (a: Dataset, b: Dataset) => a.name.localeCompare(b.name)
+    sortComparer: (a: Dataset, b: Dataset) => a.display - b.display
 });
 
 export const initialState: State = adapter.getInitialState({
diff --git a/client/src/app/metamodel/reducers/output-category.reducer.ts b/client/src/app/metamodel/reducers/output-category.reducer.ts
index 11ef8e7b..ddbed474 100644
--- a/client/src/app/metamodel/reducers/output-category.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-category.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<OutputCategory> {
     outputCategoryListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<OutputCategory> = createEntityAdapter<OutputCategory>();
+export const adapter: EntityAdapter<OutputCategory> = createEntityAdapter<OutputCategory>({
+    selectId: (outputCategory: OutputCategory) => outputCategory.id,
+    sortComparer: (a: OutputCategory, b: OutputCategory) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     outputCategoryListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/output-family.reducer.ts b/client/src/app/metamodel/reducers/output-family.reducer.ts
index ab02f1e9..cb7c5f6b 100644
--- a/client/src/app/metamodel/reducers/output-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-family.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<OutputFamily> {
     outputFamilyListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<OutputFamily> = createEntityAdapter<OutputFamily>();
+export const adapter: EntityAdapter<OutputFamily> = createEntityAdapter<OutputFamily>({
+    selectId: (outputFamily: OutputFamily) => outputFamily.id,
+    sortComparer: (a: OutputFamily, b: OutputFamily) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     outputFamilyListIsLoading: false,
diff --git a/client/src/app/metamodel/reducers/select-option.reducer.ts b/client/src/app/metamodel/reducers/select-option.reducer.ts
index 13690b29..f63ffbd5 100644
--- a/client/src/app/metamodel/reducers/select-option.reducer.ts
+++ b/client/src/app/metamodel/reducers/select-option.reducer.ts
@@ -18,7 +18,10 @@ export interface State extends EntityState<SelectOption> {
     selectOptionListIsLoaded: boolean;
 }
 
-export const adapter: EntityAdapter<SelectOption> = createEntityAdapter<SelectOption>();
+export const adapter: EntityAdapter<SelectOption> = createEntityAdapter<SelectOption>({
+    selectId: (selectOption: SelectOption) => selectOption.id,
+    sortComparer: (a: SelectOption, b: SelectOption) => a.display - b.display
+});
 
 export const initialState: State = adapter.getInitialState({
     selectOptionListIsLoading: false,
-- 
GitLab