@@ -22,6 +22,7 @@ import { PANELS } from '../QueryToolConstants';
2222import { QueryToolContext } from '../QueryToolComponent' ;
2323
2424const StyledBox = styled ( Box ) ( ( { theme} ) => ( {
25+ position : 'relative' ,
2526 '& .GeometryViewer-mapContainer' : {
2627 backgroundColor : theme . palette . background . default ,
2728 height : '100%' ,
@@ -193,31 +194,40 @@ function parseData(rows, columns, column) {
193194 } ;
194195}
195196
196- // Find primary key column from columns array
197+ // Find primary key column i.e a column with unique values from columns array in Data Output tab
197198function findPkColumn ( columns ) {
198199 return columns . find ( c => PK_COLUMN_NAMES . includes ( c . name ) ) ;
199200}
200201
202+ // Hash function for row objects
203+ function hashRow ( row ) {
204+ const str = Object . keys ( row ) . sort ( ) . map ( k => `${ k } :${ row [ k ] } ` ) . join ( '|' ) ;
205+ let hash = 0 ;
206+ for ( let i = 0 ; i < str . length ; i ++ ) {
207+ const char = str . charCodeAt ( i ) ;
208+ hash = ( ( hash << 5 ) - hash ) + char ;
209+ hash = hash & hash ;
210+ }
211+ return `hash_${ hash } ` ;
212+ }
213+
201214// Get unique row identifier using PK column or first column
202215function getRowIdentifier ( row , pkColumn , columns ) {
203216 if ( pkColumn ?. key && row [ pkColumn . key ] !== undefined ) {
204217 return row [ pkColumn . key ] ;
205218 }
206219 const firstKey = columns [ 0 ] ?. key ;
207- return firstKey && row [ firstKey ] !== undefined ? row [ firstKey ] : JSON . stringify ( row ) ;
208- }
209-
210- // Create Set of row identifiers
211- function createIdentifierSet ( rowData , pkColumn , columns ) {
212- return new Set ( rowData . map ( row => getRowIdentifier ( row , pkColumn , columns ) ) ) ;
220+ if ( firstKey && row [ firstKey ] !== undefined ) {
221+ return row [ firstKey ] ;
222+ }
223+ return hashRow ( row ) ;
213224}
214225
215226// Match rows from previous selection to current rows
216- function matchRowSelection ( prevRowData , currentRows , pkColumn , columns ) {
217- if ( prevRowData . length === 0 ) return [ ] ;
227+ function matchRowSelection ( prevIdentifiers , currentRows , pkColumn , columns ) {
228+ if ( prevIdentifiers . size === 0 ) return [ ] ;
218229
219- const prevIdSet = createIdentifierSet ( prevRowData , pkColumn , columns ) ;
220- return currentRows . filter ( row => prevIdSet . has ( getRowIdentifier ( row , pkColumn , columns ) ) ) ;
230+ return currentRows . filter ( row => prevIdentifiers . has ( getRowIdentifier ( row , pkColumn , columns ) ) ) ;
221231}
222232
223233function PopupTable ( { data} ) {
@@ -314,41 +324,10 @@ GeoJsonLayer.propTypes = {
314324
315325function TheMap ( { data} ) {
316326 const mapObj = useMap ( ) ;
317- const infoControl = useRef ( null ) ;
318327 const resetLayersKey = useRef ( 0 ) ;
319328 const zoomControlWithHome = useRef ( null ) ;
320329 const homeCoordinates = useRef ( null ) ;
321330 useEffect ( ( ) => {
322- infoControl . current = Leaflet . control ( { position : 'topright' } ) ;
323- infoControl . current . onAdd = function ( ) {
324- let ele = Leaflet . DomUtil . create ( 'div' , 'geometry-viewer-info-control' ) ;
325- ele . innerHTML = data . infoList . join ( '<br />' ) ;
326- // Style the parent control container after it's added to the map
327- setTimeout ( ( ) => {
328- let controlContainer = ele . closest ( '.leaflet-control' ) ;
329- if ( controlContainer ) {
330- controlContainer . style . cssText = `
331- position: fixed;
332- top: 70%;
333- left: 50%;
334- transform: translate(-50%, -50%);
335- margin: 0;
336- max-width: 80%;
337- text-align: center;
338- white-space: normal;
339- word-wrap: break-word;
340- background: none;
341- box-shadow: none;
342- border: none;
343- font-size: 16px;
344- ` ;
345- }
346- } , 0 ) ;
347- return ele ;
348- } ;
349- if ( data . infoList . length > 0 ) {
350- infoControl . current . addTo ( mapObj ) ;
351- }
352331 resetLayersKey . current ++ ;
353332
354333 zoomControlWithHome . current = Leaflet . control . zoom ( {
@@ -398,7 +377,6 @@ function TheMap({data}) {
398377 zoomControlWithHome . current . addTo ( mapObj ) ;
399378
400379 return ( ) => {
401- infoControl . current ?. remove ( ) ;
402380 zoomControlWithHome . current ?. remove ( ) ;
403381 } ;
404382 } , [ data ] ) ;
@@ -409,6 +387,25 @@ function TheMap({data}) {
409387
410388 return (
411389 < >
390+ { data . infoList . length > 0 && (
391+ < div style = { {
392+ position : 'absolute' ,
393+ top : '50%' ,
394+ left : '50%' ,
395+ transform : 'translate(-50%, -50%)' ,
396+ zIndex : 1000 ,
397+ maxWidth : '80%' ,
398+ textAlign : 'center' ,
399+ whiteSpace : 'normal' ,
400+ wordWrap : 'break-word' ,
401+ fontSize : '16px' ,
402+ pointerEvents : 'none' ,
403+ } } >
404+ { data . infoList . map ( ( info , idx ) => (
405+ < div key = { idx } > { info } </ div >
406+ ) ) }
407+ </ div >
408+ ) }
412409 { data . selectedSRID === 4326 &&
413410 < LayersControl position = "topright" >
414411 < LayersControl . BaseLayer checked name = { gettext ( 'Empty' ) } >
@@ -492,7 +489,7 @@ export function GeometryViewer({rows, columns, column}) {
492489 const prevStateRef = React . useRef ( {
493490 columnKey : null ,
494491 columnNames : null ,
495- selectedRowData : [ ] ,
492+ selectedRowIdentifiers : new Set ( ) ,
496493 } ) ;
497494
498495 const [ mapKey , setMapKey ] = React . useState ( 0 ) ;
@@ -513,7 +510,7 @@ export function GeometryViewer({rows, columns, column}) {
513510 prevStateRef . current = {
514511 columnKey : null ,
515512 columnNames : null ,
516- selectedRowData : [ ] ,
513+ selectedRowIdentifiers : new Set ( ) ,
517514 } ;
518515 return ;
519516 }
@@ -524,32 +521,46 @@ export function GeometryViewer({rows, columns, column}) {
524521 prevStateRef . current = {
525522 columnKey : currentColumnKey ,
526523 columnNames : currentColumnNames ,
527- selectedRowData : rows ,
524+ selectedRowIdentifiers : new Set ( rows . map ( r => getRowIdentifier ( r , pkColumn , columns ) ) ) ,
528525 } ;
529526 return ;
530527 }
531528
532529 if ( currentColumnKey === prevState . columnKey &&
533530 currentColumnNames === prevState . columnNames &&
534531 rows . length > 0 ) {
535- prevStateRef . current . selectedRowData = displayRows ;
532+ prevStateRef . current . selectedRowIdentifiers = new Set (
533+ displayRows . map ( r => getRowIdentifier ( r , pkColumn , columns ) )
534+ ) ;
536535 }
537536 } , [ currentColumnKey , currentColumnNames , rows , pkColumn , columns ] ) ;
538537
539538 // Get rows to display based on selection
540539 const displayRows = React . useMemo ( ( ) => {
540+ // No geometry column selected or no rows available - nothing to display
541541 if ( ! currentColumnKey || rows . length === 0 ) return [ ] ;
542542 const prevState = prevStateRef . current ;
543+
544+ // Column context changed (different geometry column or different query schema)
545+ // Show all new rows since previous selection is no longer valid
543546 if ( currentColumnKey !== prevState . columnKey || currentColumnNames !== prevState . columnNames ) {
544547 return rows ;
545548 }
546549
547- const prevSelected = prevState . selectedRowData ;
548- if ( prevSelected . length === 0 ) return rows ;
549- if ( prevSelected . length < rows . length ) {
550- const matched = matchRowSelection ( prevSelected , rows , pkColumn , columns ) ;
550+ const prevIdentifiers = prevState . selectedRowIdentifiers ;
551+ // No previous selection recorded - show all rows
552+ if ( prevIdentifiers . size === 0 ) return rows ;
553+
554+ // Previous selection was a subset of total rows, meaning user had specific rows selected.
555+ // Try to match those previously selected rows in the new result set using stable
556+ // row identifiers (PK value, first column value, or hash fallback).
557+ // This handles the case where same query reruns with more/fewer rows
558+ if ( prevIdentifiers . size < rows . length ) {
559+ const matched = matchRowSelection ( prevIdentifiers , rows , pkColumn , columns ) ;
560+ // If matched rows found, show only those; otherwise fall back to all rows
551561 return matched . length > 0 ? matched : rows ;
552562 }
563+ // Previous selection covered all rows (or same count) - show all current rows
553564 return rows ;
554565 } , [ rows , currentColumnKey , currentColumnNames , pkColumn , columns ] ) ;
555566
0 commit comments