summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-14 12:09:26 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-14 12:09:26 +0000
commit2e4c4055181eec9186458dd5dd3219c937032ec7 (patch)
treeeee59e7124ffcf093f1b53369436c69cfe4d9cc5 /app
parent97f0ae7454597105a27df65ffb772949d9d4f3cb (diff)
downloadgitlab-ce-2e4c4055181eec9186458dd5dd3219c937032ec7.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue12
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue48
-rw-r--r--app/assets/javascripts/monitoring/constants.js5
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js4
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js56
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js6
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue3
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue7
-rw-r--r--app/assets/stylesheets/pages/prometheus.scss7
-rw-r--r--app/controllers/projects/import/jira_controller.rb6
-rw-r--r--app/graphql/resolvers/projects/jira_imports_resolver.rb2
-rw-r--r--app/services/jira_import/start_import_service.rb1
13 files changed, 76 insertions, 83 deletions
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 9db29f327da..15b17f01daf 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -19,12 +19,7 @@ import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import { s__ } from '~/locale';
import createFlash from '~/flash';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import {
- mergeUrlParams,
- redirectTo,
- refreshCurrentPage,
- updateHistory,
-} from '~/lib/utils/url_utility';
+import { mergeUrlParams, redirectTo, updateHistory } from '~/lib/utils/url_utility';
import invalidUrl from '~/lib/utils/invalid_url';
import Icon from '~/vue_shared/components/icon.vue';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
@@ -273,6 +268,7 @@ export default {
...mapActions('monitoringDashboard', [
'setTimeRange',
'fetchData',
+ 'fetchDashboardData',
'setGettingStartedEmptyState',
'setInitialState',
'setPanelGroupMetrics',
@@ -360,7 +356,7 @@ export default {
},
refreshDashboard() {
- refreshCurrentPage();
+ this.fetchDashboardData();
},
onTimeRangeZoom({ start, end }) {
@@ -475,7 +471,7 @@ export default {
ref="refreshDashboardBtn"
v-gl-tooltip
variant="default"
- :title="s__('Metrics|Reload this page')"
+ :title="s__('Metrics|Refresh dashboard')"
@click="refreshDashboard"
>
<icon name="retry" />
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index 44e38089da8..d1394bca447 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -4,6 +4,7 @@ import { pickBy } from 'lodash';
import invalidUrl from '~/lib/utils/invalid_url';
import {
GlResizeObserverDirective,
+ GlLoadingIcon,
GlDropdown,
GlDropdownItem,
GlModal,
@@ -37,6 +38,7 @@ export default {
MonitorStackedColumnChart,
MonitorEmptyChart,
Icon,
+ GlLoadingIcon,
GlTooltip,
GlDropdown,
GlDropdownItem,
@@ -104,13 +106,17 @@ export default {
// This method is extended by ee functionality
return false;
},
- graphDataHasMetrics() {
+ graphDataHasResult() {
return (
this.graphData.metrics &&
this.graphData.metrics[0].result &&
this.graphData.metrics[0].result.length > 0
);
},
+ graphDataIsLoading() {
+ const { metrics = [] } = this.graphData;
+ return metrics.some(({ loading }) => loading);
+ },
logsPathWithTimeRange() {
const timeRange = this.zoomedTimeRange || this.timeRange;
@@ -140,7 +146,7 @@ export default {
},
isContextualMenuShown() {
return (
- this.graphDataHasMetrics &&
+ this.graphDataHasResult &&
!this.isPanelType('single-stat') &&
!this.isPanelType('heatmap') &&
!this.isPanelType('column') &&
@@ -193,7 +199,7 @@ export default {
</script>
<template>
<div v-gl-resize-observer="onResize" class="prometheus-graph">
- <div class="prometheus-graph-header">
+ <div class="d-flex align-items-center mr-3">
<h5
ref="graphTitle"
class="prometheus-graph-title gl-font-size-large font-weight-bold text-truncate append-right-8"
@@ -203,23 +209,27 @@ export default {
<gl-tooltip :target="() => $refs.graphTitle" :disabled="!showTitleTooltip">
{{ title }}
</gl-tooltip>
+ <alert-widget
+ v-if="isContextualMenuShown && alertWidgetAvailable"
+ class="mx-1"
+ :modal-id="`alert-modal-${index}`"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.metrics"
+ :alerts-to-manage="getGraphAlerts(graphData.metrics)"
+ @setAlerts="setAlerts"
+ />
+ <div class="flex-grow-1"></div>
+ <div v-if="graphDataIsLoading" class="mx-1 mt-1">
+ <gl-loading-icon />
+ </div>
<div
v-if="isContextualMenuShown"
- class="prometheus-graph-widgets js-graph-widgets flex-fill"
+ class="js-graph-widgets"
data-qa-selector="prometheus_graph_widgets"
>
<div class="d-flex align-items-center">
- <alert-widget
- v-if="alertWidgetAvailable"
- :modal-id="`alert-modal-${index}`"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.metrics"
- :alerts-to-manage="getGraphAlerts(graphData.metrics)"
- @setAlerts="setAlerts"
- />
<gl-dropdown
v-gl-tooltip
- class="ml-auto mx-3"
toggle-class="btn btn-transparent border-0"
data-qa-selector="prometheus_widgets_dropdown"
right
@@ -275,28 +285,28 @@ export default {
</div>
<monitor-single-stat-chart
- v-if="isPanelType('single-stat') && graphDataHasMetrics"
+ v-if="isPanelType('single-stat') && graphDataHasResult"
:graph-data="graphData"
/>
<monitor-heatmap-chart
- v-else-if="isPanelType('heatmap') && graphDataHasMetrics"
+ v-else-if="isPanelType('heatmap') && graphDataHasResult"
:graph-data="graphData"
/>
<monitor-bar-chart
- v-else-if="isPanelType('bar') && graphDataHasMetrics"
+ v-else-if="isPanelType('bar') && graphDataHasResult"
:graph-data="graphData"
/>
<monitor-column-chart
- v-else-if="isPanelType('column') && graphDataHasMetrics"
+ v-else-if="isPanelType('column') && graphDataHasResult"
:graph-data="graphData"
/>
<monitor-stacked-column-chart
- v-else-if="isPanelType('stacked-column') && graphDataHasMetrics"
+ v-else-if="isPanelType('stacked-column') && graphDataHasResult"
:graph-data="graphData"
/>
<component
:is="timeChartComponent"
- v-else-if="graphDataHasMetrics"
+ v-else-if="graphDataHasResult"
ref="timeChart"
:graph-data="graphData"
:deployment-data="deploymentData"
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index 6af1d399cfc..8d821c27099 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -10,7 +10,10 @@ export const metricStates = {
OK: 'OK',
/**
- * Metric data is being fetched
+ * Metric data is being fetched for the first time.
+ *
+ * Not used during data refresh, if data is available in
+ * the metric, the recommneded state is OK.
*/
LOADING: 'LOADING',
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 8427a72a68e..06b99f572e7 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -128,7 +128,7 @@ export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response
commit(types.RECEIVE_METRICS_DASHBOARD_SUCCESS, dashboard);
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data));
- return dispatch('fetchPrometheusMetrics');
+ return dispatch('fetchDashboardData');
};
export const receiveMetricsDashboardFailure = ({ commit }, error) => {
commit(types.RECEIVE_METRICS_DASHBOARD_FAILURE, error);
@@ -140,7 +140,7 @@ export const receiveMetricsDashboardFailure = ({ commit }, error) => {
* Loads timeseries data: Prometheus data points and deployment data from the project
* @param {Object} Vuex store
*/
-export const fetchPrometheusMetrics = ({ state, dispatch, getters }) => {
+export const fetchDashboardData = ({ state, dispatch, getters }) => {
dispatch('fetchDeploymentsData');
if (!state.timeRange) {
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index 0a7bb47d533..38c1524d904 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -1,4 +1,3 @@
-import Vue from 'vue';
import pick from 'lodash/pick';
import * as types from './mutation_types';
import { mapToDashboardViewModel, normalizeQueryResult } from './utils';
@@ -27,24 +26,6 @@ const findMetricInDashboard = (metricId, dashboard) => {
};
/**
- * Set a new state for a metric.
- *
- * Initally metric data is not populated, so `Vue.set` is
- * used to add new properties to the metric.
- *
- * @param {Object} metric - Metric object as defined in the dashboard
- * @param {Object} state - New state
- * @param {Array|null} state.result - Array of results
- * @param {String} state.error - Error code from metricStates
- * @param {Boolean} state.loading - True if the metric is loading
- */
-const setMetricState = (metric, { result = null, loading = false, state = null }) => {
- Vue.set(metric, 'result', result);
- Vue.set(metric, 'loading', loading);
- Vue.set(metric, 'state', state);
-};
-
-/**
* Maps a backened error state to a `metricStates` constant
* @param {Object} error - Error from backend response
*/
@@ -116,39 +97,32 @@ export default {
*/
[types.REQUEST_METRIC_RESULT](state, { metricId }) {
const metric = findMetricInDashboard(metricId, state.dashboard);
- setMetricState(metric, {
- loading: true,
- state: metricStates.LOADING,
- });
+ metric.loading = true;
+ if (!metric.result) {
+ metric.state = metricStates.LOADING;
+ }
},
[types.RECEIVE_METRIC_RESULT_SUCCESS](state, { metricId, result }) {
- if (!metricId) {
- return;
- }
-
+ const metric = findMetricInDashboard(metricId, state.dashboard);
+ metric.loading = false;
state.showEmptyState = false;
- const metric = findMetricInDashboard(metricId, state.dashboard);
if (!result || result.length === 0) {
- setMetricState(metric, {
- state: metricStates.NO_DATA,
- });
+ metric.state = metricStates.NO_DATA;
+ metric.result = null;
} else {
const normalizedResults = result.map(normalizeQueryResult);
- setMetricState(metric, {
- result: Object.freeze(normalizedResults),
- state: metricStates.OK,
- });
+
+ metric.state = metricStates.OK;
+ metric.result = Object.freeze(normalizedResults);
}
},
[types.RECEIVE_METRIC_RESULT_FAILURE](state, { metricId, error }) {
- if (!metricId) {
- return;
- }
const metric = findMetricInDashboard(metricId, state.dashboard);
- setMetricState(metric, {
- state: emptyStateFromError(error),
- });
+
+ metric.state = emptyStateFromError(error);
+ metric.loading = false;
+ metric.result = null;
},
[types.SET_INITIAL_STATE](state, initialState = {}) {
Object.assign(state, pick(initialState, initialStateKeys));
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index d01acdd031b..a212e9be703 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -76,6 +76,12 @@ const mapToMetricsViewModel = metrics =>
queryRange: query_range,
prometheusEndpointPath: prometheus_endpoint_path,
metricId: uniqMetricsId({ metric_id, id }),
+
+ // metric data
+ loading: false,
+ result: null,
+ state: null,
+
...metric,
}));
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index a58a040fb4e..cd5cfc09ea0 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -1,5 +1,4 @@
<script>
-/* eslint-disable @gitlab/vue-require-i18n-strings */
import { mapState, mapActions } from 'vuex';
import { GlSkeletonLoading } from '@gitlab/ui';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
@@ -96,7 +95,7 @@ export default {
<td class="old_line diff-line-num"></td>
<td class="new_line diff-line-num"></td>
<td v-if="error" class="js-error-lazy-load-diff diff-loading-error-block">
- {{ error }} Unable to load the diff
+ {{ __('Unable to load the diff') }}
<button
class="btn-link btn-link-retry btn-no-padding js-toggle-lazy-diff-retry-button"
@click="fetchDiff"
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
index 65c1f125b55..be7f27f210d 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
@@ -74,7 +74,7 @@ export default {
<div class="table-section section-20 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div>
- <div class="table-mobile-content">{{ testCase.name }}</div>
+ <div class="table-mobile-content pr-md-1 text-truncate">{{ testCase.name }}</div>
</div>
<div class="table-section section-10 section-wrap">
diff --git a/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue b/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue
new file mode 100644
index 00000000000..74f988476e3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue
@@ -0,0 +1,7 @@
+<template functional>
+ <footer class="form-actions d-flex justify-content-between">
+ <div><slot name="prepend"></slot></div>
+ <div><slot></slot></div>
+ <div><slot name="append"></slot></div>
+ </footer>
+</template>
diff --git a/app/assets/stylesheets/pages/prometheus.scss b/app/assets/stylesheets/pages/prometheus.scss
index 6e5daef3e7d..af0afa9cc3b 100644
--- a/app/assets/stylesheets/pages/prometheus.scss
+++ b/app/assets/stylesheets/pages/prometheus.scss
@@ -84,13 +84,6 @@
border-radius: $border-radius-default;
}
-.prometheus-graph-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: $gl-padding-8;
-}
-
.alert-current-setting {
max-width: 240px;
diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb
index ca427928d85..26d9b4b223f 100644
--- a/app/controllers/projects/import/jira_controller.rb
+++ b/app/controllers/projects/import/jira_controller.rb
@@ -3,14 +3,18 @@
module Projects
module Import
class JiraController < Projects::ApplicationController
+ before_action :authenticate_user!
+ before_action :check_issues_available!
+ before_action :authorize_read_project!
before_action :jira_import_enabled?
before_action :jira_integration_configured?
+ before_action :authorize_admin_project!, only: [:import]
def show
@is_jira_configured = @project.jira_service.present?
return if Feature.enabled?(:jira_issue_import_vue, @project)
- unless @project.latest_jira_import&.in_progress?
+ if !@project.latest_jira_import&.in_progress? && current_user&.can?(:admin_project, @project)
jira_client = @project.jira_service.client
jira_projects = jira_client.Project.all
diff --git a/app/graphql/resolvers/projects/jira_imports_resolver.rb b/app/graphql/resolvers/projects/jira_imports_resolver.rb
index b0784b3cdf7..25361c068d9 100644
--- a/app/graphql/resolvers/projects/jira_imports_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_imports_resolver.rb
@@ -16,7 +16,7 @@ module Resolvers
def authorized_resource?(project)
return false unless project.jira_issues_import_feature_flag_enabled?
- Ability.allowed?(context[:current_user], :admin_project, project)
+ context[:current_user].present? && Ability.allowed?(context[:current_user], :read_project, project)
end
end
end
diff --git a/app/services/jira_import/start_import_service.rb b/app/services/jira_import/start_import_service.rb
index 134cef089e7..6accc3cfffc 100644
--- a/app/services/jira_import/start_import_service.rb
+++ b/app/services/jira_import/start_import_service.rb
@@ -46,6 +46,7 @@ module JiraImport
def validate
return build_error_response(_('Jira import feature is disabled.')) unless project.jira_issues_import_feature_flag_enabled?
return build_error_response(_('You do not have permissions to run the import.')) unless user.can?(:admin_project, project)
+ return build_error_response(_('Cannot import because issues are not available in this project.')) unless project.feature_available?(:issues, user)
return build_error_response(_('Jira integration not configured.')) unless project.jira_service&.active?
return build_error_response(_('Unable to find Jira project to import data from.')) if jira_project_key.blank?
return build_error_response(_('Jira import is already running.')) if import_in_progress?