From afaae32abaa9f86a0253ffd684786089c5e3d823 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 15 Jan 2025 03:29:08 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../layout/empty_line_after_magic_comment.yml | 1 - .rubocop_todo/rspec/feature_category.yml | 1 - .rubocop_todo/rspec/spec_file_path_suffix.yml | 1 - GITALY_SERVER_VERSION | 2 +- GITLAB_KAS_VERSION | 2 +- .../cycle_analytics/components/base.vue | 13 +- .../analytics/cycle_analytics/constants.js | 14 -- .../analytics/cycle_analytics/utils.js | 2 + .../legacy_value_stream_metrics.vue | 157 ------------- .../components/value_stream_metrics.vue | 10 +- .../analytics/shared/graphql/constants.js | 14 +- .../javascripts/analytics/shared/utils.js | 76 +++---- app/assets/javascripts/api/analytics_api.js | 12 - .../notes/work_item_comment_form.vue | 40 +++- .../components/work_item_state_toggle.vue | 7 +- config/sidekiq_queues.yml | 2 - locale/gitlab.pot | 15 +- .../work_items/work_item_detail_spec.rb | 1 + .../cycle_analytics/components/base_spec.js | 38 +++- .../legacy_value_stream_metrics_spec.js | 208 ------------------ .../components/value_stream_metrics_spec.js | 40 +++- spec/frontend/analytics/shared/utils_spec.js | 56 ++--- spec/frontend/fixtures/analytics.rb | 17 -- .../components/work_item_state_toggle_spec.js | 10 + spec/support/rspec_order_todo.yml | 1 - 25 files changed, 188 insertions(+), 552 deletions(-) delete mode 100644 app/assets/javascripts/analytics/shared/components/legacy_value_stream_metrics.vue delete mode 100644 spec/frontend/analytics/cycle_analytics/components/legacy_value_stream_metrics_spec.js diff --git a/.rubocop_todo/layout/empty_line_after_magic_comment.yml b/.rubocop_todo/layout/empty_line_after_magic_comment.yml index c2bb25afe05..20f2992d806 100644 --- a/.rubocop_todo/layout/empty_line_after_magic_comment.yml +++ b/.rubocop_todo/layout/empty_line_after_magic_comment.yml @@ -203,7 +203,6 @@ Layout/EmptyLineAfterMagicComment: - 'ee/spec/features/projects/settings/merge_request_approvals_settings_spec.rb' - 'ee/spec/features/projects/settings/merge_requests_settings_spec.rb' - 'ee/spec/frontend/fixtures/analytics/charts.rb' - - 'ee/spec/frontend/fixtures/analytics/metrics.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_code_stage.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_issue_stage.rb' diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml index e0e27538c95..d29c0d7423f 100644 --- a/.rubocop_todo/rspec/feature_category.yml +++ b/.rubocop_todo/rspec/feature_category.yml @@ -60,7 +60,6 @@ RSpec/FeatureCategory: - 'ee/spec/finders/work_items/widgets/filters/status_spec.rb' - 'ee/spec/frontend/fixtures/analytics/charts.rb' - 'ee/spec/frontend/fixtures/analytics/devops_reports/devops_adoption/enabled_namespaces.rb' - - 'ee/spec/frontend/fixtures/analytics/metrics.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_code_stage.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_issue_stage.rb' diff --git a/.rubocop_todo/rspec/spec_file_path_suffix.yml b/.rubocop_todo/rspec/spec_file_path_suffix.yml index a7e44ae9311..73f20126af9 100644 --- a/.rubocop_todo/rspec/spec_file_path_suffix.yml +++ b/.rubocop_todo/rspec/spec_file_path_suffix.yml @@ -3,7 +3,6 @@ RSpec/SpecFilePathSuffix: Exclude: - 'ee/spec/frontend/fixtures/analytics/charts.rb' - 'ee/spec/frontend/fixtures/analytics/devops_reports/devops_adoption/enabled_namespaces.rb' - - 'ee/spec/frontend/fixtures/analytics/metrics.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_code_stage.rb' - 'ee/spec/frontend/fixtures/analytics/value_streams_issue_stage.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 67bea0a3009..154ace4d2a4 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -9170d747c9dd37ca7434095f89d11f000bf7226c +88843a6cba6fd37e13fe56faf1dd640382195314 diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION index 0560ea82879..958bc369838 100644 --- a/GITLAB_KAS_VERSION +++ b/GITLAB_KAS_VERSION @@ -1 +1 @@ -9f6b60a00d85240eec76d6a6f9a4511686f80e78 +c9ad6326777be8ab69ddb1cf4b58e91a0fa38c81 diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue index 884ea9c59f1..5dc13addf09 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue +++ b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue @@ -5,7 +5,11 @@ import { mapActions, mapState, mapGetters } from 'vuex'; import { getCookie, setCookie } from '~/lib/utils/common_utils'; import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue'; import { VSA_METRICS_GROUPS, FLOW_METRICS_QUERY_TYPE } from '~/analytics/shared/constants'; -import { toYmd, generateValueStreamsDashboardLink } from '~/analytics/shared/utils'; +import { + toYmd, + generateValueStreamsDashboardLink, + overviewMetricsRequestParams, +} from '~/analytics/shared/utils'; import PathNavigation from '~/analytics/cycle_analytics/components/path_navigation.vue'; import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue'; import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue'; @@ -121,6 +125,9 @@ export default { filterBarNamespacePath() { return this.groupPath || this.namespace.restApiRequestPath; }, + overviewRequestParams() { + return overviewMetricsRequestParams(this.filterParams); + }, }, methods: { ...mapActions([ @@ -183,8 +190,8 @@ export default { /> { return { @@ -84,6 +85,7 @@ export const buildCycleAnalyticsInitialData = ({ groupPath, namespace: { name: namespaceName, + path: namespacePath, restApiRequestPath: namespaceRestApiRequestPath, }, createdAfter: newDate(createdAfter), diff --git a/app/assets/javascripts/analytics/shared/components/legacy_value_stream_metrics.vue b/app/assets/javascripts/analytics/shared/components/legacy_value_stream_metrics.vue deleted file mode 100644 index 47751ecf162..00000000000 --- a/app/assets/javascripts/analytics/shared/components/legacy_value_stream_metrics.vue +++ /dev/null @@ -1,157 +0,0 @@ - - diff --git a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue index ef0a51d1719..3576d25e69e 100644 --- a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue +++ b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue @@ -19,9 +19,6 @@ import ValueStreamsDashboardLink from './value_streams_dashboard_link.vue'; import MetricTile from './metric_tile.vue'; const extractMetricsGroupData = (keyList = [], data = []) => { - const dataKeys = data.map(({ identifier }) => identifier); - if (!keyList.length || !dataKeys.some((key) => keyList.includes(key))) return []; - return keyList.reduce((acc, curr) => { const metric = data.find((item) => item.identifier === curr); return metric ? [...acc, metric] : acc; @@ -95,14 +92,13 @@ export default { }, computed: { queryDateRange() { - const { created_after: startDate, created_before: endDate } = this.requestParams; + const { startDate, endDate } = this.requestParams; return { startDate: toYmd(startDate), endDate: toYmd(endDate) }; }, flowMetricsVariables() { - const additionalParams = Object.keys(FLOW_METRICS_QUERY_FILTERS).reduce((acc, key) => { + const additionalParams = FLOW_METRICS_QUERY_FILTERS.reduce((acc, key) => { if (this.requestParams[key]) { - const graphqlField = FLOW_METRICS_QUERY_FILTERS[key]; - return { ...acc, [graphqlField]: this.requestParams[key] }; + return { ...acc, [key]: this.requestParams[key] }; } return acc; }, {}); diff --git a/app/assets/javascripts/analytics/shared/graphql/constants.js b/app/assets/javascripts/analytics/shared/graphql/constants.js index 003e86dfcad..27a5d3173b2 100644 --- a/app/assets/javascripts/analytics/shared/graphql/constants.js +++ b/app/assets/javascripts/analytics/shared/graphql/constants.js @@ -5,10 +5,10 @@ export const BUCKETING_INTERVAL_MONTHLY = 'MONTHLY'; * Available filters for the flow metrics query, along with date range filters * NOTE: these additional do not apply to the `deploymentCount` field */ -export const FLOW_METRICS_QUERY_FILTERS = { - label_name: 'labelNames', - project_ids: 'projectIds', - assignee_username: 'assigneeUsernames', - milestone_title: 'milestoneTitle', - author_username: 'authorUsername', -}; +export const FLOW_METRICS_QUERY_FILTERS = [ + 'labelNames', + 'projectIds', + 'assigneeUsernames', + 'milestoneTitle', + 'authorUsername', +]; diff --git a/app/assets/javascripts/analytics/shared/utils.js b/app/assets/javascripts/analytics/shared/utils.js index 46424b5c030..ccca7bcdcf4 100644 --- a/app/assets/javascripts/analytics/shared/utils.js +++ b/app/assets/javascripts/analytics/shared/utils.js @@ -1,7 +1,6 @@ -import { flatten } from 'lodash'; import dateFormat from '~/lib/dateformat'; import { SECONDS_IN_DAY } from '~/lib/utils/datetime_utility'; -import { slugify } from '~/lib/utils/text_utility'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { joinPaths } from '~/lib/utils/url_utility'; import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; import { @@ -86,49 +85,6 @@ export const removeFlash = (type = 'alert') => { document.querySelector(`.flash-${type} .js-close`)?.click(); }; -/** - * Prepares metric data to be rendered in the metric_card component - * - * @param {MetricData[]} data - The metric data to be rendered - * @param {Object} popoverContent - Key value pair of data to display in the popover - * @returns {TransformedMetricData[]} An array of metrics ready to render in the metric_card - */ -export const prepareTimeMetricsData = (data = [], popoverContent = {}) => - data.map(({ title: label, identifier, ...rest }) => { - const metricIdentifier = identifier || slugify(label); - return { - ...rest, - label, - identifier: metricIdentifier, - description: popoverContent[metricIdentifier]?.description || '', - }; - }); - -const requestData = ({ request, endpoint, requestPath, params, name }) => { - return request({ endpoint, params, requestPath }) - .then(({ data }) => data) - .catch(() => { - throw new Error(name); - }); -}; - -/** - * Takes a configuration array of metrics requests (key metrics and DORA) and returns - * a flat array of all the responses. Different metrics are retrieved from different endpoints - * additionally we only support certain metrics for FOSS users. - * - * @param {Array} requests - array of metric api requests to be made - * @param {String} requestPath - path for the group / project we are requesting - * @param {Object} params - optional parameters to filter, including `created_after` and `created_before` dates - * @returns a flat array of metrics - */ -export const fetchMetricsData = (requests = [], requestPath, params) => { - const promises = requests.map((r) => requestData({ ...r, requestPath, params })); - return Promise.all(promises).then((responses) => - prepareTimeMetricsData(flatten(responses), VALUE_STREAM_METRIC_TILE_METADATA), - ); -}; - /** * Formats any valid number as percentage * @@ -249,3 +205,33 @@ export const extractQueryResponseFromNamespace = ({ result, resultKey }) => { } return {}; }; + +/** + * Takes the raw snake_case query parameters and extracts + converts the relevant values + * for the overview metrics component + * @param {Object} params - Object containing the supported query parameters + * @param {Date} params.created_before + * @param {Date} params.created_after + * @param {string} params.author_username + * @param {string} params.milestone_title + * @param {Array} params.label_name + * @param {Array} params.assignee_username + * + * @returns {Object} CamelCased parameter names + */ +export const overviewMetricsRequestParams = (params = {}) => { + const { + createdAfter: startDate, + createdBefore: endDate, + labelName: labelNames, + assigneeUsername: assigneeUsernames, + ...rest + } = convertObjectPropsToCamelCase(params); + return { + startDate, + endDate, + labelNames, + assigneeUsernames, + ...rest, + }; +}; diff --git a/app/assets/javascripts/api/analytics_api.js b/app/assets/javascripts/api/analytics_api.js index 35c9fa20e56..a024489bb80 100644 --- a/app/assets/javascripts/api/analytics_api.js +++ b/app/assets/javascripts/api/analytics_api.js @@ -12,9 +12,6 @@ export const CYCLE_TIME_METRIC_TYPE = 'cycle_time'; export const ISSUES_METRIC_TYPE = 'issues'; export const DEPLOYS_METRIC_TYPE = 'deploys'; -export const METRIC_TYPE_SUMMARY = 'summary'; -export const METRIC_TYPE_TIME_SUMMARY = 'time_summary'; - const buildProjectMetricsPath = (namespacePath) => buildApiUrl(PROJECT_VSA_METRICS_BASE).replace(':namespace_path', namespacePath); @@ -76,15 +73,6 @@ export const getValueStreamStageCounts = ( return axios.get(joinPaths(stageBase, 'count'), { params }); }; -export const getValueStreamMetrics = ({ - endpoint = METRIC_TYPE_SUMMARY, - requestPath: namespacePath, - params = {}, -}) => { - const metricBase = buildProjectMetricsPath(namespacePath); - return axios.get(joinPaths(metricBase, endpoint), { params }); -}; - export const getValueStreamSummaryMetrics = (namespacePath, params = {}) => { const metricBase = buildProjectMetricsPath(namespacePath); return axios.get(joinPaths(metricBase, 'summary'), { params }); diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue index 70006395664..5e861a364c0 100644 --- a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue +++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue @@ -12,6 +12,7 @@ import { import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave'; import { findWidget } from '~/issues/list/utils'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; +import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; import HelpIcon from '~/vue_shared/components/help_icon/help_icon.vue'; import WorkItemStateToggle from '~/work_items/components/work_item_state_toggle.vue'; @@ -51,10 +52,15 @@ export default { GlFormCheckbox, HelpIcon, WorkItemStateToggle, + CommentTemperature: () => + import( + /* webpackChunkName: 'comment_temperature' */ 'ee_component/ai/components/comment_temperature.vue' + ), }, directives: { GlTooltip: GlTooltipDirective, }, + mixins: [glAbilitiesMixin()], props: { workItemId: { type: String, @@ -169,6 +175,7 @@ export default { toggleResolveChecked: this.isDiscussionResolved, emailParticipants: [], workItem: {}, + isMeasuringCommentTemperature: false, }; }, computed: { @@ -217,6 +224,9 @@ export default { showInternalNoteCheckbox() { return this.canMarkNoteAsInternal && this.isNewDiscussion; }, + currentUserId() { + return window.gon.current_user_id; + }, }, apollo: { emailParticipants: { @@ -296,7 +306,15 @@ export default { this.$emit('cancelEditing'); clearDraft(this.autosaveKey); }, - submitForm() { + submitForm(shouldMeasureTemperature = true) { + this.isMeasuringCommentTemperature = + this.glAbilities.measureCommentTemperature && shouldMeasureTemperature; + + if (this.isMeasuringCommentTemperature) { + this.$refs.commentTemperature.measureCommentTemperature(); + return; + } + if (this.isSubmitting) { return; } @@ -334,11 +352,20 @@ export default { supports-quick-actions :autofocus="autofocus" @input="setCommentText" - @keydown.meta.enter="submitForm" - @keydown.ctrl.enter="submitForm" + @keydown.meta.enter="submitForm()" + @keydown.ctrl.enter="submitForm()" @keydown.esc.stop="cancelEditing" /> +