Commit 1c858cc3 authored by Simon Knox's avatar Simon Knox Committed by Andrew Fontaine

Warn when mention all users in a group

Currently a naive guess at when we are including all, since
we only validate it on the backend

Changelog: changed
parent bdab03b0
......@@ -124,13 +124,6 @@ const writeButtonSelector = '.js-md-write-button';
lastTextareaPreviewed = null;
const markdownToolbar = $('.md-header-toolbar');
$.fn.setupMarkdownPreview = function () {
const $form = $(this);
$form.find('textarea.markdown-area').on('input', () => {
markdownPreview.hideReferencedUsers($form);
});
};
$(document).on('markdown-preview:show', (e, $form) => {
if (!$form) {
return;
......
......@@ -51,7 +51,6 @@ export default function dropzoneInput(form, config = { parallelUploads: 2 }) {
// Add dropzone area to the form.
const $mdArea = formTextarea.closest('.md-area');
form.setupMarkdownPreview();
const $formDropzone = form.find('.div-dropzone');
$formDropzone.parent().addClass('div-dropzone-wrapper');
$formDropzone.append(divHover);
......
......@@ -2,7 +2,7 @@
import { GlIcon } from '@gitlab/ui';
import $ from 'jquery';
import '~/behaviors/markdown/render_gfm';
import { unescape } from 'lodash';
import { debounce, unescape } from 'lodash';
import createFlash from '~/flash';
import GLForm from '~/gl_form';
import axios from '~/lib/utils/axios_utils';
......@@ -110,7 +110,7 @@ export default {
return {
markdownPreview: '',
referencedCommands: '',
referencedUsers: '',
referencedUsers: [],
hasSuggestion: false,
markdownPreviewLoading: false,
previewMarkdown: false,
......@@ -188,6 +188,24 @@ export default {
});
}
},
textareaValue: {
immediate: true,
handler(textareaValue, oldVal) {
const all = /@all([^\w._-]|$)/;
const hasAll = all.test(textareaValue);
const hadAll = all.test(oldVal);
const justAddedAll = !hadAll && hasAll;
const justRemovedAll = hadAll && !hasAll;
if (justAddedAll) {
this.debouncedFetchMarkdown();
} else if (justRemovedAll) {
this.referencedUsers = [];
}
},
},
},
mounted() {
// GLForm class handles all the toolbar buttons
......@@ -222,9 +240,9 @@ export default {
if (this.textareaValue) {
this.markdownPreviewLoading = true;
this.markdownPreview = __('Loading…');
axios
.post(this.markdownPreviewPath, { text: this.textareaValue })
.then((response) => this.renderMarkdown(response.data))
this.fetchMarkdown()
.then((data) => this.renderMarkdown(data))
.catch(() =>
createFlash({
message: __('Error loading markdown preview'),
......@@ -239,17 +257,28 @@ export default {
this.previewMarkdown = false;
},
fetchMarkdown() {
return axios.post(this.markdownPreviewPath, { text: this.textareaValue }).then(({ data }) => {
const { references } = data;
if (references) {
this.referencedCommands = references.commands;
this.referencedUsers = references.users;
this.hasSuggestion = references.suggestions?.length > 0;
this.suggestions = references.suggestions;
}
return data;
});
},
debouncedFetchMarkdown: debounce(function debouncedFetchMarkdown() {
return this.fetchMarkdown();
}, 400),
renderMarkdown(data = {}) {
this.markdownPreviewLoading = false;
this.markdownPreview = data.body || __('Nothing to preview.');
if (data.references) {
this.referencedCommands = data.references.commands;
this.referencedUsers = data.references.users;
this.hasSuggestion = data.references.suggestions && data.references.suggestions.length;
this.suggestions = data.references.suggestions;
}
this.$nextTick()
.then(() => $(this.$refs['markdown-preview']).renderGFM())
.catch(() =>
......@@ -326,18 +355,14 @@ export default {
v-html="markdownPreview /* eslint-disable-line vue/no-v-html */"
></div>
</template>
<template v-if="previewMarkdown && !markdownPreviewLoading">
<div
v-if="referencedCommands"
class="referenced-commands"
v-html="referencedCommands /* eslint-disable-line vue/no-v-html */"
></div>
<div v-if="shouldShowReferencedUsers" class="referenced-users">
<gl-icon name="warning-solid" />
<span
v-html="addMultipleToDiscussionWarning /* eslint-disable-line vue/no-v-html */"
></span>
</div>
</template>
<div
v-if="referencedCommands && previewMarkdown && !markdownPreviewLoading"
class="referenced-commands"
v-html="referencedCommands /* eslint-disable-line vue/no-v-html */"
></div>
<div v-if="shouldShowReferencedUsers" class="referenced-users">
<gl-icon name="warning-solid" />
<span v-html="addMultipleToDiscussionWarning /* eslint-disable-line vue/no-v-html */"></span>
</div>
</div>
</template>
......@@ -90,6 +90,8 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
/>
<!---->
<!---->
</div>
</div>
</div>
......
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
......@@ -242,6 +243,41 @@ describe('Markdown field component', () => {
expect(dropzoneSpy).toHaveBeenCalled();
});
describe('mentioning all users', () => {
const users = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((i) => `user_${i}`);
it('shows warning on mention of all users', async () => {
axiosMock.onPost(markdownPreviewPath).reply(200, { references: { users } });
subject.setProps({ textareaValue: 'hello @all' });
await axios.waitFor(markdownPreviewPath).then(() => {
expect(subject.text()).toContain(
'You are about to add 11 people to the discussion. They will all receive a notification.',
);
});
});
it('removes warning when all mention is removed', async () => {
axiosMock.onPost(markdownPreviewPath).reply(200, { references: { users } });
subject.setProps({ textareaValue: 'hello @all' });
await axios.waitFor(markdownPreviewPath);
jest.spyOn(axios, 'post');
subject.setProps({ textareaValue: 'hello @allan' });
await nextTick();
expect(axios.post).not.toHaveBeenCalled();
expect(subject.text()).not.toContain(
'You are about to add 11 people to the discussion. They will all receive a notification.',
);
});
});
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment