summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pages/projects
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/pages/projects')
-rw-r--r--app/assets/javascripts/pages/projects/alert_management/details/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/alert_management/index/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/blob/new/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/environments/metrics/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/index/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/issues/show.js10
-rw-r--r--app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue4
-rw-r--r--app/assets/javascripts/pages/projects/labels/event_hub.js4
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue139
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue3
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js4
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/dag/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js1
-rw-r--r--app/assets/javascripts/pages/projects/settings/access_tokens/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue49
-rw-r--r--app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue5
-rw-r--r--app/assets/javascripts/pages/projects/wikis/wikis.js13
18 files changed, 197 insertions, 75 deletions
diff --git a/app/assets/javascripts/pages/projects/alert_management/details/index.js b/app/assets/javascripts/pages/projects/alert_management/details/index.js
new file mode 100644
index 00000000000..0124795e1af
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/alert_management/details/index.js
@@ -0,0 +1,5 @@
+import AlertDetails from '~/alert_management/details';
+
+document.addEventListener('DOMContentLoaded', () => {
+ AlertDetails('#js-alert_details');
+});
diff --git a/app/assets/javascripts/pages/projects/alert_management/index/index.js b/app/assets/javascripts/pages/projects/alert_management/index/index.js
new file mode 100644
index 00000000000..1e98bcfd2eb
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/alert_management/index/index.js
@@ -0,0 +1,5 @@
+import AlertManagementList from '~/alert_management/list';
+
+document.addEventListener('DOMContentLoaded', () => {
+ AlertManagementList();
+});
diff --git a/app/assets/javascripts/pages/projects/blob/new/index.js b/app/assets/javascripts/pages/projects/blob/new/index.js
index 720cb249052..189053f3ed7 100644
--- a/app/assets/javascripts/pages/projects/blob/new/index.js
+++ b/app/assets/javascripts/pages/projects/blob/new/index.js
@@ -1,12 +1,3 @@
import initBlobBundle from '~/blob_edit/blob_bundle';
-import initPopover from '~/blob/suggest_gitlab_ci_yml';
-document.addEventListener('DOMContentLoaded', () => {
- initBlobBundle();
-
- const suggestEl = document.querySelector('.js-suggest-gitlab-ci-yml');
-
- if (suggestEl) {
- initPopover(suggestEl);
- }
-});
+document.addEventListener('DOMContentLoaded', initBlobBundle);
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 557aea0c5de..e5e4670a5d7 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -32,9 +32,10 @@ document.addEventListener('DOMContentLoaded', () => {
GpgBadges.fetch();
- if (gon.features?.codeNavigation) {
- const el = document.getElementById('js-code-navigation');
- const { codeNavigationPath, blobPath, definitionPathPrefix } = el.dataset;
+ const codeNavEl = document.getElementById('js-code-navigation');
+
+ if (gon.features?.codeNavigation && codeNavEl) {
+ const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset;
// eslint-disable-next-line promise/catch-or-return
import('~/code_navigation').then(m =>
diff --git a/app/assets/javascripts/pages/projects/environments/metrics/index.js b/app/assets/javascripts/pages/projects/environments/metrics/index.js
index 0d69a689316..31ec4e29ad2 100644
--- a/app/assets/javascripts/pages/projects/environments/metrics/index.js
+++ b/app/assets/javascripts/pages/projects/environments/metrics/index.js
@@ -1,3 +1,3 @@
-import monitoringBundle from 'ee_else_ce/monitoring/monitoring_bundle';
+import monitoringBundle from '~/monitoring/monitoring_bundle_with_alerts';
document.addEventListener('DOMContentLoaded', monitoringBundle);
diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index bf54ca972b2..e8e0cda2139 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -7,6 +7,7 @@ import UsersSelect from '~/users_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
+import initIssuablesList from '~/issuables_list';
import initManualOrdering from '~/manual_ordering';
document.addEventListener('DOMContentLoaded', () => {
@@ -16,9 +17,11 @@ document.addEventListener('DOMContentLoaded', () => {
page: FILTERED_SEARCH.ISSUES,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
- new IssuableIndex(ISSUABLE_INDEX.ISSUE);
+ new IssuableIndex(ISSUABLE_INDEX.ISSUE);
new ShortcutsNavigation();
new UsersSelect();
+
initManualOrdering();
+ initIssuablesList();
});
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index 75df80a0f6c..46c9b2fe0af 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -12,6 +12,16 @@ export default function() {
initIssueableApp();
initSentryErrorStackTraceApp();
initRelatedMergeRequestsApp();
+
+ // .js-design-management is currently EE-only.
+ // This will be moved to CE as part of https://gitlab.com/gitlab-org/gitlab/-/issues/212566#frontend
+ // at which point this conditional can be removed.
+ if (document.querySelector('.js-design-management')) {
+ import(/* webpackChunkName: 'design_management' */ '~/design_management')
+ .then(module => module.default())
+ .catch(() => {});
+ }
+
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
index 12e16b79d37..3b26047455d 100644
--- a/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
+++ b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
@@ -1,5 +1,5 @@
<script>
-import { escape as esc } from 'lodash';
+import { escape } from 'lodash';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
@@ -49,7 +49,7 @@ export default {
const label = `<span
class="label color-label"
style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
- >${esc(this.labelTitle)}</span>`;
+ >${escape(this.labelTitle)}</span>`;
return sprintf(
s__('Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>'),
diff --git a/app/assets/javascripts/pages/projects/labels/event_hub.js b/app/assets/javascripts/pages/projects/labels/event_hub.js
index 0948c2e5352..e31806ad199 100644
--- a/app/assets/javascripts/pages/projects/labels/event_hub.js
+++ b/app/assets/javascripts/pages/projects/labels/event_hub.js
@@ -1,3 +1,3 @@
-import Vue from 'vue';
+import createEventHub from '~/helpers/event_hub_factory';
-export default new Vue();
+export default createEventHub();
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
index 3a0d9c17228..4efabcb7df3 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
@@ -1,5 +1,13 @@
<script>
+import { GlSprintf, GlLink } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import { getWeekdayNames } from '~/lib/utils/datetime_utility';
+
export default {
+ components: {
+ GlSprintf,
+ GlLink,
+ },
props: {
initialCronInterval: {
type: String,
@@ -9,25 +17,51 @@ export default {
},
data() {
return {
+ isEditingCustom: false,
+ randomHour: this.generateRandomHour(),
+ randomWeekDayIndex: this.generateRandomWeekDayIndex(),
+ randomDay: this.generateRandomDay(),
inputNameAttribute: 'schedule[cron]',
cronInterval: this.initialCronInterval,
- cronIntervalPresets: {
- everyDay: '0 4 * * *',
- everyWeek: '0 4 * * 0',
- everyMonth: '0 4 1 * *',
- },
cronSyntaxUrl: 'https://en.wikipedia.org/wiki/Cron',
- customInputEnabled: false,
};
},
computed: {
+ cronIntervalPresets() {
+ return {
+ everyDay: `0 ${this.randomHour} * * *`,
+ everyWeek: `0 ${this.randomHour} * * ${this.randomWeekDayIndex}`,
+ everyMonth: `0 ${this.randomHour} ${this.randomDay} * *`,
+ };
+ },
intervalIsPreset() {
return Object.values(this.cronIntervalPresets).includes(this.cronInterval);
},
- // The text input is editable when there's a custom interval, or when it's
- // a preset interval and the user clicks the 'custom' radio button
- isEditable() {
- return Boolean(this.customInputEnabled || !this.intervalIsPreset);
+ formattedTime() {
+ if (this.randomHour > 12) {
+ return `${this.randomHour - 12}:00pm`;
+ } else if (this.randomHour === 12) {
+ return `12:00pm`;
+ }
+ return `${this.randomHour}:00am`;
+ },
+ weekday() {
+ return getWeekdayNames()[this.randomWeekDayIndex];
+ },
+ everyDayText() {
+ return sprintf(s__(`Every day (at %{time})`), { time: this.formattedTime });
+ },
+ everyWeekText() {
+ return sprintf(s__('Every week (%{weekday} at %{time})'), {
+ weekday: this.weekday,
+ time: this.formattedTime,
+ });
+ },
+ everyMonthText() {
+ return sprintf(s__('Every month (Day %{day} at %{time})'), {
+ day: this.randomDay,
+ time: this.formattedTime,
+ });
},
},
watch: {
@@ -39,14 +73,31 @@ export default {
});
},
},
- created() {
- if (this.intervalIsPreset) {
- this.enableCustomInput = false;
+ // If at the mounting stage the default is still an empty string, we
+ // know we are not editing an existing field so we update it so
+ // that the default is the first radio option
+ mounted() {
+ if (this.cronInterval === '') {
+ this.cronInterval = this.cronIntervalPresets.everyDay;
}
},
methods: {
+ setCustomInput(e) {
+ if (!this.isEditingCustom) {
+ this.isEditingCustom = true;
+ this.$refs.customInput.click();
+ // Because we need to manually trigger the click on the radio btn,
+ // it will add a space to update the v-model. If the user is typing
+ // and the space is added, it will feel very unituitive so we reset
+ // the value to the original
+ this.cronInterval = e.target.value;
+ }
+ if (this.intervalIsPreset) {
+ this.isEditingCustom = false;
+ }
+ },
toggleCustomInput(shouldEnable) {
- this.customInputEnabled = shouldEnable;
+ this.isEditingCustom = shouldEnable;
if (shouldEnable) {
// We need to change the value so other radios don't remain selected
@@ -54,6 +105,15 @@ export default {
this.cronInterval = `${this.cronInterval} `;
}
},
+ generateRandomHour() {
+ return Math.floor(Math.random() * 23);
+ },
+ generateRandomWeekDayIndex() {
+ return Math.floor(Math.random() * 6);
+ },
+ generateRandomDay() {
+ return Math.floor(Math.random() * 28);
+ },
},
};
</script>
@@ -62,24 +122,6 @@ export default {
<div class="interval-pattern-form-group">
<div class="cron-preset-radio-input">
<input
- id="custom"
- :name="inputNameAttribute"
- :value="cronInterval"
- :checked="isEditable"
- class="label-bold"
- type="radio"
- @click="toggleCustomInput(true)"
- />
-
- <label for="custom"> {{ s__('PipelineSheduleIntervalPattern|Custom') }} </label>
-
- <span class="cron-syntax-link-wrap">
- (<a :href="cronSyntaxUrl" target="_blank"> {{ __('Cron syntax') }} </a>)
- </span>
- </div>
-
- <div class="cron-preset-radio-input">
- <input
id="every-day"
v-model="cronInterval"
:name="inputNameAttribute"
@@ -89,7 +131,9 @@ export default {
@click="toggleCustomInput(false)"
/>
- <label class="label-bold" for="every-day"> {{ __('Every day (at 4:00am)') }} </label>
+ <label class="label-bold" for="every-day">
+ {{ everyDayText }}
+ </label>
</div>
<div class="cron-preset-radio-input">
@@ -104,7 +148,7 @@ export default {
/>
<label class="label-bold" for="every-week">
- {{ __('Every week (Sundays at 4:00am)') }}
+ {{ everyWeekText }}
</label>
</div>
@@ -120,20 +164,43 @@ export default {
/>
<label class="label-bold" for="every-month">
- {{ __('Every month (on the 1st at 4:00am)') }}
+ {{ everyMonthText }}
</label>
</div>
+ <div class="cron-preset-radio-input">
+ <input
+ id="custom"
+ ref="customInput"
+ v-model="cronInterval"
+ :name="inputNameAttribute"
+ :value="cronInterval"
+ class="label-bold"
+ type="radio"
+ @click="toggleCustomInput(true)"
+ />
+
+ <label for="custom"> {{ s__('PipelineSheduleIntervalPattern|Custom') }} </label>
+
+ <gl-sprintf :message="__('(%{linkStart}Cron syntax%{linkEnd})')">
+ <template #link="{content}">
+ <gl-link :href="cronSyntaxUrl" target="_blank" class="gl-font-sm">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+
<div class="cron-interval-input-wrapper">
<input
id="schedule_cron"
v-model="cronInterval"
:placeholder="__('Define a custom pattern with cron syntax')"
:name="inputNameAttribute"
- :disabled="!isEditable"
class="form-control inline cron-interval-input"
type="text"
required="true"
+ @input="setCustomInput"
/>
</div>
</div>
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
index 22512a6f12a..da96e6f36b4 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
@@ -2,7 +2,8 @@
import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../../../../../vue_shared/translate';
-import illustrationSvg from '../icons/intro_illustration.svg';
+// Full path is needed for Jest to be able to correctly mock this file
+import illustrationSvg from '~/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg';
import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(Translate);
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
index dc6df27f1c7..497e2c9c0ae 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
@@ -11,9 +11,7 @@ Vue.use(Translate);
function initIntervalPatternInput() {
const intervalPatternMount = document.getElementById('interval-pattern-input');
- const initialCronInterval = intervalPatternMount
- ? intervalPatternMount.dataset.initialInterval
- : '';
+ const initialCronInterval = intervalPatternMount?.dataset?.initialInterval;
return new Vue({
el: intervalPatternMount,
diff --git a/app/assets/javascripts/pages/projects/pipelines/dag/index.js b/app/assets/javascripts/pages/projects/pipelines/dag/index.js
new file mode 100644
index 00000000000..d19c22ba556
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/pipelines/dag/index.js
@@ -0,0 +1,2 @@
+// /dag is an alias for show
+import '../show/index';
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index 4b4a274794d..bbad3238ec4 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -50,6 +50,7 @@ document.addEventListener(
hasGitlabCi: parseBoolean(this.dataset.hasGitlabCi),
ciLintPath: this.dataset.ciLintPath,
resetCachePath: this.dataset.resetCachePath,
+ projectId: this.dataset.projectId,
},
});
},
diff --git a/app/assets/javascripts/pages/projects/settings/access_tokens/index.js b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js
new file mode 100644
index 00000000000..ae2209b0292
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js
@@ -0,0 +1,3 @@
+import initExpiresAtField from '~/access_tokens';
+
+document.addEventListener('DOMContentLoaded', initExpiresAtField);
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 6efddec1172..ab32fe18972 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
@@ -1,9 +1,8 @@
<script>
-import { GlSprintf, GlLink } from '@gitlab/ui';
+import { GlSprintf, GlLink, GlFormCheckbox } from '@gitlab/ui';
import settingsMixin from 'ee_else_ce/pages/projects/shared/permissions/mixins/settings_pannel_mixin';
import { s__ } from '~/locale';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import projectFeatureSetting from './project_feature_setting.vue';
import projectFeatureToggle from '~/vue_shared/components/toggle_button.vue';
import projectSettingRow from './project_setting_row.vue';
@@ -12,6 +11,7 @@ import {
visibilityLevelDescriptions,
featureAccessLevelMembers,
featureAccessLevelEveryone,
+ featureAccessLevel,
} from '../constants';
import { toggleHiddenClassBySelector } from '../external';
@@ -24,8 +24,9 @@ export default {
projectSettingRow,
GlSprintf,
GlLink,
+ GlFormCheckbox,
},
- mixins: [settingsMixin, glFeatureFlagsMixin()],
+ mixins: [settingsMixin],
props: {
currentSettings: {
@@ -127,7 +128,7 @@ export default {
wikiAccessLevel: 20,
snippetsAccessLevel: 20,
pagesAccessLevel: 20,
- metricsAccessLevel: visibilityOptions.PRIVATE,
+ metricsDashboardAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
containerRegistryEnabled: true,
lfsEnabled: true,
requestAccessEnabled: true,
@@ -174,6 +175,10 @@ export default {
return options;
},
+ metricsOptionsDropdownEnabled() {
+ return this.featureAccessLevelOptions.length < 2;
+ },
+
repositoryEnabled() {
return this.repositoryAccessLevel > 0;
},
@@ -195,10 +200,6 @@ export default {
'ProjectSettings|View and edit files in this project. Non-project members will only have read access',
);
},
-
- metricsDashboardVisibilitySwitchingAvailable() {
- return this.glFeatures.metricsDashboardVisibilitySwitchingAvailable;
- },
},
watch: {
@@ -211,6 +212,7 @@ export default {
this.buildsAccessLevel = Math.min(10, this.buildsAccessLevel);
this.wikiAccessLevel = Math.min(10, this.wikiAccessLevel);
this.snippetsAccessLevel = Math.min(10, this.snippetsAccessLevel);
+ this.metricsDashboardAccessLevel = Math.min(10, this.metricsDashboardAccessLevel);
if (this.pagesAccessLevel === 20) {
// When from Internal->Private narrow access for only members
this.pagesAccessLevel = 10;
@@ -225,6 +227,7 @@ export default {
if (this.wikiAccessLevel > 0) this.wikiAccessLevel = 20;
if (this.snippetsAccessLevel > 0) this.snippetsAccessLevel = 20;
if (this.pagesAccessLevel === 10) this.pagesAccessLevel = 20;
+ if (this.metricsDashboardAccessLevel === 10) this.metricsDashboardAccessLevel = 20;
this.highlightChanges();
}
},
@@ -473,7 +476,6 @@ export default {
/>
</project-setting-row>
<project-setting-row
- v-if="metricsDashboardVisibilitySwitchingAvailable"
ref="metrics-visibility-settings"
:label="__('Metrics Dashboard')"
:help-text="
@@ -485,17 +487,18 @@ export default {
<div class="project-feature-controls">
<div class="select-wrapper">
<select
- v-model="metricsAccessLevel"
+ v-model="metricsDashboardAccessLevel"
+ :disabled="metricsOptionsDropdownEnabled"
name="project[project_feature_attributes][metrics_dashboard_access_level]"
- class="form-control select-control"
+ class="form-control project-repo-select select-control"
>
<option
- :value="visibilityOptions.PRIVATE"
- :disabled="!visibilityAllowed(visibilityOptions.PRIVATE)"
+ :value="featureAccessLevelMembers[0]"
+ :disabled="!visibilityAllowed(visibilityOptions.INTERNAL)"
>{{ featureAccessLevelMembers[1] }}</option
>
<option
- :value="visibilityOptions.PUBLIC"
+ :value="featureAccessLevelEveryone[0]"
:disabled="!visibilityAllowed(visibilityOptions.PUBLIC)"
>{{ featureAccessLevelEveryone[1] }}</option
>
@@ -517,5 +520,23 @@ export default {
)
}}</span>
</project-setting-row>
+ <project-setting-row class="mb-3">
+ <input
+ :value="showDefaultAwardEmojis"
+ type="hidden"
+ name="project[project_setting_attributes][show_default_award_emojis]"
+ />
+ <gl-form-checkbox
+ v-model="showDefaultAwardEmojis"
+ name="project[project_setting_attributes][show_default_award_emojis]"
+ >
+ {{ s__('ProjectSettings|Show default award emojis') }}
+ <template #help>{{
+ s__(
+ 'ProjectSettings|When enabled, issues, merge requests, and snippets will always show thumbs-up and thumbs-down award emoji buttons.',
+ )
+ }}</template>
+ </gl-form-checkbox>
+ </project-setting-row>
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
index 6af346ace67..580cca49b5e 100644
--- a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
+++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
@@ -1,5 +1,5 @@
<script>
-import { escape as esc } from 'lodash';
+import { escape } from 'lodash';
import { GlModal, GlModalDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
@@ -38,7 +38,7 @@ export default {
return sprintf(
s__('WikiPageConfirmDelete|Delete page %{pageTitle}?'),
{
- pageTitle: esc(this.pageTitle),
+ pageTitle: escape(this.pageTitle),
},
false,
);
@@ -46,6 +46,7 @@ export default {
},
methods: {
onSubmit() {
+ window.onbeforeunload = null;
this.$refs.form.submit();
},
},
diff --git a/app/assets/javascripts/pages/projects/wikis/wikis.js b/app/assets/javascripts/pages/projects/wikis/wikis.js
index 93afdc54ce1..ed67219383b 100644
--- a/app/assets/javascripts/pages/projects/wikis/wikis.js
+++ b/app/assets/javascripts/pages/projects/wikis/wikis.js
@@ -44,6 +44,19 @@ export default class Wikis {
linkExample.innerHTML = MARKDOWN_LINK_TEXT[e.target.value];
});
}
+
+ const wikiTextarea = document.querySelector('form.wiki-form #wiki_content');
+ const wikiForm = document.querySelector('form.wiki-form');
+
+ if (wikiTextarea) {
+ wikiTextarea.addEventListener('input', () => {
+ window.onbeforeunload = () => '';
+ });
+
+ wikiForm.addEventListener('submit', () => {
+ window.onbeforeunload = null;
+ });
+ }
}
handleWikiTitleChange(e) {