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
- UI issue: Geo Primary Verification List: Hookup `geo_shar... (#538023)
- API Endpoint Issue: Geo Primary Verification API: GET `api/v4/admin... (#537710 - closed)
- Geo Replicables filters: https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/assets/javascripts/geo_replicable/filters.js
Implementation plan
- 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 };
});
- Expose newly added
FILTERED_SEARCH_TOKEN_OPTIONS
to theindex.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,
},
});
};
- 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 };
};
- 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];
},
- Add
activeFilteredSearchFilters
computed property and pass it to the proper component inapp.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
- 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>
- Update
emptyState
computed property to handle filters inapp.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,
};
},