From a5c48e0ecd326aac9a1321935b1003121e54ecff Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 5 Jul 2023 13:50:26 -0600 Subject: [PATCH 1/6] Empty the textarea content before replacing --- app/assets/javascripts/vue_shared/components/markdown/header.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 0899b752cbcbd3..04f50d5dafe2bf 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -214,6 +214,7 @@ export default { : description; if (textArea) { + textArea.value = ''; updateText({ textArea, tag: `${text}\n\n---\n\n_${addendum}_`, -- GitLab From 0bc21481e8fcabc8fd3790db067fdc0000fc6d76 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 6 Jul 2023 08:06:54 -0600 Subject: [PATCH 2/6] Use target project for the subscription Provide the source project to the mutation --- .../components/markdown/mount_markdown_editor.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js index fcfbf77217cc44..c012f2fa8ef4e2 100644 --- a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js +++ b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js @@ -17,19 +17,19 @@ export function mountMarkdownEditor() { description: __('Replace current template with filled in placeholders'), method: 'replace', subscriptionVariables() { - const projectGqlId = convertToGraphQLId( + const targetProjectGqlId = convertToGraphQLId( /* eslint-disable-next-line @gitlab/require-i18n-strings */ 'Project', - document.getElementById('merge_request_source_project_id').value, + document.getElementById('merge_request_target_project_id').value, ); return { userId: convertToGraphQLId(TYPENAME_USER, gon.current_user_id), - resourceId: projectGqlId, + resourceId: targetProjectGqlId, }; }, apolloMutation() { /* eslint-disable @gitlab/require-i18n-strings */ - const projectGqlId = convertToGraphQLId( + const sourceProjectGqlId = convertToGraphQLId( 'Project', document.getElementById('merge_request_source_project_id').value, ); @@ -50,7 +50,7 @@ export function mountMarkdownEditor() { target: targetBranch, templateContent: mrDescription, mrTitle, - projectGqlId, + sourceProjectGqlId, targetProjectGqlId, }, }; -- GitLab From 11ff33e5be464d172c5f40c4d29b9a32ef3e033e Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 6 Jul 2023 08:14:05 -0600 Subject: [PATCH 3/6] Use a regular string value for the source project ID --- .../ai/graphql/fill_mr_description.mutation.graphql | 4 ++-- .../components/markdown/mount_markdown_editor.js | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ee/app/assets/javascripts/ai/graphql/fill_mr_description.mutation.graphql b/ee/app/assets/javascripts/ai/graphql/fill_mr_description.mutation.graphql index cd93fa925a2810..9c00ba1ff7cb0b 100644 --- a/ee/app/assets/javascripts/ai/graphql/fill_mr_description.mutation.graphql +++ b/ee/app/assets/javascripts/ai/graphql/fill_mr_description.mutation.graphql @@ -1,5 +1,5 @@ mutation fillInMergeRequestTemplate( - $sourceProjectGqlId: ID + $sourceProjectId: ID $targetProjectGqlId: AiModelID! $source: String! $target: String! @@ -10,7 +10,7 @@ mutation fillInMergeRequestTemplate( input: { fillInMergeRequestTemplate: { resourceId: $targetProjectGqlId - sourceProjectId: $sourceProjectGqlId + sourceProjectId: $sourceProjectId sourceBranch: $source targetBranch: $target title: $mrTitle diff --git a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js index c012f2fa8ef4e2..4bd1565b8f1c3a 100644 --- a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js +++ b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js @@ -29,10 +29,7 @@ export function mountMarkdownEditor() { }, apolloMutation() { /* eslint-disable @gitlab/require-i18n-strings */ - const sourceProjectGqlId = convertToGraphQLId( - 'Project', - document.getElementById('merge_request_source_project_id').value, - ); + const sourceProjectId = document.getElementById('merge_request_source_project_id').value; const targetProjectGqlId = convertToGraphQLId( 'Project', document.getElementById('merge_request_target_project_id').value, @@ -50,7 +47,7 @@ export function mountMarkdownEditor() { target: targetBranch, templateContent: mrDescription, mrTitle, - sourceProjectGqlId, + sourceProjectId, targetProjectGqlId, }, }; -- GitLab From be23c4218a93bbd1a2b2e9611c4d43197c6e0c8b Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 6 Jul 2023 11:44:23 -0600 Subject: [PATCH 4/6] Test that the AI replace behavior updates the textarea properly --- .../components/markdown/header_spec.js | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/ee/spec/frontend/vue_shared/components/markdown/header_spec.js b/ee/spec/frontend/vue_shared/components/markdown/header_spec.js index fcc3955a3f7a7f..abfff488814387 100644 --- a/ee/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/ee/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -2,12 +2,16 @@ import { GlTabs, GlDisclosureDropdown, GlListboxItem } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import HeaderComponent from '~/vue_shared/components/markdown/header.vue'; import AiActionsDropdown from 'ee/ai/components/ai_actions_dropdown.vue'; +import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; describe('Markdown field header component', () => { + document.execCommand = jest.fn(); + let wrapper; - const createWrapper = (props, provide = {}) => { + const createWrapper = ({ props, provide = {}, attachTo = document.body } = {}) => { wrapper = shallowMountExtended(HeaderComponent, { + attachTo, propsData: { previewMarkdown: false, ...props, @@ -22,14 +26,53 @@ describe('Markdown field header component', () => { it.each([true, false])( 'renders/does not render "AI actions" when actions are "%s"', (enabled) => { - createWrapper( - {}, - { + createWrapper({ + provide: { editorAiActions: enabled ? [{ value: 'myAction', title: 'myAction' }] : [], }, - ); + }); expect(findAiActionsButton().exists()).toBe(enabled); }, ); + + describe('generated text responses', () => { + const sha = 'abc123'; + const addendum = ` + +--- + +_This description was generated for revision ${sha} using AI_`; + + beforeEach(() => { + setHTMLFixture(`
+ + +
+
`); + }); + + afterEach(() => { + resetHTMLFixture(); + }); + + it('replaces the text content when the AI actions dropdown reports a `replace` event', () => { + const text = document.querySelector('textarea'); + + text.value = 'test'; + + createWrapper({ + attachTo: '#root', + provide: { + editorAiActions: [{ value: 'myAction', title: 'myAction' }], + }, + }); + + expect(text.value).toBe('test'); + + findAiActionsButton().vm.$emit('replace', 'other text'); + + expect(text.value).toBe(`other text${addendum}`); + }); + }); }); -- GitLab From 26cf3e27af34c086b6a7eeeb53ba2d14faa85d5d Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 11 Jul 2023 12:47:43 -0600 Subject: [PATCH 5/6] Add reliable source of MR metadata for JS use to new and edit pages --- app/views/projects/merge_requests/_form.html.haml | 1 + .../projects/merge_requests/_source_and_target.html.haml | 9 +++++++++ .../merge_requests/creations/_new_submit.html.haml | 1 + 3 files changed, 11 insertions(+) create mode 100644 app/views/projects/merge_requests/_source_and_target.html.haml diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml index 5f1c72156eb6b3..6d2e2cfcc54218 100644 --- a/app/views/projects/merge_requests/_form.html.haml +++ b/app/views/projects/merge_requests/_form.html.haml @@ -1,3 +1,4 @@ = gitlab_ui_form_for [@project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| + = render 'source_and_target', mr: @merge_request = render 'shared/issuable/form', f: f, issuable: @merge_request, presenter: @mr_presenter diff --git a/app/views/projects/merge_requests/_source_and_target.html.haml b/app/views/projects/merge_requests/_source_and_target.html.haml new file mode 100644 index 00000000000000..e13b98716f9956 --- /dev/null +++ b/app/views/projects/merge_requests/_source_and_target.html.haml @@ -0,0 +1,9 @@ +%span{ + class: [ "js-mr-metadata", "gl-display-none" ], + data: { + "source-project-id": mr.source_project_id, + "source-branch": mr.source_branch, + "target-project-id": mr.target_project_id, + "target-branch": mr.target_branch + } +} diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml index bec7cb3fd347a3..a7151421acba1f 100644 --- a/app/views/projects/merge_requests/creations/_new_submit.html.haml +++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml @@ -1,6 +1,7 @@ %h1.page-title.gl-font-size-h-display = _('New merge request') = gitlab_ui_form_for [@project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| + = render "projects/merge_requests/source_and_target", mr: @merge_request = render 'shared/issuable/form', f: f, issuable: @merge_request, commits: @commits, presenter: @mr_presenter = f.hidden_field :source_project_id = f.hidden_field :source_branch -- GitLab From 11e368d71e9c88c334c93e656eea46692fb70a1e Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 11 Jul 2023 18:07:27 -0600 Subject: [PATCH 6/6] Update JS to use the reliable MR metadata source --- .../markdown/mount_markdown_editor.js | 4 +-- .../_source_and_target.html.haml | 3 +- .../markdown/mount_markdown_editor.js | 28 +++++-------------- 3 files changed, 11 insertions(+), 24 deletions(-) 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 e12815f0094ce7..0838bc47a9fd94 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 @@ -8,8 +8,8 @@ import { CLEAR_AUTOSAVE_ENTRY_EVENT } from '../../constants'; import MarkdownEditor from './markdown_editor.vue'; import eventHub from './eventhub'; -export const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; -export const MR_TARGET_BRANCH = 'merge_request[target_branch]'; +const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; +const MR_TARGET_BRANCH = 'merge_request[target_branch]'; function organizeQuery(obj, isFallbackKey = false) { if (!obj[MR_SOURCE_BRANCH] && !obj[MR_TARGET_BRANCH]) { diff --git a/app/views/projects/merge_requests/_source_and_target.html.haml b/app/views/projects/merge_requests/_source_and_target.html.haml index e13b98716f9956..68cd4fe9372e28 100644 --- a/app/views/projects/merge_requests/_source_and_target.html.haml +++ b/app/views/projects/merge_requests/_source_and_target.html.haml @@ -1,5 +1,6 @@ %span{ - class: [ "js-mr-metadata", "gl-display-none" ], + id: "js-merge-request-metadata", + class: ["js-merge-request-metadata", "gl-display-none"], data: { "source-project-id": mr.source_project_id, "source-branch": mr.source_branch, diff --git a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js index 4bd1565b8f1c3a..f35ae4ff23e489 100644 --- a/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js +++ b/ee/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js @@ -1,12 +1,8 @@ import { __ } from '~/locale'; -import { TYPENAME_USER } from '~/graphql_shared/constants'; +import { TYPENAME_USER, TYPENAME_PROJECT } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import aiFillDescriptionMutation from 'ee/ai/graphql/fill_mr_description.mutation.graphql'; -import { - mountMarkdownEditor as mountCEMarkdownEditor, - MR_SOURCE_BRANCH, - MR_TARGET_BRANCH, -} from '~/vue_shared/components/markdown/mount_markdown_editor'; +import { mountMarkdownEditor as mountCEMarkdownEditor } from '~/vue_shared/components/markdown/mount_markdown_editor'; export function mountMarkdownEditor() { const provideEEAiActions = []; @@ -17,26 +13,16 @@ export function mountMarkdownEditor() { description: __('Replace current template with filled in placeholders'), method: 'replace', subscriptionVariables() { - const targetProjectGqlId = convertToGraphQLId( - /* eslint-disable-next-line @gitlab/require-i18n-strings */ - 'Project', - document.getElementById('merge_request_target_project_id').value, - ); + const mrMetadata = document.getElementById('js-merge-request-metadata'); return { userId: convertToGraphQLId(TYPENAME_USER, gon.current_user_id), - resourceId: targetProjectGqlId, + resourceId: convertToGraphQLId(TYPENAME_PROJECT, mrMetadata.dataset.targetProjectId), }; }, apolloMutation() { - /* eslint-disable @gitlab/require-i18n-strings */ - const sourceProjectId = document.getElementById('merge_request_source_project_id').value; - const targetProjectGqlId = convertToGraphQLId( - 'Project', - document.getElementById('merge_request_target_project_id').value, - ); - /* eslint-enable @gitlab/require-i18n-strings */ - const sourceBranch = document.querySelector(`[name="${MR_SOURCE_BRANCH}"]`).value; - const targetBranch = document.querySelector(`[name="${MR_TARGET_BRANCH}"]`).value; + const mrMetadata = document.getElementById('js-merge-request-metadata'); + const { sourceProjectId, sourceBranch, targetProjectId, targetBranch } = mrMetadata.dataset; + const targetProjectGqlId = convertToGraphQLId(TYPENAME_PROJECT, targetProjectId); const mrTitle = document.getElementById('merge_request_title').value; const mrDescription = document.getElementById('merge_request_description').value; -- GitLab