Add latest changes from gitlab-org/gitlab@15-10-stable-ee

This commit is contained in:
GitLab Bot 2023-04-12 06:47:21 +00:00
parent 2dd1c1ab9d
commit c20ce49bda
10 changed files with 161 additions and 40 deletions

View File

@ -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"

View File

@ -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';

View File

@ -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, {

View File

@ -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, {

View File

@ -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

View File

@ -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) }

View File

@ -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) } }

View File

@ -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

View File

@ -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();

View File

@ -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