Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a17cd85
psp-11168 ensure that enriched region/district is added to property s…
devinleighsmith Jan 22, 2026
35524d5
update snapshots.
devinleighsmith Jan 22, 2026
a546fd7
only show the parcel map outage warning once.
devinleighsmith Jan 22, 2026
45327a4
Merge pull request #5172 from devinleighsmith/psp-11168
asanchezr Jan 22, 2026
c6a8b2d
Implement modal when user exits to avoid losing changes
areyeslo Jan 5, 2026
992baef
Create hook to avoid duplicated code
areyeslo Jan 7, 2026
5123027
Update properties after change
areyeslo Jan 10, 2026
36bd26b
Waiting for fetching changes and formik to update dirty state
areyeslo Jan 14, 2026
913987f
Changes in onSuccess async
areyeslo Jan 14, 2026
773bc7b
ConfirmNavigation fix for updating properties
areyeslo Jan 15, 2026
c73caa2
Merge pull request #5173 from areyeslo/hotfix/PSP-11013-test
areyeslo Jan 23, 2026
f794ce3
selectedFeatureDatasets includes PIMS or PMBC properties depending on…
areyeslo Jan 27, 2026
f9e3709
Merge pull request #5178 from areyeslo/hotfix/PSP-10976-SearchControl
areyeslo Jan 28, 2026
977d515
Do not reset the form if user wants to proceed
areyeslo Jan 31, 2026
377ff88
Merge pull request #5183 from areyeslo/hotfix/PSP-11180-DispositionFiles
areyeslo Feb 2, 2026
510887e
psp-11096 handle properties with no boundaries but with locations.
devinleighsmith Feb 4, 2026
7e8371b
Merge pull request #5189 from devinleighsmith/test
asanchezr Feb 5, 2026
c4cadf7
Merge remote-tracking branch 'upstream/test' into backmerge_test_to_dev
devinleighsmith Feb 5, 2026
d1e24ea
Update snapshots
asanchezr Feb 5, 2026
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
4 changes: 2 additions & 2 deletions source/backend/api/Pims.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<PackageReference Include="prometheus-net.AspNetCore.HealthChecks" Version="8.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.9.0" />

<!-- Transitive dependency overrides for security vulnerabilities -->
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
Expand Down Expand Up @@ -101,4 +101,4 @@
<Folder Include="Areas\Keycloak\Mapping\User\" />
<Folder Include="Helpers\Swagger\" />
</ItemGroup>
</Project>
</Project>
10 changes: 9 additions & 1 deletion source/frontend/src/components/common/MoreOptionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface IMoreOptionsMenuProps {
/** List of menu options */
options: MenuOption[];
dataTestid?: string;
/** Called when the menu is opened */
onMenuOpen?: () => void;
}

/**
Expand All @@ -43,9 +45,15 @@ const MoreOptionsMenu: React.FC<IMoreOptionsMenuProps> = ({
alignRight = true,
variant = 'light',
dataTestid,
onMenuOpen,
}) => {
return (
<Dropdown alignRight={alignRight}>
<Dropdown
alignRight={alignRight}
onToggle={isOpen => {
if (isOpen) onMenuOpen?.();
}}
>
<TooltipWrapper tooltipId="more-options-tooltip" tooltip="More options...">
<StyledToggleButton
id="dropdown-ellipsis"
Expand Down
7 changes: 6 additions & 1 deletion source/frontend/src/components/common/Section/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface SectionProps {
isCollapsable?: boolean;
initiallyExpanded?: boolean;
noPadding?: boolean;
hideOverflow?: boolean;
}

export const Section: React.FC<
Expand All @@ -28,6 +29,7 @@ export const Section: React.FC<
initiallyExpanded,
noPadding,
className,
hideOverflow,
...rest
}) => {
const [isCollapsed, setIsCollapsed] = useState<boolean>(!(initiallyExpanded === true));
Expand All @@ -40,7 +42,10 @@ export const Section: React.FC<
{exists(header) && (
<StyledSectionHeader isStyledHeader={isStyledHeader}>
<Row className="no-gutters">
<Col className="align-content-end" style={{ overflow: 'hidden' }}>
<Col
className="align-content-end"
style={{ overflow: hideOverflow === true ? 'hidden' : '' }}
>
{header}
</Col>
{isCollapsable && (
Expand Down
20 changes: 10 additions & 10 deletions source/frontend/src/components/common/mapFSM/useMapSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export const useMapSearch = () => {
findPropertyIdsByProjectTask,
]);

const validFeatures = properties.features?.filter(
const validFeatures = properties?.features?.filter(
feature =>
!!feature?.geometry && projectPropertyIds.includes(feature.properties.PROPERTY_ID),
);
Expand Down Expand Up @@ -355,10 +355,10 @@ export const useMapSearch = () => {
highwayPlanFeatures: emptyHighwayFeatures,
};

if (validFeatures.length === 0) {
if (validFeatures?.length === 0) {
toast.info('No search results found');
} else {
toast.info(`${validFeatures.length} properties found`);
toast.info(`${validFeatures?.length} properties found`);
}
}
} catch (error) {
Expand Down Expand Up @@ -469,20 +469,20 @@ export const useMapSearch = () => {
features: [...(pinPmbcData?.features || []), ...(pidPmbcData?.features || [])],
bbox: pinPmbcData?.bbox || pidPmbcData?.bbox,
};
const validPimsFeatures = pidPinInventoryData.features.filter(feature => exists(feature));
const validPimsFeatures = pidPinInventoryData?.features?.filter(feature => exists(feature));

//filter out any pmbc features that do not have geometry, or are part of the pims feature result set.
const validPmbcFeatures = attributedFeatures.features.filter(feature => exists(feature));
const validPmbcFeatures = attributedFeatures?.features?.filter(feature => exists(feature));
result = {
pimsFeatures: validPimsFeatures.length
pimsFeatures: validPimsFeatures?.length
? {
type: pidPinInventoryData.type,
bbox: pidPinInventoryData.bbox,
features: validPimsFeatures,
}
: emptyPimsFeatureCollection,
pimsLiteFeatures: emptyPimsLiteFeatureCollection,
fullyAttributedFeatures: validPmbcFeatures
fullyAttributedFeatures: validPmbcFeatures?.length
? {
type: attributedFeatures.type,
bbox: attributedFeatures.bbox,
Expand All @@ -493,10 +493,10 @@ export const useMapSearch = () => {
highwayPlanFeatures: emptyHighwayFeatures,
};

if (validPmbcFeatures.length === 0 && validPimsFeatures.length === 0) {
if (validPmbcFeatures?.length === 0 && validPimsFeatures?.length === 0) {
toast.info('No search results found');
} else {
toast.info(`${validPmbcFeatures.length + validPimsFeatures.length} properties found`);
toast.info(`${validPmbcFeatures?.length + validPimsFeatures?.length} properties found`);
}
} catch (error) {
toast.error((error as Error).message, { autoClose: 7000 });
Expand Down Expand Up @@ -550,7 +550,7 @@ export const useMapSearch = () => {
pimsLiteFeatures: {
type: pidPinInventoryData.type,
bbox: pidPinInventoryData.bbox,
features: validFeatures.map(vf => ({
features: validFeatures?.map(vf => ({
type: vf.type,
geometry: vf.geometry ?? vf?.properties?.LOCATION,
id: vf.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ exports[`FilterContentForm component > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
Show Ownership
</div>
Expand Down Expand Up @@ -620,7 +619,6 @@ exports[`FilterContentForm component > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
Project
</div>
Expand Down Expand Up @@ -733,7 +731,6 @@ exports[`FilterContentForm component > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
Tenure
</div>
Expand Down Expand Up @@ -1124,7 +1121,6 @@ exports[`FilterContentForm component > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
Lease / Licence
</div>
Expand Down Expand Up @@ -1752,7 +1748,6 @@ exports[`FilterContentForm component > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
Anomaly
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ exports[`LayersMenu View > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
PIMS
</div>
Expand Down Expand Up @@ -405,7 +404,6 @@ exports[`LayersMenu View > renders as expected 1`] = `
>
<div
class="align-content-end col"
style="overflow: hidden;"
>
External
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const SearchContainer: React.FC<ISearchContainerProps> = ({ View }) => {
const pathGenerator = usePathGenerator();

const { findDistrict, findRegion } = useAdminBoundaryMapLayer();
const [isPimsActive, setIsPimsActive] = useState(false);

const handleMapFilterChange = (filter: IPropertyFilter) => {
if (['coordinates', 'name', 'address'].includes(filter.searchBy)) {
Expand Down Expand Up @@ -70,23 +71,43 @@ export const SearchContainer: React.FC<ISearchContainerProps> = ({ View }) => {

// Base dataset (no region/district yet)
const baseDatasets = useMemo<SelectedFeatureDataset[]>(() => {
return (
mapFeatureData?.fullyAttributedFeatures.features.map<SelectedFeatureDataset>(pmbcParcel => {
const center = getFeatureBoundedCenter(pmbcParcel);
return {
parcelFeature: pmbcParcel,
pimsFeature: null,
location: { lat: center[1], lng: center[0] },
regionFeature: null,
fileLocation: null,
fileBoundary: null,
districtFeature: null,
municipalityFeature: null,
selectingComponentId: null,
};
}) ?? []
);
}, [mapFeatureData?.fullyAttributedFeatures?.features]);
if (isPimsActive) {
return (
mapFeatureData?.pimsFeatures.features.map<SelectedFeatureDataset>(pimsParcel => {
const center = getFeatureBoundedCenter(pimsParcel);
return {
parcelFeature: null,
pimsFeature: pimsParcel,
location: { lat: center[1], lng: center[0] },
regionFeature: null,
fileLocation: null,
fileBoundary: null,
districtFeature: null,
municipalityFeature: null,
selectingComponentId: null,
};
}) ?? []
);
} else {
return (
mapFeatureData?.fullyAttributedFeatures.features.map<SelectedFeatureDataset>(pmbcParcel => {
const center = getFeatureBoundedCenter(pmbcParcel);
return {
parcelFeature: pmbcParcel,
pimsFeature: null,
location:
exists(center) && center.length >= 2 ? { lat: center[1], lng: center[0] } : null,
regionFeature: null,
fileLocation: null,
fileBoundary: null,
districtFeature: null,
municipalityFeature: null,
selectingComponentId: null,
};
}) ?? []
);
}
}, [mapFeatureData, isPimsActive]);

// Enrich dataset with region/district info
const [selectedFeatureDatasets, setSelectedFeatureDatasets] = useState<SelectedFeatureDataset[]>(
Expand Down Expand Up @@ -169,13 +190,15 @@ export const SearchContainer: React.FC<ISearchContainerProps> = ({ View }) => {
propertyFilter={mapSearchCriteria ?? defaultPropertyFilter}
onFilterChange={handleMapFilterChange}
searchResult={mapFeatureData}
selectedFeatureDatasets={selectedFeatureDatasets}
canAddToOpenFile={isEditPropertiesMode}
onCreateResearchFile={onCreateResearchFile}
onCreateAcquisitionFile={onCreateAcquisitionFile}
onCreateDispositionFile={onCreateDispositionFile}
onCreateLeaseFile={onCreateLeaseFile}
onCreateManagementFile={onCreateManagementFile}
onAddToOpenFile={onAddToOpenFile}
setIsPimsActive={setIsPimsActive}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import LeaseIcon from '@/assets/images/lease-icon.svg?react';
import ManagementIcon from '@/assets/images/management-icon.svg?react';
import ResearchIcon from '@/assets/images/research-icon.svg?react';
import { MapFeatureData } from '@/components/common/mapFSM/models';
import { SelectedFeatureDataset } from '@/components/common/mapFSM/useLocationFeatureLoader';
import MoreOptionsMenu, { MenuOption } from '@/components/common/MoreOptionsMenu';
import { Section } from '@/components/common/Section/Section';
import { SimpleSectionHeader } from '@/components/common/SimpleSectionHeader';
Expand All @@ -23,7 +24,6 @@ import { ParcelDataset } from '@/features/properties/parcelList/models';
import { ParcelListContainer } from '@/features/properties/parcelList/ParcelListContainer';
import { ParcelListView } from '@/features/properties/parcelList/ParcelListView';
import useKeycloakWrapper from '@/hooks/useKeycloakWrapper';
import { PMBC_FullyAttributed_Feature_Properties } from '@/models/layers/parcelMapBC';
import { PIMS_Property_View } from '@/models/layers/pimsPropertyView';
import { exists } from '@/utils';
import { isStrataCommonProperty } from '@/utils/propertyUtils';
Expand All @@ -34,13 +34,15 @@ export interface ISearchViewProps {
onFilterChange: (filter: IPropertyFilter) => void;
propertyFilter: IPropertyFilter;
searchResult: MapFeatureData;
selectedFeatureDatasets?: SelectedFeatureDataset[];
canAddToOpenFile?: boolean;
onCreateResearchFile: () => void;
onCreateAcquisitionFile: () => void;
onCreateDispositionFile: () => void;
onCreateLeaseFile: () => void;
onCreateManagementFile: () => void;
onAddToOpenFile: () => void;
setIsPimsActive: (value: boolean) => void;
}

interface PropertyProjection<T> {
Expand All @@ -54,31 +56,29 @@ interface PropertyProjection<T> {
export const SearchView: React.FC<ISearchViewProps> = props => {
const keycloak = useKeycloakWrapper();

const groupedFeatures = chain(props.searchResult?.fullyAttributedFeatures.features)
.groupBy(feature => feature?.properties?.PLAN_NUMBER)
.map(
planGroup =>
planGroup
?.map<PropertyProjection<PMBC_FullyAttributed_Feature_Properties>>(x => ({
pid: x.properties.PID_FORMATTED,
pin: exists(x.properties.PIN) ? String(x.properties.PIN) : null,
isStrataLot: isStrataCommonProperty(x),
feature: x,
plan: x.properties.PLAN_NUMBER,
}))
.sort((a, b) => {
if (a.isStrataLot === b.isStrataLot) return 0;
if (a.isStrataLot) return -1;
if (b.isStrataLot) return 1;
return 0;
}) ?? [],
);
const propertyProjections = useMemo(() => {
const fallbackFeatures = props.searchResult?.fullyAttributedFeatures?.features ?? [];

const baseParcels = props.selectedFeatureDatasets?.length
? props.selectedFeatureDatasets.map(dataset =>
ParcelDataset.fromSelectedFeatureDataset(dataset),
)
: fallbackFeatures.map(feature => ParcelDataset.fromFullyAttributedFeature(feature));

const propertyProjections =
groupedFeatures
return chain(baseParcels)
.groupBy(parcel => parcel.pmbcFeature?.properties?.PLAN_NUMBER)
.map(group =>
group.toSorted((a, b) => {
const aIsStrata = a.pmbcFeature ? isStrataCommonProperty(a.pmbcFeature) : false;
const bIsStrata = b.pmbcFeature ? isStrataCommonProperty(b.pmbcFeature) : false;

if (aIsStrata === bIsStrata) return 0;
return aIsStrata ? -1 : 1;
}),
)
.value()
.flatMap(x => x)
.map(x => ParcelDataset.fromFullyAttributedFeature(x.feature)) ?? [];
.flat();
}, [props.searchResult, props.selectedFeatureDatasets]);

const pimsGroupedFeatures = chain(props.searchResult?.pimsFeatures.features)
.groupBy(feature => feature?.properties?.SURVEY_PLAN_NUMBER)
Expand Down Expand Up @@ -184,7 +184,11 @@ export const SearchView: React.FC<ISearchViewProps> = props => {
className="my-0 py-0"
header={
<SimpleSectionHeader title="Results (PMBC)">
<MoreOptionsMenu options={menuOptions} ariaLabel="search pmbc results more options" />
<MoreOptionsMenu
options={menuOptions}
ariaLabel="search pmbc results more options"
onMenuOpen={() => props.setIsPimsActive(false)}
/>
</SimpleSectionHeader>
}
isCollapsable
Expand All @@ -197,7 +201,11 @@ export const SearchView: React.FC<ISearchViewProps> = props => {
className="my-0 py-0"
header={
<SimpleSectionHeader title="Results (PIMS)">
<MoreOptionsMenu options={menuOptions} ariaLabel="search pims results more options" />
<MoreOptionsMenu
options={menuOptions}
ariaLabel="search pims results more options"
onMenuOpen={() => props.setIsPimsActive(true)}
/>
</SimpleSectionHeader>
}
isCollapsable
Expand Down
Loading
Loading