Skip to content

Commit 3900ee0

Browse files
authored
Merge pull request #756 from SlideRuleEarth/carlos-dev4
Carlos dev4
2 parents 4e669cd + a99d0bc commit 3900ee0

File tree

8 files changed

+337
-145
lines changed

8 files changed

+337
-145
lines changed

web-client/src/components/SrAtl03CnfColors.vue

Lines changed: 72 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,67 @@
11
<template>
2-
<div class="sr-legend-box" v-if="atl03CnfColorMapStore">
3-
<Fieldset
4-
class="sr-lb-fieldset"
5-
legend="Atl03 Cnf Colors"
6-
:toggleable="false"
7-
:collapsed="false"
8-
>
9-
<div v-for="option in atl03CnfOptions" :key="option.value" class="legend-item">
10-
<div class="color-box" :style="{ backgroundColor: atl03CnfColorMapStore.getColorForAtl03CnfValue(option.value) }"></div>
11-
<div class="label">{{ formatLabel(option.label) }} ({{ option.value }})</div>
12-
</div>
13-
</Fieldset>
14-
</div>
15-
<div v-else>
16-
Loading atl03CnfColorMap...
17-
</div>
2+
<div class="sr-legend-box" v-if="atl03CnfColorMapStore">
3+
<Fieldset
4+
class="sr-lb-fieldset"
5+
legend="Atl03 Cnf Colors"
6+
:toggleable="false"
7+
:collapsed="false"
8+
>
9+
<div v-for="option in atl03CnfOptions" :key="option.value" class="legend-item">
10+
<div
11+
class="color-box"
12+
:style="{ backgroundColor: atl03CnfColorMapStore.getColorForAtl03CnfValue(option.value) }"
13+
></div>
14+
<div class="label">{{ formatLabel(option.label) }} ({{ option.value }})</div>
15+
</div>
16+
</Fieldset>
17+
</div>
18+
<div v-else>Loading atl03CnfColorMap...</div>
1819
</template>
19-
20+
2021
<script setup lang="ts">
21-
import { onMounted, computed, watch, ref } from 'vue';
22-
import Fieldset from 'primevue/fieldset';
23-
import { useAtl03CnfColorMapStore } from '@/stores/atl03CnfColorMapStore';
24-
import { createLogger } from '@/utils/logger';
22+
import { onMounted, computed, watch, ref } from 'vue'
23+
import Fieldset from 'primevue/fieldset'
24+
import { useAtl03CnfColorMapStore } from '@/stores/atl03CnfColorMapStore'
25+
import { createLogger } from '@/utils/logger'
2526
26-
const logger = createLogger('SrAtl03CnfColors');
27+
const logger = createLogger('SrAtl03CnfColors')
2728
28-
const emit = defineEmits(['restore-atl03-color-defaults-click', 'atl03CnfColorChanged']);
29+
const emit = defineEmits(['restore-atl03-color-defaults-click', 'atl03CnfColorChanged'])
2930
const props = defineProps({
30-
reqIdStr: {
31-
type: String,
32-
required: true
33-
}
34-
});
31+
reqIdStr: {
32+
type: String,
33+
required: true
34+
}
35+
})
3536
36-
const atl03CnfColorMapStore = ref<any>(null);
37+
const atl03CnfColorMapStore = ref<any>(null)
3738
3839
onMounted(async () => {
39-
// Any initialization logic can go here
40-
atl03CnfColorMapStore.value = await useAtl03CnfColorMapStore(props.reqIdStr);
41-
});
40+
// Any initialization logic can go here
41+
atl03CnfColorMapStore.value = await useAtl03CnfColorMapStore(props.reqIdStr)
42+
})
4243
4344
// Reactive options computed from the store
44-
const atl03CnfOptions = computed(() => atl03CnfColorMapStore.value.atl03CnfOptions);
45+
const atl03CnfOptions = computed(() => atl03CnfColorMapStore.value.atl03CnfOptions)
4546
4647
// Watch for changes in the color map and trigger reactivity
4748
watch(
48-
() => atl03CnfColorMapStore.value?.atl03CnfColorMap,
49-
(newMap, _oldMap) => {
50-
// Emit an event or trigger any logic when the color map changes
51-
emit('atl03CnfColorChanged', newMap);
52-
logger.debug('Color map changed', { newMap });
53-
},
54-
{ deep: true } // Deep watch for changes inside the object
55-
);
49+
() => atl03CnfColorMapStore.value?.atl03CnfColorMap,
50+
(newMap, _oldMap) => {
51+
// Emit an event or trigger any logic when the color map changes
52+
emit('atl03CnfColorChanged', newMap)
53+
logger.debug('Color map changed', { newMap })
54+
},
55+
{ deep: true } // Deep watch for changes inside the object
56+
)
5657
5758
// Formatting labels for better readability
5859
const formatLabel = (label: string): string => {
59-
return label.replace(/^atl03_/, '').replace(/_/g, ' ');
60-
};
60+
if (!label) return ''
61+
return label.replace(/^atl03_/, '').replace(/_/g, ' ')
62+
}
6163
</script>
62-
64+
6365
<style scoped>
6466
.sr-legend-box {
6567
display: flex;
@@ -91,44 +93,43 @@ const formatLabel = (label: string): string => {
9193
}
9294
9395
.label {
94-
font-size:smaller;
96+
font-size: smaller;
9597
line-height: 1.2; /* Adjust line height */
9698
color: var(--p-primary-color);
9799
}
98100
99101
.sr-lb-fieldset {
100-
padding: 0.2rem; /* 3.2px equivalent */
101-
background-color: rgba(0, 0, 0, 0.2); /* Black with 50% transparency */
102-
border-radius: var(--p-border-radius);
103-
position: relative; /* Enable positioning for the legend */
102+
padding: 0.2rem; /* 3.2px equivalent */
103+
background-color: rgba(0, 0, 0, 0.2); /* Black with 50% transparency */
104+
border-radius: var(--p-border-radius);
105+
position: relative; /* Enable positioning for the legend */
104106
}
105107
106108
/* Custom Fieldset legend style */
107109
:deep(.sr-lb-fieldset .p-fieldset-legend) {
108-
white-space: nowrap;
109-
font-size: small;
110-
font-weight: normal;
111-
color: var(--p-primary-color);
112-
padding: 0.2rem;
113-
text-align: center;
114-
position: absolute;
115-
top: 0.5rem;
116-
left: 50%;
117-
transform: translate(-50%, -50%);
118-
background: transparent;
119-
border-radius: 0.25rem;
120-
border-color: transparent;
121-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
122-
z-index: 1;
123-
margin: 0.5rem;
124-
padding-left: 0.5rem;
125-
padding-right:0.5rem;
126-
padding-top: 0.5rem;
127-
padding-bottom: 0.5rem;
110+
white-space: nowrap;
111+
font-size: small;
112+
font-weight: normal;
113+
color: var(--p-primary-color);
114+
padding: 0.2rem;
115+
text-align: center;
116+
position: absolute;
117+
top: 0.5rem;
118+
left: 50%;
119+
transform: translate(-50%, -50%);
120+
background: transparent;
121+
border-radius: 0.25rem;
122+
border-color: transparent;
123+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
124+
z-index: 1;
125+
margin: 0.5rem;
126+
padding-left: 0.5rem;
127+
padding-right: 0.5rem;
128+
padding-top: 0.5rem;
129+
padding-bottom: 0.5rem;
128130
}
129131
130132
:deep(.p-fieldset-content-container) {
131-
padding-top: 1.5rem; /* Adjust padding to prevent overlap with the legend */
133+
padding-top: 1.5rem; /* Adjust padding to prevent overlap with the legend */
132134
}
133135
</style>
134-

web-client/src/components/SrAtl08Colors.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const atl08ClassOptions = computed(() => atl08ClassColorMapStore.value?.atl08Cla
4141
4242
// Function to format the label
4343
const formatLabel = (label: string): string => {
44+
if (!label) return ''
4445
return label.replace(/^atl08_/, '').replace(/_/g, ' ')
4546
}
4647
</script>

web-client/src/components/SrAtl24Colors.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const atl24ClassOptions = computed(() => atl24ClassColorMapStore.value?.atl24Cla
4141
4242
// Function to format the label
4343
const formatLabel = (label: string): string => {
44+
if (!label) return ''
4445
return label.replace(/^atl24_/, '').replace(/_/g, ' ')
4546
}
4647
</script>

web-client/src/components/SrEditDesc.vue

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ref, watch, onMounted } from 'vue'
44
import InputText from 'primevue/inputtext'
55
import FloatLabel from 'primevue/floatlabel'
66
import { useSrToastStore } from '@/stores/srToastStore'
7-
import { getCenter } from '@/utils/geoUtils'
7+
import { getCenter, calculateBounds } from '@/utils/geoUtils'
88
import SrCustomTooltip from '@/components/SrCustomTooltip.vue'
99
import { createLogger } from '@/utils/logger'
1010
@@ -32,38 +32,110 @@ const fetchDescription = async () => {
3232
descrRef.value = await db.getDescription(props.reqId)
3333
//console.log('fetchDescription called with reqId:', props.reqId,'descrRef.value:', descrRef.value);
3434
if (!descrRef.value) {
35-
const status = await db.getStatus(props.reqId)
36-
if (status === 'success' || status === 'imported') {
37-
const summary = await db.getWorkerSummary(props.reqId)
38-
if (summary && summary.extLatLon) {
39-
const c = getCenter(summary.extLatLon)
40-
// Fetch address data from OpenStreetMap
41-
const response = await fetch(
42-
`https://nominatim.openstreetmap.org/reverse?format=json&lat=${c.lat}&lon=${c.lon}`
43-
)
44-
const data = await response.json()
45-
const descr = data.display_name
46-
logger.debug('fetchDescription New Description', { descr })
47-
// If display_name is available, update the request record
48-
if (data && descr) {
49-
descrRef.value = descr
35+
try {
36+
const poly = await db.getSvrReqPoly(props.reqId)
37+
38+
// Check if poly is valid array with data
39+
// getSvrReqPoly returns {} as SrRegion when svr_parms doesn't have polygon data
40+
const isValidPoly = poly && Array.isArray(poly) && poly.length > 0
41+
42+
if (isValidPoly) {
43+
const bounds = calculateBounds(poly)
44+
if (!bounds) {
45+
logger.warn('fetchDescription Failed to calculate bounds from polygon', {
46+
reqId: props.reqId
47+
})
48+
descrRef.value = 'Location data unavailable'
49+
return
50+
}
51+
52+
const c = getCenter(bounds)
53+
54+
// Validate coordinates before attempting fetch
55+
if (c.lat === 0 && c.lon === 0) {
56+
logger.warn('fetchDescription Invalid coordinates (0,0), skipping geocoding', {
57+
reqId: props.reqId
58+
})
59+
descrRef.value = 'Location unavailable'
60+
return
61+
}
62+
63+
// Validate coordinates are within valid range
64+
if (Math.abs(c.lat) > 90 || Math.abs(c.lon) > 180) {
65+
logger.warn('fetchDescription Invalid coordinates out of range', {
66+
reqId: props.reqId,
67+
lat: c.lat,
68+
lon: c.lon
69+
})
70+
descrRef.value = 'Invalid location coordinates'
71+
return
72+
}
73+
74+
try {
75+
// Fetch address data from OpenStreetMap
76+
const response = await fetch(
77+
`https://nominatim.openstreetmap.org/reverse?format=json&lat=${c.lat}&lon=${c.lon}`,
78+
{ signal: AbortSignal.timeout(5000) } // 5 second timeout
79+
)
80+
81+
if (!response.ok) {
82+
throw new Error(`Geocoding failed with status ${response.status}`)
83+
}
84+
85+
const data = await response.json()
86+
const descr = data.display_name
87+
logger.debug('fetchDescription New Description', { descr })
88+
// If display_name is available, update the request record
89+
if (data && descr) {
90+
descrRef.value = descr
91+
void db.updateRequest(props.reqId, { description: descrRef.value })
92+
}
93+
} catch (error) {
94+
logger.warn('fetchDescription Failed to fetch location name', {
95+
error: error instanceof Error ? error.message : String(error),
96+
lat: c.lat,
97+
lon: c.lon
98+
})
99+
// Set a fallback description with coordinates
100+
descrRef.value = `Location: ${c.lat.toFixed(4)}, ${c.lon.toFixed(4)}`
50101
void db.updateRequest(props.reqId, { description: descrRef.value })
51102
}
52103
} else {
53-
logger.debug('fetchDescription No extLatLon found (data may still be processing)', {
54-
reqId: props.reqId
104+
// No valid polygon found in svr_parms
105+
logger.warn('fetchDescription No valid polygon in svr_parms', {
106+
reqId: props.reqId,
107+
polyType: typeof poly,
108+
isArray: Array.isArray(poly),
109+
polyLength: Array.isArray(poly) ? poly.length : 'N/A'
110+
})
111+
descrRef.value = 'Location data not available'
112+
}
113+
} catch (error) {
114+
// Error accessing svr_parms or request record
115+
const request = await db.getRequest(props.reqId)
116+
const isSuccess = request?.status === 'success'
117+
118+
if (isSuccess) {
119+
logger.error('fetchDescription Error getting svr_parms polygon', {
120+
reqId: props.reqId,
121+
status: request?.status,
122+
error: error instanceof Error ? error.message : String(error)
123+
})
124+
} else {
125+
logger.warn('fetchDescription Error getting svr_parms polygon', {
126+
reqId: props.reqId,
127+
status: request?.status,
128+
error: error instanceof Error ? error.message : String(error)
55129
})
56-
// Handle the case where no extLatLon is found
57130
}
58-
} else {
59-
logger.warn('fetchDescription No description available for status', { status })
131+
descrRef.value = 'Unable to determine location'
60132
}
61133
} else {
62134
//console.log('fetchDescription Description:', descrRef.value);
63135
// Update the store with the fetched description
64136
}
65137
} else {
66-
descrRef.value = 'fetchDescription No description available'
138+
descrRef.value = `fetchDescription No description available for props:${props.reqId}`
67139
}
68140
//console.log('fetchDescription FINAL Description:', descrRef.value);
69141
}

web-client/src/components/SrJsonDisplayDialog.vue

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,38 @@ const jsonBlock = ref<HTMLElement | null>(null)
2222
2323
const prettyJson = computed(() => {
2424
try {
25+
// Handle null, undefined, or empty string
26+
if (!props.jsonData || (typeof props.jsonData === 'string' && props.jsonData.trim() === '')) {
27+
return 'No data available'
28+
}
29+
30+
// Handle empty object
31+
if (typeof props.jsonData === 'object' && Object.keys(props.jsonData).length === 0) {
32+
return 'No data available'
33+
}
34+
2535
const jsonObj = typeof props.jsonData === 'string' ? JSON.parse(props.jsonData) : props.jsonData
2636
return JSON.stringify(jsonObj, null, 2)
27-
} catch {
28-
return 'Invalid JSON'
37+
} catch (error) {
38+
logger.warn('Failed to parse JSON data', {
39+
error: error instanceof Error ? error.message : String(error),
40+
dataType: typeof props.jsonData
41+
})
42+
return 'Invalid JSON format'
2943
}
3044
})
3145
3246
const highlightedJson = computed(() => {
33-
const result = hljs.highlight(prettyJson.value, { language: 'json' })
34-
return result.value
47+
try {
48+
const result = hljs.highlight(prettyJson.value, { language: 'json' })
49+
return result.value
50+
} catch (error) {
51+
logger.warn('Failed to highlight JSON', {
52+
error: error instanceof Error ? error.message : String(error)
53+
})
54+
// Return plain text if highlighting fails
55+
return prettyJson.value
56+
}
3557
})
3658
3759
const copyToClipboard = async () => {

0 commit comments

Comments
 (0)