summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-17 12:09:20 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-17 12:09:20 +0000
commit6b97ea1f8008a7ddb22b1faa03496cf46c546c05 (patch)
tree944c51ba3a245ab478efb74c11b838646f2a4581 /app
parent6bbf310347d4b857b111bc3b54e8a16e2e2e61c7 (diff)
downloadgitlab-ce-6b97ea1f8008a7ddb22b1faa03496cf46c546c05.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/feature_flags/components/form.vue6
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue2
-rw-r--r--app/assets/javascripts/issues/list/index.js2
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue1
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue7
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue6
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue3
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/index.js9
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue104
-rw-r--r--app/assets/javascripts/work_items/constants.js12
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_links.query.graphql28
-rw-r--r--app/graphql/mutations/issues/set_crm_contacts.rb2
-rw-r--r--app/graphql/mutations/packages/destroy_files.rb54
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/helpers/groups/crm_settings_helper.rb9
-rw-r--r--app/policies/group_policy.rb2
-rw-r--r--app/services/incident_management/timeline_events/base_service.rb2
-rw-r--r--app/services/incident_management/timeline_events/create_service.rb1
-rw-r--r--app/services/incident_management/timeline_events/destroy_service.rb1
-rw-r--r--app/services/incident_management/timeline_events/update_service.rb1
-rw-r--r--app/services/issues/move_service.rb1
-rw-r--r--app/views/groups/settings/_permissions.html.haml13
-rw-r--r--app/views/search/show.html.haml4
24 files changed, 226 insertions, 47 deletions
diff --git a/app/assets/javascripts/feature_flags/components/form.vue b/app/assets/javascripts/feature_flags/components/form.vue
index ec5a241bb16..8b79c661b12 100644
--- a/app/assets/javascripts/feature_flags/components/form.vue
+++ b/app/assets/javascripts/feature_flags/components/form.vue
@@ -188,8 +188,8 @@ export default {
<div class="row">
<div class="col-md-12">
<h4>{{ s__('FeatureFlags|Strategies') }}</h4>
- <div class="flex align-items-baseline justify-content-between">
- <p class="mr-3">{{ $options.translations.newHelpText }}</p>
+ <div class="gl-display-flex gl-align-items-baseline gl-justify-content-space-between">
+ <p class="gl-mr-5">{{ $options.translations.newHelpText }}</p>
<gl-button variant="confirm" category="secondary" @click="addStrategy">
{{ s__('FeatureFlags|Add strategy') }}
</gl-button>
@@ -206,7 +206,7 @@ export default {
@delete="deleteStrategy(strategy)"
/>
</div>
- <div v-else class="flex justify-content-center border-top py-4 w-100">
+ <div v-else class="gl-display-flex gl-justify-content-center gl-border-t gl-py-6 w-100">
<span>{{ $options.translations.noStrategiesText }}</span>
</div>
</fieldset>
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index 1a6874728ea..fa56c0183b2 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -133,6 +133,7 @@ export default {
'hasBlockedIssuesFeature',
'hasIssueWeightsFeature',
'hasMultipleIssueAssigneesFeature',
+ 'hasScopedLabelsFeature',
'initialEmail',
'initialSort',
'isAnonymousSearchDisabled',
@@ -716,6 +717,7 @@ export default {
recent-searches-storage-key="issues"
:search-input-placeholder="$options.i18n.searchPlaceholder"
:search-tokens="searchTokens"
+ :has-scoped-labels-feature="hasScopedLabelsFeature"
:initial-filter-value="filterTokens"
:sort-options="sortOptions"
:initial-sort-by="sortKey"
diff --git a/app/assets/javascripts/issues/list/index.js b/app/assets/javascripts/issues/list/index.js
index c89a6385bc4..93333c31b34 100644
--- a/app/assets/javascripts/issues/list/index.js
+++ b/app/assets/javascripts/issues/list/index.js
@@ -98,6 +98,7 @@ export function mountIssuesListApp() {
hasIssueWeightsFeature,
hasIterationsFeature,
hasMultipleIssueAssigneesFeature,
+ hasScopedLabelsFeature,
importCsvIssuesPath,
initialEmail,
initialSort,
@@ -148,6 +149,7 @@ export function mountIssuesListApp() {
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
hasIterationsFeature: parseBoolean(hasIterationsFeature),
hasMultipleIssueAssigneesFeature: parseBoolean(hasMultipleIssueAssigneesFeature),
+ hasScopedLabelsFeature: parseBoolean(hasScopedLabelsFeature),
initialSort,
isAnonymousSearchDisabled: parseBoolean(isAnonymousSearchDisabled),
isIssueRepositioningDisabled: parseBoolean(isIssueRepositioningDisabled),
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index 59fa2fca736..a949a9d1318 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -229,7 +229,7 @@ export default {
};
</script>
<template>
- <div class="flex flex-column mt-2">
+ <div class="gl-display-flex gl-flex-direction-column gl-mt-3">
<div class="gl-align-self-end gl-mb-3">
<releases-sort :value="sort" class="gl-mr-2" @input="onSortChanged" />
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
index fb1e4dcad74..aaddab43e2a 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
@@ -72,6 +72,7 @@ export default {
class="dropdown-header-button gl-p-0!"
icon="close"
data-testid="close-button"
+ data-qa-selector="close_labels_dropdown_button"
@click="$emit('closeDropdown')"
/>
</div>
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
index 6453290f6ea..a9f8caa3e1f 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
@@ -23,6 +23,11 @@ export default {
},
mixins: [timeagoMixin],
props: {
+ hasScopedLabelsFeature: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
issuableSymbol: {
type: String,
required: true,
@@ -132,7 +137,7 @@ export default {
return Boolean(this.$slots[slotName]);
},
scopedLabel(label) {
- return isScopedLabel(label);
+ return this.hasScopedLabelsFeature && isScopedLabel(label);
},
labelTitle(label) {
return label.title || label.name;
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
index 29c1c6bfa9e..8fbf0bb10a0 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
@@ -133,6 +133,11 @@ export default {
required: false,
default: 2,
},
+ hasScopedLabelsFeature: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
labelFilterParam: {
type: String,
required: false,
@@ -320,6 +325,7 @@ export default {
:class="{ 'gl-cursor-grab': isManualOrdering }"
data-qa-selector="issuable_container"
:data-qa-issuable-title="issuable.title"
+ :has-scoped-labels-feature="hasScopedLabelsFeature"
:issuable-symbol="issuableSymbol"
:issuable="issuable"
:label-filter-param="labelFilterParam"
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index da8fe222b6a..5272df2d53f 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -13,7 +13,6 @@ import WorkItemActions from './work_item_actions.vue';
import WorkItemState from './work_item_state.vue';
import WorkItemTitle from './work_item_title.vue';
import WorkItemDescription from './work_item_description.vue';
-import WorkItemLinks from './work_item_links/work_item_links.vue';
import WorkItemAssignees from './work_item_assignees.vue';
import WorkItemWeight from './work_item_weight.vue';
@@ -27,7 +26,6 @@ export default {
WorkItemDescription,
WorkItemTitle,
WorkItemState,
- WorkItemLinks,
WorkItemWeight,
},
mixins: [glFeatureFlagMixin()],
@@ -150,7 +148,6 @@ export default {
:work-item-id="workItem.id"
@error="error = $event"
/>
- <work-item-links v-if="glFeatures.workItemsHierarchy" :work-item-id="workItem.id" />
</template>
</section>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/index.js b/app/assets/javascripts/work_items/components/work_item_links/index.js
index 636bae0ad38..320a4a213e3 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/index.js
+++ b/app/assets/javascripts/work_items/components/work_item_links/index.js
@@ -1,6 +1,14 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
import WorkItemLinks from './work_item_links.vue';
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
export default function initWorkItemLinks() {
if (!window.gon.features.workItemsHierarchy) {
return;
@@ -15,6 +23,7 @@ export default function initWorkItemLinks() {
new Vue({
el: workItemLinksRoot,
name: 'WorkItemLinksRoot',
+ apolloProvider,
components: {
workItemLinks: WorkItemLinks,
},
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
index a4c1b98114c..bdfff100333 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
@@ -1,11 +1,23 @@
<script>
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlBadge, GlIcon, GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
+import {
+ STATE_OPEN,
+ WIDGET_ICONS,
+ WORK_ITEM_STATUS_TEXT,
+ WIDGET_TYPE_HIERARCHY,
+} from '../../constants';
+import getWorkItemLinksQuery from '../../graphql/work_item_links.query.graphql';
import WorkItemLinksForm from './work_item_links_form.vue';
export default {
components: {
GlButton,
+ GlBadge,
+ GlIcon,
+ GlLoadingIcon,
WorkItemLinksForm,
},
props: {
@@ -20,6 +32,25 @@ export default {
default: null,
},
},
+ apollo: {
+ children: {
+ query: getWorkItemLinksQuery,
+ variables() {
+ return {
+ id: this.issuableGid,
+ };
+ },
+ update(data) {
+ return (
+ data.workItem.widgets.find((widget) => widget.type === WIDGET_TYPE_HIERARCHY)?.children
+ .nodes ?? []
+ );
+ },
+ skip() {
+ return !this.issuableId;
+ },
+ },
+ },
data() {
return {
isShownAddForm: false,
@@ -30,7 +61,7 @@ export default {
computed: {
// Only used for children for now but should be extended later to support parents and siblings
isChildrenEmpty() {
- return this.children.length === 0;
+ return this.children?.length === 0;
},
toggleIcon() {
return this.isOpen ? 'chevron-lg-up' : 'chevron-lg-down';
@@ -40,8 +71,17 @@ export default {
? s__('WorkItem|Collapse child items')
: s__('WorkItem|Expand child items');
},
+ issuableGid() {
+ return this.issuableId ? convertToGraphQLId(TYPE_WORK_ITEM, this.issuableId) : null;
+ },
+ isLoading() {
+ return this.$apollo.queries.children.loading;
+ },
},
methods: {
+ badgeVariant(state) {
+ return state === STATE_OPEN ? 'success' : 'info';
+ },
toggle() {
this.isOpen = !this.isOpen;
},
@@ -56,11 +96,13 @@ export default {
),
addChildButtonLabel: s__('WorkItem|Add a child'),
},
+ WIDGET_TYPE_TASK_ICON: WIDGET_ICONS.TASK,
+ WORK_ITEM_STATUS_TEXT,
};
</script>
<template>
- <div class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100">
+ <div class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10">
<div
class="gl-p-4 gl-display-flex gl-justify-content-space-between"
:class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': isOpen }"
@@ -76,22 +118,48 @@ export default {
/>
</div>
</div>
- <div v-if="isOpen" class="gl-bg-gray-10 gl-p-4" data-testid="links-body">
- <div v-if="isChildrenEmpty" class="gl-px-8" data-testid="links-empty">
- <p>
- {{ $options.i18n.emptyStateMessage }}
- </p>
- <gl-button
- v-if="!isShownAddForm"
- category="secondary"
- variant="confirm"
- data-testid="toggle-add-form"
- @click="toggleAddForm"
+ <div
+ v-if="isOpen"
+ class="gl-bg-gray-10 gl-p-4 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
+ data-testid="links-body"
+ >
+ <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-3" />
+
+ <template v-else>
+ <div v-if="isChildrenEmpty" class="gl-px-8" data-testid="links-empty">
+ <p>
+ {{ $options.i18n.emptyStateMessage }}
+ </p>
+ <gl-button
+ v-if="!isShownAddForm"
+ category="secondary"
+ variant="confirm"
+ data-testid="toggle-add-form"
+ @click="toggleAddForm"
+ >
+ {{ $options.i18n.addChildButtonLabel }}
+ </gl-button>
+ <work-item-links-form v-else data-testid="add-links-form" @cancel="toggleAddForm" />
+ </div>
+ <div
+ v-for="child in children"
+ :key="child.id"
+ class="gl-relative gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-overflow-break-word gl-min-w-0 gl-bg-white gl-mb-3 gl-py-3 gl-px-4 gl-border gl-border-gray-100 gl-rounded-base"
+ data-testid="links-child"
>
- {{ $options.i18n.addChildButtonLabel }}
- </gl-button>
- <work-item-links-form v-else data-testid="add-links-form" @cancel="toggleAddForm" />
- </div>
+ <div>
+ <gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-3 gl-text-gray-700" />
+ <span class="gl-word-break-all">{{ child.title }}</span>
+ </div>
+ <div class="gl-ml-0 gl-sm-ml-auto! gl-mt-3 gl-sm-mt-0">
+ <gl-badge :variant="badgeVariant(child.state)">
+ <span class="gl-sm-display-block">{{
+ $options.WORK_ITEM_STATUS_TEXT[child.state]
+ }}</span>
+ </gl-badge>
+ </div>
+ </div>
+ </template>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js
index d3bc314fa58..2df4978a319 100644
--- a/app/assets/javascripts/work_items/constants.js
+++ b/app/assets/javascripts/work_items/constants.js
@@ -18,3 +18,15 @@ export const DEFAULT_MODAL_TYPE = 'Task';
export const WIDGET_TYPE_ASSIGNEE = 'ASSIGNEES';
export const WIDGET_TYPE_DESCRIPTION = 'DESCRIPTION';
export const WIDGET_TYPE_WEIGHT = 'WEIGHT';
+export const WIDGET_TYPE_HIERARCHY = 'HIERARCHY';
+
+export const WIDGET_TYPE_TASK_ICON = 'task-done';
+
+export const WIDGET_ICONS = {
+ TASK: 'task-done',
+};
+
+export const WORK_ITEM_STATUS_TEXT = {
+ CLOSED: s__('WorkItem|Closed'),
+ OPEN: s__('WorkItem|Open'),
+};
diff --git a/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql
new file mode 100644
index 00000000000..c2496f53cc8
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql
@@ -0,0 +1,28 @@
+query workItemQuery($id: WorkItemID!) {
+ workItem(id: $id) {
+ id
+ workItemType {
+ id
+ }
+ title
+ widgets {
+ type
+ ... on WorkItemWidgetHierarchy {
+ type
+ parent {
+ id
+ }
+ children {
+ nodes {
+ id
+ workItemType {
+ id
+ }
+ title
+ state
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/graphql/mutations/issues/set_crm_contacts.rb b/app/graphql/mutations/issues/set_crm_contacts.rb
index 4df65e4769c..cc718b4ae33 100644
--- a/app/graphql/mutations/issues/set_crm_contacts.rb
+++ b/app/graphql/mutations/issues/set_crm_contacts.rb
@@ -48,7 +48,7 @@ module Mutations
private
def feature_enabled?(project)
- Feature.enabled?(:customer_relations, project.group) && project.group&.crm_enabled?
+ project.group&.crm_enabled?
end
end
end
diff --git a/app/graphql/mutations/packages/destroy_files.rb b/app/graphql/mutations/packages/destroy_files.rb
new file mode 100644
index 00000000000..3900a2c46ae
--- /dev/null
+++ b/app/graphql/mutations/packages/destroy_files.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Packages
+ class DestroyFiles < ::Mutations::BaseMutation
+ graphql_name 'DestroyPackageFiles'
+
+ include FindsProject
+
+ MAXIMUM_FILES = 100
+
+ authorize :destroy_package
+
+ argument :project_path,
+ GraphQL::Types::ID,
+ required: true,
+ description: 'Project path where the packages cleanup policy is located.'
+
+ argument :ids,
+ [::Types::GlobalIDType[::Packages::PackageFile]],
+ required: true,
+ description: 'IDs of the Package file.'
+
+ def resolve(project_path:, ids:)
+ project = authorized_find!(project_path)
+ raise_resource_not_available_error! "Cannot delete more than #{MAXIMUM_FILES} files" if ids.size > MAXIMUM_FILES
+
+ package_files = ::Packages::PackageFile.where(id: parse_gids(ids)) # rubocop:disable CodeReuse/ActiveRecord
+
+ ensure_file_access!(project, package_files)
+
+ result = ::Packages::MarkPackageFilesForDestructionService.new(package_files).execute
+
+ errors = result.error? ? Array.wrap(result[:message]) : []
+
+ { errors: errors }
+ end
+
+ private
+
+ def ensure_file_access!(project, package_files)
+ project_ids = package_files.map(&:project_id).uniq
+
+ unless project_ids.size == 1 && project_ids.include?(project.id)
+ raise_resource_not_available_error! 'All files must be in the requested project'
+ end
+ end
+
+ def parse_gids(gids)
+ gids.map { |gid| GitlabSchema.parse_gid(gid, expected_type: ::Packages::PackageFile).model_id }
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 7ce751b8f2a..8642957af02 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -136,6 +136,7 @@ module Types
mount_mutation Mutations::UserPreferences::Update
mount_mutation Mutations::Packages::Destroy
mount_mutation Mutations::Packages::DestroyFile
+ mount_mutation Mutations::Packages::DestroyFiles
mount_mutation Mutations::Packages::Cleanup::Policy::Update
mount_mutation Mutations::Echo
mount_mutation Mutations::WorkItems::Create, deprecated: { milestone: '15.1', reason: :alpha }
diff --git a/app/helpers/groups/crm_settings_helper.rb b/app/helpers/groups/crm_settings_helper.rb
deleted file mode 100644
index d7ca25a9d1b..00000000000
--- a/app/helpers/groups/crm_settings_helper.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-module Groups
- module CrmSettingsHelper
- def crm_feature_available?(group)
- Feature.enabled?(:customer_relations, group)
- end
- end
-end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 9aae295aea7..6ca30ba5dab 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -76,7 +76,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
with_scope :subject
condition(:has_project_with_service_desk_enabled) { @subject.has_project_with_service_desk_enabled? }
- condition(:crm_enabled, score: 0, scope: :subject) { Feature.enabled?(:customer_relations, @subject) && @subject.crm_enabled? }
+ condition(:crm_enabled, score: 0, scope: :subject) { @subject.crm_enabled? }
condition(:group_runner_registration_allowed) do
Feature.disabled?(:runner_registration_control) || Gitlab::CurrentSettings.valid_runner_registrars.include?('group')
diff --git a/app/services/incident_management/timeline_events/base_service.rb b/app/services/incident_management/timeline_events/base_service.rb
index cae58465e4a..7168e2fdd38 100644
--- a/app/services/incident_management/timeline_events/base_service.rb
+++ b/app/services/incident_management/timeline_events/base_service.rb
@@ -3,6 +3,8 @@
module IncidentManagement
module TimelineEvents
class BaseService
+ include Gitlab::Utils::UsageData
+
def allowed?
user&.can?(:admin_incident_management_timeline_event, incident)
end
diff --git a/app/services/incident_management/timeline_events/create_service.rb b/app/services/incident_management/timeline_events/create_service.rb
index 3a7e8d2509d..5e5feed65c2 100644
--- a/app/services/incident_management/timeline_events/create_service.rb
+++ b/app/services/incident_management/timeline_events/create_service.rb
@@ -33,6 +33,7 @@ module IncidentManagement
if timeline_event.save
add_system_note(timeline_event)
+ track_usage_event(:incident_management_timeline_event_created, user.id)
success(timeline_event)
else
error_in_save(timeline_event)
diff --git a/app/services/incident_management/timeline_events/destroy_service.rb b/app/services/incident_management/timeline_events/destroy_service.rb
index 8bb186c289a..90e95ae8869 100644
--- a/app/services/incident_management/timeline_events/destroy_service.rb
+++ b/app/services/incident_management/timeline_events/destroy_service.rb
@@ -18,6 +18,7 @@ module IncidentManagement
if timeline_event.destroy
add_system_note(incident, user)
+ track_usage_event(:incident_management_timeline_event_deleted, user.id)
success(timeline_event)
else
error_in_save(timeline_event)
diff --git a/app/services/incident_management/timeline_events/update_service.rb b/app/services/incident_management/timeline_events/update_service.rb
index 347c6cd3e05..83497b123dd 100644
--- a/app/services/incident_management/timeline_events/update_service.rb
+++ b/app/services/incident_management/timeline_events/update_service.rb
@@ -23,6 +23,7 @@ module IncidentManagement
if timeline_event.update(update_params)
add_system_note(timeline_event)
+ track_usage_event(:incident_management_timeline_event_edited, user.id)
success(timeline_event)
else
error_in_save(timeline_event)
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index e210e6a2362..d210ba2a76c 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -110,7 +110,6 @@ module Issues
end
def copy_contacts
- return unless Feature.enabled?(:customer_relations, original_entity.project.root_ancestor)
return unless original_entity.project.root_ancestor == new_entity.project.root_ancestor
new_entity.customer_relations_contacts = original_entity.customer_relations_contacts
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index a30770b292d..319af7be22e 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -45,12 +45,11 @@
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
= render 'groups/settings/membership', f: f, group: @group
- - if crm_feature_available?(@group)
- %h5= _('Customer relations')
- .form-group.gl-mb-3
- = f.gitlab_ui_checkbox_component :crm_enabled,
- s_('GroupSettings|Enable customer relations'),
- checkbox_options: { checked: @group.crm_enabled? },
- help_text: s_('GroupSettings|Allows creating organizations and contacts and associating them with issues.')
+ %h5= _('Customer relations')
+ .form-group.gl-mb-3
+ = f.gitlab_ui_checkbox_component :crm_enabled,
+ s_('GroupSettings|Enable customer relations'),
+ checkbox_options: { checked: @group.crm_enabled? },
+ help_text: s_('GroupSettings|Allows creating organizations and contacts and associating them with issues.')
= f.submit _('Save changes'), class: 'btn gl-button btn-confirm gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 7d0859ac0ec..5a45e512579 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -15,8 +15,8 @@
- page_description(_("%{count} %{scope} for term '%{term}'") % { count: @search_results.formatted_count(@scope), scope: @scope, term: @search_term })
- page_card_attributes("Namespace" => @group&.full_path, "Project" => @project&.full_path)
-.page-title-holder.d-flex.flex-wrap.justify-content-between
- %h1.page-title.gl-font-size-h-display.mr-3= _('Search')
+.page-title-holder.gl-display-flex.gl-flex-wrap.gl-justify-content-space-between
+ %h1.page-title.gl-font-size-h-display.gl-mr-5= _('Search')
= render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
.gl-mt-3