Commit a65be6a1 authored by Martin Wortschack's avatar Martin Wortschack

Switch VSA to be using GraphQL for projects query

- This MR switches group-level VSA
to be using the GraphQL API
for querying projects
parent 1e5ef1a2
......@@ -3,7 +3,7 @@ import { GlEmptyState } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
import { PROJECTS_PER_PAGE } from '../constants';
import ProjectsDropdownFilter from '../../shared/components/projects_dropdown_filter.vue';
import { SIMILARITY_ORDER, LAST_ACTIVITY_AT, DATE_RANGE_LIMIT } from '../../shared/constants';
import { DATE_RANGE_LIMIT } from '../../shared/constants';
import DateRange from '../../shared/components/daterange.vue';
import StageTable from './stage_table.vue';
import DurationChart from './duration_chart.vue';
......@@ -116,12 +116,8 @@ export default {
},
projectsQueryParams() {
return {
per_page: PROJECTS_PER_PAGE,
with_shared: false,
order_by: this.featureFlags.hasAnalyticsSimilaritySearch
? SIMILARITY_ORDER
: LAST_ACTIVITY_AT,
include_subgroups: true,
first: PROJECTS_PER_PAGE,
includeSubgroups: true,
};
},
},
......
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlToast } from '@gitlab/ui';
import CycleAnalytics from './components/base.vue';
import createStore from './store';
import { buildCycleAnalyticsInitialData } from '../shared/utils';
import createDefaultClient from '~/lib/graphql';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
Vue.use(GlToast);
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default () => {
const el = document.querySelector('#js-cycle-analytics-app');
......@@ -43,6 +50,7 @@ export default () => {
return new Vue({
el,
name: 'CycleAnalyticsApp',
apolloProvider,
store,
render: createElement =>
createElement(CycleAnalytics, {
......
import dateFormat from 'dateformat';
import { isNumber } from 'lodash';
import httpStatus from '~/lib/utils/http_status';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { dateFormats } from '../../shared/constants';
import { transformStagesForPathNavigation } from '../utils';
......@@ -14,7 +15,7 @@ export const currentValueStreamId = ({ selectedValueStream }) =>
export const currentGroupPath = ({ currentGroup }) => currentGroup?.fullPath || null;
export const selectedProjectIds = ({ selectedProjects }) =>
selectedProjects?.map(({ id }) => id) || [];
selectedProjects?.map(({ id }) => getIdFromGraphQLId(id)) || [];
export const cycleAnalyticsRequestParams = (state, getters) => {
const {
......
......@@ -10,7 +10,6 @@ import {
GlSearchBoxByType,
} from '@gitlab/ui';
import { n__, s__, __ } from '~/locale';
import Api from '~/api';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { DATA_REFETCH_DELAY } from '../constants';
import { filterBySearchTerm } from '../utils';
......@@ -56,11 +55,6 @@ export default {
required: false,
default: () => [],
},
useGraphql: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
......@@ -133,42 +127,33 @@ export default {
fetchData() {
this.loading = true;
if (this.useGraphql) {
return this.$apollo
.query({
query: getProjects,
variables: {
groupFullPath: this.groupNamespace,
search: this.searchTerm,
...this.queryParams,
},
})
.then(response => {
const {
data: {
group: {
projects: { nodes },
},
return this.$apollo
.query({
query: getProjects,
variables: {
groupFullPath: this.groupNamespace,
search: this.searchTerm,
...this.queryParams,
},
})
.then(response => {
const {
data: {
group: {
projects: { nodes },
},
} = response;
this.loading = false;
this.projects = nodes;
});
}
},
} = response;
return Api.groupProjects(this.groupId, this.searchTerm, this.queryParams, projects => {
this.projects = projects;
this.loading = false;
});
this.loading = false;
this.projects = nodes;
});
},
isProjectSelected(id) {
return this.selectedProjects ? this.selectedProjectIds.includes(id) : false;
},
getEntityId(project) {
if (this.useGraphql) return getIdFromGraphQLId(project.id);
return project?.id || null;
return getIdFromGraphQLId(project.id);
},
},
};
......@@ -184,7 +169,7 @@ export default {
<div class="gl-display-flex gl-flex-fill-1">
<gl-avatar
v-if="isOnlyOneProjectSelected"
:src="useGraphql ? selectedProjects[0].avatarUrl : selectedProjects[0].avatar_url"
:src="selectedProjects[0].avatarUrl"
:entity-id="getEntityId(selectedProjects[0])"
:entity-name="selectedProjects[0].name"
:size="16"
......@@ -213,7 +198,7 @@ export default {
:size="16"
:entity-id="getEntityId(project)"
:entity-name="project.name"
:src="useGraphql ? project.avatarUrl : project.avatar_url"
:src="project.avatarUrl"
shape="rect"
/>
{{ project.name }}
......
......@@ -14,10 +14,6 @@ export const scatterChartLineProps = {
},
};
export const LAST_ACTIVITY_AT = 'last_activity_at';
export const SIMILARITY_ORDER = 'similarity';
export const DATE_RANGE_LIMIT = 180;
export const OFFSET_DATE_BY_ONE = 1;
......
......@@ -113,7 +113,7 @@ module Gitlab
def project_data_attributes(project)
{
id: project.id,
id: project.to_gid.to_s,
name: project.name,
path_with_namespace: project.path_with_namespace,
avatar_url: project.avatar_url
......
......@@ -24,6 +24,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
import UrlSync from '~/vue_shared/components/url_sync.vue';
import * as commonUtils from '~/lib/utils/common_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import * as mockData from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
......@@ -62,6 +63,11 @@ const mocks = {
$toast: {
show: jest.fn(),
},
$apollo: {
query: jest.fn().mockResolvedValue({
data: { group: { projects: { nodes: [] } } },
}),
},
};
function mockRequiredRoutes(mockAdapter) {
......@@ -387,25 +393,6 @@ describe('Cycle Analytics component', () => {
});
});
describe('when analyticsSimilaritySearch feature flag is on', () => {
beforeEach(async () => {
wrapper = await createComponent({
withStageSelected: true,
featureFlags: {
hasAnalyticsSimilaritySearch: true,
},
});
});
it('uses similarity as the order param', () => {
displaysProjectsDropdownFilter(true);
expect(wrapper.find(ProjectsDropdownFilter).props().queryParams.order_by).toEqual(
'similarity',
);
});
});
it('displays the date range picker', () => {
displaysDateRangePicker(true);
});
......@@ -632,7 +619,7 @@ describe('Cycle Analytics component', () => {
project_ids: null,
};
const selectedProjectIds = mockData.selectedProjects.map(({ id }) => id);
const selectedProjectIds = mockData.selectedProjects.map(({ id }) => getIdFromGraphQLId(id));
beforeEach(async () => {
commonUtils.historyPushState = jest.fn();
......
......@@ -251,13 +251,13 @@ export const rawDurationMedianData = [
export const selectedProjects = [
{
id: 1,
id: 'gid://gitlab/Project/1',
name: 'cool project',
pathWithNamespace: 'group/cool-project',
avatarUrl: null,
},
{
id: 2,
id: 'gid://gitlab/Project/2',
name: 'another cool project',
pathWithNamespace: 'group/another-cool-project',
avatarUrl: null,
......
......@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::RequestParams do
describe 'optional `project_ids`' do
context 'when `project_ids` is not empty' do
def json_project(project)
{ id: project.id,
{ id: project.to_gid.to_s,
name: project.name,
path_with_namespace: project.path_with_namespace,
avatar_url: project.avatar_url }.to_json
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment