summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/admin/statistics_panel/components/app.vue45
-rw-r--r--app/assets/javascripts/admin/statistics_panel/constants.js14
-rw-r--r--app/assets/javascripts/admin/statistics_panel/index.js22
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/actions.js28
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/getters.js17
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/index.js16
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/mutation_types.js3
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/mutations.js16
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/state.js5
-rw-r--r--app/assets/javascripts/api.js6
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js8
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js2
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue6
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue1
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue1
-rw-r--r--app/assets/javascripts/pages/admin/index.js7
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue3
-rw-r--r--app/assets/javascripts/pipelines/mixins/graph_component_mixin.js10
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue49
22 files changed, 247 insertions, 18 deletions
diff --git a/app/assets/javascripts/admin/statistics_panel/components/app.vue b/app/assets/javascripts/admin/statistics_panel/components/app.vue
new file mode 100644
index 00000000000..29077d926cf
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/components/app.vue
@@ -0,0 +1,45 @@
+<script>
+import { mapState, mapGetters, mapActions } from 'vuex';
+import { GlLoadingIcon } from '@gitlab/ui';
+import statisticsLabels from '../constants';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ },
+ data() {
+ return {
+ statisticsLabels,
+ };
+ },
+ computed: {
+ ...mapState(['isLoading', 'statistics']),
+ ...mapGetters(['getStatistics']),
+ },
+ mounted() {
+ this.fetchStatistics();
+ },
+ methods: {
+ ...mapActions(['fetchStatistics']),
+ },
+};
+</script>
+
+<template>
+ <div class="info-well">
+ <div class="well-segment admin-well admin-well-statistics">
+ <h4>{{ __('Statistics') }}</h4>
+ <gl-loading-icon v-if="isLoading" size="md" class="my-3" />
+ <template v-else>
+ <p
+ v-for="statistic in getStatistics(statisticsLabels)"
+ :key="statistic.key"
+ class="js-stats"
+ >
+ {{ statistic.label }}
+ <span class="light float-right">{{ statistic.value }}</span>
+ </p>
+ </template>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/admin/statistics_panel/constants.js b/app/assets/javascripts/admin/statistics_panel/constants.js
new file mode 100644
index 00000000000..2dce19a3894
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/constants.js
@@ -0,0 +1,14 @@
+import { s__ } from '~/locale';
+
+const statisticsLabels = {
+ forks: s__('AdminStatistics|Forks'),
+ issues: s__('AdminStatistics|Issues'),
+ mergeRequests: s__('AdminStatistics|Merge Requests'),
+ notes: s__('AdminStatistics|Notes'),
+ snippets: s__('AdminStatistics|Snippets'),
+ sshKeys: s__('AdminStatistics|SSH Keys'),
+ milestones: s__('AdminStatistics|Milestones'),
+ activeUsers: s__('AdminStatistics|Active Users'),
+};
+
+export default statisticsLabels;
diff --git a/app/assets/javascripts/admin/statistics_panel/index.js b/app/assets/javascripts/admin/statistics_panel/index.js
new file mode 100644
index 00000000000..39112e3ddc0
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import StatisticsPanelApp from './components/app.vue';
+import createStore from './store';
+
+export default function(el) {
+ if (!el) {
+ return false;
+ }
+
+ const store = createStore();
+
+ return new Vue({
+ el,
+ store,
+ components: {
+ StatisticsPanelApp,
+ },
+ render(h) {
+ return h(StatisticsPanelApp);
+ },
+ });
+}
diff --git a/app/assets/javascripts/admin/statistics_panel/store/actions.js b/app/assets/javascripts/admin/statistics_panel/store/actions.js
new file mode 100644
index 00000000000..537025f524c
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/actions.js
@@ -0,0 +1,28 @@
+import Api from '~/api';
+import { s__ } from '~/locale';
+import createFlash from '~/flash';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import * as types from './mutation_types';
+
+export const requestStatistics = ({ commit }) => commit(types.REQUEST_STATISTICS);
+
+export const fetchStatistics = ({ dispatch }) => {
+ dispatch('requestStatistics');
+
+ Api.adminStatistics()
+ .then(({ data }) => {
+ dispatch('receiveStatisticsSuccess', convertObjectPropsToCamelCase(data, { deep: true }));
+ })
+ .catch(error => dispatch('receiveStatisticsError', error));
+};
+
+export const receiveStatisticsSuccess = ({ commit }, statistics) =>
+ commit(types.RECEIVE_STATISTICS_SUCCESS, statistics);
+
+export const receiveStatisticsError = ({ commit }, error) => {
+ commit(types.RECEIVE_STATISTICS_ERROR, error);
+ createFlash(s__('AdminDashboard|Error loading the statistics. Please try again'));
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/admin/statistics_panel/store/getters.js b/app/assets/javascripts/admin/statistics_panel/store/getters.js
new file mode 100644
index 00000000000..24437bc76bf
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/getters.js
@@ -0,0 +1,17 @@
+/**
+ * Merges the statisticsLabels with the state's data
+ * and returns an array of the following form:
+ * [{ key: "forks", label: "Forks", value: 50 }]
+ */
+export const getStatistics = state => labels =>
+ Object.keys(labels).map(key => {
+ const result = {
+ key,
+ label: labels[key],
+ value: state.statistics && state.statistics[key] ? state.statistics[key] : null,
+ };
+ return result;
+ });
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/admin/statistics_panel/store/index.js b/app/assets/javascripts/admin/statistics_panel/store/index.js
new file mode 100644
index 00000000000..ece9e6419dd
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/index.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+import state from './state';
+
+Vue.use(Vuex);
+
+export default () =>
+ new Vuex.Store({
+ actions,
+ getters,
+ mutations,
+ state: state(),
+ });
diff --git a/app/assets/javascripts/admin/statistics_panel/store/mutation_types.js b/app/assets/javascripts/admin/statistics_panel/store/mutation_types.js
new file mode 100644
index 00000000000..4e0ca4ed3cd
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/mutation_types.js
@@ -0,0 +1,3 @@
+export const REQUEST_STATISTICS = 'REQUEST_STATISTICS';
+export const RECEIVE_STATISTICS_SUCCESS = 'RECEIVE_STATISTICS_SUCCESS';
+export const RECEIVE_STATISTICS_ERROR = 'RECEIVE_STATISTICS_ERROR';
diff --git a/app/assets/javascripts/admin/statistics_panel/store/mutations.js b/app/assets/javascripts/admin/statistics_panel/store/mutations.js
new file mode 100644
index 00000000000..d0fac5cfbab
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/mutations.js
@@ -0,0 +1,16 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.REQUEST_STATISTICS](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_STATISTICS_SUCCESS](state, data) {
+ state.isLoading = false;
+ state.error = null;
+ state.statistics = data;
+ },
+ [types.RECEIVE_STATISTICS_ERROR](state, error) {
+ state.isLoading = false;
+ state.error = error;
+ },
+};
diff --git a/app/assets/javascripts/admin/statistics_panel/store/state.js b/app/assets/javascripts/admin/statistics_panel/store/state.js
new file mode 100644
index 00000000000..f2f2dc0a4d2
--- /dev/null
+++ b/app/assets/javascripts/admin/statistics_panel/store/state.js
@@ -0,0 +1,5 @@
+export default () => ({
+ error: null,
+ isLoading: false,
+ statistics: null,
+});
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 136ffdf8b9d..1d97ad5ec11 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -36,6 +36,7 @@ const Api = {
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
createBranchPath: '/api/:version/projects/:id/repository/branches',
releasesPath: '/api/:version/projects/:id/releases',
+ adminStatisticsPath: 'api/:version/application/statistics',
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
@@ -376,6 +377,11 @@ const Api = {
return axios.get(url);
},
+ adminStatistics() {
+ const url = Api.buildUrl(this.adminStatisticsPath);
+ return axios.get(url);
+ },
+
buildUrl(url) {
return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
},
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 7e3515b1f4b..66cb9fd7672 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -46,7 +46,6 @@ export default class Shortcuts {
$(document).on('click.more_help', '.js-more-help-button', function clickMoreHelp(e) {
$(this).remove();
- $('.hidden-shortcut').show();
e.preventDefault();
});
}
@@ -104,7 +103,6 @@ export default class Shortcuts {
return results;
}
- $('.hidden-shortcut').show();
return $('.js-more-help-button').remove();
});
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
index c8eb96a625c..f7b327b2af1 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
@@ -6,7 +6,7 @@ import { CopyAsGFM } from '../markdown/copy_as_gfm';
import { getSelectedFragment } from '~/lib/utils/common_utils';
export default class ShortcutsIssuable extends Shortcuts {
- constructor(isMergeRequest) {
+ constructor() {
super();
Mousetrap.bind('a', () => ShortcutsIssuable.openSidebarDropdown('assignee'));
@@ -14,12 +14,6 @@ export default class ShortcutsIssuable extends Shortcuts {
Mousetrap.bind('l', () => ShortcutsIssuable.openSidebarDropdown('labels'));
Mousetrap.bind('r', ShortcutsIssuable.replyWithSelectedText);
Mousetrap.bind('e', ShortcutsIssuable.editIssue);
-
- if (isMergeRequest) {
- this.enabledHelp.push('.hidden-shortcut.merge_requests');
- } else {
- this.enabledHelp.push('.hidden-shortcut.issues');
- }
}
static replyWithSelectedText() {
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js
index bef1553703b..b46b4132ba8 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js
@@ -23,7 +23,5 @@ export default class ShortcutsNavigation extends Shortcuts {
Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-environments'));
Mousetrap.bind('g l', () => findAndFollowLink('.shortcuts-metrics'));
Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue'));
-
- this.enabledHelp.push('.hidden-shortcut.project');
}
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js
index a88c280fa3b..3e791e4673a 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js
@@ -11,7 +11,5 @@ export default class ShortcutsNetwork extends ShortcutsNavigation {
Mousetrap.bind(['down', 'j'], graph.scrollDown);
Mousetrap.bind(['shift+up', 'shift+k'], graph.scrollTop);
Mousetrap.bind(['shift+down', 'shift+j'], graph.scrollBottom);
-
- this.enabledHelp.push('.hidden-shortcut.network');
}
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js
index 208c91a1f08..8b7e6a56d25 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js
@@ -6,8 +6,6 @@ export default class ShortcutsWiki extends ShortcutsNavigation {
constructor() {
super();
Mousetrap.bind('e', ShortcutsWiki.editWiki);
-
- this.enabledHelp.push('.hidden-shortcut.wiki');
}
static editWiki() {
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index f9284266b72..f9a08f151c5 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -2,9 +2,9 @@
import $ from 'jquery';
import { GlButton } from '@gitlab/ui';
import { getMilestone } from 'ee_else_ce/boards/boards_util';
+import ListIssue from 'ee_else_ce/boards/models/issue';
import eventHub from '../eventhub';
import ProjectSelect from './project_select.vue';
-import ListIssue from '../models/issue';
import boardsStore from '../stores/boards_store';
export default {
@@ -54,6 +54,9 @@ export default {
const assignees = this.list.assignee ? [this.list.assignee] : [];
const milestone = getMilestone(this.list);
+ const { weightFeatureAvailable } = boardsStore;
+ const { weight } = weightFeatureAvailable ? boardsStore.state.currentBoard : {};
+
const issue = new ListIssue({
title: this.title,
labels,
@@ -61,6 +64,7 @@ export default {
assignees,
milestone,
project_id: this.selectedProject.id,
+ weight,
});
eventHub.$emit(`scroll-board-list-${this.list.id}`);
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 7296426549a..ebb2f5b23e4 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -245,6 +245,7 @@ export default {
<div
v-if="!loading"
ref="content"
+ data-qa-selector="boards_dropdown_content"
class="dropdown-content flex-fill"
@scroll.passive="throttledSetScrollFade"
>
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index b6da572b201..27959898fb7 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -458,7 +458,6 @@ export default {
</div>
</application-row>
<application-row
- v-if="isProjectCluster"
id="knative"
:logo-url="knativeLogo"
:title="applications.knative.title"
diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js
index 8a32556f06c..74f2eead755 100644
--- a/app/assets/javascripts/pages/admin/index.js
+++ b/app/assets/javascripts/pages/admin/index.js
@@ -1,3 +1,8 @@
import initAdmin from './admin';
+import initAdminStatisticsPanel from '../../admin/statistics_panel/index';
-document.addEventListener('DOMContentLoaded', initAdmin());
+document.addEventListener('DOMContentLoaded', () => {
+ const statisticsPanelContainer = document.getElementById('js-admin-statistics-container');
+ initAdmin();
+ initAdminStatisticsPanel(statisticsPanelContainer);
+});
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index ba0dea626dc..27c1b639889 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -20,6 +20,9 @@ export default {
<stage-column-component
v-for="(stage, index) in graph"
:key="stage.name"
+ :class="{
+ 'append-right-48': shouldAddRightMargin(index),
+ }"
:title="capitalizeStageName(stage.name)"
:groups="stage.groups"
:stage-connector-class="stageConnectorClass(index, stage)"
diff --git a/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js b/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js
index 66e9476dadf..f383a4b3368 100644
--- a/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js
+++ b/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js
@@ -40,5 +40,15 @@ export default {
refreshPipelineGraph() {
this.$emit('refreshPipelineGraph');
},
+ /**
+ * CSS class is applied:
+ * - if pipeline graph contains only one stage column component
+ *
+ * @param {number} index
+ * @returns {boolean}
+ */
+ shouldAddRightMargin(index) {
+ return !(index === this.graph.length - 1);
+ },
},
};
diff --git a/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue b/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue
new file mode 100644
index 00000000000..b649dac029a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue
@@ -0,0 +1,49 @@
+<script>
+import { GlToggle } from '@gitlab/ui';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+
+export default {
+ name: 'GlToggleVuex',
+ components: {
+ GlToggle,
+ },
+ props: {
+ stateProperty: {
+ type: String,
+ required: true,
+ },
+ storeModule: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ setAction: {
+ type: String,
+ required: false,
+ default() {
+ return `set${capitalizeFirstCharacter(this.stateProperty)}`;
+ },
+ },
+ },
+ computed: {
+ value: {
+ get() {
+ const { state } = this.$store;
+ const { stateProperty, storeModule } = this;
+ return storeModule ? state[storeModule][stateProperty] : state[stateProperty];
+ },
+ set(value) {
+ const { stateProperty, storeModule, setAction } = this;
+ const action = storeModule ? `${storeModule}/${setAction}` : setAction;
+ this.$store.dispatch(action, { key: stateProperty, value });
+ },
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-toggle v-model="value">
+ <slot v-bind="{ value }"></slot>
+ </gl-toggle>
+</template>