Skip to content

Commit 8837feb

Browse files
authored
Merge pull request #914 from SlideRuleEarth/carlos-dev4
Carlos dev4
2 parents 4c64d28 + 46a2dea commit 8837feb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3757
-533
lines changed

web-client/src/App.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,14 @@ async function handleLongTourButtonClick() {
676676
<template>
677677
<div class="app-layout">
678678
<div>
679-
<SrToast position="top-left" />
679+
<SrToast position="top-left">
680+
<template #message="slotProps">
681+
<div class="sr-toast-content">
682+
<span class="sr-toast-summary">{{ slotProps.message.summary }}</span>
683+
<div class="sr-toast-detail" v-html="slotProps.message.detail"></div>
684+
</div>
685+
</template>
686+
</SrToast>
680687
</div>
681688
<header class="app-header">
682689
<SrAppBar

web-client/src/components/SrJsonEditDialog.vue

Lines changed: 140 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
<script setup lang="ts">
22
import { ref, computed, watch, onMounted, nextTick } from 'vue'
3-
import type { Ref } from 'vue'
43
import Dialog from 'primevue/dialog'
54
import Button from 'primevue/button'
65
import Textarea from 'primevue/textarea'
6+
import Select from 'primevue/select'
77
import SrJsonDiffViewer from './SrJsonDiffViewer.vue'
8-
import hljs from 'highlight.js/lib/core'
9-
import json from 'highlight.js/lib/languages/json'
10-
import 'highlight.js/styles/atom-one-dark.css'
8+
import SrParmsFormatTabs from './SrParmsFormatTabs.vue'
9+
import { missionItems, iceSat2APIsItems, gediAPIsItems } from '@/types/SrStaticOptions'
1110
import type { ZodTypeAny } from 'zod'
1211
import { useJsonImporter } from '@/composables/SrJsonImporter'
1312
import { importRequestJsonToStore } from '@/utils/importRequestToStore'
@@ -27,8 +26,6 @@ const mapStore = useMapStore()
2726
2827
const toast = useToast()
2928
30-
hljs.registerLanguage('json', json)
31-
3229
function showToast(summary: string, detail: string, severity = 'warn') {
3330
toast.add({
3431
severity,
@@ -41,19 +38,16 @@ const props = withDefaults(
4138
defineProps<{
4239
zodSchema: ZodTypeAny
4340
width?: string
44-
title?: string
4541
}>(),
4642
{
47-
width: '60vw',
48-
title: 'JSON Viewer'
43+
width: '60vw'
4944
}
5045
)
5146
5247
const emit = defineEmits<{
5348
(_e: 'json-valid', _value: unknown): void
5449
}>()
5550
56-
const jsonBlock = ref<HTMLElement | null>(null)
5751
const editableReqJson = ref('')
5852
const parsedEditableReqJson = computed(() => {
5953
try {
@@ -94,12 +88,70 @@ const hasChangesToApply = computed(() => {
9488
return JSON.stringify(parsedEditableReqJson.value) !== JSON.stringify(parsedCurrentReqJson.value)
9589
})
9690
97-
const readonlyHighlightedJson = computed(() => {
98-
return hljs.highlight(currentReqJson.value, { language: 'json' }).value
91+
// Compute automatic fields based on selected API
92+
// These fields are auto-populated by the system and shouldn't show force checkboxes
93+
const computedAutomaticFields = computed(() => {
94+
const baseFields = ['asset', 'output', 'cmr']
95+
const api = reqParamsStore.iceSat2SelectedAPI
96+
97+
// Add API-specific automatic fields
98+
if (api === 'atl03x-surface' || api === 'atl06p') {
99+
baseFields.push('fit')
100+
} else if (api === 'atl03x-phoreal' || api === 'atl08p') {
101+
baseFields.push('phoreal')
102+
} else if (api === 'atl24x') {
103+
baseFields.push('atl24')
104+
} else if (api === 'atl13x') {
105+
baseFields.push('atl13')
106+
}
107+
108+
return new Set(baseFields)
99109
})
100110
101111
const fileInputRef = ref<HTMLInputElement | null>(null)
102112
113+
// Endpoint selector state (used in header)
114+
const selectedMission = ref(reqParamsStore.missionValue)
115+
const selectedAPI = ref(reqParamsStore.getCurAPIStr())
116+
117+
// Computed API options based on selected mission
118+
const apiOptions = computed(() => {
119+
return selectedMission.value === 'ICESat-2' ? iceSat2APIsItems : gediAPIsItems
120+
})
121+
122+
// Update selected API when mission changes
123+
watch(selectedMission, (newMission) => {
124+
const options = newMission === 'ICESat-2' ? iceSat2APIsItems : gediAPIsItems
125+
// If current API is not in new mission's options, reset to first option
126+
if (!options.includes(selectedAPI.value)) {
127+
selectedAPI.value = options[0]
128+
}
129+
})
130+
131+
// Handle mission change from header selector
132+
function handleMissionChange() {
133+
reqParamsStore.setMissionValue(selectedMission.value)
134+
// Update API in store based on new mission
135+
if (selectedMission.value === 'ICESat-2') {
136+
reqParamsStore.setIceSat2API(selectedAPI.value)
137+
} else {
138+
reqParamsStore.setGediAPI(selectedAPI.value)
139+
}
140+
// Refresh the request parameters display
141+
updateEditableJsonFromStore()
142+
}
143+
144+
// Handle API change from header selector
145+
function handleAPIChange() {
146+
if (selectedMission.value === 'ICESat-2') {
147+
reqParamsStore.setIceSat2API(selectedAPI.value)
148+
} else {
149+
reqParamsStore.setGediAPI(selectedAPI.value)
150+
}
151+
// Refresh the request parameters display
152+
updateEditableJsonFromStore()
153+
}
154+
103155
const { data: importedData, error: importError, importJson } = useJsonImporter(props.zodSchema)
104156
105157
const importFromFile = () => {
@@ -194,27 +246,17 @@ const copyEditableReqJsonToClipboard = async () => {
194246
}
195247
196248
watch(computedShowParamsDialog, (newVal) => {
197-
//console.log('SrJsonEditDialog watch showParamsDialog changed:', newVal);
198249
if (newVal) {
199-
//console.log('SrJsonEditDialog watch showParamsDialog Dialog opened, highlighting JSON.');
250+
// Initialize endpoint selectors with current store values
251+
selectedMission.value = reqParamsStore.missionValue
252+
selectedAPI.value = reqParamsStore.getCurAPIStr()
200253
updateEditableJsonFromStore()
201-
void nextTick(() => highlightJson())
202254
} else {
203-
//console.log('SrJsonEditDialog watch showParamsDialog Dialog closed.');
204255
// Zoom to poly if it exists
205256
zoomToPoly()
206257
}
207258
})
208259
209-
const highlightJson = () => {
210-
logger.debug('Highlighting JSON in readonly panel')
211-
if (jsonBlock.value) {
212-
jsonBlock.value.removeAttribute('data-highlighted') // allow re-highlighting
213-
jsonBlock.value.innerHTML = readonlyHighlightedJson.value // replace with fresh content
214-
hljs.highlightElement(jsonBlock.value)
215-
}
216-
}
217-
218260
function updateEditableJsonFromStore() {
219261
currentReqObj.value = reqParamsStore.getAtlxxReqParams(0)
220262
editableReqJson.value = JSON.stringify(currentReqObj.value, null, 2)
@@ -243,24 +285,6 @@ const importToStore = () => {
243285
isValidJson.value = false
244286
}
245287
}
246-
function exportToFile(json: string | Ref<string>) {
247-
const jsonString = typeof json === 'string' ? json : json.value
248-
249-
const defaultName = `sliderule-request-${new Date().toISOString().replace(/[:.]/g, '-')}.json`
250-
const filename = prompt('Enter file name to save:', defaultName)
251-
252-
if (!filename) return // user cancelled
253-
254-
const blob = new Blob([jsonString], { type: 'application/json' })
255-
const url = URL.createObjectURL(blob)
256-
257-
const a = document.createElement('a')
258-
a.href = url
259-
a.download = filename.endsWith('.json') ? filename : `${filename}.json`
260-
a.click()
261-
262-
URL.revokeObjectURL(url)
263-
}
264288
265289
function handleParamsAccessed(index: number) {
266290
logger.debug('Params accessed at index (pre-flush)', { index })
@@ -365,8 +389,24 @@ function zoomToPoly() {
365389
:modal="true"
366390
:closable="true"
367391
:style="{ width: props.width }"
368-
:header="props.title"
369392
>
393+
<template #header>
394+
<div class="endpoint-header">
395+
<span class="endpoint-label">endpoint =</span>
396+
<Select
397+
v-model="selectedMission"
398+
:options="missionItems"
399+
class="endpoint-mission-select"
400+
@change="handleMissionChange"
401+
/>
402+
<Select
403+
v-model="selectedAPI"
404+
:options="apiOptions"
405+
class="endpoint-api-select"
406+
@change="handleAPIChange"
407+
/>
408+
</div>
409+
</template>
370410
<div class="sr-dialog-container">
371411
<div class="json-dual-panel">
372412
<!-- Editable panel -->
@@ -416,34 +456,17 @@ function zoomToPoly() {
416456
/>
417457
</div>
418458
</div>
419-
<!-- Readonly panel -->
459+
<!-- Current Request State panel with format tabs -->
420460
<div class="json-pane">
421461
<h3 class="pane-title">Current Request State</h3>
422-
<!-- eslint-disable-next-line vue/no-v-html -->
423-
<pre ref="jsonBlock" v-html="readonlyHighlightedJson"></pre>
424-
<div class="copy-btn-container">
425-
<Button
426-
label="Copy to clipboard"
427-
size="small"
428-
icon="pi pi-copy"
429-
@click="copyEditableReqJsonToClipboard"
430-
class="copy-btn"
431-
/>
432-
<Button
433-
label="Output to File"
434-
size="small"
435-
icon="pi pi-file-export"
436-
@click="exportToFile(editableReqJson)"
437-
class="copy-btn"
438-
/>
439-
</div>
462+
<SrParmsFormatTabs :rcvdParms="currentReqObj" :endpoint="selectedAPI" mode="sending" />
440463
</div>
441464
</div>
442465
<div class="sr-diff-footer">
443466
<SrJsonDiffViewer
444467
:before="parsedEditableReqJson"
445468
:after="parsedCurrentReqJson"
446-
:automaticFields="new Set(['asset', 'output', 'cmr'])"
469+
:automaticFields="computedAutomaticFields"
447470
beforeLabel="Editable Request"
448471
afterLabel="Current Request State"
449472
@forced-req_params="handleParamsAccessed"
@@ -492,12 +515,44 @@ pre {
492515
.json-dual-panel {
493516
display: flex;
494517
gap: 1rem;
518+
align-items: stretch;
495519
}
496520
497521
.json-pane {
498522
flex: 1;
499523
display: flex;
500524
flex-direction: column;
525+
min-width: 0;
526+
}
527+
528+
/* Make the right pane's tabs component stretch to fill available height */
529+
.json-pane :deep(.p-tabs) {
530+
display: flex;
531+
flex-direction: column;
532+
flex: 1;
533+
}
534+
535+
.json-pane :deep(.p-tabpanels) {
536+
flex: 1;
537+
display: flex;
538+
flex-direction: column;
539+
}
540+
541+
.json-pane :deep(.p-tabpanel) {
542+
flex: 1;
543+
display: flex;
544+
flex-direction: column;
545+
}
546+
547+
.json-pane :deep(.tab-content) {
548+
flex: 1;
549+
display: flex;
550+
flex-direction: column;
551+
}
552+
553+
.json-pane :deep(.tab-content pre) {
554+
flex: 1;
555+
max-height: none;
501556
}
502557
503558
.pane-title {
@@ -546,4 +601,25 @@ pre {
546601
font-weight: bold;
547602
padding: 0.5rem 1rem;
548603
}
604+
605+
/* Endpoint header selector styles */
606+
.endpoint-header {
607+
display: flex;
608+
align-items: center;
609+
gap: 0.5rem;
610+
font-size: 1.1rem;
611+
}
612+
613+
.endpoint-label {
614+
font-weight: 600;
615+
color: var(--text-color);
616+
}
617+
618+
.endpoint-mission-select {
619+
min-width: 120px;
620+
}
621+
622+
.endpoint-api-select {
623+
min-width: 150px;
624+
}
549625
</style>

0 commit comments

Comments
 (0)