Geo Replicables List: Add ability to store pagination in URL

Why are we doing this work

The list view is currently going through a migration and may look different depending on if you have the feature flag geo_replicables_filtered_list_view and/or geo_replicables_show_view enabled.

We have begun storing query information in the URL. However, the pagination is not, so users cannot return to a previous page by refresh if they would so desire. In this change we'd suggest hooking up the existing pagination cursor information into the URL.

Relevant links

Demo

Proposal Demo

Screen_Recording_2025-04-11_at_1.38.58_PM

Implementation plan

  1. Add the ability to manage the activePagination in the vuex store (geo_replicable/store)
// state.js

activePagination: {
  before: '',
  after: '',
  first: DEFAULT_PAGE_SIZE,
  last: null
},
// mutation_types.js

export const SET_ACTIVE_PAGINATION = 'SET_ACTIVE_PAGINATION';
// mutations.js

[types.SET_ACTIVE_PAGINATION](state, pagination) {
  state.activePagination = pagination;
},
// actions.js

export const setActivePagination = ({ commit }, pagination) => {
  commit(types.SET_ACTIVE_PAGINATION, pagination);
};
  1. Update Vuex action fetchReplicableItems to get pagination from activePagination
// some of file omitted for clarity
// actions.js

--- let before = '';
--- let after = '';

--- // If we are going backwards we want the last 20, otherwise get the first 20.
--- let first = DEFAULT_PAGE_SIZE;
--- let last = null;

--- if (direction === PREV) {
---    before = state.paginationData.startCursor;
---    first = null;
---    last = DEFAULT_PAGE_SIZE;
---  } else if (direction === NEXT) {
---    after = state.paginationData.endCursor;
---  }

--- export const fetchReplicableItems = ({ state, dispatch }, direction) => {
+++ export const fetchReplicableItems = ({ state, dispatch }) => {
  dispatch('requestReplicableItems');

  const replicationState = state.statusFilter ? state.statusFilter.toUpperCase() : null
+++ const { first, last, before, after } = state.activePagination

  // ...
};
  1. Add support getting the pagination object and processing the pagination object in geo_replicable/filters.js
// some of file omitted for clarity
// filters.js

export const getPaginationObject = ({ before, after, first, last }) => {
  return {
    before: before || '',
    after: after || '',
    first: Number(first) || null,
    last: Number(last) || null
  }
}

export const processPagination = ({ direction, paginationData }) => {
  // If we are going backwards we want the last 20, otherwise get the first 20.
  const query = {
    before: '',
    after: '',
    first: DEFAULT_PAGE_SIZE,
    last: null
  };

  if (direction === PREV) {
    query.before = paginationData.startCursor;
    query.first = null;
    query.last = DEFAULT_PAGE_SIZE;
  } else if (direction === NEXT) {
    query.after = paginationData.endCursor;
  }

  return { query };
};
  1. Update geo_replicable.vue to emit a paginate event when page change is triggered.
// some of file omitted for clarity
// geo_replicable.vue

<script>
  export default {
    methods: {
      updatePagination(direction) {
        this.$emit('paginate', direction)
      }
    },
  }
</script>

<template>
  <gl-keyset-pagination
    v-bind="paginationData"
    @next="updatePagination($options.NEXT)"
    @prev="updatePagination($options.PREV)" 
  />
</template>
  1. Add method to handle onPaginate in app.vue
// some of file omitted for clarity
// app.vue

onPaginate(direction) {
  const { query } = processPagination({ direction, paginationData: this.paginationData })

  visitUrl(setUrlParams(query))
}
  1. Add method to handle getPaginationFromQuery in app.vue
// some of file omitted for clarity
// app.vue

<script>
  export default {
    created() {
      if (this.glFeatures.geoReplicablesFilteredListView) {
        this.getPaginationFromQuery();
      }
    },
    methods: {
      getPaginationFromQuery() {
        const { before, after, first, last } = queryToObject(window.location.search || '');

        if (before || after || first || last) {
          this.setActivePagination(getPaginationObject({ before, after, first, last }))
        }
      }
    }
  }
</script>
Edited by 🤖 GitLab Bot 🤖