Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlena Horal-Koretska <ohoralkoretska@gitlab.com>2019-08-29 22:14:58 +0300
committerOlena Horal-Koretska <ohoralkoretska@gitlab.com>2019-08-29 22:14:58 +0300
commit20ccdb0763b536c727735ad338d112f511a41f3e (patch)
tree043636931552aa764d4a3deab17e09fe5941ad59
parentad666a697bdd3615183d7e2224cecf85f4d6def5 (diff)
Basic structure
-rw-r--r--app/assets/javascripts/contributors/components/contributors.vue132
-rw-r--r--app/assets/javascripts/contributors/filtered_search_issues_analytics.js27
-rw-r--r--app/assets/javascripts/contributors/index.js25
-rw-r--r--app/assets/javascripts/contributors/services/contributors_service.js7
-rw-r--r--app/assets/javascripts/contributors/stores/index.js14
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/actions.js26
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/getters.js2
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/index.js12
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/mutation_types.js3
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/mutations.js15
-rw-r--r--app/assets/javascripts/contributors/stores/modules/contributors/state.js5
-rw-r--r--app/assets/javascripts/pages/projects/graphs/charts/index.js1
-rw-r--r--app/assets/javascripts/pages/projects/graphs/show/index.js4
-rw-r--r--app/views/projects/graphs/show.html.haml2
14 files changed, 275 insertions, 0 deletions
diff --git a/app/assets/javascripts/contributors/components/contributors.vue b/app/assets/javascripts/contributors/components/contributors.vue
new file mode 100644
index 00000000000..6da3729b8b6
--- /dev/null
+++ b/app/assets/javascripts/contributors/components/contributors.vue
@@ -0,0 +1,132 @@
+<script>
+import { s__ } from '~/locale';
+import { mapGetters, mapActions, mapState } from 'vuex';
+import { engineeringNotation, sum, average } from '@gitlab/ui/utils/number_utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import { GlChartLegend } from '@gitlab/ui/charts';
+import { GlAreaChart } from '@gitlab/ui/dist/charts';
+import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
+
+export default {
+ components: {
+ GlAreaChart,
+ GlLoadingIcon,
+ GlChartLegend,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ svgs: {},
+ chart: null,
+ seriesInfo: [
+ {
+ type: 'solid',
+ name: s__('IssuesAnalytics | Issues created'),
+ color: '#1F78D1',
+ },
+ ],
+ };
+ },
+ computed: {
+ ...mapState('contributors', ['chartData', 'loading']),
+ ...mapGetters('contributors', ['hasFilters', 'appliedFilters']),
+ data() {
+ const { chartData, chartHasData } = this;
+ const data = [];
+
+ if (chartHasData()) {
+ Object.keys(chartData).forEach(key => {
+ const date = new Date(key);
+ const label = `${getMonthNames(true)[date.getUTCMonth()]} ${date.getUTCFullYear()}`;
+ const val = chartData[key];
+
+ data.push([label, val]);
+ });
+ }
+
+ return data;
+ },
+ chartLabels() {
+ return this.data.map(val => val[0]);
+ },
+ chartDateRange() {
+ return `${this.chartLabels[0]} - ${this.chartLabels[this.chartLabels.length - 1]}`;
+ },
+ showChart() {
+ return !this.loading && this.chartHasData();
+ },
+ chartOptions() {
+ return {
+ dataZoom: [
+ {
+ type: 'slider',
+ startValue: 0,
+ handleIcon: this.svgs['scroll-handle'],
+ },
+ ],
+ };
+ },
+ series() {
+ return this.data.map(val => val[1]);
+ },
+ seriesAverage() {
+ return engineeringNotation(average(...this.series), 0);
+ },
+ seriesTotal() {
+ return engineeringNotation(sum(...this.series));
+ },
+ },
+ watch: {
+ appliedFilters() {
+ this.fetchChartData(this.endpoint);
+ },
+ showNoDataEmptyState(showEmptyState) {
+ if (showEmptyState) {
+ this.$nextTick(() => this.filterBlockEl.classList.add('hide'));
+ }
+ },
+ },
+ created() {
+ this.setSvg('scroll-handle');
+ },
+ mounted() {
+ this.fetchChartData(this.endpoint);
+ },
+ methods: {
+ ...mapActions('contributors', ['fetchChartData']),
+ onCreated(chart) {
+ this.chart = chart;
+ },
+ chartHasData() {
+ if (!this.chartData) {
+ return false;
+ }
+
+ return Object.values(this.chartData).some(val => val > 0);
+ },
+ setSvg(name) {
+ getSvgIconPathContent(name)
+ .then(path => {
+ if (path) {
+ this.$set(this.svgs, name, `path://${path}`);
+ }
+ })
+ .catch(() => {});
+ },
+ },
+};
+</script>
+<template>
+ <div class="issues-analytics-wrapper">
+ <!-- <div v-if="loading" class="issues-analytics-loading text-center">
+ <gl-loading-icon :inline="true" :size="4"/>
+ </div>-->
+
+ This is just the beginning
+ </div>
+</template>
diff --git a/app/assets/javascripts/contributors/filtered_search_issues_analytics.js b/app/assets/javascripts/contributors/filtered_search_issues_analytics.js
new file mode 100644
index 00000000000..7248bf2ae21
--- /dev/null
+++ b/app/assets/javascripts/contributors/filtered_search_issues_analytics.js
@@ -0,0 +1,27 @@
+import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
+import FilteredSearchManager from '~/filtered_search/filtered_search_manager';
+import { historyPushState } from '~/lib/utils/common_utils';
+import issueAnalyticsStore from './stores';
+
+export default class FilteredSearchIssueAnalytics extends FilteredSearchManager {
+ constructor() {
+ super({
+ page: 'issues_analytics',
+ isGroupDecendent: true,
+ stateFiltersSelector: '.issues-state-filters',
+ isGroup: true,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ });
+
+ this.isHandledAsync = true;
+ }
+
+ /**
+ * Updates issues analytics store and window history
+ * with filter path
+ */
+ updateObject = path => {
+ historyPushState(path);
+ issueAnalyticsStore.dispatch('issueAnalytics/setFilters', path);
+ };
+}
diff --git a/app/assets/javascripts/contributors/index.js b/app/assets/javascripts/contributors/index.js
new file mode 100644
index 00000000000..d2cf2083009
--- /dev/null
+++ b/app/assets/javascripts/contributors/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import ContributorsGraphs from './components/contributors.vue';
+import store from './stores';
+
+export default () => {
+ const el = document.querySelector('.js-contributors-graph');
+
+ if (!el) return null;
+
+ return new Vue({
+ el,
+ store,
+ components: {
+ ContributorsGraphs,
+ },
+
+ render(createElement) {
+ return createElement('contributors-graphs', {
+ props: {
+ endpoint: el.dataset.projectGraphPath,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/contributors/services/contributors_service.js b/app/assets/javascripts/contributors/services/contributors_service.js
new file mode 100644
index 00000000000..f5f8fcad127
--- /dev/null
+++ b/app/assets/javascripts/contributors/services/contributors_service.js
@@ -0,0 +1,7 @@
+import axios from '~/lib/utils/axios_utils';
+
+export default {
+ fetchChartData(endpoint, filters) {
+ return axios.get(`${endpoint}${filters}`);
+ },
+};
diff --git a/app/assets/javascripts/contributors/stores/index.js b/app/assets/javascripts/contributors/stores/index.js
new file mode 100644
index 00000000000..1fb8450098d
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/index.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import contributorsGraph from './modules/contributors';
+
+Vue.use(Vuex);
+
+export const createStore = () =>
+ new Vuex.Store({
+ modules: {
+ contributors: contributorsGraph(),
+ },
+ });
+
+export default createStore();
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/actions.js b/app/assets/javascripts/contributors/stores/modules/contributors/actions.js
new file mode 100644
index 00000000000..0f65f0923ee
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/actions.js
@@ -0,0 +1,26 @@
+import flash from '~/flash';
+import { __ } from '~/locale';
+import service from '../../../services/contributors_service';
+import * as types from './mutation_types';
+
+export const setFilters = ({ commit }, value) => {
+ commit(types.SET_FILTERS, value);
+};
+
+export const setLoadingState = ({ commit }, value) => {
+ commit(types.SET_LOADING_STATE, value);
+};
+
+export const fetchChartData = ({ commit, dispatch, getters }, endpoint) => {
+ dispatch('setLoadingState', true);
+
+ return service
+ .fetchChartData(endpoint, getters.appliedFilters)
+ .then(res => res.data)
+ .then(data => commit(types.SET_CHART_DATA, data))
+ .then(() => dispatch('setLoadingState', false))
+ .catch(() => flash(__('An error occurred while loading chart data')));
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/getters.js b/app/assets/javascripts/contributors/stores/modules/contributors/getters.js
new file mode 100644
index 00000000000..608816e58d5
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/getters.js
@@ -0,0 +1,2 @@
+export const hasFilters = state => Object.keys(state.filters).length > 0;
+export const appliedFilters = state => state.filters;
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/index.js b/app/assets/javascripts/contributors/stores/modules/contributors/index.js
new file mode 100644
index 00000000000..81dab0566c1
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/index.js
@@ -0,0 +1,12 @@
+import state from './state';
+import mutations from './mutations';
+import * as actions from './actions';
+import * as getters from './getters';
+
+export default () => ({
+ namespaced: true,
+ state: state(),
+ mutations,
+ actions,
+ getters,
+});
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/mutation_types.js b/app/assets/javascripts/contributors/stores/modules/contributors/mutation_types.js
new file mode 100644
index 00000000000..7d89d99622b
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/mutation_types.js
@@ -0,0 +1,3 @@
+export const SET_FILTERS = 'SET_FILTERS';
+export const SET_CHART_DATA = 'SET_CHART_DATA';
+export const SET_LOADING_STATE = 'SET_LOADING_STATE';
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/mutations.js b/app/assets/javascripts/contributors/stores/modules/contributors/mutations.js
new file mode 100644
index 00000000000..9b0f0152879
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/mutations.js
@@ -0,0 +1,15 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_LOADING_STATE](state, value) {
+ state.loading = value;
+ },
+ [types.SET_CHART_DATA](state, chartData) {
+ Object.assign(state, {
+ chartData,
+ });
+ },
+ [types.SET_FILTERS](state, value) {
+ state.filters = value;
+ },
+};
diff --git a/app/assets/javascripts/contributors/stores/modules/contributors/state.js b/app/assets/javascripts/contributors/stores/modules/contributors/state.js
new file mode 100644
index 00000000000..1fa6e91b5d5
--- /dev/null
+++ b/app/assets/javascripts/contributors/stores/modules/contributors/state.js
@@ -0,0 +1,5 @@
+export default () => ({
+ loading: false,
+ filters: '',
+ chartData: null,
+});
diff --git a/app/assets/javascripts/pages/projects/graphs/charts/index.js b/app/assets/javascripts/pages/projects/graphs/charts/index.js
index 314519ee442..ca7db55cea1 100644
--- a/app/assets/javascripts/pages/projects/graphs/charts/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/charts/index.js
@@ -5,6 +5,7 @@ import _ from 'underscore';
import { barChartOptions, pieChartOptions } from '~/lib/utils/chart_utils';
document.addEventListener('DOMContentLoaded', () => {
+ debugger;
const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
const barChart = (selector, data) => {
diff --git a/app/assets/javascripts/pages/projects/graphs/show/index.js b/app/assets/javascripts/pages/projects/graphs/show/index.js
index f79c386b59e..81e634645ad 100644
--- a/app/assets/javascripts/pages/projects/graphs/show/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/show/index.js
@@ -3,8 +3,10 @@ import flash from '~/flash';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import ContributorsStatGraph from './stat_graph_contributors';
+import initContributorsGraphs from '~/contributors';
document.addEventListener('DOMContentLoaded', () => {
+ initContributorsGraphs();
const url = document.querySelector('.js-graphs-show').dataset.projectGraphPath;
axios
@@ -22,4 +24,6 @@ document.addEventListener('DOMContentLoaded', () => {
$('.loading-graph').hide();
})
.catch(() => flash(__('Error fetching contributors data.')));
+
+
});
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 4b2417ff43b..82c6b751fa2 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,6 +1,8 @@
- @no_container = true
- page_title _('Contributors')
+.js-contributors-graph{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
+
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
.sub-header-block
.tree-ref-holder.inline.vertical-align-middle