+
{{ title }}
diff --git a/app/assets/javascripts/pages/admin/labels/edit/index.js b/app/assets/javascripts/pages/admin/labels/edit/index.js
index f7c25347e75..a3b9c43388a 100644
--- a/app/assets/javascripts/pages/admin/labels/edit/index.js
+++ b/app/assets/javascripts/pages/admin/labels/edit/index.js
@@ -1,3 +1,3 @@
-import Labels from '../../../../labels';
+import Labels from '~/labels/labels';
new Labels(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/labels/new/index.js b/app/assets/javascripts/pages/admin/labels/new/index.js
index f7c25347e75..a3b9c43388a 100644
--- a/app/assets/javascripts/pages/admin/labels/new/index.js
+++ b/app/assets/javascripts/pages/admin/labels/new/index.js
@@ -1,3 +1,3 @@
-import Labels from '../../../../labels';
+import Labels from '~/labels/labels';
new Labels(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/groups/issues/index.js b/app/assets/javascripts/pages/groups/issues/index.js
index 8c9f23732aa..640824d02cf 100644
--- a/app/assets/javascripts/pages/groups/issues/index.js
+++ b/app/assets/javascripts/pages/groups/issues/index.js
@@ -1,5 +1,5 @@
import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
-import issuableInitBulkUpdateSidebar from '~/issuable_bulk_update_sidebar/issuable_init_bulk_update_sidebar';
+import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
import { mountIssuablesListApp, mountIssuesListApp } from '~/issues_list';
import initManualOrdering from '~/manual_ordering';
import { FILTERED_SEARCH } from '~/pages/constants';
diff --git a/app/assets/javascripts/pages/groups/labels/edit/index.js b/app/assets/javascripts/pages/groups/labels/edit/index.js
index 2e8308fe084..e4e377f62fc 100644
--- a/app/assets/javascripts/pages/groups/labels/edit/index.js
+++ b/app/assets/javascripts/pages/groups/labels/edit/index.js
@@ -1,4 +1,4 @@
-import Labels from 'ee_else_ce/labels';
+import Labels from 'ee_else_ce/labels/labels';
// eslint-disable-next-line no-new
new Labels();
diff --git a/app/assets/javascripts/pages/groups/labels/index/index.js b/app/assets/javascripts/pages/groups/labels/index/index.js
index 95c2c7cd7d0..80ee3293d69 100644
--- a/app/assets/javascripts/pages/groups/labels/index/index.js
+++ b/app/assets/javascripts/pages/groups/labels/index/index.js
@@ -1,5 +1,5 @@
-import initDeleteLabelModal from '~/delete_label_modal';
-import initLabels from '~/init_labels';
+import initDeleteLabelModal from '~/labels/delete_label_modal';
+import initLabels from '~/labels/init_labels';
initLabels();
initDeleteLabelModal();
diff --git a/app/assets/javascripts/pages/groups/labels/new/index.js b/app/assets/javascripts/pages/groups/labels/new/index.js
index 2e8308fe084..e4e377f62fc 100644
--- a/app/assets/javascripts/pages/groups/labels/new/index.js
+++ b/app/assets/javascripts/pages/groups/labels/new/index.js
@@ -1,4 +1,4 @@
-import Labels from 'ee_else_ce/labels';
+import Labels from 'ee_else_ce/labels/labels';
// eslint-disable-next-line no-new
new Labels();
diff --git a/app/assets/javascripts/pages/groups/merge_requests/index.js b/app/assets/javascripts/pages/groups/merge_requests/index.js
index 02a0a50f984..05679f4d96d 100644
--- a/app/assets/javascripts/pages/groups/merge_requests/index.js
+++ b/app/assets/javascripts/pages/groups/merge_requests/index.js
@@ -1,6 +1,6 @@
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
-import issuableInitBulkUpdateSidebar from '~/issuable_bulk_update_sidebar/issuable_init_bulk_update_sidebar';
+import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
import { FILTERED_SEARCH } from '~/pages/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import projectSelect from '~/project_select';
diff --git a/app/assets/javascripts/pages/projects/issues/form.js b/app/assets/javascripts/pages/projects/issues/form.js
index c17c127d560..adccdda3475 100644
--- a/app/assets/javascripts/pages/projects/issues/form.js
+++ b/app/assets/javascripts/pages/projects/issues/form.js
@@ -1,12 +1,12 @@
/* eslint-disable no-new */
import $ from 'jquery';
-import IssuableForm from 'ee_else_ce/issuable_form';
+import IssuableForm from 'ee_else_ce/issuable/issuable_form';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GLForm from '~/gl_form';
import initSuggestions from '~/issues/suggestions';
import initIssuableTypeSelector from '~/issues/type_selector';
-import LabelsSelect from '~/labels_select';
+import LabelsSelect from '~/labels/labels_select';
import MilestoneSelect from '~/milestones/milestone_select';
import IssuableTemplateSelectors from '~/templates/issuable_template_selectors';
diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index 8cd703133f5..24e75150940 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -2,7 +2,7 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons';
import initIssuableByEmail from '~/issuable/init_issuable_by_email';
-import IssuableIndex from '~/issuable_index';
+import IssuableIndex from '~/issuable/issuable_index';
import { mountIssuablesListApp, mountIssuesListApp, mountJiraIssuesListApp } from '~/issues_list';
import initManualOrdering from '~/manual_ordering';
import { FILTERED_SEARCH } from '~/pages/constants';
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index 0df3a8983bd..5a48f463acc 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -1,7 +1,7 @@
import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
-import initIssuableSidebar from '~/init_issuable_sidebar';
-import { IssuableType } from '~/issuable_show/constants';
+import initIssuableSidebar from '~/issuable/init_issuable_sidebar';
+import { IssuableType } from '~/vue_shared/issuable/show/constants';
import Issue from '~/issue';
import { initIncidentApp, initIncidentHeaderActions } from '~/issues/show/incident';
import { initIssuableApp, initIssueHeaderActions } from '~/issues/show/issue';
diff --git a/app/assets/javascripts/pages/projects/labels/edit/index.js b/app/assets/javascripts/pages/projects/labels/edit/index.js
index 3b7562deed9..c4d7af39767 100644
--- a/app/assets/javascripts/pages/projects/labels/edit/index.js
+++ b/app/assets/javascripts/pages/projects/labels/edit/index.js
@@ -1,3 +1,3 @@
-import Labels from 'ee_else_ce/labels';
+import Labels from 'ee_else_ce/labels/labels';
new Labels(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/labels/index/index.js b/app/assets/javascripts/pages/projects/labels/index/index.js
index 94ab0d64de4..6685272429c 100644
--- a/app/assets/javascripts/pages/projects/labels/index/index.js
+++ b/app/assets/javascripts/pages/projects/labels/index/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
-import initDeleteLabelModal from '~/delete_label_modal';
-import initLabels from '~/init_labels';
+import initDeleteLabelModal from '~/labels/delete_label_modal';
+import initLabels from '~/labels/init_labels';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
import PromoteLabelModal from '../components/promote_label_modal.vue';
diff --git a/app/assets/javascripts/pages/projects/labels/new/index.js b/app/assets/javascripts/pages/projects/labels/new/index.js
index 2e8308fe084..e4e377f62fc 100644
--- a/app/assets/javascripts/pages/projects/labels/new/index.js
+++ b/app/assets/javascripts/pages/projects/labels/new/index.js
@@ -1,4 +1,4 @@
-import Labels from 'ee_else_ce/labels';
+import Labels from 'ee_else_ce/labels/labels';
// eslint-disable-next-line no-new
new Labels();
diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
index d279086df7b..b17a70cda77 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -3,7 +3,7 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons';
import initIssuableByEmail from '~/issuable/init_issuable_by_email';
-import IssuableIndex from '~/issuable_index';
+import IssuableIndex from '~/issuable/issuable_index';
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
index f2777434029..49197881731 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
@@ -1,11 +1,11 @@
/* eslint-disable no-new */
import $ from 'jquery';
-import IssuableForm from 'ee_else_ce/issuable_form';
+import IssuableForm from 'ee_else_ce/issuable/issuable_form';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import Diff from '~/diff';
import GLForm from '~/gl_form';
-import LabelsSelect from '~/labels_select';
+import LabelsSelect from '~/labels/labels_select';
import MilestoneSelect from '~/milestones/milestone_select';
import IssuableTemplateSelectors from '~/templates/issuable_template_selectors';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
index 99094617b0a..971f26f1358 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
@@ -3,7 +3,7 @@ import VueApollo from 'vue-apollo';
import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import { initPipelineCountListener } from '~/commit/pipelines/utils';
-import initIssuableSidebar from '~/init_issuable_sidebar';
+import initIssuableSidebar from '~/issuable/init_issuable_sidebar';
import StatusBox from '~/issuable/components/status_box.vue';
import createDefaultClient from '~/lib/graphql';
import initSourcegraph from '~/sourcegraph';
diff --git a/app/assets/javascripts/vue_shared/components/registry/list_item.vue b/app/assets/javascripts/vue_shared/components/registry/list_item.vue
index 89de95f8d9a..6bb321713d5 100644
--- a/app/assets/javascripts/vue_shared/components/registry/list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/registry/list_item.vue
@@ -57,7 +57,7 @@ export default {
@@ -105,7 +105,7 @@ export default {
diff --git a/app/assets/javascripts/issuable_show/components/issuable_body.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_body.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_description.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_description.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_discussion.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_discussion.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_discussion.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_discussion.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_header.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_header.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_show_root.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue
diff --git a/app/assets/javascripts/issuable_show/components/issuable_title.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue
similarity index 100%
rename from app/assets/javascripts/issuable_show/components/issuable_title.vue
rename to app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue
diff --git a/app/assets/javascripts/issuable_show/constants.js b/app/assets/javascripts/vue_shared/issuable/show/constants.js
similarity index 100%
rename from app/assets/javascripts/issuable_show/constants.js
rename to app/assets/javascripts/vue_shared/issuable/show/constants.js
diff --git a/app/assets/javascripts/issuable_show/event_hub.js b/app/assets/javascripts/vue_shared/issuable/show/event_hub.js
similarity index 100%
rename from app/assets/javascripts/issuable_show/event_hub.js
rename to app/assets/javascripts/vue_shared/issuable/show/event_hub.js
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index e00bb83362a..f79dc38f2f7 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -174,3 +174,30 @@ body {
min-height: 0;
}
}
+
+.gl-drawer-responsive {
+ // Both width & min-width
+ // are defined as per Pajamas
+ // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44902#note_429056182
+ width: 28%;
+ min-width: 400px;
+ padding-left: $gl-padding;
+ padding-right: $gl-padding;
+ box-shadow: none;
+ background-color: $gray-10;
+ border-left: 1px solid $gray-100;
+
+ @include media-breakpoint-down(sm) {
+ min-width: unset;
+ width: 100%;
+ }
+
+ // These overrides should not happen here,
+ // we should ideally have support for custom
+ // header and body classes in `GlDrawer`.
+ .gl-drawer-header,
+ .gl-drawer-body > * {
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
diff --git a/app/helpers/time_zone_helper.rb b/app/helpers/time_zone_helper.rb
index bc054269e0f..d16f13304e5 100644
--- a/app/helpers/time_zone_helper.rb
+++ b/app/helpers/time_zone_helper.rb
@@ -33,7 +33,7 @@ module TimeZoneHelper
end
end
- def local_time_instance(timezone)
+ def local_timezone_instance(timezone)
return Time.zone if timezone.blank?
ActiveSupport::TimeZone.new(timezone) || Time.zone
@@ -42,7 +42,7 @@ module TimeZoneHelper
def local_time(timezone)
return if timezone.blank?
- time_zone_instance = local_time_instance(timezone)
+ time_zone_instance = local_timezone_instance(timezone)
time_zone_instance.now.strftime("%-l:%M %p")
end
end
diff --git a/app/policies/namespace_policy.rb b/app/policies/namespace_policy.rb
index 0cf1bcb9737..33c90d49f68 100644
--- a/app/policies/namespace_policy.rb
+++ b/app/policies/namespace_policy.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
-class NamespacePolicy < ::Namespaces::UserNamespacePolicy
+class NamespacePolicy < BasePolicy
# NamespacePolicy has been traditionally for user namespaces.
# So these policies have been moved into Namespaces::UserNamespacePolicy.
# Once the user namespace conversion is complete, we can look at
# either removing this file or locating common namespace policy items
# here.
+ # See https://gitlab.com/groups/gitlab-org/-/epics/6689 for details
end
diff --git a/app/policies/namespaces/project_namespace_policy.rb b/app/policies/namespaces/project_namespace_policy.rb
index bc08a7a45ed..bbc7f17d871 100644
--- a/app/policies/namespaces/project_namespace_policy.rb
+++ b/app/policies/namespaces/project_namespace_policy.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Namespaces
- class ProjectNamespacePolicy < BasePolicy
+ class ProjectNamespacePolicy < NamespacePolicy
# For now users are not granted any permissions on project namespace
# as it's completely hidden to them. When we start using project
# namespaces in queries, we will have to extend this policy.
diff --git a/app/policies/namespaces/user_namespace_policy.rb b/app/policies/namespaces/user_namespace_policy.rb
index f8b285e5312..93626c6d1a1 100644
--- a/app/policies/namespaces/user_namespace_policy.rb
+++ b/app/policies/namespaces/user_namespace_policy.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Namespaces
- class UserNamespacePolicy < BasePolicy
+ class UserNamespacePolicy < ::NamespacePolicy
rule { anonymous }.prevent_all
condition(:personal_project, scope: :subject) { @subject.kind == 'user' }
diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml
index 0d904de9372..a3949375eaa 100644
--- a/app/views/users/_overview.html.haml
+++ b/app/views/users/_overview.html.haml
@@ -2,7 +2,7 @@
.row.d-none.d-sm-flex
.col-12.calendar-block.gl-my-3
- .user-calendar.light{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: local_time_instance(@user.timezone).now.utc_offset } }
+ .user-calendar.light{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: local_timezone_instance(@user.timezone).now.utc_offset } }
.gl-spinner.gl-spinner-md.gl-my-8
.user-calendar-error.invisible
= _('There was an error loading users activity calendar.')
diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml
index 1ade990d78a..8da1aa09215 100644
--- a/app/views/users/calendar_activities.html.haml
+++ b/app/views/users/calendar_activities.html.haml
@@ -7,7 +7,7 @@
%li
%span.light.js-localtime{ :data => { :datetime => event.created_at.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), :toggle => 'tooltip', :placement => 'top' } }
= sprite_icon('clock', css_class: 'gl-vertical-align-text-bottom')
- = event.created_at.to_time.in_time_zone(local_time_instance(@user.timezone)).strftime('%-I:%M%P')
+ = event.created_at.to_time.in_time_zone(local_timezone_instance(@user.timezone)).strftime('%-I:%M%P')
- if event.visible_to_user?(current_user)
- if event.push_action?
#{event.action_name} #{event.ref_type}
diff --git a/config/feature_flags/development/ci_yaml_limit_size.yml b/config/feature_flags/development/ci_yaml_limit_size.yml
index 2b68939968d..222dc409c45 100644
--- a/config/feature_flags/development/ci_yaml_limit_size.yml
+++ b/config/feature_flags/development/ci_yaml_limit_size.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://dev.gitlab.org/gitlab/gitlabhq/-/merge_requests/3126
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/29875
milestone: '12.0'
type: development
-group: group::pipeline execution
+group: group::pipeline authoring
default_enabled: true
diff --git a/config/feature_flags/development/s3_multithreaded_uploads.yml b/config/feature_flags/development/s3_multithreaded_uploads.yml
index 92ba4da7e67..f80510a4c64 100644
--- a/config/feature_flags/development/s3_multithreaded_uploads.yml
+++ b/config/feature_flags/development/s3_multithreaded_uploads.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50922
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296772
milestone: '13.8'
type: development
-group: group::pipeline execution
+group: group::testing
default_enabled: true
diff --git a/db/post_migrate/20211206073851_create_calendar_events_index_synchronously.rb b/db/post_migrate/20211206073851_create_calendar_events_index_synchronously.rb
new file mode 100644
index 00000000000..020dceac004
--- /dev/null
+++ b/db/post_migrate/20211206073851_create_calendar_events_index_synchronously.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class CreateCalendarEventsIndexSynchronously < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_events_author_id_project_id_action_target_type_created_at'
+
+ def up
+ add_concurrent_index :events, [:author_id, :project_id, :action, :target_type, :created_at], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :events, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20211206074547_remove_old_calendar_events_index.rb b/db/post_migrate/20211206074547_remove_old_calendar_events_index.rb
new file mode 100644
index 00000000000..51460a9dc95
--- /dev/null
+++ b/db/post_migrate/20211206074547_remove_old_calendar_events_index.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveOldCalendarEventsIndex < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ OLD_INDEX_NAME = 'index_events_on_author_id_and_project_id'
+
+ def up
+ remove_concurrent_index_by_name :events, OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :events, [:author_id, :project_id], name: OLD_INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20211206073851 b/db/schema_migrations/20211206073851
new file mode 100644
index 00000000000..bfd8140b109
--- /dev/null
+++ b/db/schema_migrations/20211206073851
@@ -0,0 +1 @@
+403592fda1d82ed3c3fb8d5315593b67954a4ecbc368d9bcd5eedc75bb3c9821
\ No newline at end of file
diff --git a/db/schema_migrations/20211206074547 b/db/schema_migrations/20211206074547
new file mode 100644
index 00000000000..dd84a987827
--- /dev/null
+++ b/db/schema_migrations/20211206074547
@@ -0,0 +1 @@
+ba1c0d20e21ef51278109d0eaeb23f1c541eb5eb9aeb9a92583ee6de83c68918
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index cfe07cac82b..e2032970bc9 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -26018,14 +26018,14 @@ CREATE INDEX index_et_errors_on_project_id_and_status_first_seen_at_id_desc ON e
CREATE INDEX index_et_errors_on_project_id_and_status_last_seen_at_id_desc ON error_tracking_errors USING btree (project_id, status, last_seen_at DESC, id DESC);
+CREATE INDEX index_events_author_id_project_id_action_target_type_created_at ON events USING btree (author_id, project_id, action, target_type, created_at);
+
CREATE INDEX index_events_on_action ON events USING btree (action);
CREATE INDEX index_events_on_author_id_and_created_at ON events USING btree (author_id, created_at);
CREATE INDEX index_events_on_author_id_and_created_at_merge_requests ON events USING btree (author_id, created_at) WHERE ((target_type)::text = 'MergeRequest'::text);
-CREATE INDEX index_events_on_author_id_and_project_id ON events USING btree (author_id, project_id);
-
CREATE INDEX index_events_on_created_at_and_id ON events USING btree (created_at, id) WHERE (created_at > '2021-08-27 00:00:00+00'::timestamp with time zone);
CREATE INDEX index_events_on_group_id_partial ON events USING btree (group_id) WHERE (group_id IS NOT NULL);
diff --git a/doc/administration/geo/secondary_proxy/index.md b/doc/administration/geo/secondary_proxy/index.md
index a7a6c5056b2..ebd71757e91 100644
--- a/doc/administration/geo/secondary_proxy/index.md
+++ b/doc/administration/geo/secondary_proxy/index.md
@@ -69,6 +69,8 @@ a single URL used by all Geo sites, including the primary.
is using the secondary proxying and set the `URL` field to the single URL.
Make sure the primary site is also using this URL.
+In Kubernetes, you can use the same domain under `global.hosts.domain` as for the primary site.
+
## Disable Geo proxying
You can disable the secondary proxying on each Geo site, separately, by following these steps with Omnibus-based packages:
@@ -121,18 +123,22 @@ for details.
## Limitations
-The asynchronous Geo replication can cause unexpected issues when secondary proxying is used, for accelerated
-data types that may be replicated to the Geo secondaries with a delay.
+- When secondary proxying is used, the asynchronous Geo replication can cause unexpected issues for accelerated
+ data types that may be replicated to the Geo secondaries with a delay.
-For example, we found a potential issue where
-[Replication lag introduces read-your-own-write inconsistencies](https://gitlab.com/gitlab-org/gitlab/-/issues/345267).
-If the replication lag is high enough, this can result in Git reads receiving stale data when hitting a secondary.
+ For example, we found a potential issue where
+ [replication lag introduces read-after-write inconsistencies](https://gitlab.com/gitlab-org/gitlab/-/issues/345267).
+ If the replication lag is high enough, this can result in Git reads receiving stale data when hitting a secondary.
-Non-Rails requests are not proxied, so other services may need to use a separate, non-unified URL to ensure requests
-are always sent to the primary. These services include:
+- Non-Rails requests are not proxied, so other services may need to use a separate, non-unified URL to ensure requests
+ are always sent to the primary. These services include:
-- GitLab Container Registry - [can be configured to use a separate domain](../../packages/container_registry.md#configure-container-registry-under-its-own-domain).
-- GitLab Pages - should always use a separate domain, as part of [the prerequisites for running GitLab Pages](../../pages/index.md#prerequisites).
+ - GitLab Container Registry - [can be configured to use a separate domain](../../packages/container_registry.md#configure-container-registry-under-its-own-domain).
+ - GitLab Pages - should always use a separate domain, as part of [the prerequisites for running GitLab Pages](../../pages/index.md#prerequisites).
+
+- With a unified URL, Let's Encrypt can't generate certificates unless it can reach both IPs through the same domain.
+ To use TLS certificates with Let's Encrypt, you can manually point the domain to one of the Geo sites, generate
+ the certificate, then copy it to all other sites.
## Features accelerated by secondary Geo sites
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 747aa572a84..f48ba27888c 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -10,7 +10,7 @@ module Gitlab
def initialize(contributor, current_user = nil)
@contributor = contributor
- @contributor_time_instance = local_time_instance(contributor.timezone)
+ @contributor_time_instance = local_timezone_instance(contributor.timezone).now
@current_user = current_user
@projects = if @contributor.include_private_contributions?
ContributedProjectsFinder.new(@contributor).execute(@contributor)
@@ -24,18 +24,20 @@ module Gitlab
return {} if @projects.empty?
return @activity_dates if @activity_dates.present?
- date_interval = "INTERVAL '#{@contributor_time_instance.now.utc_offset} seconds'"
+ start_time = @contributor_time_instance.years_ago(1).beginning_of_day
+ end_time = @contributor_time_instance.end_of_day
+
+ date_interval = "INTERVAL '#{@contributor_time_instance.utc_offset} seconds'"
# Can't use Event.contributions here because we need to check 3 different
# project_features for the (currently) 3 different contribution types
- date_from = @contributor_time_instance.now.years_ago(1)
- repo_events = event_created_at(date_from, :repository)
+ repo_events = events_created_between(start_time, end_time, :repository)
.where(action: :pushed)
- issue_events = event_created_at(date_from, :issues)
+ issue_events = events_created_between(start_time, end_time, :issues)
.where(action: [:created, :closed], target_type: "Issue")
- mr_events = event_created_at(date_from, :merge_requests)
+ mr_events = events_created_between(start_time, end_time, :merge_requests)
.where(action: [:merged, :created, :closed], target_type: "MergeRequest")
- note_events = event_created_at(date_from, :merge_requests)
+ note_events = events_created_between(start_time, end_time, :merge_requests)
.where(action: :commented)
events = Event
@@ -54,7 +56,7 @@ module Gitlab
def events_by_date(date)
return Event.none unless can_read_cross_project?
- date_in_time_zone = date.in_time_zone(@contributor_time_instance)
+ date_in_time_zone = date.in_time_zone(@contributor_time_instance.time_zone)
Event.contributions.where(author_id: contributor.id)
.where(created_at: date_in_time_zone.beginning_of_day..date_in_time_zone.end_of_day)
@@ -64,11 +66,11 @@ module Gitlab
# rubocop: enable CodeReuse/ActiveRecord
def starting_year
- @contributor_time_instance.now.years_ago(1).year
+ @contributor_time_instance.years_ago(1).year
end
def starting_month
- @contributor_time_instance.today.month
+ @contributor_time_instance.month
end
private
@@ -78,9 +80,7 @@ module Gitlab
end
# rubocop: disable CodeReuse/ActiveRecord
- def event_created_at(date_from, feature)
- t = Event.arel_table
-
+ def events_created_between(start_time, end_time, feature)
# re-running the contributed projects query in each union is expensive, so
# use IN(project_ids...) instead. It's the intersection of two users so
# the list will be (relatively) short
@@ -89,24 +89,22 @@ module Gitlab
# no need to check feature access of current user, if the contributor opted-in
# to show all private events anyway - otherwise they would get filtered out again
authed_projects = if @contributor.include_private_contributions?
- @contributed_project_ids.join(",")
+ @contributed_project_ids
else
ProjectFeature
.with_feature_available_for_user(feature, current_user)
.where(project_id: @contributed_project_ids)
.reorder(nil)
.select(:project_id)
- .to_sql
end
- conditions = t[:created_at].gteq(date_from.beginning_of_day)
- .and(t[:created_at].lteq(@contributor_time_instance.today.end_of_day))
- .and(t[:author_id].eq(contributor.id))
-
Event.reorder(nil)
.select(:created_at)
- .where(conditions)
- .where("events.project_id in (#{authed_projects})") # rubocop:disable GitlabSecurity/SqlInjection
+ .where(
+ author_id: contributor.id,
+ created_at: start_time..end_time,
+ events: { project_id: authed_projects }
+ )
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5ceaf9f1c94..8ea49e00eac 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10202,6 +10202,9 @@ msgstr ""
msgid "Critical vulnerabilities present"
msgstr ""
+msgid "Crm|Contact has been added"
+msgstr ""
+
msgid "Crm|Create new contact"
msgstr ""
@@ -10220,6 +10223,9 @@ msgstr ""
msgid "Crm|Last name"
msgstr ""
+msgid "Crm|New Contact"
+msgstr ""
+
msgid "Crm|New contact"
msgstr ""
diff --git a/spec/frontend/crm/contacts_root_spec.js b/spec/frontend/crm/contacts_root_spec.js
index c7410d13365..18bd2d7c45b 100644
--- a/spec/frontend/crm/contacts_root_spec.js
+++ b/spec/frontend/crm/contacts_root_spec.js
@@ -122,16 +122,6 @@ describe('Customer relations contacts root app', () => {
expect(findError().exists()).toBe(true);
});
-
- it('should exist when new contact form emits error', async () => {
- router.replace({ path: '/new' });
- mountComponent();
-
- findNewContactForm().vm.$emit('error');
- await waitForPromises();
-
- expect(findError().exists()).toBe(true);
- });
});
describe('on successful load', () => {
diff --git a/spec/frontend/crm/new_contact_form_spec.js b/spec/frontend/crm/new_contact_form_spec.js
index 681c0539536..1497c348676 100644
--- a/spec/frontend/crm/new_contact_form_spec.js
+++ b/spec/frontend/crm/new_contact_form_spec.js
@@ -1,3 +1,4 @@
+import { GlAlert } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -21,6 +22,7 @@ describe('Customer relations contacts root app', () => {
const findCreateNewContactButton = () => wrapper.findByTestId('create-new-contact-button');
const findCancelButton = () => wrapper.findByTestId('cancel-button');
const findForm = () => wrapper.find('form');
+ const findError = () => wrapper.findComponent(GlAlert);
const mountComponent = ({ mountFunction = shallowMountExtended } = {}) => {
fakeApollo = createMockApollo([[createContactMutation, queryHandler]]);
@@ -32,6 +34,7 @@ describe('Customer relations contacts root app', () => {
wrapper = mountFunction(NewContactForm, {
provide: { groupId: 26, groupFullPath: 'flightjs' },
apolloProvider: fakeApollo,
+ propsData: { drawerOpen: true },
});
};
@@ -83,26 +86,25 @@ describe('Customer relations contacts root app', () => {
});
describe('when query fails', () => {
- it('should emit error on reject', async () => {
+ it('should show error on reject', async () => {
queryHandler = jest.fn().mockRejectedValue('ERROR');
mountComponent();
findForm().trigger('submit');
await waitForPromises();
- expect(wrapper.emitted().error).toBeTruthy();
+ expect(findError().exists()).toBe(true);
});
- it('should emit error on error response', async () => {
+ it('should show error on error response', async () => {
queryHandler = jest.fn().mockResolvedValue(createContactMutationErrorResponse);
mountComponent();
findForm().trigger('submit');
await waitForPromises();
- expect(wrapper.emitted().error[0][0]).toEqual(
- createContactMutationErrorResponse.data.customerRelationsContactCreate.errors,
- );
+ expect(findError().exists()).toBe(true);
+ expect(findError().text()).toBe('Phone is invalid.');
});
});
});
diff --git a/spec/frontend/issuable_bulk_update_sidebar/components/status_select_spec.js b/spec/frontend/issuable/bulk_update_sidebar/components/status_select_spec.js
similarity index 94%
rename from spec/frontend/issuable_bulk_update_sidebar/components/status_select_spec.js
rename to spec/frontend/issuable/bulk_update_sidebar/components/status_select_spec.js
index 09dcb963154..8ecbf41ce56 100644
--- a/spec/frontend/issuable_bulk_update_sidebar/components/status_select_spec.js
+++ b/spec/frontend/issuable/bulk_update_sidebar/components/status_select_spec.js
@@ -1,7 +1,7 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import StatusSelect from '~/issuable_bulk_update_sidebar/components/status_select.vue';
-import { ISSUE_STATUS_SELECT_OPTIONS } from '~/issuable_bulk_update_sidebar/constants';
+import StatusSelect from '~/issuable/bulk_update_sidebar/components/status_select.vue';
+import { ISSUE_STATUS_SELECT_OPTIONS } from '~/issuable/bulk_update_sidebar/constants';
describe('StatusSelect', () => {
let wrapper;
diff --git a/spec/frontend/issuable_form_spec.js b/spec/frontend/issuable/issuable_form_spec.js
similarity index 96%
rename from spec/frontend/issuable_form_spec.js
rename to spec/frontend/issuable/issuable_form_spec.js
index c77fde4261e..321c61ead1e 100644
--- a/spec/frontend/issuable_form_spec.js
+++ b/spec/frontend/issuable/issuable_form_spec.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
-import IssuableForm from '~/issuable_form';
+import IssuableForm from '~/issuable/issuable_form';
function createIssuable() {
const instance = new IssuableForm($(document.createElement('form')));
diff --git a/spec/frontend/issuable_spec.js b/spec/frontend/issuable/issuable_spec.js
similarity index 84%
rename from spec/frontend/issuable_spec.js
rename to spec/frontend/issuable/issuable_spec.js
index e0bd7b802c9..7115861bb51 100644
--- a/spec/frontend/issuable_spec.js
+++ b/spec/frontend/issuable/issuable_spec.js
@@ -1,5 +1,5 @@
-import issuableInitBulkUpdateSidebar from '~/issuable_bulk_update_sidebar/issuable_init_bulk_update_sidebar';
-import IssuableIndex from '~/issuable_index';
+import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
+import IssuableIndex from '~/issuable/issuable_index';
describe('Issuable', () => {
describe('initBulkUpdate', () => {
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index 9556d54104f..7d39f342f27 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -2,7 +2,7 @@ import { GlButton, GlDropdown, GlDropdownItem, GlLink, GlModal } from '@gitlab/u
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import createFlash, { FLASH_TYPES } from '~/flash';
-import { IssuableType } from '~/issuable_show/constants';
+import { IssuableType } from '~/vue_shared/issuable/show/constants';
import HeaderActions from '~/issues/show/components/header_actions.vue';
import { IssuableStatus, IssueStateEvent } from '~/issues/show/constants';
import promoteToEpicMutation from '~/issues/show/queries/promote_to_epic.mutation.graphql';
diff --git a/spec/frontend/delete_label_modal_spec.js b/spec/frontend/labels/delete_label_modal_spec.js
similarity index 97%
rename from spec/frontend/delete_label_modal_spec.js
rename to spec/frontend/labels/delete_label_modal_spec.js
index 0b3e6fe652a..7d3b58078b0 100644
--- a/spec/frontend/delete_label_modal_spec.js
+++ b/spec/frontend/labels/delete_label_modal_spec.js
@@ -1,5 +1,5 @@
import { TEST_HOST } from 'helpers/test_constants';
-import initDeleteLabelModal from '~/delete_label_modal';
+import initDeleteLabelModal from '~/labels/delete_label_modal';
describe('DeleteLabelModal', () => {
const buttons = [
diff --git a/spec/frontend/labels_select_spec.js b/spec/frontend/labels/labels_select_spec.js
similarity index 98%
rename from spec/frontend/labels_select_spec.js
rename to spec/frontend/labels/labels_select_spec.js
index cbc9a923f8b..f6e280564cc 100644
--- a/spec/frontend/labels_select_spec.js
+++ b/spec/frontend/labels/labels_select_spec.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import LabelsSelect from '~/labels_select';
+import LabelsSelect from '~/labels/labels_select';
const mockUrl = '/foo/bar/url';
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
index 7e3ff734981..67c3b8b795a 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
@@ -86,7 +86,7 @@ exports[`packages_list_row renders 1`] = `