From d737098e054efc0c9363b202f58d70457127f92d Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 13 Oct 2023 14:16:20 +0200 Subject: [PATCH 1/5] Add fallback key to sort columns --- .../ReportingList/constants.ts | 16 +++++-- .../ReportingList/index.tsx | 5 +- frontend/src/hooks/useTable/TableHead.tsx | 4 +- frontend/src/hooks/useTable/index.tsx | 46 +++++++++---------- frontend/src/hooks/useTable/types.ts | 1 + 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts index 05c2d5c431..5cc565a42b 100644 --- a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts +++ b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts @@ -6,6 +6,7 @@ import type { TableOptions } from '../../../../../hooks/useTable/types' export const REPORTING_LIST_TABLE_OPTIONS: TableOptions = { columns: [ { + fallbackKey: 'creationDate', fixedWidth: 112, isSortable: true, key: 'validationDate', @@ -13,14 +14,14 @@ export const REPORTING_LIST_TABLE_OPTIONS: TableOptions {tableData.map((reporting, index) => { const editingIsDisabled = reporting.type === ReportingType.ALERT + const reportingDate = reporting.validationDate || reporting.creationDate return ( @@ -187,8 +188,8 @@ MMSI: ${reporting.mmsi || ''}` onChange={() => toggleTableCheckForId(reporting.id)} /> - - {timeago.format(reporting.validationDate || reporting.creationDate, 'fr')} + + {timeago.format(reportingDate, 'fr')} {getReportingOrigin(reporting)} diff --git a/frontend/src/hooks/useTable/TableHead.tsx b/frontend/src/hooks/useTable/TableHead.tsx index 555a8ec22f..cae74def0f 100644 --- a/frontend/src/hooks/useTable/TableHead.tsx +++ b/frontend/src/hooks/useTable/TableHead.tsx @@ -13,7 +13,7 @@ export type TableHeadProps = { isCheckable?: boolean | undefined isSortingDesc: boolean onAllCheckChange: () => Promisable - onSort: (key: string, isDesc: boolean) => Promisable + onSort: (key: string, isDesc: boolean, fallbackKey?: string | undefined) => Promisable sortingKey?: string | undefined } export function TableHead({ @@ -30,7 +30,7 @@ export function TableHead({ return } - onSort(column.key, column.key === sortingKey && !isSortingDesc) + onSort(column.key, column.key === sortingKey && !isSortingDesc, column.fallbackKey) } return ( diff --git a/frontend/src/hooks/useTable/index.tsx b/frontend/src/hooks/useTable/index.tsx index a27485e708..2a05082f5f 100644 --- a/frontend/src/hooks/useTable/index.tsx +++ b/frontend/src/hooks/useTable/index.tsx @@ -1,12 +1,13 @@ import diacritics from 'diacritics' import Fuse from 'fuse.js' -import { ascend, assocPath, descend, equals, path, pipe, propEq, sortWith } from 'ramda' +import { get, orderBy } from 'lodash' +import { assocPath, equals, path, pipe, propEq } from 'ramda' import { useCallback, useEffect, useMemo, useState } from 'react' import { TableHead } from './TableHead' import { getArrayPathFromStringPath, normalizeSearchQuery } from './utils' -import type { TableItem, FilterFunction, TableOptions } from './types' +import type { FilterFunction, TableItem, TableOptions } from './types' import type { CollectionItem } from '../../types' export function useTable( @@ -25,6 +26,7 @@ export function useTable( const [checkedIds, setCheckedIds] = useState<(number | string)[]>([]) const [isSortingDesc, setIsSortingDesc] = useState(Boolean(isDefaultSortingDesc)) const [sortingKey, setSortingKey] = useState(defaultSortedKey) + const [sortingFallbackKey, setSortingFallbackKey] = useState(undefined) const rawData = useMemo(() => maybeRawData || [], [maybeRawData]) @@ -152,30 +154,23 @@ export function useTable( return filteredAndSearchedTableData } - const sortingKeyAsArrayPath = getArrayPathFromStringPath(sortingKey) - const sortingKeyPath = path(['$sortable', ...sortingKeyAsArrayPath]) as any - const bySortingKey = isSortingDesc ? descend(sortingKeyPath) : ascend(sortingKeyPath) - - return sortWith( - [ - bySortingKey, - // Sort undefined values (to the bottom when ascending and to the top when descending) - (firstDataItem, secondDataItem) => { - const firstDataItemProp = sortingKeyPath(firstDataItem) - const secondDataItemProp = sortingKeyPath(secondDataItem) - - if (isSortingDesc) { - // eslint-disable-next-line no-nested-ternary - return firstDataItemProp === undefined ? (secondDataItemProp === undefined ? 0 : -1) : 1 - } - - // eslint-disable-next-line no-nested-ternary - return firstDataItemProp === undefined ? (secondDataItemProp === undefined ? 0 : 1) : -1 + return orderBy( + filteredAndSearchedTableData, + item => { + const value = get(item, sortingKey) + if (value !== undefined) { + return value } - ], - filteredAndSearchedTableData + + if (!sortingFallbackKey) { + return undefined + } + + return get(item, sortingFallbackKey) + }, + isSortingDesc ? ['desc'] : ['asc'] ) - }, [filteredAndSearchedTableData, isSortingDesc, sortingKey]) + }, [filteredAndSearchedTableData, isSortingDesc, sortingKey, sortingFallbackKey]) const getCheckedData = useCallback( () => filteredAndSearchedAndSortedTableData.filter(({ id }) => checkedIds.includes(id)), @@ -186,8 +181,9 @@ export function useTable( setCheckedIds(isAllChecked ? [] : filteredAndSearchedAndSortedTableData.map(({ id }) => id).sort()) }, [filteredAndSearchedAndSortedTableData, isAllChecked]) - const sortColumn = useCallback((key: string, isDesc: boolean) => { + const sortColumn = useCallback((key: string, isDesc: boolean, fallbackKey: string | undefined) => { setSortingKey(key) + setSortingFallbackKey(fallbackKey) setIsSortingDesc(isDesc) }, []) diff --git a/frontend/src/hooks/useTable/types.ts b/frontend/src/hooks/useTable/types.ts index ddc49334ea..d96bbae7c6 100644 --- a/frontend/src/hooks/useTable/types.ts +++ b/frontend/src/hooks/useTable/types.ts @@ -2,6 +2,7 @@ import type { CollectionItem, Native } from '../../types' import type Fuse from 'fuse.js' export type TableColumn = Record> = { + fallbackKey?: string | undefined /** Fixed width expressed in root ephemeral unit (rem) */ fixedWidth?: number isSortable?: boolean From c0b9903e5828eda91e1f844f595b4e5b53addfa7 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 13 Oct 2023 14:20:51 +0200 Subject: [PATCH 2/5] Re-add overlay in reporting list --- frontend/src/features/SideWindow/index.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/frontend/src/features/SideWindow/index.tsx b/frontend/src/features/SideWindow/index.tsx index 8ee5015f1d..858a2e3e83 100644 --- a/frontend/src/features/SideWindow/index.tsx +++ b/frontend/src/features/SideWindow/index.tsx @@ -52,7 +52,7 @@ function SideWindowWithRef({ isFromURL }: SideWindowProps, ref: ForwardedRef ({ background: THEME.color.charcoal, height: '100%', @@ -121,12 +121,9 @@ function SideWindowWithRef({ isFromURL }: SideWindowProps, ref: ForwardedRef - {/* TODO Move that within BeaconMalfunctionBoard. */} - {selectedPath.menu === SideWindowMenuKey.BEACON_MALFUNCTION_BOARD && ( - + {(selectedPath.menu === SideWindowMenuKey.BEACON_MALFUNCTION_BOARD || + selectedPath.menu === SideWindowMenuKey.ALERT_LIST_AND_REPORTING_LIST) && ( + )} {isPreloading && ( @@ -228,7 +225,7 @@ const Content = styled.div` min-width: 0; ` -const BeaconMalfunctionsBoardGrayOverlay = styled.div`` +const GrayOverlay = styled.div`` const Loading = styled.div` margin-left: 550px; From 6f1c2a849fb2e1179aad64d060bb8e2ba404e9c4 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 13 Oct 2023 17:28:13 +0200 Subject: [PATCH 3/5] Use transform with lodash --- .../V666.19__Insert_dummy_reportings.sql | 2 +- .../ReportingList/constants.ts | 4 ++-- frontend/src/hooks/useTable/TableHead.tsx | 4 ++-- frontend/src/hooks/useTable/index.tsx | 19 +++---------------- frontend/src/hooks/useTable/types.ts | 1 - 5 files changed, 8 insertions(+), 22 deletions(-) diff --git a/backend/src/main/resources/db/testdata/V666.19__Insert_dummy_reportings.sql b/backend/src/main/resources/db/testdata/V666.19__Insert_dummy_reportings.sql index d3110032a9..911573866f 100644 --- a/backend/src/main/resources/db/testdata/V666.19__Insert_dummy_reportings.sql +++ b/backend/src/main/resources/db/testdata/V666.19__Insert_dummy_reportings.sql @@ -51,7 +51,7 @@ VALUES ('ALERT', 'MARIAGE ÎLE HASARD', 'ABC000180832', 'VP374069', 'CG1312', 'I '"seaFront": "NAMO"' || '}')::jsonb, null, null, 10), ('INFRACTION_SUSPICION', 'RENCONTRER VEILLER APPARTEMENT"', 'ABC000597493', 'JL026591', 'CMQ7994', - 'INTERNAL_REFERENCE_NUMBER', 'FR', NOW() - ('1 DAY 1 HOUR')::interval, NOW() - ('1 DAY 1 HOUR')::interval, false, + 'INTERNAL_REFERENCE_NUMBER', 'FR', NOW() - ('1 DAY 1 HOUR')::interval, null, false, false, ('{' || '"reportingActor": "UNIT",' || '"controlUnitId": 10012,' || diff --git a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts index 5cc565a42b..7936a5ff41 100644 --- a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts +++ b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts @@ -6,11 +6,11 @@ import type { TableOptions } from '../../../../../hooks/useTable/types' export const REPORTING_LIST_TABLE_OPTIONS: TableOptions = { columns: [ { - fallbackKey: 'creationDate', fixedWidth: 112, isSortable: true, key: 'validationDate', - label: 'Ouvert il y a...' + label: 'Ouvert il y a...', + sortingTransform: item => item.validationDate || item.creationDate }, { fixedWidth: 112, diff --git a/frontend/src/hooks/useTable/TableHead.tsx b/frontend/src/hooks/useTable/TableHead.tsx index cae74def0f..555a8ec22f 100644 --- a/frontend/src/hooks/useTable/TableHead.tsx +++ b/frontend/src/hooks/useTable/TableHead.tsx @@ -13,7 +13,7 @@ export type TableHeadProps = { isCheckable?: boolean | undefined isSortingDesc: boolean onAllCheckChange: () => Promisable - onSort: (key: string, isDesc: boolean, fallbackKey?: string | undefined) => Promisable + onSort: (key: string, isDesc: boolean) => Promisable sortingKey?: string | undefined } export function TableHead({ @@ -30,7 +30,7 @@ export function TableHead({ return } - onSort(column.key, column.key === sortingKey && !isSortingDesc, column.fallbackKey) + onSort(column.key, column.key === sortingKey && !isSortingDesc) } return ( diff --git a/frontend/src/hooks/useTable/index.tsx b/frontend/src/hooks/useTable/index.tsx index 2a05082f5f..25d4ceb2b9 100644 --- a/frontend/src/hooks/useTable/index.tsx +++ b/frontend/src/hooks/useTable/index.tsx @@ -26,7 +26,6 @@ export function useTable( const [checkedIds, setCheckedIds] = useState<(number | string)[]>([]) const [isSortingDesc, setIsSortingDesc] = useState(Boolean(isDefaultSortingDesc)) const [sortingKey, setSortingKey] = useState(defaultSortedKey) - const [sortingFallbackKey, setSortingFallbackKey] = useState(undefined) const rawData = useMemo(() => maybeRawData || [], [maybeRawData]) @@ -156,21 +155,10 @@ export function useTable( return orderBy( filteredAndSearchedTableData, - item => { - const value = get(item, sortingKey) - if (value !== undefined) { - return value - } - - if (!sortingFallbackKey) { - return undefined - } - - return get(item, sortingFallbackKey) - }, + item => get(item, `$sortable.${sortingKey}`), isSortingDesc ? ['desc'] : ['asc'] ) - }, [filteredAndSearchedTableData, isSortingDesc, sortingKey, sortingFallbackKey]) + }, [filteredAndSearchedTableData, isSortingDesc, sortingKey]) const getCheckedData = useCallback( () => filteredAndSearchedAndSortedTableData.filter(({ id }) => checkedIds.includes(id)), @@ -181,9 +169,8 @@ export function useTable( setCheckedIds(isAllChecked ? [] : filteredAndSearchedAndSortedTableData.map(({ id }) => id).sort()) }, [filteredAndSearchedAndSortedTableData, isAllChecked]) - const sortColumn = useCallback((key: string, isDesc: boolean, fallbackKey: string | undefined) => { + const sortColumn = useCallback((key: string, isDesc: boolean) => { setSortingKey(key) - setSortingFallbackKey(fallbackKey) setIsSortingDesc(isDesc) }, []) diff --git a/frontend/src/hooks/useTable/types.ts b/frontend/src/hooks/useTable/types.ts index d96bbae7c6..ddc49334ea 100644 --- a/frontend/src/hooks/useTable/types.ts +++ b/frontend/src/hooks/useTable/types.ts @@ -2,7 +2,6 @@ import type { CollectionItem, Native } from '../../types' import type Fuse from 'fuse.js' export type TableColumn = Record> = { - fallbackKey?: string | undefined /** Fixed width expressed in root ephemeral unit (rem) */ fixedWidth?: number isSortable?: boolean From f7e6da0a9459951839a4de59beba18c19860afed Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Mon, 16 Oct 2023 10:11:33 +0200 Subject: [PATCH 4/5] Add title and origin as sortable in reporting table --- .../AlertListAndReportingList/ReportingList/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts index 7936a5ff41..b69b18bbe3 100644 --- a/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts +++ b/frontend/src/features/SideWindow/Alert/AlertListAndReportingList/ReportingList/constants.ts @@ -14,14 +14,14 @@ export const REPORTING_LIST_TABLE_OPTIONS: TableOptions Date: Mon, 16 Oct 2023 16:09:51 +0200 Subject: [PATCH 5/5] Add wait when clicking on regulation --- frontend/cypress/e2e/sidebars/regulatory_layers.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/cypress/e2e/sidebars/regulatory_layers.spec.ts b/frontend/cypress/e2e/sidebars/regulatory_layers.spec.ts index 388df2c0ae..04b0236b5c 100644 --- a/frontend/cypress/e2e/sidebars/regulatory_layers.spec.ts +++ b/frontend/cypress/e2e/sidebars/regulatory_layers.spec.ts @@ -52,6 +52,7 @@ context('Sidebars > Regulatory Layers', () => { // ).as('getRegulation') cy.get('*[data-cy="regulatory-layers-my-zones-zone-show"]').eq(0).click({ timeout: 10000 }) cy.wait('@getRegulation').then(({ response }) => expect(response && response.statusCode).equal(200)) + cy.wait(200) cy.get('.regulatory', { timeout: 10000 }).click(490, 580, { force: true, timeout: 10000 }) cy.wait('@getRegulation').then(({ response }) => expect(response && response.statusCode).equal(200))