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-02-14 03:10:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-14 03:10:09 +0300
commit8aea332821a78e83ce93f5b3bac7de5f95a3c7b8 (patch)
tree722cb345de067f3b62bbe0f849178c74dec657eb /app
parent4f4b85e1c7f7a5518f12a6981709cf3ef3f0f653 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/select2-spinner.gifbin1849 -> 0 bytes
-rw-r--r--app/assets/images/select2.pngbin613 -> 0 bytes
-rw-r--r--app/assets/images/select2x2.pngbin845 -> 0 bytes
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue2
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/constants.js2
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/components/ml_experiments_index.vue85
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/constants.js17
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/index.js3
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/translations.js11
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/table/admin_jobs_table_app.vue19
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/index.js27
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js2
-rw-r--r--app/assets/javascripts/pages/dashboard/merge_requests/index.js2
-rw-r--r--app/assets/javascripts/pages/dashboard/milestones/index/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/edit/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/merge_requests/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/ml/experiments/index/index.js24
-rw-r--r--app/assets/javascripts/pages/projects/project.js8
-rw-r--r--app/assets/javascripts/project_select.js128
-rw-r--r--app/assets/javascripts/project_select_combo_button.js122
-rw-r--r--app/assets/stylesheets/framework/common.scss6
-rw-r--r--app/assets/stylesheets/framework/header.scss5
-rw-r--r--app/assets/stylesheets/framework/secondary_navigation_elements.scss15
-rw-r--r--app/assets/stylesheets/framework/variables.scss6
-rw-r--r--app/assets/stylesheets/lazy_bundles/select2.scss654
-rw-r--r--app/assets/stylesheets/lazy_bundles/select2_overrides.scss341
-rw-r--r--app/assets/stylesheets/pages/issues.scss6
-rw-r--r--app/controllers/admin/jobs_controller.rb4
-rw-r--r--app/controllers/projects/ml/experiments_controller.rb7
-rw-r--r--app/helpers/projects/ml/experiments_helper.rb20
-rw-r--r--app/helpers/selects_helper.rb35
-rw-r--r--app/services/export_csv/base_service.rb18
-rw-r--r--app/services/export_csv/map_export_fields_service.rb40
-rw-r--r--app/services/work_items/export_csv_service.rb26
-rw-r--r--app/views/admin/jobs/index.html.haml34
-rw-r--r--app/views/projects/ml/experiments/index.html.haml16
-rw-r--r--app/views/shared/_new_project_item_select.html.haml9
38 files changed, 317 insertions, 1386 deletions
diff --git a/app/assets/images/select2-spinner.gif b/app/assets/images/select2-spinner.gif
deleted file mode 100644
index 5b33f7e54f4..00000000000
--- a/app/assets/images/select2-spinner.gif
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/select2.png b/app/assets/images/select2.png
deleted file mode 100644
index 1d804ffb996..00000000000
--- a/app/assets/images/select2.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/select2x2.png b/app/assets/images/select2x2.png
deleted file mode 100644
index 4bdd5c961d4..00000000000
--- a/app/assets/images/select2x2.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
index b13f7dae2c2..1d6a06a08dc 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
@@ -453,7 +453,7 @@ export default {
data-testid="aws-guidance-tip"
@dismiss="dismissTip"
>
- <div class="gl-display-flex gl-flex-direction-row gl-flex-wrap-wrap gl-md-flex-wrap-nowrap">
+ <div class="gl-display-flex gl-flex-direction-row gl-md-flex-wrap-nowraps gl-gap-3">
<div>
<p>
<gl-sprintf :message="$options.i18n.awsTipMessage">
diff --git a/app/assets/javascripts/ml/experiment_tracking/constants.js b/app/assets/javascripts/ml/experiment_tracking/constants.js
index 4092180b988..15462b519e1 100644
--- a/app/assets/javascripts/ml/experiment_tracking/constants.js
+++ b/app/assets/javascripts/ml/experiment_tracking/constants.js
@@ -15,6 +15,8 @@ export const BASE_SORT_FIELDS = Object.freeze([
},
]);
+export const EMPTY_STATE_SVG = '/assets/illustrations/empty-state/empty-dag-md.svg';
+
export const FEATURE_NAME = s__('MlExperimentTracking|Machine learning experiment tracking');
export const FEATURE_FEEDBACK_ISSUE = 'https://gitlab.com/gitlab-org/gitlab/-/issues/381660';
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/components/ml_experiments_index.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/components/ml_experiments_index.vue
new file mode 100644
index 00000000000..4f2b8db3c00
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/components/ml_experiments_index.vue
@@ -0,0 +1,85 @@
+<script>
+import { GlTableLite, GlEmptyState, GlLink } from '@gitlab/ui';
+import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
+import Pagination from '~/vue_shared/components/incubation/pagination.vue';
+import {
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+ EMPTY_STATE_SVG,
+} from '~/ml/experiment_tracking/constants';
+import * as constants from '~/ml/experiment_tracking/routes/experiments/index/constants';
+import * as translations from '~/ml/experiment_tracking/routes/experiments/index/translations';
+
+export default {
+ name: 'MlExperimentsIndexApp',
+ components: {
+ Pagination,
+ IncubationAlert,
+ GlTableLite,
+ GlEmptyState,
+ GlLink,
+ },
+ props: {
+ experiments: {
+ type: Array,
+ required: true,
+ },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ tableFields: constants.EXPERIMENTS_TABLE_FIELDS,
+ i18n: translations,
+ computed: {
+ hasExperiments() {
+ return this.experiments.length > 0;
+ },
+ tableItems() {
+ return this.experiments.map((exp) => ({
+ nameColumn: { name: exp.name, path: exp.path },
+ candidateCountColumn: exp.candidate_count,
+ }));
+ },
+ },
+ constants: {
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+ EMPTY_STATE_SVG,
+ ...constants,
+ },
+};
+</script>
+
+<template>
+ <div v-if="hasExperiments">
+ <h1 class="page-title gl-font-size-h-display">
+ {{ $options.i18n.TITLE_LABEL }}
+ </h1>
+
+ <incubation-alert
+ :feature-name="$options.constants.FEATURE_NAME"
+ :link-to-feedback-issue="$options.constants.FEATURE_FEEDBACK_ISSUE"
+ />
+
+ <gl-table-lite :items="tableItems" :fields="$options.tableFields">
+ <template #cell(nameColumn)="data">
+ <gl-link :href="data.value.path">
+ {{ data.value.name }}
+ </gl-link>
+ </template>
+ </gl-table-lite>
+
+ <pagination v-if="hasExperiments" v-bind="pageInfo" />
+ </div>
+
+ <gl-empty-state
+ v-else
+ :title="$options.i18n.EMPTY_STATE_TITLE_LABEL"
+ :primary-button-text="$options.i18n.CREATE_NEW_LABEL"
+ :primary-button-link="$options.constants.CREATE_EXPERIMENT_HELP_PATH"
+ :svg-path="$options.constants.EMPTY_STATE_SVG"
+ :description="$options.i18n.EMPTY_STATE_DESCRIPTION_LABEL"
+ class="gl-py-8"
+ />
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/constants.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/constants.js
new file mode 100644
index 00000000000..3026bce0972
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/constants.js
@@ -0,0 +1,17 @@
+import { s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+
+export const CREATE_EXPERIMENT_HELP_PATH = helpPagePath(
+ 'user/project/ml/experiment_tracking/index.md',
+ {
+ anchor: 'tracking-new-experiments-and-trials',
+ },
+);
+
+export const EXPERIMENTS_TABLE_FIELDS = Object.freeze([
+ { key: 'nameColumn', label: s__('MlExperimentTracking|Experiment') },
+ {
+ key: 'candidateCountColumn',
+ label: s__('MlExperimentTracking|Logged candidates for experiment'),
+ },
+]);
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/index.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/index.js
new file mode 100644
index 00000000000..b40735ebe22
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/index.js
@@ -0,0 +1,3 @@
+import MlExperimentsIndex from './components/ml_experiments_index.vue';
+
+export default MlExperimentsIndex;
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/translations.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/translations.js
new file mode 100644
index 00000000000..e954c054cf5
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/index/translations.js
@@ -0,0 +1,11 @@
+import { s__ } from '~/locale';
+
+export const TITLE_LABEL = s__('MlExperimentTracking|Model experiments');
+
+export const CREATE_NEW_LABEL = s__('MlExperimentTracking|Create a new experiment');
+
+export const EMPTY_STATE_TITLE_LABEL = s__('MlExperimentTracking|No experiments');
+
+export const EMPTY_STATE_DESCRIPTION_LABEL = s__(
+ 'MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client.',
+);
diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js
index f1e92cf195a..366be334e87 100644
--- a/app/assets/javascripts/pages/admin/application_settings/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/index.js
@@ -1,5 +1,4 @@
import initVariableList from '~/ci/ci_variable_list';
-import projectSelect from '~/project_select';
import initSearchSettings from '~/search_settings';
import selfMonitor from '~/self_monitor';
import initSettingsPanels from '~/settings_panels';
@@ -8,5 +7,4 @@ initVariableList('js-instance-variables');
selfMonitor();
// Initialize expandable settings panels
initSettingsPanels();
-projectSelect();
initSearchSettings();
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/table/admin_jobs_table_app.vue b/app/assets/javascripts/pages/admin/jobs/index/components/table/admin_jobs_table_app.vue
new file mode 100644
index 00000000000..c5a0509b625
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/table/admin_jobs_table_app.vue
@@ -0,0 +1,19 @@
+<script>
+export default {
+ inject: {
+ jobStatuses: {
+ default: null,
+ },
+ url: {
+ default: '',
+ },
+ emptyStateSvgPath: {
+ default: '',
+ },
+ },
+};
+</script>
+
+<template>
+ <div>{{ __('Jobs') }}</div>
+</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/index/index.js b/app/assets/javascripts/pages/admin/jobs/index/index.js
index f9bc097da4c..9df52557212 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/index.js
+++ b/app/assets/javascripts/pages/admin/jobs/index/index.js
@@ -3,6 +3,7 @@ import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
import { CANCEL_JOBS_MODAL_ID } from './components/constants';
import CancelJobsModal from './components/cancel_jobs_modal.vue';
+import AdminJobsTableApp from './components/table/admin_jobs_table_app.vue';
Vue.use(Translate);
@@ -34,4 +35,28 @@ function initJobs() {
}
}
-initJobs();
+export function initAdminJobsApp() {
+ const containerEl = document.getElementById('admin-jobs-app');
+
+ if (!containerEl) return false;
+
+ const { jobStatuses, emptyStateSvgPath, url } = containerEl.dataset;
+
+ return new Vue({
+ el: containerEl,
+ provide: {
+ url,
+ emptyStateSvgPath,
+ jobStatuses: JSON.parse(jobStatuses),
+ },
+ render(createElement) {
+ return createElement(AdminJobsTableApp);
+ },
+ });
+}
+
+if (gon.features.adminJobsVue) {
+ initAdminJobsApp();
+} else {
+ initJobs();
+}
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index 659982fcc3a..2ca11e96f69 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -3,7 +3,6 @@ import { mountIssuesDashboardApp } from '~/issues/dashboard';
import initManualOrdering from '~/issues/manual_ordering';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
-import projectSelect from '~/project_select';
import { initNewResourceDropdown } from '~/vue_shared/components/new_resource_dropdown/init_new_resource_dropdown';
initFilteredSearch({
@@ -12,7 +11,6 @@ initFilteredSearch({
useDefaultState: true,
});
-projectSelect();
initNewResourceDropdown();
initManualOrdering();
diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
index f86dc2e2e30..a8c59ea6f3d 100644
--- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js
+++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
@@ -2,7 +2,6 @@ import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
-import projectSelect from '~/project_select';
import { initNewResourceDropdown } from '~/vue_shared/components/new_resource_dropdown/init_new_resource_dropdown';
import { RESOURCE_TYPE_MERGE_REQUEST } from '~/vue_shared/components/new_resource_dropdown/constants';
import searchUserProjectsWithMergeRequestsEnabled from '~/vue_shared/components/new_resource_dropdown/graphql/search_user_projects_with_merge_requests_enabled.query.graphql';
@@ -15,7 +14,6 @@ initFilteredSearch({
useDefaultState: true,
});
-projectSelect();
initNewResourceDropdown({
resourceType: RESOURCE_TYPE_MERGE_REQUEST,
query: searchUserProjectsWithMergeRequestsEnabled,
diff --git a/app/assets/javascripts/pages/dashboard/milestones/index/index.js b/app/assets/javascripts/pages/dashboard/milestones/index/index.js
index 951941cc83d..88061d9ca22 100644
--- a/app/assets/javascripts/pages/dashboard/milestones/index/index.js
+++ b/app/assets/javascripts/pages/dashboard/milestones/index/index.js
@@ -1,9 +1,7 @@
-import projectSelect from '~/project_select';
import { initNewResourceDropdown } from '~/vue_shared/components/new_resource_dropdown/init_new_resource_dropdown';
import { RESOURCE_TYPE_MILESTONE } from '~/vue_shared/components/new_resource_dropdown/constants';
import searchUserGroupsAndProjects from '~/vue_shared/components/new_resource_dropdown/graphql/search_user_groups_and_projects.query.graphql';
-projectSelect();
initNewResourceDropdown({
resourceType: RESOURCE_TYPE_MILESTONE,
query: searchUserGroupsAndProjects,
diff --git a/app/assets/javascripts/pages/groups/edit/index.js b/app/assets/javascripts/pages/groups/edit/index.js
index 91a0ef07bc4..dec06fe6f4d 100644
--- a/app/assets/javascripts/pages/groups/edit/index.js
+++ b/app/assets/javascripts/pages/groups/edit/index.js
@@ -6,7 +6,6 @@ import { initGroupSelects } from '~/vue_shared/components/entity_select/init_gro
import { initProjectSelects } from '~/vue_shared/components/entity_select/init_project_selects';
import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
-import projectSelect from '~/project_select';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
import initConfirmDanger from '~/init_confirm_danger';
@@ -26,7 +25,5 @@ initGroupSelects();
// Initialize project selectors
initProjectSelects();
-projectSelect();
-
initSearchSettings();
initCascadingSettingsLockPopovers();
diff --git a/app/assets/javascripts/pages/groups/merge_requests/index.js b/app/assets/javascripts/pages/groups/merge_requests/index.js
index 40b4c289ab0..2cf75fcf666 100644
--- a/app/assets/javascripts/pages/groups/merge_requests/index.js
+++ b/app/assets/javascripts/pages/groups/merge_requests/index.js
@@ -3,7 +3,6 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import { initBulkUpdateSidebar } from '~/issuable';
import initFilteredSearch from '~/pages/search/init_filtered_search';
-import projectSelect from '~/project_select';
import { initNewResourceDropdown } from '~/vue_shared/components/new_resource_dropdown/init_new_resource_dropdown';
import { RESOURCE_TYPE_MERGE_REQUEST } from '~/vue_shared/components/new_resource_dropdown/constants';
import searchUserGroupProjectsWithMergeRequestsEnabled from '~/vue_shared/components/new_resource_dropdown/graphql/search_user_group_projects_with_merge_requests_enabled.query.graphql';
@@ -19,7 +18,6 @@ initFilteredSearch({
useDefaultState: true,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
-projectSelect();
initNewResourceDropdown({
resourceType: RESOURCE_TYPE_MERGE_REQUEST,
query: searchUserGroupProjectsWithMergeRequestsEnabled,
diff --git a/app/assets/javascripts/pages/projects/ml/experiments/index/index.js b/app/assets/javascripts/pages/projects/ml/experiments/index/index.js
new file mode 100644
index 00000000000..e9ffd4b528b
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/ml/experiments/index/index.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import MlExperimentsIndex from '~/ml/experiment_tracking/routes/experiments/index';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+const initIndexMlExperiments = () => {
+ const element = document.querySelector('#js-project-ml-experiments-index');
+ if (!element) {
+ return undefined;
+ }
+
+ const props = {
+ experiments: JSON.parse(element.dataset.experiments),
+ pageInfo: convertObjectPropsToCamelCase(JSON.parse(element.dataset.pageInfo)),
+ };
+
+ return new Vue({
+ el: element,
+ render(h) {
+ return h(MlExperimentsIndex, { props });
+ },
+ });
+};
+
+initIndexMlExperiments();
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 4c9eb830ff6..5773737c41b 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -9,7 +9,6 @@ import axios from '~/lib/utils/axios_utils';
import { serializeForm } from '~/lib/utils/forms';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
-import projectSelect from '~/project_select';
const BRANCH_REF_TYPE = 'heads';
const TAG_REF_TYPE = 'tags';
@@ -44,13 +43,6 @@ export default class Project {
$(this).parents('.auto-devops-implicitly-enabled-banner').remove();
return e.preventDefault();
});
-
- Project.projectSelectDropdown();
- }
-
- static projectSelectDropdown() {
- projectSelect();
- $('.project-item-select').on('click', (e) => Project.changeProject($(e.currentTarget).val()));
}
static changeProject(url) {
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
deleted file mode 100644
index 705234537a8..00000000000
--- a/app/assets/javascripts/project_select.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/* eslint-disable func-names */
-
-import $ from 'jquery';
-import { createAlert } from '~/flash';
-import Api from './api';
-import { loadCSSFile } from './lib/utils/css_utils';
-import { s__ } from './locale';
-import ProjectSelectComboButton from './project_select_combo_button';
-
-const projectSelect = async () => {
- await loadCSSFile(gon.select2_css_path);
-
- $('.ajax-project-select').each(function (i, select) {
- let placeholder;
- const simpleFilter = $(select).data('simpleFilter') || false;
- const isInstantiated = $(select).data('select2');
- this.groupId = $(select).data('groupId');
- this.userId = $(select).data('userId');
- this.includeGroups = $(select).data('includeGroups');
- this.allProjects = $(select).data('allProjects') || false;
- this.orderBy = $(select).data('orderBy') || 'id';
- this.withIssuesEnabled = $(select).data('withIssuesEnabled');
- this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
- this.withShared =
- $(select).data('withShared') === undefined ? true : $(select).data('withShared');
- this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false;
- this.allowClear = $(select).data('allowClear') || false;
-
- placeholder = s__('ProjectSelect|Search for project');
- if (this.includeGroups) {
- placeholder += s__('ProjectSelect| or group');
- }
-
- $(select).select2({
- placeholder,
- minimumInputLength: 0,
- query: (query) => {
- let projectsCallback;
- const finalCallback = function (projects) {
- const data = {
- results: projects,
- };
- return query.callback(data);
- };
- if (this.includeGroups) {
- projectsCallback = function (projects) {
- const groupsCallback = function (groups) {
- const data = groups.concat(projects);
- return finalCallback(data);
- };
- return Api.groups(query.term, {}, groupsCallback);
- };
- } else {
- projectsCallback = finalCallback;
- }
- if (this.groupId) {
- return Api.groupProjects(
- this.groupId,
- query.term,
- {
- with_issues_enabled: this.withIssuesEnabled,
- with_merge_requests_enabled: this.withMergeRequestsEnabled,
- with_shared: this.withShared,
- include_subgroups: this.includeProjectsInSubgroups,
- order_by: 'similarity',
- simple: true,
- },
- projectsCallback,
- ).catch(() => {
- createAlert({
- message: s__('ProjectSelect|Something went wrong while fetching projects'),
- });
- });
- } else if (this.userId) {
- return Api.userProjects(
- this.userId,
- query.term,
- {
- with_issues_enabled: this.withIssuesEnabled,
- with_merge_requests_enabled: this.withMergeRequestsEnabled,
- with_shared: this.withShared,
- include_subgroups: this.includeProjectsInSubgroups,
- },
- projectsCallback,
- );
- }
- return Api.projects(
- query.term,
- {
- order_by: this.orderBy,
- with_issues_enabled: this.withIssuesEnabled,
- with_merge_requests_enabled: this.withMergeRequestsEnabled,
- membership: !this.allProjects,
- },
- projectsCallback,
- );
- },
- id(project) {
- if (simpleFilter) return project.id;
- return JSON.stringify({
- name: project.name,
- url: project.web_url,
- });
- },
- text(project) {
- return project.name_with_namespace || project.name;
- },
-
- initSelection(el, callback) {
- return Api.project(el.val()).then(({ data }) => callback(data));
- },
-
- allowClear: this.allowClear,
-
- dropdownCssClass: 'ajax-project-dropdown',
- });
- if (isInstantiated || simpleFilter) return select;
- return new ProjectSelectComboButton(select);
- });
-};
-
-export default () => {
- if ($('.ajax-project-select').length) {
- import(/* webpackChunkName: 'select2' */ 'select2/select2')
- .then(projectSelect)
- .catch(() => {});
- }
-};
diff --git a/app/assets/javascripts/project_select_combo_button.js b/app/assets/javascripts/project_select_combo_button.js
deleted file mode 100644
index ad80032c551..00000000000
--- a/app/assets/javascripts/project_select_combo_button.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import $ from 'jquery';
-import { sprintf, __ } from '~/locale';
-import { sanitizeUrl } from '~/lib/utils/url_utility';
-import AccessorUtilities from './lib/utils/accessor';
-import { loadCSSFile } from './lib/utils/css_utils';
-
-export default class ProjectSelectComboButton {
- constructor(select) {
- this.projectSelectInput = $(select);
- this.newItemBtn = $('.js-new-project-item-link');
- this.resourceType = this.newItemBtn.data('type');
- this.resourceLabel = this.newItemBtn.data('label');
- this.formattedText = this.deriveTextVariants();
- this.groupId = this.projectSelectInput.data('groupId');
- this.bindEvents();
- this.initLocalStorage();
- }
-
- bindEvents() {
- this.projectSelectInput
- .siblings('.new-project-item-select-button')
- .on('click', (e) => this.openDropdown(e));
-
- this.newItemBtn.on('click', (e) => {
- if (!this.getProjectFromLocalStorage()) {
- e.preventDefault();
- this.openDropdown(e);
- }
- });
-
- this.projectSelectInput.on('change', () => this.selectProject());
- }
-
- initLocalStorage() {
- const localStorageIsSafe = AccessorUtilities.canUseLocalStorage();
-
- if (localStorageIsSafe) {
- this.localStorageKey = [
- 'group',
- this.groupId,
- this.formattedText.localStorageItemType,
- 'recent-project',
- ].join('-');
- this.setBtnTextFromLocalStorage();
- }
- }
-
- // eslint-disable-next-line class-methods-use-this
- openDropdown(event) {
- import(/* webpackChunkName: 'select2' */ 'select2/select2')
- .then(() => {
- // eslint-disable-next-line promise/no-nesting
- loadCSSFile(gon.select2_css_path)
- .then(() => {
- $(event.currentTarget).siblings('.project-item-select').select2('open');
- })
- .catch(() => {});
- })
- .catch(() => {});
- }
-
- selectProject() {
- const selectedProjectData = JSON.parse(this.projectSelectInput.val());
- const projectUrl = `${selectedProjectData.url}/${this.projectSelectInput.data('relativePath')}`;
- const projectName = selectedProjectData.name;
-
- const projectMeta = {
- url: projectUrl,
- name: projectName,
- };
-
- this.setNewItemBtnAttributes(projectMeta);
- this.setProjectInLocalStorage(projectMeta);
- }
-
- setBtnTextFromLocalStorage() {
- const cachedProjectData = this.getProjectFromLocalStorage();
-
- this.setNewItemBtnAttributes(cachedProjectData);
- }
-
- setNewItemBtnAttributes(project) {
- if (project) {
- this.newItemBtn.attr('href', sanitizeUrl(project.url));
- this.newItemBtn.text(
- sprintf(__('New %{type} in %{project}'), {
- type: this.resourceLabel,
- project: project.name,
- }),
- );
- } else {
- this.newItemBtn.text(
- sprintf(__('Select project to create %{type}'), {
- type: this.formattedText.presetTextSuffix,
- }),
- );
- }
- }
-
- getProjectFromLocalStorage() {
- const projectString = localStorage.getItem(this.localStorageKey);
-
- return JSON.parse(projectString);
- }
-
- setProjectInLocalStorage(projectMeta) {
- const projectString = JSON.stringify(projectMeta);
-
- localStorage.setItem(this.localStorageKey, projectString);
- }
-
- deriveTextVariants() {
- // the trailing slice call depluralizes each of these strings (e.g. new-issues -> new-issue)
- const localStorageItemType = `new-${this.resourceType.split('_').join('-').slice(0, -1)}`;
- const presetTextSuffix = this.resourceType.split('_').join(' ').slice(0, -1);
-
- return {
- localStorageItemType, // new-issue / new-merge-request
- presetTextSuffix, // issue / merge request
- };
- }
-}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 0bc920b1f73..cc7a45e1c82 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -301,12 +301,6 @@ img.emoji {
height: 4px;
}
-.project-item-select-holder {
- .project-item-select {
- min-width: 250px;
- }
-}
-
.gl-accessibility {
&:focus {
display: flex;
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index a131ab667e1..7baf84198e4 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -63,11 +63,6 @@ $search-input-field-x-min-width: 200px;
@include gl-focus($focus-ring: $focus-ring-dark);
}
}
-
- .project-item-select {
- right: auto;
- left: 0;
- }
}
.dropdown.open {
diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
index 7e0a601223d..5ba0b1d0828 100644
--- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss
+++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
@@ -179,11 +179,6 @@
display: inline-block;
}
- .project-item-select-holder {
- margin: 0;
- width: 100%;
- }
-
&.inline {
display: flex;
flex-flow: row wrap;
@@ -367,13 +362,3 @@
}
}
}
-
-.project-item-select-holder.btn-group {
- .new-project-item-select-button {
- max-width: 32px;
- }
-}
-
-.empty-state .project-item-select-holder.btn-group {
- max-width: 320px;
-}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index f136a8c3a08..c616915073e 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -788,12 +788,6 @@ $stat-graph-selection-fill: #333;
$stat-graph-selection-stroke: #333;
/*
-* Selects
-*/
-$select2-drop-shadow1: rgba(76, 86, 103, 0.247059);
-$select2-drop-shadow2: rgba(31, 37, 50, 0.317647);
-
-/*
* Typography
*/
$body-text-shadow: rgba(255, 255, 255, 0.01);
diff --git a/app/assets/stylesheets/lazy_bundles/select2.scss b/app/assets/stylesheets/lazy_bundles/select2.scss
deleted file mode 100644
index f2c372020ef..00000000000
--- a/app/assets/stylesheets/lazy_bundles/select2.scss
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
-Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
-Updated 2020-10-05 by TimZ
-*/
-.select2-container {
- margin: 0;
- position: relative;
- display: inline-block;
-}
-
-.select2-container,
-.select2-drop,
-.select2-search,
-.select2-search input {
- box-sizing: border-box;
-}
-
-.select2-container .select2-choice {
- display: block;
- height: 26px;
- padding: 0 0 0 8px;
- overflow: hidden;
- position: relative;
-
- border: 1px solid #aaa;
- white-space: nowrap;
- line-height: 26px;
- color: #444;
- text-decoration: none;
-
- border-radius: 4px;
-
- background-clip: padding-box;
-
- user-select: none;
-
- background-color: #fff;
- background-image: linear-gradient(to top, #eee 0%, #fff 50%);
-}
-
-html[dir='rtl'] .select2-container .select2-choice {
- padding: 0 8px 0 0;
-}
-
-.select2-container.select2-drop-above .select2-choice {
- border-bottom-color: #aaa;
-
- border-radius: 0 0 4px 4px;
-
- background-image: linear-gradient(to bottom, #eee 0%, #fff 90%);
-}
-
-.select2-container.select2-allowclear .select2-choice .select2-chosen {
- margin-right: 42px;
-}
-
-.select2-container .select2-choice > .select2-chosen {
- margin-right: 26px;
- display: block;
- overflow: hidden;
-
- white-space: nowrap;
-
- text-overflow: ellipsis;
- float: none;
- width: auto;
-}
-
-html[dir='rtl'] .select2-container .select2-choice > .select2-chosen {
- margin-left: 26px;
- margin-right: 0;
-}
-
-.select2-container .select2-choice abbr {
- display: none;
- width: 12px;
- height: 12px;
- position: absolute;
- right: 24px;
- top: 8px;
-
- font-size: 1px;
- text-decoration: none;
-
- border: 0;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path('select2.png')) right top no-repeat;
- cursor: pointer;
- outline: 0;
-}
-
-.select2-container.select2-allowclear .select2-choice abbr {
- display: inline-block;
-}
-
-.select2-container .select2-choice abbr:hover {
- background-position: right -11px;
- cursor: pointer;
-}
-
-.select2-drop-mask {
- border: 0;
- margin: 0;
- padding: 0;
- position: fixed;
- left: 0;
- top: 0;
- min-height: 100%;
- min-width: 100%;
- height: auto;
- width: auto;
- opacity: 0;
- z-index: 9998;
- /* styles required for IE to work */
- background-color: #fff;
- filter: alpha(opacity=0);
-}
-
-.select2-drop {
- width: 100%;
- margin-top: -1px;
- position: absolute;
- z-index: 9999;
- top: 100%;
-
- background: #fff;
- color: #000;
- border: 1px solid #aaa;
- border-top: 0;
-
- border-radius: 0 0 4px 4px;
-
- box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
-}
-
-.select2-drop.select2-drop-above {
- margin-top: 1px;
- border-top: 1px solid #aaa;
- border-bottom: 0;
-
- border-radius: 4px 4px 0 0;
-
- box-shadow: 0 -4px 5px rgba(0, 0, 0, 0.15);
-}
-
-.select2-drop-active {
- border: 1px solid #5897fb;
- border-top: 0;
-}
-
-.select2-drop.select2-drop-above.select2-drop-active {
- border-top: 1px solid #5897fb;
-}
-
-.select2-drop-auto-width {
- border-top: 1px solid #aaa;
- width: auto;
-}
-
-.select2-drop-auto-width .select2-search {
- padding-top: 4px;
-}
-
-.select2-container .select2-choice .select2-arrow {
- display: inline-block;
- width: 18px;
- height: 100%;
- position: absolute;
- right: 0;
- top: 0;
-
- border-left: 1px solid #aaa;
- border-radius: 0 4px 4px 0;
-
- background-clip: padding-box;
-
- background: #ccc;
- background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
-}
-
-html[dir='rtl'] .select2-container .select2-choice .select2-arrow {
- left: 0;
- right: auto;
-
- border-left: 0;
- border-right: 1px solid #aaa;
- border-radius: 4px 0 0 4px;
-}
-
-.select2-container .select2-choice .select2-arrow b {
- display: block;
- width: 100%;
- height: 100%;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path("select2.png")) no-repeat 0 1px;
-}
-
-html[dir='rtl'] .select2-container .select2-choice .select2-arrow b {
- background-position: 2px 1px;
-}
-
-.select2-search {
- display: inline-block;
- width: 100%;
- min-height: 26px;
- margin: 0;
- padding-left: 4px;
- padding-right: 4px;
-
- position: relative;
- z-index: 10000;
-
- white-space: nowrap;
-}
-
-.select2-search input {
- width: 100%;
- height: auto !important;
- min-height: 26px;
- padding: 4px 20px 4px 5px;
- margin: 0;
-
- outline: 0;
- font-family: sans-serif;
- font-size: 1em;
-
- border: 1px solid #aaa;
- border-radius: 0;
-
- box-shadow: none;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path('select2.png')) no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
-}
-
-html[dir='rtl'] .select2-search input {
- padding: 4px 5px 4px 20px;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path('select2.png')) no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
-}
-
-.select2-drop.select2-drop-above .select2-search input {
- margin-top: 4px;
-}
-
-.select2-search input.select2-active {
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path('select2-spinner.gif')) no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
-}
-
-.select2-container-active .select2-choice,
-.select2-container-active .select2-choices {
- border: 1px solid #5897fb;
- outline: none;
-
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
-}
-
-.select2-dropdown-open .select2-choice {
- border-bottom-color: transparent;
- box-shadow: 0 1px 0 #fff inset;
-
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
-
- background-color: #eee;
- background-image: linear-gradient(to top, #fff 0%, #eee 50%);
-}
-
-.select2-dropdown-open.select2-drop-above .select2-choice,
-.select2-dropdown-open.select2-drop-above .select2-choices {
- border: 1px solid #5897fb;
- border-top-color: transparent;
-
- background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
-}
-
-.select2-dropdown-open .select2-choice .select2-arrow {
- background: transparent;
- border-left: 0;
- filter: none;
-}
-
-html[dir='rtl'] .select2-dropdown-open .select2-choice .select2-arrow {
- border-right: 0;
-}
-
-.select2-dropdown-open .select2-choice .select2-arrow b {
- background-position: -18px 1px;
-}
-
-html[dir='rtl'] .select2-dropdown-open .select2-choice .select2-arrow b {
- background-position: -16px 1px;
-}
-
-.select2-hidden-accessible {
- border: 0;
- clip: rect(0 0 0 0);
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position: absolute;
- width: 1px;
-}
-
-/* results */
-.select2-results {
- max-height: 200px;
- padding: 0 0 0 4px;
- margin: 4px 4px 4px 0;
- position: relative;
- overflow-x: hidden;
- overflow-y: auto;
-}
-
-html[dir='rtl'] .select2-results {
- padding: 0 4px 0 0;
- margin: 4px 0 4px 4px;
-}
-
-.select2-results ul.select2-result-sub {
- margin: 0;
- padding-left: 0;
-}
-
-.select2-results li {
- list-style: none;
- display: list-item;
- background-image: none;
-}
-
-.select2-results li.select2-result-with-children > .select2-result-label {
- font-weight: bold;
-}
-
-.select2-results .select2-result-label {
- padding: 3px 7px 4px;
- margin: 0;
- cursor: pointer;
-
- min-height: 1em;
-
- user-select: none;
-}
-
-.select2-results-dept-1 .select2-result-label { padding-left: 20px; }
-.select2-results-dept-2 .select2-result-label { padding-left: 40px; }
-.select2-results-dept-3 .select2-result-label { padding-left: 60px; }
-.select2-results-dept-4 .select2-result-label { padding-left: 80px; }
-.select2-results-dept-5 .select2-result-label { padding-left: 100px; }
-.select2-results-dept-6 .select2-result-label { padding-left: 110px; }
-.select2-results-dept-7 .select2-result-label { padding-left: 120px; }
-
-.select2-results .select2-highlighted {
- background: #3875d7;
- color: #fff;
-}
-
-.select2-results li em {
- background: #feffde;
- font-style: normal;
-}
-
-.select2-results .select2-highlighted em {
- background: transparent;
-}
-
-.select2-results .select2-highlighted ul {
- background: #fff;
- color: #000;
-}
-
-.select2-results .select2-no-results,
-.select2-results .select2-searching,
-.select2-results .select2-ajax-error,
-.select2-results .select2-selection-limit {
- background: #f4f4f4;
- display: list-item;
- padding-left: 5px;
-}
-
-/*
-disabled look for disabled choices in the results dropdown
-*/
-.select2-results .select2-disabled.select2-highlighted {
- color: #666;
- background: #f4f4f4;
- display: list-item;
- cursor: default;
-}
-
-.select2-results .select2-disabled {
- background: #f4f4f4;
- display: list-item;
- cursor: default;
-}
-
-.select2-results .select2-selected {
- display: none;
-}
-
-.select2-more-results.select2-active {
- /* stylelint-disable-next-line function-url-quotes */
- background: #f4f4f4 url(image-path('select2-spinner.gif')) no-repeat 100%;
-}
-
-.select2-results .select2-ajax-error {
- background: rgba(255, 50, 50, 0.2);
-}
-
-.select2-more-results {
- background: #f4f4f4;
- display: list-item;
-}
-
-/* disabled styles */
-
-.select2-container.select2-container-disabled .select2-choice {
- background-color: #f4f4f4;
- background-image: none;
- border: 1px solid #ddd;
- cursor: default;
-}
-
-.select2-container.select2-container-disabled .select2-choice .select2-arrow {
- background-color: #f4f4f4;
- background-image: none;
- border-left: 0;
-}
-
-.select2-container.select2-container-disabled .select2-choice abbr {
- display: none;
-}
-
-
-/* multiselect */
-
-.select2-container-multi .select2-choices {
- height: auto !important;
- height: 1%;
- margin: 0;
- padding: 0 5px 0 0;
- position: relative;
-
- border: 1px solid #aaa;
- cursor: text;
- overflow: hidden;
-
- background-color: #fff;
- background-image: linear-gradient(to bottom, #eee 1%, #fff 15%);
-}
-
-html[dir='rtl'] .select2-container-multi .select2-choices {
- padding: 0 0 0 5px;
-}
-
-.select2-locked {
- padding: 3px 5px !important;
-}
-
-.select2-container-multi .select2-choices {
- min-height: 26px;
-}
-
-.select2-container-multi.select2-container-active .select2-choices {
- border: 1px solid #5897fb;
- outline: none;
-
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
-}
-
-.select2-container-multi .select2-choices li {
- float: left;
- list-style: none;
-}
-
-html[dir='rtl'] .select2-container-multi .select2-choices li {
- float: right;
-}
-
-.select2-container-multi .select2-choices .select2-search-field {
- margin: 0;
- padding: 0;
- white-space: nowrap;
-}
-
-.select2-container-multi .select2-choices .select2-search-field input {
- padding: 5px;
- margin: 1px 0;
-
- font-family: sans-serif;
- font-size: 100%;
- color: #666;
- outline: 0;
- border: 0;
-
- box-shadow: none;
- background: transparent !important;
-}
-
-.select2-container-multi .select2-choices .select2-search-field input.select2-active {
- /* stylelint-disable-next-line function-url-quotes */
- background: #fff url(image-path('select2-spinner.gif')) no-repeat 100% !important;
-}
-
-.select2-default {
- color: #999 !important;
-}
-
-.select2-container-multi .select2-choices .select2-search-choice {
- padding: 3px 5px 3px 18px;
- margin: 3px 0 3px 5px;
- position: relative;
-
- line-height: 13px;
- color: #333;
- cursor: default;
- border: 1px solid #aaa;
-
- border-radius: 3px;
-
- box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
-
- background-clip: padding-box;
-
- user-select: none;
-
- background-color: #e4e4e4;
- background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
-}
-
-html[dir='rtl'] .select2-container-multi .select2-choices .select2-search-choice {
- margin: 3px 5px 3px 0;
- padding: 3px 18px 3px 5px;
-}
-
-.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
- cursor: default;
-}
-
-.select2-container-multi .select2-choices .select2-search-choice-focus {
- background: #d4d4d4;
-}
-
-.select2-search-choice-close {
- display: block;
- width: 12px;
- height: 13px;
- position: absolute;
- right: 3px;
- top: 4px;
-
- font-size: 1px;
- outline: none;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(image-path('select2.png')) right top no-repeat;
-}
-
-html[dir='rtl'] .select2-search-choice-close {
- right: auto;
- left: 3px;
-}
-
-.select2-container-multi .select2-search-choice-close {
- left: 3px;
-}
-
-html[dir='rtl'] .select2-container-multi .select2-search-choice-close {
- left: auto;
- right: 2px;
-}
-
-.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
- background-position: right -11px;
-}
-
-.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
- background-position: right -11px;
-}
-
-/* disabled styles */
-.select2-container-multi.select2-container-disabled .select2-choices {
- background-color: #f4f4f4;
- background-image: none;
- border: 1px solid #ddd;
- cursor: default;
-}
-
-.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
- padding: 3px 5px;
- border: 1px solid #ddd;
- background-image: none;
- background-color: #f4f4f4;
-}
-
-.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close {
- display: none;
- background: none;
-}
-/* end multiselect */
-
-
-.select2-result-selectable .select2-match,
-.select2-result-unselectable .select2-match {
- text-decoration: underline;
-}
-
-.select2-offscreen,
-.select2-offscreen:focus {
- clip: rect(0 0 0 0) !important;
- width: 1px !important;
- height: 1px !important;
- border: 0 !important;
- margin: 0 !important;
- padding: 0 !important;
- overflow: hidden !important;
- position: absolute !important;
- outline: 0 !important;
- left: 0 !important;
- top: 0 !important;
-}
-
-.select2-display-none {
- display: none;
-}
-
-.select2-measure-scrollbar {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 100px;
- height: 100px;
- overflow: scroll;
-}
-
-@media only screen and (min-resolution: 120dpi) {
- .select2-search input,
- .select2-search-choice-close,
- .select2-container .select2-choice abbr,
- .select2-container .select2-choice .select2-arrow b {
- /* stylelint-disable-next-line function-url-quotes */
- background-image: url(image-path("select2x2.png")) !important;
- background-repeat: no-repeat !important;
- background-size: 60px 40px !important;
- }
-
- .select2-search input {
- background-position: 100% -21px !important;
- }
-}
-
-/* End of select2.css */
-
-@import './select2_overrides';
diff --git a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss b/app/assets/stylesheets/lazy_bundles/select2_overrides.scss
deleted file mode 100644
index e3cec187fab..00000000000
--- a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss
+++ /dev/null
@@ -1,341 +0,0 @@
-@import 'page_bundles/mixins_and_variables_and_functions';
-/** Select2 selectbox style override **/
-.select2-container {
- width: 100% !important;
-
- &.input-md,
- &.input-lg {
- display: block;
- }
-}
-
-.select2-container,
-.select2-container.select2-drop-above {
- .select2-choice {
- background: var(--white, $white);
- color: var(--gl-text-color, $gl-text-color);
- border-color: var(--gray-400, $gray-400);
- height: 34px;
- padding: $gl-vert-padding $gl-input-padding;
- font-size: $gl-font-size;
- line-height: 1.42857143;
- border-radius: $gl-border-radius-base;
-
- .select2-arrow {
- padding-top: 12px;
- padding-right: 20px;
- /* stylelint-disable-next-line function-url-quotes */
- background: url(asset_path('chevron-down.png')) no-repeat 2px 8px;
-
- .gl-dark & {
- filter: invert(0.9);
- }
-
- b {
- display: none;
- }
- }
-
- .select2-chosen {
- margin-right: 15px;
- }
-
- &:hover {
- border-color: var(--gray-400, $gray-400);
- color: var(--gl-text-color, $gl-text-color);
- }
- }
-
- // Essentially we’re doing @include form-control-focus here (from
- // bootstrap/scss/mixins/_forms.scss), except that the bootstrap mixin adds a
- // `&:focus` selector and we’re never actually focusing the .select2-choice
- // link nor the .select2-container, the Select2 library focuses an off-screen
- // .select2-focusser element instead.
- &.select2-container-active:not(.select2-dropdown-open) {
- .select2-choice {
- color: var(--gray-700, $gray-700);
- background-color: var(--white, $white);
- border-color: $input-focus-border-color;
- outline: 0;
- }
-
- // Reusable focus “glow” box-shadow
- @mixin form-control-focus-glow {
- @if $enable-shadows {
- box-shadow: $input-box-shadow, $input-focus-box-shadow;
- } @else {
- box-shadow: $input-focus-box-shadow;
- }
- }
-
- // Apply the focus “glow” shadow to the .select2-container if it also has
- // the .block-truncated class as that applies an overflow: hidden, thereby
- // hiding the glow of the nested .select2-choice element.
- &.block-truncated {
- @include form-control-focus-glow;
- }
-
- // Apply the glow directly to the .select2-choice link if we’re not
- // block-truncating the container.
- &:not(.block-truncated) .select2-choice {
- @include form-control-focus-glow;
- }
- }
-
- &.is-invalid {
- ~ .invalid-feedback {
- display: block;
- }
-
- .select2-choices,
- .select2-choice {
- border-color: var(--red-500, $red-500);
- }
- }
-}
-
-.select2-drop,
-.select2-drop.select2-drop-above {
- background: var(--white, $white);
- box-shadow: 0 2px 4px $dropdown-shadow-color;
- border-radius: $gl-border-radius-base;
- border: 1px solid var(--gray-400, $gray-400);
- min-width: 175px;
- color: var(--gl-text-color, $gl-text-color);
- z-index: 999;
-
- .modal-open & {
- z-index: $zindex-modal + 200;
- }
-}
-
-.select2-drop-mask {
- z-index: 998;
-
- .modal-open & {
- z-index: $zindex-modal + 100;
- }
-}
-
-.select2-drop.select2-drop-above.select2-drop-active {
- border-top: 1px solid var(--gray-400, $gray-400);
- margin-top: -6px;
-}
-
-.select2-container-active {
- .select2-choice,
- .select2-choices {
- box-shadow: none;
- }
-}
-
-.select2-dropdown-open,
-.select2-dropdown-open.select2-drop-above {
- .select2-choice {
- border-color: var(--gray-400, $gray-400);
- outline: 0;
- }
-}
-
-.select2-container-multi {
- .select2-choices {
- border-radius: $border-radius-default;
- border-color: var(--gray-400, $gray-400);
- background: none;
-
- .select2-search-field input {
- padding: 5px $gl-input-padding;
- height: auto;
- font-family: inherit;
- font-size: inherit;
- }
-
- .select2-search-choice {
- margin: 5px 0 0 8px;
- box-shadow: none;
- border-color: var(--gray-400, $gray-400);
- color: var(--gl-text-color, $gl-text-color);
- line-height: 15px;
- background-color: var(--gray-50, $gray-50);
- background-image: none;
- padding: 3px 18px 3px 5px;
-
- .select2-search-choice-close {
- top: 5px;
- left: initial;
- right: 3px;
- }
-
- &.select2-search-choice-focus {
- border-color: var(--gray-400, $gray-400);
- }
- }
- }
-}
-
-.select2-drop-active {
- margin-top: $dropdown-vertical-offset;
- font-size: 14px;
-
- .select2-results {
- max-height: 350px;
- }
-}
-
-.select2-search {
- padding: $grid-size;
-
- .select2-drop-auto-width & {
- padding: $grid-size;
- }
-
- input {
- padding: $grid-size;
- background: transparent image-url('select2.png');
- color: var(--gl-text-color, $gl-text-color);
- background-clip: content-box;
- background-origin: content-box;
- background-repeat: no-repeat;
- background-position: right 0 bottom 0 !important;
- border: 1px solid var(--gray-400, $gray-400);
- border-radius: $border-radius-default;
- line-height: 16px;
- transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
-
- &:focus {
- border-color: var(--blue-300, $blue-300);
- }
-
- &.select2-active {
- background-color: var(--white, $white);
- background-image: image-url('select2-spinner.gif') !important;
- background-origin: content-box;
- background-repeat: no-repeat;
- background-position: right 6px center !important;
- background-size: 16px 16px !important;
- }
- }
-
- + .select2-results {
- padding-top: 0;
- }
-}
-
-.select2-results {
- margin: 0;
- padding: #{$gl-padding / 2} 0;
-
- .select2-no-results,
- .select2-searching,
- .select2-ajax-error,
- .select2-selection-limit {
- background: transparent;
- padding: #{$gl-padding / 2} $gl-padding;
- }
-
- .select2-result-label,
- .select2-more-results {
- padding: #{$gl-padding / 2} $gl-padding;
- }
-
- .select2-highlighted {
- background: transparent;
- color: var(--gl-text-color, $gl-text-color);
-
- .select2-result-label {
- background: var(--gray-50, $gray-50);
- }
- }
-
- .select2-result {
- padding: 0 1px;
- }
-
- li.select2-result-with-children > .select2-result-label {
- font-weight: $gl-font-weight-bold;
- color: var(--gl-text-color, $gl-text-color);
- }
-}
-
-.select2-highlighted {
- .group-result {
- .group-path {
- color: var(--gray-700, $gray-700);
- }
- }
-}
-
-.select2-result-selectable,
-.select2-result-unselectable {
- .select2-match {
- font-weight: $gl-font-weight-bold;
- text-decoration: none;
- }
-}
-
-.input-group {
- .select2-container {
- display: table-cell;
- max-width: 180px;
- }
-}
-
-.file-editor {
- .select2 {
- float: right;
- }
-}
-
-.import-namespace-select {
- > .select2-choice {
- border-radius: $border-radius-default 0 0 $border-radius-default;
- position: relative;
- left: 1px;
- }
-}
-
-.issue-form {
- .select2-container {
- width: 250px !important;
- }
-}
-
-.new_project,
-.edit-project,
-.import-project {
- .input-group {
- .select2-container {
- display: unset;
- max-width: unset;
- flex-grow: 1;
- }
- }
-
- .input-group-prepend,
- .input-group-append {
- + .select2 a {
- border-radius: 0 $gl-border-radius-base $gl-border-radius-base 0;
- }
- }
-}
-
-.project-path {
- .select2-choice {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- }
-}
-
-.right-sidebar {
- .block {
- .select2-container span {
- margin-top: 0;
- }
- }
-}
-
-.block-truncated {
- > div:not(.block):not(.select2-display-none) {
- display: inline;
- }
-}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index c2ac4f32480..75c81b74ba7 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -101,12 +101,6 @@ ul.related-merge-requests > li gl-emoji {
}
}
-.issue-form {
- .select2-container {
- width: 250px !important;
- }
-}
-
.issues-nav-controls {
.btn-group:empty {
display: none;
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb
index ef9264d1615..5ea8c672993 100644
--- a/app/controllers/admin/jobs_controller.rb
+++ b/app/controllers/admin/jobs_controller.rb
@@ -6,6 +6,10 @@ class Admin::JobsController < Admin::ApplicationController
feature_category :continuous_integration
urgency :low
+ before_action do
+ push_frontend_feature_flag(:admin_jobs_vue)
+ end
+
def index
# We need all builds for tabs counters
@all_builds = Ci::JobsFinder.new(current_user: current_user).execute
diff --git a/app/controllers/projects/ml/experiments_controller.rb b/app/controllers/projects/ml/experiments_controller.rb
index 20f5b39bac7..00b965542f6 100644
--- a/app/controllers/projects/ml/experiments_controller.rb
+++ b/app/controllers/projects/ml/experiments_controller.rb
@@ -13,7 +13,12 @@ module Projects
MAX_CANDIDATES_PER_PAGE = 30
def index
- @experiments = ::Ml::Experiment.by_project_id(@project.id).page(params[:page]).per(MAX_EXPERIMENTS_PER_PAGE)
+ paginator = ::Ml::Experiment.by_project_id(@project.id)
+ .with_candidate_count
+ .keyset_paginate(cursor: params[:cursor], per_page: MAX_EXPERIMENTS_PER_PAGE)
+
+ @experiments = paginator.records
+ @page_info = page_info(paginator)
end
def show
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
index 9f41db2f8b9..8467ee61b35 100644
--- a/app/helpers/projects/ml/experiments_helper.rb
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -33,7 +33,7 @@ module Projects
iid: candidate.iid,
path_to_artifact: link_to_artifact(candidate),
experiment_name: candidate.experiment.name,
- path_to_experiment: link_to_experiment(candidate),
+ path_to_experiment: link_to_experiment(candidate.project, candidate.experiment),
status: candidate.status
},
metadata: candidate.metadata
@@ -42,6 +42,18 @@ module Projects
Gitlab::Json.generate(data)
end
+ def experiments_as_data(project, experiments)
+ data = experiments.map do |exp|
+ {
+ name: exp.name,
+ path: link_to_experiment(project, exp),
+ candidate_count: exp.candidate_count
+ }
+ end
+
+ Gitlab::Json.generate(data)
+ end
+
def page_info(paginator)
{
has_next_page: paginator.has_next_page?,
@@ -67,10 +79,8 @@ module Projects
project_ml_candidate_path(candidate.project, candidate.iid)
end
- def link_to_experiment(candidate)
- experiment = candidate.experiment
-
- project_ml_experiment_path(experiment.project, experiment.iid)
+ def link_to_experiment(project, experiment)
+ project_ml_experiment_path(project, experiment.iid)
end
def user_info(candidate)
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
deleted file mode 100644
index 7ee40c28bad..00000000000
--- a/app/helpers/selects_helper.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-module SelectsHelper
- def project_select_tag(id, opts = {})
- opts[:class] = [*opts[:class], 'ajax-project-select'].join(' ')
-
- unless opts.delete(:scope) == :all
- if @group
- opts['data-group-id'] = @group.id
- end
- end
-
- with_feature_enabled_data_attribute =
- case opts.delete(:with_feature_enabled)
- when 'issues' then 'data-with-issues-enabled'
- when 'merge_requests' then 'data-with-merge-requests-enabled'
- end
-
- opts[with_feature_enabled_data_attribute] = true
-
- hidden_field_tag(id, opts[:selected], opts)
- end
-
- def select2_tag(id, opts = {})
- klass_opts = [opts[:class]]
- klass_opts << 'multiselect' if opts[:multiple]
-
- opts[:class] = klass_opts.join(' ')
- value = opts[:selected] || ''
-
- hidden_field_tag(id, value, opts)
- end
-end
-
-SelectsHelper.prepend_mod_with('SelectsHelper')
diff --git a/app/services/export_csv/base_service.rb b/app/services/export_csv/base_service.rb
index 98ab33d4c33..84d44fd75fc 100644
--- a/app/services/export_csv/base_service.rb
+++ b/app/services/export_csv/base_service.rb
@@ -5,9 +5,10 @@ module ExportCsv
# Target attachment size before base64 encoding
TARGET_FILESIZE = 15.megabytes
- def initialize(relation, resource_parent)
+ def initialize(relation, resource_parent, fields = [])
@objects = relation
@resource_parent = resource_parent
+ @fields = fields
end
def csv_data
@@ -18,18 +19,25 @@ module ExportCsv
raise NotImplementedError
end
+ def invalid_fields
+ ::ExportCsv::MapExportFieldsService.new(fields, header_to_value_hash).invalid_fields
+ end
+
private
- attr_reader :resource_parent, :objects
+ attr_reader :resource_parent, :objects, :fields
# rubocop: disable CodeReuse/ActiveRecord
def csv_builder
- @csv_builder ||=
+ @csv_builder ||= begin
+ data_hash = MapExportFieldsService.new(fields, header_to_value_hash).execute
+
if preload_associations_in_batches?
- CsvBuilder.new(objects, header_to_value_hash, associations_to_preload)
+ CsvBuilder.new(objects, data_hash, associations_to_preload)
else
- CsvBuilder.new(objects.preload(associations_to_preload), header_to_value_hash, [])
+ CsvBuilder.new(objects.preload(associations_to_preload), data_hash, [])
end
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/export_csv/map_export_fields_service.rb b/app/services/export_csv/map_export_fields_service.rb
new file mode 100644
index 00000000000..d4f46c65328
--- /dev/null
+++ b/app/services/export_csv/map_export_fields_service.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module ExportCsv
+ class MapExportFieldsService < BaseService
+ attr_reader :fields, :data
+
+ def initialize(fields, data)
+ @fields = fields
+ @data = data
+ end
+
+ def execute
+ return data if fields.empty?
+
+ selected_fields_to_hash
+ end
+
+ def invalid_fields
+ fields.reject { |field| permitted_field?(field) }
+ end
+
+ private
+
+ def selected_fields_to_hash
+ data.select { |key| requested_field?(key) }
+ end
+
+ def requested_field?(field)
+ field.downcase.in?(fields.map(&:downcase))
+ end
+
+ def permitted_field?(field)
+ field.downcase.in?(keys.map(&:downcase))
+ end
+
+ def keys
+ data.keys
+ end
+ end
+end
diff --git a/app/services/work_items/export_csv_service.rb b/app/services/work_items/export_csv_service.rb
new file mode 100644
index 00000000000..e0a1b90b597
--- /dev/null
+++ b/app/services/work_items/export_csv_service.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module WorkItems
+ class ExportCsvService < ExportCsv::BaseService
+ def email(mail_to_user)
+ # TODO - will be implemented as part of https://gitlab.com/gitlab-org/gitlab/-/issues/379082
+ end
+
+ private
+
+ def associations_to_preload
+ [:work_item_type, :author]
+ end
+
+ def header_to_value_hash
+ {
+ 'Id' => 'iid',
+ 'Title' => 'title',
+ 'Type' => ->(work_item) { work_item.work_item_type.name },
+ 'Author' => 'author_name',
+ 'Author Username' => ->(work_item) { work_item.author.username },
+ 'Created At (UTC)' => ->(work_item) { work_item.created_at.to_s(:csv) }
+ }
+ end
+ end
+end
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 667c90f0228..7b00019cc21 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -4,21 +4,25 @@
- breadcrumb_title _("Jobs")
- page_title _("Jobs")
-.top-area
- .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
- = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
+- if Feature.enabled?(:admin_jobs_vue)
+ #admin-jobs-app{ data: { job_statuses: job_statuses.to_json, empty_state_svg_path: image_path('jobs-empty-state.svg'), url: cancel_all_admin_jobs_path } }
- - if @all_builds.running_or_pending.any?
- #js-stop-jobs-modal
- .nav-controls
- = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'js-stop-jobs-button', data: { url: cancel_all_admin_jobs_path } }) do
- = s_('AdminArea|Stop all jobs')
+- else
+ .top-area
+ .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
-.row-content-block.second-block
- #{(@scope || 'all').capitalize} jobs
+ - if @all_builds.running_or_pending.any?
+ #js-stop-jobs-modal
+ .nav-controls
+ = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'js-stop-jobs-button', data: { url: cancel_all_admin_jobs_path } }) do
+ = s_('AdminArea|Stop all jobs')
-%ul.content-list.builds-content-list.admin-builds-table
- = render "projects/jobs/table", builds: @builds, admin: true
+ .row-content-block.second-block
+ #{(@scope || 'all').capitalize} jobs
+
+ %ul.content-list.builds-content-list.admin-builds-table
+ = render "projects/jobs/table", builds: @builds, admin: true
diff --git a/app/views/projects/ml/experiments/index.html.haml b/app/views/projects/ml/experiments/index.html.haml
index a84cb15d940..dd064239e36 100644
--- a/app/views/projects/ml/experiments/index.html.haml
+++ b/app/views/projects/ml/experiments/index.html.haml
@@ -1,11 +1,7 @@
-- breadcrumb_title _('ML Experiments')
-- page_title _('ML Experiments')
+- breadcrumb_title s_('MlExperimentTracking|Model experiments')
+- page_title s_('MlExperimentTracking|Model experiments')
-.page-title-holder.d-flex.align-items-center
- %h1.page-title.gl-font-size-h-display= _('Machine Learning Experiments')
-
-= render "incubation_banner"
-
-%div{ class: container_class }
- .content-list.builds-content-list
- = render "experiment_list", experiments: @experiments, project: @project
+#js-project-ml-experiments-index{ data: {
+ experiments: experiments_as_data(@project, @experiments),
+ page_info: formatted_page_info(@page_info)
+} }
diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml
deleted file mode 100644
index 2249fb03f62..00000000000
--- a/app/views/shared/_new_project_item_select.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# This view is used to initialize a select2-based selector, which we are migrating away from.
--# To initialize the Vue selector, use the new_project_item_vue_select view instead.
--# Refer to https://gitlab.com/gitlab-org/gitlab/-/issues/374098 for more information.
-- if any_projects?(@projects)
- .dropdown.b-dropdown.gl-dropdown.btn-group.project-item-select-holder{ class: 'gl-display-inline-flex!' }
- %a.btn.gl-button.btn-confirm.split-content-button.js-new-project-item-link.block-truncated{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } }
- = gl_loading_icon(inline: true, color: 'light')
- = project_select_tag :project_path, class: "project-item-select gl-absolute! gl-visibility-hidden", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled]
- %button.btn.dropdown-toggle.btn-confirm.btn-md.gl-button.gl-dropdown-toggle.dropdown-toggle-split.new-project-item-select-button{ 'aria-label': _('Toggle project select') }