From dfe9dcdff57839fb8f81c63ddd5b7d7ca048aca2 Mon Sep 17 00:00:00 2001 From: psjakubowska Date: Thu, 7 Nov 2024 17:05:16 +0100 Subject: [PATCH 1/6] Add Edit button to tree header Passes web_ide_button_data down to new Repository header component. Changelog: other EE: true --- .../repository/components/header_area.vue | 60 ++++++++++++++++++- .../javascripts/repository/init_header_app.js | 36 ++++++++++- app/views/projects/_files.html.haml | 16 ++++- app/views/projects/_readme.html.haml | 16 ++++- .../repository/components/header_area_spec.js | 23 +++++++ 5 files changed, 147 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/repository/components/header_area.vue b/app/assets/javascripts/repository/components/header_area.vue index adb53b911b726c..7a8d3cc2b6f5f5 100644 --- a/app/assets/javascripts/repository/components/header_area.vue +++ b/app/assets/javascripts/repository/components/header_area.vue @@ -7,7 +7,8 @@ import { keysFor, START_SEARCH_PROJECT_FILE } from '~/behaviors/shortcuts/keybin import { sanitize } from '~/lib/dompurify'; import { InternalEvents } from '~/tracking'; import { FIND_FILE_BUTTON_CLICK } from '~/tracking/constants'; -import { visitUrl, joinPaths } from '~/lib/utils/url_utility'; +import { visitUrl, joinPaths, webIDEUrl } from '~/lib/utils/url_utility'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_utils'; import RefSelector from '~/ref/components/ref_selector.vue'; import Breadcrumbs from '~/repository/components/header_area/breadcrumbs.vue'; @@ -24,6 +25,7 @@ export default { RefSelector, Breadcrumbs, BlobControls, + WebIdeLink: () => import('ee_else_ce/vue_shared/components/web_ide_link.vue'), }, directives: { GlTooltip: GlTooltipDirective, @@ -45,6 +47,21 @@ export default { 'projectRootPath', 'comparePath', 'isReadmeView', + 'webIdePromoPopoverImg', + 'isFork', + 'needsToFork', + 'gitpodEnabled', + 'isBlob', + 'showEditButton', + 'showWebIdeButton', + 'showGitpodButton', + 'showPipelineEditorUrl', + 'webIdeUrl', + 'editUrl', + 'pipelineEditorUrl', + 'gitpodUrl', + 'userPreferencesGitpodPath', + 'userProfileEnableGitpodPath', ], props: { projectPath: { @@ -84,6 +101,24 @@ export default { refSelectorValue() { return this.refType ? joinPaths('refs', this.refType, this.currentRef) : this.currentRef; }, + webIDEUrl() { + return this.isBlob + ? this.webIdeUrl + : webIDEUrl( + joinPaths( + '/', + this.projectPath, + 'edit', + this.currentRef, + '-', + this.$route?.params.path || '', + '/', + ), + ); + }, + projectIdAsNumber() { + return getIdFromGraphQLId(this.projectId); + }, findFileTooltip() { const { description } = START_SEARCH_PROJECT_FILE; const key = this.findFileShortcutKey; @@ -161,6 +196,29 @@ export default { {{ $options.i18n.findFile }} + diff --git a/app/assets/javascripts/repository/init_header_app.js b/app/assets/javascripts/repository/init_header_app.js index d5fd179b2e6ae4..5c8c094cbe6eb1 100644 --- a/app/assets/javascripts/repository/init_header_app.js +++ b/app/assets/javascripts/repository/init_header_app.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import { parseBoolean } from '~/lib/utils/common_utils'; +import { parseBoolean, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import apolloProvider from './graphql'; import projectShortPathQuery from './queries/project_short_path.query.graphql'; import projectPathQuery from './queries/project_path.query.graphql'; @@ -52,9 +52,28 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView projectRootPath, comparePath, projectPath, + webIdePromoPopoverImg, + webIdeButtonOptions, projectShortPath, } = headerEl.dataset; + const { + isFork, + needsToFork, + gitpodEnabled, + isBlob, + showEditButton, + showWebIdeButton, + showGitpodButton, + showPipelineEditorUrl, + webIdeUrl, + editUrl, + pipelineEditorUrl, + gitpodUrl, + userPreferencesGitpodPath, + userProfileEnableGitpodPath, + } = convertObjectPropsToCamelCase(JSON.parse(webIdeButtonOptions)); + initClientQueries({ projectPath, projectShortPath, ref, escapedRef }); // eslint-disable-next-line no-new @@ -78,6 +97,21 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView projectShortPath, comparePath, isReadmeView, + webIdePromoPopoverImg, + isFork: parseBoolean(isFork), + needsToFork: parseBoolean(needsToFork), + gitpodEnabled: parseBoolean(gitpodEnabled), + isBlob: parseBoolean(isBlob), + showEditButton: parseBoolean(showEditButton), + showWebIdeButton: parseBoolean(showWebIdeButton), + showGitpodButton: parseBoolean(showGitpodButton), + showPipelineEditorUrl: parseBoolean(showPipelineEditorUrl), + webIdeUrl, + editUrl, + pipelineEditorUrl, + gitpodUrl, + userPreferencesGitpodPath, + userProfileEnableGitpodPath, isBlobView, }, apolloProvider, diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml index 6c36bdc9c36622..463c56087837cc 100644 --- a/app/views/projects/_files.html.haml +++ b/app/views/projects/_files.html.haml @@ -1,5 +1,7 @@ - ref = local_assigns.fetch(:ref) { current_ref } - project = local_assigns.fetch(:project) { @project } +- web_ide_button_data = web_ide_button_data({ blob: nil }) +- fork_options = fork_modal_options(@project, nil) - add_page_startup_api_call logs_file_project_ref_path(@project, ref, @path, format: "json", offset: 0, ref_type: @ref_type) - if readme_path = @project.repository.readme_path - add_page_startup_api_call project_blob_path(@project, tree_join(@ref, readme_path), viewer: "rich", format: "json") @@ -10,7 +12,19 @@ #tree-holder.tree-holder.clearfix.js-per-page.gl-mt-5{ data: { blame_per_page: Gitlab::Git::BlamePagination::PAGINATION_PER_PAGE } } - if params[:common_repository_blob_header_app] == 'true' - #js-repository-blob-header-app{ data: { project_id: @project.id, ref: ref, ref_type: @ref_type.to_s, breadcrumbs: breadcrumb_data_attributes, project_root_path: project_path(@project), project_path: project.full_path, compare_path: compare_path, escaped_ref: ActionDispatch::Journey::Router::Utils.escape_path(ref) } } + #js-repository-blob-header-app{ data: { + project_id: @project.id, + ref: ref, + ref_type: @ref_type.to_s, + breadcrumbs: breadcrumb_data_attributes, + project_root_path: project_path(@project), + project_path: project.full_path, + compare_path: compare_path, + web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), + web_ide_button_options: web_ide_button_data.merge(fork_options).to_json, + web_ide_button_default_branch: @project.default_branch_or_main, + escaped_ref: ActionDispatch::Journey::Router::Utils.escape_path(ref) + } } - else .nav-block.gl-flex.gl-flex-col.sm:gl-flex-row.gl-items-stretch diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml index fea04813828d21..13616611d2817f 100644 --- a/app/views/projects/_readme.html.haml +++ b/app/views/projects/_readme.html.haml @@ -1,5 +1,7 @@ - ref = local_assigns.fetch(:ref) { current_ref } - project = local_assigns.fetch(:project) { @project } +- web_ide_button_data = web_ide_button_data({ blob: nil }) +- fork_options = fork_modal_options(@project, nil) - add_page_specific_style 'page_bundles/projects' - unless @ref.blank? || @repository&.root_ref == @ref - compare_path = project_compare_index_path(@project, from: @repository&.root_ref, to: @ref) @@ -7,7 +9,19 @@ - if (readme = @repository.readme) && readme.rich_viewer .tree-holder.gl-mt-5 - if params[:common_repository_blob_header_app] == 'true' - #js-repository-blob-header-app{ data: { project_id: @project.id, ref: ref, ref_type: @ref_type.to_s, breadcrumbs: breadcrumb_data_attributes, project_root_path: project_path(@project), project_path: project.full_path, compare_path: compare_path, escaped_ref: ActionDispatch::Journey::Router::Utils.escape_path(ref) } } + #js-repository-blob-header-app{ data: { + project_id: @project.id, + ref: ref, + ref_type: @ref_type.to_s, + breadcrumbs: breadcrumb_data_attributes, + project_root_path: project_path(@project), + project_path: project.full_path, + compare_path: compare_path, + web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), + web_ide_button_options: web_ide_button_data.merge(fork_options).to_json, + web_ide_button_default_branch: @project.default_branch_or_main, + escaped_ref: ActionDispatch::Journey::Router::Utils.escape_path(ref) + } } - else .nav-block.mt-0 diff --git a/spec/frontend/repository/components/header_area_spec.js b/spec/frontend/repository/components/header_area_spec.js index 009592ae3088cb..0f33b47f07dd05 100644 --- a/spec/frontend/repository/components/header_area_spec.js +++ b/spec/frontend/repository/components/header_area_spec.js @@ -36,6 +36,21 @@ const defaultProvided = { projectRootPath: '/project/root/path', comparePath: undefined, isReadmeView: false, + webIdePromoPopoverImg: 'https://example.com/web-ide-promo.png', + isFork: false, + needsToFork: true, + gitpodEnabled: false, + isBlob: true, + showEditButton: true, + showWebIdeButton: true, + showGitpodButton: false, + showPipelineEditorUrl: true, + webIdeUrl: 'https://gitlab.com/project/-/ide/', + editUrl: 'https://gitlab.com/project/-/edit/main/', + pipelineEditorUrl: 'https://gitlab.com/project/-/ci/editor', + gitpodUrl: 'https://gitpod.io/#https://gitlab.com/project', + userPreferencesGitpodPath: '/profile/preferences#gitpod', + userProfileEnableGitpodPath: '/profile/preferences?enable_gitpod=true', }; describe('HeaderArea', () => { @@ -45,6 +60,8 @@ describe('HeaderArea', () => { const findRefSelector = () => wrapper.findComponent(RefSelector); const findFindFileButton = () => wrapper.findByTestId('tree-find-file-control'); const findCompareButton = () => wrapper.findByTestId('tree-compare-control'); + const findWebIdeButton = () => wrapper.findByTestId('js-tree-web-ide-link'); + const { bindInternalEventDocument } = useMockInternalEventsTracking(); const createComponent = (props = {}, routeName = 'blobPathDecoded', provided = {}) => { @@ -126,6 +143,12 @@ describe('HeaderArea', () => { expect(findCompareButton().exists()).toBe(true); }); }); + + describe('Edit button', () => { + it('renders WebIdeLink component', () => { + expect(findWebIdeButton().exists()).toBe(true); + }); + }); }); describe('when rendered for blob view', () => { -- GitLab From 859dc3aa291aa49274e10f422070c17e736fe5f5 Mon Sep 17 00:00:00 2001 From: psjakubowska Date: Wed, 13 Nov 2024 20:05:56 +0100 Subject: [PATCH 2/6] Add Code dropdown Add Code button for desktop version of Repository header. --- .../repository/components/header_area.vue | 19 ++++++++++++++++++- .../javascripts/repository/init_header_app.js | 10 ++++++++++ app/views/projects/_files.html.haml | 6 ++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/repository/components/header_area.vue b/app/assets/javascripts/repository/components/header_area.vue index 7a8d3cc2b6f5f5..79d4f3b923142b 100644 --- a/app/assets/javascripts/repository/components/header_area.vue +++ b/app/assets/javascripts/repository/components/header_area.vue @@ -13,6 +13,7 @@ import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_util import RefSelector from '~/ref/components/ref_selector.vue'; import Breadcrumbs from '~/repository/components/header_area/breadcrumbs.vue'; import BlobControls from '~/repository/components/header_area/blob_controls.vue'; +import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue'; export default { name: 'HeaderArea', @@ -25,6 +26,7 @@ export default { RefSelector, Breadcrumbs, BlobControls, + CodeDropdown, WebIdeLink: () => import('ee_else_ce/vue_shared/components/web_ide_link.vue'), }, directives: { @@ -62,6 +64,11 @@ export default { 'gitpodUrl', 'userPreferencesGitpodPath', 'userProfileEnableGitpodPath', + 'httpUrl', + 'xcodeUrl', + 'sshUrl', + 'kerberosUrl', + 'directoryDownloadLinks', ], props: { projectPath: { @@ -197,7 +204,7 @@ export default { + diff --git a/app/assets/javascripts/repository/init_header_app.js b/app/assets/javascripts/repository/init_header_app.js index 5c8c094cbe6eb1..36f5d6b607e671 100644 --- a/app/assets/javascripts/repository/init_header_app.js +++ b/app/assets/javascripts/repository/init_header_app.js @@ -54,6 +54,11 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView projectPath, webIdePromoPopoverImg, webIdeButtonOptions, + sshUrl, + httpUrl, + xcodeUrl, + kerberosUrl, + directoryDownloadLinks, projectShortPath, } = headerEl.dataset; @@ -112,6 +117,11 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView gitpodUrl, userPreferencesGitpodPath, userProfileEnableGitpodPath, + httpUrl, + xcodeUrl, + sshUrl, + kerberosUrl, + directoryDownloadLinks: JSON.parse(directoryDownloadLinks), isBlobView, }, apolloProvider, diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml index 463c56087837cc..683fc52ffedcb4 100644 --- a/app/views/projects/_files.html.haml +++ b/app/views/projects/_files.html.haml @@ -2,6 +2,8 @@ - project = local_assigns.fetch(:project) { @project } - web_ide_button_data = web_ide_button_data({ blob: nil }) - fork_options = fork_modal_options(@project, nil) +- archive_prefix = ref ? "#{project.path}-#{ref.tr('/', '-')}" : '' +- directory_download_links = !project.empty_repo? ? directory_download_links(project, ref, archive_prefix).to_json : '' - add_page_startup_api_call logs_file_project_ref_path(@project, ref, @path, format: "json", offset: 0, ref_type: @ref_type) - if readme_path = @project.repository.readme_path - add_page_startup_api_call project_blob_path(@project, tree_join(@ref, readme_path), viewer: "rich", format: "json") @@ -23,6 +25,10 @@ web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), web_ide_button_options: web_ide_button_data.merge(fork_options).to_json, web_ide_button_default_branch: @project.default_branch_or_main, + ssh_url: ssh_enabled? ? ssh_clone_url_to_repo(@project) : '', + http_url: http_enabled? ? http_clone_url_to_repo(@project) : '', + xcode_url: show_xcode_link?(@project) ? xcode_uri_to_repo(@project) : '', + directory_download_links: directory_download_links, escaped_ref: ActionDispatch::Journey::Router::Utils.escape_path(ref) } } -- GitLab From 2f09bd6aa908f20b5b36877a4ebdf8ef61ca435b Mon Sep 17 00:00:00 2001 From: psjakubowska Date: Thu, 14 Nov 2024 12:10:34 +0100 Subject: [PATCH 3/6] Adjust the layout of the controls --- app/assets/javascripts/repository/components/header_area.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/repository/components/header_area.vue b/app/assets/javascripts/repository/components/header_area.vue index 79d4f3b923142b..763d0dfa4e38b4 100644 --- a/app/assets/javascripts/repository/components/header_area.vue +++ b/app/assets/javascripts/repository/components/header_area.vue @@ -150,7 +150,7 @@ export default {