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>2022-01-26 00:15:18 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-01-26 00:15:18 +0300
commit616a16ea4d50ad4858f2089f8bfc56c105516599 (patch)
tree53d2e4986ec9f9c23fdad68febc0d811536da602 /app
parent2b2d833ab3e78f8c9f626af950a16d43fc38c9f8 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/boards/components/board_settings_sidebar.vue43
-rw-r--r--app/assets/javascripts/ide/components/preview/clientside.vue18
-rw-r--r--app/assets/javascripts/ide/constants.js4
-rw-r--r--app/assets/javascripts/ide/stores/modules/clientside/actions.js4
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue14
-rw-r--r--app/assets/javascripts/members/constants.js1
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue8
-rw-r--r--app/controllers/projects/autocomplete_sources_controller.rb11
-rw-r--r--app/controllers/projects/service_ping_controller.rb8
-rw-r--r--app/finders/crm/contacts_finder.rb39
-rw-r--r--app/models/preloaders/single_hierarchy_project_group_plans_preloader.rb17
-rw-r--r--app/services/projects/autocomplete_service.rb5
12 files changed, 153 insertions, 19 deletions
diff --git a/app/assets/javascripts/boards/components/board_settings_sidebar.vue b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
index 6b7c08d05a5..24071c6f0b4 100644
--- a/app/assets/javascripts/boards/components/board_settings_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlDrawer, GlLabel } from '@gitlab/ui';
+import { GlButton, GlDrawer, GlLabel, GlModal, GlModalDirective } from '@gitlab/ui';
import { MountingPortal } from 'portal-vue';
import { mapActions, mapState, mapGetters } from 'vuex';
import { LIST, ListType, ListTypeTitles } from '~/boards/constants';
@@ -11,8 +11,14 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
listSettingsText: __('List settings'),
+ i18n: {
+ modalAction: __('Remove list'),
+ modalCopy: __('Are you sure you want to remove this list?'),
+ modalCancel: __('Cancel'),
+ },
components: {
GlButton,
+ GlModal,
GlDrawer,
GlLabel,
MountingPortal,
@@ -21,6 +27,9 @@ export default {
BoardSettingsListTypes: () =>
import('ee_component/boards/components/board_settings_list_types.vue'),
},
+ directives: {
+ GlModal: GlModalDirective,
+ },
mixins: [glFeatureFlagMixin(), Tracking.mixin()],
inject: ['canAdminList', 'scopedLabelsAvailable'],
inheritAttrs: false,
@@ -29,6 +38,7 @@ export default {
ListType,
};
},
+ modalId: 'board-settings-sidebar-modal',
computed: {
...mapGetters(['isSidebarOpen', 'isEpicBoard']),
...mapState(['activeId', 'sidebarType', 'boardLists']),
@@ -59,16 +69,16 @@ export default {
},
methods: {
...mapActions(['unsetActiveId', 'removeList']),
+ handleModalPrimary() {
+ this.deleteBoard();
+ },
showScopedLabels(label) {
return this.scopedLabelsAvailable && isScopedLabel(label);
},
deleteBoard() {
- // eslint-disable-next-line no-alert
- if (window.confirm(__('Are you sure you want to remove this list?'))) {
- this.track('click_button', { label: 'remove_list' });
- this.removeList(this.activeId);
- this.unsetActiveId();
- }
+ this.track('click_button', { label: 'remove_list' });
+ this.removeList(this.activeId);
+ this.unsetActiveId();
},
},
};
@@ -92,11 +102,10 @@ export default {
<template #header>
<div v-if="canAdminList && activeList.id" class="gl-mt-3">
<gl-button
+ v-gl-modal="$options.modalId"
variant="danger"
category="secondary"
size="small"
- data-testid="remove-list"
- @click.stop="deleteBoard"
>{{ __('Remove list') }}
</gl-button>
</div>
@@ -122,5 +131,21 @@ export default {
/>
</template>
</gl-drawer>
+ <gl-modal
+ :modal-id="$options.modalId"
+ :title="$options.i18n.modalAction"
+ size="sm"
+ :action-primary="{
+ text: $options.i18n.modalAction,
+ attributes: [{ variant: 'danger' }],
+ }"
+ :action-secondary="{
+ text: $options.i18n.modalCancel,
+ attributes: [{ variant: 'default' }],
+ }"
+ @primary="handleModalPrimary"
+ >
+ <p>{{ $options.i18n.modalCopy }}</p>
+ </gl-modal>
</mounting-portal>
</template>
diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue
index 13f2e775fc3..b1f6f2c87b9 100644
--- a/app/assets/javascripts/ide/components/preview/clientside.vue
+++ b/app/assets/javascripts/ide/components/preview/clientside.vue
@@ -4,7 +4,12 @@ import { listen } from 'codesandbox-api';
import { isEmpty, debounce } from 'lodash';
import { Manager } from 'smooshpack';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { packageJsonPath, LIVE_PREVIEW_DEBOUNCE } from '../../constants';
+import {
+ packageJsonPath,
+ LIVE_PREVIEW_DEBOUNCE,
+ PING_USAGE_PREVIEW_KEY,
+ PING_USAGE_PREVIEW_SUCCESS_KEY,
+} from '../../constants';
import eventHub from '../../eventhub';
import { createPathWithExt } from '../../utils';
import Navigator from './navigator.vue';
@@ -62,6 +67,15 @@ export default {
};
},
},
+ watch: {
+ sandpackReady: {
+ handler(val) {
+ if (val) {
+ this.pingUsage(PING_USAGE_PREVIEW_SUCCESS_KEY);
+ }
+ },
+ },
+ },
mounted() {
this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE);
eventHub.$on('ide.files.change', this.onFilesChangeCallback);
@@ -101,7 +115,7 @@ export default {
initPreview() {
if (!this.mainEntry) return null;
- this.pingUsage();
+ this.pingUsage(PING_USAGE_PREVIEW_KEY);
return this.loadFileContent(this.mainEntry)
.then(() => this.$nextTick())
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 775b6906498..bfe4c3ac271 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -114,3 +114,7 @@ export const LIVE_PREVIEW_DEBOUNCE = 2000;
export const MAX_MR_FILES_AUTO_OPEN = 10;
export const DEFAULT_BRANCH = 'main';
+
+// Ping Usage Metrics Keys
+export const PING_USAGE_PREVIEW_KEY = 'web_ide_clientside_preview';
+export const PING_USAGE_PREVIEW_SUCCESS_KEY = 'web_ide_clientside_preview_success';
diff --git a/app/assets/javascripts/ide/stores/modules/clientside/actions.js b/app/assets/javascripts/ide/stores/modules/clientside/actions.js
index e36419cd7eb..1a8e665867f 100644
--- a/app/assets/javascripts/ide/stores/modules/clientside/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/clientside/actions.js
@@ -1,9 +1,9 @@
import axios from '~/lib/utils/axios_utils';
-export const pingUsage = ({ rootGetters }) => {
+export const pingUsage = ({ rootGetters }, metricName) => {
const { web_url: projectUrl } = rootGetters.currentProject;
- const url = `${projectUrl}/service_ping/web_ide_clientside_preview`;
+ const url = `${projectUrl}/service_ping/${metricName}`;
return axios.post(url);
};
diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue
index e09d16cf680..b4ba9aa36e7 100644
--- a/app/assets/javascripts/members/components/table/members_table.vue
+++ b/app/assets/javascripts/members/components/table/members_table.vue
@@ -11,7 +11,9 @@ import {
ACTIVE_TAB_QUERY_PARAM_NAME,
TAB_QUERY_PARAM_VALUES,
MEMBER_STATE_AWAITING,
+ MEMBER_STATE_ACTIVE,
USER_STATE_BLOCKED_PENDING_APPROVAL,
+ BADGE_LABELS_AWAITING_USER_SIGNUP,
BADGE_LABELS_PENDING_OWNER_APPROVAL,
} from '../../constants';
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
@@ -154,8 +156,12 @@ export default {
* @see {@link ~/app/serializers/member_entity.rb}
* @returns {boolean}
*/
- isNewUser(memberInviteMetadata) {
- return memberInviteMetadata && !memberInviteMetadata.userState;
+ isNewUser(memberInviteMetadata, memberState) {
+ return (
+ memberInviteMetadata &&
+ !memberInviteMetadata.userState &&
+ memberState !== MEMBER_STATE_ACTIVE
+ );
},
/**
* Returns whether the user is awaiting root approval
@@ -204,6 +210,10 @@ export default {
* @returns {string}
*/
inviteBadge(memberInviteMetadata, memberState) {
+ if (this.isNewUser(memberInviteMetadata, memberState)) {
+ return BADGE_LABELS_AWAITING_USER_SIGNUP;
+ }
+
if (this.shouldAddPendingOwnerApprovalBadge(memberInviteMetadata, memberState)) {
return BADGE_LABELS_PENDING_OWNER_APPROVAL;
}
diff --git a/app/assets/javascripts/members/constants.js b/app/assets/javascripts/members/constants.js
index 62241eaed04..273f1acebc7 100644
--- a/app/assets/javascripts/members/constants.js
+++ b/app/assets/javascripts/members/constants.js
@@ -111,6 +111,7 @@ export const MEMBER_STATE_CREATED = 0;
export const MEMBER_STATE_AWAITING = 1;
export const MEMBER_STATE_ACTIVE = 2;
+export const BADGE_LABELS_AWAITING_USER_SIGNUP = __('Awaiting user signup');
export const BADGE_LABELS_PENDING_OWNER_APPROVAL = __('Pending owner approval');
export const DAYS_TO_EXPIRE_SOON = 7;
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index 8e32c3b3073..ddf72587ba3 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -5,6 +5,7 @@ import DraftNote from '~/batch_comments/components/draft_note.vue';
import createFlash from '~/flash';
import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave';
import { isLoggedIn } from '~/lib/utils/common_utils';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { s__, __ } from '~/locale';
import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
@@ -170,12 +171,13 @@ export default {
this.expandDiscussion({ discussionId: this.discussion.id });
}
},
- cancelReplyForm(shouldConfirm, isDirty) {
+ async cancelReplyForm(shouldConfirm, isDirty) {
if (shouldConfirm && isDirty) {
const msg = s__('Notes|Are you sure you want to cancel creating this comment?');
- // eslint-disable-next-line no-alert
- if (!window.confirm(msg)) {
+ const confirmed = await confirmAction(msg);
+
+ if (!confirmed) {
return;
}
}
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index cf432cfb429..f678e19d05d 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -2,8 +2,9 @@
class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :authorize_read_milestone!, only: :milestones
+ before_action :authorize_read_crm_contact!, only: :contacts
- feature_category :team_planning, [:issues, :labels, :milestones, :commands]
+ feature_category :team_planning, [:issues, :labels, :milestones, :commands, :contacts]
feature_category :code_review, [:merge_requests]
feature_category :users, [:members]
feature_category :snippets, [:snippets]
@@ -38,6 +39,10 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
render json: autocomplete_service.snippets
end
+ def contacts
+ render json: autocomplete_service.contacts
+ end
+
private
def autocomplete_service
@@ -49,6 +54,10 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
.new(project, current_user)
.execute(params[:type], params[:type_id])
end
+
+ def authorize_read_crm_contact!
+ render_404 unless can?(current_user, :read_crm_contact, project.root_ancestor)
+ end
end
Projects::AutocompleteSourcesController.prepend_mod_with('Projects::AutocompleteSourcesController')
diff --git a/app/controllers/projects/service_ping_controller.rb b/app/controllers/projects/service_ping_controller.rb
index 00530c09be8..368da8d1ef2 100644
--- a/app/controllers/projects/service_ping_controller.rb
+++ b/app/controllers/projects/service_ping_controller.rb
@@ -13,6 +13,14 @@ class Projects::ServicePingController < Projects::ApplicationController
head(200)
end
+ def web_ide_clientside_preview_success
+ return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
+
+ Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_success_count
+
+ head(200)
+ end
+
def web_ide_pipelines_count
Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count
diff --git a/app/finders/crm/contacts_finder.rb b/app/finders/crm/contacts_finder.rb
new file mode 100644
index 00000000000..c2d44bec27b
--- /dev/null
+++ b/app/finders/crm/contacts_finder.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# Finder for retrieving contacts scoped to a group
+#
+# Arguments:
+# current_user - user performing the action. Must have the correct permission level for the group.
+# params:
+# group: Group, required
+module Crm
+ class ContactsFinder
+ include Gitlab::Allowable
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :params, :current_user
+
+ def initialize(current_user, params = {})
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute
+ return CustomerRelations::Contact.none unless root_group
+
+ root_group.contacts
+ end
+
+ private
+
+ def root_group
+ strong_memoize(:root_group) do
+ group = params[:group]&.root_ancestor
+
+ next unless can?(@current_user, :read_crm_contact, group)
+
+ group
+ end
+ end
+ end
+end
diff --git a/app/models/preloaders/single_hierarchy_project_group_plans_preloader.rb b/app/models/preloaders/single_hierarchy_project_group_plans_preloader.rb
new file mode 100644
index 00000000000..179214666ed
--- /dev/null
+++ b/app/models/preloaders/single_hierarchy_project_group_plans_preloader.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Preloaders
+ class SingleHierarchyProjectGroupPlansPreloader
+ attr_reader :projects
+
+ def initialize(projects_relation)
+ @projects = projects_relation
+ end
+
+ def execute
+ # no-op in FOSS
+ end
+ end
+end
+
+Preloaders::SingleHierarchyProjectGroupPlansPreloader.prepend_mod_with('Preloaders::SingleHierarchyProjectGroupPlansPreloader')
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 55f16aa3e3d..e6b1b33a82a 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -33,6 +33,11 @@ module Projects
SnippetsFinder.new(current_user, project: project).execute.select([:id, :title])
end
+ def contacts
+ Crm::ContactsFinder.new(current_user, group: project.group).execute
+ .select([:id, :email, :first_name, :last_name])
+ end
+
def labels_as_hash(target)
super(target, project_id: project.id, include_ancestor_groups: true)
end