From 9d6d87a7aef53b1e4f9a1917adc9d91fb075dc16 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Wed, 27 May 2020 14:50:15 +0200
Subject: [PATCH] chore: sort modalities alphabetically chore: use constant for
 aria labels

---
 common/constants.js                           |  5 +++
 docs/releases/v2.2.2.md                       |  5 +++
 .../browsingForDatasets.prod.e2e-spec.js      | 31 ++++++++++++++-
 .../scrollDatasetContainer.prod.e2e-spec.js   | 19 +++-------
 e2e/src/util.js                               | 17 +++++++++
 mkdocs.yml                                    |  1 +
 .../databrowserModule/databrowser.module.ts   |  3 +-
 .../databrowser/databrowser.component.ts      |  5 +++
 .../databrowser/databrowser.template.html     |  5 ++-
 .../modalityPicker.component.spec.ts          | 38 +++++++++++++++++++
 .../modalityPicker.component.ts               | 15 +++++++-
 .../modalityPicker.template.html              |  2 +-
 .../searchSideNav/searchSideNav.component.ts  |  4 ++
 .../searchSideNav/searchSideNav.template.html |  2 +-
 14 files changed, 131 insertions(+), 21 deletions(-)
 create mode 100644 docs/releases/v2.2.2.md
 create mode 100644 src/ui/databrowserModule/modalityPicker/modalityPicker.component.spec.ts

diff --git a/common/constants.js b/common/constants.js
index c5f7c0567..8981be7c4 100644
--- a/common/constants.js
+++ b/common/constants.js
@@ -1,6 +1,11 @@
 (function(exports){
 
   exports.ARIA_LABELS = {
+    // dataset specific
+    TOGGLE_EXPLORE_PANEL: `Toggle explore panel`,
+    MODALITY_FILTER: `Toggle dataset modality filter`,
+    LIST_OF_DATASETS: `List of datasets`,
+
     // overlay specific
     CONTEXT_MENU: `Viewer context menu`,
 
diff --git a/docs/releases/v2.2.2.md b/docs/releases/v2.2.2.md
new file mode 100644
index 000000000..c46eed59a
--- /dev/null
+++ b/docs/releases/v2.2.2.md
@@ -0,0 +1,5 @@
+# v2.2.2
+
+## Bugfixes
+
+- Modal filters are now sorted alphabetically (#523)
\ No newline at end of file
diff --git a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js b/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js
index b5cb270a7..7850abac0 100644
--- a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js
+++ b/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js
@@ -1,4 +1,6 @@
 const { AtlasPage } = require('../util')
+const { ARIA_LABELS } = require('../../../common/constants')
+const { TOGGLE_EXPLORE_PANEL, MODALITY_FILTER } = ARIA_LABELS
 
 const templates = [
   'MNI Colin 27',
@@ -121,4 +123,31 @@ describe('> dataset previews', () => {
     const modalHasImage = await iavPage.modalHasChild('div[data-img-src]')
     expect(modalHasImage).toEqual(true)
   })
-})
\ No newline at end of file
+})
+
+describe('> modality picker', () => {
+  let iavPage
+  beforeAll(async () => {
+    iavPage = new AtlasPage()
+    await iavPage.init()
+    await iavPage.goto()
+  })
+  it('> sorted alphabetically', async () => {
+    await iavPage.selectTitleCard(templates[1])
+    await iavPage.wait(500)
+    await iavPage.waitUntilAllChunksLoaded()
+    await iavPage.click(`[aria-label="${TOGGLE_EXPLORE_PANEL}"]`)
+    await iavPage.wait(500)
+    await iavPage.clearAlerts()
+    await iavPage.click(`[aria-label="${MODALITY_FILTER}"]`)
+    await iavPage.wait(500)
+    const modalities = await iavPage.getModalities()
+    for (let i = 1; i < modalities.length; i ++) {
+      expect(
+        modalities[i].charCodeAt(0)
+      ).toBeGreaterThanOrEqual(
+        modalities[i - 1].charCodeAt(0)
+      )
+    }
+  })
+})
diff --git a/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js b/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js
index 198be8f23..0643817f7 100644
--- a/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js
+++ b/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js
@@ -1,11 +1,12 @@
 const { AtlasPage } = require('../util')
-
+const { ARIA_LABELS } = require('../../../common/constants')
 describe('> scroll dataset container', () => {
   let iavPage
 
   beforeEach(async () => {
     iavPage = new AtlasPage()
     await iavPage.init()
+
   })
 
   it('> can scroll to the end', async () => {
@@ -14,23 +15,13 @@ describe('> scroll dataset container', () => {
     await iavPage.wait(1000)
     await iavPage.waitForAsync()
 
-    const btnCssSelector = `[aria-label="Toggle explore panel"]`
-    // const btnCssSelector = `button[mat-stroked-button].m-1.flex-grow-1.overflow-hidden`
-
-    // TODO use .clickByCss method in future
-    // TODO import aria label from common/constant.js in future
-    await iavPage._browser
-      .findElement( By.css(btnCssSelector) )
-      .click()
+    await iavPage.click(`[aria-label="${ARIA_LABELS.TOGGLE_EXPLORE_PANEL}"]`)
 
     await iavPage.clearAlerts()
 
-    const scrollContainerCssSelector = '[aria-label="List of datasets"]'
-    // const scrollContainerCssSelector = 'cdk-virtual-scroll-viewport'
-
     let countdown = 100
     do {
-      await iavPage.scrollElementBy(scrollContainerCssSelector, {
+      await iavPage.scrollElementBy(`[aria-label="${ARIA_LABELS.LIST_OF_DATASETS}"]`, {
         delta: [0, 100]
       })
       await iavPage.wait(100)
@@ -39,7 +30,7 @@ describe('> scroll dataset container', () => {
 
     await iavPage.wait(500)
 
-    const val = await iavPage.getScrollStatus(scrollContainerCssSelector)
+    const val = await iavPage.getScrollStatus(`[aria-label="${ARIA_LABELS.LIST_OF_DATASETS}"]`)
     expect(val).toBeGreaterThanOrEqual(10000)
   })
 })
\ No newline at end of file
diff --git a/e2e/src/util.js b/e2e/src/util.js
index 134ca978f..a279f3e49 100644
--- a/e2e/src/util.js
+++ b/e2e/src/util.js
@@ -772,6 +772,23 @@ class WdIavPage extends WdLayoutPage{
     }
   }
 
+  _getModalityListView(){
+    return this._browser
+      .findElement( By.tagName('modality-picker') )
+      .findElements( By.tagName('mat-checkbox') )
+  }
+
+  async getModalities(){
+    const els = await this._getModalityListView()
+    const returnArr = []
+    for (const el of els) {
+      returnArr.push(
+        await el.getText()
+      )
+    }
+    return returnArr
+  }
+
   _getSingleDatasetListView(){
     return this._browser
       .findElement( By.tagName('data-browser') )
diff --git a/mkdocs.yml b/mkdocs.yml
index 25324af62..351f3d914 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -40,6 +40,7 @@ pages:
     - Fetching datasets: 'advanced/datasets.md'
     - Display non-atlas volumes: 'advanced/otherVolumes.md'
   - Release notes:
+    - v2.2.2: 'releases/v2.2.2.md'
     - v2.2.1: 'releases/v2.2.1.md'
     - v2.2.0: 'releases/v2.2.0.md'
     - v2.1.3: 'releases/v2.1.3.md'
diff --git a/src/ui/databrowserModule/databrowser.module.ts b/src/ui/databrowserModule/databrowser.module.ts
index 422d9cb01..dbbcd361d 100644
--- a/src/ui/databrowserModule/databrowser.module.ts
+++ b/src/ui/databrowserModule/databrowser.module.ts
@@ -7,7 +7,7 @@ import { DoiParserPipe } from "src/util/pipes/doiPipe.pipe";
 import { UtilModule } from "src/util/util.module";
 import { DataBrowser } from "./databrowser/databrowser.component";
 import { KgSingleDatasetService } from "./kgSingleDatasetService.service"
-import { ModalityPicker } from "./modalityPicker/modalityPicker.component";
+import { ModalityPicker, SortModalityAlphabeticallyPipe } from "./modalityPicker/modalityPicker.component";
 import { SingleDatasetView } from './singleDataset/detailedView/singleDataset.component'
 import { AggregateArrayIntoRootPipe } from "./util/aggregateArrayIntoRoot.pipe";
 import { CopyPropertyPipe } from "./util/copyProperty.pipe";
@@ -115,6 +115,7 @@ const previewEmitFactory = (store: Store<any>, previewDisplayed: (file,dataset)
     PreviewFileVisibleInSelectedReferenceTemplatePipe,
     UnavailableTooltip,
     TransformDatasetToIdPipe,
+    SortModalityAlphabeticallyPipe
   ],
   exports: [
     DataBrowser,
diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts
index 94167944c..75daf7070 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.component.ts
+++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts
@@ -4,6 +4,9 @@ import { LoggingService } from "src/logging";
 import { IDataEntry } from "src/services/stateStore.service";
 import { CountedDataModality, DatabrowserService } from "../databrowser.service";
 import { ModalityPicker } from "../modalityPicker/modalityPicker.component";
+import { ARIA_LABELS } from 'common/constants.js'
+
+const { MODALITY_FILTER, LIST_OF_DATASETS } = ARIA_LABELS
 
 @Component({
   selector : 'data-browser',
@@ -17,6 +20,8 @@ import { ModalityPicker } from "../modalityPicker/modalityPicker.component";
 
 export class DataBrowser implements OnChanges, OnDestroy, OnInit {
 
+  public MODALITY_FILTER_ARIA_LABEL = MODALITY_FILTER
+  public LIST_OF_DATASETS_ARIA_LABEL = LIST_OF_DATASETS
   @Input()
   public regions: any[] = []
 
diff --git a/src/ui/databrowserModule/databrowser/databrowser.template.html b/src/ui/databrowserModule/databrowser/databrowser.template.html
index 007409078..72c51396a 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.template.html
+++ b/src/ui/databrowserModule/databrowser/databrowser.template.html
@@ -70,7 +70,7 @@
     <mat-card-content class="dataset-container w-100 overflow-hidden">
       <!-- TODO export aria labels to common/constants -->
       <cdk-virtual-scroll-viewport
-        [attr.aria-label]="'List of datasets'"
+        [attr.aria-label]="LIST_OF_DATASETS_ARIA_LABEL"
         class="h-100"
         minBufferPx="200"
         maxBufferPx="400"
@@ -103,7 +103,8 @@
     <!-- Filters -->
     <mat-expansion-panel hideToggle>
 
-      <mat-expansion-panel-header class="align-items-center">
+      <mat-expansion-panel-header class="align-items-center"
+        [attr.aria-label]="MODALITY_FILTER_ARIA_LABEL">
         <mat-panel-title class="d-inline-flex align-items-center">
           <div class="flex-grow-1 flex-shrink-1 d-flex flex-column">
             <span>
diff --git a/src/ui/databrowserModule/modalityPicker/modalityPicker.component.spec.ts b/src/ui/databrowserModule/modalityPicker/modalityPicker.component.spec.ts
new file mode 100644
index 000000000..f7313420c
--- /dev/null
+++ b/src/ui/databrowserModule/modalityPicker/modalityPicker.component.spec.ts
@@ -0,0 +1,38 @@
+import { SortModalityAlphabeticallyPipe } from "./modalityPicker.component"
+import { CountedDataModality } from "../databrowser.service"
+
+describe('> modalityPicker.component.ts', () => {
+  describe('> ModalityPicker', () => {
+    // TODO
+  })
+
+  describe('> SortModalityAlphabeticallyPipe', () => {
+
+    const mods: CountedDataModality[] = [{
+      name: 'bbb',
+      occurance: 0,
+      visible: false
+    }, {
+      name: 'AAA',
+      occurance: 1,
+      visible: false
+    }, {
+      name: '007',
+      occurance: 17,
+      visible: false
+    }]
+    const beforeInput = [...mods]
+    const pipe = new SortModalityAlphabeticallyPipe()
+
+    const output = pipe.transform(mods)
+
+    it('> does not mutate', () => {
+      expect(mods).toEqual(beforeInput)
+    })
+    it('> should sort modalities as expected', () => {
+      expect(output).toEqual([
+        mods[2], mods[1], mods[0]
+      ])
+    })
+  })
+})
diff --git a/src/ui/databrowserModule/modalityPicker/modalityPicker.component.ts b/src/ui/databrowserModule/modalityPicker/modalityPicker.component.ts
index f7505efcd..b6a897adb 100644
--- a/src/ui/databrowserModule/modalityPicker/modalityPicker.component.ts
+++ b/src/ui/databrowserModule/modalityPicker/modalityPicker.component.ts
@@ -1,4 +1,4 @@
-import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core";
+import { Component, EventEmitter, Input, OnChanges, Output, Pipe, PipeTransform } from "@angular/core";
 import { CountedDataModality } from "../databrowser.service";
 
 @Component({
@@ -61,3 +61,16 @@ export class ModalityPicker implements OnChanges {
     )
   }
 }
+
+const sortByFn = (a: CountedDataModality, b: CountedDataModality) => (a.name || '0').charCodeAt(0) - (b.name || '0').charCodeAt(0) 
+
+@Pipe({
+  name: 'sortModalityAlphabetically',
+  pure: true
+})
+
+export class SortModalityAlphabeticallyPipe implements PipeTransform{
+  public transform(arr: CountedDataModality[]): CountedDataModality[]{
+    return [...arr].sort(sortByFn)
+  }
+}
diff --git a/src/ui/databrowserModule/modalityPicker/modalityPicker.template.html b/src/ui/databrowserModule/modalityPicker/modalityPicker.template.html
index 0a84ce45d..e0bcaa540 100644
--- a/src/ui/databrowserModule/modalityPicker/modalityPicker.template.html
+++ b/src/ui/databrowserModule/modalityPicker/modalityPicker.template.html
@@ -2,6 +2,6 @@
   [checked]="datamodality.visible"
   (change)="toggleModality(datamodality)"
   [ngClass]="{'muted': datamodality.occurance === 0}"
-  *ngFor="let datamodality of countedDataM">
+  *ngFor="let datamodality of countedDataM | sortModalityAlphabetically">
   {{ datamodality.name }} <span class="text-muted">({{ datamodality.occurance }})</span>
 </mat-checkbox>
\ No newline at end of file
diff --git a/src/ui/searchSideNav/searchSideNav.component.ts b/src/ui/searchSideNav/searchSideNav.component.ts
index fe9bcb9dc..ca50684e1 100644
--- a/src/ui/searchSideNav/searchSideNav.component.ts
+++ b/src/ui/searchSideNav/searchSideNav.component.ts
@@ -13,6 +13,9 @@ import { IavRootStoreInterface, SELECT_REGIONS } from "src/services/stateStore.s
 import { trackRegionBy } from '../viewerStateController/regionHierachy/regionHierarchy.component'
 import { MatDialog, MatDialogRef } from "@angular/material/dialog";
 import { MatSnackBar } from "@angular/material/snack-bar";
+import { ARIA_LABELS } from 'common/constants.js'
+
+const { TOGGLE_EXPLORE_PANEL } = ARIA_LABELS
 
 @Component({
   selector: 'search-side-nav',
@@ -23,6 +26,7 @@ import { MatSnackBar } from "@angular/material/snack-bar";
 })
 
 export class SearchSideNav implements OnDestroy {
+  public TOGGLE_EXPLORE_PANEL_ARIA_LABEL = TOGGLE_EXPLORE_PANEL
   public availableDatasets: number = 0
 
   private subscriptions: Subscription[] = []
diff --git a/src/ui/searchSideNav/searchSideNav.template.html b/src/ui/searchSideNav/searchSideNav.template.html
index 5335dd861..d9f0f5b8a 100644
--- a/src/ui/searchSideNav/searchSideNav.template.html
+++ b/src/ui/searchSideNav/searchSideNav.template.html
@@ -14,7 +14,7 @@
     <div class="d-flex flex-row justify-content-center" card-footer>
       <!-- TODO export all aria labels to common/constants.js in future patch -->
       <button mat-stroked-button
-        aria-label="Toggle explore panel"
+        [attr.aria-label]="TOGGLE_EXPLORE_PANEL_ARIA_LABEL"
         *ngIf="!(sidePanelExploreCurrentViewIsOpen$ | async)"
         (click)="expandSidePanelCurrentView()"
         [disabled]="!(viewerStateController.parcellationSelected$ | async)"
-- 
GitLab