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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-21 21:16:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-21 21:16:10 +0300
commitd2f2219fd58e572c10d77183e2f65de8fcc8df96 (patch)
tree2cde75cd3d994b7febe1349ab61b7a94a95c78cf /app/assets
parent6323146895db2be6f04846b3c98060b7349207b9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue1
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_bundle.js13
-rw-r--r--app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue76
-rw-r--r--app/assets/javascripts/lib/utils/constants.js5
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js45
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue8
-rw-r--r--app/assets/javascripts/search/store/actions.js51
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue4
-rw-r--r--app/assets/stylesheets/page_bundles/login.scss3
9 files changed, 130 insertions, 76 deletions
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index aacb460a817..8bd55e697fa 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -368,6 +368,7 @@ export default {
</div>
<div v-if="clusterAgent" :class="$options.kubernetesOverviewClasses">
<kubernetes-overview
+ :class="{ 'gl-ml-7': inFolder }"
:cluster-agent="clusterAgent"
:namespace="kubernetesNamespace"
:flux-resource-path="fluxResourcePath"
diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
index 0201fb53f77..05a2eba6af3 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
import createDefaultClient from '~/lib/graphql';
import Translate from '~/vue_shared/translate';
+import { removeLastSlashInUrlPath } from '~/lib/utils/url_utility';
import { apolloProvider } from '../graphql/client';
import EnvironmentsFolderView from './environments_folder_view.vue';
import EnvironmentsFolderApp from './environments_folder_app.vue';
@@ -20,10 +21,9 @@ export default () => {
if (gon.features.environmentsFolderNewLook) {
Vue.use(VueRouter);
- const folderName = environmentsData.environmentsDataFolderName;
- const folderPath = environmentsData.environmentsDataEndpoint.replace('.json', '');
- const projectPath = environmentsData.environmentsDataProjectPath;
- const helpPagePath = environmentsData.environmentsDataHelpPagePath;
+ const folderPath = environmentsData.endpoint.replace('.json', '');
+ const kasTunnelUrl = removeLastSlashInUrlPath(environmentsData.kasTunnelUrl);
+ const { projectPath, folderName, helpPagePath } = environmentsData;
const router = new VueRouter({
mode: 'history',
@@ -54,6 +54,7 @@ export default () => {
provide: {
projectPath,
helpPagePath,
+ kasTunnelUrl,
},
apolloProvider,
router,
@@ -74,8 +75,8 @@ export default () => {
},
data() {
return {
- endpoint: environmentsData.environmentsDataEndpoint,
- folderName: environmentsData.environmentsDataFolderName,
+ endpoint: environmentsData.endpoint,
+ folderName: environmentsData.folderName,
cssContainerClass: environmentsData.cssClass,
};
},
diff --git a/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
index 52a12cc7771..e3fa0ce8073 100644
--- a/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
+++ b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
@@ -1,20 +1,20 @@
<script>
import { GlAvatarLabeled, GlCollapsibleListbox } from '@gitlab/ui';
import { debounce } from 'lodash';
+import produce from 'immer';
import { __ } from '~/locale';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
import { PROJECTS_PER_PAGE } from '../constants';
import getProjectsQuery from '../graphql/queries/get_projects.query.graphql';
export default {
- PROJECTS_PER_PAGE,
- projectQueryPageInfo: {
- endCursor: '',
- },
+ name: 'ProjectDropdown',
+
components: {
GlAvatarLabeled,
GlCollapsibleListbox,
},
+
props: {
selectedProject: {
type: Object,
@@ -22,27 +22,29 @@ export default {
default: null,
},
},
+
data() {
return {
initialProjectsLoading: true,
+ isLoadingMore: false,
projectSearchQuery: '',
selectedProjectId: this.selectedProject?.id,
};
},
+
apollo: {
projects: {
query: getProjectsQuery,
variables() {
return {
- search: this.projectSearchQuery,
- first: this.$options.PROJECTS_PER_PAGE,
- after: this.$options.projectQueryPageInfo.endCursor,
- searchNamespaces: true,
- sort: 'similarity',
+ ...this.queryVariables,
};
},
update(data) {
- return data?.projects?.nodes.filter((project) => !project.repository?.empty) ?? [];
+ return {
+ nodes: data?.projects?.nodes.filter((project) => !project.repository?.empty) ?? [],
+ pageInfo: data?.projects?.pageInfo,
+ };
},
result() {
this.initialProjectsLoading = false;
@@ -52,24 +54,37 @@ export default {
},
},
},
+
computed: {
- projectsLoading() {
- return Boolean(this.$apollo.queries.projects.loading);
+ queryVariables() {
+ return {
+ search: this.projectSearchQuery,
+ first: PROJECTS_PER_PAGE,
+ searchNamespaces: true,
+ sort: 'similarity',
+ };
+ },
+ isLoading() {
+ return this.$apollo.queries.projects.loading && !this.isLoadingMore;
},
projectDropdownText() {
return this.selectedProject?.nameWithNamespace || this.$options.i18n.selectProjectText;
},
projectList() {
- return (this.projects || []).map((project) => ({
+ return (this.projects?.nodes || []).map((project) => ({
...project,
text: project.nameWithNamespace,
value: String(project.id),
}));
},
+ hasNextPage() {
+ return this.projects?.pageInfo?.hasNextPage;
+ },
},
+
methods: {
findProjectById(id) {
- return this.projects.find((project) => id === project.id);
+ return this.projects?.nodes?.find((project) => id === project.id);
},
onProjectSelect(projectId) {
this.$emit('change', this.findProjectById(projectId));
@@ -77,13 +92,41 @@ export default {
onError({ message } = {}) {
this.$emit('error', { message });
},
+ async onBottomReached() {
+ if (!this.hasNextPage) return;
+
+ this.isLoadingMore = true;
+
+ try {
+ await this.$apollo.queries.projects.fetchMore({
+ variables: {
+ ...this.queryVariables,
+ after: this.projects.pageInfo?.endCursor,
+ },
+ updateQuery: (previousResult, { fetchMoreResult }) => {
+ return produce(fetchMoreResult, (draftData) => {
+ draftData.projects.nodes = [
+ ...previousResult.projects.nodes,
+ ...draftData.projects.nodes,
+ ];
+ });
+ },
+ });
+ } catch (error) {
+ this.onError({ message: __('Failed to load projects') });
+ } finally {
+ this.isLoadingMore = false;
+ }
+ },
onSearch: debounce(function debouncedSearch(query) {
this.projectSearchQuery = query;
}, 250),
},
+
i18n: {
selectProjectText: __('Select a project'),
},
+
AVATAR_SHAPE_OPTION_RECT,
};
</script>
@@ -97,8 +140,11 @@ export default {
:header-text="$options.i18n.selectProjectText"
:loading="initialProjectsLoading"
:searchable="true"
- :searching="projectsLoading"
+ :searching="isLoading"
fluid-width
+ infinite-scroll
+ :infinite-scroll-loading="isLoadingMore"
+ @bottom-reached="onBottomReached"
@search="onSearch"
@select="onProjectSelect"
>
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js
index d9ac0abf7b3..77986539403 100644
--- a/app/assets/javascripts/lib/utils/constants.js
+++ b/app/assets/javascripts/lib/utils/constants.js
@@ -19,10 +19,5 @@ export const DRAWER_Z_INDEX = 252;
export const MIN_USERNAME_LENGTH = 2;
-export const BYTES_FORMAT_BYTES = 'B';
-export const BYTES_FORMAT_KIB = 'KiB';
-export const BYTES_FORMAT_MIB = 'MiB';
-export const BYTES_FORMAT_GIB = 'GiB';
-
export const DEFAULT_CI_CONFIG_PATH = '.gitlab-ci.yml';
export const CI_CONFIG_PATH_EXTENSION = /(\.gitlab-ci\.yml)/;
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index d17719c0bc0..01c5bc1f1fc 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -1,12 +1,5 @@
import { sprintf, __ } from '~/locale';
-import {
- BYTES_IN_KIB,
- THOUSAND,
- BYTES_FORMAT_BYTES,
- BYTES_FORMAT_KIB,
- BYTES_FORMAT_MIB,
- BYTES_FORMAT_GIB,
-} from './constants';
+import { BYTES_IN_KIB, THOUSAND } from './constants';
/**
* Function that allows a number with an X amount of decimals
@@ -73,47 +66,47 @@ export function bytesToGiB(number) {
/**
* Formats the bytes in number into a more understandable
* representation. Returns an array with the first value being the human size
- * and the second value being the format (e.g., [1.5, 'KiB']).
+ * and the second value being the label (e.g., [1.5, 'KiB']).
*
- * @param {Number} size
- * @param {Number} digits - The number of digits to appear after the decimal point
- * @returns {String}
+ * @param {number} size
+ * @param {number} [digits=2] - The number of digits to appear after the decimal point
+ * @returns {string[]}
*/
export function numberToHumanSizeSplit(size, digits = 2) {
const abs = Math.abs(size);
if (abs < BYTES_IN_KIB) {
- return [size.toString(), BYTES_FORMAT_BYTES];
+ return [size.toString(), __('B')];
}
if (abs < BYTES_IN_KIB ** 2) {
- return [bytesToKiB(size).toFixed(digits), BYTES_FORMAT_KIB];
+ return [bytesToKiB(size).toFixed(digits), __('KiB')];
}
if (abs < BYTES_IN_KIB ** 3) {
- return [bytesToMiB(size).toFixed(digits), BYTES_FORMAT_MIB];
+ return [bytesToMiB(size).toFixed(digits), __('MiB')];
}
- return [bytesToGiB(size).toFixed(digits), BYTES_FORMAT_GIB];
+ return [bytesToGiB(size).toFixed(digits), __('GiB')];
}
/**
* Port of rails number_to_human_size
* Formats the bytes in number into a more understandable
- * representation (e.g., giving it 1500 yields 1.5 KB).
+ * representation (e.g., giving it 1536 yields 1.5 KiB).
*
- * @param {Number} size
- * @param {Number} digits - The number of digits to appear after the decimal point
- * @returns {String}
+ * @param {number} size
+ * @param {number} [digits=2] - The number of digits to appear after the decimal point
+ * @returns {string}
*/
export function numberToHumanSize(size, digits = 2) {
- const [humanSize, format] = numberToHumanSizeSplit(size, digits);
+ const [humanSize, label] = numberToHumanSizeSplit(size, digits);
- switch (format) {
- case BYTES_FORMAT_BYTES:
+ switch (label) {
+ case __('B'):
return sprintf(__('%{size} B'), { size: humanSize });
- case BYTES_FORMAT_KIB:
+ case __('KiB'):
return sprintf(__('%{size} KiB'), { size: humanSize });
- case BYTES_FORMAT_MIB:
+ case __('MiB'):
return sprintf(__('%{size} MiB'), { size: humanSize });
- case BYTES_FORMAT_GIB:
+ case __('GiB'):
return sprintf(__('%{size} GiB'), { size: humanSize });
default:
return '';
diff --git a/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
index 874803a720d..eb56113a4dd 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
@@ -1,6 +1,6 @@
<script>
// eslint-disable-next-line no-restricted-imports
-import { mapActions, mapState, mapGetters } from 'vuex';
+import { mapActions, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import eventHub from '~/super_sidebar/event_hub';
import NavItem from '~/super_sidebar/components/nav_item.vue';
@@ -15,15 +15,11 @@ export default {
NavItem,
},
computed: {
- ...mapState(['navigation', 'urlQuery']),
...mapGetters(['navigationItems']),
},
created() {
eventHub.$emit('toggle-menu-header', false);
-
- if (this.urlQuery?.search) {
- this.fetchSidebarCount();
- }
+ this.fetchSidebarCount();
},
methods: {
...mapActions(['fetchSidebarCount']),
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index 211bbaf82cd..d5e275b8a19 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -1,7 +1,13 @@
import Api from '~/api';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
-import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
+import {
+ visitUrl,
+ setUrlParams,
+ getBaseURL,
+ queryToObject,
+ objectToQuery,
+} from '~/lib/utils/url_utility';
import { logError } from '~/lib/logger';
import { __ } from '~/locale';
import { labelFilterData } from '~/search/sidebar/components/label_filter/data';
@@ -135,19 +141,38 @@ export const setLabelFilterSearch = ({ commit }, { value }) => {
commit(types.SET_LABEL_SEARCH_STRING, value);
};
+const injectWildCardSearch = (state, link) => {
+ const urlObject = new URL(`${getBaseURL()}${link}`);
+ if (!state.urlQuery.search) {
+ const queryObject = queryToObject(urlObject.search);
+ urlObject.search = objectToQuery({ ...queryObject, search: '*' });
+ }
+
+ return urlObject.href;
+};
+
export const fetchSidebarCount = ({ commit, state }) => {
- const promises = Object.values(state.navigation).map((navItem) => {
- // active nav item has count already so we skip it
- if (!navItem.active && navItem.count_link) {
- return axios
- .get(navItem.count_link)
- .then(({ data: { count } }) => {
- commit(types.RECEIVE_NAVIGATION_COUNT, { key: navItem.scope, count });
- })
- .catch((e) => logError(e));
- }
- return Promise.resolve();
- });
+ const items = Object.values(state.navigation)
+ .filter((navigationItem) => !navigationItem.active && navigationItem.count_link)
+ .map((navItem) => {
+ const navigationItem = { ...navItem };
+
+ if (navigationItem.count_link) {
+ navigationItem.count_link = injectWildCardSearch(state, navigationItem.count_link);
+ }
+
+ return navigationItem;
+ });
+
+ const promises = items.map((navigationItem) =>
+ axios
+ .get(navigationItem.count_link)
+ .then(({ data: { count } }) => {
+ commit(types.RECEIVE_NAVIGATION_COUNT, { key: navigationItem.scope, count });
+ })
+ .catch((e) => logError(e)),
+ );
+
return Promise.all(promises);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index a4afdee4d49..1aed3362c42 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -48,7 +48,7 @@ export default {
variables() {
return this.mergeRequestQueryVariables;
},
- update: (data) => data.project.mergeRequest,
+ update: (data) => data.project?.mergeRequest || {},
},
},
components: {
@@ -90,7 +90,7 @@ export default {
return this.state.rebaseInProgress;
},
canPushToSourceBranch() {
- return this.state.userPermissions.pushToSourceBranch;
+ return this.state.userPermissions?.pushToSourceBranch || false;
},
targetBranch() {
return this.state.targetBranch;
diff --git a/app/assets/stylesheets/page_bundles/login.scss b/app/assets/stylesheets/page_bundles/login.scss
index b63f199f7b9..4cc44b01e60 100644
--- a/app/assets/stylesheets/page_bundles/login.scss
+++ b/app/assets/stylesheets/page_bundles/login.scss
@@ -230,11 +230,8 @@
height: 100%;
body {
- padding-top: 48px; // Remove this line when the restyle_login_page feature flag is deleted. Instead, add self-align `center` to container, and maybe a top margin.
-
&.with-system-header {
padding-top: $system-header-height;
- padding-top: calc(#{$system-header-height} + 48px); // Remove this line when the restyle_login_page feature flag is deleted
}
&.with-system-footer {