Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show loading icon when get request for time series is pending #932

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 12 additions & 7 deletions src/components/charts/ElevationChart.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div class="chart-with-chips">
<div ref="chartContainer" class="chart-container"></div>
<LoadingOverlay v-if="isLoading" :offsets="margin" height="90%" />
<div ref="chartContainer" class="chart-container" v-show="!isLoading"></div>
<v-sheet
class="chart-controls"
rounded
Expand Down Expand Up @@ -56,6 +57,7 @@ import {
VerticalMouseOver,
ZoomHandler,
} from '@deltares/fews-web-oc-charts'
import LoadingOverlay from '@/components/charts/LoadingOverlay.vue'
import type { ChartConfig } from '../../lib/charts/types/ChartConfig.js'
import type { ChartSeries } from '../../lib/charts/types/ChartSeries.js'
import { Series } from '../../lib/timeseries/timeSeries.js'
Expand All @@ -68,6 +70,7 @@ const LEGEND_HEIGHT = 76
interface Props {
config?: ChartConfig
series?: Record<string, Series>
isLoading?: boolean
}

interface Tag {
Expand Down Expand Up @@ -96,6 +99,13 @@ const chipGroup = ref<VChipGroup>()
const expanded = ref(false)
const requiresExpand = ref(false)

const margin = {
top: 110,
left: 70,
right: 30,
bottom: 50,
}

onMounted(() => {
const axisOptions: CartesianAxesOptions = {
x: [
Expand All @@ -117,12 +127,7 @@ onMounted(() => {
nice: true,
},
],
margin: {
top: 110,
left: 70,
right: 30,
bottom: 50,
},
margin,
}

const chartWidth = 800
Expand Down
49 changes: 49 additions & 0 deletions src/components/charts/LoadingOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<div class="loading-overlay" :style="style">
<v-skeleton-loader type="image" class="w-100 h-100" />
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue'

interface Props {
offsets?: {
top?: number
right?: number
bottom?: number
left?: number
}
height?: string
width?: string
}

const props = defineProps<Props>()

const style = computed(() => ({
paddingTop: props.offsets?.top ? `${props.offsets.top - 32}px` : undefined,
paddingRight: props.offsets?.right ? `${props.offsets.right}px` : undefined,
paddingBottom: props.offsets?.bottom
? `${props.offsets.bottom}px`
: undefined,
paddingLeft: props.offsets?.left ? `${props.offsets.left}px` : undefined,
}))
</script>

<style scoped>
.loading-overlay {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}

:deep(.v-skeleton-loader__image) {
height: v-bind(height);
width: v-bind(width);
border-radius: 4px;
}
</style>
17 changes: 11 additions & 6 deletions src/components/charts/TimeSeriesChart.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div class="chart-with-chips">
<div ref="chartContainer" class="chart-container"></div>
<LoadingOverlay v-if="isLoading" :offsets="margin" height="80%" />
<div ref="chartContainer" class="chart-container" v-show="!isLoading"></div>
<v-sheet
class="chart-controls"
rounded
Expand Down Expand Up @@ -64,6 +65,7 @@ import {
CurrentTime,
MouseOver,
} from '@deltares/fews-web-oc-charts'
import LoadingOverlay from '@/components/charts/LoadingOverlay.vue'
import type { ChartConfig } from '../../lib/charts/types/ChartConfig.js'
import type { ChartSeries } from '../../lib/charts/types/ChartSeries.js'
import type { ThresholdLine } from '../../lib/charts/types/ThresholdLine.js'
Expand All @@ -80,6 +82,7 @@ interface Props {
config?: ChartConfig
series?: Record<string, Series>
currentTime?: Date
isLoading?: boolean
}

interface Tag {
Expand Down Expand Up @@ -114,6 +117,12 @@ const expanded = ref(false)
const requiresExpand = ref(false)
const axisTime = ref<CurrentTime>()

const margin = {
top: 110,
right: 50,
left: 50,
}

onMounted(() => {
const axisOptions: CartesianAxesOptions = {
x: [
Expand All @@ -138,11 +147,7 @@ onMounted(() => {
nice: true,
},
],
margin: {
top: 110,
left: 50,
right: 50,
},
margin,
}

if (chartContainer.value) {
Expand Down
18 changes: 16 additions & 2 deletions src/components/timeseries/TimeSeriesComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
:series="series"
:key="`${subplot.title}-${i}`"
:currentTime="props.currentTime"
:isLoading="isLoading(subplot, loadingSeriesIds)"
>
</TimeSeriesChart>
</KeepAlive>
Expand Down Expand Up @@ -40,6 +41,7 @@
:series="elevationChartSeries"
:key="`${subplot.title}-${i}`"
:style="`min-width: ${xs ? 100 : 50}%`"
:isLoading="isLoading(subplot, elevationLoadingSeriesIds)"
>
</ElevationChart>
</KeepAlive>
Expand Down Expand Up @@ -118,20 +120,32 @@ const options = computed<UseTimeSeriesOptions>(() => {
}
})
const baseUrl = configManager.get('VITE_FEWS_WEBSERVICES_URL')
const { series } = useTimeSeries(
const { series, loadingSeriesIds } = useTimeSeries(
baseUrl,
() => props.config.requests,
lastUpdated,
options,
)
const { series: elevationChartSeries } = useTimeSeries(
const {
series: elevationChartSeries,
loadingSeriesIds: elevationLoadingSeriesIds,
} = useTimeSeries(
baseUrl,
() => props.elevationChartConfig.requests,
lastUpdated,
options,
() => props.currentTime,
)

function isLoading(subplot: ChartConfig, loadingSeriesIds: string[]) {
return subplot.series
.map((s) => s.id)
.some((id) => {
const idWithoutIndex = id.replace(/\[\d+\]$/, '')
return loadingSeriesIds.includes(idWithoutIndex)
})
}

async function onDataChange(newData: Record<string, TimeSeriesEvent[]>) {
await postTimeSeriesEdit(baseUrl, props.config.requests, newData)
lastUpdated.value = new Date()
Expand Down
16 changes: 14 additions & 2 deletions src/services/useTimeSeries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
type TimeSeriesEvent,
DomainAxisEventValuesStringArray,
} from '@deltares/fews-pi-requests'
import { onUnmounted, ref, shallowRef, toValue, watch } from 'vue'
import { computed, onUnmounted, ref, shallowRef, toValue, watch } from 'vue'
import type { MaybeRefOrGetter, Ref } from 'vue'
import { absoluteUrl } from '../../lib/utils/absoluteUrl'
import { DateTime, Interval } from 'luxon'
Expand All @@ -15,12 +15,14 @@ import { createTransformRequestFn } from '@/lib/requests/transformRequest'
import { difference } from 'lodash-es'
import { SeriesData } from '@/lib/timeseries/types/SeriesData'
import { convertFewsPiDateTimeToJsDate } from '@/lib/date'
import { debouncedRef } from '@vueuse/core'

export interface UseTimeSeriesReturn {
error: Ref<any>
series: Ref<Record<string, Series>>
isReady: Ref<boolean>
isLoading: Ref<boolean>
loadingSeriesIds: Ref<string[]>
}

export interface UseTimeSeriesOptions {
Expand Down Expand Up @@ -55,10 +57,12 @@ export function useTimeSeries(
): UseTimeSeriesReturn {
let controller = new AbortController()
const isReady = ref(false)
const isLoading = ref(false)
const series = ref<Record<string, Series>>({})
const error = shallowRef<any | undefined>(undefined)
const MAX_SERIES = 20
const loadingSeriesIds = ref<string[]>([])
const debouncedLoadingSeriesIds = debouncedRef(loadingSeriesIds, 100)
const isLoading = computed(() => debouncedLoadingSeriesIds.value.length > 0)

watch([lastUpdated, selectedTime ?? ref(), requests, options], () => {
controller.abort('Timeseries request triggered again before finishing.')
Expand All @@ -72,6 +76,8 @@ export function useTimeSeries(

const currentSeriesIds = Object.keys(series.value)
const updatedSeriesIds: string[] = []
loadingSeriesIds.value = _requests.flatMap((r) => (r.key ? [r.key] : []))

for (const r in _requests) {
const request = _requests[r]
const url = absoluteUrl(`${baseUrl}/${request.request}`)
Expand Down Expand Up @@ -117,6 +123,11 @@ export function useTimeSeries(
const relativeUrl = request.request.split('?')[0] + url.search
const isGridTimeSEries = request.request.includes('/timeseries/grid?')
piProvider.getTimeSeriesWithRelativeUrl(relativeUrl).then((piSeries) => {
if (request.key)
loadingSeriesIds.value.splice(
loadingSeriesIds.value.indexOf(request.key),
1,
)
if (piSeries.timeSeries !== undefined)
for (const index in piSeries.timeSeries) {
const timeSeries = piSeries.timeSeries[index]
Expand Down Expand Up @@ -189,6 +200,7 @@ export function useTimeSeries(
series,
isReady,
isLoading,
loadingSeriesIds: debouncedLoadingSeriesIds,
error,
}

Expand Down
Loading