Skip to content

Geo Primary Verification List: Hookup filtered search filters to UI

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Why are we doing this work

This work will be behind feature flag geo_primary_verification_view

This work is focused on taking the UI added as as part of Geo Primary Verification List: Hookup `geo_shar... (#538023) and hooking up the filters that will be supported in the API Geo Primary Verification API: GET `api/v4/admin... (#537710 - closed). The API itself will be hooked up to the UI in Geo Primary Verification List: Hookup API to UI (#538025) and this functionality can be added whether or not that is implemented yet.

These filters will function very similar to how we utilize them in the Geo Replicables views: https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/assets/javascripts/geo_replicable/filters.js

Relevant links

Implementation plan

  1. Define tokens and items needed in the constants.js
export const CHECKSUM_STATUS_STATES_ARRAY = [
  {
    title: s__('Geo|Pending'),
    value: 'pending',
  },
  {
    title: s__('Geo|Started'),
    value: 'started',
  },
  {
    title: s__('Geo|Succeeded'),
    value: 'succeeded',
  },
  {
    title: s__('Geo|Failed'),
    value: 'failed',
  },
  {
    title: s__('Geo|Disabled'),
    value: 'disabled',
  },
  {
    title: s__('Geo|Unknown'),
    value: null,
  },
]

export const TOKEN_TYPES = {
  CHECKSUM_STATUS: 'checksum_status'
};

export const FILTERED_SEARCH_TOKEN_DEFINITIONS = [
  {
    title: s__('Geo|Checksum status'),
    type: TOKEN_TYPES.CHECKSUM_STATUS,
    icon: 'check-circle',
    token: GlFilteredSearchToken,
    operators: OPERATORS_IS,
    unique: true,
  },
];

export const FILTERED_SEARCH_TOKEN_OPTIONS = FILTERED_SEARCH_TOKEN_DEFINITIONS.map((def) => {
  let options = [];

  if (def.type === TOKEN_TYPES.CHECKSUM_STATUS) {
    options = CHECKSUM_STATUS_STATES_ARRAY;
  }

  return { ...def, options };
});
  1. Expose newly added FILTERED_SEARCH_TOKEN_OPTIONS to the index.js and provide it to the Vue app.
import { FILTERED_SEARCH_TOKEN_OPTIONS } from './constants'

export const initDataManagement = () => {
  // most of file omitted


  return new Vue({
    // omitted
    provide: {
      filteredSearchTokens: FILTERED_SEARCH_TOKEN_OPTIONS,
    },
  });
};
  1. Added needed methods and new filter support to the filters.js
export const isValidFilter = (data, array) => {
  return data && array?.some(({ value }) => value === data);
};

export const getChecksumStatusFilter = (data) => {
  return {
    type: TOKEN_TYPES.CHECKSUM_STATUS,
    value: {
      data,
    },
  };
};

export const processFilters = (filters) => {
  // URL Structure: /admin/data_management/${MODEL}?${FILTERS}
  const url = new URL(window.location.href);
  const query = {};

  filters.forEach((filter) => {
    // other filters omitted

    if (filter.type === TOKEN_TYPES.CHECKSUM_STATUS) {
      query[TOKEN_TYPES.CHECKSUM_STATUS] = filter.value.data;
    }
  });

  return { query, url };
};
  1. Add updated logic to get filter from URL onCreate in the `app.vue
getFiltersFromQuery() {
  const filters = [];
  const url = new URL(window.location.href);
  const segments = pathSegments(url);
  const { checksum_status: checksumStatus } = queryToObject(window.location.search || '');

  if (isValidFilter(checksumStatus, CHECKSUM_STATUS_STATES_ARRAY)) {
    filters.push(getChecksumStatusFilter(checksumStatus));
  }

  this.activeFilters = [getModelFilter(segments.pop()), ...filters];
},
  1. Add activeFilteredSearchFilters computed property and pass it to the proper component in app.vue
<script>
export default {
  computed: {
    activeFilteredSearchFilters() {
      return this.activeFilters.filter(({ type }) => type !== TOKEN_TYPES.MODEL);
    },
  },
}
</script>

<template>
  <geo-list-top-bar
    :active-filtered-search-filters="activeFilteredSearchFilters"
  />
</template
  1. Update events to process filter changes and hook up event in template in app.vue
<script>
export default {
  methods: {
    // This event needs to handle the activeFilteredSearchFilters now
    onListboxChange(val) {
      this.onSearch([getModelFilter(val), ...this.activeFilteredSearchFilters]);
    },
  }
}
</script>

<template>
  <geo-list-top-bar
    @search="onSearch"
  />
</template>
  1. Update emptyState computed property to handle filters in app.vue
emptyState() {
  const title = this.activeFilteredSearchFilters.length
    ? sprintf(this.$options.i18n.noResultsFilteredTitle, { model: this.activeModel })
    : this.$options.i18n.noResultsFoundTitle

  const description = this.activeFilteredSearchFilters.length
    ? this.$options.i18n.noResultsFilteredDescription
    : this.$options.i18n.noResultsFoundDescription

  return {
    title,
    description,
    item: this.activeModel,
    svgPath: this.emptyStateSvgPath,
    helpLink: GEO_TROUBLESHOOTING_LINK,
  };
},
Edited by 🤖 GitLab Bot 🤖