Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VesselGroups refactor #2846

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/fishing-map/features/dataviews/dataviews.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getActiveDatasetsInDataview,
isPrivateDataset,
} from 'features/datasets/datasets.utils'
import { INCLUDES_RELATED_SELF_REPORTED_INFO_ID } from 'features/vessel/vessel.config'

// used in workspaces with encounter events layers
export const ENCOUNTER_EVENTS_SOURCE_ID = 'encounter'
Expand Down Expand Up @@ -57,7 +58,7 @@ export const getVesselInfoDataviewInstanceDatasetConfig = (
{ id: 'dataset', value: info },
{
id: 'includes',
value: ['POTENTIAL_RELATED_SELF_REPORTED_INFO'],
value: [INCLUDES_RELATED_SELF_REPORTED_INFO_ID],
},
],
endpoint: EndpointId.Vessel,
Expand Down
3 changes: 2 additions & 1 deletion apps/fishing-map/features/map/map.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
selectEventsDataviews,
selectVesselGroupDataviews,
} from 'features/dataviews/selectors/dataviews.categories.selectors'
import { INCLUDES_RELATED_SELF_REPORTED_INFO_ID } from 'features/vessel/vessel.config'

export const MAX_TOOLTIP_LIST = 5

Expand Down Expand Up @@ -197,7 +198,7 @@ const getVesselInfoEndpoint = (vesselDatasets: Dataset[], vesselIds: string[]) =
},
{
id: 'includes',
value: ['POTENTIAL_RELATED_SELF_REPORTED_INFO'],
value: [INCLUDES_RELATED_SELF_REPORTED_INFO_ID],
},
],
}
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map/features/modals/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ROOT_DOM_ELEMENT } from 'data/config'
import useSecretMenu, { useSecretKeyboardCombo } from 'hooks/secret-menu.hooks'
import { selectBigQueryActive, toggleBigQueryMenu } from 'features/bigquery/bigquery.slice'
import { selectDownloadActivityAreaKey } from 'features/download/downloadActivity.slice'
import { selectVesselGroupModalOpen } from 'features/vessel-groups/vessel-groups.slice'
import { selectVesselGroupModalOpen } from 'features/vessel-groups/vessel-groups-modal.slice'
import GFWOnly from 'features/user/GFWOnly'
import { useAppDispatch } from 'features/app/app.hooks'
import { selectDatasetUploadModalOpen, setModalOpen } from 'features/modals/modals.slice'
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map/features/modals/modals.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
selectLayerLibraryModalOpen,
selectScreenshotModalOpen,
} from 'features/modals/modals.slice'
import { selectVesselGroupModalOpen } from 'features/vessel-groups/vessel-groups.slice'
import { selectVesselGroupModalOpen } from 'features/vessel-groups/vessel-groups-modal.slice'
import { WelcomeContentKey } from 'features/welcome/welcome.content'
import {
selectLocationCategory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,23 @@ import cx from 'classnames'
import { Fragment, useMemo } from 'react'
import { unparse as unparseCSV } from 'papaparse'
import { saveAs } from 'file-saver'
import { uniq } from 'es-toolkit'
import { Button, IconButton } from '@globalfishingwatch/ui-components'
import I18nNumber from 'features/i18n/i18nNumber'
import { useLocationConnect } from 'routes/routes.hook'
import VesselGroupAddButton from 'features/vessel-groups/VesselGroupAddButton'
import { selectTimeRange } from 'features/app/selectors/app.timebar.selectors'
import { REPORT_SHOW_MORE_VESSELS_PER_PAGE, REPORT_VESSELS_PER_PAGE } from 'data/config'
import { useAppDispatch } from 'features/app/app.hooks'
import {
setVesselGroupConfirmationMode,
setVesselGroupCurrentDataviewIds,
} from 'features/vessel-groups/vessel-groups.slice'
import { setVesselGroupConfirmationMode } from 'features/vessel-groups/vessel-groups-modal.slice'
import { selectActiveActivityAndDetectionsDataviews } from 'features/dataviews/selectors/dataviews.selectors'
import { TrackCategory, trackEvent } from 'features/app/analytics.hooks'
import { selectReportVesselFilter } from 'features/reports/areas/area-reports.config.selectors'
import {
selectReportAreaName,
ReportVesselWithDatasets,
} from 'features/reports/areas/area-reports.selectors'
import {
parseReportVesselsToIdentity,
getVesselsFiltered,
} from 'features/reports/areas/area-reports.utils'
import { getVesselsFiltered } from 'features/reports/areas/area-reports.utils'
import styles from './ReportVesselsTableFooter.module.css'
import {
selectReportVesselsListWithAllInfo,
Expand All @@ -51,8 +46,15 @@ export default function ReportVesselsTableFooter({ reportName }: ReportVesselsTa
const heatmapDataviews = useSelector(selectActiveActivityAndDetectionsDataviews)
const { start, end } = useSelector(selectTimeRange)

const vesselGroupIdentityVessels = useMemo(() => {
return parseReportVesselsToIdentity(reportVesselFilter ? allFilteredVessels : allVessels)
const vesselGroupVessels = useMemo(() => {
const vessels = reportVesselFilter ? allFilteredVessels : allVessels
if (!vessels?.length) {
return null
}
return {
ids: vessels?.flatMap((v) => v.id || v.vesselId || []),
datasets: uniq(vessels.flatMap((v) => v.dataset || [])),
}
}, [allFilteredVessels, allVessels, reportVesselFilter])

const onDownloadVesselsClick = () => {
Expand Down Expand Up @@ -99,11 +101,7 @@ export default function ReportVesselsTableFooter({ reportName }: ReportVesselsTa
})
}
const onAddToVesselGroup = () => {
const dataviewIds = heatmapDataviews.map(({ id }) => id)
dispatch(setVesselGroupConfirmationMode('saveAndSeeInWorkspace'))
if (dataviewIds?.length) {
dispatch(setVesselGroupCurrentDataviewIds(dataviewIds))
}
trackEvent({
category: TrackCategory.VesselGroups,
action: 'add_to_vessel_group',
Expand Down Expand Up @@ -171,7 +169,8 @@ export default function ReportVesselsTableFooter({ reportName }: ReportVesselsTa
</div>
<div className={cx(styles.flex, styles.expand)}>
<VesselGroupAddButton
vessels={vesselGroupIdentityVessels}
vesselsToResolve={vesselGroupVessels?.ids}
datasetsToResolve={vesselGroupVessels?.datasets}
onAddToVesselGroup={onAddToVesselGroup}
/>
<Button testId="download-vessel-table-report" onClick={onDownloadVesselsClick}>
Expand Down
47 changes: 2 additions & 45 deletions apps/fishing-map/features/reports/areas/area-reports.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Bbox, BufferOperation, BufferUnit } from 'types'
import { Area, AreaGeometry } from 'features/areas/areas.slice'
import { IdentityVesselData, VesselDataIdentity } from 'features/vessel/vessel.slice'
import { VesselGroupReportVesselParsed } from 'features/reports/vessel-groups/vessels/vessel-group-report-vessels.types'
import { VesselGroupVesselTableParsed } from '../vessel-groups/vessels/vessel-group-report-vessels.selectors'
import {
DEFAULT_BUFFER_OPERATION,
DEFAULT_POINT_BUFFER_UNIT,
Expand Down Expand Up @@ -266,50 +267,6 @@ export const parseReportUrl = (url: string) => {
}
}

function parseReportToIdentityVessel(vessel: ReportVesselWithDatasets) {
return {
id: vessel.id || vessel.vesselId,
shipname: vessel.shipName,
flag: vessel.flag,
gearType: vessel.geartype,
vesselType: vessel.vesselType,
mmsi: vessel.mmsi,
callsign: vessel.callsign,
transmissionDateFrom: vessel.firstTransmissionDate,
transmissionDateTo: vessel.lastTransmissionDate,
identitySource: 'selfReportedInfo',
imo: vessel.imo,
nShipname: '',
ssvid: vessel.mmsi,
sourceCode: ['AIS'],
geartypes: vessel.geartype ? [vessel.geartype] : [],
shiptypes: vessel.vesselType ? [vessel.vesselType] : [],
} as VesselDataIdentity
}
export function parseReportVesselsToIdentity(
vessels?: ReportVesselWithDatasets[] | null
): IdentityVesselData[] {
if (!vessels || !vessels.length) {
return []
}
const identityVessels = vessels.flatMap((vessel) => {
if (!vessel) {
return []
}
return {
id: vessel.id || vessel.vesselId,
dataset: vessel.infoDataset,
info: vessel.infoDataset?.id!,
track: vessel.trackDataset?.id!,
registryOwners: [],
registryPublicAuthorizations: [],
combinedSourcesInfo: [],
identities: [parseReportToIdentityVessel(vessel)],
} as IdentityVesselData
})
return identityVessels
}

export type FilterProperty = 'name' | 'flag' | 'mmsi' | 'gear' | 'type'
export const FILTER_PROPERTIES: Record<FilterProperty, string[]> = {
name: ['shipName'],
Expand All @@ -320,7 +277,7 @@ export const FILTER_PROPERTIES: Record<FilterProperty, string[]> = {
}

export function getVesselsFiltered<
Vessel = ReportVesselWithDatasets | VesselGroupReportVesselParsed
Vessel = ReportVesselWithDatasets | VesselGroupReportVesselParsed | VesselGroupVesselTableParsed
>(vessels: Vessel[], filter: string, filterProperties = FILTER_PROPERTIES) {
if (!filter || !filter.length) {
return vessels
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ export default function VesselGroupReportVesselsTableFooter() {
// const onAddToVesselGroup = () => {
// const dataviewIds = heatmapDataviews.map(({ id }) => id)
// dispatch(setVesselGroupConfirmationMode('saveAndNavigate'))
// if (dataviewIds?.length) {
// dispatch(setVesselGroupCurrentDataviewIds(dataviewIds))
// }
// trackEvent({
// category: TrackCategory.VesselGroups,
// action: 'add_to_vessel_group',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
VesselGroupEventsVesselsParams,
} from 'queries/vessel-group-events-stats-api'
import { selectVGRData } from 'features/reports/vessel-groups/vessel-group-report.slice'
import { getSearchIdentityResolved, getVesselId } from 'features/vessel/vessel.utils'
import { getSearchIdentityResolved } from 'features/vessel/vessel.utils'
import { selectTimeRange } from 'features/app/selectors/app.timebar.selectors'
import { selectReportVesselGroupId } from 'routes/routes.selectors'
import {
Expand Down Expand Up @@ -49,11 +49,11 @@ export const selectVGREventsVessels = createSelector(
return
}
const insightVessels = vesselGroup?.vessels?.flatMap((vessel) => {
const vesselWithEvents = data?.find((v) => v.vesselId === getVesselId(vessel))
const vesselWithEvents = data?.find((v) => v.vesselId === vessel.vesselId)
if (!vesselWithEvents) {
return []
}
const identity = getSearchIdentityResolved(vessel)
const identity = getSearchIdentityResolved(vessel.identity!)
return {
...vesselWithEvents,
...identity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { useAppDispatch } from 'features/app/app.hooks'
import ReportTitlePlaceholder from 'features/reports/areas/placeholders/ReportTitlePlaceholder'
import { TrackCategory, trackEvent } from 'features/app/analytics.hooks'
import {
setNewVesselGroupSearchVessels,
setVesselGroupEditId,
setVesselGroupModalVessels,
setVesselGroupsModalOpen,
} from 'features/vessel-groups/vessel-groups.slice'
} from 'features/vessel-groups/vessel-groups-modal.slice'
import { formatInfoField } from 'utils/info'
import { useLocationConnect } from 'routes/routes.hook'
import { selectHasOtherVesselGroupDataviews } from 'features/dataviews/selectors/dataviews.selectors'
Expand All @@ -35,7 +35,7 @@ export default function VesselGroupReportTitle({ vesselGroup, loading }: ReportT
const onEditClick = useCallback(() => {
if (vesselGroup?.id || !vesselGroup?.vessels?.length) {
dispatch(setVesselGroupEditId(vesselGroup.id))
dispatch(setNewVesselGroupSearchVessels(vesselGroup.vessels))
dispatch(setVesselGroupModalVessels(vesselGroup.vessels))
dispatch(setVesselGroupsModalOpen(true))
}
}, [dispatch, vesselGroup?.id, vesselGroup?.vessels])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,11 @@ export const selectVGRVesselsByInsight = <Insight = any>(
return []
}
const insightVessels = vesselGroup?.vessels?.flatMap((vessel) => {
const vesselWithInsight = data?.[insightProperty]?.find(
(v) => v.vesselId === getVesselId(vessel)
)
const vesselWithInsight = data?.[insightProperty]?.find((v) => v.vesselId === vessel.vesselId)
if (!vesselWithInsight || (insightCounter && get(vesselWithInsight, insightCounter) === 0)) {
return []
}
return { ...vesselWithInsight, identity: getSearchIdentityResolved(vessel) }
return { ...vesselWithInsight, identity: getSearchIdentityResolved(vessel.identity!) }
})
return insightVessels.sort((a, b) => {
if (insightCounter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import { stringify } from 'qs'
import { GFWAPI } from '@globalfishingwatch/api-client'
import { APIPagination, IdentityVessel, VesselGroup } from '@globalfishingwatch/api-types'
import { AsyncError, AsyncReducerStatus } from 'utils/async-slice'
import { getVesselProperty } from 'features/vessel/vessel.utils'
import { mergeVesselGroupVesselIdentities } from 'features/vessel-groups/vessel-groups.utils'
import { VesselGroupVesselIdentity } from 'features/vessel-groups/vessel-groups-modal.slice'
import { INCLUDES_RELATED_SELF_REPORTED_INFO_ID } from 'features/vessel/vessel.config'

export type VesselGroupReport = Omit<VesselGroup, 'vessels'> & { vessels: IdentityVessel[] }
export type VesselGroupReport = Omit<VesselGroup, 'vessels'> & {
vessels: VesselGroupVesselIdentity[]
}

interface ReportState {
status: AsyncReducerStatus
Expand All @@ -30,20 +34,17 @@ export const fetchVesselGroupReportThunk = createAsyncThunk(
async ({ vesselGroupId }: FetchVesselGroupReportThunkParams, { rejectWithValue, signal }) => {
try {
const vesselGroup = await GFWAPI.fetch<VesselGroup>(`/vessel-groups/${vesselGroupId}`)
const params = {
'vessel-groups': [vesselGroupId],
includes: [INCLUDES_RELATED_SELF_REPORTED_INFO_ID],
}
const vesselGroupVessels = await GFWAPI.fetch<APIPagination<IdentityVessel>>(
`/vessels?${stringify({ 'vessel-groups': [vesselGroupId] })}`,
`/vessels?${stringify(params)}`,
{ cache: 'reload', signal }
)
return {
...vesselGroup,
vessels: vesselGroupVessels.entries.toSorted((a, b) => {
const aValue = getVesselProperty(a, 'shipname')
const bValue = getVesselProperty(b, 'shipname')
if (aValue === bValue) {
return 0
}
return aValue > bValue ? 1 : -1
}),
vessels: mergeVesselGroupVesselIdentities(vesselGroup.vessels, vesselGroupVessels.entries),
}
} catch (e) {
console.warn(e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { DateTime } from 'luxon'
import { useTranslation } from 'react-i18next'
import parse from 'html-react-parser'
import ReportVesselsFilter from 'features/reports/activity/vessels/ReportVesselsFilter'
import { selectVGRVessels } from 'features/reports/vessel-groups/vessel-group-report.slice'
import {
selectVGRUniqVessels,
selectVGRVesselsFlags,
selectVGRVesselsGraphDataGrouped,
selectVGRVesselsTimeRange,
Expand All @@ -25,7 +25,7 @@ import styles from './VesselGroupReportVessels.module.css'

function VesselGroupReportVessels() {
const { t } = useTranslation()
const vessels = useSelector(selectVGRVessels)
const vessels = useSelector(selectVGRUniqVessels)
const subsection = useSelector(selectVGRVesselsSubsection)
const reportDataview = useSelector(selectVGRDataview)
const timeRange = useSelector(selectVGRVesselsTimeRange)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@ import {
selectVGRVesselsOrderDirection,
selectVGRVesselsOrderProperty,
} from 'features/reports/vessel-groups/vessel-group.config.selectors'
import { selectVGRVessels } from 'features/reports/vessel-groups/vessel-group-report.slice'
import {
VGRVesselsOrderProperty,
VGRVesselsOrderDirection,
} from 'features/vessel-groups/vessel-groups.types'
import { getSearchIdentityResolved } from 'features/vessel/vessel.utils'
import styles from './VesselGroupReportVesselsTable.module.css'
import { selectVGRVesselsPaginated } from './vessel-group-report-vessels.selectors'
import VesselGroupReportVesselsTableFooter from './VesselGroupReportVesselsTableFooter'

export default function VesselGroupReportVesselsTable() {
const { t } = useTranslation()
const { dispatchQueryParams } = useLocationConnect()
const vesselsRaw = useSelector(selectVGRVessels)
const vessels = useSelector(selectVGRVesselsPaginated)
const userData = useSelector(selectUserData)
const dataviews = useSelector(selectActiveReportDataviews)
Expand Down Expand Up @@ -107,7 +106,8 @@ export default function VesselGroupReportVesselsTable() {
/>
</div>
{vessels?.map((vessel, i) => {
const { id, shipName, flag, flagTranslatedClean, flagTranslated, mmsi, index } = vessel
const { shipName, flagTranslated, flagTranslatedClean, identity } = vessel
const { id, flag, ssvid } = getSearchIdentityResolved(identity!)
const isLastRow = i === vessels.length - 1
const flagInteractionEnabled = !EMPTY_API_VALUES.includes(flagTranslated)
const type = vessel.vesselType
Expand All @@ -117,7 +117,7 @@ export default function VesselGroupReportVesselsTable() {
<Fragment key={id}>
<div className={cx({ [styles.border]: !isLastRow }, styles.icon)}>
<VesselPin
vessel={vesselsRaw?.[index]}
vessel={vessel.identity}
disabled={!workspaceReady}
onClick={onPinClick}
/>
Expand All @@ -132,7 +132,7 @@ export default function VesselGroupReportVesselsTable() {
)}
</div>
<div className={cx({ [styles.border]: !isLastRow })}>
<span>{mmsi || EMPTY_FIELD_PLACEHOLDER}</span>
<span>{ssvid || EMPTY_FIELD_PLACEHOLDER}</span>
</div>
<div
className={cx({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,6 @@ export default function VesselGroupReportVesselsTableFooter() {
// const onAddToVesselGroup = () => {
// const dataviewIds = heatmapDataviews.map(({ id }) => id)
// dispatch(setVesselGroupConfirmationMode('saveAndNavigate'))
// if (dataviewIds?.length) {
// dispatch(setVesselGroupCurrentDataviewIds(dataviewIds))
// }
// trackEvent({
// category: TrackCategory.VesselGroups,
// action: 'add_to_vessel_group',
Expand Down
Loading
Loading