diff --git a/package.json b/package.json index fa162038..6873dd04 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "url": "git+https://github.com/opencor/webapp.git" }, "type": "module", - "version": "0.20260117.0", + "version": "0.20260119.0", "scripts": { "archive:web": "bun src/renderer/scripts/archive.web.js", "build": "electron-vite build", diff --git a/src/renderer/package.json b/src/renderer/package.json index 969358ae..d2934bbc 100644 --- a/src/renderer/package.json +++ b/src/renderer/package.json @@ -39,7 +39,7 @@ }, "./style.css": "./dist/opencor.css" }, - "version": "0.20260117.0", + "version": "0.20260119.0", "scripts": { "build": "vite build", "build:lib": "vite build --config vite.lib.config.ts && cp index.d.ts dist/index.d.ts", diff --git a/src/renderer/src/components/ContentsComponent.vue b/src/renderer/src/components/ContentsComponent.vue index 8ee8f36e..ec94c3af 100644 --- a/src/renderer/src/components/ContentsComponent.vue +++ b/src/renderer/src/components/ContentsComponent.vue @@ -39,10 +39,7 @@
{{ - fileTab.file - .path() - .split(/(\\|\/)/g) - .pop() + fileName(fileTab.file.path()) }}
@@ -136,6 +133,18 @@ vue.watch(activeFile, (newActiveFile: string) => { electronApi?.fileSelected(newActiveFile); }); +function fileName(filePath: string): string { + const res = filePath.split(/(\\|\/)/g).pop() || ''; + + try { + return decodeURIComponent(res); + } catch (error: unknown) { + console.error('Failed to decode the file path:', res, error); + + return res; + } +} + function openFile(file: locApi.File): void { const filePath = file.path(); const prevActiveFile = activeFile.value; diff --git a/src/renderer/src/components/views/SimulationExperimentView.vue b/src/renderer/src/components/views/SimulationExperimentView.vue index 8a8c3f89..35733c49 100644 --- a/src/renderer/src/components/views/SimulationExperimentView.vue +++ b/src/renderer/src/components/views/SimulationExperimentView.vue @@ -98,89 +98,55 @@
-
-
-
-
- Live run -
-
- -
- -
-
-
-
-
-
+
- Run #{{ index + 1 }} + {{ run.isLiveRun ? 'Live run' : `Run #${index}` }}
@@ -189,19 +155,20 @@ :icon="run.visible ? 'pi pi-eye' : 'pi pi-eye-slash'" :severity="run.visible ? 'info' : 'secondary'" text size="small" - :title="(run.visible ? 'Hide' : 'Show') + ' run'" + :title="`${run.visible ? 'Hide' : 'Show'} ${run.isLiveRun ? 'live run' : 'run'}`" @click="onToggleRun(index)" /> -
-
+
There are no (additional) runs.
Click "Add run" to add one.
@@ -250,6 +217,7 @@ interface ISimulationRun { data: IGraphPanelData[]; color: string; tooltip: string; + isLiveRun: boolean; } const props = defineProps<{ @@ -411,14 +379,20 @@ const interactiveShowInput = vue.ref( interactiveModeAvailable.value ? props.uiJson.input.map((input: locApi.IUiJsonInput) => input.visible ?? 'true') : [] ); const interactiveIdToInfo: Record = {}; -const interactiveRuns = vue.ref([]); -const interactiveLiveRunColor = vue.ref(DefaultGraphPanelWidgetColor); -const interactiveLiveRunVisible = vue.ref(true); -const interactiveLiveRunColorPopover = vue.ref(); +const interactiveRuns = vue.ref([ + { + inputParameters: {}, + visible: true, + data: [], + color: DefaultGraphPanelWidgetColor, + tooltip: '', + isLiveRun: true + } +]); const interactiveRunColorPopoverIndex = vue.ref(-1); -const interactiveRunPopoverRefs = vue.ref>({}); +const interactiveRunColorPopoverRefs = vue.ref>({}); const interactiveCompData = vue.computed(() => { - // Combine the live data with the data from the visible runs. + // Combine the live data with the data from the additional runs. const res: IGraphPanelData[] = []; @@ -427,36 +401,31 @@ const interactiveCompData = vue.computed(() => { interactiveDataIndex < (interactiveData.value.length || 0); ++interactiveDataIndex ) { - const traces: IGraphPanelPlotTrace[] = interactiveLiveRunVisible.value - ? (interactiveData.value[interactiveDataIndex]?.traces ?? []).map((trace, traceIndex) => { - return { - ...trace, - name: trace.name + (interactiveRuns.value.length ? ` [Live]` : ''), - color: - GraphPanelWidgetPalette[ - (GraphPanelWidgetPalette.indexOf(interactiveLiveRunColor.value) + traceIndex) % - GraphPanelWidgetPalette.length - ] ?? DefaultGraphPanelWidgetColor, - zorder: 1 - }; - }) - : []; + const traces: IGraphPanelPlotTrace[] = []; interactiveRuns.value.forEach((interactiveRun: ISimulationRun, runIndex: number) => { - if (interactiveRun.visible) { - const runTraces = (interactiveRun.data[interactiveDataIndex]?.traces ?? []).map((trace, traceIndex) => { - return { - ...trace, - name: trace.name + (interactiveRuns.value.length ? ` [#${runIndex + 1}]` : ''), - color: - GraphPanelWidgetPalette[ - (GraphPanelWidgetPalette.indexOf(interactiveRun.color) + traceIndex) % GraphPanelWidgetPalette.length - ] ?? DefaultGraphPanelWidgetColor - }; - }); - - traces.push(...runTraces); + if (!interactiveRun.visible) { + return; } + + const data = interactiveRun.isLiveRun + ? interactiveData.value[interactiveDataIndex] + : interactiveRun.data[interactiveDataIndex]; + const runTraces = (data?.traces ?? []).map((trace, traceIndex) => { + return { + ...trace, + name: + trace.name + + (interactiveRuns.value.length === 1 ? '' : interactiveRun.isLiveRun ? ' [Live]' : ` [#${runIndex}]`), + color: + GraphPanelWidgetPalette[ + (GraphPanelWidgetPalette.indexOf(interactiveRun.color) + traceIndex) % GraphPanelWidgetPalette.length + ] ?? DefaultGraphPanelWidgetColor, + zorder: interactiveRun.isLiveRun ? 1 : undefined + }; + }); + + traces.push(...runTraces); }); res.push({ @@ -693,9 +662,8 @@ function onAddRun(): void { // Determine the colour (of the first trace) by using the next unused colour in the palette unless all the colours // have already been used. - const usedColors = new Set([interactiveLiveRunColor.value, ...interactiveRuns.value.map((run) => run.color)]); - const interactiveRun = interactiveRuns.value.length ? interactiveRuns.value[interactiveRuns.value.length - 1] : null; - const lastColor = interactiveRun ? interactiveRun.color : interactiveLiveRunColor.value; + const usedColors = new Set(interactiveRuns.value.map((run) => run.color)); + const lastColor = interactiveRuns.value[interactiveRuns.value.length - 1]?.color ?? DefaultGraphPanelWidgetColor; const lastColorIndex = GraphPanelWidgetPalette.indexOf(lastColor); let color: string = DefaultGraphPanelWidgetColor; @@ -716,7 +684,8 @@ function onAddRun(): void { visible: true, data: interactiveData.value, color, - tooltip + tooltip, + isLiveRun: false }); } @@ -727,9 +696,9 @@ function onRemoveRun(index: number): void { } function onRemoveAllRuns(): void { - // Remove all the runs. + // Remove all the runs except the live run. - interactiveRuns.value = []; + interactiveRuns.value.splice(1); } function onToggleRun(index: number): void { @@ -742,40 +711,25 @@ function onToggleRun(index: number): void { } } -function onLiveRunColorChange(color: string) { - interactiveLiveRunColor.value = color; - - interactiveLiveRunColorPopover.value.hide(); -} - function onRunColorChange(index: number, color: string) { const interactiveRun = interactiveRuns.value[index]; if (interactiveRun) { interactiveRun.color = color; - - closeRunColorPopover(index); } } function onToggleRunColorPopover(index: number, event: MouseEvent) { - if (interactiveRunColorPopoverIndex.value === index) { - closeRunColorPopover(index); - } else { - interactiveRunColorPopoverIndex.value = index; + // Note: interactiveRunColorPopoverIndex is only used to ensure that the active popover gets properly hidden when the + // window loses focus as a result of switching tabs (see onMounted below). - vue.nextTick(() => { - // Note: we do this in a next tick to ensure that the reference is available. + interactiveRunColorPopoverIndex.value = index; - interactiveRunPopoverRefs.value[index]?.toggle(event); - }); - } -} - -function closeRunColorPopover(index: number) { - interactiveRunPopoverRefs.value[index]?.hide(); + vue.nextTick(() => { + // Note: we do this in a next tick to ensure that the reference is available. - interactiveRunColorPopoverIndex.value = -1; + interactiveRunColorPopoverRefs.value[index]?.toggle(event); + }); } // "Initialise" our standard and/or interactive modes. @@ -839,16 +793,16 @@ vue.onMounted(() => { mutationObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] }); - // Close popovers when the window loses focus. + // Make sure that our active popover gets hidden when the window loses focus. vue.watch( () => windowIsFocused.value, (isFocused) => { if (!isFocused) { - interactiveLiveRunColorPopover.value?.hide(); - if (interactiveRunColorPopoverIndex.value !== -1) { - closeRunColorPopover(interactiveRunColorPopoverIndex.value); + interactiveRunColorPopoverRefs.value[interactiveRunColorPopoverIndex.value]?.hide(); + + interactiveRunColorPopoverIndex.value = -1; } } } @@ -931,4 +885,8 @@ if (common.isDesktop()) { .run { border-color: var(--p-content-border-color); } + +.selected-color { + outline: 3px solid var(--p-text-color); +}