diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-27 00:09:19 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-27 00:09:19 +0000 |
commit | 0a0e82d1440b06650e5fc524168b1f50a8feec68 (patch) | |
tree | c2202560fb250008cf4109e99537b10604faf01b /app | |
parent | f82d5dcab7c3d9a672abc827c92f86887b683a7d (diff) | |
download | gitlab-ce-0a0e82d1440b06650e5fc524168b1f50a8feec68.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
13 files changed, 138 insertions, 94 deletions
diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index 0e86359534b..4f5d583e61f 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -26,36 +26,7 @@ class ListIssue { } refreshData(obj, defaultAvatar) { - this.id = obj.id; - this.iid = obj.iid; - this.title = obj.title; - this.confidential = obj.confidential; - this.dueDate = obj.due_date; - this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; - this.referencePath = obj.reference_path; - this.path = obj.real_path; - this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint; - this.project_id = obj.project_id; - this.timeEstimate = obj.time_estimate; - this.assignableLabelsEndpoint = obj.assignable_labels_endpoint; - this.blocked = obj.blocked; - - if (obj.project) { - this.project = new IssueProject(obj.project); - } - - if (obj.milestone) { - this.milestone = new ListMilestone(obj.milestone); - this.milestone_id = obj.milestone.id; - } - - if (obj.labels) { - this.labels = obj.labels.map(label => new ListLabel(label)); - } - - if (obj.assignees) { - this.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar)); - } + boardsStore.refreshIssueData(this, obj, defaultAvatar); } addLabel(label) { diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index f233228614f..010eda9b6c5 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -12,6 +12,10 @@ import axios from '~/lib/utils/axios_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import eventHub from '../eventhub'; import { ListType } from '../constants'; +import IssueProject from '../models/project'; +import ListLabel from '../models/label'; +import ListAssignee from '../models/assignee'; +import ListMilestone from '../models/milestone'; const boardsStore = { disabled: false, @@ -593,6 +597,38 @@ const boardsStore = { clearMultiSelect() { this.multiSelect.list = []; }, + refreshIssueData(issue, obj, defaultAvatar) { + issue.id = obj.id; + issue.iid = obj.iid; + issue.title = obj.title; + issue.confidential = obj.confidential; + issue.dueDate = obj.due_date; + issue.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; + issue.referencePath = obj.reference_path; + issue.path = obj.real_path; + issue.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint; + issue.project_id = obj.project_id; + issue.timeEstimate = obj.time_estimate; + issue.assignableLabelsEndpoint = obj.assignable_labels_endpoint; + issue.blocked = obj.blocked; + + if (obj.project) { + issue.project = new IssueProject(obj.project); + } + + if (obj.milestone) { + issue.milestone = new ListMilestone(obj.milestone); + issue.milestone_id = obj.milestone.id; + } + + if (obj.labels) { + issue.labels = obj.labels.map(label => new ListLabel(label)); + } + + if (obj.assignees) { + issue.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar)); + } + }, }; BoardsStoreEE.initEESpecific(boardsStore); diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 79f32b357fc..a6d10d37103 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -522,7 +522,7 @@ export default { <div v-if="!showEmptyState"> <graph-group - v-for="(groupData, index) in dashboard.panel_groups" + v-for="(groupData, index) in dashboard.panelGroups" :key="`${groupData.group}.${groupData.priority}`" :name="groupData.group" :show-panels="showPanels" diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue index 49188a7af8f..15366b45618 100644 --- a/app/assets/javascripts/monitoring/components/embed.vue +++ b/app/assets/javascripts/monitoring/components/embed.vue @@ -28,10 +28,10 @@ export default { ...mapState('monitoringDashboard', ['dashboard']), ...mapGetters('monitoringDashboard', ['metricsWithData']), charts() { - if (!this.dashboard || !this.dashboard.panel_groups) { + if (!this.dashboard || !this.dashboard.panelGroups) { return []; } - const groupWithMetrics = this.dashboard.panel_groups.find(group => + const groupWithMetrics = this.dashboard.panelGroups.find(group => group.panels.find(chart => this.chartHasData(chart)), ) || { panels: [] }; diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js index daa095d9b3b..aa6c35d97be 100644 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ b/app/assets/javascripts/monitoring/stores/actions.js @@ -51,9 +51,11 @@ export const requestMetricsDashboard = ({ commit }) => { commit(types.REQUEST_METRICS_DATA); }; export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => { - commit(types.SET_ALL_DASHBOARDS, response.all_dashboards); - commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard); - commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(response.metrics_data)); + const { all_dashboards, dashboard, metrics_data } = response; + + commit(types.SET_ALL_DASHBOARDS, all_dashboards); + commit(types.RECEIVE_METRICS_DATA_SUCCESS, dashboard); + commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data)); return dispatch('fetchPrometheusMetrics', params); }; @@ -149,16 +151,16 @@ export const fetchPrometheusMetric = ({ commit }, { metric, params }) => { step, }; - commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metric_id }); + commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId }); - return fetchPrometheusResult(metric.prometheus_endpoint_path, queryParams) + return fetchPrometheusResult(metric.prometheusEndpointPath, queryParams) .then(result => { - commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metric_id, result }); + commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metricId, result }); }) .catch(error => { Sentry.captureException(error); - commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metric_id, error }); + commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metricId, error }); // Continue to throw error so the dashboard can notify using createFlash throw error; }); @@ -168,7 +170,7 @@ export const fetchPrometheusMetrics = ({ state, commit, dispatch, getters }, par commit(types.REQUEST_METRICS_DATA); const promises = []; - state.dashboard.panel_groups.forEach(group => { + state.dashboard.panelGroups.forEach(group => { group.panels.forEach(panel => { panel.metrics.forEach(metric => { promises.push(dispatch('fetchPrometheusMetric', { metric, params })); diff --git a/app/assets/javascripts/monitoring/stores/getters.js b/app/assets/javascripts/monitoring/stores/getters.js index 3801149e49d..1affc6f0a76 100644 --- a/app/assets/javascripts/monitoring/stores/getters.js +++ b/app/assets/javascripts/monitoring/stores/getters.js @@ -11,7 +11,7 @@ const metricsIdsInPanel = panel => * states in all the metric in the dashboard or group. */ export const getMetricStates = state => groupKey => { - let groups = state.dashboard.panel_groups; + let groups = state.dashboard.panelGroups; if (groupKey) { groups = groups.filter(group => group.key === groupKey); } @@ -43,7 +43,7 @@ export const getMetricStates = state => groupKey => { * filtered by group key. */ export const metricsWithData = state => groupKey => { - let groups = state.dashboard.panel_groups; + let groups = state.dashboard.panelGroups; if (groupKey) { groups = groups.filter(group => group.key === groupKey); } diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js index 8bd53a24b61..7aac98821c9 100644 --- a/app/assets/javascripts/monitoring/stores/mutations.js +++ b/app/assets/javascripts/monitoring/stores/mutations.js @@ -1,18 +1,11 @@ import Vue from 'vue'; import pick from 'lodash/pick'; -import { slugify } from '~/lib/utils/text_utility'; import * as types from './mutation_types'; -import { normalizeMetric, normalizeQueryResult } from './utils'; +import { mapToDashboardViewModel, normalizeQueryResult } from './utils'; import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils'; import { metricStates } from '../constants'; import httpStatusCodes from '~/lib/utils/http_status'; -const normalizePanelMetrics = (metrics, defaultLabel) => - metrics.map(metric => ({ - ...normalizeMetric(metric), - label: metric.label || defaultLabel, - })); - /** * Locate and return a metric in the dashboard by its id * as generated by `uniqMetricsId()`. @@ -21,10 +14,10 @@ const normalizePanelMetrics = (metrics, defaultLabel) => */ const findMetricInDashboard = (metricId, dashboard) => { let res = null; - dashboard.panel_groups.forEach(group => { + dashboard.panelGroups.forEach(group => { group.panels.forEach(panel => { panel.metrics.forEach(metric => { - if (metric.metric_id === metricId) { + if (metric.metricId === metricId) { res = metric; } }); @@ -86,27 +79,9 @@ export default { state.showEmptyState = true; }, [types.RECEIVE_METRICS_DATA_SUCCESS](state, dashboard) { - state.dashboard = { - ...dashboard, - panel_groups: dashboard.panel_groups.map((group, i) => { - const key = `${slugify(group.group || 'default')}-${i}`; - let { panels = [] } = group; - - // each panel has metric information that needs to be normalized - panels = panels.map(panel => ({ - ...panel, - metrics: normalizePanelMetrics(panel.metrics, panel.y_label), - })); - - return { - ...group, - panels, - key, - }; - }), - }; + state.dashboard = mapToDashboardViewModel(dashboard); - if (!state.dashboard.panel_groups.length) { + if (!state.dashboard.panelGroups.length) { state.emptyState = 'noData'; } }, @@ -206,7 +181,7 @@ export default { state.showErrorBanner = enabled; }, [types.SET_PANEL_GROUP_METRICS](state, payload) { - const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key); + const panelGroup = state.dashboard.panelGroups.find(pg => payload.key === pg.key); panelGroup.panels = payload.panels; }, [types.SET_ENVIRONMENTS_FILTER](state, searchTerm) { diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js index a2050f8e893..2b1907e8df7 100644 --- a/app/assets/javascripts/monitoring/stores/state.js +++ b/app/assets/javascripts/monitoring/stores/state.js @@ -15,7 +15,7 @@ export default () => ({ showEmptyState: true, showErrorBanner: true, dashboard: { - panel_groups: [], + panelGroups: [], }, allDashboards: [], diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js index cd586c6af3e..82deaa7ccfd 100644 --- a/app/assets/javascripts/monitoring/stores/utils.js +++ b/app/assets/javascripts/monitoring/stores/utils.js @@ -1,4 +1,4 @@ -import { omit } from 'lodash'; +import { slugify } from '~/lib/utils/text_utility'; import createGqClient, { fetchPolicies } from '~/lib/graphql'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; @@ -9,6 +9,13 @@ export const gqClient = createGqClient( }, ); +/** + * Metrics loaded from project-defined dashboards do not have a metric_id. + * This method creates a unique ID combining metric_id and id, if either is present. + * This is hopefully a temporary solution until BE processes metrics before passing to fE + * @param {Object} metric - metric + * @returns {Object} - normalized metric with a uniqueID + */ export const uniqMetricsId = metric => `${metric.metric_id}_${metric.id}`; /** @@ -41,22 +48,75 @@ export const parseEnvironmentsResponse = (response = [], projectPath) => }); /** - * Metrics loaded from project-defined dashboards do not have a metric_id. - * This method creates a unique ID combining metric_id and id, if either is present. - * This is hopefully a temporary solution until BE processes metrics before passing to fE - * @param {Object} metric - metric - * @returns {Object} - normalized metric with a uniqueID + * Maps metrics to its view model + * + * This function difers from other in that is maps all + * non-define properties as-is to the object. This is not + * advisable as it could lead to unexpected side-effects. + * + * Related issue: + * https://gitlab.com/gitlab-org/gitlab/issues/207198 + * + * @param {Array} metrics - Array of prometheus metrics + * @param {String} defaultLabel - Default label for metrics + * @returns {Object} */ +const mapToMetricsViewModel = (metrics, defaultLabel) => + metrics.map(({ label, id, metric_id, query_range, prometheus_endpoint_path, ...metric }) => ({ + label: label || defaultLabel, + queryRange: query_range, + prometheusEndpointPath: prometheus_endpoint_path, + metricId: uniqMetricsId({ metric_id, id }), -export const normalizeMetric = (metric = {}) => - omit( - { - ...metric, - metric_id: uniqMetricsId(metric), - metricId: uniqMetricsId(metric), - }, - 'id', - ); + // `metric_id` is used by embed.vue, keeping this duplicated. + // https://gitlab.com/gitlab-org/gitlab/issues/37492 + metric_id: uniqMetricsId({ metric_id, id }), + ...metric, + })); + +/** + * Maps a metrics panel to its view model + * + * @param {Object} panel - Metrics panel + * @returns {Object} + */ +const mapToPanelViewModel = ({ title = '', type, y_label, metrics = [] }) => { + return { + title, + type, + y_label, + metrics: mapToMetricsViewModel(metrics, y_label), + }; +}; + +/** + * Maps a metrics panel group to its view model + * + * @param {Object} panelGroup - Panel Group + * @returns {Object} + */ +const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => { + return { + key: `${slugify(group || 'default')}-${i}`, + group, + panels: panels.map(mapToPanelViewModel), + }; +}; + +/** + * Maps a dashboard json object to its view model + * + * @param {Object} dashboard - Dashboard object + * @param {String} dashboard.dashboard - Dashboard name object + * @param {Array} dashboard.panel_groups - Panel groups array + * @returns {Object} + */ +export const mapToDashboardViewModel = ({ dashboard = '', panel_groups = [] }) => { + return { + dashboard, + panelGroups: panel_groups.map(mapToPanelGroupViewModel), + }; +}; export const normalizeQueryResult = timeSeries => { let normalizedResult = {}; diff --git a/app/assets/javascripts/monitoring/utils.js b/app/assets/javascripts/monitoring/utils.js index b2fa44835e6..6694ae2f157 100644 --- a/app/assets/javascripts/monitoring/utils.js +++ b/app/assets/javascripts/monitoring/utils.js @@ -7,7 +7,7 @@ import { /** * This method is used to validate if the graph data format for a chart component - * that needs a time series as a response from a prometheus query (query_range) is + * that needs a time series as a response from a prometheus query (queryRange) is * of a valid format or not. * @param {Object} graphData the graph data response from a prometheus request * @returns {boolean} whether the graphData format is correct diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb index 84c25cfb180..ac4ca197d72 100644 --- a/app/controllers/groups/registry/repositories_controller.rb +++ b/app/controllers/groups/registry/repositories_controller.rb @@ -17,7 +17,7 @@ module Groups serializer = ContainerRepositoriesSerializer .new(current_user: current_user) - if Feature.enabled?(:vue_container_registry_explorer) + if Feature.enabled?(:vue_container_registry_explorer, group) render json: serializer.with_pagination(request, response) .represent_read_only(@images) else diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index e524d1c29a2..d6d993f427d 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -17,7 +17,7 @@ module Projects serializer = ContainerRepositoriesSerializer .new(project: project, current_user: current_user) - if Feature.enabled?(:vue_container_registry_explorer) + if Feature.enabled?(:vue_container_registry_explorer, project.group) render json: serializer.with_pagination(request, response).represent(@images) else render json: serializer.represent(@images) diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml index c668c9e8494..247cf021cc7 100644 --- a/app/views/projects/registry/repositories/index.html.haml +++ b/app/views/projects/registry/repositories/index.html.haml @@ -4,7 +4,7 @@ %section .row.registry-placeholder.prepend-bottom-10 .col-12 - - if Feature.enabled?(:vue_container_registry_explorer, @project) + - if Feature.enabled?(:vue_container_registry_explorer, @project.group) #js-container-registry{ data: { endpoint: project_container_registry_index_path(@project), project_path: @project.full_path, "help_page_path" => help_page_path('user/packages/container_registry/index'), |