summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pages
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 09:40:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 09:40:42 +0000
commitee664acb356f8123f4f6b00b73c1e1cf0866c7fb (patch)
treef8479f94a28f66654c6a4f6fb99bad6b4e86a40e /app/assets/javascripts/pages
parent62f7d5c5b69180e82ae8196b7b429eeffc8e7b4f (diff)
downloadgitlab-ce-ee664acb356f8123f4f6b00b73c1e1cf0866c7fb.tar.gz
Add latest changes from gitlab-org/gitlab@15-5-stable-eev15.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/pages')
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_downloader.js4
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_previewer.js4
-rw-r--r--app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js4
-rw-r--r--app/assets/javascripts/pages/admin/broadcast_messages/index.js9
-rw-r--r--app/assets/javascripts/pages/admin/dashboard/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/groups/show/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue4
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js6
-rw-r--r--app/assets/javascripts/pages/groups/merge_requests/index.js8
-rw-r--r--app/assets/javascripts/pages/groups/new/group_path_validator.js4
-rw-r--r--app/assets/javascripts/pages/groups/new/index.js9
-rw-r--r--app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/settings/index.js2
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue4
-rw-r--r--app/assets/javascripts/pages/import/fogbugz/new_user_map/components/user_select.vue95
-rw-r--r--app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js20
-rw-r--r--app/assets/javascripts/pages/import/history/components/import_history_app.vue4
-rw-r--r--app/assets/javascripts/pages/profiles/index.js2
-rw-r--r--app/assets/javascripts/pages/profiles/init_timezone_dropdown.js34
-rw-r--r--app/assets/javascripts/pages/projects/blame/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue4
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue4
-rw-r--r--app/assets/javascripts/pages/projects/hooks/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js4
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/edit/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/index/index.js9
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js15
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/timezone_dropdown.js3
-rw-r--r--app/assets/javascripts/pages/projects/project.js4
-rw-r--r--app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/repository/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue30
-rw-r--r--app/assets/javascripts/pages/sessions/new/username_validator.js4
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue4
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue221
-rw-r--r--app/assets/javascripts/pages/users/activity_calendar.js6
41 files changed, 365 insertions, 199 deletions
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
index 8cecc1d3ef7..97fb64f9971 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -29,7 +29,7 @@ export default class PayloadDownloader {
PayloadDownloader.downloadFile(data);
})
.catch(() => {
- createFlash({
+ createAlert({
message: __('Error fetching payload data.'),
});
})
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
index 616005565c4..1cd19fc09a8 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -43,7 +43,7 @@ export default class PayloadPreviewer {
})
.catch(() => {
this.spinner.classList.remove('gl-display-inline');
- createFlash({
+ createAlert({
message: __('Error fetching payload data.'),
});
});
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
index 18ba89f8856..40348e0b18a 100644
--- a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { __ } from '~/locale';
@@ -30,7 +30,7 @@ export default () => {
$jsBroadcastMessagePreview.html(data);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while rendering preview broadcast message'),
}),
);
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/index.js b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
index f687423594d..ffd976be8c6 100644
--- a/app/assets/javascripts/pages/admin/broadcast_messages/index.js
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
@@ -1,5 +1,10 @@
+import initBroadcastMessages from '~/admin/broadcast_messages';
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import initBroadcastMessagesForm from './broadcast_message';
-initBroadcastMessagesForm();
-initDeprecatedRemoveRowBehavior();
+if (gon.features.vueBroadcastMessages) {
+ initBroadcastMessages();
+} else {
+ initBroadcastMessagesForm();
+ initDeprecatedRemoveRowBehavior();
+}
diff --git a/app/assets/javascripts/pages/admin/dashboard/index.js b/app/assets/javascripts/pages/admin/dashboard/index.js
new file mode 100644
index 00000000000..b63e612be47
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/dashboard/index.js
@@ -0,0 +1,3 @@
+import initGitlabVersionCheck from '~/gitlab_version_check';
+
+initGitlabVersionCheck();
diff --git a/app/assets/javascripts/pages/admin/groups/show/index.js b/app/assets/javascripts/pages/admin/groups/show/index.js
deleted file mode 100644
index 86b80a0ba5b..00000000000
--- a/app/assets/javascripts/pages/admin/groups/show/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import UsersSelect from '~/users_select';
-
-new UsersSelect(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js
index a249864fa36..eaee625c047 100644
--- a/app/assets/javascripts/pages/admin/index.js
+++ b/app/assets/javascripts/pages/admin/index.js
@@ -1,10 +1,8 @@
-import initGitlabVersionCheck from '~/gitlab_version_check';
import initAdminStatisticsPanel from '~/admin/statistics_panel/index';
import initVueAlerts from '~/vue_alerts';
import initAdmin from './admin';
initVueAlerts();
-initGitlabVersionCheck();
const statisticsPanelContainer = document.getElementById('js-admin-statistics-container');
initAdmin();
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
index 63b98f4143b..4f42ef2892d 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { redirectTo } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
@@ -31,7 +31,7 @@ export default {
redirectTo(response.request.responseURL);
})
.catch((error) => {
- createFlash({
+ createAlert({
message: s__('AdminArea|Stopping jobs failed'),
});
throw error;
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
index b6f42a27002..2a7619da8cc 100644
--- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
import { getGroups } from '~/api/groups_api';
import { getProjects } from '~/api/projects_api';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { isMetaClick } from '~/lib/utils/common_utils';
import { addDelimiter } from '~/lib/utils/text_utility';
@@ -119,7 +119,7 @@ export default class Todos {
})
.catch(() => {
this.updateRowState(target, true);
- return createFlash({
+ return createAlert({
message: __('Error updating status of to-do item.'),
});
});
@@ -168,7 +168,7 @@ export default class Todos {
this.updateBadges(data);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error updating status for all to-do items.'),
}),
);
diff --git a/app/assets/javascripts/pages/groups/merge_requests/index.js b/app/assets/javascripts/pages/groups/merge_requests/index.js
index de28f027126..377ba0f13a9 100644
--- a/app/assets/javascripts/pages/groups/merge_requests/index.js
+++ b/app/assets/javascripts/pages/groups/merge_requests/index.js
@@ -1,6 +1,10 @@
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
-import { initBulkUpdateSidebar } from '~/issuable/bulk_update_sidebar';
+import {
+ initBulkUpdateSidebar,
+ initStatusDropdown,
+ initSubscriptionsDropdown,
+} from '~/issuable/bulk_update_sidebar';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import projectSelect from '~/project_select';
@@ -9,6 +13,8 @@ const ISSUABLE_BULK_UPDATE_PREFIX = 'merge_request_';
addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
initBulkUpdateSidebar(ISSUABLE_BULK_UPDATE_PREFIX);
+initStatusDropdown();
+initSubscriptionsDropdown();
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
diff --git a/app/assets/javascripts/pages/groups/new/group_path_validator.js b/app/assets/javascripts/pages/groups/new/group_path_validator.js
index 8ce73be6e74..fa111032b2e 100644
--- a/app/assets/javascripts/pages/groups/new/group_path_validator.js
+++ b/app/assets/javascripts/pages/groups/new/group_path_validator.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';
import { getGroupPathAvailability } from '~/rest_api';
@@ -62,7 +62,7 @@ export default class GroupPathValidator extends InputValidator {
}
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while validating group path'),
}),
);
diff --git a/app/assets/javascripts/pages/groups/new/index.js b/app/assets/javascripts/pages/groups/new/index.js
index 7dab5258b24..a555038ed5c 100644
--- a/app/assets/javascripts/pages/groups/new/index.js
+++ b/app/assets/javascripts/pages/groups/new/index.js
@@ -1,4 +1,6 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
import BindInOut from '~/behaviors/bind_in_out';
import initFilePickers from '~/file_pickers';
import Group from '~/group';
@@ -8,6 +10,8 @@ import NewGroupCreationApp from './components/app.vue';
import GroupPathValidator from './group_path_validator';
import initToggleInviteMembers from './toggle_invite_members';
+Vue.use(VueApollo);
+
new GroupPathValidator(); // eslint-disable-line no-new
new Group(); // eslint-disable-line no-new
initGroupNameAndPath();
@@ -31,8 +35,13 @@ function initNewGroupCreation(el) {
hasErrors: parseBoolean(hasErrors),
};
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
return new Vue({
el,
+ apolloProvider,
provide: {
verificationRequired: parseBoolean(verificationRequired),
verificationFormUrl,
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 bf77d968e7d..b1a1cc21764 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
@@ -2,9 +2,11 @@ import initStaleRunnerCleanupSetting from 'ee_else_ce/group_settings/stale_runne
import initVariableList from '~/ci_variable_list';
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
import initSettingsPanels from '~/settings_panels';
+import initDeployTokens from '~/deploy_tokens';
// Initialize expandable settings panels
initSettingsPanels();
+initDeployTokens();
initSharedRunnersForm();
initStaleRunnerCleanupSetting();
diff --git a/app/assets/javascripts/pages/groups/settings/index.js b/app/assets/javascripts/pages/groups/settings/index.js
index cb787c60002..7e97cd865b7 100644
--- a/app/assets/javascripts/pages/groups/settings/index.js
+++ b/app/assets/javascripts/pages/groups/settings/index.js
@@ -1,5 +1,7 @@
import initRevokeButton from '~/deploy_tokens/init_revoke_button';
import initSearchSettings from '~/search_settings';
+import initDeployTokens from '~/deploy_tokens';
+initDeployTokens();
initSearchSettings();
initRevokeButton();
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
index 9cce6723bf7..6feb4c2188f 100644
--- 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
@@ -2,7 +2,7 @@
import { GlButton, GlEmptyState, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { s__, __ } from '~/locale';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { getBulkImportsHistory } from '~/rest_api';
@@ -107,7 +107,7 @@ export default {
this.pageInfo = parseIntPagination(normalizeHeaders(headers));
this.historyItems = historyItems;
} catch (e) {
- createFlash({ message: DEFAULT_ERROR, captureError: true, error: e });
+ createAlert({ message: DEFAULT_ERROR, captureError: true, error: e });
} finally {
this.loading = false;
}
diff --git a/app/assets/javascripts/pages/import/fogbugz/new_user_map/components/user_select.vue b/app/assets/javascripts/pages/import/fogbugz/new_user_map/components/user_select.vue
new file mode 100644
index 00000000000..20ce296bbec
--- /dev/null
+++ b/app/assets/javascripts/pages/import/fogbugz/new_user_map/components/user_select.vue
@@ -0,0 +1,95 @@
+<script>
+import { GlAvatarLabeled, GlListbox } from '@gitlab/ui';
+import { __ } from '~/locale';
+import searchUsersQuery from '~/graphql_shared/queries/users_search_all.query.graphql';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+
+const USERS_PER_PAGE = 20;
+
+export default {
+ components: {
+ GlAvatarLabeled,
+ GlListbox,
+ },
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ },
+ apollo: {
+ usersQuery: {
+ query: searchUsersQuery,
+ variables() {
+ return {
+ search: this.search,
+ first: USERS_PER_PAGE,
+ };
+ },
+ update(data) {
+ return data;
+ },
+ debounce: DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
+ },
+ },
+ data() {
+ return {
+ user: '',
+ search: '',
+ };
+ },
+ computed: {
+ userId() {
+ return getIdFromGraphQLId(this.user);
+ },
+ users() {
+ return [
+ { text: __('(no user)'), value: '' },
+ ...(this.usersQuery?.users.nodes || []).map((u) => ({
+ username: `@${u.username}`,
+ avatarUrl: u.avatarUrl,
+ text: u.name,
+ value: u.id,
+ })),
+ ];
+ },
+ },
+ methods: {
+ clearTransform() {
+ // FIXME: workaround for listbox issue
+ // https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1986
+ const { listbox } = this.$refs;
+ if (listbox.querySelector('.dropdown-menu')) {
+ listbox.querySelector('.dropdown-menu').style.transform = '';
+ }
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-listbox
+ ref="listbox"
+ v-model="user"
+ :items="users"
+ searchable
+ is-check-centered
+ :searching="$apollo.loading"
+ @click.capture.native="clearTransform"
+ @search="search = $event"
+ >
+ <template #list-item="{ item }">
+ <gl-avatar-labeled
+ shape="circle"
+ :size="32"
+ :src="item.avatarUrl"
+ :label="item.text"
+ :sub-label="item.username"
+ />
+ </template>
+ </gl-listbox>
+ <input type="hidden" :name="name" :value="userId" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
index 86b80a0ba5b..ef549f20cf3 100644
--- a/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
+++ b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
@@ -1,3 +1,19 @@
-import UsersSelect from '~/users_select';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import UserSelect from './components/user_select.vue';
-new UsersSelect(); // eslint-disable-line no-new
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+Array.from(document.querySelectorAll('.js-gitlab-user')).forEach(
+ (node) =>
+ new Vue({
+ el: node,
+ apolloProvider,
+ render: (h) => h(UserSelect, { props: { name: node.dataset.name } }),
+ }),
+);
diff --git a/app/assets/javascripts/pages/import/history/components/import_history_app.vue b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
index db6f0c23dbd..09b1b3a9c0f 100644
--- a/app/assets/javascripts/pages/import/history/components/import_history_app.vue
+++ b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlEmptyState, GlIcon, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { s__, __ } from '~/locale';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { getProjects } from '~/rest_api';
import ImportStatus from '~/import_entities/components/import_status.vue';
@@ -104,7 +104,7 @@ export default {
this.pageInfo = parseIntPagination(normalizeHeaders(headers));
this.historyItems = historyItems;
} catch (e) {
- createFlash({ message: DEFAULT_ERROR, captureError: true, error: e });
+ createAlert({ message: DEFAULT_ERROR, captureError: true, error: e });
} finally {
this.loading = false;
}
diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js
index 6afb3636998..91b20a05196 100644
--- a/app/assets/javascripts/pages/profiles/index.js
+++ b/app/assets/javascripts/pages/profiles/index.js
@@ -3,6 +3,7 @@ import '~/profile/gl_crop';
import Profile from '~/profile/profile';
import initSearchSettings from '~/search_settings';
import initPasswordPrompt from './password_prompt';
+import { initTimezoneDropdown } from './init_timezone_dropdown';
// eslint-disable-next-line func-names
$(document).on('input.ssh_key', '#key_key', function () {
@@ -21,3 +22,4 @@ new Profile(); // eslint-disable-line no-new
initSearchSettings();
initPasswordPrompt();
+initTimezoneDropdown();
diff --git a/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js b/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js
new file mode 100644
index 00000000000..80b911493a8
--- /dev/null
+++ b/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js
@@ -0,0 +1,34 @@
+import Vue from 'vue';
+import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
+
+export const initTimezoneDropdown = () => {
+ const el = document.querySelector('.js-timezone-dropdown');
+
+ if (!el) {
+ return null;
+ }
+
+ const { timezoneData, initialValue } = el.dataset;
+ const timezones = JSON.parse(timezoneData);
+
+ const timezoneDropdown = new Vue({
+ el,
+ data() {
+ return {
+ value: initialValue,
+ };
+ },
+ render(h) {
+ return h(TimezoneDropdown, {
+ props: {
+ value: this.value,
+ timezoneData: timezones,
+ name: 'user[timezone]',
+ },
+ class: 'gl-md-form-input-lg',
+ });
+ },
+ });
+
+ return timezoneDropdown;
+};
diff --git a/app/assets/javascripts/pages/projects/blame/show/index.js b/app/assets/javascripts/pages/projects/blame/show/index.js
index fa22c11d1d7..1e4b9de90f2 100644
--- a/app/assets/javascripts/pages/projects/blame/show/index.js
+++ b/app/assets/javascripts/pages/projects/blame/show/index.js
@@ -1,3 +1,5 @@
import initBlob from '~/pages/projects/init_blob';
+import redirectToCorrectPage from '~/blame/blame_redirect';
+redirectToCorrectPage();
initBlob();
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index eca3cf7ab13..af0097b415c 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -4,7 +4,7 @@ import Vue from 'vue';
import loadAwardsHandler from '~/awards_handler';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import Diff from '~/diff';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import initDeprecatedNotes from '~/init_deprecated_notes';
import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
import axios from '~/lib/utils/axios_utils';
@@ -69,7 +69,7 @@ if (filesContainer.length) {
loadDiffStats();
})
.catch(() => {
- createFlash({ message: __('An error occurred while retrieving diff files') });
+ createAlert({ message: __('An error occurred while retrieving diff files') });
});
} else {
new Diff();
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
index b415e36bf09..30cefa3d717 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
@@ -12,7 +12,7 @@ import {
} from '@gitlab/ui';
import { kebabCase } from 'lodash';
import { buildApiUrl } from '~/api/api_utils';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import csrf from '~/lib/utils/csrf';
import { redirectTo } from '~/lib/utils/url_utility';
@@ -220,7 +220,7 @@ export default {
redirectTo(data.web_url);
return;
} catch (error) {
- createFlash({
+ createAlert({
message: s__(
'ForkProject|An error occurred while forking the project. Please try again.',
),
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
index 2b3055ecd66..00e0649deed 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
@@ -9,7 +9,7 @@ import {
GlSearchBoxByType,
GlTruncate,
} from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -41,7 +41,7 @@ export default {
return length > 0 && length < MINIMUM_SEARCH_LENGTH;
},
error(error) {
- createFlash({
+ createAlert({
message: s__(
'ForkProject|Something went wrong while loading data. Please refresh the page to try again.',
),
diff --git a/app/assets/javascripts/pages/projects/hooks/index.js b/app/assets/javascripts/pages/projects/hooks/index.js
index 2a120a690ef..ed476d25f8b 100644
--- a/app/assets/javascripts/pages/projects/hooks/index.js
+++ b/app/assets/javascripts/pages/projects/hooks/index.js
@@ -1,3 +1,5 @@
import initSearchSettings from '~/search_settings';
+import initWebhookForm from '~/webhooks';
initSearchSettings();
+initWebhookForm();
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
index 9a38c2cc765..65942464e2b 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
@@ -39,7 +39,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
}
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error fetching refs'),
}),
);
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 5179d1b31ab..406959c80ea 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -33,7 +33,7 @@ function initTargetBranchSelector() {
callback(data);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error fetching branches'),
}),
);
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 e284e7b2c5e..2399aafc9b5 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -2,14 +2,19 @@ import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import { initCsvImportExportButtons, initIssuableByEmail } from '~/issuable';
-import { initBulkUpdateSidebar, initIssueStatusSelect } from '~/issuable/bulk_update_sidebar';
+import {
+ initBulkUpdateSidebar,
+ initStatusDropdown,
+ initSubscriptionsDropdown,
+} from '~/issuable/bulk_update_sidebar';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import { ISSUABLE_INDEX } from '~/issuable/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import UsersSelect from '~/users_select';
initBulkUpdateSidebar(ISSUABLE_INDEX.MERGE_REQUEST);
-initIssueStatusSelect();
+initStatusDropdown();
+initSubscriptionsDropdown();
addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
IssuableFilteredSearchTokenKeys.removeTokensForKeys('iteration');
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
index 6dd21380bec..0edce2db0a3 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
@@ -1,3 +1,8 @@
+import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
-initForm();
+if (gon.features?.pipelineSchedulesVue) {
+ initPipelineSchedulesFormApp('#pipeline-schedules-form-edit');
+} else {
+ initForm();
+}
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
index 9513f42d9c9..7d0930f6424 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
@@ -1,9 +1,10 @@
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
+import initPipelineSchedulesApp from '~/pipeline_schedules/mount_pipeline_schedules_app';
import PipelineSchedulesTakeOwnershipModal from '~/pipeline_schedules/components/take_ownership_modal.vue';
import PipelineSchedulesCallout from '../shared/components/pipeline_schedules_callout.vue';
-function initPipelineSchedules() {
+function initPipelineSchedulesCallout() {
const el = document.getElementById('pipeline-schedules-callout');
if (!el) {
@@ -15,6 +16,7 @@ function initPipelineSchedules() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'PipelineSchedulesCalloutRoot',
provide: {
docsUrl,
illustrationUrl,
@@ -25,6 +27,8 @@ function initPipelineSchedules() {
});
}
+// TODO: move take ownership feature into new Vue app
+// located in directory app/assets/javascripts/pipeline_schedules/components
function initTakeownershipModal() {
const modalId = 'pipeline-take-ownership-modal';
const buttonSelector = 'js-take-ownership-button';
@@ -63,5 +67,10 @@ function initTakeownershipModal() {
});
}
-initPipelineSchedules();
-initTakeownershipModal();
+initPipelineSchedulesCallout();
+
+if (gon.features?.pipelineSchedulesVue) {
+ initPipelineSchedulesApp();
+} else {
+ initTakeownershipModal();
+}
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
index 6dd21380bec..06084fa729b 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
@@ -1,3 +1,8 @@
+import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
-initForm();
+if (gon.features?.pipelineSchedulesVue) {
+ initPipelineSchedulesFormApp('#pipeline-schedules-form-new');
+} else {
+ initForm();
+}
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 277d2e0d30a..bc467952551 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
@@ -1,4 +1,5 @@
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+import { formatTimezone } from '~/lib/utils/datetime_utility';
const defaultTimezone = { identifier: 'Etc/UTC', name: 'UTC', offset: 0 };
const defaults = {
@@ -17,8 +18,6 @@ export const formatUtcOffset = (offset) => {
return `${prefix} ${Math.abs(offset / 3600)}`;
};
-export const formatTimezone = (item) => `[UTC ${formatUtcOffset(item.offset)}] ${item.name}`;
-
export const findTimezoneByIdentifier = (tzList = [], identifier = null) => {
if (tzList && tzList.length && identifier && identifier.length) {
return tzList.find((tz) => tz.identifier === identifier) || null;
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index ccabaad5b2e..d177c67f133 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
import { setCookie } from '~/lib/utils/common_utils';
import initClonePanel from '~/clone_panel';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { serializeForm } from '~/lib/utils/forms';
import { mergeUrlParams } from '~/lib/utils/url_utility';
@@ -80,7 +80,7 @@ export default class Project {
})
.then(({ data }) => callback(data))
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while getting projects'),
}),
);
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 6a9bd34db22..8909ff1f221 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
@@ -10,6 +10,7 @@ import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_to
import initSettingsPanels from '~/settings_panels';
import { initTokenAccess } from '~/token_access';
import { initCiSecureFiles } from '~/ci_secure_files';
+import initDeployTokens from '~/deploy_tokens';
// Initialize expandable settings panels
initSettingsPanels();
@@ -34,6 +35,7 @@ document.querySelector('.js-toggle-extra-settings').addEventListener('click', (e
});
registrySettingsApp();
+initDeployTokens();
initDeployFreeze();
initSettingsPipelinesTriggers();
diff --git a/app/assets/javascripts/pages/projects/settings/index.js b/app/assets/javascripts/pages/projects/settings/index.js
index cb787c60002..7e97cd865b7 100644
--- a/app/assets/javascripts/pages/projects/settings/index.js
+++ b/app/assets/javascripts/pages/projects/settings/index.js
@@ -1,5 +1,7 @@
import initRevokeButton from '~/deploy_tokens/init_revoke_button';
import initSearchSettings from '~/search_settings';
+import initDeployTokens from '~/deploy_tokens';
+initDeployTokens();
initSearchSettings();
initRevokeButton();
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 655243eee30..d2263fa815d 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js
@@ -1,5 +1,7 @@
import MirrorRepos from '~/mirrors/mirror_repos';
import mountBranchRules from '~/projects/settings/repository/branch_rules/mount_branch_rules';
+import mountDefaultBranchSelector from '~/projects/settings/mount_default_branch_selector';
+
import initForm from '../form';
initForm();
@@ -8,3 +10,4 @@ const mirrorReposContainer = document.querySelector('.js-mirror-settings');
if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init();
mountBranchRules(document.getElementById('js-branch-rules'));
+mountDefaultBranchSelector(document.querySelector('.js-select-default-branch'));
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 a82f485bf44..3e5c02bbf19 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
@@ -898,7 +898,9 @@ export default {
:help-path="pagesHelpPath"
:label="$options.i18n.pagesLabel"
:help-text="
- s__('ProjectSettings|With GitLab Pages you can host your static websites on GitLab.')
+ s__(
+ 'ProjectSettings|With GitLab Pages you can host your static websites on GitLab. GitLab Pages uses a caching mechanism for efficiency. Your changes may not take effect until that cache is invalidated, which usually takes less than a minute.',
+ )
"
>
<project-feature-setting
@@ -979,20 +981,20 @@ export default {
name="project[project_feature_attributes][feature_flags_access_level]"
/>
</project-setting-row>
- <project-setting-row
- ref="releases-settings"
- :label="$options.i18n.releasesLabel"
- :help-text="$options.i18n.releasesHelpText"
- :help-path="releasesHelpPath"
- >
- <project-feature-setting
- v-model="releasesAccessLevel"
- :label="$options.i18n.releasesLabel"
- :options="featureAccessLevelOptions"
- name="project[project_feature_attributes][releases_access_level]"
- />
- </project-setting-row>
</template>
+ <project-setting-row
+ ref="releases-settings"
+ :label="$options.i18n.releasesLabel"
+ :help-text="$options.i18n.releasesHelpText"
+ :help-path="releasesHelpPath"
+ >
+ <project-feature-setting
+ v-model="releasesAccessLevel"
+ :label="$options.i18n.releasesLabel"
+ :options="featureAccessLevelOptions"
+ name="project[project_feature_attributes][releases_access_level]"
+ />
+ </project-setting-row>
</div>
<project-setting-row v-if="canDisableEmails" ref="email-settings" class="mb-3">
<label class="js-emails-disabled">
diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js
index 7ea744a68a6..1848aa70cf0 100644
--- a/app/assets/javascripts/pages/sessions/new/username_validator.js
+++ b/app/assets/javascripts/pages/sessions/new/username_validator.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';
@@ -51,7 +51,7 @@ export default class UsernameValidator extends InputValidator {
);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while validating username'),
}),
);
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
index 10b95fd6f3c..b72579276e8 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
@@ -1,6 +1,6 @@
<script>
import { GlSkeletonLoader, GlSafeHtmlDirective, GlAlert } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { handleLocationHash } from '~/lib/utils/common_utils';
@@ -47,7 +47,7 @@ export default {
handleLocationHash();
})
.catch(() =>
- createFlash({
+ createAlert({
message: this.$options.i18n.renderingContentFailed,
}),
);
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
index 9acc1cb62a1..7b9656de362 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -8,21 +8,19 @@ import {
GlFormGroup,
GlFormInput,
GlFormSelect,
- GlSegmentedControl,
} from '@gitlab/ui';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import axios from '~/lib/utils/axios_utils';
+import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
import csrf from '~/lib/utils/csrf';
import { setUrlFragment } from '~/lib/utils/url_utility';
import { s__, sprintf } from '~/locale';
import Tracking from '~/tracking';
-import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import {
- CONTENT_EDITOR_LOADED_ACTION,
SAVED_USING_CONTENT_EDITOR_ACTION,
WIKI_CONTENT_EDITOR_TRACKING_LABEL,
WIKI_FORMAT_LABEL,
WIKI_FORMAT_UPDATED_ACTION,
+ CONTENT_EDITOR_LOADED_ACTION,
} from '../constants';
const trackingMixin = Tracking.mixin({
@@ -36,6 +34,29 @@ const MARKDOWN_LINK_TEXT = {
org: '[[page-slug]]',
};
+function getPagePath(pageInfo) {
+ return pageInfo.persisted ? pageInfo.path : pageInfo.createPath;
+}
+
+const autosaveKey = (pageInfo, field) => {
+ const path = pageInfo.persisted ? pageInfo.path : pageInfo.createPath;
+
+ return `${path}/${field}`;
+};
+
+const titleAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'title');
+const formatAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'format');
+const contentAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'content');
+const commitAutosaveKey = (pageInfo) => autosaveKey(pageInfo, 'commit');
+
+const getTitle = (pageInfo) => getDraft(titleAutosaveKey(pageInfo)) || pageInfo.title?.trim() || '';
+const getFormat = (pageInfo) =>
+ getDraft(formatAutosaveKey(pageInfo)) || pageInfo.format || 'markdown';
+const getContent = (pageInfo) => getDraft(contentAutosaveKey(pageInfo)) || pageInfo.content || '';
+const getCommitMessage = (pageInfo) =>
+ getDraft(commitAutosaveKey(pageInfo)) || pageInfo.commitMessage || '';
+const getIsFormDirty = (pageInfo) => Boolean(getDraft(titleAutosaveKey(pageInfo)));
+
export default {
i18n: {
title: {
@@ -74,10 +95,6 @@ export default {
},
cancel: s__('WikiPage|Cancel'),
},
- switchEditingControlOptions: [
- { text: s__('Wiki Page|Source'), value: 'source' },
- { text: s__('Wiki Page|Rich text'), value: 'richText' },
- ],
components: {
GlIcon,
GlForm,
@@ -87,26 +104,21 @@ export default {
GlSprintf,
GlLink,
GlButton,
- GlSegmentedControl,
- MarkdownField,
- LocalStorageSync,
- ContentEditor: () =>
- import(
- /* webpackChunkName: 'content_editor' */ '~/content_editor/components/content_editor.vue'
- ),
+ MarkdownEditor,
},
mixins: [trackingMixin],
inject: ['formatOptions', 'pageInfo'],
data() {
return {
editingMode: 'source',
- title: this.pageInfo.title?.trim() || '',
- format: this.pageInfo.format || 'markdown',
- content: this.pageInfo.content || '',
- commitMessage: '',
- isDirty: false,
+ title: getTitle(this.pageInfo),
+ format: getFormat(this.pageInfo),
+ content: getContent(this.pageInfo),
+ commitMessage: getCommitMessage(this.pageInfo),
contentEditorEmpty: false,
+ isContentEditorActive: false,
switchEditingControlDisabled: false,
+ isFormDirty: getIsFormDirty(this.pageInfo),
};
},
computed: {
@@ -117,7 +129,7 @@ export default {
return csrf.token;
},
formAction() {
- return this.pageInfo.persisted ? this.pageInfo.path : this.pageInfo.createPath;
+ return getPagePath(this.pageInfo);
},
helpPath() {
return setUrlFragment(
@@ -162,15 +174,9 @@ export default {
disableSubmitButton() {
return this.noContent || !this.title;
},
- isContentEditorActive() {
- return this.isMarkdownFormat && this.useContentEditor;
- },
- useContentEditor() {
- return this.editingMode === 'richText';
- },
},
mounted() {
- this.updateCommitMessage();
+ if (!this.commitMessage) this.updateCommitMessage();
window.addEventListener('beforeunload', this.onPageUnload);
},
@@ -178,51 +184,45 @@ export default {
window.removeEventListener('beforeunload', this.onPageUnload);
},
methods: {
- renderMarkdown(content) {
- return axios
- .post(this.pageInfo.markdownPreviewPath, { text: content })
- .then(({ data }) => data.body);
- },
-
- setEditingMode(editingMode) {
- this.editingMode = editingMode;
- },
-
async handleFormSubmit(e) {
- e.preventDefault();
+ this.isFormDirty = false;
- if (this.useContentEditor) {
- this.trackFormSubmit();
- }
+ e.preventDefault();
+ this.trackFormSubmit();
this.trackWikiFormat();
// Wait until form field values are refreshed
await this.$nextTick();
e.target.submit();
+ },
- this.isDirty = false;
+ updateDrafts() {
+ updateDraft(titleAutosaveKey(this.pageInfo), this.title);
+ updateDraft(formatAutosaveKey(this.pageInfo), this.format);
+ updateDraft(contentAutosaveKey(this.pageInfo), this.content);
+ updateDraft(commitAutosaveKey(this.pageInfo), this.commitMessage);
},
- handleContentChange() {
- this.isDirty = true;
+ clearDrafts() {
+ clearDraft(titleAutosaveKey(this.pageInfo));
+ clearDraft(formatAutosaveKey(this.pageInfo));
+ clearDraft(contentAutosaveKey(this.pageInfo));
+ clearDraft(commitAutosaveKey(this.pageInfo));
},
- handleContentEditorChange({ empty, markdown, changed }) {
+ handleContentEditorChange({ empty, markdown }) {
this.contentEditorEmpty = empty;
- this.isDirty = changed;
this.content = markdown;
},
- onPageUnload(event) {
- if (!this.isDirty) return undefined;
-
- event.preventDefault();
-
- // eslint-disable-next-line no-param-reassign
- event.returnValue = '';
- return '';
+ onPageUnload() {
+ if (this.isFormDirty) {
+ this.updateDrafts();
+ } else {
+ this.clearDrafts();
+ }
},
updateCommitMessage() {
@@ -235,8 +235,13 @@ export default {
this.commitMessage = newCommitMessage;
},
- trackContentEditorLoaded() {
- this.track(CONTENT_EDITOR_LOADED_ACTION);
+ notifyContentEditorActive() {
+ this.isContentEditorActive = true;
+ this.trackContentEditorLoaded();
+ },
+
+ notifyContentEditorInactive() {
+ this.isContentEditorActive = false;
},
trackFormSubmit() {
@@ -256,12 +261,12 @@ export default {
});
},
- enableSwitchEditingControl() {
- this.switchEditingControlDisabled = false;
+ trackContentEditorLoaded() {
+ this.track(CONTENT_EDITOR_LOADED_ACTION);
},
- disableSwitchEditingControl() {
- this.switchEditingControlDisabled = true;
+ submitFormWithShortcut() {
+ this.$refs.form.submit();
},
},
};
@@ -269,10 +274,12 @@ export default {
<template>
<gl-form
+ ref="form"
:action="formAction"
method="post"
class="wiki-form common-note-form gl-mt-3 js-quick-submit"
@submit="handleFormSubmit"
+ @input="isFormDirty = true"
>
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<input v-if="pageInfo.persisted" type="hidden" name="_method" value="put" />
@@ -329,74 +336,23 @@ export default {
<div class="row" data-testid="wiki-form-content-fieldset">
<div class="col-sm-12 row-sm-5">
<gl-form-group>
- <div v-if="isMarkdownFormat" class="gl-display-flex gl-justify-content-start gl-mb-3">
- <gl-segmented-control
- data-testid="toggle-editing-mode-button"
- data-qa-selector="editing_mode_button"
- class="gl-display-flex"
- :checked="editingMode"
- :options="$options.switchEditingControlOptions"
- :disabled="switchEditingControlDisabled"
- @input="setEditingMode"
- />
- </div>
- <local-storage-sync
- storage-key="gl-wiki-content-editor-enabled"
- :value="editingMode"
- @input="setEditingMode"
- />
- <markdown-field
- v-if="!isContentEditorActive"
- :markdown-preview-path="pageInfo.markdownPreviewPath"
- :can-attach-file="true"
- :enable-autocomplete="true"
- :textarea-value="content"
+ <markdown-editor
+ v-model="content"
+ :render-markdown-path="pageInfo.markdownPreviewPath"
:markdown-docs-path="pageInfo.markdownHelpPath"
:uploads-path="pageInfo.uploadsPath"
+ :enable-content-editor="isMarkdownFormat"
:enable-preview="isMarkdownFormat"
- class="bordered-box"
- >
- <template #textarea>
- <textarea
- id="wiki_content"
- ref="textarea"
- v-model="content"
- name="wiki[content]"
- class="note-textarea js-gfm-input js-autosize markdown-area"
- dir="auto"
- data-supports-quick-actions="false"
- data-qa-selector="wiki_content_textarea"
- :autofocus="pageInfo.persisted"
- :aria-label="$options.i18n.content.label"
- :placeholder="$options.i18n.content.placeholder"
- @input="handleContentChange"
- >
- </textarea>
- </template>
- </markdown-field>
- <div v-if="isContentEditorActive">
- <content-editor
- :render-markdown="renderMarkdown"
- :uploads-path="pageInfo.uploadsPath"
- :markdown="content"
- @initialized="trackContentEditorLoaded"
- @change="handleContentEditorChange"
- @loading="disableSwitchEditingControl"
- @loadingSuccess="enableSwitchEditingControl"
- @loadingError="enableSwitchEditingControl"
- />
- <input
- id="wiki_content"
- v-model.trim="content"
- type="hidden"
- name="wiki[content]"
- data-qa-selector="wiki_hidden_content"
- />
- </div>
-
- <div class="clearfix"></div>
- <div class="error-alert"></div>
-
+ :init-on-autofocus="pageInfo.persisted"
+ :form-field-placeholder="$options.i18n.content.placeholder"
+ :form-field-aria-label="$options.i18n.content.label"
+ form-field-id="wiki_content"
+ form-field-name="wiki[content]"
+ @contentEditor="notifyContentEditorActive"
+ @markdownField="notifyContentEditorInactive"
+ @keydown.ctrl.enter="submitFormShortcut"
+ @keydown.meta.enter="submitFormShortcut"
+ />
<div class="form-text gl-text-gray-600">
<gl-sprintf
v-if="displayWikiSpecificMarkdownHelp"
@@ -447,9 +403,14 @@ export default {
:disabled="disableSubmitButton"
>{{ submitButtonText }}</gl-button
>
- <gl-button data-testid="wiki-cancel-button" :href="cancelFormPath" class="float-right">{{
- $options.i18n.cancel
- }}</gl-button>
+ <gl-button
+ data-testid="wiki-cancel-button"
+ :href="cancelFormPath"
+ class="float-right"
+ @click="isFormDirty = false"
+ >
+ {{ $options.i18n.cancel }}</gl-button
+ >
</div>
</gl-form>
</template>
diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index 9e0af426f6e..fb761725c43 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -1,7 +1,7 @@
import { select } from 'd3-selection';
import $ from 'jquery';
import { last } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import dateFormat from '~/lib/dateformat';
import axios from '~/lib/utils/axios_utils';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
@@ -151,7 +151,7 @@ export default class ActivityCalendar {
.select(container)
.append('svg')
.attr('width', width)
- .attr('height', 167)
+ .attr('height', 169)
.attr('class', 'contrib-calendar');
}
@@ -302,7 +302,7 @@ export default class ActivityCalendar {
});
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while retrieving calendar activity'),
}),
);