diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 18:18:33 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 18:18:33 +0000 |
commit | f64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch) | |
tree | a2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /app/assets/javascripts/pages | |
parent | bfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff) | |
download | gitlab-ce-f64a639bcfa1fc2bc89ca7db268f594306edfd7c.tar.gz |
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'app/assets/javascripts/pages')
79 files changed, 1106 insertions, 500 deletions
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js index 5649c47d7e8..0a4311ec73a 100644 --- a/app/assets/javascripts/pages/admin/abuse_reports/index.js +++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js @@ -1,8 +1,5 @@ -/* eslint-disable no-new */ import UsersSelect from '~/users_select'; import AbuseReports from './abuse_reports'; -document.addEventListener('DOMContentLoaded', () => { - new AbuseReports(); - new UsersSelect(); -}); +new AbuseReports(); /* eslint-disable-line no-new */ +new UsersSelect(); /* eslint-disable-line no-new */ diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js index e92262852cf..2732fc191be 100644 --- a/app/assets/javascripts/pages/admin/admin.js +++ b/app/assets/javascripts/pages/admin/admin.js @@ -12,8 +12,6 @@ function showDenylistType() { } export default function adminInit() { - const modal = $('.change-owner-holder'); - $('input#user_force_random_password').on('change', function randomPasswordClick() { const $elems = $('#user_password, #user_password_confirmation'); if ($(this).attr('checked')) { @@ -28,36 +26,6 @@ export default function adminInit() { $('.js-toggle-colors-container').toggleClass('hide'); }); - $('.log-tabs a').on('click', function logTabsClick(e) { - e.preventDefault(); - $(this).tab('show'); - }); - - $('.log-bottom').on('click', (e) => { - e.preventDefault(); - const $visibleLog = $('.file-content:visible'); - - // eslint-disable-next-line no-jquery/no-animate - $visibleLog.animate( - { - scrollTop: $visibleLog.find('ol').height(), - }, - 'fast', - ); - }); - - $('.change-owner-link').on('click', function changeOwnerLinkClick(e) { - e.preventDefault(); - $(this).hide(); - modal.show(); - }); - - $('.change-owner-cancel-link').on('click', (e) => { - e.preventDefault(); - modal.hide(); - $('.change-owner-link').show(); - }); - $('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage); $("input[name='denylist_type']").on('click', showDenylistType); diff --git a/app/assets/javascripts/pages/admin/application_settings/general/index.js b/app/assets/javascripts/pages/admin/application_settings/general/index.js index f7bd32880ff..eda1a9d3599 100644 --- a/app/assets/javascripts/pages/admin/application_settings/general/index.js +++ b/app/assets/javascripts/pages/admin/application_settings/general/index.js @@ -1,25 +1,27 @@ -// This is a true violation of @gitlab/no-runtime-template-compiler, as it -// relies on app/views/admin/application_settings/_gitpod.html.haml for its -// template. -/* eslint-disable @gitlab/no-runtime-template-compiler */ import Vue from 'vue'; import IntegrationHelpText from '~/vue_shared/components/integrations_help_text.vue'; import initUserInternalRegexPlaceholder from '../account_and_limits'; -document.addEventListener('DOMContentLoaded', () => { +(() => { initUserInternalRegexPlaceholder(); - const gitpodSettingEl = document.querySelector('#js-gitpod-settings-help-text'); - if (!gitpodSettingEl) { + const el = document.querySelector('#js-gitpod-settings-help-text'); + if (!el) { return; } + const { message, messageUrl } = el.dataset; + // eslint-disable-next-line no-new new Vue({ - el: gitpodSettingEl, - name: 'GitpodSettings', - components: { - IntegrationHelpText, + el, + render(createElement) { + return createElement(IntegrationHelpText, { + props: { + message, + messageUrl, + }, + }); }, }); -}); +})(); diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js index e7e74588bec..e3c6b0f6f5b 100644 --- a/app/assets/javascripts/pages/admin/application_settings/index.js +++ b/app/assets/javascripts/pages/admin/application_settings/index.js @@ -4,13 +4,11 @@ import initSearchSettings from '~/search_settings'; import selfMonitor from '~/self_monitor'; import initSettingsPanels from '~/settings_panels'; -document.addEventListener('DOMContentLoaded', () => { - if (gon.features?.ciInstanceVariablesUi) { - initVariableList('js-instance-variables'); - } - selfMonitor(); - // Initialize expandable settings panels - initSettingsPanels(); - projectSelect(); - initSearchSettings(); -}); +if (gon.features?.ciInstanceVariablesUi) { + initVariableList('js-instance-variables'); +} +selfMonitor(); +// Initialize expandable settings panels +initSettingsPanels(); +projectSelect(); +initSearchSettings(); diff --git a/app/assets/javascripts/pages/admin/dev_ops_report/index.js b/app/assets/javascripts/pages/admin/dev_ops_report/index.js index 220fc049562..cf06ee2c22a 100644 --- a/app/assets/javascripts/pages/admin/dev_ops_report/index.js +++ b/app/assets/javascripts/pages/admin/dev_ops_report/index.js @@ -1,5 +1,3 @@ -import initDevopAdoption from 'ee_else_ce/admin/dev_ops_report/devops_adoption'; -import initDevOpsScoreEmptyState from '~/admin/dev_ops_report/devops_score_empty_state'; +import initDevOpsScoreEmptyState from '~/analytics/devops_report/devops_score_empty_state'; initDevOpsScoreEmptyState(); -initDevopAdoption(); diff --git a/app/assets/javascripts/pages/admin/impersonation_tokens/index.js b/app/assets/javascripts/pages/admin/impersonation_tokens/index.js index ae2209b0292..dc1bb88bf4b 100644 --- a/app/assets/javascripts/pages/admin/impersonation_tokens/index.js +++ b/app/assets/javascripts/pages/admin/impersonation_tokens/index.js @@ -1,3 +1,3 @@ -import initExpiresAtField from '~/access_tokens'; +import { initExpiresAtField } from '~/access_tokens'; -document.addEventListener('DOMContentLoaded', initExpiresAtField); +initExpiresAtField(); diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js index 792a6eda14e..8d5dfd689e8 100644 --- a/app/assets/javascripts/pages/admin/index.js +++ b/app/assets/javascripts/pages/admin/index.js @@ -2,10 +2,8 @@ import initAdminStatisticsPanel from '../../admin/statistics_panel/index'; import initVueAlerts from '../../vue_alerts'; import initAdmin from './admin'; -document.addEventListener('DOMContentLoaded', initVueAlerts); +initVueAlerts(); -document.addEventListener('DOMContentLoaded', () => { - const statisticsPanelContainer = document.getElementById('js-admin-statistics-container'); - initAdmin(); - initAdminStatisticsPanel(statisticsPanelContainer); -}); +const statisticsPanelContainer = document.getElementById('js-admin-statistics-container'); +initAdmin(); +initAdminStatisticsPanel(statisticsPanelContainer); diff --git a/app/assets/javascripts/pages/admin/instance_statistics/index.js b/app/assets/javascripts/pages/admin/instance_statistics/index.js deleted file mode 100644 index d6b0a834ce3..00000000000 --- a/app/assets/javascripts/pages/admin/instance_statistics/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import initInstanceStatisticsApp from '~/analytics/instance_statistics'; - -document.addEventListener('DOMContentLoaded', () => initInstanceStatisticsApp()); diff --git a/app/assets/javascripts/pages/admin/projects/index.js b/app/assets/javascripts/pages/admin/projects/index.js index 2286a085143..042ff7808f1 100644 --- a/app/assets/javascripts/pages/admin/projects/index.js +++ b/app/assets/javascripts/pages/admin/projects/index.js @@ -17,12 +17,10 @@ function mountRemoveMemberModal() { }); } -document.addEventListener('DOMContentLoaded', () => { - mountRemoveMemberModal(); +mountRemoveMemberModal(); - new ProjectsList(); // eslint-disable-line no-new +new ProjectsList(); // eslint-disable-line no-new - document - .querySelectorAll('.js-namespace-select') - .forEach((dropdown) => new NamespaceSelect({ dropdown })); -}); +document + .querySelectorAll('.js-namespace-select') + .forEach((dropdown) => new NamespaceSelect({ dropdown })); diff --git a/app/assets/javascripts/pages/admin/projects/index/index.js b/app/assets/javascripts/pages/admin/projects/index/index.js index 1971323abac..cc9a9b6cc38 100644 --- a/app/assets/javascripts/pages/admin/projects/index/index.js +++ b/app/assets/javascripts/pages/admin/projects/index/index.js @@ -6,7 +6,7 @@ import Translate from '~/vue_shared/translate'; import deleteProjectModal from './components/delete_project_modal.vue'; -document.addEventListener('DOMContentLoaded', () => { +(() => { Vue.use(Translate); const deleteProjectModalEl = document.getElementById('delete-project-modal'); @@ -39,4 +39,4 @@ document.addEventListener('DOMContentLoaded', () => { }); }, }); -}); +})(); diff --git a/app/assets/javascripts/pages/admin/runners/index.js b/app/assets/javascripts/pages/admin/runners/index.js index f07ac1d8674..45ed3ac6bd8 100644 --- a/app/assets/javascripts/pages/admin/runners/index.js +++ b/app/assets/javascripts/pages/admin/runners/index.js @@ -3,12 +3,10 @@ import { FILTERED_SEARCH } from '~/pages/constants'; import initFilteredSearch from '~/pages/search/init_filtered_search'; import { initInstallRunner } from '~/pages/shared/mount_runner_instructions'; -document.addEventListener('DOMContentLoaded', () => { - initFilteredSearch({ - page: FILTERED_SEARCH.ADMIN_RUNNERS, - filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys, - useDefaultState: true, - }); - - initInstallRunner(); +initFilteredSearch({ + page: FILTERED_SEARCH.ADMIN_RUNNERS, + filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys, + useDefaultState: true, }); + +initInstallRunner(); diff --git a/app/assets/javascripts/pages/admin/services/index/index.js b/app/assets/javascripts/pages/admin/services/index/index.js index b2dfbb5a9fc..b695cf70c5d 100644 --- a/app/assets/javascripts/pages/admin/services/index/index.js +++ b/app/assets/javascripts/pages/admin/services/index/index.js @@ -1,6 +1,4 @@ import PersistentUserCallout from '~/persistent_user_callout'; -document.addEventListener('DOMContentLoaded', () => { - const callout = document.querySelector('.js-service-templates-deprecated'); - PersistentUserCallout.factory(callout); -}); +const callout = document.querySelector('.js-service-templates-deprecated'); +PersistentUserCallout.factory(callout); diff --git a/app/assets/javascripts/pages/admin/usage_trends/index.js b/app/assets/javascripts/pages/admin/usage_trends/index.js new file mode 100644 index 00000000000..23d2bd85979 --- /dev/null +++ b/app/assets/javascripts/pages/admin/usage_trends/index.js @@ -0,0 +1,3 @@ +import initUsageTrendsApp from '~/analytics/usage_trends'; + +initUsageTrendsApp(); diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js index 3ad95fb1318..3e09b1796b1 100644 --- a/app/assets/javascripts/pages/dashboard/issues/index.js +++ b/app/assets/javascripts/pages/dashboard/issues/index.js @@ -4,13 +4,11 @@ import { FILTERED_SEARCH } from '~/pages/constants'; import initFilteredSearch from '~/pages/search/init_filtered_search'; import projectSelect from '~/project_select'; -document.addEventListener('DOMContentLoaded', () => { - initFilteredSearch({ - page: FILTERED_SEARCH.ISSUES, - filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, - useDefaultState: true, - }); - - projectSelect(); - initManualOrdering(); +initFilteredSearch({ + page: FILTERED_SEARCH.ISSUES, + filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, + useDefaultState: true, }); + +projectSelect(); +initManualOrdering(); diff --git a/app/assets/javascripts/pages/dashboard/milestones/show/index.js b/app/assets/javascripts/pages/dashboard/milestones/show/index.js index 8b529585898..397149aaa9e 100644 --- a/app/assets/javascripts/pages/dashboard/milestones/show/index.js +++ b/app/assets/javascripts/pages/dashboard/milestones/show/index.js @@ -6,6 +6,4 @@ document.addEventListener('DOMContentLoaded', () => { new Milestone(); // eslint-disable-line no-new new Sidebar(); // eslint-disable-line no-new new MountMilestoneSidebar(); // eslint-disable-line no-new - - Milestone.initDeprecationMessage(); }); diff --git a/app/assets/javascripts/pages/dashboard/projects/index/index.js b/app/assets/javascripts/pages/dashboard/projects/index/index.js index b3c95f4ac1f..c34d15b869a 100644 --- a/app/assets/javascripts/pages/dashboard/projects/index/index.js +++ b/app/assets/javascripts/pages/dashboard/projects/index/index.js @@ -1,8 +1,5 @@ import ProjectsList from '~/projects_list'; import initCustomizeHomepageBanner from './init_customize_homepage_banner'; -document.addEventListener('DOMContentLoaded', () => { - new ProjectsList(); // eslint-disable-line no-new - - initCustomizeHomepageBanner(); -}); +new ProjectsList(); // eslint-disable-line no-new +initCustomizeHomepageBanner(); diff --git a/app/assets/javascripts/pages/dashboard/todos/index/index.js b/app/assets/javascripts/pages/dashboard/todos/index/index.js index 9d2c2f2994f..2fe90c24e77 100644 --- a/app/assets/javascripts/pages/dashboard/todos/index/index.js +++ b/app/assets/javascripts/pages/dashboard/todos/index/index.js @@ -1,3 +1,3 @@ import Todos from './todos'; -document.addEventListener('DOMContentLoaded', () => new Todos()); +new Todos(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/groups/activity/index.js b/app/assets/javascripts/pages/groups/activity/index.js index 1b887cad496..8b7c36a0976 100644 --- a/app/assets/javascripts/pages/groups/activity/index.js +++ b/app/assets/javascripts/pages/groups/activity/index.js @@ -1,3 +1,4 @@ import Activities from '~/activities'; -document.addEventListener('DOMContentLoaded', () => new Activities()); +// eslint-disable-next-line no-new +new Activities(); diff --git a/app/assets/javascripts/pages/groups/edit/index.js b/app/assets/javascripts/pages/groups/edit/index.js index 95ee512b71a..176d2406751 100644 --- a/app/assets/javascripts/pages/groups/edit/index.js +++ b/app/assets/javascripts/pages/groups/edit/index.js @@ -6,6 +6,7 @@ import TransferDropdown from '~/groups/transfer_dropdown'; import groupsSelect from '~/groups_select'; import mountBadgeSettings from '~/pages/shared/mount_badge_settings'; import projectSelect from '~/project_select'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; import setupTransferEdit from '~/transfer_edit'; @@ -24,5 +25,7 @@ document.addEventListener('DOMContentLoaded', () => { projectSelect(); + initSearchSettings(); + return new TransferDropdown(); }); diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js index 3496f699b06..ab70fa572ba 100644 --- a/app/assets/javascripts/pages/groups/group_members/index.js +++ b/app/assets/javascripts/pages/groups/group_members/index.js @@ -1,11 +1,13 @@ import Vue from 'vue'; import { groupMemberRequestFormatter } from '~/groups/members/utils'; import groupsSelect from '~/groups_select'; +import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger'; +import initInviteMembersForm from '~/invite_members/init_invite_members_form'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import { s__ } from '~/locale'; import memberExpirationDate from '~/member_expiration_date'; -import { initMembersApp } from '~/members/index'; +import { initMembersApp } from '~/members'; import { groupLinkRequestFormatter } from '~/members/utils'; import UsersSelect from '~/users_select'; import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue'; @@ -70,5 +72,10 @@ memberExpirationDate('.js-access-expiration-date-groups'); mountRemoveMemberModal(); initInviteMembersModal(); initInviteMembersTrigger(); +initInviteGroupTrigger(); + +// This is only used when `invite_members_group_modal` feature flag is disabled. +// This can be removed when `invite_members_group_modal` feature flag is removed. +initInviteMembersForm(); new UsersSelect(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/groups/milestones/show/index.js b/app/assets/javascripts/pages/groups/milestones/show/index.js index 3094fe5cd21..2a2cc5faebe 100644 --- a/app/assets/javascripts/pages/groups/milestones/show/index.js +++ b/app/assets/javascripts/pages/groups/milestones/show/index.js @@ -1,9 +1,7 @@ -import Milestone from '~/milestone'; import initDeleteMilestoneModal from '~/pages/milestones/shared/delete_milestone_modal_init'; import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show'; document.addEventListener('DOMContentLoaded', () => { initMilestonesShow(); initDeleteMilestoneModal(); - Milestone.initDeprecationMessage(); }); diff --git a/app/assets/javascripts/pages/groups/new/index.js b/app/assets/javascripts/pages/groups/new/index.js index 63515abe698..322ad2c79e7 100644 --- a/app/assets/javascripts/pages/groups/new/index.js +++ b/app/assets/javascripts/pages/groups/new/index.js @@ -2,6 +2,7 @@ import $ from 'jquery'; import BindInOut from '~/behaviors/bind_in_out'; import initFilePickers from '~/file_pickers'; import Group from '~/group'; +import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs'; import GroupPathValidator from './group_path_validator'; const parentId = $('#group_parent_id'); @@ -12,3 +13,16 @@ BindInOut.initAll(); initFilePickers(); new Group(); // eslint-disable-line no-new + +const CONTAINER_SELECTOR = '.group-edit-container .nav-tabs'; +const DEFAULT_ACTION = '#create-group-pane'; +// eslint-disable-next-line no-new +new LinkedTabs({ + defaultAction: DEFAULT_ACTION, + parentEl: CONTAINER_SELECTOR, + hashedTabs: true, +}); + +if (window.location.hash) { + $(CONTAINER_SELECTOR).find(`a[href="${window.location.hash}"]`).tab('show'); +} diff --git a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js index 378b8663777..0c3fdcf3e75 100644 --- a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js +++ b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js @@ -4,21 +4,22 @@ import initSharedRunnersForm from '~/group_settings/mount_shared_runners'; import { FILTERED_SEARCH } from '~/pages/constants'; import initFilteredSearch from '~/pages/search/init_filtered_search'; import { initInstallRunner } from '~/pages/shared/mount_runner_instructions'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; -document.addEventListener('DOMContentLoaded', () => { - // Initialize expandable settings panels - initSettingsPanels(); +// Initialize expandable settings panels +initSettingsPanels(); - initFilteredSearch({ - page: FILTERED_SEARCH.ADMIN_RUNNERS, - filteredSearchTokenKeys: GroupRunnersFilteredSearchTokenKeys, - anchor: FILTERED_SEARCH.GROUP_RUNNERS_ANCHOR, - useDefaultState: false, - }); +initFilteredSearch({ + page: FILTERED_SEARCH.ADMIN_RUNNERS, + filteredSearchTokenKeys: GroupRunnersFilteredSearchTokenKeys, + anchor: FILTERED_SEARCH.GROUP_RUNNERS_ANCHOR, + useDefaultState: false, +}); - initSharedRunnersForm(); - initVariableList(); +initSharedRunnersForm(); +initVariableList(); - initInstallRunner(); -}); +initInstallRunner(); + +initSearchSettings(); diff --git a/app/assets/javascripts/pages/groups/settings/integrations/edit/index.js b/app/assets/javascripts/pages/groups/settings/integrations/edit/index.js index ba4b271f09e..a8698e10c57 100644 --- a/app/assets/javascripts/pages/groups/settings/integrations/edit/index.js +++ b/app/assets/javascripts/pages/groups/settings/integrations/edit/index.js @@ -1,13 +1,11 @@ import IntegrationSettingsForm from '~/integrations/integration_settings_form'; import PrometheusMetrics from '~/prometheus_metrics/prometheus_metrics'; -document.addEventListener('DOMContentLoaded', () => { - const prometheusSettingsWrapper = document.querySelector('.js-prometheus-metrics-monitoring'); - const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - integrationSettingsForm.init(); +const prometheusSettingsWrapper = document.querySelector('.js-prometheus-metrics-monitoring'); +const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); +integrationSettingsForm.init(); - if (prometheusSettingsWrapper) { - const prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring'); - prometheusMetrics.loadActiveMetrics(); - } -}); +if (prometheusSettingsWrapper) { + const prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring'); + prometheusMetrics.loadActiveMetrics(); +} diff --git a/app/assets/javascripts/pages/groups/settings/packages_and_registries/index.js b/app/assets/javascripts/pages/groups/settings/packages_and_registries/index.js index 3b922622d2c..d13bf026777 100644 --- a/app/assets/javascripts/pages/groups/settings/packages_and_registries/index.js +++ b/app/assets/javascripts/pages/groups/settings/packages_and_registries/index.js @@ -1,3 +1,6 @@ import bundle from '~/packages_and_registries/settings/group/bundle'; +import initSearchSettings from '~/search_settings'; bundle(); + +document.addEventListener('DOMContentLoaded', initSearchSettings); diff --git a/app/assets/javascripts/pages/groups/settings/repository/show/index.js b/app/assets/javascripts/pages/groups/settings/repository/show/index.js index a1bcf6dbf57..2c9867653de 100644 --- a/app/assets/javascripts/pages/groups/settings/repository/show/index.js +++ b/app/assets/javascripts/pages/groups/settings/repository/show/index.js @@ -1,9 +1,10 @@ import DueDateSelectors from '~/due_date_select'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; -document.addEventListener('DOMContentLoaded', () => { - // Initialize expandable settings panels - initSettingsPanels(); +// Initialize expandable settings panels +initSettingsPanels(); - new DueDateSelectors(); // eslint-disable-line no-new -}); +new DueDateSelectors(); // eslint-disable-line no-new + +initSearchSettings(); diff --git a/app/assets/javascripts/pages/groups/shared/group_details.js b/app/assets/javascripts/pages/groups/shared/group_details.js index 8c272e561db..9e75985c130 100644 --- a/app/assets/javascripts/pages/groups/shared/group_details.js +++ b/app/assets/javascripts/pages/groups/shared/group_details.js @@ -3,12 +3,8 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants'; import initInviteMembersBanner from '~/groups/init_invite_members_banner'; -import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; -import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import { getPagePath, getDashPath } from '~/lib/utils/common_utils'; import initNotificationsDropdown from '~/notifications'; -import notificationsDropdown from '~/notifications_dropdown'; -import NotificationsForm from '~/notifications_form'; import ProjectsList from '~/projects_list'; import GroupTabs from './group_tabs'; @@ -22,17 +18,10 @@ export default function initGroupDetails(actionName = 'show') { new GroupTabs({ parentEl: '.groups-listing', action }); new ShortcutsNavigation(); - new NotificationsForm(); - if (gon.features?.vueNotificationDropdown) { - initNotificationsDropdown(); - } else { - notificationsDropdown(); - } + initNotificationsDropdown(); new ProjectsList(); initInviteMembersBanner(); - initInviteMembersModal(); - initInviteMembersTrigger(); } diff --git a/app/assets/javascripts/pages/groups/show/index.js b/app/assets/javascripts/pages/groups/show/index.js index 82ee5ead83d..e4a84dd5eec 100644 --- a/app/assets/javascripts/pages/groups/show/index.js +++ b/app/assets/javascripts/pages/groups/show/index.js @@ -1,7 +1,5 @@ import leaveByUrl from '~/namespaces/leave_by_url'; import initGroupDetails from '../shared/group_details'; -document.addEventListener('DOMContentLoaded', () => { - leaveByUrl('group'); - initGroupDetails(); -}); +leaveByUrl('group'); +initGroupDetails(); diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js index 535fe5fa4eb..80bc32dd43f 100644 --- a/app/assets/javascripts/pages/profiles/index.js +++ b/app/assets/javascripts/pages/profiles/index.js @@ -3,21 +3,19 @@ import '~/profile/gl_crop'; import Profile from '~/profile/profile'; import initSearchSettings from '~/search_settings'; -document.addEventListener('DOMContentLoaded', () => { - // eslint-disable-next-line func-names - $(document).on('input.ssh_key', '#key_key', function () { - const $title = $('#key_title'); - const comment = $(this) - .val() - .match(/^\S+ \S+ (.+)\n?$/); +// eslint-disable-next-line func-names +$(document).on('input.ssh_key', '#key_key', function () { + const $title = $('#key_title'); + const comment = $(this) + .val() + .match(/^\S+ \S+ (.+)\n?$/); - // Extract the SSH Key title from its comment - if (comment && comment.length > 1) { - $title.val(comment[1]).change(); - } - }); + // Extract the SSH Key title from its comment + if (comment && comment.length > 1) { + $title.val(comment[1]).change(); + } +}); - new Profile(); // eslint-disable-line no-new +new Profile(); // eslint-disable-line no-new - initSearchSettings(); -}); +initSearchSettings(); diff --git a/app/assets/javascripts/pages/profiles/index/index.js b/app/assets/javascripts/pages/profiles/index/index.js deleted file mode 100644 index 586b3be8661..00000000000 --- a/app/assets/javascripts/pages/profiles/index/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import notificationsDropdown from '../../../notifications_dropdown'; -import NotificationsForm from '../../../notifications_form'; - -document.addEventListener('DOMContentLoaded', () => { - new NotificationsForm(); // eslint-disable-line no-new - notificationsDropdown(); -}); diff --git a/app/assets/javascripts/pages/profiles/notifications/show/index.js b/app/assets/javascripts/pages/profiles/notifications/show/index.js index 639f5deb72c..51ba6c7a01e 100644 --- a/app/assets/javascripts/pages/profiles/notifications/show/index.js +++ b/app/assets/javascripts/pages/profiles/notifications/show/index.js @@ -1,9 +1,5 @@ import initNotificationsDropdown from '~/notifications'; -import notificationsDropdown from '../../../../notifications_dropdown'; -import NotificationsForm from '../../../../notifications_form'; document.addEventListener('DOMContentLoaded', () => { - new NotificationsForm(); // eslint-disable-line no-new - notificationsDropdown(); initNotificationsDropdown(); }); diff --git a/app/assets/javascripts/pages/profiles/personal_access_tokens/index.js b/app/assets/javascripts/pages/profiles/personal_access_tokens/index.js index ae2209b0292..fdbfc35456f 100644 --- a/app/assets/javascripts/pages/profiles/personal_access_tokens/index.js +++ b/app/assets/javascripts/pages/profiles/personal_access_tokens/index.js @@ -1,3 +1,4 @@ -import initExpiresAtField from '~/access_tokens'; +import { initExpiresAtField, initProjectsField } from '~/access_tokens'; -document.addEventListener('DOMContentLoaded', initExpiresAtField); +initExpiresAtField(); +initProjectsField(); diff --git a/app/assets/javascripts/pages/projects/blob/edit/index.js b/app/assets/javascripts/pages/projects/blob/edit/index.js index 189053f3ed7..ed416610173 100644 --- a/app/assets/javascripts/pages/projects/blob/edit/index.js +++ b/app/assets/javascripts/pages/projects/blob/edit/index.js @@ -1,3 +1,3 @@ import initBlobBundle from '~/blob_edit/blob_bundle'; -document.addEventListener('DOMContentLoaded', initBlobBundle); +initBlobBundle(); diff --git a/app/assets/javascripts/pages/projects/blob/new/index.js b/app/assets/javascripts/pages/projects/blob/new/index.js index 189053f3ed7..ed416610173 100644 --- a/app/assets/javascripts/pages/projects/blob/new/index.js +++ b/app/assets/javascripts/pages/projects/blob/new/index.js @@ -1,3 +1,3 @@ import initBlobBundle from '~/blob_edit/blob_bundle'; -document.addEventListener('DOMContentLoaded', initBlobBundle); +initBlobBundle(); diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index 61ff1c95a38..10bac6d60c2 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -7,61 +7,59 @@ import initWebIdeLink from '~/pages/projects/shared/web_ide_link'; import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import '~/sourcegraph/load'; -document.addEventListener('DOMContentLoaded', () => { - new BlobViewer(); // eslint-disable-line no-new - initBlob(); +new BlobViewer(); // eslint-disable-line no-new +initBlob(); - const CommitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status'); - const statusLink = document.querySelector('.commit-actions .ci-status-link'); - if (statusLink) { - statusLink.remove(); - // eslint-disable-next-line no-new - new Vue({ - el: CommitPipelineStatusEl, - components: { - commitPipelineStatus, - }, - render(createElement) { - return createElement('commit-pipeline-status', { - props: { - endpoint: CommitPipelineStatusEl.dataset.endpoint, - }, - }); - }, - }); - } +const CommitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status'); +const statusLink = document.querySelector('.commit-actions .ci-status-link'); +if (statusLink) { + statusLink.remove(); + // eslint-disable-next-line no-new + new Vue({ + el: CommitPipelineStatusEl, + components: { + commitPipelineStatus, + }, + render(createElement) { + return createElement('commit-pipeline-status', { + props: { + endpoint: CommitPipelineStatusEl.dataset.endpoint, + }, + }); + }, + }); +} - initWebIdeLink({ el: document.getElementById('js-blob-web-ide-link') }); +initWebIdeLink({ el: document.getElementById('js-blob-web-ide-link') }); - GpgBadges.fetch(); +GpgBadges.fetch(); - const codeNavEl = document.getElementById('js-code-navigation'); +const codeNavEl = document.getElementById('js-code-navigation'); - if (codeNavEl) { - const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset; +if (codeNavEl) { + const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset; - // eslint-disable-next-line promise/catch-or-return - import('~/code_navigation').then((m) => - m.default({ - blobs: [{ path: blobPath, codeNavigationPath }], - definitionPathPrefix, - }), - ); - } + // eslint-disable-next-line promise/catch-or-return + import('~/code_navigation').then((m) => + m.default({ + blobs: [{ path: blobPath, codeNavigationPath }], + definitionPathPrefix, + }), + ); +} - const successPipelineEl = document.querySelector('.js-success-pipeline-modal'); +const successPipelineEl = document.querySelector('.js-success-pipeline-modal'); - if (successPipelineEl) { - // eslint-disable-next-line no-new - new Vue({ - el: successPipelineEl, - render(createElement) { - return createElement(PipelineTourSuccessModal, { - props: { - ...successPipelineEl.dataset, - }, - }); - }, - }); - } -}); +if (successPipelineEl) { + // eslint-disable-next-line no-new + new Vue({ + el: successPipelineEl, + render(createElement) { + return createElement(PipelineTourSuccessModal, { + props: { + ...successPipelineEl.dataset, + }, + }); + }, + }); +} diff --git a/app/assets/javascripts/pages/projects/boards/index.js b/app/assets/javascripts/pages/projects/boards/index.js index 3a06d0faa3e..bde0007ec6a 100644 --- a/app/assets/javascripts/pages/projects/boards/index.js +++ b/app/assets/javascripts/pages/projects/boards/index.js @@ -2,8 +2,6 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import initBoards from '~/boards'; import UsersSelect from '~/users_select'; -document.addEventListener('DOMContentLoaded', () => { - new UsersSelect(); // eslint-disable-line no-new - new ShortcutsNavigation(); // eslint-disable-line no-new - initBoards(); -}); +new UsersSelect(); // eslint-disable-line no-new +new ShortcutsNavigation(); // eslint-disable-line no-new +initBoards(); diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js index 623d0a10606..72861855c5a 100644 --- a/app/assets/javascripts/pages/projects/branches/index/index.js +++ b/app/assets/javascripts/pages/projects/branches/index/index.js @@ -2,8 +2,6 @@ import AjaxLoadingSpinner from '~/branches/ajax_loading_spinner'; import DeleteModal from '~/branches/branches_delete_modal'; import initDiverganceGraph from '~/branches/divergence_graph'; -document.addEventListener('DOMContentLoaded', () => { - AjaxLoadingSpinner.init(); - new DeleteModal(); // eslint-disable-line no-new - initDiverganceGraph(document.querySelector('.js-branch-list').dataset.divergingCountsEndpoint); -}); +AjaxLoadingSpinner.init(); +new DeleteModal(); // eslint-disable-line no-new +initDiverganceGraph(document.querySelector('.js-branch-list').dataset.divergingCountsEndpoint); diff --git a/app/assets/javascripts/pages/projects/branches/new/index.js b/app/assets/javascripts/pages/projects/branches/new/index.js index 13ff47d53c2..364223f1898 100644 --- a/app/assets/javascripts/pages/projects/branches/new/index.js +++ b/app/assets/javascripts/pages/projects/branches/new/index.js @@ -1,11 +1,8 @@ import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; -document.addEventListener( - 'DOMContentLoaded', - () => - new NewBranchForm( - $('.js-create-branch-form'), - JSON.parse(document.getElementById('availableRefs').innerHTML), - ), +// eslint-disable-next-line no-new +new NewBranchForm( + $('.js-create-branch-form'), + JSON.parse(document.getElementById('availableRefs').innerHTML), ); diff --git a/app/assets/javascripts/pages/projects/compare/show/index.js b/app/assets/javascripts/pages/projects/compare/show/index.js index f1cf9caa28b..549e596cb8d 100644 --- a/app/assets/javascripts/pages/projects/compare/show/index.js +++ b/app/assets/javascripts/pages/projects/compare/show/index.js @@ -1,6 +1,9 @@ import Diff from '~/diff'; import GpgBadges from '~/gpg_badges'; import initChangesDropdown from '~/init_changes_dropdown'; +import initCompareSelector from '~/projects/compare'; + +initCompareSelector(); document.addEventListener('DOMContentLoaded', () => { new Diff(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js b/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js index df58e9dd072..255d05b39be 100644 --- a/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js +++ b/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js @@ -1,3 +1,3 @@ -import initCycleAnalytics from '~/cycle_analytics/cycle_analytics_bundle'; +import initCycleAnalytics from '~/cycle_analytics'; document.addEventListener('DOMContentLoaded', initCycleAnalytics); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js index bbe84322462..43fd5375222 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-new */ + import Vue from 'vue'; import Vuex from 'vuex'; import EditUserList from '~/user_lists/components/edit_user_list.vue'; @@ -5,15 +7,13 @@ import createStore from '~/user_lists/store/edit'; Vue.use(Vuex); -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-edit-user-list'); - const { userListsDocsPath } = el.dataset; - return new Vue({ - el, - store: createStore(el.dataset), - provide: { userListsDocsPath }, - render(h) { - return h(EditUserList, {}); - }, - }); +const el = document.getElementById('js-edit-user-list'); +const { userListsDocsPath } = el.dataset; +new Vue({ + el, + store: createStore(el.dataset), + provide: { userListsDocsPath }, + render(h) { + return h(EditUserList, {}); + }, }); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js index 679f0af8efc..e855447d5ce 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-new */ + import Vue from 'vue'; import Vuex from 'vuex'; import NewUserList from '~/user_lists/components/new_user_list.vue'; @@ -5,18 +7,16 @@ import createStore from '~/user_lists/store/new'; Vue.use(Vuex); -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-new-user-list'); - const { userListsDocsPath, featureFlagsPath } = el.dataset; - return new Vue({ - el, - store: createStore(el.dataset), - provide: { - userListsDocsPath, - featureFlagsPath, - }, - render(h) { - return h(NewUserList); - }, - }); +const el = document.getElementById('js-new-user-list'); +const { userListsDocsPath, featureFlagsPath } = el.dataset; +new Vue({ + el, + store: createStore(el.dataset), + provide: { + userListsDocsPath, + featureFlagsPath, + }, + render(h) { + return h(NewUserList); + }, }); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js index bccd9dce2ec..2dca0ea7f29 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js @@ -1,18 +1,3 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import UserList from '~/user_lists/components/user_list.vue'; -import createStore from '~/user_lists/store/show'; +import featureFlagsUserListInit from '~/projects/feature_flags_user_lists/show/index'; -Vue.use(Vuex); - -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-edit-user-list'); - return new Vue({ - el, - store: createStore(el.dataset), - render(h) { - const { emptyStatePath } = el.dataset; - return h(UserList, { props: { emptyStatePath } }); - }, - }); -}); +featureFlagsUserListInit(); diff --git a/app/assets/javascripts/pages/projects/forks/new/components/app.vue b/app/assets/javascripts/pages/projects/forks/new/components/app.vue new file mode 100644 index 00000000000..02b357d389b --- /dev/null +++ b/app/assets/javascripts/pages/projects/forks/new/components/app.vue @@ -0,0 +1,72 @@ +<script> +import ForkForm from './fork_form.vue'; + +export default { + components: { + ForkForm, + }, + props: { + forkIllustration: { + type: String, + required: true, + }, + endpoint: { + type: String, + required: true, + }, + projectFullPath: { + type: String, + required: true, + }, + projectId: { + type: String, + required: true, + }, + projectName: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + projectDescription: { + type: String, + required: true, + }, + projectVisibility: { + type: String, + required: true, + }, + }, +}; +</script> + +<template> + <div class="row gl-mt-5"> + <div class="col-lg-3"> + <img :src="forkIllustration" /> + <h4 class="">{{ s__('ForkProject|Fork project') }}</h4> + <p> + {{ s__('ForkProject|A fork is a copy of a project.') }} + <br /> + {{ + s__( + 'ForkProject|Forking a repository allows you to make changes without affecting the original project.', + ) + }} + </p> + </div> + <div class="col-lg-9"> + <fork-form + :endpoint="endpoint" + :project-full-path="projectFullPath" + :project-id="projectId" + :project-name="projectName" + :project-path="projectPath" + :project-description="projectDescription" + :project-visibility="projectVisibility" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue new file mode 100644 index 00000000000..7112b23775d --- /dev/null +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue @@ -0,0 +1,304 @@ +<script> +import { + GlIcon, + GlLink, + GlForm, + GlFormInputGroup, + GlInputGroupText, + GlFormInput, + GlFormGroup, + GlFormTextarea, + GlButton, + GlFormRadio, + GlFormRadioGroup, + GlFormSelect, +} from '@gitlab/ui'; +import { buildApiUrl } from '~/api/api_utils'; +import createFlash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import csrf from '~/lib/utils/csrf'; +import { redirectTo } from '~/lib/utils/url_utility'; +import { s__ } from '~/locale'; + +const PRIVATE_VISIBILITY = 'private'; +const INTERNAL_VISIBILITY = 'internal'; +const PUBLIC_VISIBILITY = 'public'; + +const ALLOWED_VISIBILITY = { + private: [PRIVATE_VISIBILITY], + internal: [INTERNAL_VISIBILITY, PRIVATE_VISIBILITY], + public: [INTERNAL_VISIBILITY, PRIVATE_VISIBILITY, PUBLIC_VISIBILITY], +}; + +export default { + components: { + GlForm, + GlIcon, + GlLink, + GlButton, + GlFormInputGroup, + GlInputGroupText, + GlFormInput, + GlFormTextarea, + GlFormGroup, + GlFormRadio, + GlFormRadioGroup, + GlFormSelect, + }, + inject: { + newGroupPath: { + default: '', + }, + visibilityHelpPath: { + default: '', + }, + }, + props: { + endpoint: { + type: String, + required: true, + }, + projectFullPath: { + type: String, + required: true, + }, + projectId: { + type: String, + required: true, + }, + projectName: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + projectDescription: { + type: String, + required: true, + }, + projectVisibility: { + type: String, + required: true, + }, + }, + data() { + return { + isSaving: false, + namespaces: [], + selectedNamespace: {}, + fork: { + name: this.projectName, + slug: this.projectPath, + description: this.projectDescription, + visibility: this.projectVisibility, + }, + }; + }, + computed: { + projectUrl() { + return `${gon.gitlab_url}/`; + }, + projectAllowedVisibility() { + return ALLOWED_VISIBILITY[this.projectVisibility]; + }, + namespaceAllowedVisibility() { + return ( + ALLOWED_VISIBILITY[this.selectedNamespace.visibility] || + ALLOWED_VISIBILITY[PUBLIC_VISIBILITY] + ); + }, + visibilityLevels() { + return [ + { + text: s__('ForkProject|Private'), + value: PRIVATE_VISIBILITY, + icon: 'lock', + help: s__('ForkProject|The project can be accessed without any authentication.'), + disabled: this.isVisibilityLevelDisabled(PRIVATE_VISIBILITY), + }, + { + text: s__('ForkProject|Internal'), + value: INTERNAL_VISIBILITY, + icon: 'shield', + help: s__('ForkProject|The project can be accessed by any logged in user.'), + disabled: this.isVisibilityLevelDisabled(INTERNAL_VISIBILITY), + }, + { + text: s__('ForkProject|Public'), + value: PUBLIC_VISIBILITY, + icon: 'earth', + help: s__( + 'ForkProject|Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.', + ), + disabled: this.isVisibilityLevelDisabled(PUBLIC_VISIBILITY), + }, + ]; + }, + }, + watch: { + selectedNamespace(newVal) { + const { visibility } = newVal; + + if (this.projectAllowedVisibility.includes(visibility)) { + this.fork.visibility = visibility; + } + }, + }, + mounted() { + this.fetchNamespaces(); + }, + methods: { + async fetchNamespaces() { + const { data } = await axios.get(this.endpoint); + this.namespaces = data.namespaces; + }, + isVisibilityLevelDisabled(visibilityLevel) { + return !( + this.projectAllowedVisibility.includes(visibilityLevel) && + this.namespaceAllowedVisibility.includes(visibilityLevel) + ); + }, + async onSubmit() { + this.isSaving = true; + + const { projectId } = this; + const { name, slug, description, visibility } = this.fork; + const { id: namespaceId } = this.selectedNamespace; + + const postParams = { + id: projectId, + name, + namespace_id: namespaceId, + path: slug, + description, + visibility, + }; + + const forkProjectPath = `/api/:version/projects/:id/fork`; + const url = buildApiUrl(forkProjectPath).replace(':id', encodeURIComponent(this.projectId)); + + try { + const { data } = await axios.post(url, postParams); + redirectTo(data.web_url); + return; + } catch (error) { + createFlash({ message: error }); + } + }, + }, + csrf, +}; +</script> + +<template> + <gl-form method="POST" @submit.prevent="onSubmit"> + <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> + + <gl-form-group label="Project name" label-for="fork-name"> + <gl-form-input id="fork-name" v-model="fork.name" data-testid="fork-name-input" required /> + </gl-form-group> + + <div class="gl-md-display-flex"> + <div class="gl-flex-basis-half"> + <gl-form-group label="Project URL" label-for="fork-url" class="gl-md-mr-3"> + <gl-form-input-group> + <template #prepend> + <gl-input-group-text> + {{ projectUrl }} + </gl-input-group-text> + </template> + <gl-form-select + id="fork-url" + v-model="selectedNamespace" + data-testid="fork-url-input" + required + > + <template slot="first"> + <option :value="null" disabled>{{ s__('ForkProject|Select a namespace') }}</option> + </template> + <option v-for="namespace in namespaces" :key="namespace.id" :value="namespace"> + {{ namespace.name }} + </option> + </gl-form-select> + </gl-form-input-group> + </gl-form-group> + </div> + <div class="gl-flex-basis-half"> + <gl-form-group label="Project slug" label-for="fork-slug" class="gl-md-ml-3"> + <gl-form-input + id="fork-slug" + v-model="fork.slug" + data-testid="fork-slug-input" + required + /> + </gl-form-group> + </div> + </div> + + <p class="gl-mt-n5 gl-text-gray-500"> + {{ s__('ForkProject|Want to house several dependent projects under the same namespace?') }} + <gl-link :href="newGroupPath" target="_blank"> + {{ s__('ForkProject|Create a group') }} + </gl-link> + </p> + + <gl-form-group label="Project description (optional)" label-for="fork-description"> + <gl-form-textarea + id="fork-description" + v-model="fork.description" + data-testid="fork-description-textarea" + /> + </gl-form-group> + + <gl-form-group> + <label> + {{ s__('ForkProject|Visibility level') }} + <gl-link :href="visibilityHelpPath" target="_blank"> + <gl-icon name="question-o" /> + </gl-link> + </label> + <gl-form-radio-group + v-model="fork.visibility" + data-testid="fork-visibility-radio-group" + required + > + <gl-form-radio + v-for="{ text, value, icon, help, disabled } in visibilityLevels" + :key="value" + :value="value" + :disabled="disabled" + :data-testid="`radio-${value}`" + > + <div> + <gl-icon :name="icon" /> + <span>{{ text }}</span> + </div> + <template #help>{{ help }}</template> + </gl-form-radio> + </gl-form-radio-group> + </gl-form-group> + + <div class="gl-display-flex gl-justify-content-space-between gl-mt-8"> + <gl-button + type="submit" + category="primary" + variant="confirm" + data-testid="submit-button" + :loading="isSaving" + > + {{ s__('ForkProject|Fork project') }} + </gl-button> + <gl-button + type="reset" + class="gl-mr-3" + data-testid="cancel-button" + :disabled="isSaving" + :href="projectFullPath" + > + {{ s__('ForkProject|Cancel') }} + </gl-button> + </div> + </gl-form> +</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue index 46d1696b88b..88f4bba5e2a 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue @@ -11,6 +11,7 @@ import { } from '@gitlab/ui'; import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '~/groups/constants'; import csrf from '~/lib/utils/csrf'; +import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue'; export default { components: { @@ -20,6 +21,7 @@ export default { GlButton, GlTooltip, GlLink, + UserAccessRoleBadge, }, directives: { GlTooltip: GlTooltipDirective, @@ -72,7 +74,9 @@ export default { <template> <li :class="rowClass" class="group-row"> <div class="group-row-contents gl-display-flex gl-align-items-center gl-py-3 gl-pr-5"> - <div class="folder-toggle-wrap gl-mr-2 gl-display-flex gl-align-items-center"> + <div + class="folder-toggle-wrap gl-mr-3 gl-display-flex gl-align-items-center gl-text-gray-500" + > <gl-icon name="folder-o" /> </div> <gl-link @@ -84,12 +88,12 @@ export default { <div class="gl-min-w-0 gl-display-flex gl-flex-grow-1 gl-flex-shrink-1 gl-align-items-center"> <div class="gl-min-w-0 gl-flex-grow-1 flex-shrink-1"> <div class="title gl-display-flex gl-align-items-center gl-flex-wrap gl-mr-3"> - <gl-link :href="group.relative_path" class="gl-mt-3 gl-mr-3 gl-text-gray-900!">{{ - group.full_name - }}</gl-link> + <gl-link :href="group.relative_path" class="gl-mt-3 gl-mr-3 gl-text-gray-900!"> + {{ group.full_name }} + </gl-link> <gl-icon v-gl-tooltip.hover.bottom - class="gl-mr-0 gl-inline-flex gl-mt-3 text-secondary" + class="gl-display-inline-flex gl-mt-3 gl-mr-3 gl-text-gray-500" :name="visibilityIcon" :title="visibilityTooltip" /> @@ -99,11 +103,11 @@ export default { class="gl-display-none gl-sm-display-flex gl-mt-3 gl-mr-1" >{{ __('pending removal') }}</gl-badge > - <span v-if="group.permission" class="user-access-role gl-mt-3"> + <user-access-role-badge v-if="group.permission" class="gl-mt-3"> {{ group.permission }} - </span> + </user-access-role-badge> </div> - <div v-if="group.description" class="description"> + <div v-if="group.description" class="description gl-line-height-20"> <span v-safe-html="group.markdown_description"> </span> </div> </div> diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js index a018d7e0926..372967c8a1e 100644 --- a/app/assets/javascripts/pages/projects/forks/new/index.js +++ b/app/assets/javascripts/pages/projects/forks/new/index.js @@ -1,12 +1,52 @@ import Vue from 'vue'; +import App from './components/app.vue'; import ForkGroupsList from './components/fork_groups_list.vue'; -document.addEventListener('DOMContentLoaded', () => { - const mountElement = document.getElementById('fork-groups-mount-element'); +const mountElement = document.getElementById('fork-groups-mount-element'); +if (gon.features.forkProjectForm) { + const { + forkIllustration, + endpoint, + newGroupPath, + projectFullPath, + visibilityHelpPath, + projectId, + projectName, + projectPath, + projectDescription, + projectVisibility, + } = mountElement.dataset; + + // eslint-disable-next-line no-new + new Vue({ + el: mountElement, + provide: { + newGroupPath, + visibilityHelpPath, + }, + render(h) { + return h(App, { + props: { + forkIllustration, + endpoint, + newGroupPath, + projectFullPath, + visibilityHelpPath, + projectId, + projectName, + projectPath, + projectDescription, + projectVisibility, + }, + }); + }, + }); +} else { const { endpoint } = mountElement.dataset; - return new Vue({ + // eslint-disable-next-line no-new + new Vue({ el: mountElement, render(h) { return h(ForkGroupsList, { @@ -16,4 +56,4 @@ document.addEventListener('DOMContentLoaded', () => { }); }, }); -}); +} diff --git a/app/assets/javascripts/pages/projects/imports/show/index.js b/app/assets/javascripts/pages/projects/imports/show/index.js index d5f92baf054..8397826f8eb 100644 --- a/app/assets/javascripts/pages/projects/imports/show/index.js +++ b/app/assets/javascripts/pages/projects/imports/show/index.js @@ -1,5 +1,3 @@ import ProjectImport from '~/project_import'; -document.addEventListener('DOMContentLoaded', () => { - new ProjectImport(); // eslint-disable-line no-new -}); +new ProjectImport(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js index 525d90e162d..366f8dc61bc 100644 --- a/app/assets/javascripts/pages/projects/issues/index/index.js +++ b/app/assets/javascripts/pages/projects/issues/index/index.js @@ -2,9 +2,10 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; +import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons'; import initIssuableByEmail from '~/issuable/init_issuable_by_email'; import IssuableIndex from '~/issuable_index'; -import initIssuablesList from '~/issues_list'; +import initIssuablesList, { initIssuesListApp } from '~/issues_list'; import initManualOrdering from '~/manual_ordering'; import { FILTERED_SEARCH } from '~/pages/constants'; import { ISSUABLE_INDEX } from '~/pages/projects/constants'; @@ -26,3 +27,5 @@ new UsersSelect(); initManualOrdering(); initIssuablesList(); initIssuableByEmail(); +initCsvImportExportButtons(); +initIssuesListApp(); diff --git a/app/assets/javascripts/pages/projects/jobs/index/index.js b/app/assets/javascripts/pages/projects/jobs/index/index.js index 6a70d4cf26d..681d151b77f 100644 --- a/app/assets/javascripts/pages/projects/jobs/index/index.js +++ b/app/assets/javascripts/pages/projects/jobs/index/index.js @@ -1,19 +1,17 @@ import Vue from 'vue'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; -document.addEventListener('DOMContentLoaded', () => { - const remainingTimeElements = document.querySelectorAll('.js-remaining-time'); - remainingTimeElements.forEach( - (el) => - new Vue({ - el, - render(h) { - return h(GlCountdown, { - props: { - endDateString: el.dateTime, - }, - }); - }, - }), - ); -}); +const remainingTimeElements = document.querySelectorAll('.js-remaining-time'); +remainingTimeElements.forEach( + (el) => + new Vue({ + el, + render(h) { + return h(GlCountdown, { + props: { + endDateString: el.dateTime, + }, + }); + }, + }), +); diff --git a/app/assets/javascripts/pages/projects/labels/edit/index.js b/app/assets/javascripts/pages/projects/labels/edit/index.js index 83d6ac9fd14..3b7562deed9 100644 --- a/app/assets/javascripts/pages/projects/labels/edit/index.js +++ b/app/assets/javascripts/pages/projects/labels/edit/index.js @@ -1,3 +1,3 @@ import Labels from 'ee_else_ce/labels'; -document.addEventListener('DOMContentLoaded', () => new Labels()); +new Labels(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue index 0393793bfe1..32ca623ca45 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue @@ -1,11 +1,11 @@ <script> import { GlLink } from '@gitlab/ui'; -import { ACTION_TEXT } from '../constants'; +import { ACTION_LABELS } from '../constants'; export default { components: { GlLink }, i18n: { - ACTION_TEXT, + ACTION_LABELS, }, props: { actions: { @@ -18,9 +18,9 @@ export default { <template> <ul> <li v-for="(value, action) in actions" :key="action"> - <span v-if="value.completed">{{ $options.i18n.ACTION_TEXT[action] }}</span> + <span v-if="value.completed">{{ $options.i18n.ACTION_LABELS[action].title }}</span> <span v-else> - <gl-link :href="value.url">{{ $options.i18n.ACTION_TEXT[action] }}</gl-link> + <gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link> </span> </li> </ul> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue index 0393793bfe1..230054ff76e 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue @@ -1,11 +1,35 @@ <script> -import { GlLink } from '@gitlab/ui'; -import { ACTION_TEXT } from '../constants'; +import { GlProgressBar, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { ACTION_LABELS } from '../constants'; +import LearnGitlabInfoCard from './learn_gitlab_info_card.vue'; export default { - components: { GlLink }, + components: { LearnGitlabInfoCard, GlProgressBar, GlSprintf }, i18n: { - ACTION_TEXT, + title: s__('LearnGitLab|Learn GitLab'), + description: s__( + 'LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project.', + ), + percentageCompleted: s__(`LearnGitLab|%{percentage}%{percentSymbol} completed`), + workspace: { + title: s__('LearnGitLab|Set up your workspace'), + description: s__( + "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:", + ), + }, + plan: { + title: s__('LearnGitLab|Plan and execute'), + description: s__( + 'LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:', + ), + }, + deploy: { + title: s__('LearnGitLab|Deploy'), + description: s__( + 'LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:', + ), + }, }, props: { actions: { @@ -13,15 +37,76 @@ export default { type: Object, }, }, + maxValue: Object.keys(ACTION_LABELS).length, + methods: { + infoProps(action) { + return { + ...this.actions[action], + ...ACTION_LABELS[action], + }; + }, + progressValue() { + return Object.values(this.actions).filter((a) => a.completed).length; + }, + progressPercentage() { + return Math.round((this.progressValue() / this.$options.maxValue) * 100); + }, + }, }; </script> <template> - <ul> - <li v-for="(value, action) in actions" :key="action"> - <span v-if="value.completed">{{ $options.i18n.ACTION_TEXT[action] }}</span> - <span v-else> - <gl-link :href="value.url">{{ $options.i18n.ACTION_TEXT[action] }}</gl-link> - </span> - </li> - </ul> + <div> + <div class="row"> + <div class="gl-mb-7 col-md-8 col-lg-7"> + <h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1> + <p class="gl-text-gray-700 gl-mb-0">{{ $options.i18n.description }}</p> + </div> + </div> + + <div class="gl-mb-3"> + <p class="gl-text-gray-500 gl-mb-2" data-testid="completion-percentage"> + <gl-sprintf :message="$options.i18n.percentageCompleted"> + <template #percentage>{{ progressPercentage() }}</template> + <template #percentSymbol>%</template> + </gl-sprintf> + </p> + <gl-progress-bar :value="progressValue()" :max="$options.maxValue" /> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.workspace.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.workspace.description }}</p> + + <div class="row row-cols-2 row-cols-md-3 row-cols-lg-4"> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('userAdded')" /></div> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('gitWrite')" /></div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('pipelineCreated')" /> + </div> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('trialStarted')" /></div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('codeOwnersEnabled')" /> + </div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('requiredMrApprovalsEnabled')" /> + </div> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.plan.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.plan.description }}</p> + + <div class="row row-cols-2 row-cols-md-3 row-cols-lg-4"> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('mergeRequestCreated')" /> + </div> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.deploy.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.deploy.description }}</p> + + <div class="row row-cols-2 row-cols-lg-4 g-2 g-lg-3"> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('securityScanEnabled')" /> + </div> + </div> + </div> </template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue new file mode 100644 index 00000000000..3d2a8eed9d4 --- /dev/null +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue @@ -0,0 +1,70 @@ +<script> +import { GlLink, GlCard, GlIcon } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +export default { + name: 'LearnGitlabInfoCard', + components: { GlLink, GlCard, GlIcon }, + i18n: { + trial: s__('Learn GitLab|Trial only'), + }, + props: { + title: { + required: true, + type: String, + }, + description: { + required: true, + type: String, + }, + actionLabel: { + required: true, + type: String, + }, + url: { + required: true, + type: String, + }, + completed: { + required: true, + type: Boolean, + }, + svg: { + required: true, + type: String, + }, + trialRequired: { + default: false, + required: false, + type: Boolean, + }, + }, +}; +</script> +<template> + <gl-card class="gl-pt-0"> + <div class="gl-text-right gl-h-5"> + <gl-icon + v-if="completed" + name="check-circle-filled" + class="gl-text-green-500" + :size="16" + data-testid="completed-icon" + /> + <span + v-else-if="trialRequired" + class="gl-text-gray-500 gl-font-sm gl-font-style-italic" + data-testid="trial-only" + >{{ $options.i18n.trial }}</span + > + </div> + <div + class="gl-text-center gl-display-flex gl-justify-content-center gl-align-items-center gl-flex-direction-column learn-gitlab-info-card-content" + > + <img :src="svg" /> + <h6>{{ title }}</h6> + <p class="gl-font-sm gl-text-gray-700">{{ description }}</p> + <gl-link :href="url" target="_blank">{{ actionLabel }}</gl-link> + </div> + </gl-card> +</template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js index 8606af29785..80f04b0cf44 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js @@ -1,12 +1,50 @@ import { s__ } from '~/locale'; -export const ACTION_TEXT = { - gitWrite: s__('LearnGitLab|Create a repository'), - userAdded: s__('LearnGitLab|Invite your colleagues'), - pipelineCreated: s__('LearnGitLab|Set-up CI/CD'), - trialStarted: s__('LearnGitLab|Start a free trial of GitLab Gold'), - codeOwnersEnabled: s__('LearnGitLab|Add code owners'), - requiredMrApprovalsEnabled: s__('LearnGitLab|Enable require merge approvals'), - mergeRequestCreated: s__('LearnGitLab|Submit a merge request (MR)'), - securityScanEnabled: s__('LearnGitLab|Run a Security scan using CI/CD'), +export const ACTION_LABELS = { + gitWrite: { + title: s__('LearnGitLab|Create or import a repository'), + actionLabel: s__('LearnGitLab|Create or import a repository'), + description: s__('LearnGitLab|Create or import your first repository into your new project.'), + }, + userAdded: { + title: s__('LearnGitLab|Invite your colleagues'), + actionLabel: s__('LearnGitLab|Invite your colleagues'), + description: s__( + 'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.', + ), + }, + pipelineCreated: { + title: s__('LearnGitLab|Set up CI/CD'), + actionLabel: s__('LearnGitLab|Set-up CI/CD'), + description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'), + }, + trialStarted: { + title: s__('LearnGitLab|Start a free Ultimate trial'), + actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'), + description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'), + }, + codeOwnersEnabled: { + title: s__('LearnGitLab|Add code owners'), + actionLabel: s__('LearnGitLab|Add code owners'), + description: s__( + 'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.', + ), + trialRequired: true, + }, + requiredMrApprovalsEnabled: { + title: s__('LearnGitLab|Add merge request approval'), + actionLabel: s__('LearnGitLab|Enable require merge approvals'), + description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'), + trialRequired: true, + }, + mergeRequestCreated: { + title: s__('LearnGitLab|Submit a merge request'), + actionLabel: s__('LearnGitLab|Submit a merge request (MR)'), + description: s__('LearnGitLab|Review and edit proposed changes to source code.'), + }, + securityScanEnabled: { + title: s__('LearnGitLab|Run a security scan'), + actionLabel: s__('LearnGitLab|Run a Security scan'), + description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'), + }, }; diff --git a/app/assets/javascripts/pages/projects/logs/index.js b/app/assets/javascripts/pages/projects/logs/index.js index 36747069ebb..0cff1ffc27e 100644 --- a/app/assets/javascripts/pages/projects/logs/index.js +++ b/app/assets/javascripts/pages/projects/logs/index.js @@ -1,3 +1,3 @@ import logsBundle from '~/logs'; -document.addEventListener('DOMContentLoaded', logsBundle); +logsBundle(); diff --git a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js index 399aebb0c83..ec21d8c84e0 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js @@ -1,7 +1,5 @@ import initMergeRequest from '~/pages/projects/merge_requests/init_merge_request'; import initCheckFormState from './check_form_state'; -document.addEventListener('DOMContentLoaded', () => { - initMergeRequest(); - initCheckFormState(); -}); +initMergeRequest(); +initCheckFormState(); diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js index 76705256fe2..d279086df7b 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js @@ -1,6 +1,7 @@ import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; +import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons'; import initIssuableByEmail from '~/issuable/init_issuable_by_email'; import IssuableIndex from '~/issuable_index'; import { FILTERED_SEARCH } from '~/pages/constants'; @@ -22,3 +23,4 @@ new UsersSelect(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new initIssuableByEmail(); +initCsvImportExportButtons(); diff --git a/app/assets/javascripts/pages/projects/milestones/edit/index.js b/app/assets/javascripts/pages/projects/milestones/edit/index.js index 9a4ebf9890d..4f8514a9a1d 100644 --- a/app/assets/javascripts/pages/projects/milestones/edit/index.js +++ b/app/assets/javascripts/pages/projects/milestones/edit/index.js @@ -1,3 +1,3 @@ -import initForm from '../../../../shared/milestones/form'; +import initForm from '~/shared/milestones/form'; -document.addEventListener('DOMContentLoaded', () => initForm()); +initForm(); diff --git a/app/assets/javascripts/pages/projects/milestones/index/index.js b/app/assets/javascripts/pages/projects/milestones/index/index.js index 38789365a67..150b506b121 100644 --- a/app/assets/javascripts/pages/projects/milestones/index/index.js +++ b/app/assets/javascripts/pages/projects/milestones/index/index.js @@ -1,3 +1,3 @@ import milestones from '~/pages/milestones/shared'; -document.addEventListener('DOMContentLoaded', milestones); +milestones(); diff --git a/app/assets/javascripts/pages/projects/milestones/new/index.js b/app/assets/javascripts/pages/projects/milestones/new/index.js index 9a4ebf9890d..364b0d95d9c 100644 --- a/app/assets/javascripts/pages/projects/milestones/new/index.js +++ b/app/assets/javascripts/pages/projects/milestones/new/index.js @@ -1,3 +1,3 @@ import initForm from '../../../../shared/milestones/form'; -document.addEventListener('DOMContentLoaded', () => initForm()); +initForm(); diff --git a/app/assets/javascripts/pages/projects/milestones/show/index.js b/app/assets/javascripts/pages/projects/milestones/show/index.js index a853413e1f7..3c755e9b98c 100644 --- a/app/assets/javascripts/pages/projects/milestones/show/index.js +++ b/app/assets/javascripts/pages/projects/milestones/show/index.js @@ -1,7 +1,5 @@ import milestones from '~/pages/milestones/shared'; import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show'; -document.addEventListener('DOMContentLoaded', () => { - initMilestonesShow(); - milestones(); -}); +initMilestonesShow(); +milestones(); diff --git a/app/assets/javascripts/pages/projects/new/index.js b/app/assets/javascripts/pages/projects/new/index.js index 437594fdf11..e10e2872dce 100644 --- a/app/assets/javascripts/pages/projects/new/index.js +++ b/app/assets/javascripts/pages/projects/new/index.js @@ -3,28 +3,26 @@ import { __ } from '~/locale'; import initProjectVisibilitySelector from '../../../project_visibility'; import initProjectNew from '../../../projects/project_new'; -document.addEventListener('DOMContentLoaded', () => { - initProjectVisibilitySelector(); - initProjectNew.bindEvents(); +initProjectVisibilitySelector(); +initProjectNew.bindEvents(); - import( - /* webpackChunkName: 'experiment_new_project_creation' */ '../../../projects/experiment_new_project_creation' - ) - .then((m) => { - const el = document.querySelector('.js-experiment-new-project-creation'); +import( + /* webpackChunkName: 'experiment_new_project_creation' */ '../../../projects/experiment_new_project_creation' +) + .then((m) => { + const el = document.querySelector('.js-experiment-new-project-creation'); - if (!el) { - return; - } + if (!el) { + return; + } - const config = { - hasErrors: 'hasErrors' in el.dataset, - isCiCdAvailable: 'isCiCdAvailable' in el.dataset, - newProjectGuidelines: el.dataset.newProjectGuidelines, - }; - m.default(el, config); - }) - .catch(() => { - createFlash(__('An error occurred while loading project creation UI')); - }); -}); + const config = { + hasErrors: 'hasErrors' in el.dataset, + isCiCdAvailable: 'isCiCdAvailable' in el.dataset, + newProjectGuidelines: el.dataset.newProjectGuidelines, + }; + m.default(el, config); + }) + .catch(() => { + createFlash(__('An error occurred while loading project creation UI')); + }); diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js index ed11b07be4a..4aea5614bfb 100644 --- a/app/assets/javascripts/pages/projects/project_members/index.js +++ b/app/assets/javascripts/pages/projects/project_members/index.js @@ -1,11 +1,14 @@ import Vue from 'vue'; -import { deprecatedCreateFlash as flash } from '~/flash'; import groupsSelect from '~/groups_select'; +import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger'; +import initInviteMembersForm from '~/invite_members/init_invite_members_form'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; -import { __ } from '~/locale'; +import { s__ } from '~/locale'; import memberExpirationDate from '~/member_expiration_date'; -import Members from '~/members'; +import { initMembersApp } from '~/members'; +import { groupLinkRequestFormatter } from '~/members/utils'; +import { projectMemberRequestFormatter } from '~/projects/members/utils'; import UsersSelect from '~/users_select'; import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue'; @@ -29,68 +32,51 @@ memberExpirationDate('.js-access-expiration-date-groups'); mountRemoveMemberModal(); initInviteMembersModal(); initInviteMembersTrigger(); +initInviteGroupTrigger(); -new Members(); // eslint-disable-line no-new -new UsersSelect(); // eslint-disable-line no-new +// This is only used when `invite_members_group_modal` feature flag is disabled. +// This can be removed when `invite_members_group_modal` feature flag is removed. +initInviteMembersForm(); -if (window.gon.features.vueProjectMembersList) { - const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions']; +new UsersSelect(); // eslint-disable-line no-new - Promise.all([ - import('~/members/index'), - import('~/members/utils'), - import('~/projects/members/utils'), - import('~/locale'), - ]) - .then( - ([ - { initMembersApp }, - { groupLinkRequestFormatter }, - { projectMemberRequestFormatter }, - { s__ }, - ]) => { - initMembersApp(document.querySelector('.js-project-members-list'), { - tableFields: SHARED_FIELDS.concat(['source', 'granted']), - tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, - tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'], - requestFormatter: projectMemberRequestFormatter, - filteredSearchBar: { - show: true, - tokens: ['with_inherited_permissions'], - searchParam: 'search', - placeholder: s__('Members|Filter members'), - recentSearchesStorageKey: 'project_members', - }, - }); +const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions']; +initMembersApp(document.querySelector('.js-project-members-list'), { + tableFields: SHARED_FIELDS.concat(['source', 'granted']), + tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, + tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'], + requestFormatter: projectMemberRequestFormatter, + filteredSearchBar: { + show: true, + tokens: ['with_inherited_permissions'], + searchParam: 'search', + placeholder: s__('Members|Filter members'), + recentSearchesStorageKey: 'project_members', + }, +}); - initMembersApp(document.querySelector('.js-project-group-links-list'), { - tableFields: SHARED_FIELDS.concat('granted'), - tableAttrs: { - table: { 'data-qa-selector': 'groups_list' }, - tr: { 'data-qa-selector': 'group_row' }, - }, - requestFormatter: groupLinkRequestFormatter, - filteredSearchBar: { - show: true, - tokens: [], - searchParam: 'search_groups', - placeholder: s__('Members|Search groups'), - recentSearchesStorageKey: 'project_group_links', - }, - }); +initMembersApp(document.querySelector('.js-project-group-links-list'), { + tableFields: SHARED_FIELDS.concat('granted'), + tableAttrs: { + table: { 'data-qa-selector': 'groups_list' }, + tr: { 'data-qa-selector': 'group_row' }, + }, + requestFormatter: groupLinkRequestFormatter, + filteredSearchBar: { + show: true, + tokens: [], + searchParam: 'search_groups', + placeholder: s__('Members|Search groups'), + recentSearchesStorageKey: 'project_group_links', + }, +}); - initMembersApp(document.querySelector('.js-project-invited-members-list'), { - tableFields: SHARED_FIELDS.concat('invited'), - requestFormatter: projectMemberRequestFormatter, - }); +initMembersApp(document.querySelector('.js-project-invited-members-list'), { + tableFields: SHARED_FIELDS.concat('invited'), + requestFormatter: projectMemberRequestFormatter, +}); - initMembersApp(document.querySelector('.js-project-access-requests-list'), { - tableFields: SHARED_FIELDS.concat('requested'), - requestFormatter: projectMemberRequestFormatter, - }); - }, - ) - .catch(() => { - flash(__('An error occurred while loading the members, please try again.')); - }); -} +initMembersApp(document.querySelector('.js-project-access-requests-list'), { + tableFields: SHARED_FIELDS.concat('requested'), + requestFormatter: projectMemberRequestFormatter, +}); diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js index 2fd047675b9..82856c1c8b9 100644 --- a/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js @@ -1,3 +1,3 @@ -import customMetrics from '~/custom_metrics'; +import CustomMetrics from '~/custom_metrics'; -document.addEventListener('DOMContentLoaded', customMetrics); +CustomMetrics(); diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js index 2fd047675b9..82856c1c8b9 100644 --- a/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js @@ -1,3 +1,3 @@ -import customMetrics from '~/custom_metrics'; +import CustomMetrics from '~/custom_metrics'; -document.addEventListener('DOMContentLoaded', customMetrics); +CustomMetrics(); diff --git a/app/assets/javascripts/pages/projects/settings/access_tokens/index.js b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js index 22dddb72f98..dc1bb88bf4b 100644 --- a/app/assets/javascripts/pages/projects/settings/access_tokens/index.js +++ b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js @@ -1,3 +1,3 @@ -import initExpiresAtField from '~/access_tokens'; +import { initExpiresAtField } from '~/access_tokens'; initExpiresAtField(); diff --git a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js index be9259ec3ca..b7e8d4b03ac 100644 --- a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js @@ -6,6 +6,7 @@ import initDeployFreeze from '~/deploy_freeze'; import { initInstallRunner } from '~/pages/shared/mount_runner_instructions'; import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_toggle'; import registrySettingsApp from '~/registry/settings/registry_settings_bundle'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; document.addEventListener('DOMContentLoaded', () => { @@ -42,4 +43,6 @@ document.addEventListener('DOMContentLoaded', () => { } initInstallRunner(); + + initSearchSettings(); }); diff --git a/app/assets/javascripts/pages/projects/settings/operations/show/index.js b/app/assets/javascripts/pages/projects/settings/operations/show/index.js index 3a46241e2eb..4a800ab150d 100644 --- a/app/assets/javascripts/pages/projects/settings/operations/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/operations/show/index.js @@ -3,6 +3,7 @@ import mountErrorTrackingForm from '~/error_tracking_settings'; import mountGrafanaIntegration from '~/grafana_integration'; import initIncidentsSettings from '~/incidents_settings'; import mountOperationSettings from '~/operation_settings'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; initIncidentsSettings(); @@ -13,3 +14,7 @@ if (!IS_EE) { initSettingsPanels(); } mountAlertsSettings(document.querySelector('.js-alerts-settings')); + +document.addEventListener('DOMContentLoaded', () => { + initSearchSettings(); +}); diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/index.js b/app/assets/javascripts/pages/projects/settings/repository/show/index.js index e90954c14c5..c7bcbb83051 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js @@ -1,4 +1,5 @@ import MirrorRepos from '~/mirrors/mirror_repos'; +import initSearchSettings from '~/search_settings'; import initForm from '../form'; document.addEventListener('DOMContentLoaded', () => { @@ -6,4 +7,6 @@ document.addEventListener('DOMContentLoaded', () => { const mirrorReposContainer = document.querySelector('.js-mirror-settings'); if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init(); + + initSearchSettings(); }); diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index 94a9bc168e5..0b58cb4731d 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -11,6 +11,7 @@ import { featureAccessLevelEveryone, featureAccessLevel, featureAccessLevelNone, + CVE_ID_REQUEST_BUTTON_I18N, } from '../constants'; import { toggleHiddenClassBySelector } from '../external'; import projectFeatureSetting from './project_feature_setting.vue'; @@ -19,6 +20,10 @@ import projectSettingRow from './project_setting_row.vue'; const PAGE_FEATURE_ACCESS_LEVEL = s__('ProjectSettings|Everyone'); export default { + i18n: { + ...CVE_ID_REQUEST_BUTTON_I18N, + }, + components: { projectFeatureSetting, projectSettingRow, @@ -31,6 +36,11 @@ export default { mixins: [settingsMixin, glFeatureFlagsMixin()], props: { + requestCveAvailable: { + type: Boolean, + required: false, + default: false, + }, currentSettings: { type: Object, required: true, @@ -74,11 +84,6 @@ export default { required: false, default: false, }, - securityAndComplianceAvailable: { - type: Boolean, - required: false, - default: false, - }, visibilityHelpPath: { type: String, required: false, @@ -99,6 +104,11 @@ export default { required: false, default: '', }, + cveIdRequestHelpPath: { + type: String, + required: false, + default: '', + }, registryHelpPath: { type: String, required: false, @@ -152,6 +162,7 @@ export default { requestAccessEnabled: true, highlightChangesClass: false, emailsDisabled: false, + cveIdRequestEnabled: true, featureAccessLevelEveryone, featureAccessLevelMembers, }; @@ -230,6 +241,9 @@ export default { 'ProjectSettings|View and edit files in this project. Non-project members will only have read access.', ); }, + cveIdRequestIsDisabled() { + return this.visibilityLevel !== visibilityOptions.PUBLIC; + }, }, watch: { @@ -417,6 +431,19 @@ export default { :options="featureAccessLevelOptions" name="project[project_feature_attributes][issues_access_level]" /> + <project-setting-row + v-if="requestCveAvailable" + :help-path="cveIdRequestHelpPath" + :help-text="$options.i18n.cve_request_toggle_label" + > + <gl-toggle + v-model="cveIdRequestEnabled" + class="gl-my-2" + :disabled="cveIdRequestIsDisabled" + name="project[project_setting_attributes][cve_id_request_enabled]" + data-testid="cve_id_request_toggle" + /> + </project-setting-row> </project-setting-row> <project-setting-row ref="repository-settings" @@ -563,7 +590,6 @@ export default { /> </project-setting-row> <project-setting-row - v-if="securityAndComplianceAvailable" :label="s__('ProjectSettings|Security & Compliance')" :help-text="s__('ProjectSettings|Security & Compliance for this project')" > @@ -613,7 +639,9 @@ export default { <project-setting-row ref="operations-settings" :label="s__('ProjectSettings|Operations')" - :help-text="s__('ProjectSettings|Environments, logs, cluster management, and more.')" + :help-text=" + s__('ProjectSettings|Configure your project resources and monitor their health.') + " > <project-feature-setting v-model="operationsAccessLevel" diff --git a/app/assets/javascripts/pages/projects/shared/permissions/constants.js b/app/assets/javascripts/pages/projects/shared/permissions/constants.js index 6771391254e..e160fdacca6 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/constants.js +++ b/app/assets/javascripts/pages/projects/shared/permissions/constants.js @@ -1,4 +1,4 @@ -import { __ } from '~/locale'; +import { s__, __ } from '~/locale'; export const visibilityOptions = { PRIVATE: 0, @@ -42,3 +42,7 @@ export const featureAccessLevelEveryone = [ featureAccessLevel.EVERYONE, featureAccessLevelDescriptions[featureAccessLevel.EVERYONE], ]; + +export const CVE_ID_REQUEST_BUTTON_I18N = { + cve_request_toggle_label: s__('CVE|Enable CVE ID requests in the issue sidebar'), +}; diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 0494dad6e33..83e43d7ac48 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -3,20 +3,16 @@ import Activities from '~/activities'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import BlobViewer from '~/blob/viewer/index'; import { initUploadForm } from '~/blob_edit/blob_bundle'; -import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; -import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import leaveByUrl from '~/namespaces/leave_by_url'; import initVueNotificationsDropdown from '~/notifications'; -import NotificationsForm from '~/notifications_form'; +import { initUploadFileTrigger } from '~/projects/upload_file_experiment'; import initReadMore from '~/read_more'; import UserCallout from '~/user_callout'; -import notificationsDropdown from '../../../notifications_dropdown'; import Star from '../../../star'; initReadMore(); new Star(); // eslint-disable-line no-new -new NotificationsForm(); // eslint-disable-line no-new // eslint-disable-next-line no-new new UserCallout({ setCalloutPerProject: false, @@ -24,9 +20,12 @@ new UserCallout({ }); // Project show page loads different overview content based on user preferences -const treeSlider = document.getElementById('js-tree-list'); -if (treeSlider) { + +if (document.querySelector('.js-upload-blob-form')) { initUploadForm(); +} + +if (document.getElementById('js-tree-list')) { initTree(); } @@ -40,15 +39,8 @@ if (document.querySelector('.project-show-activity')) { leaveByUrl('project'); -if (gon.features?.vueNotificationDropdown) { - initVueNotificationsDropdown(); -} else { - notificationsDropdown(); -} - initVueNotificationsDropdown(); new ShortcutsNavigation(); // eslint-disable-line no-new -initInviteMembersTrigger(); -initInviteMembersModal(); +initUploadFileTrigger(); diff --git a/app/assets/javascripts/pages/projects/tags/new/index.js b/app/assets/javascripts/pages/projects/tags/new/index.js index 11a19a673b1..b071e7a45fc 100644 --- a/app/assets/javascripts/pages/projects/tags/new/index.js +++ b/app/assets/javascripts/pages/projects/tags/new/index.js @@ -3,8 +3,6 @@ import GLForm from '../../../../gl_form'; import RefSelectDropdown from '../../../../ref_select_dropdown'; import ZenMode from '../../../../zen_mode'; -document.addEventListener('DOMContentLoaded', () => { - new ZenMode(); // eslint-disable-line no-new - new GLForm($('.tag-form')); // eslint-disable-line no-new - new RefSelectDropdown($('.js-branch-select')); // eslint-disable-line no-new -}); +new ZenMode(); // eslint-disable-line no-new +new GLForm($('.tag-form')); // eslint-disable-line no-new +new RefSelectDropdown($('.js-branch-select')); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/tags/releases/index.js b/app/assets/javascripts/pages/projects/tags/releases/index.js index abdc97f62d0..cafd880b4be 100644 --- a/app/assets/javascripts/pages/projects/tags/releases/index.js +++ b/app/assets/javascripts/pages/projects/tags/releases/index.js @@ -2,7 +2,5 @@ import $ from 'jquery'; import GLForm from '~/gl_form'; import ZenMode from '~/zen_mode'; -document.addEventListener('DOMContentLoaded', () => { - new ZenMode(); // eslint-disable-line no-new - new GLForm($('.release-form')); // eslint-disable-line no-new -}); +new ZenMode(); // eslint-disable-line no-new +new GLForm($('.release-form')); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/search/show/index.js b/app/assets/javascripts/pages/search/show/index.js index a8c288c3663..2ee33584ee1 100644 --- a/app/assets/javascripts/pages/search/show/index.js +++ b/app/assets/javascripts/pages/search/show/index.js @@ -1,5 +1,3 @@ import { initSearchApp } from '~/search'; -document.addEventListener('DOMContentLoaded', () => { - initSearchApp(); -}); +initSearchApp(); diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_alert.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_alert.vue new file mode 100644 index 00000000000..6cea26f2bed --- /dev/null +++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_alert.vue @@ -0,0 +1,31 @@ +<script> +import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui'; + +export default { + components: { + GlAlert, + GlLink, + GlSprintf, + }, + props: { + error: { + type: String, + required: true, + }, + wikiPagePath: { + type: String, + required: true, + }, + }, +}; +</script> + +<template> + <gl-alert variant="danger" :dismissible="false"> + <gl-sprintf :message="error"> + <template #wikiLink="{ content }"> + <gl-link :href="wikiPagePath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </gl-alert> +</template> diff --git a/app/assets/javascripts/pages/shared/wikis/index.js b/app/assets/javascripts/pages/shared/wikis/index.js index c8dc75828e4..c382a372260 100644 --- a/app/assets/javascripts/pages/shared/wikis/index.js +++ b/app/assets/javascripts/pages/shared/wikis/index.js @@ -6,9 +6,10 @@ import Translate from '~/vue_shared/translate'; import GLForm from '../../../gl_form'; import ZenMode from '../../../zen_mode'; import deleteWikiModal from './components/delete_wiki_modal.vue'; +import wikiAlert from './components/wiki_alert.vue'; import Wikis from './wikis'; -export default () => { +const createModalVueApp = () => { new Wikis(); // eslint-disable-line no-new new ShortcutsWiki(); // eslint-disable-line no-new new ZenMode(); // eslint-disable-line no-new @@ -39,3 +40,28 @@ export default () => { }); } }; + +const createAlertVueApp = () => { + const el = document.getElementById('js-wiki-error'); + if (el) { + const { error, wikiPagePath } = el.dataset; + + // eslint-disable-next-line no-new + new Vue({ + el, + render(createElement) { + return createElement(wikiAlert, { + props: { + error, + wikiPagePath, + }, + }); + }, + }); + } +}; + +export default () => { + createModalVueApp(); + createAlertVueApp(); +}; diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js index b22287a0093..58ceb524360 100644 --- a/app/assets/javascripts/pages/users/index.js +++ b/app/assets/javascripts/pages/users/index.js @@ -15,9 +15,7 @@ function initUserProfile(action) { }); } -document.addEventListener('DOMContentLoaded', () => { - const page = $('body').attr('data-page'); - const action = page.split(':')[1]; - initUserProfile(action); - new UserCallout(); // eslint-disable-line no-new -}); +const page = $('body').attr('data-page'); +const action = page.split(':')[1]; +initUserProfile(action); +new UserCallout(); // eslint-disable-line no-new |