From e2a80cacf8a603525fa59349451d874acc8948f0 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 27 Feb 2025 21:24:46 -0700 Subject: [PATCH 01/13] Add variables for the disclosure dropdown item --- .../rapid_diffs/diff_file_header_component.html.haml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index e0411e679fc409..17b53d042624f0 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -11,6 +11,9 @@ -# * toggle file comments -# * submodule compare +- view_title = _('View file @ %{short_sha}') % { short_sha: Commit.truncate_sha(@diff_file.content_sha) } +- view_href = "href" # @diff_file.view_path + .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } .rd-diff-file-toggle< = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'chevron-down', button_options: { class: 'rd-diff-file-toggle-button', data: { opened: '', click: 'toggleFile' }, aria: { label: _('Hide file contents') } }) @@ -51,4 +54,6 @@ %span{ "data-testid" => "js-file-deletion-line" }= @diff_file.removed_lines .rd-diff-file-options-menu .js-options-menu + %template#options-menu-items + %d-i{ data: { title: view_title, href: view_href } } = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'ellipsis_v', button_options: { class: 'js-options-button', data: { click: 'toggleOptionsMenu' }, aria: { label: _('Options') } }) -- GitLab From 8a25fcabd447665968607c627c6ca0ecc3c7d82c Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 27 Feb 2025 21:53:42 -0700 Subject: [PATCH 02/13] Add disclosure item stub --- app/assets/javascripts/rapid_diffs/options_menu/adapter.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js index e7cc7f9d2bc784..59d28a7e70c147 100644 --- a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js +++ b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js @@ -14,6 +14,12 @@ export const OptionsMenuAdapter = { createElement(GlDisclosureDropdown, { props: { icon: 'ellipsis_v', + items: [ + { + text: 'View file @ abcdef', + href: 'href' + } + ], startOpened: true, noCaret: true, category: 'tertiary', -- GitLab From 7008e9dd420ffaa35541cd3851761eeeff103d28 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Mon, 3 Mar 2025 18:08:11 -0700 Subject: [PATCH 03/13] Add a parser to get server-rendered items for the disclosure menu --- .../rapid_diffs/options_menu/adapter.js | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js index 59d28a7e70c147..a94892b9ae686f 100644 --- a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js +++ b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js @@ -1,25 +1,35 @@ import Vue from 'vue'; import { GlDisclosureDropdown } from '@gitlab/ui'; +function getMenuItems(template) { + const fragment = template.content.cloneNode(true); + + return Array.from(fragment.querySelectorAll('ssr-stub')).map((item) => { + const data = item.dataset; + + return { + text: data.title, + href: data.href, + }; + }); +} + export const OptionsMenuAdapter = { clicks: { toggleOptionsMenu(event) { const button = event.target.closest('.js-options-button'); + const menuContainer = button.parentElement; + const itemsTemplate = menuContainer.querySelector('template'); if (!this.sink.optionsMenu) { this.sink.optionsMenu = new Vue({ - el: Vue.version.startsWith('2') ? button : button.parentElement, + el: Vue.version.startsWith('2') ? button : menuContainer, name: 'GlDisclosureDropdown', render: (createElement = Vue.h) => createElement(GlDisclosureDropdown, { props: { icon: 'ellipsis_v', - items: [ - { - text: 'View file @ abcdef', - href: 'href' - } - ], + items: getMenuItems(itemsTemplate), startOpened: true, noCaret: true, category: 'tertiary', -- GitLab From 16d0ec2a5718f0d25d6732806a781c672c90300a Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Mon, 3 Mar 2025 18:08:51 -0700 Subject: [PATCH 04/13] Add the "View file @ [SHA]" dropdown menu item --- .../rapid_diffs/diff_file_header_component.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index 17b53d042624f0..c0a3c5283b0842 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -11,8 +11,8 @@ -# * toggle file comments -# * submodule compare -- view_title = _('View file @ %{short_sha}') % { short_sha: Commit.truncate_sha(@diff_file.content_sha) } -- view_href = "href" # @diff_file.view_path +- view_title = _('View file @ %{commitSha}') % { short_sha: Commit.truncate_sha(@diff_file.content_sha) } +- view_href = project_blob_path(@diff_file.repository.project, helpers.tree_join(@diff_file.content_sha, @diff_file.new_path)) .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } .rd-diff-file-toggle< @@ -55,5 +55,5 @@ .rd-diff-file-options-menu .js-options-menu %template#options-menu-items - %d-i{ data: { title: view_title, href: view_href } } + %ssr-stub{ data: { title: view_title, href: view_href } } = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'ellipsis_v', button_options: { class: 'js-options-button', data: { click: 'toggleOptionsMenu' }, aria: { label: _('Options') } }) -- GitLab From 778d2aa6d1cc5c155ca1aa4beb43aac4f10853ca Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 4 Mar 2025 19:08:00 -0700 Subject: [PATCH 05/13] Fix mismatched interpolation variable name --- app/components/rapid_diffs/diff_file_header_component.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index c0a3c5283b0842..da71b971330fe8 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -11,7 +11,7 @@ -# * toggle file comments -# * submodule compare -- view_title = _('View file @ %{commitSha}') % { short_sha: Commit.truncate_sha(@diff_file.content_sha) } +- view_title = _('View file @ %{commit_sha}') % { commit_sha: Commit.truncate_sha(@diff_file.content_sha) } - view_href = project_blob_path(@diff_file.repository.project, helpers.tree_join(@diff_file.content_sha, @diff_file.new_path)) .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } -- GitLab From 7ae9b38e60914f16ef65390476ab2e99a15818ac Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 4 Mar 2025 19:25:11 -0700 Subject: [PATCH 06/13] Use pure JSON instead of mediating it through DOM nodes --- .../javascripts/rapid_diffs/options_menu/adapter.js | 10 +++------- .../rapid_diffs/diff_file_header_component.html.haml | 5 +++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js index a94892b9ae686f..c6b80914dfd47a 100644 --- a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js +++ b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js @@ -2,14 +2,10 @@ import Vue from 'vue'; import { GlDisclosureDropdown } from '@gitlab/ui'; function getMenuItems(template) { - const fragment = template.content.cloneNode(true); - - return Array.from(fragment.querySelectorAll('ssr-stub')).map((item) => { - const data = item.dataset; - + return JSON.parse(template.content.textContent).map((item) => { return { - text: data.title, - href: data.href, + text: item.title, + href: item.href, }; }); } diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index da71b971330fe8..dd198f8b041cb7 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -13,6 +13,7 @@ - view_title = _('View file @ %{commit_sha}') % { commit_sha: Commit.truncate_sha(@diff_file.content_sha) } - view_href = project_blob_path(@diff_file.repository.project, helpers.tree_join(@diff_file.content_sha, @diff_file.new_path)) +- options_menu_items = [ { "title": "#{view_title}", "href": "#{view_href}" } ].to_json .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } .rd-diff-file-toggle< @@ -54,6 +55,6 @@ %span{ "data-testid" => "js-file-deletion-line" }= @diff_file.removed_lines .rd-diff-file-options-menu .js-options-menu - %template#options-menu-items - %ssr-stub{ data: { title: view_title, href: view_href } } + %template#options-menu-data + = options_menu_items = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'ellipsis_v', button_options: { class: 'js-options-button', data: { click: 'toggleOptionsMenu' }, aria: { label: _('Options') } }) -- GitLab From f6677071d8dd470f830a08de58129f182d7b4246 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 5 Mar 2025 16:30:05 -0700 Subject: [PATCH 07/13] Test that options menu items are rendered --- .../rapid_diffs/options_menu/adapter_spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js index 27a9c790ce12fb..d78dd0b9514ac1 100644 --- a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js +++ b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js @@ -2,12 +2,16 @@ import { DiffFile } from '~/rapid_diffs/diff_file'; import { OptionsMenuAdapter } from '~/rapid_diffs/options_menu/adapter'; describe('Diff File Options Menu', () => { + const item1 = { title: 'item 1', path: 'item/1/path' }; const html = `
+
@@ -23,6 +27,8 @@ describe('Diff File Options Menu', () => { container: () => get('file').querySelector('.js-options-menu'), serverButton: () => get('container').querySelector('.js-options-button'), vueButton: () => get('container').querySelector('[data-testid="base-dropdown-toggle"]'), + menuItems: () => + get('container').querySelectorAll('[data-testid="disclosure-dropdown-item"]'), }; return elements[element]?.(); @@ -61,4 +67,16 @@ describe('Diff File Options Menu', () => { */ expect(get('serverButton')).toBeNull(); }); + + it('renders the correct menu items in the GlDisclosureDropdown as provided by the back end', () => { + const button = get('serverButton'); + + button.click(); + + const items = Array.from(get('menuItems')); + + expect(items.length).toBe(1); + expect(items[0].textContent.trim()).toBe(item1.title); + expect(items[0].querySelector('a').getAttribute('href')).toBe(item1.path); + }); }); -- GitLab From 4efbb0fe35f1ef24f76a4377920de2199970cfd0 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 5 Mar 2025 16:31:51 -0700 Subject: [PATCH 08/13] Use previously defined interpolation variable to avoid updating l10n --- app/components/rapid_diffs/diff_file_header_component.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index dd198f8b041cb7..fa060d8593fdd0 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -11,7 +11,7 @@ -# * toggle file comments -# * submodule compare -- view_title = _('View file @ %{commit_sha}') % { commit_sha: Commit.truncate_sha(@diff_file.content_sha) } +- view_title = _('View file @ %{commitSha}') % { commitSha: Commit.truncate_sha(@diff_file.content_sha) } - view_href = project_blob_path(@diff_file.repository.project, helpers.tree_join(@diff_file.content_sha, @diff_file.new_path)) - options_menu_items = [ { "title": "#{view_title}", "href": "#{view_href}" } ].to_json -- GitLab From 325682807c5b58693a6076517c935aab42742b01 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Thu, 6 Mar 2025 12:51:45 -0700 Subject: [PATCH 09/13] Remove template ID that will be duplicated for every diff file --- app/components/rapid_diffs/diff_file_header_component.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index fa060d8593fdd0..c598e29e92b2bb 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -55,6 +55,6 @@ %span{ "data-testid" => "js-file-deletion-line" }= @diff_file.removed_lines .rd-diff-file-options-menu .js-options-menu - %template#options-menu-data + %template = options_menu_items = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'ellipsis_v', button_options: { class: 'js-options-button', data: { click: 'toggleOptionsMenu' }, aria: { label: _('Options') } }) -- GitLab From 10d32df78f27bd6c73d21df15301a54b8b7e83b8 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Mon, 10 Mar 2025 12:44:03 -0600 Subject: [PATCH 10/13] Switch to data block to eliminate character escaping --- .../javascripts/rapid_diffs/options_menu/adapter.js | 12 +++--------- .../rapid_diffs/diff_file_header_component.html.haml | 6 +++--- .../rapid_diffs/options_menu/adapter_spec.js | 4 ++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js index c6b80914dfd47a..9f28b2fe9022c8 100644 --- a/app/assets/javascripts/rapid_diffs/options_menu/adapter.js +++ b/app/assets/javascripts/rapid_diffs/options_menu/adapter.js @@ -1,13 +1,8 @@ import Vue from 'vue'; import { GlDisclosureDropdown } from '@gitlab/ui'; -function getMenuItems(template) { - return JSON.parse(template.content.textContent).map((item) => { - return { - text: item.title, - href: item.href, - }; - }); +function getMenuItems(container) { + return JSON.parse(container.querySelector('script').textContent); } export const OptionsMenuAdapter = { @@ -15,7 +10,6 @@ export const OptionsMenuAdapter = { toggleOptionsMenu(event) { const button = event.target.closest('.js-options-button'); const menuContainer = button.parentElement; - const itemsTemplate = menuContainer.querySelector('template'); if (!this.sink.optionsMenu) { this.sink.optionsMenu = new Vue({ @@ -25,7 +19,7 @@ export const OptionsMenuAdapter = { createElement(GlDisclosureDropdown, { props: { icon: 'ellipsis_v', - items: getMenuItems(itemsTemplate), + items: getMenuItems(menuContainer), startOpened: true, noCaret: true, category: 'tertiary', diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index c598e29e92b2bb..43ab8abc389662 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -13,7 +13,7 @@ - view_title = _('View file @ %{commitSha}') % { commitSha: Commit.truncate_sha(@diff_file.content_sha) } - view_href = project_blob_path(@diff_file.repository.project, helpers.tree_join(@diff_file.content_sha, @diff_file.new_path)) -- options_menu_items = [ { "title": "#{view_title}", "href": "#{view_href}" } ].to_json +- options_menu_items = [ { "text": "#{view_title}", "href": "#{view_href}" } ].to_json .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } .rd-diff-file-toggle< @@ -55,6 +55,6 @@ %span{ "data-testid" => "js-file-deletion-line" }= @diff_file.removed_lines .rd-diff-file-options-menu .js-options-menu - %template - = options_menu_items + %script{ type: "application/json" } + = options_menu_items.html_safe = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'ellipsis_v', button_options: { class: 'js-options-button', data: { click: 'toggleOptionsMenu' }, aria: { label: _('Options') } }) diff --git a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js index d78dd0b9514ac1..fa0e11cc24c73b 100644 --- a/spec/frontend/rapid_diffs/options_menu/adapter_spec.js +++ b/spec/frontend/rapid_diffs/options_menu/adapter_spec.js @@ -9,9 +9,9 @@ describe('Diff File Options Menu', () => {
-