Add latest changes from gitlab-org/gitlab@15-10-stable-ee
This commit is contained in:
parent
2dd1c1ab9d
commit
c20ce49bda
|
|
@ -17,13 +17,7 @@ import { redirectTo } from '~/lib/utils/url_utility';
|
|||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import {
|
||||
BROADCAST_MESSAGES_PATH,
|
||||
MESSAGES_PREVIEW_PATH,
|
||||
THEMES,
|
||||
TYPES,
|
||||
TYPE_BANNER,
|
||||
} from '../constants';
|
||||
import { THEMES, TYPES, TYPE_BANNER } from '../constants';
|
||||
import MessageFormGroup from './message_form_group.vue';
|
||||
import DatetimePicker from './datetime_picker.vue';
|
||||
|
||||
|
|
@ -49,7 +43,17 @@ export default {
|
|||
SafeHtml,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
inject: ['targetAccessLevelOptions'],
|
||||
inject: {
|
||||
targetAccessLevelOptions: {
|
||||
default: [[]],
|
||||
},
|
||||
messagesPath: {
|
||||
default: '',
|
||||
},
|
||||
previewPath: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
message: s__('BroadcastMessages|Message'),
|
||||
messagePlaceholder: s__('BroadcastMessages|Your message here'),
|
||||
|
|
@ -111,8 +115,8 @@ export default {
|
|||
},
|
||||
formPath() {
|
||||
return this.isAddForm
|
||||
? BROADCAST_MESSAGES_PATH
|
||||
: `${BROADCAST_MESSAGES_PATH}/${this.broadcastMessage.id}`;
|
||||
? this.messagesPath
|
||||
: `${this.messagesPath}/${this.broadcastMessage.id}`;
|
||||
},
|
||||
formPayload() {
|
||||
return JSON.stringify({
|
||||
|
|
@ -138,7 +142,7 @@ export default {
|
|||
|
||||
const success = await this.submitForm();
|
||||
if (success) {
|
||||
redirectTo(BROADCAST_MESSAGES_PATH);
|
||||
redirectTo(this.messagesPath);
|
||||
} else {
|
||||
this.loading = false;
|
||||
}
|
||||
|
|
@ -161,7 +165,7 @@ export default {
|
|||
|
||||
async renderPreview() {
|
||||
try {
|
||||
const res = await axios.post(MESSAGES_PREVIEW_PATH, this.formPayload, FORM_HEADERS);
|
||||
const res = await axios.post(this.previewPath, this.formPayload, FORM_HEADERS);
|
||||
this.renderedMessage = res.data;
|
||||
} catch (e) {
|
||||
this.renderedMessage = '';
|
||||
|
|
@ -175,7 +179,13 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<gl-form @submit.prevent="onSubmit">
|
||||
<gl-broadcast-message class="gl-my-6" :type="type" :theme="theme" :dismissible="dismissable">
|
||||
<gl-broadcast-message
|
||||
class="gl-my-6"
|
||||
:type="type"
|
||||
:theme="theme"
|
||||
:dismissible="dismissable"
|
||||
data-testid="preview-broadcast-message"
|
||||
>
|
||||
<div v-safe-html:[$options.safeHtmlConfig]="messagePreview"></div>
|
||||
</gl-broadcast-message>
|
||||
|
||||
|
|
@ -186,6 +196,7 @@ export default {
|
|||
size="sm"
|
||||
:debounce="$options.DEFAULT_DEBOUNCE_AND_THROTTLE_MS"
|
||||
:placeholder="$options.i18n.messagePlaceholder"
|
||||
data-testid="message-input"
|
||||
/>
|
||||
</message-form-group>
|
||||
|
||||
|
|
@ -241,7 +252,7 @@ export default {
|
|||
<datetime-picker v-model="endsAt" />
|
||||
</message-form-group>
|
||||
|
||||
<div class="form-actions gl-mb-3">
|
||||
<div class="form-actions gl-my-3">
|
||||
<gl-button
|
||||
type="submit"
|
||||
variant="confirm"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { s__ } from '~/locale';
|
||||
|
||||
export const BROADCAST_MESSAGES_PATH = '/admin/broadcast_messages';
|
||||
export const MESSAGES_PREVIEW_PATH = '/admin/broadcast_messages/preview';
|
||||
|
||||
export const TYPE_BANNER = 'banner';
|
||||
export const TYPE_NOTIFICATION = 'notification';
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ export default () => {
|
|||
dismissable,
|
||||
targetAccessLevels,
|
||||
targetAccessLevelOptions,
|
||||
messagesPath,
|
||||
previewPath,
|
||||
targetPath,
|
||||
startsAt,
|
||||
endsAt,
|
||||
|
|
@ -21,6 +23,8 @@ export default () => {
|
|||
name: 'EditBroadcastMessage',
|
||||
provide: {
|
||||
targetAccessLevelOptions: JSON.parse(targetAccessLevelOptions),
|
||||
messagesPath,
|
||||
previewPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(MessageForm, {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,22 @@ import BroadcastMessagesBase from './components/base.vue';
|
|||
|
||||
export default () => {
|
||||
const el = document.querySelector('#js-broadcast-messages');
|
||||
const { page, targetAccessLevelOptions, messagesCount, messages } = el.dataset;
|
||||
const {
|
||||
page,
|
||||
targetAccessLevelOptions,
|
||||
messagesPath,
|
||||
previewPath,
|
||||
messagesCount,
|
||||
messages,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'BroadcastMessages',
|
||||
provide: {
|
||||
targetAccessLevelOptions: JSON.parse(targetAccessLevelOptions),
|
||||
messagesPath,
|
||||
previewPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(BroadcastMessagesBase, {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,23 @@ module BroadcastMessagesHelper
|
|||
end.to_json
|
||||
end
|
||||
|
||||
def broadcast_message_data(broadcast_message)
|
||||
{
|
||||
id: broadcast_message.id,
|
||||
message: broadcast_message.message,
|
||||
broadcast_type: broadcast_message.broadcast_type,
|
||||
theme: broadcast_message.theme,
|
||||
dismissable: broadcast_message.dismissable.to_s,
|
||||
target_access_levels: broadcast_message.target_access_levels,
|
||||
messages_path: admin_broadcast_messages_path,
|
||||
preview_path: preview_admin_broadcast_messages_path,
|
||||
target_path: broadcast_message.target_path,
|
||||
starts_at: broadcast_message.starts_at.iso8601,
|
||||
ends_at: broadcast_message.ends_at.iso8601,
|
||||
target_access_level_options: target_access_level_options.to_json
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user_access_level_for_project_or_group
|
||||
|
|
|
|||
|
|
@ -2,15 +2,4 @@
|
|||
- breadcrumb_title @broadcast_message.id
|
||||
- page_title _("Broadcast Messages")
|
||||
|
||||
#js-broadcast-message{ data: {
|
||||
id: @broadcast_message.id,
|
||||
message: @broadcast_message.message,
|
||||
broadcast_type: @broadcast_message.broadcast_type,
|
||||
theme: @broadcast_message.theme,
|
||||
dismissable: @broadcast_message.dismissable.to_s,
|
||||
target_access_levels: @broadcast_message.target_access_levels,
|
||||
target_path: @broadcast_message.target_path,
|
||||
starts_at: @broadcast_message.starts_at,
|
||||
ends_at: @broadcast_message.ends_at,
|
||||
target_access_level_options: target_access_level_options.to_json,
|
||||
} }
|
||||
#js-broadcast-message{ data: broadcast_message_data(@broadcast_message) }
|
||||
|
|
|
|||
|
|
@ -9,5 +9,7 @@
|
|||
#js-broadcast-messages{ data: {
|
||||
page: params[:page] || 1,
|
||||
target_access_level_options: target_access_level_options.to_json,
|
||||
messages_path: admin_broadcast_messages_path,
|
||||
preview_path: preview_admin_broadcast_messages_path,
|
||||
messages_count: @broadcast_messages.total_count,
|
||||
messages: admin_broadcast_messages_data(@broadcast_messages) } }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Admin Broadcast Messages', :js, feature_category: :onboarding do
|
||||
context 'when creating and editing' do
|
||||
it 'previews, creates and edits a broadcast message' do
|
||||
admin = create(:admin)
|
||||
sign_in(admin)
|
||||
gitlab_enable_admin_mode_sign_in(admin)
|
||||
|
||||
# create
|
||||
visit admin_broadcast_messages_path
|
||||
|
||||
fill_in 'Message', with: 'test message'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within(preview_container) do
|
||||
expect(page).to have_content('test message')
|
||||
end
|
||||
|
||||
click_button 'Add broadcast message'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within(preview_container) do
|
||||
expect(page).to have_content('Your message here')
|
||||
end
|
||||
|
||||
page.within(first_message_container) do
|
||||
expect(page).to have_content('test message')
|
||||
end
|
||||
|
||||
# edit
|
||||
page.within(first_message_container) do
|
||||
find('[data-testid="edit-message"]').click
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(find('[data-testid="message-input"]').value).to eq('test message')
|
||||
|
||||
fill_in 'Message', with: 'changed test message'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within(preview_container) do
|
||||
expect(page).to have_content('changed test message')
|
||||
end
|
||||
|
||||
click_button 'Update broadcast message'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within(preview_container) do
|
||||
expect(page).to have_content('Your message here')
|
||||
end
|
||||
|
||||
page.within(first_message_container) do
|
||||
expect(page).to have_content('changed test message')
|
||||
end
|
||||
end
|
||||
|
||||
def preview_container
|
||||
find('[data-testid="preview-broadcast-message"]')
|
||||
end
|
||||
|
||||
def first_message_container
|
||||
find('[data-testid="message-row"]', match: :first)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,12 +5,7 @@ import { createAlert } from '~/alert';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
|
||||
import MessageForm from '~/admin/broadcast_messages/components/message_form.vue';
|
||||
import {
|
||||
BROADCAST_MESSAGES_PATH,
|
||||
TYPE_BANNER,
|
||||
TYPE_NOTIFICATION,
|
||||
THEMES,
|
||||
} from '~/admin/broadcast_messages/constants';
|
||||
import { TYPE_BANNER, TYPE_NOTIFICATION, THEMES } from '~/admin/broadcast_messages/constants';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { MOCK_TARGET_ACCESS_LEVELS } from '../mock_data';
|
||||
|
|
@ -32,6 +27,8 @@ describe('MessageForm', () => {
|
|||
endsAt: new Date(),
|
||||
};
|
||||
|
||||
const messagesPath = '_messages_path_';
|
||||
|
||||
const findPreview = () => extendedWrapper(wrapper.findComponent(GlBroadcastMessage));
|
||||
const findThemeSelect = () => wrapper.findComponent('[data-testid=theme-select]');
|
||||
const findDismissable = () => wrapper.findComponent('[data-testid=dismissable-checkbox]');
|
||||
|
|
@ -44,6 +41,8 @@ describe('MessageForm', () => {
|
|||
provide: {
|
||||
glFeatures,
|
||||
targetAccessLevelOptions: MOCK_TARGET_ACCESS_LEVELS,
|
||||
messagesPath,
|
||||
previewPath: '_preview_path_',
|
||||
},
|
||||
propsData: {
|
||||
broadcastMessage: {
|
||||
|
|
@ -153,14 +152,14 @@ describe('MessageForm', () => {
|
|||
|
||||
expect(axiosMock.history.post).toHaveLength(1);
|
||||
expect(axiosMock.history.post[0]).toMatchObject({
|
||||
url: BROADCAST_MESSAGES_PATH,
|
||||
url: messagesPath,
|
||||
data: JSON.stringify(defaultPayload),
|
||||
});
|
||||
});
|
||||
|
||||
it('shows an error alert if the create request fails', async () => {
|
||||
createComponent({ broadcastMessage: { id: undefined } });
|
||||
axiosMock.onPost(BROADCAST_MESSAGES_PATH).replyOnce(HTTP_STATUS_BAD_REQUEST);
|
||||
axiosMock.onPost(messagesPath).replyOnce(HTTP_STATUS_BAD_REQUEST);
|
||||
findForm().vm.$emit('submit', { preventDefault: () => {} });
|
||||
await waitForPromises();
|
||||
|
||||
|
|
@ -179,7 +178,7 @@ describe('MessageForm', () => {
|
|||
|
||||
expect(axiosMock.history.patch).toHaveLength(1);
|
||||
expect(axiosMock.history.patch[0]).toMatchObject({
|
||||
url: `${BROADCAST_MESSAGES_PATH}/${id}`,
|
||||
url: `${messagesPath}/${id}`,
|
||||
data: JSON.stringify(defaultPayload),
|
||||
});
|
||||
});
|
||||
|
|
@ -187,7 +186,7 @@ describe('MessageForm', () => {
|
|||
it('shows an error alert if the update request fails', async () => {
|
||||
const id = 1337;
|
||||
createComponent({ broadcastMessage: { id } });
|
||||
axiosMock.onPost(`${BROADCAST_MESSAGES_PATH}/${id}`).replyOnce(HTTP_STATUS_BAD_REQUEST);
|
||||
axiosMock.onPost(`${messagesPath}/${id}`).replyOnce(HTTP_STATUS_BAD_REQUEST);
|
||||
findForm().vm.$emit('submit', { preventDefault: () => {} });
|
||||
await waitForPromises();
|
||||
|
||||
|
|
|
|||
|
|
@ -157,4 +157,24 @@ RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do
|
|||
expect(single_broadcast_message['ends_at']).to eq('2020-01-02T00:00:00Z')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#broadcast_message_data' do
|
||||
let(:starts_at) { 1.day.ago }
|
||||
let(:ends_at) { 1.day.from_now }
|
||||
let(:message) { build(:broadcast_message, id: non_existing_record_id, starts_at: starts_at, ends_at: ends_at) }
|
||||
|
||||
it 'returns the expected message data attributes' do
|
||||
keys = [
|
||||
:id, :message, :broadcast_type, :theme, :dismissable, :target_access_levels, :messages_path,
|
||||
:preview_path, :target_path, :starts_at, :ends_at, :target_access_level_options
|
||||
]
|
||||
|
||||
expect(broadcast_message_data(message).keys).to match(keys)
|
||||
end
|
||||
|
||||
it 'has the correct iso formatted date', time_travel_to: '2020-01-01 00:00:00 +0000' do
|
||||
expect(broadcast_message_data(message)[:starts_at]).to eq('2019-12-31T00:00:00Z')
|
||||
expect(broadcast_message_data(message)[:ends_at]).to eq('2020-01-02T00:00:00Z')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue