Moved pagination management to Timeline component

This commit is contained in:
Fabio Manganiello 2025-03-30 12:01:10 +02:00
parent 282828df0b
commit 6b7e984817
Signed by: blacklight
GPG key ID: D90FBA7F76362774
3 changed files with 84 additions and 60 deletions
frontend/src/components

View file

@ -44,13 +44,8 @@
<FilterForm :value="locationQuery"
:devices="devices"
:disabled="loading"
:has-next-page="hasNextPage"
:has-prev-page="hasPrevPage"
:resolution="resolutionMeters"
@refresh="locationQuery = $event"
@reset-page="locationQuery.minId = locationQuery.maxId = null"
@next-page="fetchNextPage"
@prev-page="fetchPrevPage"
@set-resolution="setResolution" />
</div>
<FilterButton @input="showControls = !showControls"
@ -70,8 +65,12 @@
<div class="timeline">
<Timeline :loading="loading"
:locationQuery="locationQuery"
:points="gpsPoints"
:show-metrics="showMetrics"
@next-page="fetchNextPage"
@prev-page="fetchPrevPage"
@reset-page="resetPage"
@point-hover="onTimelinePointHover"
@show-metrics="setShowMetrics" />
</div>
@ -283,6 +282,12 @@ export default {
this.locationQuery = prevPageQuery
},
async resetPage() {
const oldQuery = { ...this.locationQuery }
this.locationQuery.minId = this.locationQuery.maxId = null
await this.processQueryChange(this.locationQuery, oldQuery)
},
createMap(): Map {
this.pointsLayer = this.createPointsLayer(Object.values(this.mappedPoints) as Point[])
this.routesLayer = this.createRoutesLayer(Object.values(this.mappedPoints) as Point[])
@ -431,6 +436,8 @@ export default {
...this.locationQuery,
startDate: null,
endDate: null,
minId: null,
maxId: null,
minLongitude: startLon,
minLatitude: startLat,
maxLongitude: endLon,
@ -444,6 +451,8 @@ export default {
} else {
this.locationQuery = {
...this.locationQuery,
minId: null,
maxId: null,
minLongitude: null,
minLatitude: null,
maxLongitude: null,
@ -451,18 +460,8 @@ export default {
}
}
},
},
watch: {
locationQuery: {
async handler(newQuery: LocationQuery, oldQuery: LocationQuery) {
if (!this.isQueryChanged({
newValue: newQuery,
oldValue: oldQuery,
})) {
return
}
async processQueryChange(newQuery: LocationQuery, oldQuery: LocationQuery) {
// If startDate/endDate have changed, reset minId/maxId
if (newQuery.startDate !== oldQuery.startDate || newQuery.endDate !== oldQuery.endDate) {
newQuery.minId = null
@ -507,6 +506,20 @@ export default {
this.refreshMap()
}
},
},
watch: {
locationQuery: {
async handler(newQuery: LocationQuery, oldQuery: LocationQuery) {
if (!this.isQueryChanged({
newValue: newQuery,
oldValue: oldQuery,
})) {
return
}
await this.processQueryChange(newQuery, oldQuery)
},
deep: true,
},

View file

@ -23,9 +23,31 @@
</button>
</div>
<div class="page-button-container">
<button @click="$emit('prev-page')"
title="Previous results">
<font-awesome-icon icon="chevron-left" />
</button>
</div>
<div class="timeline">
<Line :data="graphData" :options="graphOptions" />
</div>
<div class="page-button-container">
<button @click="$emit('next-page')"
title="Next results">
<font-awesome-icon icon="chevron-right" />
</button>
</div>
<div class="page-button-container"
v-if="locationQuery?.minId || locationQuery?.maxId">
<button @click="$emit('reset-page')"
title="Reset pagination">
<font-awesome-icon icon="fas fa-undo" />
</button>
</div>
</div>
</div>
</template>
@ -47,6 +69,7 @@ import 'chartjs-adapter-date-fns';
import Geo from '../mixins/Geo.vue';
import GPSPoint from '../models/GPSPoint';
import LocationQuery from '../models/LocationQuery';
import TimelineMetricsConfiguration from '../models/TimelineMetricsConfiguration';
ChartJS.register(
@ -60,7 +83,13 @@ ChartJS.register(
);
export default {
emits: ['point-hover', 'show-metrics'],
emits: [
'next-page',
'point-hover',
'prev-page',
'reset-page',
'show-metrics',
],
mixins: [Geo],
components: {
Line,
@ -71,6 +100,9 @@ export default {
type: Boolean,
default: false,
},
locationQuery: {
type: LocationQuery,
},
points: {
type: Array as () => GPSPoint[],
default: () => [],
@ -332,4 +364,26 @@ $options-width: 5em;
}
}
}
.page-button-container {
width: 3em;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
button {
width: 100%;
height: 100%;
font-size: 1em;
background-color: var(--color-background);
border: 0;
margin-left: 0.5em;
cursor: pointer;
&:hover {
color: var(--color-hover);
}
}
}
</style>

View file

@ -86,24 +86,6 @@
</div>
<div class="pagination-container">
<div class="page-button-container">
<button type="button"
:disabled="disabled"
v-if="value?.minId || value?.maxId"
@click.stop="$emit('reset-page')">
<font-awesome-icon icon="fas fa-undo" />
</button>
</div>
<div class="page-button-container">
<button type="button"
@click="$emit('prev-page')"
title="Previous Results"
:disabled="disabled || !hasPrevPage">
<font-awesome-icon icon="fas fa-chevron-left" />
</button>
</div>
<div class="limit-container">
<label for="limit">Max Results</label>
<input type="number"
@ -115,15 +97,6 @@
:disabled="disabled"
min="1" />
</div>
<div class="page-button-container">
<button type="button"
@click="$emit('next-page')"
title="Next Results"
:disabled="disabled || !hasNextPage">
<font-awesome-icon icon="fas fa-chevron-right" />
</button>
</div>
</div>
<div class="resolution-container">
@ -176,9 +149,6 @@ import UserDevice from '../../models/UserDevice'
export default {
mixins: [LocationQueryMixin],
emit: [
'next-page',
'prev-page',
'reset-page',
'refresh',
'set-resolution',
],
@ -193,14 +163,6 @@ export default {
type: Boolean,
default: false,
},
hasPrevPage: {
type: Boolean,
default: true,
},
hasNextPage: {
type: Boolean,
default: true,
},
resolution: {
type: Number,
required: true,
@ -432,11 +394,6 @@ export default {
align-items: center;
}
.page-button-container {
display: flex;
justify-content: center;
}
label {
margin-bottom: 0.25em;
}