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
path: root/app
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
parent0878b072b015ae4db00f4824e2f5444d66d5ae5c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-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
-rw-r--r--app/views/groups/_import_group_from_file_panel.html.haml4
-rw-r--r--app/views/groups/settings/_export.html.haml2
6 files changed, 187 insertions, 19 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>
diff --git a/app/views/groups/_import_group_from_file_panel.html.haml b/app/views/groups/_import_group_from_file_panel.html.haml
index c39f5cf87c7..43a8ccdaae4 100644
--- a/app/views/groups/_import_group_from_file_panel.html.haml
+++ b/app/views/groups/_import_group_from_file_panel.html.haml
@@ -10,14 +10,14 @@
alert_options: { class: 'gl-mb-5' },
dismissible: false) do |c|
- c.with_body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') }
+ - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index') }
- link_end = '</a>'.html_safe
= s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: link_end }
= render 'shared/groups/group_name_and_path_fields', f: f
.form-group
= f.label :file, s_('GroupsNew|Upload file')
.gl-font-weight-normal
- - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/group/import/index') }
+ - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/project/settings/import_export', anchor: 'migrate-groups-by-uploading-an-export-file-deprecated') }
= s_('GroupsNew|To import a group, navigate to the group settings for the GitLab source instance, %{link_start}generate an export file%{link_end}, and upload it here.').html_safe % { link_start: import_export_link_start, link_end: '</a>'.html_safe }
.gl-mt-3
= render 'shared/file_picker_button', f: f, field: :file, help_text: nil
diff --git a/app/views/groups/settings/_export.html.haml b/app/views/groups/settings/_export.html.haml
index ff1d76f470c..c7909a7c249 100644
--- a/app/views/groups/settings/_export.html.haml
+++ b/app/views/groups/settings/_export.html.haml
@@ -10,7 +10,7 @@
- c.with_body do
= render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c|
- c.with_body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') }
+ - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index') }
- docs_link_end = '</a>'.html_safe
= s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
%p