diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-27 12:14:36 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-27 12:14:36 +0300 |
commit | 7596630be2bb8febb34e782817c8339ba6ec7b2c (patch) | |
tree | e2cbab17c8792538df117050b09ac0a587f1f8b7 /app/assets | |
parent | 0878b072b015ae4db00f4824e2f5444d66d5ae5c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
4 files changed, 184 insertions, 16 deletions
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue index dead90eeb71..4f6ca5c5638 100644 --- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue +++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue @@ -7,11 +7,7 @@ import Api from '~/api'; import Tracking from '~/tracking'; import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants'; import { n__, s__, sprintf } from '~/locale'; -import { - memberName, - triggerExternalAlert, - inviteMembersTrackingOptions, -} from 'ee_else_ce/invite_members/utils/member_utils'; +import { memberName, triggerExternalAlert } from 'ee_else_ce/invite_members/utils/member_utils'; import { captureException } from '~/ci/runner/sentry_utils'; import { USERS_FILTER_ALL, @@ -142,9 +138,6 @@ export default { isCelebration() { return this.mode === 'celebrate'; }, - baseTrackingDetails() { - return { label: this.source, celebrate: this.isCelebration }; - }, isTextForAdmin() { return this.isCurrentUserAdmin && Boolean(this.newUsersUrl); }, @@ -265,7 +258,7 @@ export default { this.source = source; this.$root.$emit(BV_SHOW_MODAL, this.modalId); - this.track('render', inviteMembersTrackingOptions(this.baseTrackingDetails)); + this.track('render', { label: this.source }); }, closeModal() { this.$root.$emit(BV_HIDE_MODAL, this.modalId); @@ -335,10 +328,10 @@ export default { return this.newUsersToInvite.find((member) => memberName(member) === username)?.name; }, onCancel() { - this.track('click_cancel', inviteMembersTrackingOptions(this.baseTrackingDetails)); + this.track('click_cancel', { label: this.source }); }, onClose() { - this.track('click_x', inviteMembersTrackingOptions(this.baseTrackingDetails)); + this.track('click_x', { label: this.source }); }, resetFields() { this.clearValidation(); @@ -347,7 +340,7 @@ export default { this.newUsersToInvite = []; }, onInviteSuccess() { - this.track('invite_successful', inviteMembersTrackingOptions(this.baseTrackingDetails)); + this.track('invite_successful', { label: this.source }); if (this.reloadPageOnSubmit) { reloadOnInvitationSuccess(); diff --git a/app/assets/javascripts/invite_members/utils/member_utils.js b/app/assets/javascripts/invite_members/utils/member_utils.js index 52fb5e98f27..7998cb69445 100644 --- a/app/assets/javascripts/invite_members/utils/member_utils.js +++ b/app/assets/javascripts/invite_members/utils/member_utils.js @@ -6,7 +6,3 @@ export function memberName(member) { export function triggerExternalAlert() { return false; } - -export function inviteMembersTrackingOptions(options) { - return { label: options.label }; -} diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js index 3a793c9dc14..b7e4ae8e8ea 100644 --- a/app/assets/javascripts/observability/client.js +++ b/app/assets/javascripts/observability/client.js @@ -1,3 +1,4 @@ +import { isValidDate } from '~/lib/utils/datetime_utility'; import * as Sentry from '~/sentry/sentry_browser_wrapper'; import axios from '~/lib/utils/axios_utils'; import { logError } from '~/lib/logger'; @@ -128,6 +129,24 @@ function handleAttributeFilter(filterValue, filterOperator, searchParams) { } } +function handlePeriodFilter(rawValue, filterName, filterParams) { + if (rawValue.trim().indexOf(' ') < 0) { + filterParams.append(filterName, rawValue.trim()); + return; + } + + const dateParts = rawValue.split(' - '); + if (dateParts.length === 2) { + const [start, end] = dateParts; + const startDate = new Date(start); + const endDate = new Date(end); + if (isValidDate(startDate) && isValidDate(endDate)) { + filterParams.append('start_time', startDate.toISOString()); + filterParams.append('end_time', endDate.toISOString()); + } + } +} + /** * Builds URLSearchParams from a filter object of type { [filterName]: undefined | null | Array<{operator: String, value: any} } * e.g: @@ -154,6 +173,8 @@ function filterObjToQueryParams(filterObj) { validFilters.forEach(({ operator, value: rawValue }) => { if (filterName === 'attribute') { handleAttributeFilter(rawValue, operator, filterParams); + } else if (filterName === 'period') { + handlePeriodFilter(rawValue, filterName, filterParams); } else { const paramName = getFilterParamName(filterName, operator); let value = rawValue; diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/daterange_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/daterange_token.vue new file mode 100644 index 00000000000..8da5f0cca4a --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/daterange_token.vue @@ -0,0 +1,158 @@ +<script> +import { + GlIcon, + GlDaterangePicker, + GlFilteredSearchToken, + GlFilteredSearchSuggestion, + GlOutsideDirective, +} from '@gitlab/ui'; +import { __ } from '~/locale'; +import { formatDate } from '~/lib/utils/datetime/date_format_utility'; + +const CUSTOM_DATE_FILTER_TYPE = 'custom-date'; + +export default { + directives: { Outside: GlOutsideDirective }, + components: { + GlIcon, + GlDaterangePicker, + GlFilteredSearchToken, + GlFilteredSearchSuggestion, + }, + props: { + active: { + type: Boolean, + required: true, + }, + value: { + type: Object, + required: true, + }, + config: { + type: Object, + required: true, + }, + }, + data() { + return { + datePickerShown: false, + }; + }, + computed: { + isActive() { + return this.datePickerShown || this.active; + }, + computedValue() { + if (this.datePickerShown) { + return { + ...this.value, + data: '', + }; + } + return this.value; + }, + dataSegmentInputAttributes() { + const id = 'time_range_data_segment_input'; + if (this.datePickerShown) { + return { + id, + placeholder: 'YYYY-MM-DD - YYYY-MM-DD', // eslint-disable-line @gitlab/require-i18n-strings + style: 'padding-left: 23px;', + }; + } + return { + id, + }; + }, + computedConfig() { + return { + ...this.config, + options: undefined, // remove options from config to avoid default options being rendered + }; + }, + suggestions() { + const suggestions = this.config.options.map((option) => ({ + value: option.value, + text: option.title, + })); + suggestions.push({ value: CUSTOM_DATE_FILTER_TYPE, text: __('Custom') }); + return suggestions; + }, + defaultStartDate() { + return new Date(); + }, + }, + methods: { + hideDatePicker() { + this.datePickerShown = false; + }, + showDatePicker() { + this.datePickerShown = true; + }, + handleClickOutside() { + this.hideDatePicker(); + }, + handleComplete(value) { + if (value === CUSTOM_DATE_FILTER_TYPE) { + this.showDatePicker(); + } + }, + selectValue(inputValue, submitValue) { + let value = inputValue; + if (typeof inputValue === 'object' && inputValue.startDate && inputValue.endDate) { + const { startDate, endDate } = inputValue; + const format = 'yyyy-mm-dd'; + value = `${formatDate(startDate, format)} - ${formatDate(endDate, format)}`; + } + submitValue(value); + this.hideDatePicker(); + }, + }, + CUSTOM_DATE_FILTER_TYPE: 'custom-date', +}; +</script> + +<template> + <gl-filtered-search-token + :data-segment-input-attributes="dataSegmentInputAttributes" + v-bind="{ ...$props, ...$attrs }" + :view-only="datePickerShown" + :active="isActive" + :value="computedValue" + :config="computedConfig" + v-on="$listeners" + @complete="handleComplete" + > + <template #before-data-segment-input="{ submitValue }"> + <gl-icon + v-if="datePickerShown" + class="gl-text-gray-500" + name="calendar" + style="margin-left: 5px; margin-right: -15px; z-index: 1; pointer-events: none" + /> + <div + v-if="datePickerShown" + v-outside="handleClickOutside" + class="gl-absolute gl-z-index-1 gl-bg-white gl-border-1 gl-border-gray-200 gl-my-2 gl-p-4 gl-rounded-base gl-shadow-x0-y2-b4-s0 gl-top-full" + > + <gl-daterange-picker + start-opened + :default-start-date="defaultStartDate" + @input="selectValue($event, submitValue)" + /> + </div> + </template> + + <template #suggestions> + <div v-if="!datePickerShown"> + <gl-filtered-search-suggestion + v-for="token in suggestions" + :key="token.value" + :value="token.value" + > + {{ token.text }} + </gl-filtered-search-suggestion> + </div> + </template> + </gl-filtered-search-token> +</template> |