From d0d5f02f6f71d3f0702d886685f8178a84c9c30f Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 22 Oct 2024 23:19:06 +0200 Subject: [PATCH 1/4] click to migrate in vessel group report --- .../VesselGroupReport.module.css | 7 +++++ .../vessel-groups/VesselGroupReport.tsx | 27 +++++++++++++++++-- .../vessel-group-report.hooks.ts | 21 +++++++++++++++ .../features/user/UserVesselGroups.tsx | 13 ++------- .../public/locales/en/translations.json | 1 + 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.module.css b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.module.css index 1946a3fddf..83f5269e48 100644 --- a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.module.css +++ b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.module.css @@ -16,3 +16,10 @@ text-decoration: underline; flex: 1; } + +.updateContainer { + display: flex; + gap: var(--space-S); + flex-direction: column; + align-items: center; +} diff --git a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx index c4a01c456d..69f0f815e7 100644 --- a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx +++ b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' import { useCallback, useEffect, useMemo } from 'react' -import { Tab, Tabs } from '@globalfishingwatch/ui-components' +import { Button, Tab, Tabs } from '@globalfishingwatch/ui-components' import { selectReportVesselGroupId } from 'routes/routes.selectors' import { AsyncReducerStatus } from 'utils/async-slice' import { TrackCategory, trackEvent } from 'features/app/analytics.hooks' @@ -17,18 +17,20 @@ import VGRActivity from 'features/reports/vessel-groups/activity/VGRActivity' import { useSetMapCoordinates } from 'features/map/map-viewport.hooks' import { selectIsGFWUser } from 'features/user/selectors/user.selectors' import { selectTrackDataviews } from 'features/dataviews/selectors/dataviews.instances.selectors' +import { isOutdatedVesselGroup } from 'features/vessel-groups/vessel-groups.utils' import { useFitAreaInViewport, useReportAreaCenter, useVesselGroupBounds, } from '../areas/area-reports.hooks' -import { useFetchVesselGroupReport } from './vessel-group-report.hooks' +import { useEditVesselGroupModal, useFetchVesselGroupReport } from './vessel-group-report.hooks' import { selectVGRData, selectVGRStatus } from './vessel-group-report.slice' import VesselGroupReportTitle from './VesselGroupReportTitle' import VesselGroupReportVessels from './vessels/VesselGroupReportVessels' import { selectVGRSection } from './vessel-group.config.selectors' import VesselGroupReportInsights from './insights/VGRInsights' import { selectVGRDataview } from './vessel-group-report.selectors' +import styles from './VesselGroupReport.module.css' function VesselGroupReport() { const { t } = useTranslation() @@ -48,6 +50,9 @@ function VesselGroupReport() { const setMapCoordinates = useSetMapCoordinates() const bboxHash = bbox ? bbox.join(',') : '' const vesselsInWorkspace = useSelector(selectTrackDataviews) + const isOutdated = isOutdatedVesselGroup(vesselGroup) + const onEditClick = useEditVesselGroupModal() + useEffect(() => { fetchVesselGroupReport(vesselGroupId) if (reportDataview) { @@ -116,6 +121,24 @@ function VesselGroupReport() { [t, isGFWUser] ) + if (isOutdated) { + return ( +
+
+ + +
+
+ ) + } + // if (reportStatus === AsyncReducerStatus.Error) { // return // } diff --git a/apps/fishing-map/features/reports/vessel-groups/vessel-group-report.hooks.ts b/apps/fishing-map/features/reports/vessel-groups/vessel-group-report.hooks.ts index c996c13b26..da191e0096 100644 --- a/apps/fishing-map/features/reports/vessel-groups/vessel-group-report.hooks.ts +++ b/apps/fishing-map/features/reports/vessel-groups/vessel-group-report.hooks.ts @@ -1,5 +1,11 @@ import { useCallback } from 'react' +import { VesselGroup } from '@globalfishingwatch/api-types' import { useAppDispatch } from 'features/app/app.hooks' +import { + setVesselGroupEditId, + setVesselGroupsModalOpen, + setVesselGroupConfirmationMode, +} from 'features/vessel-groups/vessel-groups-modal.slice' import { fetchVesselGroupReportThunk } from './vessel-group-report.slice' export function useFetchVesselGroupReport() { @@ -20,3 +26,18 @@ export function useFetchVesselGroupReport() { return fetchVesselGroupReport } + +export function useEditVesselGroupModal() { + const dispatch = useAppDispatch() + + const onEditClick = useCallback( + async (vesselGroup: VesselGroup) => { + dispatch(setVesselGroupEditId(vesselGroup.id)) + dispatch(setVesselGroupsModalOpen(true)) + dispatch(setVesselGroupConfirmationMode('update')) + }, + [dispatch] + ) + + return onEditClick +} diff --git a/apps/fishing-map/features/user/UserVesselGroups.tsx b/apps/fishing-map/features/user/UserVesselGroups.tsx index 085b8035fb..5d882347f2 100644 --- a/apps/fishing-map/features/user/UserVesselGroups.tsx +++ b/apps/fishing-map/features/user/UserVesselGroups.tsx @@ -21,10 +21,9 @@ import { sortByCreationDate } from 'utils/dates' import VesselGroupReportLink from 'features/reports/vessel-groups/VesselGroupReportLink' import { selectVesselGroupEditId, - setVesselGroupConfirmationMode, - setVesselGroupEditId, setVesselGroupsModalOpen, } from 'features/vessel-groups/vessel-groups-modal.slice' +import { useEditVesselGroupModal } from 'features/reports/vessel-groups/vessel-group-report.hooks' import { selectUserVesselGroups } from './selectors/user.permissions.selectors' import styles from './User.module.css' @@ -39,20 +38,12 @@ function UserVesselGroups() { datasetsStatus === AsyncReducerStatus.Loading || vesselGroupStatus === AsyncReducerStatus.Loading const editingGroupId = useSelector(selectVesselGroupEditId) + const onEditClick = useEditVesselGroupModal() const onNewGroupClick = useCallback(() => { dispatch(setVesselGroupsModalOpen(true)) }, [dispatch]) - const onEditClick = useCallback( - async (vesselGroup: VesselGroup) => { - dispatch(setVesselGroupEditId(vesselGroup.id)) - dispatch(setVesselGroupsModalOpen(true)) - dispatch(setVesselGroupConfirmationMode('update')) - }, - [dispatch] - ) - const onDeleteClick = useCallback( (vesselGroup: VesselGroup) => { const confirmation = window.confirm( diff --git a/apps/fishing-map/public/locales/en/translations.json b/apps/fishing-map/public/locales/en/translations.json index e41ecbc55a..2187e766c1 100644 --- a/apps/fishing-map/public/locales/en/translations.json +++ b/apps/fishing-map/public/locales/en/translations.json @@ -1024,6 +1024,7 @@ "addToWorkspace": "Add vessel group to workspace", "addVessels": "Add vessels to vessel group", "addVisibleVessels": "Add visible vessels to vessel group", + "clickToMigrate": "Click to migrate", "clickToUpdate": "Click to migrate your vessel group to latest available data", "confirmAbort": "You will lose any changes made in this vessel group. Are you sure?", "confirmRemove": "Are you sure you want to permanently delete this vessel group?", From 2cb4564d92519d9d496b3c1e5f7b21bdf0f478e4 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 22 Oct 2024 23:32:59 +0200 Subject: [PATCH 2/4] fix viewOnlyVesselGroup layers toggle --- .../features/reports/events/VGREventsVesselsTable.tsx | 1 + .../features/reports/vessel-groups/VesselGroupReport.tsx | 7 ------- .../reports/vessel-groups/VesselGroupReportLink.tsx | 3 +++ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/fishing-map/features/reports/events/VGREventsVesselsTable.tsx b/apps/fishing-map/features/reports/events/VGREventsVesselsTable.tsx index 68f2b66089..9aef57cc4e 100644 --- a/apps/fishing-map/features/reports/events/VGREventsVesselsTable.tsx +++ b/apps/fishing-map/features/reports/events/VGREventsVesselsTable.tsx @@ -32,6 +32,7 @@ export default function VesselGroupReportEventsVesselsTable() { } ) const vessels = useSelector(selectVGREventsVesselsPaginated) + const onPinClick = ({ vesselInWorkspace, }: { diff --git a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx index 69f0f815e7..dcb71e8834 100644 --- a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx +++ b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReport.tsx @@ -16,7 +16,6 @@ import VGREvents from 'features/reports/events/VGREvents' import VGRActivity from 'features/reports/vessel-groups/activity/VGRActivity' import { useSetMapCoordinates } from 'features/map/map-viewport.hooks' import { selectIsGFWUser } from 'features/user/selectors/user.selectors' -import { selectTrackDataviews } from 'features/dataviews/selectors/dataviews.instances.selectors' import { isOutdatedVesselGroup } from 'features/vessel-groups/vessel-groups.utils' import { useFitAreaInViewport, @@ -49,7 +48,6 @@ function VesselGroupReport() { const coordinates = useReportAreaCenter(bbox!) const setMapCoordinates = useSetMapCoordinates() const bboxHash = bbox ? bbox.join(',') : '' - const vesselsInWorkspace = useSelector(selectTrackDataviews) const isOutdated = isOutdatedVesselGroup(vesselGroup) const onEditClick = useEditVesselGroupModal() @@ -67,11 +65,6 @@ function VesselGroupReport() { vesselGroupId, ]) - useEffect(() => { - if (vesselsInWorkspace.length) { - dispatchQueryParams({ viewOnlyVesselGroup: false }) - } - }, [dispatchQueryParams, vesselsInWorkspace]) useEffect(() => { if (reportSection === 'vessels' && coordinates) { setMapCoordinates(coordinates) diff --git a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReportLink.tsx b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReportLink.tsx index 762328616f..e46e05c14c 100644 --- a/apps/fishing-map/features/reports/vessel-groups/VesselGroupReportLink.tsx +++ b/apps/fishing-map/features/reports/vessel-groups/VesselGroupReportLink.tsx @@ -5,6 +5,7 @@ import { VESSEL_GROUP_REPORT } from 'routes/routes' import { selectWorkspace } from 'features/workspace/workspace.selectors' import { DEFAULT_WORKSPACE_CATEGORY, DEFAULT_WORKSPACE_ID } from 'data/workspaces' import { selectLocationQuery } from 'routes/routes.selectors' +import { selectTrackDataviews } from 'features/dataviews/selectors/dataviews.instances.selectors' import styles from './VesselGroupReport.module.css' type VesselGroupReportLinkProps = { @@ -15,6 +16,7 @@ type VesselGroupReportLinkProps = { function VesselGroupReportLink({ children, vesselGroupId }: VesselGroupReportLinkProps) { const workspace = useSelector(selectWorkspace) const query = useSelector(selectLocationQuery) + const vesselsInWorkspace = useSelector(selectTrackDataviews) if (!workspace || !vesselGroupId) { return children @@ -28,6 +30,7 @@ function VesselGroupReportLink({ children, vesselGroupId }: VesselGroupReportLin category: workspace?.category || DEFAULT_WORKSPACE_CATEGORY, workspaceId: workspace?.id || DEFAULT_WORKSPACE_ID, vesselGroupId: vesselGroupId, + ...(vesselsInWorkspace?.length && { viewOnlyVesselGroup: false }), }, query: query, }} From 0d8ff4751fa9f3ca0b8d4f65264f5f77790fe7b6 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 22 Oct 2024 23:38:05 +0200 Subject: [PATCH 3/4] ensure AIS is selected as default source --- .../features/vessel-groups/VesselGroupModal.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/fishing-map/features/vessel-groups/VesselGroupModal.tsx b/apps/fishing-map/features/vessel-groups/VesselGroupModal.tsx index 0b5132070a..77667c151a 100644 --- a/apps/fishing-map/features/vessel-groups/VesselGroupModal.tsx +++ b/apps/fishing-map/features/vessel-groups/VesselGroupModal.tsx @@ -45,6 +45,7 @@ import { import { getPlaceholderBySelections } from 'features/i18n/utils' import { selectVesselGroupCompatibleDatasets } from 'features/datasets/datasets.selectors' import { getDatasetLabel } from 'features/datasets/datasets.utils' +import { DEFAULT_VESSEL_IDENTITY_DATASET } from 'features/vessel/vessel.config' import { IdField, createVesselGroupThunk, @@ -120,7 +121,12 @@ function VesselGroupModal(): React.ReactElement { id: d.id, label: getDatasetLabel(d), })) - const [sourcesSelected, setSourcesSelected] = useState([sourceOptions[0]]) + const defaultSourceSelected = sourceOptions.find((s) => + s.id.includes(DEFAULT_VESSEL_IDENTITY_DATASET) + ) + const [sourcesSelected, setSourcesSelected] = useState( + defaultSourceSelected ? [defaultSourceSelected] : [] + ) const onSelectSourceClick = useCallback( (source: SelectOption) => { @@ -317,7 +323,7 @@ function VesselGroupModal(): React.ReactElement { const missesRequiredParams = hasVesselGroupsVessels ? groupName === '' - : searchIdField === '' || !vesselGroupVesselsToSearch?.length + : searchIdField === '' || !vesselGroupVesselsToSearch?.length || !sourcesSelected?.length const confirmButtonDisabled = loading || hasVesselsOverflow || From d16a9d50accef7a2ef279c246cead412d8c62857 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 22 Oct 2024 23:45:27 +0200 Subject: [PATCH 4/4] skip activity and detection colors in colorCyclingType --- apps/fishing-map/features/workspace/workspace.hook.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/fishing-map/features/workspace/workspace.hook.ts b/apps/fishing-map/features/workspace/workspace.hook.ts index f891dc34da..6acdbdec9b 100644 --- a/apps/fishing-map/features/workspace/workspace.hook.ts +++ b/apps/fishing-map/features/workspace/workspace.hook.ts @@ -17,6 +17,8 @@ import { useLocationConnect } from 'routes/routes.hook' import { selectDataviewInstancesResolved } from 'features/dataviews/selectors/dataviews.resolvers.selectors' import { useSetMapCoordinates } from 'features/map/map-viewport.hooks' import { useTimerangeConnect } from 'features/timebar/timebar.hooks' +import { LAYERS_LIBRARY_ACTIVITY } from 'data/layer-library/layers-activity' +import { LAYERS_LIBRARY_DETECTIONS } from 'data/layer-library/layers-detections' import { selectWorkspaceDataviewInstances } from './workspace.selectors' export const useFitWorkspaceBounds = () => { @@ -50,7 +52,10 @@ const createDataviewsInstances = ( newDataviewInstances: Partial[], currentDataviewInstances: UrlDataviewInstance[] = [] ): UrlDataviewInstance[] => { - const currentColors = currentDataviewInstances.flatMap((dv) => dv.config?.color || []) + const defaultDataviewInstances = [...LAYERS_LIBRARY_ACTIVITY, ...LAYERS_LIBRARY_DETECTIONS] + const currentColors = (currentDataviewInstances || defaultDataviewInstances).flatMap( + (dv) => dv.config?.color || [] + ) return newDataviewInstances.map((dataview) => { if (dataview.config?.colorCyclingType) { const nextColor = getNextColor(dataview.config.colorCyclingType, currentColors)