From 3db4e2960aebe87b0c5f67bbf9ad9c87c9b9d483 Mon Sep 17 00:00:00 2001 From: Janis Altherr <jaltherr@gitlab.com> Date: Wed, 12 Jul 2023 04:11:19 +0000 Subject: [PATCH] Use Markdown editor in Milestone descriptions This MR enables the new markdown editor wrapper in Milestone descriptions as part of https://gitlab.com/groups/gitlab-org/-/epics/7098 Changelog: changed --- app/assets/javascripts/milestones/index.js | 19 ++------ .../markdown/mount_markdown_editor.js | 3 +- .../groups/milestones_controller.rb | 4 ++ .../projects/milestones_controller.rb | 4 ++ app/views/groups/milestones/_form.html.haml | 16 ++++--- app/views/projects/milestones/_form.html.haml | 17 +++++--- spec/features/groups/milestone_spec.rb | 2 +- spec/frontend/dropzone_input_spec.js | 2 +- spec/frontend/fixtures/milestones.rb | 43 ------------------- spec/frontend/fixtures/static/textarea.html | 27 ++++++++++++ .../milestone_editing_shared_examples.rb | 4 +- 11 files changed, 65 insertions(+), 76 deletions(-) delete mode 100644 spec/frontend/fixtures/milestones.rb create mode 100644 spec/frontend/fixtures/static/textarea.html diff --git a/app/assets/javascripts/milestones/index.js b/app/assets/javascripts/milestones/index.js index 420f7cee4d2b8..403db0865f0fe 100644 --- a/app/assets/javascripts/milestones/index.js +++ b/app/assets/javascripts/milestones/index.js @@ -1,10 +1,9 @@ -import $ from 'jquery'; import Vue from 'vue'; import initDatePicker from '~/behaviors/date_picker'; -import GLForm from '~/gl_form'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import Milestone from '~/milestones/milestone'; import { renderGFM } from '~/behaviors/markdown/render_gfm'; +import { mountMarkdownEditor } from '~/vue_shared/components/markdown/mount_markdown_editor'; import Sidebar from '~/right_sidebar'; import MountMilestoneSidebar from '~/sidebar/mount_milestone_sidebar'; import Translate from '~/vue_shared/translate'; @@ -22,22 +21,10 @@ export const MILESTONE_DESCRIPTION_ELEMENT = '.milestone-detail .description'; export const MILESTONE_DESCRIPTION_TASK_LIST_CONTAINER_ELEMENT = `${MILESTONE_DESCRIPTION_ELEMENT}.js-task-list-container`; export const MILESTONE_DETAIL_ELEMENT = '.milestone-detail'; -export function initForm(initGFM = true) { +export function initForm() { + mountMarkdownEditor(); new ZenMode(); // eslint-disable-line no-new initDatePicker(); - - // eslint-disable-next-line no-new - new GLForm($('.milestone-form'), { - emojis: true, - members: initGFM, - issues: initGFM, - mergeRequests: initGFM, - epics: initGFM, - milestones: initGFM, - labels: initGFM, - snippets: initGFM, - vulnerabilities: initGFM, - }); } export function initShow() { diff --git a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js index e12815f0094ce..b7b154bfc236b 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js +++ b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js @@ -79,6 +79,7 @@ export function mountMarkdownEditor(options = {}) { const supportsQuickActions = parseBoolean(el.dataset.supportsQuickActions ?? true); const enableAutocomplete = parseBoolean(el.dataset.enableAutocomplete ?? true); const disableAttachments = parseBoolean(el.dataset.disableAttachments ?? false); + const autofocus = parseBoolean(el.dataset.autofocus ?? true); const hiddenInput = el.querySelector('input[type="hidden"]'); const formFieldName = hiddenInput.getAttribute('name'); const formFieldId = hiddenInput.getAttribute('id'); @@ -128,7 +129,7 @@ export function mountMarkdownEditor(options = {}) { autocompleteDataSources: gl.GfmAutoComplete?.dataSources, supportsQuickActions, disableAttachments, - autofocus: true, + autofocus, }, }); }, diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 5f6b55ea9288f..cbed75019f2cd 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -9,6 +9,10 @@ class Groups::MilestonesController < Groups::ApplicationController feature_category :team_planning urgency :low + before_action do + push_frontend_feature_flag(:content_editor_on_issues, group) + end + def index respond_to do |format| format.html do diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index 35b65dbce7e0d..1f4e5b545004a 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -24,6 +24,10 @@ class Projects::MilestonesController < Projects::ApplicationController feature_category :team_planning urgency :low + before_action do + push_frontend_feature_flag(:content_editor_on_issues, @project) + end + def index @sort = params[:sort] || 'due_date_asc' @milestones = milestones.sort_by_attribute(@sort) diff --git a/app/views/groups/milestones/_form.html.haml b/app/views/groups/milestones/_form.html.haml index 89f460606cbd4..e84fd7a869288 100644 --- a/app/views/groups/milestones/_form.html.haml +++ b/app/views/groups/milestones/_form.html.haml @@ -10,12 +10,16 @@ = render "shared/milestones/form_dates", f: f .form-group = f.label :description, _("Description") - = render layout: 'shared/md_preview', locals: { url: group_preview_markdown_path } do - = render 'shared/zen', f: f, attr: :description, - classes: 'note-textarea', - qa_selector: 'milestone_description_field', - supports_autocomplete: true, - placeholder: _('Write milestone description...') + - @gfm_form = true + .js-markdown-editor{ data: { render_markdown_path: group_preview_markdown_path, + markdown_docs_path: help_page_path('user/markdown'), + qa_selector: 'milestone_description_field', + form_field_placeholder: _('Write milestone description...'), + supports_quick_actions: 'false', + enable_autocomplete: 'true', + autofocus: 'false', + form_field_classes: 'note-textarea js-gfm-input markdown-area' } } + = f.hidden_field :description .clearfix .error-alert diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index be6f9ac83dc5c..a1300ccd83534 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -12,13 +12,16 @@ = render 'shared/milestones/form_dates', f: f .form-group = f.label :description, _('Description') - = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project) } do - = render 'shared/zen', f: f, attr: :description, - classes: 'note-textarea', - qa_selector: 'milestone_description_field', - supports_autocomplete: true, - placeholder: _('Write milestone description...') - = render 'shared/notes/hints' + - @gfm_form = true + .js-markdown-editor{ data: { render_markdown_path: preview_markdown_path(@project), + markdown_docs_path: help_page_path('user/markdown'), + qa_selector: 'milestone_description_field', + form_field_placeholder: _('Write milestone description...'), + supports_quick_actions: 'false', + enable_autocomplete: 'true', + autofocus: 'false', + form_field_classes: 'note-textarea js-gfm-input markdown-area' } } + = f.hidden_field :description .clearfix .error-alert diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 0a697eaa798cd..bb7cc3db452c6 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -27,7 +27,7 @@ click_button("Preview") - preview = find('.js-md-preview') + preview = find('.js-vue-md-preview') expect(preview).to have_content('Nothing to preview.') diff --git a/spec/frontend/dropzone_input_spec.js b/spec/frontend/dropzone_input_spec.js index 57debf79c7b95..ba4d838e44b7c 100644 --- a/spec/frontend/dropzone_input_spec.js +++ b/spec/frontend/dropzone_input_spec.js @@ -1,6 +1,5 @@ import MockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; -import htmlNewMilestone from 'test_fixtures/milestones/new-milestone.html'; import mock from 'xhr-mock'; import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import waitForPromises from 'helpers/wait_for_promises'; @@ -9,6 +8,7 @@ import PasteMarkdownTable from '~/behaviors/markdown/paste_markdown_table'; import dropzoneInput from '~/dropzone_input'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status'; +import htmlNewMilestone from 'test_fixtures_static/textarea.html'; const TEST_FILE = new File([], 'somefile.jpg'); TEST_FILE.upload = {}; diff --git a/spec/frontend/fixtures/milestones.rb b/spec/frontend/fixtures/milestones.rb deleted file mode 100644 index 5e39dcf190a6b..0000000000000 --- a/spec/frontend/fixtures/milestones.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::MilestonesController, '(JavaScript fixtures)', :with_license, feature_category: :team_planning, type: :controller do - include JavaScriptFixturesHelpers - - let_it_be(:user) { create(:user, feed_token: 'feedtoken:coldfeed') } - let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures') } - let_it_be(:project) { create(:project_empty_repo, namespace: namespace, path: 'milestones-project') } - - render_views - - before do - project.add_maintainer(user) - sign_in(user) - end - - after do - remove_repository(project) - end - - it 'milestones/new-milestone.html' do - get :new, params: { - namespace_id: project.namespace.to_param, - project_id: project - } - - expect(response).to be_successful - end - - private - - def render_milestone(milestone) - get :show, params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: milestone.to_param - } - - expect(response).to be_successful - end -end diff --git a/spec/frontend/fixtures/static/textarea.html b/spec/frontend/fixtures/static/textarea.html new file mode 100644 index 0000000000000..68d5a0f2d4d2c --- /dev/null +++ b/spec/frontend/fixtures/static/textarea.html @@ -0,0 +1,27 @@ +<body> +<meta charset="utf-8"> +<title>Document with Textarea</title> +<form class="milestone-form common-note-form js-quick-submit js-requires-input" id="new_milestone" + action="http://test.host/frontend-fixtures/milestones-project/-/milestones" + accept-charset="UTF-8" method="post"> + <div class="form-group"> + <div class="md-write-holder"> + <div class="zen-backdrop"> + <textarea class="note-textarea js-gfm-input js-autosize markdown-area" + placeholder="Write milestone description..." dir="auto" + data-supports-quick-actions="false" data-supports-autocomplete="true" + data-qa-selector="milestone_description_field" data-autofocus="false" + name="milestone[description]" + id="milestone_description"></textarea> + <a class="zen-control zen-control-leave js-zen-leave gl-text-gray-500" + href="#"> + <svg class="s16" data-testid="minimize-icon"> + <use href="http://test.host/assets/icons-b8c5a9711f73b1de3c81754da0aca72f43b0e6844aa06dd03092b601a493f45b.svg#minimize"></use> + </svg> + </a> + </div> + </div> + </div> +</form> + +</body> diff --git a/spec/support/shared_examples/features/milestone_editing_shared_examples.rb b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb index d21bf62ecfa5e..53498a1bb3963 100644 --- a/spec/support/shared_examples/features/milestone_editing_shared_examples.rb +++ b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true RSpec.shared_examples 'milestone handling version conflicts' do - it 'warns about version conflict when milestone has been updated in the background' do + it 'warns about version conflict when milestone has been updated in the background', :js do + wait_for_all_requests + # Update the milestone in the background in order to trigger a version conflict milestone.update!(title: "New title") -- GitLab