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-04-13 15:15:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-13 15:15:20 +0300
commit944a3a7b7e19354abdfcaa79129d0736c4b8565f (patch)
tree627802e84525946f11fdd6976ab5f04fb69e702c /app
parent62798ed33c878f936009da05fdddb707e1c7d58d (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue2
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue47
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue27
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue4
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js2
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher.vue7
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/groups_list.vue15
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/pinned_section.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/projects_list.vue15
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar.vue9
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue4
-rw-r--r--app/assets/stylesheets/framework/header.scss7
-rw-r--r--app/assets/stylesheets/framework/system_messages.scss21
-rw-r--r--app/assets/stylesheets/page_bundles/design_management.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/search.scss12
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss2
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss2
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss3
-rw-r--r--app/assets/stylesheets/utilities.scss6
-rw-r--r--app/finders/clusters/agent_authorizations_finder.rb69
-rw-r--r--app/finders/clusters/agents/authorizations/ci_access/finder.rb75
-rw-r--r--app/helpers/sidebars_helper.rb29
-rw-r--r--app/models/ci/build_metadata.rb2
-rw-r--r--app/models/ci/pipeline.rb2
-rw-r--r--app/models/clusters/agent.rb8
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/group_authorization.rb24
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb27
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/project_authorization.rb24
-rw-r--r--app/models/clusters/agents/group_authorization.rb20
-rw-r--r--app/models/clusters/agents/implicit_authorization.rb23
-rw-r--r--app/models/clusters/agents/project_authorization.rb20
-rw-r--r--app/models/concerns/clusters/agents/authorization_config_scopes.rb25
-rw-r--r--app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb29
-rw-r--r--app/services/ci/generate_kubeconfig_service.rb2
-rw-r--r--app/services/clusters/agents/authorizations/ci_access/filter_service.rb54
-rw-r--r--app/services/clusters/agents/authorizations/ci_access/refresh_service.rb106
-rw-r--r--app/services/clusters/agents/authorize_proxy_user_service.rb4
-rw-r--r--app/services/clusters/agents/filter_authorizations_service.rb50
-rw-r--r--app/services/clusters/agents/refresh_authorization_service.rb102
-rw-r--r--app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json (renamed from app/validators/json_schemas/cluster_agent_authorization_configuration.json)0
-rw-r--r--app/views/search/_results.html.haml10
-rw-r--r--app/views/search/show.html.haml8
44 files changed, 504 insertions, 405 deletions
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index 0251ffe28f9..2f2b2ed1a90 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -332,7 +332,7 @@ export default {
<template>
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue
new file mode 100644
index 00000000000..5b840a5ed43
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue
@@ -0,0 +1,47 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
+import { __ } from '~/locale';
+import { visitUrl } from '~/lib/utils/url_utility';
+
+export default {
+ name: 'ExperimentHeader',
+ components: {
+ DeleteButton,
+ GlButton,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ deleteInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ methods: {
+ downloadCsv() {
+ const currentPath = window.location.pathname;
+ const currentSearch = window.location.search;
+
+ visitUrl(`${currentPath}.csv${currentSearch}`);
+ },
+ },
+ i18n: {
+ downloadAsCsvLabel: __('Download as CSV'),
+ },
+};
+</script>
+
+<template>
+ <div class="detail-page-header gl-flex-wrap-wrap">
+ <div class="detail-page-header-body">
+ <h1 class="page-title gl-font-size-h-display flex-fill">{{ title }}</h1>
+
+ <gl-button @click="downloadCsv">{{ $options.i18n.downloadAsCsvLabel }}</gl-button>
+
+ <delete-button v-bind="deleteInfo" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
index 40b9e0723e9..acb5fc7cad2 100644
--- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
@@ -12,7 +12,7 @@ import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue';
import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
-import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
+import ExperimentHeader from './components/experiment_header.vue';
import {
LIST_KEY_CREATED_AT,
BASE_SORT_FIELDS,
@@ -31,7 +31,7 @@ export default {
IncubationAlert,
RegistrySearch,
KeysetPagination,
- DeleteButton,
+ ExperimentHeader,
},
props: {
experiment: {
@@ -130,6 +130,14 @@ export default {
hasItems() {
return this.candidates.length > 0;
},
+ deleteButtonInfo() {
+ return {
+ deletePath: this.experiment.path,
+ deleteConfirmationText: translations.DELETE_EXPERIMENT_CONFIRMATION_MESSAGE,
+ actionPrimaryText: translations.DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL,
+ modalTitle: translations.DELETE_EXPERIMENT_MODAL_TITLE,
+ };
+ },
},
methods: {
submitFilters() {
@@ -163,20 +171,7 @@ export default {
:link-to-feedback-issue="$options.constants.FEATURE_FEEDBACK_ISSUE"
/>
- <div class="detail-page-header gl-flex-wrap-wrap">
- <div class="detail-page-header-body">
- <h1 class="page-title gl-font-size-h-display flex-fill">
- {{ experiment.name }}
- </h1>
-
- <delete-button
- :delete-path="experiment.path"
- :delete-confirmation-text="$options.i18n.DELETE_EXPERIMENT_CONFIRMATION_MESSAGE"
- :action-primary-text="$options.i18n.DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL"
- :modal-title="$options.i18n.DELETE_EXPERIMENT_MODAL_TITLE"
- />
- </div>
- </div>
+ <experiment-header :title="experiment.name" :delete-info="deleteButtonInfo" />
<registry-search
:filters="filters"
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
index 02a3870f499..1c81f652387 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -22,7 +22,9 @@ export default {
...mapState(['navigation', 'urlQuery']),
},
created() {
- this.fetchSidebarCount();
+ if (this.urlQuery?.search) {
+ this.fetchSidebarCount();
+ }
},
methods: {
...mapActions(['fetchSidebarCount']),
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
index 395629dc70c..f123494fba2 100644
--- a/app/assets/javascripts/search/sidebar/constants/index.js
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -12,7 +12,7 @@ export const NAV_LINK_DEFAULT_CLASSES = [
'gl-justify-content-space-between',
];
export const NAV_LINK_COUNT_DEFAULT_CLASSES = ['gl-font-sm', 'gl-font-weight-normal'];
-export const HR_DEFAULT_CLASSES = ['gl-my-5', 'gl-mx-5', 'gl-border-gray-100'];
+export const HR_DEFAULT_CLASSES = ['gl-m-5', 'gl-border-gray-100'];
export const ONLY_SHOW_MD = ['gl-display-none', 'gl-md-display-block'];
export const TRACKING_LABEL_CHECKBOX = 'Checkbox';
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher.vue b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
index 5c1cebe0195..fa9da6cef9d 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
@@ -150,7 +150,12 @@ export default {
{{ $options.i18n.switchTo }}
</div>
<ul :aria-label="$options.i18n.switchTo" class="gl-p-0">
- <nav-item v-for="item in persistentLinks" :key="item.link" :item="item" />
+ <nav-item
+ v-for="item in persistentLinks"
+ :key="item.link"
+ :item="item"
+ :link-classes="{ [item.link_classes]: item.link_classes }"
+ />
</ul>
</li>
<projects-list
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
index 451e12df697..e56ef9e410b 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
@@ -38,7 +38,7 @@ export default {
<button
v-collapse-toggle.context-switcher
type="button"
- class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8"
+ class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8"
>
<span
v-if="context.icon"
diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue
index eb256e4971b..4fa15f1cd76 100644
--- a/app/assets/javascripts/super_sidebar/components/groups_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/groups_list.vue
@@ -36,11 +36,14 @@ export default {
storageKey() {
return `${this.username}/frequent-groups`;
},
- viewAllItem() {
+ viewAllProps() {
return {
- link: this.viewAllLink,
- title: s__('Navigation|View all your groups'),
- icon: 'group',
+ item: {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all your groups'),
+ icon: 'group',
+ },
+ linkClasses: { 'dashboard-shortcuts-groups': true },
};
},
},
@@ -61,7 +64,7 @@ export default {
:search-results="searchResults"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</search-results>
<frequent-items-list
@@ -72,7 +75,7 @@ export default {
:pristine-text="$options.i18n.pristineText"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</frequent-items-list>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 3a3eb72a4a8..53698a808a7 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -146,7 +146,7 @@ export default {
<component
:is="elem"
v-bind="linkProps"
- class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-text-decoration-none!"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-mb-1 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none!"
:class="computedLinkClasses"
data-qa-selector="nav_item_link"
data-testid="nav-item-link"
diff --git a/app/assets/javascripts/super_sidebar/components/pinned_section.vue b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
index d1c0e757a91..193de143c2b 100644
--- a/app/assets/javascripts/super_sidebar/components/pinned_section.vue
+++ b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
@@ -60,7 +60,7 @@ export default {
<section class="gl-mx-2">
<a
href="#"
- class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-py-3 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-text-decoration-none!"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-py-3 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none!"
@click.prevent="expanded = !expanded"
>
<div class="gl-flex-shrink-0 gl-w-6 gl-mx-3">
diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue
index b7a29a78d5f..78860e35eb1 100644
--- a/app/assets/javascripts/super_sidebar/components/projects_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/projects_list.vue
@@ -36,11 +36,14 @@ export default {
storageKey() {
return `${this.username}/frequent-projects`;
},
- viewAllItem() {
+ viewAllProps() {
return {
- link: this.viewAllLink,
- title: s__('Navigation|View all your projects'),
- icon: 'project',
+ item: {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all your projects'),
+ icon: 'project',
+ },
+ linkClasses: { 'dashboard-shortcuts-projects': true },
};
},
},
@@ -62,7 +65,7 @@ export default {
:search-results="searchResults"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</search-results>
<frequent-items-list
@@ -73,7 +76,7 @@ export default {
:pristine-text="$options.i18n.pristineText"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</frequent-items-list>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index 302b6a9d4b0..2a95d2c37c4 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -108,5 +108,14 @@ export default {
</div>
</div>
</aside>
+ <a
+ v-for="shortcutLink in sidebarData.shortcut_links"
+ :key="shortcutLink.href"
+ :href="shortcutLink.href"
+ :class="shortcutLink.css_class"
+ class="gl-display-none"
+ >
+ {{ shortcutLink.title }}
+ </a>
</div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index 498c082ddb2..b69ebc6be17 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -137,7 +137,7 @@ export default {
<div class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2">
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.issues"
- class="gl-flex-basis-third"
+ class="gl-flex-basis-third dashboard-shortcuts-issues"
icon="issues"
:count="sidebarData.assigned_open_issues_count"
:href="sidebarData.issues_dashboard_path"
@@ -165,7 +165,7 @@ export default {
</merge-request-menu>
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.todoList"
- class="gl-flex-basis-third"
+ class="gl-flex-basis-third shortcuts-todos"
icon="todo-done"
:count="sidebarData.todos_pending_count"
href="/dashboard/todos"
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 0d18835ac0f..22c6fb04d3b 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -8,7 +8,7 @@ $search-input-field-x-min-width: 200px;
min-height: $header-height;
border: 0;
position: fixed;
- top: 0;
+ top: $calc-application-bars-height;
left: 0;
right: 0;
border-radius: 0;
@@ -479,11 +479,6 @@ $search-input-field-x-min-width: 200px;
visibility: visible;
}
-.with-performance-bar .navbar-gitlab,
-.with-performance-bar .fixed-top {
- top: $performance-bar-height;
-}
-
.navbar-empty {
justify-content: center;
height: $header-height;
diff --git a/app/assets/stylesheets/framework/system_messages.scss b/app/assets/stylesheets/framework/system_messages.scss
index db59a482c64..946a241e6dd 100644
--- a/app/assets/stylesheets/framework/system_messages.scss
+++ b/app/assets/stylesheets/framework/system_messages.scss
@@ -36,27 +36,6 @@
}
}
-// System Header
-.with-system-header {
- // main navigation
- // login page
- .navbar-gitlab,
- .fixed-top {
- top: $system-header-height;
- }
-
- // Performance Bar
- // System Header
- &.with-performance-bar {
- // main navigation
- header.navbar-gitlab,
- .fixed-top {
- top: $performance-bar-height + $system-header-height;
- }
-
- }
-}
-
// System Footer
.with-system-footer {
// navless pages' footer eg: login page
diff --git a/app/assets/stylesheets/page_bundles/design_management.scss b/app/assets/stylesheets/page_bundles/design_management.scss
index 143682e1cd7..f56eb4ae6fb 100644
--- a/app/assets/stylesheets/page_bundles/design_management.scss
+++ b/app/assets/stylesheets/page_bundles/design_management.scss
@@ -20,10 +20,7 @@ $t-gray-a-16-design-pin: rgba($black, 0.16);
.design-detail {
background-color: rgba($modal-backdrop-bg, $modal-backdrop-opacity);
-
- .with-performance-bar & {
- top: 35px;
- }
+ bottom: $calc-application-footer-height;
.comment-indicator {
border-radius: 50%;
diff --git a/app/assets/stylesheets/page_bundles/search.scss b/app/assets/stylesheets/page_bundles/search.scss
index cde570cfb0f..d37e87b5cd5 100644
--- a/app/assets/stylesheets/page_bundles/search.scss
+++ b/app/assets/stylesheets/page_bundles/search.scss
@@ -21,18 +21,18 @@ $border-radius-medium: 3px;
}
}
+.language-filter-checkbox {
+ .custom-control-label {
+ flex-grow: 1;
+ }
+}
+
.search-sidebar {
@include media-breakpoint-up(md) {
min-width: $search-sidebar-min-width;
max-width: $search-sidebar-max-width;
}
- .language-filter-checkbox {
- .custom-control-label {
- flex-grow: 1;
- }
- }
-
.language-filter-max-height {
max-height: $language-filter-max-height;
}
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index de2a2ddcf32..5219cd62775 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -750,7 +750,7 @@ kbd {
min-height: var(--header-height, 48px);
border: 0;
position: fixed;
- top: 0;
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
left: 0;
right: 0;
border-radius: 0;
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index e0a71a1c306..16bf2c20bbc 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -750,7 +750,7 @@ kbd {
min-height: var(--header-height, 48px);
border: 0;
position: fixed;
- top: 0;
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
left: 0;
right: 0;
border-radius: 0;
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 3663c97f41a..fcdcab5caeb 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -769,6 +769,9 @@ svg {
fill: currentColor;
}
+.fixed-top {
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
+}
.gl-display-flex {
display: flex;
}
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 66c543aa654..e5f99879166 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -39,6 +39,12 @@
.border-radius-small { border-radius: $border-radius-small; }
.box-shadow-default { box-shadow: 0 2px 4px 0 $black-transparent; }
+// Override Bootstrap class with offset for system-header and
+// performance bar when present
+.fixed-top {
+ top: $calc-application-bars-height;
+}
+
.gl-children-ml-sm-3 > * {
@include media-breakpoint-up(sm) {
@include gl-ml-3;
diff --git a/app/finders/clusters/agent_authorizations_finder.rb b/app/finders/clusters/agent_authorizations_finder.rb
deleted file mode 100644
index 70c0868cc7f..00000000000
--- a/app/finders/clusters/agent_authorizations_finder.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- class AgentAuthorizationsFinder
- def initialize(project)
- @project = project
- end
-
- def execute
- # closest, most-specific authorization for a given agent wins
- (project_authorizations + implicit_authorizations + group_authorizations)
- .uniq(&:agent_id)
- end
-
- private
-
- attr_reader :project
-
- def implicit_authorizations
- project.cluster_agents.map do |agent|
- Clusters::Agents::ImplicitAuthorization.new(agent: agent)
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def project_authorizations
- namespace_ids = project.group ? all_namespace_ids : project.namespace_id
-
- Clusters::Agents::ProjectAuthorization
- .where(project_id: project.id)
- .joins(agent: :project)
- .preload(agent: :project)
- .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
- .with_available_ci_access_fields(project)
- .to_a
- end
-
- def group_authorizations
- return [] unless project.group
-
- authorizations = Clusters::Agents::GroupAuthorization.arel_table
-
- ordered_ancestors_cte = Gitlab::SQL::CTE.new(
- :ordered_ancestors,
- project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
- )
-
- cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
- authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
- ).join_sources
-
- Clusters::Agents::GroupAuthorization
- .with(ordered_ancestors_cte.to_arel)
- .joins(cte_join_sources)
- .joins(agent: :project)
- .with_available_ci_access_fields(project)
- .where(projects: { namespace_id: all_namespace_ids })
- .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
- .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
- .preload(agent: :project)
- .to_a
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def all_namespace_ids
- project.root_ancestor.self_and_descendants.select(:id)
- end
- end
-end
diff --git a/app/finders/clusters/agents/authorizations/ci_access/finder.rb b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
new file mode 100644
index 00000000000..97d378669a4
--- /dev/null
+++ b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class Finder
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ # closest, most-specific authorization for a given agent wins
+ (project_authorizations + implicit_authorizations + group_authorizations)
+ .uniq(&:agent_id)
+ end
+
+ private
+
+ attr_reader :project
+
+ def implicit_authorizations
+ project.cluster_agents.map do |agent|
+ Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: agent)
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def project_authorizations
+ namespace_ids = project.group ? all_namespace_ids : project.namespace_id
+
+ Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
+ .where(project_id: project.id)
+ .joins(agent: :project)
+ .preload(agent: :project)
+ .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
+ .with_available_ci_access_fields(project)
+ .to_a
+ end
+
+ def group_authorizations
+ return [] unless project.group
+
+ authorizations = Clusters::Agents::Authorizations::CiAccess::GroupAuthorization.arel_table
+
+ ordered_ancestors_cte = Gitlab::SQL::CTE.new(
+ :ordered_ancestors,
+ project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
+ )
+
+ cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
+ authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
+ ).join_sources
+
+ Clusters::Agents::Authorizations::CiAccess::GroupAuthorization
+ .with(ordered_ancestors_cte.to_arel)
+ .joins(cte_join_sources)
+ .joins(agent: :project)
+ .with_available_ci_access_fields(project)
+ .where(projects: { namespace_id: all_namespace_ids })
+ .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
+ .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
+ .preload(agent: :project)
+ .to_a
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def all_namespace_ids
+ project.root_ancestor.self_and_descendants.select(:id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index a6eddb4d529..8af4204e5e1 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -89,7 +89,8 @@ module SidebarsHelper
panel_type: panel_type,
update_pins_url: pins_url,
is_impersonating: impersonating?,
- stop_impersonation_path: admin_impersonation_path
+ stop_impersonation_path: admin_impersonation_path,
+ shortcut_links: shortcut_links
}
end
@@ -180,7 +181,8 @@ module SidebarsHelper
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_assigned',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-merge_requests'
}
},
{
@@ -190,7 +192,8 @@ module SidebarsHelper
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_to_review',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-review_requests'
}
}
]
@@ -334,6 +337,26 @@ module SidebarsHelper
def impersonating?
!!session[:impersonator_id]
end
+
+ def shortcut_links
+ [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ }
+ ]
+ end
end
SidebarsHelper.prepend_mod_with('SidebarsHelper')
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index 4b2be446fe3..b98fdba44ec 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -11,9 +11,11 @@ module Ci
include ChronicDurationAttribute
include Gitlab::Utils::StrongMemoize
include IgnorableColumns
+ include SafelyChangeColumnDefault
self.table_name = 'p_ci_builds_metadata'
self.primary_key = 'id'
+ columns_changing_default :partition_id
partitionable scope: :build
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 8c7b0193199..f5a2911fc59 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -1334,7 +1334,7 @@ module Ci
def cluster_agent_authorizations
strong_memoize(:cluster_agent_authorizations) do
- ::Clusters::AgentAuthorizationsFinder.new(project).execute
+ ::Clusters::Agents::Authorizations::CiAccess::Finder.new(project).execute
end
end
diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb
index 3478bb69707..4e2de06577d 100644
--- a/app/models/clusters/agent.rb
+++ b/app/models/clusters/agent.rb
@@ -12,11 +12,11 @@ module Clusters
has_many :agent_tokens, -> { order_last_used_at_desc }, class_name: 'Clusters::AgentToken', inverse_of: :agent
- has_many :group_authorizations, class_name: 'Clusters::Agents::GroupAuthorization'
- has_many :authorized_groups, class_name: '::Group', through: :group_authorizations, source: :group
+ has_many :ci_access_group_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::GroupAuthorization'
+ has_many :ci_access_authorized_groups, class_name: '::Group', through: :ci_access_group_authorizations, source: :group
- has_many :project_authorizations, class_name: 'Clusters::Agents::ProjectAuthorization'
- has_many :authorized_projects, class_name: '::Project', through: :project_authorizations, source: :project
+ has_many :ci_access_project_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization'
+ has_many :ci_access_authorized_projects, class_name: '::Project', through: :ci_access_project_authorizations, source: :project
has_many :activity_events, -> { in_timeline_order }, class_name: 'Clusters::Agents::ActivityEvent', inverse_of: :agent
diff --git a/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb
new file mode 100644
index 00000000000..4261fd6570f
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class GroupAuthorization < ApplicationRecord
+ include ConfigScopes
+
+ self.table_name = 'agent_group_authorizations'
+
+ belongs_to :agent, class_name: 'Clusters::Agent', optional: false
+ belongs_to :group, class_name: '::Group', optional: false
+
+ validates :config, json_schema: { filename: 'clusters_agents_authorizations_ci_access_config' }
+
+ def config_project
+ agent.project
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb
new file mode 100644
index 00000000000..b996ae3f92b
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class ImplicitAuthorization
+ attr_reader :agent
+
+ delegate :id, to: :agent, prefix: true
+
+ def initialize(agent:)
+ @agent = agent
+ end
+
+ def config_project
+ agent.project
+ end
+
+ def config
+ {}
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb
new file mode 100644
index 00000000000..7742d109cdb
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class ProjectAuthorization < ApplicationRecord
+ include ConfigScopes
+
+ self.table_name = 'agent_project_authorizations'
+
+ belongs_to :agent, class_name: 'Clusters::Agent', optional: false
+ belongs_to :project, class_name: '::Project', optional: false
+
+ validates :config, json_schema: { filename: 'clusters_agents_authorizations_ci_access_config' }
+
+ def config_project
+ agent.project
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/group_authorization.rb b/app/models/clusters/agents/group_authorization.rb
deleted file mode 100644
index 58ba874ab53..00000000000
--- a/app/models/clusters/agents/group_authorization.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class GroupAuthorization < ApplicationRecord
- include ::Clusters::Agents::AuthorizationConfigScopes
-
- self.table_name = 'agent_group_authorizations'
-
- belongs_to :agent, class_name: 'Clusters::Agent', optional: false
- belongs_to :group, class_name: '::Group', optional: false
-
- validates :config, json_schema: { filename: 'cluster_agent_authorization_configuration' }
-
- def config_project
- agent.project
- end
- end
- end
-end
diff --git a/app/models/clusters/agents/implicit_authorization.rb b/app/models/clusters/agents/implicit_authorization.rb
deleted file mode 100644
index a365ccdc568..00000000000
--- a/app/models/clusters/agents/implicit_authorization.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class ImplicitAuthorization
- attr_reader :agent
-
- delegate :id, to: :agent, prefix: true
-
- def initialize(agent:)
- @agent = agent
- end
-
- def config_project
- agent.project
- end
-
- def config
- {}
- end
- end
- end
-end
diff --git a/app/models/clusters/agents/project_authorization.rb b/app/models/clusters/agents/project_authorization.rb
deleted file mode 100644
index b9b44741936..00000000000
--- a/app/models/clusters/agents/project_authorization.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class ProjectAuthorization < ApplicationRecord
- include ::Clusters::Agents::AuthorizationConfigScopes
-
- self.table_name = 'agent_project_authorizations'
-
- belongs_to :agent, class_name: 'Clusters::Agent', optional: false
- belongs_to :project, class_name: '::Project', optional: false
-
- validates :config, json_schema: { filename: 'cluster_agent_authorization_configuration' }
-
- def config_project
- agent.project
- end
- end
- end
-end
diff --git a/app/models/concerns/clusters/agents/authorization_config_scopes.rb b/app/models/concerns/clusters/agents/authorization_config_scopes.rb
deleted file mode 100644
index 0a0406c3389..00000000000
--- a/app/models/concerns/clusters/agents/authorization_config_scopes.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- module AuthorizationConfigScopes
- extend ActiveSupport::Concern
-
- included do
- scope :with_available_ci_access_fields, ->(project) {
- where("config->'access_as' IS NULL")
- .or(where("config->'access_as' = '{}'"))
- .or(where("config->'access_as' ?| array[:fields]", fields: available_ci_access_fields(project)))
- }
- end
-
- class_methods do
- def available_ci_access_fields(_project)
- %w(agent)
- end
- end
- end
- end
-end
-
-Clusters::Agents::AuthorizationConfigScopes.prepend_mod
diff --git a/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
new file mode 100644
index 00000000000..eef68bfd349
--- /dev/null
+++ b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ module ConfigScopes
+ extend ActiveSupport::Concern
+
+ included do
+ scope :with_available_ci_access_fields, ->(project) {
+ where("config->'access_as' IS NULL")
+ .or(where("config->'access_as' = '{}'"))
+ .or(where("config->'access_as' ?| array[:fields]", fields: available_ci_access_fields(project)))
+ }
+ end
+
+ class_methods do
+ def available_ci_access_fields(_project)
+ %w(agent)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+Clusters::Agents::Authorizations::CiAccess::ConfigScopes.prepend_mod
diff --git a/app/services/ci/generate_kubeconfig_service.rb b/app/services/ci/generate_kubeconfig_service.rb
index 1c6aaa9d1ff..56e22a64529 100644
--- a/app/services/ci/generate_kubeconfig_service.rb
+++ b/app/services/ci/generate_kubeconfig_service.rb
@@ -41,7 +41,7 @@ module Ci
attr_reader :pipeline, :token, :environment, :template
def agent_authorizations
- ::Clusters::Agents::FilterAuthorizationsService.new(
+ ::Clusters::Agents::Authorizations::CiAccess::FilterService.new(
pipeline.cluster_agent_authorizations,
environment: environment
).execute
diff --git a/app/services/clusters/agents/authorizations/ci_access/filter_service.rb b/app/services/clusters/agents/authorizations/ci_access/filter_service.rb
new file mode 100644
index 00000000000..cd08aaa12d4
--- /dev/null
+++ b/app/services/clusters/agents/authorizations/ci_access/filter_service.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class FilterService
+ def initialize(authorizations, filter_params)
+ @authorizations = authorizations
+ @filter_params = filter_params
+
+ @environments_matcher = {}
+ end
+
+ def execute
+ filter_by_environment(authorizations)
+ end
+
+ private
+
+ attr_reader :authorizations, :filter_params
+
+ def filter_by_environment(auths)
+ return auths unless filter_by_environment?
+
+ auths.select do |auth|
+ next true if auth.config['environments'].blank?
+
+ auth.config['environments'].any? { |environment_pattern| matches_environment?(environment_pattern) }
+ end
+ end
+
+ def filter_by_environment?
+ filter_params.has_key?(:environment)
+ end
+
+ def environment_filter
+ @environment_filter ||= filter_params[:environment]
+ end
+
+ def matches_environment?(environment_pattern)
+ return false if environment_filter.nil?
+
+ environments_matcher(environment_pattern).match?(environment_filter)
+ end
+
+ def environments_matcher(environment_pattern)
+ @environments_matcher[environment_pattern] ||= ::Gitlab::Ci::EnvironmentMatcher.new(environment_pattern)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb b/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb
new file mode 100644
index 00000000000..047a0725a2c
--- /dev/null
+++ b/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class RefreshService
+ include Gitlab::Utils::StrongMemoize
+
+ AUTHORIZED_ENTITY_LIMIT = 100
+
+ delegate :project, to: :agent, private: true
+ delegate :root_ancestor, to: :project, private: true
+
+ def initialize(agent, config:)
+ @agent = agent
+ @config = config
+ end
+
+ def execute
+ refresh_projects!
+ refresh_groups!
+
+ true
+ end
+
+ private
+
+ attr_reader :agent, :config
+
+ def refresh_projects!
+ if allowed_project_configurations.present?
+ project_ids = allowed_project_configurations.map { |config| config.fetch(:project_id) }
+
+ agent.with_lock do
+ agent.ci_access_project_authorizations.upsert_all(allowed_project_configurations, unique_by: [:agent_id, :project_id])
+ agent.ci_access_project_authorizations.where.not(project_id: project_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
+ end
+ else
+ agent.ci_access_project_authorizations.delete_all(:delete_all)
+ end
+ end
+
+ def refresh_groups!
+ if allowed_group_configurations.present?
+ group_ids = allowed_group_configurations.map { |config| config.fetch(:group_id) }
+
+ agent.with_lock do
+ agent.ci_access_group_authorizations.upsert_all(allowed_group_configurations, unique_by: [:agent_id, :group_id])
+ agent.ci_access_group_authorizations.where.not(group_id: group_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
+ end
+ else
+ agent.ci_access_group_authorizations.delete_all(:delete_all)
+ end
+ end
+
+ def allowed_project_configurations
+ strong_memoize(:allowed_project_configurations) do
+ project_entries = extract_config_entries(entity: 'projects')
+
+ if project_entries
+ allowed_projects.where_full_path_in(project_entries.keys).map do |project|
+ { project_id: project.id, config: project_entries[project.full_path.downcase] }
+ end
+ end
+ end
+ end
+
+ def allowed_group_configurations
+ strong_memoize(:allowed_group_configurations) do
+ group_entries = extract_config_entries(entity: 'groups')
+
+ if group_entries
+ allowed_groups.where_full_path_in(group_entries.keys).map do |group|
+ { group_id: group.id, config: group_entries[group.full_path.downcase] }
+ end
+ end
+ end
+ end
+
+ def extract_config_entries(entity:)
+ config.dig('ci_access', entity)
+ &.first(AUTHORIZED_ENTITY_LIMIT)
+ &.index_by { |config| config.delete('id').downcase }
+ end
+
+ def allowed_projects
+ root_ancestor.all_projects
+ end
+
+ def allowed_groups
+ if group_root_ancestor?
+ root_ancestor.self_and_descendants
+ else
+ ::Group.none
+ end
+ end
+
+ def group_root_ancestor?
+ root_ancestor.group_namespace?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/agents/authorize_proxy_user_service.rb b/app/services/clusters/agents/authorize_proxy_user_service.rb
index ec6645b2db4..ba90d61a7ef 100644
--- a/app/services/clusters/agents/authorize_proxy_user_service.rb
+++ b/app/services/clusters/agents/authorize_proxy_user_service.rb
@@ -57,7 +57,7 @@ module Clusters
def authorized_projects(user_access)
strong_memoize_with(:authorized_projects, user_access) do
user_access.fetch(:projects, [])
- .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .first(::Clusters::Agents::Authorizations::CiAccess::RefreshService::AUTHORIZED_ENTITY_LIMIT)
.map { |project| ::Project.find_by_full_path(project[:id]) }
.select { |project| current_user.can?(:use_k8s_proxies, project) }
end
@@ -66,7 +66,7 @@ module Clusters
def authorized_groups(user_access)
strong_memoize_with(:authorized_groups, user_access) do
user_access.fetch(:groups, [])
- .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .first(::Clusters::Agents::Authorizations::CiAccess::RefreshService::AUTHORIZED_ENTITY_LIMIT)
.map { |group| ::Group.find_by_full_path(group[:id]) }
.select { |group| current_user.can?(:use_k8s_proxies, group) }
end
diff --git a/app/services/clusters/agents/filter_authorizations_service.rb b/app/services/clusters/agents/filter_authorizations_service.rb
deleted file mode 100644
index 68517ceec04..00000000000
--- a/app/services/clusters/agents/filter_authorizations_service.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class FilterAuthorizationsService
- def initialize(authorizations, filter_params)
- @authorizations = authorizations
- @filter_params = filter_params
-
- @environments_matcher = {}
- end
-
- def execute
- filter_by_environment(authorizations)
- end
-
- private
-
- attr_reader :authorizations, :filter_params
-
- def filter_by_environment(auths)
- return auths unless filter_by_environment?
-
- auths.select do |auth|
- next true if auth.config['environments'].blank?
-
- auth.config['environments'].any? { |environment_pattern| matches_environment?(environment_pattern) }
- end
- end
-
- def filter_by_environment?
- filter_params.has_key?(:environment)
- end
-
- def environment_filter
- @environment_filter ||= filter_params[:environment]
- end
-
- def matches_environment?(environment_pattern)
- return false if environment_filter.nil?
-
- environments_matcher(environment_pattern).match?(environment_filter)
- end
-
- def environments_matcher(environment_pattern)
- @environments_matcher[environment_pattern] ||= ::Gitlab::Ci::EnvironmentMatcher.new(environment_pattern)
- end
- end
- end
-end
diff --git a/app/services/clusters/agents/refresh_authorization_service.rb b/app/services/clusters/agents/refresh_authorization_service.rb
deleted file mode 100644
index 23ececef6a1..00000000000
--- a/app/services/clusters/agents/refresh_authorization_service.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class RefreshAuthorizationService
- include Gitlab::Utils::StrongMemoize
-
- AUTHORIZED_ENTITY_LIMIT = 100
-
- delegate :project, to: :agent, private: true
- delegate :root_ancestor, to: :project, private: true
-
- def initialize(agent, config:)
- @agent = agent
- @config = config
- end
-
- def execute
- refresh_projects!
- refresh_groups!
-
- true
- end
-
- private
-
- attr_reader :agent, :config
-
- def refresh_projects!
- if allowed_project_configurations.present?
- project_ids = allowed_project_configurations.map { |config| config.fetch(:project_id) }
-
- agent.with_lock do
- agent.project_authorizations.upsert_all(allowed_project_configurations, unique_by: [:agent_id, :project_id])
- agent.project_authorizations.where.not(project_id: project_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
- end
- else
- agent.project_authorizations.delete_all(:delete_all)
- end
- end
-
- def refresh_groups!
- if allowed_group_configurations.present?
- group_ids = allowed_group_configurations.map { |config| config.fetch(:group_id) }
-
- agent.with_lock do
- agent.group_authorizations.upsert_all(allowed_group_configurations, unique_by: [:agent_id, :group_id])
- agent.group_authorizations.where.not(group_id: group_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
- end
- else
- agent.group_authorizations.delete_all(:delete_all)
- end
- end
-
- def allowed_project_configurations
- strong_memoize(:allowed_project_configurations) do
- project_entries = extract_config_entries(entity: 'projects')
-
- if project_entries
- allowed_projects.where_full_path_in(project_entries.keys).map do |project|
- { project_id: project.id, config: project_entries[project.full_path.downcase] }
- end
- end
- end
- end
-
- def allowed_group_configurations
- strong_memoize(:allowed_group_configurations) do
- group_entries = extract_config_entries(entity: 'groups')
-
- if group_entries
- allowed_groups.where_full_path_in(group_entries.keys).map do |group|
- { group_id: group.id, config: group_entries[group.full_path.downcase] }
- end
- end
- end
- end
-
- def extract_config_entries(entity:)
- config.dig('ci_access', entity)
- &.first(AUTHORIZED_ENTITY_LIMIT)
- &.index_by { |config| config.delete('id').downcase }
- end
-
- def allowed_projects
- root_ancestor.all_projects
- end
-
- def allowed_groups
- if group_root_ancestor?
- root_ancestor.self_and_descendants
- else
- ::Group.none
- end
- end
-
- def group_root_ancestor?
- root_ancestor.group_namespace?
- end
- end
- end
-end
diff --git a/app/validators/json_schemas/cluster_agent_authorization_configuration.json b/app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json
index f3de0b7043b..f3de0b7043b 100644
--- a/app/validators/json_schemas/cluster_agent_authorization_configuration.json
+++ b/app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 3280dcf2cd4..99558f61b25 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,9 +1,5 @@
-- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
-
= render_if_exists 'shared/promotions/promote_advanced_search'
-.results.gl-md-display-flex.gl-mt-0
- #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
- .gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
- = render partial: 'search/results_status' if @search_objects.present?
- = render partial: 'search/results_list'
+.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
+ = render partial: 'search/results_status' unless @search_objects.to_a.empty?
+ = render partial: 'search/results_list'
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 826d78c470d..934f59ea586 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -1,12 +1,14 @@
- @hide_top_links = true
- breadcrumb_title _('Search')
- page_title @search_term
+- nav 'search'
- if params[:group_id].present?
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
= hidden_field_tag :project_id, params[:project_id]
- group_attributes = @group&.attributes&.slice('id', 'name')&.merge(full_name: @group&.full_name)
- project_attributes = @project&.attributes&.slice('id', 'namespace_id', 'name')&.merge(name_with_namespace: @project&.name_with_namespace)
+- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
- if @search_results && !(@search_results.respond_to?(:failed?) && @search_results.failed?)
- if @search_service_presenter.without_count?
@@ -20,5 +22,7 @@
= render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "elasticsearch-enabled": @search_service_presenter.advanced_search_enabled?.to_s, "default-branch-name": @project&.default_branch } }
-- if @search_term
- = render 'search/results'
+.results.gl-md-display-flex.gl-mt-0
+ #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
+ - if @search_term
+ = render 'search/results'