summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-10 21:08:12 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-10 21:08:12 +0000
commitddfa6a1f19f1c6847d30314858f1d0ad21de13f9 (patch)
tree715fd181e594d7c6339d90eb8daaa45c962f2565 /app
parentf27a1b0faf16a83ba9c3f71f660262e368f4509a (diff)
downloadgitlab-ce-ddfa6a1f19f1c6847d30314858f1d0ad21de13f9.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue38
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js18
-rw-r--r--app/assets/javascripts/pages/projects/edit/index.js2
-rw-r--r--app/assets/javascripts/projects/commit/components/branches_dropdown.vue84
-rw-r--r--app/assets/javascripts/projects/commit/components/form_modal.vue7
-rw-r--r--app/assets/javascripts/projects/prune_objects_button.js23
-rw-r--r--app/assets/javascripts/projects/prune_unreachable_objects_button.vue75
-rw-r--r--app/controllers/projects_controller.rb8
-rw-r--r--app/services/packages/create_event_service.rb26
-rw-r--r--app/views/projects/edit.html.haml3
-rw-r--r--app/workers/concerns/git_garbage_collect_methods.rb7
11 files changed, 189 insertions, 102 deletions
diff --git a/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
index 1ec3f8da7c3..8dde3ac4e19 100644
--- a/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
@@ -162,22 +162,28 @@ export default {
</script>
<template>
- <div v-if="checkedCount" class="gl-my-4 gl-p-4 gl-border-1 gl-border-solid gl-border-gray-100">
- <div class="gl-display-flex gl-align-items-center">
- <div>
- <gl-sprintf :message="bannerMessage">
- <template #strong="{ content }">
- <strong>{{ content }}</strong>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-ml-auto">
- <gl-button variant="default" @click="onClearChecked">{{
- s__('Runners|Clear selection')
- }}</gl-button>
- <gl-button v-gl-modal="$options.BULK_DELETE_MODAL_ID" variant="danger">{{
- s__('Runners|Delete selected')
- }}</gl-button>
+ <div>
+ <div
+ v-if="checkedCount"
+ data-testid="runner-bulk-delete-banner"
+ class="gl-my-4 gl-p-4 gl-border-1 gl-border-solid gl-border-gray-100"
+ >
+ <div class="gl-display-flex gl-align-items-center">
+ <div>
+ <gl-sprintf :message="bannerMessage">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-ml-auto">
+ <gl-button variant="default" @click="onClearChecked">{{
+ s__('Runners|Clear selection')
+ }}</gl-button>
+ <gl-button v-gl-modal="$options.BULK_DELETE_MODAL_ID" variant="danger">{{
+ s__('Runners|Delete selected')
+ }}</gl-button>
+ </div>
</div>
</div>
<gl-modal
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 457a519d70e..9bf382c41e7 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -4,7 +4,7 @@
import { GlBreakpointInstance as breakpointInstance } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
-import { isFunction, defer, escape } from 'lodash';
+import { isFunction, defer, escape, partial, toLower } from 'lodash';
import Cookies from '~/lib/utils/cookies';
import { SCOPED_LABEL_DELIMITER } from '~/sidebar/components/labels/labels_select_widget/constants';
import { convertToCamelCase, convertToSnakeCase } from './text_utility';
@@ -552,6 +552,22 @@ export const convertObjectPropsToCamelCase = (obj = {}, options = {}) =>
convertObjectProps(convertToCamelCase, obj, options);
/**
+ * This method returns a new object with lowerCase property names
+ *
+ * Reasoning for this method is to ensure consistent access for some
+ * sort of objects
+ *
+ * This method also supports additional params in `options` object
+ *
+ * @param {Object} obj - Object to be converted.
+ * @param {Object} options - Object containing additional options.
+ * @param {boolean} options.deep - FLag to allow deep object converting
+ * @param {Array[]} options.dropKeys - List of properties to discard while building new object
+ * @param {Array[]} options.ignoreKeyNames - List of properties to leave intact while building new object
+ */
+export const convertObjectPropsToLowerCase = partial(convertObjectProps, toLower);
+
+/**
* Converts all the object keys to snake case
*
* This method also supports additional params in `options` object
diff --git a/app/assets/javascripts/pages/projects/edit/index.js b/app/assets/javascripts/pages/projects/edit/index.js
index 7d81ef30f2c..82035008459 100644
--- a/app/assets/javascripts/pages/projects/edit/index.js
+++ b/app/assets/javascripts/pages/projects/edit/index.js
@@ -11,6 +11,7 @@ import initSettingsPanels from '~/settings_panels';
import UserCallout from '~/user_callout';
import initTopicsTokenSelector from '~/projects/settings/topics';
import { initProjectSelects } from '~/vue_shared/components/entity_select/init_project_selects';
+import initPruneObjectsButton from '~/projects/prune_objects_button';
import initProjectPermissionsSettings from '../shared/permissions';
import initProjectLoadingSpinner from '../shared/save_project_loader';
@@ -18,6 +19,7 @@ initFilePickers();
initConfirmDanger();
initSettingsPanels();
initProjectDeleteButton();
+initPruneObjectsButton();
mountBadgeSettings(PROJECT_BADGE);
new UserCallout({ className: 'js-service-desk-callout' }); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
index a037e721677..0ed154c47dd 100644
--- a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
+++ b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
@@ -1,12 +1,7 @@
<script>
-import {
- GlDropdown,
- GlSearchBoxByType,
- GlDropdownItem,
- GlDropdownText,
- GlLoadingIcon,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
+import { debounce } from 'lodash';
import {
I18N_NO_RESULTS_MESSAGE,
I18N_BRANCH_HEADER,
@@ -16,11 +11,7 @@ import {
export default {
name: 'BranchesDropdown',
components: {
- GlDropdown,
- GlSearchBoxByType,
- GlDropdownItem,
- GlDropdownText,
- GlLoadingIcon,
+ GlCollapsibleListbox,
},
props: {
value: {
@@ -46,19 +37,17 @@ export default {
},
computed: {
...mapGetters(['joinedBranches']),
- ...mapState(['isFetching', 'branch', 'branches']),
- filteredResults() {
- const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
- return this.joinedBranches.filter((resultString) =>
- resultString.toLowerCase().includes(lowerCasedSearchTerm),
- );
+ ...mapState(['isFetching']),
+ listboxItems() {
+ return this.joinedBranches.map((value) => ({ value, text: value }));
},
},
watch: {
// Parent component can set the branch value (e.g. when the user selects a different project)
// and we need to keep the search term in sync with the selected value
value(val) {
- this.searchTermChanged(val);
+ this.searchTerm = val;
+ this.fetchBranches(this.searchTerm);
},
},
mounted() {
@@ -67,50 +56,29 @@ export default {
methods: {
...mapActions(['fetchBranches']),
selectBranch(branch) {
- this.$emit('selectBranch', branch);
- this.searchTerm = branch; // enables isSelected to work as expected
- },
- isSelected(selectedBranch) {
- return selectedBranch === this.branch;
+ this.$emit('input', branch);
},
+ debouncedSearch: debounce(function debouncedSearch() {
+ this.fetchBranches(this.searchTerm);
+ }, 250),
searchTermChanged(value) {
- this.searchTerm = value;
- this.fetchBranches(value);
+ this.searchTerm = value.trim();
+ this.debouncedSearch(value);
},
},
};
</script>
<template>
- <gl-dropdown :text="value" :header-text="$options.i18n.branchHeaderTitle">
- <gl-search-box-by-type
- :value="searchTerm"
- trim
- autocomplete="off"
- :debounce="250"
- :placeholder="$options.i18n.branchSearchPlaceholder"
- data-testid="dropdown-search-box"
- @input="searchTermChanged"
- />
- <gl-dropdown-item
- v-for="branch in filteredResults"
- v-show="!isFetching"
- :key="branch"
- :name="branch"
- :is-checked="isSelected(branch)"
- is-check-item
- data-testid="dropdown-item"
- @click="selectBranch(branch)"
- >
- {{ branch }}
- </gl-dropdown-item>
- <gl-dropdown-text v-show="isFetching" data-testid="dropdown-text-loading-icon">
- <gl-loading-icon size="sm" class="gl-mx-auto" />
- </gl-dropdown-text>
- <gl-dropdown-text
- v-if="!filteredResults.length && !isFetching"
- data-testid="empty-result-message"
- >
- <span class="gl-text-gray-500">{{ $options.i18n.noResultsMessage }}</span>
- </gl-dropdown-text>
- </gl-dropdown>
+ <gl-collapsible-listbox
+ :header-text="$options.i18n.branchHeaderTitle"
+ :toggle-text="value"
+ :items="listboxItems"
+ searchable
+ :search-placeholder="$options.i18n.branchSearchPlaceholder"
+ :searching="isFetching"
+ :selected="value"
+ :no-results-text="$options.i18n.noResultsMessage"
+ @search="searchTermChanged"
+ @select="selectBranch"
+ />
</template>
diff --git a/app/assets/javascripts/projects/commit/components/form_modal.vue b/app/assets/javascripts/projects/commit/components/form_modal.vue
index 921c66587c9..f78afef1c17 100644
--- a/app/assets/javascripts/projects/commit/components/form_modal.vue
+++ b/app/assets/javascripts/projects/commit/components/form_modal.vue
@@ -151,12 +151,7 @@ export default {
>
<input id="start_branch" type="hidden" name="start_branch" :value="branch" />
- <branches-dropdown
- class="gl-w-half"
- :value="branch"
- :blanked="isRevert"
- @selectBranch="setBranch"
- />
+ <branches-dropdown :value="branch" :blanked="isRevert" @input="setBranch" />
</gl-form-group>
<gl-form-checkbox
diff --git a/app/assets/javascripts/projects/prune_objects_button.js b/app/assets/javascripts/projects/prune_objects_button.js
new file mode 100644
index 00000000000..dba73f6a19d
--- /dev/null
+++ b/app/assets/javascripts/projects/prune_objects_button.js
@@ -0,0 +1,23 @@
+import Vue from 'vue';
+import PruneUnreachableObjectsButton from './prune_unreachable_objects_button.vue';
+
+export default (selector = '#js-project-prune-unreachable-objects-button') => {
+ const el = document.querySelector(selector);
+
+ if (!el) return;
+
+ const { pruneObjectsPath, pruneObjectsDocPath } = el.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ render(createElement) {
+ return createElement(PruneUnreachableObjectsButton, {
+ props: {
+ pruneObjectsPath,
+ pruneObjectsDocPath,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/projects/prune_unreachable_objects_button.vue b/app/assets/javascripts/projects/prune_unreachable_objects_button.vue
new file mode 100644
index 00000000000..1387fbb78c0
--- /dev/null
+++ b/app/assets/javascripts/projects/prune_unreachable_objects_button.vue
@@ -0,0 +1,75 @@
+<script>
+import { GlButton, GlLink, GlModal, GlModalDirective } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { s__ } from '~/locale';
+
+export default {
+ components: {
+ GlButton,
+ GlLink,
+ GlModal,
+ },
+ PRUNE_UNREACHABLE_OBJECTS_MODAL_ID: 'prune-objects-modal',
+ MODAL_ACTION_PRIMARY: {
+ text: s__('UpdateProject|Prune'),
+ attributes: [{ variant: 'danger' }],
+ },
+ MODAL_ACTION_CANCEL: {
+ text: s__('UpdateProject|Cancel'),
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ props: {
+ pruneObjectsPath: {
+ type: String,
+ required: true,
+ },
+ pruneObjectsDocPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ csrfToken() {
+ return csrf.token;
+ },
+ },
+ methods: {
+ submitForm() {
+ this.$refs.form.submit();
+ },
+ },
+};
+</script>
+
+<template>
+ <form ref="form" :action="pruneObjectsPath" method="post">
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
+ <input value="true" type="hidden" name="prune" />
+ <gl-modal
+ :modal-id="$options.PRUNE_UNREACHABLE_OBJECTS_MODAL_ID"
+ :title="s__('UpdateProject|Are you sure you want to prune unreachable objects?')"
+ :action-primary="$options.MODAL_ACTION_PRIMARY"
+ :action-cancel="$options.MODAL_ACTION_CANCEL"
+ size="sm"
+ :no-focus-on-show="true"
+ @ok="submitForm"
+ >
+ <p>
+ {{ s__('UpdateProject|Pruning unreachable objects can lead to repository corruption.') }}
+ <gl-link :href="pruneObjectsDocPath" target="_blank">
+ {{ s__('UpdateProject|Learn more.') }}
+ </gl-link>
+ {{ s__('UpdateProject|Are you sure you want to prune?') }}
+ </p>
+ </gl-modal>
+ <gl-button
+ v-gl-modal="$options.PRUNE_UNREACHABLE_OBJECTS_MODAL_ID"
+ category="primary"
+ variant="danger"
+ >
+ {{ s__('UpdateProject|Prune unreachable objects') }}
+ </gl-button>
+ </form>
+</template>
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index c5306d16bc7..0338c912b53 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -222,7 +222,13 @@ class ProjectsController < Projects::ApplicationController
end
def housekeeping
- ::Repositories::HousekeepingService.new(@project, :eager).execute
+ task = if params[:prune].present?
+ :prune
+ else
+ :eager
+ end
+
+ ::Repositories::HousekeepingService.new(@project, task).execute
redirect_to(
project_path(@project),
diff --git a/app/services/packages/create_event_service.rb b/app/services/packages/create_event_service.rb
index 8fed6e2def8..82c4292fca8 100644
--- a/app/services/packages/create_event_service.rb
+++ b/app/services/packages/create_event_service.rb
@@ -21,6 +21,17 @@ module Packages
end
end
+ def originator_type
+ case current_user
+ when User
+ :user
+ when DeployToken
+ :deploy_token
+ else
+ :guest
+ end
+ end
+
private
def event_scope
@@ -34,20 +45,5 @@ module Packages
def event_name
params[:event_name]
end
-
- def originator_type
- case current_user
- when User
- :user
- when DeployToken
- :deploy_token
- else
- :guest
- end
- end
-
- def guest?
- originator_type == :guest
- end
end
end
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index e9335762577..e87005434e4 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -74,6 +74,9 @@
= link_to _('Run housekeeping'), housekeeping_project_path(@project),
method: :post, class: "btn gl-button btn-default"
+ .gl-display-inline-flex
+ #js-project-prune-unreachable-objects-button{ data: { prune_objects_path: housekeeping_project_path(@project, prune: true), prune_objects_doc_path: help_page_path('administration/housekeeping', anchor: 'prune-unreachable-objects') } }
+
= render 'export', project: @project
= render_if_exists 'projects/settings/archive'
diff --git a/app/workers/concerns/git_garbage_collect_methods.rb b/app/workers/concerns/git_garbage_collect_methods.rb
index de3796f7e43..718031ec33e 100644
--- a/app/workers/concerns/git_garbage_collect_methods.rb
+++ b/app/workers/concerns/git_garbage_collect_methods.rb
@@ -84,13 +84,10 @@ module GitGarbageCollectMethods
repository = resource.repository.raw_repository
client = repository.gitaly_repository_client
- case task
- when :prune
+ if task == :prune
client.prune_unreachable_objects
- when :eager
- client.optimize_repository(eager: true)
else
- client.optimize_repository
+ client.optimize_repository(eager: task == :eager)
end
rescue GRPC::NotFound => e
Gitlab::GitLogger.error("#{__method__} failed:\nRepository not found")