diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-12 06:47:21 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-12 06:47:21 +0000 |
commit | c20ce49bdab650656be01968381f6ee1a5f96e7c (patch) | |
tree | 808be3d86edf4e29a5f148aae6bb9817ea3ee9be | |
parent | 2dd1c1ab9db62a17d8f7ccaa29cec5a5f437d8de (diff) | |
download | gitlab-ce-c20ce49bdab650656be01968381f6ee1a5f96e7c.tar.gz |
Add latest changes from gitlab-org/gitlab@15-10-stable-ee
10 files changed, 161 insertions, 40 deletions
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue index 65aa4cba074..4482198675d 100644 --- a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue +++ b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue @@ -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" diff --git a/app/assets/javascripts/admin/broadcast_messages/constants.js b/app/assets/javascripts/admin/broadcast_messages/constants.js index 323ac6857f6..9f64b2dcaa0 100644 --- a/app/assets/javascripts/admin/broadcast_messages/constants.js +++ b/app/assets/javascripts/admin/broadcast_messages/constants.js @@ -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'; diff --git a/app/assets/javascripts/admin/broadcast_messages/edit.js b/app/assets/javascripts/admin/broadcast_messages/edit.js index 70a270f7a56..91dae949d45 100644 --- a/app/assets/javascripts/admin/broadcast_messages/edit.js +++ b/app/assets/javascripts/admin/broadcast_messages/edit.js @@ -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, { diff --git a/app/assets/javascripts/admin/broadcast_messages/index.js b/app/assets/javascripts/admin/broadcast_messages/index.js index fd8b2aad4ec..29021043b1a 100644 --- a/app/assets/javascripts/admin/broadcast_messages/index.js +++ b/app/assets/javascripts/admin/broadcast_messages/index.js @@ -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, { diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb index 1c5a601de25..bc3527565a6 100644 --- a/app/helpers/broadcast_messages_helper.rb +++ b/app/helpers/broadcast_messages_helper.rb @@ -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 diff --git a/app/views/admin/broadcast_messages/edit.html.haml b/app/views/admin/broadcast_messages/edit.html.haml index 212cc437d3d..63ce08eef85 100644 --- a/app/views/admin/broadcast_messages/edit.html.haml +++ b/app/views/admin/broadcast_messages/edit.html.haml @@ -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) } diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml index 010cc493ddf..fb63e761f69 100644 --- a/app/views/admin/broadcast_messages/index.html.haml +++ b/app/views/admin/broadcast_messages/index.html.haml @@ -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) } } diff --git a/spec/features/admin/broadcast_messages_spec.rb b/spec/features/admin/broadcast_messages_spec.rb new file mode 100644 index 00000000000..fca4cdb0ff4 --- /dev/null +++ b/spec/features/admin/broadcast_messages_spec.rb @@ -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 diff --git a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js index 292575c984b..ba8b9dd1345 100644 --- a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js +++ b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js @@ -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(); diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb index e0bdb09f257..8d2245c820f 100644 --- a/spec/helpers/broadcast_messages_helper_spec.rb +++ b/spec/helpers/broadcast_messages_helper_spec.rb @@ -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 |