Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-27 12:14:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-27 12:14:36 +0300
commit7596630be2bb8febb34e782817c8339ba6ec7b2c (patch)
treee2cbab17c8792538df117050b09ac0a587f1f8b7 /app/assets
parent0878b072b015ae4db00f4824e2f5444d66d5ae5c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue17
-rw-r--r--app/assets/javascripts/invite_members/utils/member_utils.js4
-rw-r--r--app/assets/javascripts/observability/client.js21
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/daterange_token.vue158
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>