Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
commitd9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch)
tree2341ef426af70ad1e289c38036737e04b0aa5007 /app/assets/javascripts/pages
parentd6e514dd13db8947884cd58fe2a9c2a063400a9b (diff)
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/assets/javascripts/pages')
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/usage_statistics.js2
-rw-r--r--app/assets/javascripts/pages/admin/projects/components/namespace_select.vue143
-rw-r--r--app/assets/javascripts/pages/admin/projects/index.js38
-rw-r--r--app/assets/javascripts/pages/admin/serverless/domains/index.js17
-rw-r--r--app/assets/javascripts/pages/admin/topics/edit/index.js8
-rw-r--r--app/assets/javascripts/pages/admin/topics/new/index.js8
-rw-r--r--app/assets/javascripts/pages/groups/dependency_proxies/index.js14
-rw-r--r--app/assets/javascripts/pages/groups/group_members/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/packages/index/index.js13
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue176
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/index.js15
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/utils/error_messages.js3
-rw-r--r--app/assets/javascripts/pages/profiles/index.js2
-rw-r--r--app/assets/javascripts/pages/profiles/password_prompt/constants.js9
-rw-r--r--app/assets/javascripts/pages/profiles/password_prompt/index.js58
-rw-r--r--app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue82
-rw-r--r--app/assets/javascripts/pages/projects/cluster_agents/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/clusters/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/new/components/app.vue124
-rw-r--r--app/assets/javascripts/pages/projects/new/components/new_project_push_tip_popover.vue66
-rw-r--r--app/assets/javascripts/pages/projects/new/components/new_project_url_select.vue98
-rw-r--r--app/assets/javascripts/pages/projects/new/index.js66
-rw-r--r--app/assets/javascripts/pages/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql14
-rw-r--r--app/assets/javascripts/pages/projects/packages/packages/index/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js34
-rw-r--r--app/assets/javascripts/pages/projects/project_members/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/wikis/diff/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/wikis/edit/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/wikis/git_access/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/wikis/show/index.js3
-rw-r--r--app/assets/javascripts/pages/sessions/new/oauth_remember_me.js2
-rw-r--r--app/assets/javascripts/pages/shared/mount_runner_instructions.js7
-rw-r--r--app/assets/javascripts/pages/shared/wikis/async_edit.js11
-rw-r--r--app/assets/javascripts/pages/shared/wikis/edit.js (renamed from app/assets/javascripts/pages/shared/wikis/index.js)12
-rw-r--r--app/assets/javascripts/pages/shared/wikis/wikis.js6
36 files changed, 629 insertions, 437 deletions
diff --git a/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/usage_statistics.js b/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/usage_statistics.js
index 4c312a008cb..68849857d0f 100644
--- a/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/usage_statistics.js
+++ b/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/usage_statistics.js
@@ -1,7 +1,7 @@
import { __ } from '~/locale';
export const HELPER_TEXT_SERVICE_PING_DISABLED = __(
- 'To enable Registration Features, make sure "Enable service ping" is checked.',
+ 'To enable Registration Features, first enable Service Ping.',
);
export const HELPER_TEXT_SERVICE_PING_ENABLED = __(
diff --git a/app/assets/javascripts/pages/admin/projects/components/namespace_select.vue b/app/assets/javascripts/pages/admin/projects/components/namespace_select.vue
new file mode 100644
index 00000000000..c75c031b0b1
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/projects/components/namespace_select.vue
@@ -0,0 +1,143 @@
+<script>
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ GlSearchBoxByType,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import Api from '~/api';
+import { __ } from '~/locale';
+
+export default {
+ i18n: {
+ dropdownHeader: __('Namespaces'),
+ searchPlaceholder: __('Search for Namespace'),
+ anyNamespace: __('Any namespace'),
+ },
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+ },
+ props: {
+ showAny: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ placeholder: {
+ type: String,
+ required: false,
+ default: __('Namespace'),
+ },
+ fieldName: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ namespaceOptions: [],
+ selectedNamespaceId: null,
+ selectedNamespace: null,
+ searchTerm: '',
+ isLoading: false,
+ };
+ },
+ computed: {
+ selectedNamespaceName() {
+ if (this.selectedNamespaceId === null) {
+ return this.placeholder;
+ }
+ return this.selectedNamespace;
+ },
+ },
+ watch: {
+ searchTerm() {
+ this.fetchNamespaces(this.searchTerm);
+ },
+ },
+ mounted() {
+ this.fetchNamespaces();
+ },
+ methods: {
+ fetchNamespaces(filter) {
+ this.isLoading = true;
+ this.namespaceOptions = [];
+ return Api.namespaces(filter, (namespaces) => {
+ this.namespaceOptions = namespaces;
+ this.isLoading = false;
+ });
+ },
+ selectNamespace(key) {
+ this.selectedNamespaceId = this.namespaceOptions[key].id;
+ this.selectedNamespace = this.getNamespaceString(this.namespaceOptions[key]);
+ this.$emit('setNamespace', this.selectedNamespaceId);
+ },
+ selectAnyNamespace() {
+ this.selectedNamespaceId = null;
+ this.selectedNamespace = null;
+ this.$emit('setNamespace', null);
+ },
+ getNamespaceString(namespace) {
+ return `${namespace.kind}: ${namespace.full_path}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex">
+ <input
+ v-if="fieldName"
+ :name="fieldName"
+ :value="selectedNamespaceId"
+ type="hidden"
+ data-testid="hidden-input"
+ />
+ <gl-dropdown
+ :text="selectedNamespaceName"
+ :header-text="$options.i18n.dropdownHeader"
+ toggle-class="dropdown-menu-toggle large"
+ data-testid="namespace-dropdown"
+ :right="true"
+ >
+ <template #header>
+ <gl-search-box-by-type
+ v-model.trim="searchTerm"
+ class="namespace-search-box"
+ debounce="250"
+ :placeholder="$options.i18n.searchPlaceholder"
+ />
+ </template>
+
+ <template v-if="showAny">
+ <gl-dropdown-item @click="selectAnyNamespace">
+ {{ $options.i18n.anyNamespace }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ </template>
+
+ <gl-loading-icon v-if="isLoading" />
+
+ <gl-dropdown-item
+ v-for="(namespace, key) in namespaceOptions"
+ :key="namespace.id"
+ @click="selectNamespace(key)"
+ >
+ {{ getNamespaceString(namespace) }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
+</template>
+
+<style scoped>
+/* workaround position: relative imposed by .top-area .nav-controls */
+.namespace-search-box >>> input {
+ position: static;
+}
+</style>
diff --git a/app/assets/javascripts/pages/admin/projects/index.js b/app/assets/javascripts/pages/admin/projects/index.js
index b07ca815f13..3098d06510b 100644
--- a/app/assets/javascripts/pages/admin/projects/index.js
+++ b/app/assets/javascripts/pages/admin/projects/index.js
@@ -1,8 +1,38 @@
-import NamespaceSelect from '~/namespace_select';
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import { mergeUrlParams } from '~/lib/utils/url_utility';
import ProjectsList from '~/projects_list';
+import NamespaceSelect from './components/namespace_select.vue';
new ProjectsList(); // eslint-disable-line no-new
-document
- .querySelectorAll('.js-namespace-select')
- .forEach((dropdown) => new NamespaceSelect({ dropdown }));
+function mountNamespaceSelect() {
+ const el = document.querySelector('.js-namespace-select');
+ if (!el) {
+ return false;
+ }
+
+ const { showAny, fieldName, placeholder, updateLocation } = el.dataset;
+
+ return new Vue({
+ el,
+ render(createComponent) {
+ return createComponent(NamespaceSelect, {
+ props: {
+ showAny: parseBoolean(showAny),
+ fieldName,
+ placeholder,
+ },
+ on: {
+ setNamespace(newNamespace) {
+ if (fieldName && updateLocation) {
+ window.location = mergeUrlParams({ [fieldName]: newNamespace }, window.location.href);
+ }
+ },
+ },
+ });
+ },
+ });
+}
+
+mountNamespaceSelect();
diff --git a/app/assets/javascripts/pages/admin/serverless/domains/index.js b/app/assets/javascripts/pages/admin/serverless/domains/index.js
deleted file mode 100644
index 4fab7a1d9cb..00000000000
--- a/app/assets/javascripts/pages/admin/serverless/domains/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import initSettingsPanels from '~/settings_panels';
-
-// Initialize expandable settings panels
-initSettingsPanels();
-
-const domainCard = document.querySelector('.js-domain-cert-show');
-const domainForm = document.querySelector('.js-domain-cert-inputs');
-const domainReplaceButton = document.querySelector('.js-domain-cert-replace-btn');
-const domainSubmitButton = document.querySelector('.js-serverless-domain-submit');
-
-if (domainReplaceButton && domainCard && domainForm) {
- domainReplaceButton.addEventListener('click', () => {
- domainCard.classList.add('hidden');
- domainForm.classList.remove('hidden');
- domainSubmitButton.removeAttribute('disabled');
- });
-}
diff --git a/app/assets/javascripts/pages/admin/topics/edit/index.js b/app/assets/javascripts/pages/admin/topics/edit/index.js
new file mode 100644
index 00000000000..c4e05bbd092
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/topics/edit/index.js
@@ -0,0 +1,8 @@
+import $ from 'jquery';
+import GLForm from '~/gl_form';
+import initFilePickers from '~/file_pickers';
+import ZenMode from '~/zen_mode';
+
+new GLForm($('.js-project-topic-form')); // eslint-disable-line no-new
+initFilePickers();
+new ZenMode(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/topics/new/index.js b/app/assets/javascripts/pages/admin/topics/new/index.js
new file mode 100644
index 00000000000..c4e05bbd092
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/topics/new/index.js
@@ -0,0 +1,8 @@
+import $ from 'jquery';
+import GLForm from '~/gl_form';
+import initFilePickers from '~/file_pickers';
+import ZenMode from '~/zen_mode';
+
+new GLForm($('.js-project-topic-form')); // eslint-disable-line no-new
+initFilePickers();
+new ZenMode(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/groups/dependency_proxies/index.js b/app/assets/javascripts/pages/groups/dependency_proxies/index.js
index 77c885d3858..862ba468296 100644
--- a/app/assets/javascripts/pages/groups/dependency_proxies/index.js
+++ b/app/assets/javascripts/pages/groups/dependency_proxies/index.js
@@ -1,13 +1,3 @@
-import $ from 'jquery';
-import initDependencyProxy from '~/dependency_proxy';
+import { initDependencyProxyApp } from '~/packages_and_registries/dependency_proxy/';
-initDependencyProxy();
-
-const form = document.querySelector('form.edit_dependency_proxy_group_setting');
-const toggleInput = $('input.js-project-feature-toggle-input');
-
-if (form && toggleInput) {
- toggleInput.on('trigger-change', () => {
- form.submit();
- });
-}
+initDependencyProxyApp();
diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js
index 0137ff87979..01a371920f8 100644
--- a/app/assets/javascripts/pages/groups/group_members/index.js
+++ b/app/assets/javascripts/pages/groups/group_members/index.js
@@ -11,7 +11,7 @@ import { MEMBER_TYPES } from '~/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
import UsersSelect from '~/users_select';
-const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
+const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-group-members-list-app'), {
[MEMBER_TYPES.user]: {
diff --git a/app/assets/javascripts/pages/groups/packages/index/index.js b/app/assets/javascripts/pages/groups/packages/index/index.js
index 1c4a10fd653..95522573b53 100644
--- a/app/assets/javascripts/pages/groups/packages/index/index.js
+++ b/app/assets/javascripts/pages/groups/packages/index/index.js
@@ -1,5 +1,10 @@
-import initPackageList from '~/packages/list/packages_list_app_bundle';
+(async function packageApp() {
+ if (window.gon.features.packageListApollo) {
+ const newPackageList = await import('~/packages_and_registries/package_registry/pages/list');
-if (document.getElementById('js-vue-packages-list')) {
- initPackageList();
-}
+ newPackageList.default();
+ } else {
+ const packageList = await import('~/packages/list/packages_list_app_bundle');
+ packageList.default();
+ }
+})();
diff --git a/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
new file mode 100644
index 00000000000..ec3cf4a8a92
--- /dev/null
+++ b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
@@ -0,0 +1,176 @@
+<script>
+import { GlButton, GlEmptyState, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
+
+import { s__, __ } from '~/locale';
+import createFlash from '~/flash';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
+import { joinPaths } from '~/lib/utils/url_utility';
+import { getBulkImportsHistory } from '~/rest_api';
+import ImportStatus from '~/import_entities/components/import_status.vue';
+import PaginationBar from '~/import_entities/components/pagination_bar.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import { DEFAULT_ERROR } from '../utils/error_messages';
+
+const DEFAULT_PER_PAGE = 20;
+const DEFAULT_TH_CLASSES =
+ 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-200! gl-border-b-1! gl-p-5!';
+
+const tableCell = (config) => ({
+ thClass: `${DEFAULT_TH_CLASSES}`,
+ tdClass: (value, key, item) => {
+ return {
+ // eslint-disable-next-line no-underscore-dangle
+ 'gl-border-b-0!': item._showDetails,
+ };
+ },
+ ...config,
+});
+
+export default {
+ components: {
+ GlButton,
+ GlEmptyState,
+ GlLink,
+ GlLoadingIcon,
+ GlTable,
+ PaginationBar,
+ ImportStatus,
+ TimeAgo,
+ },
+
+ data() {
+ return {
+ loading: true,
+ historyItems: [],
+ paginationConfig: {
+ page: 1,
+ perPage: DEFAULT_PER_PAGE,
+ },
+ pageInfo: {},
+ };
+ },
+
+ fields: [
+ tableCell({
+ key: 'source_full_path',
+ label: s__('BulkImport|Source group'),
+ thClass: `${DEFAULT_TH_CLASSES} gl-w-30p`,
+ }),
+ tableCell({
+ key: 'destination_name',
+ label: s__('BulkImport|New group'),
+ thClass: `${DEFAULT_TH_CLASSES} gl-w-40p`,
+ }),
+ tableCell({
+ key: 'created_at',
+ label: __('Date'),
+ }),
+ tableCell({
+ key: 'status',
+ label: __('Status'),
+ tdAttr: { 'data-qa-selector': 'import_status_indicator' },
+ }),
+ ],
+
+ computed: {
+ hasHistoryItems() {
+ return this.historyItems.length > 0;
+ },
+ },
+
+ watch: {
+ paginationConfig: {
+ handler() {
+ this.loadHistoryItems();
+ },
+ deep: true,
+ immediate: true,
+ },
+ },
+
+ methods: {
+ async loadHistoryItems() {
+ try {
+ this.loading = true;
+ const { data: historyItems, headers } = await getBulkImportsHistory({
+ page: this.paginationConfig.page,
+ per_page: this.paginationConfig.perPage,
+ });
+ this.pageInfo = parseIntPagination(normalizeHeaders(headers));
+ this.historyItems = historyItems;
+ } catch (e) {
+ createFlash({ message: DEFAULT_ERROR, captureError: true, error: e });
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ getDestinationUrl({ destination_name: name, destination_namespace: namespace }) {
+ return [namespace, name].filter(Boolean).join('/');
+ },
+
+ getFullDestinationUrl(params) {
+ return joinPaths(gon.relative_url_root || '', this.getDestinationUrl(params));
+ },
+ },
+
+ gitlabLogo: window.gon.gitlab_logo,
+};
+</script>
+
+<template>
+ <div>
+ <div
+ class="gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-display-flex gl-align-items-center"
+ >
+ <h1 class="gl-my-0 gl-py-4 gl-font-size-h1">
+ <img :src="$options.gitlabLogo" class="gl-w-6 gl-h-6 gl-mb-2 gl-display-inline gl-mr-2" />
+ {{ s__('BulkImport|Group import history') }}
+ </h1>
+ </div>
+ <gl-loading-icon v-if="loading" size="md" class="gl-mt-5" />
+ <gl-empty-state
+ v-else-if="!hasHistoryItems"
+ :title="s__('BulkImport|No history is available')"
+ :description="s__('BulkImport|Your imported groups will appear here.')"
+ />
+ <template v-else>
+ <gl-table
+ :fields="$options.fields"
+ :items="historyItems"
+ data-qa-selector="import_history_table"
+ class="gl-w-full"
+ >
+ <template #cell(destination_name)="{ item }">
+ <gl-link :href="getFullDestinationUrl(item)" target="_blank">
+ {{ getDestinationUrl(item) }}
+ </gl-link>
+ </template>
+ <template #cell(created_at)="{ value }">
+ <time-ago :time="value" />
+ </template>
+ <template #cell(status)="{ value, item, toggleDetails, detailsShowing }">
+ <import-status :status="value" class="gl-display-inline-block gl-w-13" />
+ <gl-button
+ v-if="item.failures.length"
+ class="gl-ml-3"
+ :selected="detailsShowing"
+ @click="toggleDetails"
+ >{{ __('Details') }}</gl-button
+ >
+ </template>
+ <template #row-details="{ item }">
+ <pre>{{ item.failures }}</pre>
+ </template>
+ </gl-table>
+ <pagination-bar
+ :page-info="pageInfo"
+ :items-count="historyItems.length"
+ class="gl-m-0 gl-mt-3"
+ @set-page="paginationConfig.page = $event"
+ @set-page-size="paginationConfig.perPage = $event"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pages/import/bulk_imports/history/index.js b/app/assets/javascripts/pages/import/bulk_imports/history/index.js
new file mode 100644
index 00000000000..5a67aa99baa
--- /dev/null
+++ b/app/assets/javascripts/pages/import/bulk_imports/history/index.js
@@ -0,0 +1,15 @@
+import Vue from 'vue';
+import BulkImportHistoryApp from './components/bulk_imports_history_app.vue';
+
+function mountImportHistoryApp(mountElement) {
+ if (!mountElement) return undefined;
+
+ return new Vue({
+ el: mountElement,
+ render(createElement) {
+ return createElement(BulkImportHistoryApp);
+ },
+ });
+}
+
+mountImportHistoryApp(document.querySelector('#import-history-mount-element'));
diff --git a/app/assets/javascripts/pages/import/bulk_imports/history/utils/error_messages.js b/app/assets/javascripts/pages/import/bulk_imports/history/utils/error_messages.js
new file mode 100644
index 00000000000..24669e22ade
--- /dev/null
+++ b/app/assets/javascripts/pages/import/bulk_imports/history/utils/error_messages.js
@@ -0,0 +1,3 @@
+import { __ } from '~/locale';
+
+export const DEFAULT_ERROR = __('Something went wrong on our end.');
diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js
index 80bc32dd43f..6afb3636998 100644
--- a/app/assets/javascripts/pages/profiles/index.js
+++ b/app/assets/javascripts/pages/profiles/index.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import '~/profile/gl_crop';
import Profile from '~/profile/profile';
import initSearchSettings from '~/search_settings';
+import initPasswordPrompt from './password_prompt';
// eslint-disable-next-line func-names
$(document).on('input.ssh_key', '#key_key', function () {
@@ -19,3 +20,4 @@ $(document).on('input.ssh_key', '#key_key', function () {
new Profile(); // eslint-disable-line no-new
initSearchSettings();
+initPasswordPrompt();
diff --git a/app/assets/javascripts/pages/profiles/password_prompt/constants.js b/app/assets/javascripts/pages/profiles/password_prompt/constants.js
new file mode 100644
index 00000000000..99b8442c928
--- /dev/null
+++ b/app/assets/javascripts/pages/profiles/password_prompt/constants.js
@@ -0,0 +1,9 @@
+import { __, s__ } from '~/locale';
+
+export const I18N_PASSWORD_PROMPT_TITLE = s__('PasswordPrompt|Confirm password to continue');
+export const I18N_PASSWORD_PROMPT_FORM_LABEL = s__(
+ 'PasswordPrompt|Please enter your password to confirm',
+);
+export const I18N_PASSWORD_PROMPT_ERROR_MESSAGE = s__('PasswordPrompt|Password is required');
+export const I18N_PASSWORD_PROMPT_CONFIRM_BUTTON = s__('PasswordPrompt|Confirm password');
+export const I18N_PASSWORD_PROMPT_CANCEL_BUTTON = __('Cancel');
diff --git a/app/assets/javascripts/pages/profiles/password_prompt/index.js b/app/assets/javascripts/pages/profiles/password_prompt/index.js
new file mode 100644
index 00000000000..20645112893
--- /dev/null
+++ b/app/assets/javascripts/pages/profiles/password_prompt/index.js
@@ -0,0 +1,58 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import PasswordPromptModal from './password_prompt_modal.vue';
+
+Vue.use(Translate);
+
+const emailFieldSelector = '#user_email';
+const editFormSelector = '.js-password-prompt-form';
+const passwordPromptFieldSelector = '.js-password-prompt-field';
+const passwordPromptBtnSelector = '.js-password-prompt-btn';
+
+const passwordPromptModalId = 'password-prompt-modal';
+
+const getEmailValue = () => document.querySelector(emailFieldSelector).value.trim();
+const passwordPromptButton = document.querySelector(passwordPromptBtnSelector);
+const field = document.querySelector(passwordPromptFieldSelector);
+const form = document.querySelector(editFormSelector);
+
+const handleConfirmPassword = (pw) => {
+ // update the validation_password field
+ field.value = pw;
+ // submit the form
+ form.submit();
+};
+
+export default () => {
+ const passwordPromptModalEl = document.getElementById(passwordPromptModalId);
+
+ if (passwordPromptModalEl && field) {
+ return new Vue({
+ el: passwordPromptModalEl,
+ data() {
+ return {
+ initialEmail: '',
+ };
+ },
+ mounted() {
+ this.initialEmail = getEmailValue();
+ passwordPromptButton.addEventListener('click', this.handleSettingsUpdate);
+ },
+ methods: {
+ handleSettingsUpdate(ev) {
+ const email = getEmailValue();
+ if (email !== this.initialEmail) {
+ ev.preventDefault();
+ this.$root.$emit('bv::show::modal', passwordPromptModalId, passwordPromptBtnSelector);
+ }
+ },
+ },
+ render(createElement) {
+ return createElement(PasswordPromptModal, {
+ props: { handleConfirmPassword },
+ });
+ },
+ });
+ }
+ return null;
+};
diff --git a/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue b/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue
new file mode 100644
index 00000000000..44728ea9cdf
--- /dev/null
+++ b/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue
@@ -0,0 +1,82 @@
+<script>
+import { GlModal, GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui';
+import {
+ I18N_PASSWORD_PROMPT_TITLE,
+ I18N_PASSWORD_PROMPT_FORM_LABEL,
+ I18N_PASSWORD_PROMPT_ERROR_MESSAGE,
+ I18N_PASSWORD_PROMPT_CANCEL_BUTTON,
+ I18N_PASSWORD_PROMPT_CONFIRM_BUTTON,
+} from './constants';
+
+export default {
+ components: {
+ GlModal,
+ GlForm,
+ GlFormGroup,
+ GlFormInput,
+ },
+ props: {
+ handleConfirmPassword: {
+ type: Function,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ passwordCheck: '',
+ };
+ },
+ computed: {
+ isValid() {
+ return Boolean(this.passwordCheck.length);
+ },
+ primaryProps() {
+ return {
+ text: I18N_PASSWORD_PROMPT_CONFIRM_BUTTON,
+ attributes: [{ variant: 'danger' }, { category: 'primary' }, { disabled: !this.isValid }],
+ };
+ },
+ },
+ methods: {
+ onConfirmPassword() {
+ this.handleConfirmPassword(this.passwordCheck);
+ },
+ },
+ cancelProps: {
+ text: I18N_PASSWORD_PROMPT_CANCEL_BUTTON,
+ },
+ i18n: {
+ title: I18N_PASSWORD_PROMPT_TITLE,
+ formLabel: I18N_PASSWORD_PROMPT_FORM_LABEL,
+ errorMessage: I18N_PASSWORD_PROMPT_ERROR_MESSAGE,
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ data-testid="password-prompt-modal"
+ modal-id="password-prompt-modal"
+ :title="$options.i18n.title"
+ :action-primary="primaryProps"
+ :action-cancel="$options.cancelProps"
+ @primary="onConfirmPassword"
+ >
+ <gl-form @submit.prevent="onConfirmPassword">
+ <gl-form-group
+ :label="$options.i18n.formLabel"
+ label-for="password-prompt-confirmation"
+ :invalid-feedback="$options.i18n.errorMessage"
+ :state="isValid"
+ >
+ <gl-form-input
+ id="password-prompt-confirmation"
+ v-model="passwordCheck"
+ name="password-confirmation"
+ type="password"
+ data-testid="password-prompt-field"
+ />
+ </gl-form-group>
+ </gl-form>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/cluster_agents/show/index.js b/app/assets/javascripts/pages/projects/cluster_agents/show/index.js
new file mode 100644
index 00000000000..4ed3e2f7bea
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/cluster_agents/show/index.js
@@ -0,0 +1,3 @@
+import loadClusterAgentVues from '~/clusters/agents';
+
+loadClusterAgentVues();
diff --git a/app/assets/javascripts/pages/projects/clusters/index/index.js b/app/assets/javascripts/pages/projects/clusters/index/index.js
index 2b5451bd18b..a1ba920b322 100644
--- a/app/assets/javascripts/pages/projects/clusters/index/index.js
+++ b/app/assets/javascripts/pages/projects/clusters/index/index.js
@@ -1,4 +1,4 @@
-import initClustersListApp from 'ee_else_ce/clusters_list';
+import initClustersListApp from '~/clusters_list';
import PersistentUserCallout from '~/persistent_user_callout';
const callout = document.querySelector('.gcp-signup-offer');
diff --git a/app/assets/javascripts/pages/projects/new/components/app.vue b/app/assets/javascripts/pages/projects/new/components/app.vue
deleted file mode 100644
index 6e9efc50be8..00000000000
--- a/app/assets/javascripts/pages/projects/new/components/app.vue
+++ /dev/null
@@ -1,124 +0,0 @@
-<script>
-import createFromTemplateIllustration from '@gitlab/svgs/dist/illustrations/project-create-from-template-sm.svg';
-import blankProjectIllustration from '@gitlab/svgs/dist/illustrations/project-create-new-sm.svg';
-import importProjectIllustration from '@gitlab/svgs/dist/illustrations/project-import-sm.svg';
-import ciCdProjectIllustration from '@gitlab/svgs/dist/illustrations/project-run-CICD-pipelines-sm.svg';
-import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
-import NewProjectPushTipPopover from './new_project_push_tip_popover.vue';
-
-const CI_CD_PANEL = 'cicd_for_external_repo';
-const PANELS = [
- {
- key: 'blank',
- name: 'blank_project',
- selector: '#blank-project-pane',
- title: s__('ProjectsNew|Create blank project'),
- description: s__(
- 'ProjectsNew|Create a blank project to house your files, plan your work, and collaborate on code, among other things.',
- ),
- illustration: blankProjectIllustration,
- },
- {
- key: 'template',
- name: 'create_from_template',
- selector: '#create-from-template-pane',
- title: s__('ProjectsNew|Create from template'),
- description: s__(
- 'ProjectsNew|Create a project pre-populated with the necessary files to get you started quickly.',
- ),
- illustration: createFromTemplateIllustration,
- },
- {
- key: 'import',
- name: 'import_project',
- selector: '#import-project-pane',
- title: s__('ProjectsNew|Import project'),
- description: s__(
- 'ProjectsNew|Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab.',
- ),
- illustration: importProjectIllustration,
- },
- {
- key: 'ci',
- name: CI_CD_PANEL,
- selector: '#ci-cd-project-pane',
- title: s__('ProjectsNew|Run CI/CD for external repository'),
- description: s__('ProjectsNew|Connect your external repository to GitLab CI/CD.'),
- illustration: ciCdProjectIllustration,
- },
-];
-
-export default {
- components: {
- NewNamespacePage,
- NewProjectPushTipPopover,
- },
- directives: {
- SafeHtml,
- },
- props: {
- hasErrors: {
- type: Boolean,
- required: false,
- default: false,
- },
- isCiCdAvailable: {
- type: Boolean,
- required: false,
- default: false,
- },
- newProjectGuidelines: {
- type: String,
- required: false,
- default: '',
- },
- },
-
- computed: {
- availablePanels() {
- return this.isCiCdAvailable ? PANELS : PANELS.filter((p) => p.name !== CI_CD_PANEL);
- },
- },
-
- methods: {
- resetProjectErrors() {
- const errorsContainer = document.querySelector('.project-edit-errors');
- if (errorsContainer) {
- errorsContainer.innerHTML = '';
- }
- },
- },
-};
-</script>
-
-<template>
- <new-namespace-page
- :initial-breadcrumb="s__('New project')"
- :panels="availablePanels"
- :jump-to-last-persisted-panel="hasErrors"
- :title="s__('ProjectsNew|Create new project')"
- persistence-key="new_project_last_active_tab"
- @panel-change="resetProjectErrors"
- >
- <template #extra-description>
- <div
- v-if="newProjectGuidelines"
- id="new-project-guideline"
- v-safe-html="newProjectGuidelines"
- ></div>
- </template>
- <template #welcome-footer>
- <div class="gl-pt-5 gl-text-center">
- <p>
- {{ __('You can also create a project from the command line.') }}
- <a ref="clipTip" href="#" @click.prevent>
- {{ __('Show command') }}
- </a>
- <new-project-push-tip-popover :target="() => $refs.clipTip" />
- </p>
- </div>
- </template>
- </new-namespace-page>
-</template>
diff --git a/app/assets/javascripts/pages/projects/new/components/new_project_push_tip_popover.vue b/app/assets/javascripts/pages/projects/new/components/new_project_push_tip_popover.vue
deleted file mode 100644
index e42d9154866..00000000000
--- a/app/assets/javascripts/pages/projects/new/components/new_project_push_tip_popover.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { GlPopover, GlFormInputGroup } from '@gitlab/ui';
-import { __ } from '~/locale';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-
-export default {
- components: {
- GlPopover,
- GlFormInputGroup,
- ClipboardButton,
- },
- inject: ['pushToCreateProjectCommand', 'workingWithProjectsHelpPath'],
- props: {
- target: {
- type: [Function, HTMLElement],
- required: true,
- },
- },
- i18n: {
- clipboardButtonTitle: __('Copy command'),
- commandInputAriaLabel: __('Push project from command line'),
- helpLinkText: __('What does this command do?'),
- labelText: __('Private projects can be created in your personal namespace with:'),
- popoverTitle: __('Push to create a project'),
- },
-};
-</script>
-<template>
- <gl-popover
- :target="target"
- :title="$options.i18n.popoverTitle"
- triggers="click blur"
- placement="top"
- >
- <p>
- <label for="push-to-create-tip" class="gl-font-weight-normal">
- {{ $options.i18n.labelText }}
- </label>
- </p>
- <p>
- <gl-form-input-group
- id="push-to-create-tip"
- :value="pushToCreateProjectCommand"
- readonly
- select-on-click
- :aria-label="$options.i18n.commandInputAriaLabel"
- >
- <template #append>
- <clipboard-button
- :text="pushToCreateProjectCommand"
- :title="$options.i18n.clipboardButtonTitle"
- tooltip-placement="right"
- />
- </template>
- </gl-form-input-group>
- </p>
- <p>
- <a
- :href="`${workingWithProjectsHelpPath}#push-to-create-a-new-project`"
- class="gl-font-sm"
- target="_blank"
- >{{ $options.i18n.helpLinkText }}</a
- >
- </p>
- </gl-popover>
-</template>
diff --git a/app/assets/javascripts/pages/projects/new/components/new_project_url_select.vue b/app/assets/javascripts/pages/projects/new/components/new_project_url_select.vue
deleted file mode 100644
index ba8858c985a..00000000000
--- a/app/assets/javascripts/pages/projects/new/components/new_project_url_select.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-<script>
-import {
- GlButton,
- GlButtonGroup,
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlLoadingIcon,
- GlSearchBoxByType,
-} from '@gitlab/ui';
-import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import Tracking from '~/tracking';
-import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
-import searchNamespacesWhereUserCanCreateProjectsQuery from '../queries/search_namespaces_where_user_can_create_projects.query.graphql';
-
-export default {
- components: {
- GlButton,
- GlButtonGroup,
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlLoadingIcon,
- GlSearchBoxByType,
- },
- mixins: [Tracking.mixin()],
- apollo: {
- currentUser: {
- query: searchNamespacesWhereUserCanCreateProjectsQuery,
- variables() {
- return {
- search: this.search,
- };
- },
- skip() {
- return this.search.length > 0 && this.search.length < MINIMUM_SEARCH_LENGTH;
- },
- debounce: DEBOUNCE_DELAY,
- },
- },
- inject: ['namespaceFullPath', 'namespaceId', 'rootUrl', 'trackLabel'],
- data() {
- return {
- currentUser: {},
- search: '',
- selectedNamespace: {
- id: this.namespaceId,
- fullPath: this.namespaceFullPath,
- },
- };
- },
- computed: {
- userGroups() {
- return this.currentUser.groups?.nodes || [];
- },
- userNamespace() {
- return this.currentUser.namespace || {};
- },
- },
- methods: {
- handleClick({ id, fullPath }) {
- this.selectedNamespace = {
- id: getIdFromGraphQLId(id),
- fullPath,
- };
- },
- },
-};
-</script>
-
-<template>
- <gl-button-group class="gl-w-full">
- <gl-button label>{{ rootUrl }}</gl-button>
- <gl-dropdown
- class="gl-w-full"
- :text="selectedNamespace.fullPath"
- toggle-class="gl-rounded-top-right-base! gl-rounded-bottom-right-base!"
- data-qa-selector="select_namespace_dropdown"
- @show="track('activate_form_input', { label: trackLabel, property: 'project_path' })"
- >
- <gl-search-box-by-type v-model.trim="search" />
- <gl-loading-icon v-if="$apollo.queries.currentUser.loading" />
- <template v-else>
- <gl-dropdown-section-header>{{ __('Groups') }}</gl-dropdown-section-header>
- <gl-dropdown-item v-for="group of userGroups" :key="group.id" @click="handleClick(group)">
- {{ group.fullPath }}
- </gl-dropdown-item>
- <gl-dropdown-section-header>{{ __('Users') }}</gl-dropdown-section-header>
- <gl-dropdown-item @click="handleClick(userNamespace)">
- {{ userNamespace.fullPath }}
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
-
- <input type="hidden" name="project[namespace_id]" :value="selectedNamespace.id" />
- </gl-button-group>
-</template>
diff --git a/app/assets/javascripts/pages/projects/new/index.js b/app/assets/javascripts/pages/projects/new/index.js
index ed816e3be95..d89b4d0e0a3 100644
--- a/app/assets/javascripts/pages/projects/new/index.js
+++ b/app/assets/javascripts/pages/projects/new/index.js
@@ -1,66 +1,6 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createDefaultClient from '~/lib/graphql';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import initProjectVisibilitySelector from '../../../project_visibility';
-import initProjectNew from '../../../projects/project_new';
-import NewProjectCreationApp from './components/app.vue';
-import NewProjectUrlSelect from './components/new_project_url_select.vue';
-
-function initNewProjectCreation() {
- const el = document.querySelector('.js-new-project-creation');
-
- const {
- pushToCreateProjectCommand,
- workingWithProjectsHelpPath,
- newProjectGuidelines,
- hasErrors,
- isCiCdAvailable,
- } = el.dataset;
-
- const props = {
- hasErrors: parseBoolean(hasErrors),
- isCiCdAvailable: parseBoolean(isCiCdAvailable),
- newProjectGuidelines,
- };
-
- const provide = {
- workingWithProjectsHelpPath,
- pushToCreateProjectCommand,
- };
-
- return new Vue({
- el,
- provide,
- render(h) {
- return h(NewProjectCreationApp, { props });
- },
- });
-}
-
-function initNewProjectUrlSelect() {
- const el = document.querySelector('.js-vue-new-project-url-select');
-
- if (!el) {
- return undefined;
- }
-
- Vue.use(VueApollo);
-
- return new Vue({
- el,
- apolloProvider: new VueApollo({
- defaultClient: createDefaultClient({}, { assumeImmutableResults: true }),
- }),
- provide: {
- namespaceFullPath: el.dataset.namespaceFullPath,
- namespaceId: el.dataset.namespaceId,
- rootUrl: el.dataset.rootUrl,
- trackLabel: el.dataset.trackLabel,
- },
- render: (createElement) => createElement(NewProjectUrlSelect),
- });
-}
+import { initNewProjectCreation, initNewProjectUrlSelect } from '~/projects/new';
+import initProjectVisibilitySelector from '~/project_visibility';
+import initProjectNew from '~/projects/project_new';
initProjectVisibilitySelector();
initProjectNew.bindEvents();
diff --git a/app/assets/javascripts/pages/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql b/app/assets/javascripts/pages/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql
deleted file mode 100644
index e16fe5dde49..00000000000
--- a/app/assets/javascripts/pages/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql
+++ /dev/null
@@ -1,14 +0,0 @@
-query searchNamespacesWhereUserCanCreateProjects($search: String) {
- currentUser {
- groups(permissionScope: CREATE_PROJECTS, search: $search) {
- nodes {
- id
- fullPath
- }
- }
- namespace {
- id
- fullPath
- }
- }
-}
diff --git a/app/assets/javascripts/pages/projects/packages/packages/index/index.js b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
index c94782fdf1b..95522573b53 100644
--- a/app/assets/javascripts/pages/projects/packages/packages/index/index.js
+++ b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
@@ -1,3 +1,10 @@
-import initPackageList from '~/packages/list/packages_list_app_bundle';
+(async function packageApp() {
+ if (window.gon.features.packageListApollo) {
+ const newPackageList = await import('~/packages_and_registries/package_registry/pages/list');
-initPackageList();
+ newPackageList.default();
+ } else {
+ const packageList = await import('~/packages/list/packages_list_app_bundle');
+ packageList.default();
+ }
+})();
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js
index 16c4a6191b2..e92b9b30fa4 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js
@@ -27,19 +27,22 @@ export const findTimezoneByIdentifier = (tzList = [], identifier = null) => {
};
export default class TimezoneDropdown {
- constructor({ $dropdownEl, $inputEl, onSelectTimezone, displayFormat } = defaults) {
+ constructor({
+ $dropdownEl,
+ $inputEl,
+ onSelectTimezone,
+ displayFormat,
+ allowEmpty = false,
+ } = defaults) {
this.$dropdown = $dropdownEl;
this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text');
this.$input = $inputEl;
- this.timezoneData = this.$dropdown.data('data');
+ this.timezoneData = this.$dropdown.data('data') || [];
this.onSelectTimezone = onSelectTimezone;
this.displayFormat = displayFormat || defaults.displayFormat;
+ this.allowEmpty = allowEmpty;
- this.initialTimezone =
- findTimezoneByIdentifier(this.timezoneData, this.$input.val()) || defaultTimezone;
-
- this.initDefaultTimezone();
this.initDropdown();
}
@@ -52,24 +55,25 @@ export default class TimezoneDropdown {
search: {
fields: ['name'],
},
- clicked: (cfg) => this.updateInputValue(cfg),
+ clicked: (cfg) => this.handleDropdownChange(cfg),
text: (item) => formatTimezone(item),
});
- this.setDropdownToggle(this.displayFormat(this.initialTimezone));
- }
+ const initialTimezone = findTimezoneByIdentifier(this.timezoneData, this.$input.val());
- initDefaultTimezone() {
- if (!this.$input.val()) {
- this.$input.val(defaultTimezone.name);
+ if (initialTimezone !== null) {
+ this.setDropdownValue(initialTimezone);
+ } else if (!this.allowEmpty) {
+ this.setDropdownValue(defaultTimezone);
}
}
- setDropdownToggle(dropdownText) {
- this.$dropdownToggle.text(dropdownText);
+ setDropdownValue(timezone) {
+ this.$dropdownToggle.text(this.displayFormat(timezone));
+ this.$input.val(timezone.name);
}
- updateInputValue({ selectedObj, e }) {
+ handleDropdownChange({ selectedObj, e }) {
e.preventDefault();
this.$input.val(selectedObj.identifier);
if (this.onSelectTimezone) {
diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js
index 0b662c945c6..947bbdacf2c 100644
--- a/app/assets/javascripts/pages/projects/project_members/index.js
+++ b/app/assets/javascripts/pages/projects/project_members/index.js
@@ -26,7 +26,7 @@ initInviteMembersForm();
new UsersSelect(); // eslint-disable-line no-new
-const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
+const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-project-members-list-app'), {
[MEMBER_TYPES.user]: {
tableFields: SHARED_FIELDS.concat(['source', 'granted']),
diff --git a/app/assets/javascripts/pages/projects/wikis/diff/index.js b/app/assets/javascripts/pages/projects/wikis/diff/index.js
new file mode 100644
index 00000000000..73440db761f
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/wikis/diff/index.js
@@ -0,0 +1,3 @@
+import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
+
+initDiffStatsDropdown();
diff --git a/app/assets/javascripts/pages/projects/wikis/edit/index.js b/app/assets/javascripts/pages/projects/wikis/edit/index.js
new file mode 100644
index 00000000000..b2288c2655c
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/wikis/edit/index.js
@@ -0,0 +1,3 @@
+import { mountApplications } from '~/pages/shared/wikis/edit';
+
+mountApplications();
diff --git a/app/assets/javascripts/pages/projects/wikis/git_access/index.js b/app/assets/javascripts/pages/projects/wikis/git_access/index.js
new file mode 100644
index 00000000000..b1f3006bc1a
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/wikis/git_access/index.js
@@ -0,0 +1,3 @@
+import initClonePanel from '~/clone_panel';
+
+initClonePanel();
diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index 2c1f9e634ab..83fcd348ddf 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -1,5 +1,3 @@
-import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
-import initWikis from '~/pages/shared/wikis';
+import Wikis from '~/pages/shared/wikis/wikis';
-initWikis();
-initDiffStatsDropdown();
+export default new Wikis();
diff --git a/app/assets/javascripts/pages/projects/wikis/show/index.js b/app/assets/javascripts/pages/projects/wikis/show/index.js
new file mode 100644
index 00000000000..c08a10122b6
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/wikis/show/index.js
@@ -0,0 +1,3 @@
+import { mountApplications as mountEditApplications } from '~/pages/shared/wikis/async_edit';
+
+mountEditApplications();
diff --git a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
index 8d2d5d41f6a..ee48543f0d2 100644
--- a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
+++ b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
@@ -20,7 +20,7 @@ export default class OAuthRememberMe {
toggleRememberMe(event) {
const rememberMe = $(event.target).is(':checked');
- $('.oauth-login', this.container).each((i, element) => {
+ $('.js-oauth-login', this.container).each((i, element) => {
const $form = $(element).parent('form');
const href = $form.attr('action');
diff --git a/app/assets/javascripts/pages/shared/mount_runner_instructions.js b/app/assets/javascripts/pages/shared/mount_runner_instructions.js
index e83c73edfde..1cb7259be64 100644
--- a/app/assets/javascripts/pages/shared/mount_runner_instructions.js
+++ b/app/assets/javascripts/pages/shared/mount_runner_instructions.js
@@ -9,7 +9,12 @@ export function initInstallRunner(componentId = 'js-install-runner') {
const installRunnerEl = document.getElementById(componentId);
if (installRunnerEl) {
- const defaultClient = createDefaultClient();
+ const defaultClient = createDefaultClient(
+ {},
+ {
+ assumeImmutableResults: true,
+ },
+ );
const apolloProvider = new VueApollo({
defaultClient,
diff --git a/app/assets/javascripts/pages/shared/wikis/async_edit.js b/app/assets/javascripts/pages/shared/wikis/async_edit.js
new file mode 100644
index 00000000000..4536a076568
--- /dev/null
+++ b/app/assets/javascripts/pages/shared/wikis/async_edit.js
@@ -0,0 +1,11 @@
+export const mountApplications = async () => {
+ const el = document.querySelector('.js-wiki-edit-page');
+
+ if (el) {
+ const { mountApplications: mountEditApplications } = await import(
+ /* webpackChunkName: 'wiki_edit' */ './edit'
+ );
+
+ mountEditApplications();
+ }
+};
diff --git a/app/assets/javascripts/pages/shared/wikis/index.js b/app/assets/javascripts/pages/shared/wikis/edit.js
index 42aefe81325..beeabfde1a6 100644
--- a/app/assets/javascripts/pages/shared/wikis/index.js
+++ b/app/assets/javascripts/pages/shared/wikis/edit.js
@@ -1,6 +1,5 @@
import $ from 'jquery';
import Vue from 'vue';
-import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import csrf from '~/lib/utils/csrf';
import Translate from '~/vue_shared/translate';
@@ -9,14 +8,8 @@ import ZenMode from '../../../zen_mode';
import deleteWikiModal from './components/delete_wiki_modal.vue';
import wikiAlert from './components/wiki_alert.vue';
import wikiForm from './components/wiki_form.vue';
-import Wikis from './wikis';
const createModalVueApp = () => {
- new Wikis(); // eslint-disable-line no-new
- new ShortcutsWiki(); // eslint-disable-line no-new
- new ZenMode(); // eslint-disable-line no-new
- new GLForm($('.wiki-form')); // eslint-disable-line no-new
-
const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper');
if (deleteWikiModalWrapperEl) {
@@ -85,7 +78,10 @@ const createWikiFormApp = () => {
}
};
-export default () => {
+export const mountApplications = () => {
+ new ZenMode(); // eslint-disable-line no-new
+ new GLForm($('.wiki-form')); // eslint-disable-line no-new
+
createModalVueApp();
createAlertVueApp();
createWikiFormApp();
diff --git a/app/assets/javascripts/pages/shared/wikis/wikis.js b/app/assets/javascripts/pages/shared/wikis/wikis.js
index 7d0b0c90c8d..8d0105bc681 100644
--- a/app/assets/javascripts/pages/shared/wikis/wikis.js
+++ b/app/assets/javascripts/pages/shared/wikis/wikis.js
@@ -1,6 +1,7 @@
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import Tracking from '~/tracking';
import showToast from '~/vue_shared/plugins/global_toast';
+import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
const TRACKING_EVENT_NAME = 'view_wiki_page';
const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/wiki_page_context/jsonschema/1-0-1';
@@ -20,6 +21,7 @@ export default class Wikis {
Wikis.trackPageView();
Wikis.showToasts();
+ Wikis.initShortcuts();
}
handleToggleSidebar(e) {
@@ -64,4 +66,8 @@ export default class Wikis {
const toasts = document.querySelectorAll('.js-toast-message');
toasts.forEach((toast) => showToast(toast.dataset.message));
}
+
+ static initShortcuts() {
+ new ShortcutsWiki(); // eslint-disable-line no-new
+ }
}