summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue')
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue132
1 files changed, 99 insertions, 33 deletions
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue b/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
index 5d13122765a..c09aabb0d40 100644
--- a/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
@@ -1,9 +1,20 @@
<script>
-import { GlTable, GlLink, GlPagination, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { getParameterValues, setUrlParams } from '~/lib/utils/url_utility';
+import { GlTable, GlLink, GlTooltipDirective } from '@gitlab/ui';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import IncubationAlert from './incubation_alert.vue';
+import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
+import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ LIST_KEY_CREATED_AT,
+ BASE_SORT_FIELDS,
+ METRIC_KEY_PREFIX,
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+} from '~/ml/experiment_tracking/constants';
+import { s__ } from '~/locale';
+import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue';
+import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
export default {
name: 'MlExperiment',
@@ -12,19 +23,36 @@ export default {
GlLink,
TimeAgo,
IncubationAlert,
- GlPagination,
+ RegistrySearch,
+ KeysetPagination,
},
directives: {
GlTooltip: GlTooltipDirective,
},
- inject: ['candidates', 'metricNames', 'paramNames', 'pagination'],
+ inject: ['candidates', 'metricNames', 'paramNames', 'pageInfo'],
data() {
+ const query = queryToObject(window.location.search);
+
+ const filter = query.name ? [{ value: { data: query.name }, type: FILTERED_SEARCH_TERM }] : [];
+
+ let orderBy = query.orderBy || LIST_KEY_CREATED_AT;
+
+ if (query.orderByType === 'metric') {
+ orderBy = `${METRIC_KEY_PREFIX}${orderBy}`;
+ }
+
return {
- page: parseInt(getParameterValues('page')[0], 10) || 1,
+ filters: filter,
+ sorting: {
+ orderBy,
+ sort: (query.sort || 'desc').toLowerCase(),
+ },
};
},
computed: {
fields() {
+ if (this.candidates.length === 0) return [];
+
return [
{ key: 'name', label: this.$options.i18n.nameLabel },
{ key: 'created_at', label: this.$options.i18n.createdAtLabel },
@@ -38,39 +66,87 @@ export default {
displayPagination() {
return this.candidates.length > 0;
},
- prevPage() {
- return this.pagination.page > 1 ? this.pagination.page - 1 : null;
+ sortableFields() {
+ return [
+ ...BASE_SORT_FIELDS,
+ ...this.metricNames.map((name) => ({
+ orderBy: `${METRIC_KEY_PREFIX}${name}`,
+ label: capitalizeFirstCharacter(name),
+ })),
+ ];
},
- nextPage() {
- return !this.pagination.isLastPage ? this.pagination.page + 1 : null;
+ parsedQuery() {
+ const name = this.filters
+ .map((f) => f.value.data)
+ .join(' ')
+ .trim();
+
+ const filterByQuery = name === '' ? {} : { name };
+
+ let orderByType = 'column';
+ let { orderBy } = this.sorting;
+ const { sort } = this.sorting;
+
+ if (orderBy.startsWith(METRIC_KEY_PREFIX)) {
+ orderBy = this.sorting.orderBy.slice(METRIC_KEY_PREFIX.length);
+ orderByType = 'metric';
+ }
+
+ return { ...filterByQuery, orderBy, orderByType, sort };
},
},
methods: {
- generateLink(page) {
- return setUrlParams({ page });
+ submitFilters() {
+ return visitUrl(setUrlParams({ ...this.parsedQuery }));
+ },
+ updateFilters(newValue) {
+ this.filters = newValue;
+ },
+ updateSorting(newValue) {
+ this.sorting = { ...this.sorting, ...newValue };
+ },
+ updateSortingAndEmitUpdate(newValue) {
+ this.updateSorting(newValue);
+ this.submitFilters();
},
},
i18n: {
- titleLabel: __('Experiment candidates'),
- emptyStateLabel: __('This experiment has no logged candidates'),
- artifactsLabel: __('Artifacts'),
- detailsLabel: __('Details'),
- userLabel: __('User'),
- createdAtLabel: __('Created at'),
- nameLabel: __('Name'),
- noDataContent: __('-'),
+ titleLabel: s__('MlExperimentTracking|Experiment candidates'),
+ emptyStateLabel: s__('MlExperimentTracking|No candidates to display'),
+ artifactsLabel: s__('MlExperimentTracking|Artifacts'),
+ detailsLabel: s__('MlExperimentTracking|Details'),
+ userLabel: s__('MlExperimentTracking|User'),
+ createdAtLabel: s__('MlExperimentTracking|Created at'),
+ nameLabel: s__('MlExperimentTracking|Name'),
+ noDataContent: s__('MlExperimentTracking|-'),
+ filterCandidatesLabel: s__('MlExperimentTracking|Filter candidates'),
},
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
};
</script>
<template>
<div>
- <incubation-alert />
+ <incubation-alert
+ :feature-name="$options.FEATURE_NAME"
+ :link-to-feedback-issue="$options.FEATURE_FEEDBACK_ISSUE"
+ />
<h3>
{{ $options.i18n.titleLabel }}
</h3>
+ <registry-search
+ :filters="filters"
+ :sorting="sorting"
+ :sortable-fields="sortableFields"
+ @sorting:changed="updateSortingAndEmitUpdate"
+ @filter:changed="updateFilters"
+ @filter:submit="submitFilters"
+ @filter:clear="filters = []"
+ />
+
<gl-table
:fields="fields"
:items="candidates"
@@ -119,16 +195,6 @@ export default {
</template>
</gl-table>
- <gl-pagination
- v-if="displayPagination"
- v-model="pagination.page"
- :prev-page="prevPage"
- :next-page="nextPage"
- :total-items="pagination.totalItems"
- :per-page="pagination.perPage"
- :link-gen="generateLink"
- align="center"
- class="w-100"
- />
+ <keyset-pagination v-if="displayPagination" v-bind="pageInfo" />
</div>
</template>