diff --git a/app/assets/images/web-ide-promo-popover.svg b/app/assets/images/web-ide-promo-popover.svg
deleted file mode 100644
index 3ced89860da429b9a79d1f275abad079db8c12f8..0000000000000000000000000000000000000000
--- a/app/assets/images/web-ide-promo-popover.svg
+++ /dev/null
@@ -1,101 +0,0 @@
-
diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
index 275a9cf76d10abaf1277c78ed587af3cd819572e..a2c93f0345dad3dd76b65a8ce8a3fa8ff878e85f 100644
--- a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
+++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
@@ -18,7 +18,7 @@ export default ({ el, router }) => {
const { projectPath, ref, isBlob, webIdeUrl, ...options } = convertObjectPropsToCamelCase(
JSON.parse(el.dataset.options),
);
- const { webIdePromoPopoverImg, cssClasses, defaultBranch } = el.dataset;
+ const { cssClasses, defaultBranch } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
@@ -33,7 +33,6 @@ export default ({ el, router }) => {
return h(WebIdeButton, {
props: {
isBlob,
- webIdePromoPopoverImg,
webIdeUrl: isBlob
? webIdeUrl
: webIDEUrl(
diff --git a/app/assets/javascripts/repository/components/header_area.vue b/app/assets/javascripts/repository/components/header_area.vue
index adb53b911b726c10fc82a81bb10d4366f8a8f188..f3f7e61a8e2d2b63c8029e09ced7d0f4008f9edf 100644
--- a/app/assets/javascripts/repository/components/header_area.vue
+++ b/app/assets/javascripts/repository/components/header_area.vue
@@ -7,11 +7,15 @@ 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';
import BlobControls from '~/repository/components/header_area/blob_controls.vue';
+import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
+import SourceCodeDownloadDropdown from '~/vue_shared/components/download_dropdown/download_dropdown.vue';
+import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
export default {
name: 'HeaderArea',
@@ -24,6 +28,10 @@ export default {
RefSelector,
Breadcrumbs,
BlobControls,
+ CodeDropdown,
+ SourceCodeDownloadDropdown,
+ CloneCodeDropdown,
+ WebIdeLink: () => import('ee_else_ce/vue_shared/components/web_ide_link.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -45,6 +53,26 @@ export default {
'projectRootPath',
'comparePath',
'isReadmeView',
+ 'isFork',
+ 'needsToFork',
+ 'gitpodEnabled',
+ 'isBlob',
+ 'showEditButton',
+ 'showWebIdeButton',
+ 'showGitpodButton',
+ 'showPipelineEditorUrl',
+ 'webIdeUrl',
+ 'editUrl',
+ 'pipelineEditorUrl',
+ 'gitpodUrl',
+ 'userPreferencesGitpodPath',
+ 'userProfileEnableGitpodPath',
+ 'httpUrl',
+ 'xcodeUrl',
+ 'sshUrl',
+ 'kerberosUrl',
+ 'downloadLinks',
+ 'downloadArtifacts',
],
props: {
projectPath: {
@@ -84,6 +112,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;
@@ -108,7 +154,7 @@ 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 d5fd179b2e6ae46fb66745ca68b1051c761970b4..9d4082b7f2554be514fb48a9116d875aa5ee352c 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,33 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView
projectRootPath,
comparePath,
projectPath,
+ webIdeButtonOptions,
+ sshUrl,
+ httpUrl,
+ xcodeUrl,
+ kerberosUrl,
+ downloadLinks,
+ downloadArtifacts,
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 +102,26 @@ export default function initHeaderApp({ router, isReadmeView = false, isBlobView
projectShortPath,
comparePath,
isReadmeView,
+ 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,
+ httpUrl,
+ xcodeUrl,
+ sshUrl,
+ kerberosUrl,
+ downloadLinks: downloadLinks ? JSON.parse(downloadLinks) : null,
+ downloadArtifacts: downloadArtifacts ? JSON.parse(downloadArtifacts) : [],
isBlobView,
},
apolloProvider,
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index 0a40c391c37f042409baf7657caa6b8c9347ca68..b08f643f2d74e5da49ff29c6c3d1bde7104411f7 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -17,7 +17,7 @@ import { fetchPolicies } from '~/lib/graphql';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
-import SnippetCodeDropdown from '~/vue_shared/components/code_dropdown/snippet_code_dropdown.vue';
+import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/alert';
import { VISIBILITY_LEVEL_PUBLIC_STRING } from '~/visibility_level/constants';
@@ -38,7 +38,7 @@ export const i18n = {
export default {
components: {
- SnippetCodeDropdown,
+ CloneCodeDropdown,
GlIcon,
GlSprintf,
GlModal,
@@ -290,10 +290,10 @@ export default {
{{ editItem.text }}
- ({
+ components: { CloneCodeDropdown },
+ props: Object.keys(argTypes),
+ template: '',
+});
+
+const sshUrl = 'ssh://some-ssh-link';
+const httpLink = 'https://some-http-link';
+
+export const Default = Template.bind({});
+Default.args = {
+ sshUrl,
+ httpUrl: httpLink,
+};
diff --git a/app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdown.vue b/app/assets/javascripts/vue_shared/components/code_dropdown/clone_code_dropdown.vue
similarity index 72%
rename from app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdown.vue
rename to app/assets/javascripts/vue_shared/components/code_dropdown/clone_code_dropdown.vue
index e3bb9e553a4b21c17a4a10c9b939c44ed68f208e..2940edbeedabaf08dc2b5795069191fcc37f030a 100644
--- a/app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/code_dropdown/clone_code_dropdown.vue
@@ -13,19 +13,25 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
- sshLink: {
+ sshUrl: {
type: String,
required: false,
default: '',
},
- httpLink: {
+ httpUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ kerberosUrl: {
type: String,
required: false,
default: '',
},
url: {
type: String,
- required: true,
+ required: false,
+ default: '',
},
embeddable: {
type: Boolean,
@@ -35,16 +41,24 @@ export default {
},
computed: {
httpLabel() {
- const protocol = this.httpLink ? getHTTPProtocol(this.httpLink)?.toUpperCase() : '';
+ const protocol = this.httpUrl ? getHTTPProtocol(this.httpUrl)?.toUpperCase() : '';
return sprintf(__('Clone with %{protocol}'), { protocol });
},
sections() {
const sections = [
- { label: __('Clone with SSH'), link: this.sshLink, testId: 'copy-ssh-url' },
- { label: this.httpLabel, link: this.httpLink, testId: 'copy-http-url' },
+ { label: __('Clone with SSH'), link: this.sshUrl, testId: 'copy-ssh-url' },
+ { label: this.httpLabel, link: this.httpUrl, testId: 'copy-http-url' },
];
- if (this.embeddable) {
+ if (this.kerberosUrl) {
+ sections.push({
+ label: __('Clone with KRB5'),
+ link: this.kerberosUrl,
+ testId: 'copy-kerberos-url',
+ });
+ }
+
+ if (this.embeddable && this.url) {
sections.push(
{
label: __('Embed'),
diff --git a/app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdownstories.js b/app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdownstories.js
deleted file mode 100644
index d47fb8e9ef30f4c1e26f00eb2ea2280d8364cf79..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdownstories.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import SnippetCodeDropdown from './snippet_code_dropdown.vue';
-
-export default {
- component: SnippetCodeDropdown,
- title: 'vue_shared/components/snippet_code_dropdown',
-};
-
-const Template = (args, { argTypes }) => ({
- components: { SnippetCodeDropdown },
- props: Object.keys(argTypes),
- template: '',
-});
-
-const sshLink = 'ssh://some-ssh-link';
-const httpLink = 'https://some-http-link';
-
-export const Default = Template.bind({});
-Default.args = {
- sshLink,
- httpLink,
-};
-
-export const HttpLink = Template.bind({});
-HttpLink.args = {
- httpLink,
- sshLink: '',
-};
-
-export const SSHLink = Template.bind({});
-SSHLink.args = {
- sshLink,
- httpLink: '',
-};
diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
index 2a85d7d20046671478f7bb92c8f39e6b48833275..a656d470b1e6200d6e728953bc5b32661aa9bf22 100644
--- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue
+++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
@@ -124,11 +124,6 @@ export default {
required: false,
default: '',
},
- webIdePromoPopoverImg: {
- type: String,
- required: false,
- default: '',
- },
cssClasses: {
type: String,
required: false,
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index 6c36bdc9c36622b66b46a17905e1c7514109583e..f18a980ce1db3fa444044fadcd0b7170f9245961 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -1,5 +1,11 @@
- 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)
+- archive_prefix = ref ? "#{project.path}-#{ref.tr('/', '-')}" : ''
+- download_links = !project.empty_repo? ? download_links(project, ref, archive_prefix).to_json : ''
+- pipeline = local_assigns.fetch(:pipeline, nil)
+- download_artifacts = pipeline && previous_artifacts(project, ref, pipeline.latest_builds_with_artifacts).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")
@@ -10,7 +16,24 @@
#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_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) : '',
+ kerberos_url: alternative_kerberos_url? ? project.kerberos_url_to_repo : '',
+ download_links: download_links,
+ download_artifacts: download_artifacts,
+ 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 fea04813828d2198fa772bec5544ceed40a43692..5320ca8db186ed9d1e6850784b78b16487ea40ad 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,18 @@
- 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_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/app/views/shared/_web_ide_button.html.haml b/app/views/shared/_web_ide_button.html.haml
index a625234d7f3e45d206c6895c9cece37ac52e6111..2409eb42e87b828b1ff978ad0dd5071739229145 100644
--- a/app/views/shared/_web_ide_button.html.haml
+++ b/app/views/shared/_web_ide_button.html.haml
@@ -5,4 +5,4 @@
- fork_options = fork_modal_options(@project, blob)
- css_classes = false unless local_assigns[:css_classes]
-.gl-inline-block{ data: { options: button_data.merge(fork_options).to_json, web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), css_classes: css_classes, default_branch: @project.default_branch_or_main }, id: "js-#{type}-web-ide-link" }
+.gl-inline-block{ data: { options: button_data.merge(fork_options).to_json, css_classes: css_classes, default_branch: @project.default_branch_or_main }, id: "js-#{type}-web-ide-link" }
diff --git a/qa/qa/page/component/snippet.rb b/qa/qa/page/component/snippet.rb
index abd0a7c25d0289fac88d74dd4a3cca1d35b11ade..6d4cf5718ba2108046af5c88a12f4d2b5576dbdc 100644
--- a/qa/qa/page/component/snippet.rb
+++ b/qa/qa/page/component/snippet.rb
@@ -33,7 +33,7 @@ def self.included(base)
element 'blob-viewer-file-content'
end
- base.view 'app/assets/javascripts/vue_shared/components/code_dropdown/snippet_code_dropdown.vue' do
+ base.view 'app/assets/javascripts/vue_shared/components/code_dropdown/clone_code_dropdown.vue' do
element 'copy-http-url'
element 'copy-ssh-url'
end
diff --git a/spec/frontend/repository/components/header_area_spec.js b/spec/frontend/repository/components/header_area_spec.js
index 009592ae3088cbaf0a3d2dfcb9ac876b7138264e..d4cb2bc9574fbd2fa3516607f6ac9b06895fbe7d 100644
--- a/spec/frontend/repository/components/header_area_spec.js
+++ b/spec/frontend/repository/components/header_area_spec.js
@@ -3,6 +3,9 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import RefSelector from '~/ref/components/ref_selector.vue';
import HeaderArea from '~/repository/components/header_area.vue';
import Breadcrumbs from '~/repository/components/header_area/breadcrumbs.vue';
+import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
+import SourceCodeDownloadDropdown from '~/vue_shared/components/download_dropdown/download_dropdown.vue';
+import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
import BlobControls from '~/repository/components/header_area/blob_controls.vue';
import Shortcuts from '~/behaviors/shortcuts/shortcuts';
import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper';
@@ -36,6 +39,33 @@ const defaultProvided = {
projectRootPath: '/project/root/path',
comparePath: undefined,
isReadmeView: false,
+ 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',
+ httpUrl: 'https://gitlab.com/example-group/example-project.git',
+ xcodeUrl: 'xcode://clone?repo=https://gitlab.com/example-group/example-project.git',
+ sshUrl: 'git@gitlab.com:example-group/example-project.git',
+ kerberosUrl: 'https://kerberos@gitlab.com/example-group/example-project.git',
+ downloadLinks: [
+ 'https://gitlab.com/example-group/example-project/-/archive/main/example-project-main.zip',
+ 'https://gitlab.com/example-group/example-project/-/archive/main/example-project-main.tar.gz',
+ 'https://gitlab.com/example-group/example-project/-/archive/main/example-project-main.tar.bz2',
+ 'https://gitlab.com/example-group/example-project/-/releases',
+ ],
+ downloadArtifacts: [
+ 'https://gitlab.com/example-group/example-project/-/jobs/artifacts/main/download?job=build',
+ ],
};
describe('HeaderArea', () => {
@@ -45,6 +75,11 @@ 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 findCodeDropdown = () => wrapper.findComponent(CodeDropdown);
+ const findSourceCodeDownloadDropdown = () => wrapper.findComponent(SourceCodeDownloadDropdown);
+ const findCloneCodeDropdown = () => wrapper.findComponent(CloneCodeDropdown);
+
const { bindInternalEventDocument } = useMockInternalEventsTracking();
const createComponent = (props = {}, routeName = 'blobPathDecoded', provided = {}) => {
@@ -126,6 +161,35 @@ describe('HeaderArea', () => {
expect(findCompareButton().exists()).toBe(true);
});
});
+
+ describe('Edit button', () => {
+ it('renders WebIdeLink component', () => {
+ expect(findWebIdeButton().exists()).toBe(true);
+ });
+ });
+
+ describe('CodeDropdown', () => {
+ it('renders CodeDropdown component with correct props for desktop layout', () => {
+ expect(findCodeDropdown().exists()).toBe(true);
+ expect(findCodeDropdown().props('sshUrl')).toBe(defaultProvided.sshUrl);
+ expect(findCodeDropdown().props('httpUrl')).toBe(defaultProvided.httpUrl);
+ });
+ });
+
+ describe('SourceCodeDownloadDropdown', () => {
+ it('renders SourceCodeDownloadDropdown and CloneCodeDropdown component with correct props for mobile layout', () => {
+ expect(findSourceCodeDownloadDropdown().exists()).toBe(true);
+ expect(findSourceCodeDownloadDropdown().props('downloadLinks')).toEqual(
+ defaultProvided.downloadLinks,
+ );
+ expect(findSourceCodeDownloadDropdown().props('downloadArtifacts')).toEqual(
+ defaultProvided.downloadArtifacts,
+ );
+ expect(findCloneCodeDropdown().exists()).toBe(true);
+ expect(findCloneCodeDropdown().props('sshUrl')).toBe(defaultProvided.sshUrl);
+ expect(findCloneCodeDropdown().props('httpUrl')).toBe(defaultProvided.httpUrl);
+ });
+ });
});
describe('when rendered for blob view', () => {
@@ -136,6 +200,11 @@ describe('HeaderArea', () => {
expect(blobControls.props('projectPath')).toBe('test/project');
expect(blobControls.props('refType')).toBe('');
});
+
+ it('does not render CodeDropdown and SourceCodeDownloadDropdown', () => {
+ expect(findCodeDropdown().exists()).toBe(false);
+ expect(findSourceCodeDownloadDropdown().exists()).toBe(false);
+ });
});
describe('when isReadmeView is true', () => {
@@ -147,5 +216,10 @@ describe('HeaderArea', () => {
expect(findRefSelector().exists()).toBe(false);
expect(findBreadcrumbs().exists()).toBe(false);
});
+
+ it('does not render CodeDropdown and SourceCodeDownloadDropdown', () => {
+ expect(findCodeDropdown().exists()).toBe(false);
+ expect(findSourceCodeDownloadDropdown().exists()).toBe(false);
+ });
});
});
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index 1261ae32278b9d56af7da3f8263490fa94a4cd40..7a57b47008c68a628577e03632b7726f360820ad 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -22,7 +22,7 @@ import {
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
import SnippetHeader, { i18n } from '~/snippets/components/snippet_header.vue';
-import SnippetCodeDropdown from '~/vue_shared/components/code_dropdown/snippet_code_dropdown.vue';
+import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
import ImportedBadge from '~/vue_shared/components/imported_badge.vue';
import DeleteSnippetMutation from '~/snippets/mutations/delete_snippet.mutation.graphql';
import axios from '~/lib/utils/axios_utils';
@@ -86,7 +86,7 @@ describe('Snippet header component', () => {
},
},
stubs: {
- SnippetCodeDropdown,
+ CloneCodeDropdown,
GlButton,
GlDisclosureDropdown,
GlDisclosureDropdownGroup,
@@ -113,7 +113,7 @@ describe('Snippet header component', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findTooltip = () => getBinding(findIcon().element, 'gl-tooltip');
const findSpamIcon = () => wrapper.findByTestId('snippets-spam-icon');
- const findCodeDropdown = () => wrapper.findComponent(SnippetCodeDropdown);
+ const findCodeDropdown = () => wrapper.findComponent(CloneCodeDropdown);
const findImportedBadge = () => wrapper.findComponent(ImportedBadge);
const webUrl = 'http://foo.bar';
diff --git a/spec/frontend/vue_shared/components/code_dropdown/snippet_code_dropdown_spec.js b/spec/frontend/vue_shared/components/code_dropdown/clone_code_dropdown_spec.js
similarity index 61%
rename from spec/frontend/vue_shared/components/code_dropdown/snippet_code_dropdown_spec.js
rename to spec/frontend/vue_shared/components/code_dropdown/clone_code_dropdown_spec.js
index 6092b965a8c44860813d1bc606ece920827d12ad..912c648c2a3e2a1fce91b92a1a162e9a53890759 100644
--- a/spec/frontend/vue_shared/components/code_dropdown/snippet_code_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/code_dropdown/clone_code_dropdown_spec.js
@@ -1,19 +1,19 @@
import { GlFormInputGroup } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
-import SnippetCodeDropdown from '~/vue_shared/components/code_dropdown/snippet_code_dropdown.vue';
+import CloneCodeDropdown from '~/vue_shared/components/code_dropdown/clone_code_dropdown.vue';
import CodeDropdownItem from '~/vue_shared/components/code_dropdown/code_dropdown_item.vue';
-describe('SnippetCodeDropdown', () => {
+describe('CloneCodeDropdown', () => {
let wrapper;
- const sshLink = 'ssh://foo.bar';
- const httpLink = 'http://foo.bar';
- const httpsLink = 'https://foo.bar';
+ const sshUrl = 'ssh://foo.bar';
+ const httpUrl = 'http://foo.bar';
+ const httpsUrl = 'https://foo.bar';
const embedUrl = 'http://link.to.snippet';
const embedCode = ``;
const defaultPropsData = {
- sshLink,
- httpLink,
+ sshUrl,
+ httpUrl,
url: embedUrl,
embeddable: true,
};
@@ -24,13 +24,14 @@ describe('SnippetCodeDropdown', () => {
const findCopyHttpUrlButton = () => wrapper.findComponentByTestId('copy-http-url');
const findCopyEmbeddedCodeButton = () => wrapper.findComponentByTestId('copy-embedded-code');
const findCopyShareUrlButton = () => wrapper.findComponentByTestId('copy-share-url');
+ const findCopyKRB5UrlButton = () => wrapper.findComponentByTestId('copy-kerberos-url');
const createComponent = (propsData = defaultPropsData) => {
- wrapper = shallowMountExtended(SnippetCodeDropdown, {
+ wrapper = shallowMountExtended(CloneCodeDropdown, {
propsData,
stubs: {
GlFormInputGroup,
- SnippetCodeDropdown: stubComponent(SnippetCodeDropdown),
+ CloneCodeDropdown: stubComponent(CloneCodeDropdown),
},
});
};
@@ -38,8 +39,8 @@ describe('SnippetCodeDropdown', () => {
describe('rendering', () => {
it.each`
name | index | link
- ${'SSH'} | ${0} | ${sshLink}
- ${'HTTP'} | ${1} | ${httpLink}
+ ${'SSH'} | ${0} | ${sshUrl}
+ ${'HTTP'} | ${1} | ${httpUrl}
${'Embed'} | ${2} | ${embedCode}
${'Share'} | ${3} | ${embedUrl}
`('renders correct link and a copy-button for $name', ({ index, link }) => {
@@ -50,9 +51,9 @@ describe('SnippetCodeDropdown', () => {
});
it.each`
- name | finder | value
- ${'sshLink'} | ${findCopySshUrlButton} | ${sshLink}
- ${'httpLink'} | ${findCopyHttpUrlButton} | ${httpLink}
+ name | finder | value
+ ${'sshUrl'} | ${findCopySshUrlButton} | ${sshUrl}
+ ${'httpUrl'} | ${findCopyHttpUrlButton} | ${httpUrl}
`('does not fail if only $name is set', ({ name, finder, value }) => {
createComponent({ [name]: value, url: embedCode });
@@ -67,11 +68,30 @@ describe('SnippetCodeDropdown', () => {
expect(findCopyEmbeddedCodeButton().exists()).toBe(false);
expect(findCopyShareUrlButton().exists()).toBe(false);
});
+
+ it('does not render Embed and Share items, if url is not provided', () => {
+ createComponent({ ...defaultPropsData, url: '' });
+
+ expect(findCopyEmbeddedCodeButton().exists()).toBe(false);
+ expect(findCopyShareUrlButton().exists()).toBe(false);
+ });
+
+ it('does not render KRB5 link, if kerberosUrl is not provided', () => {
+ createComponent();
+
+ expect(findCopyKRB5UrlButton().exists()).toBe(false);
+ });
+
+ it('renders KRB5 link, if kerberosUrl is provided', () => {
+ createComponent({ ...defaultPropsData, kerberosUrl: 'http://:@gitlab.com/project-2.git' });
+
+ expect(findCopyKRB5UrlButton().exists()).toBe(true);
+ });
});
describe('functionality', () => {
it('correctly calculates httpLabel for HTTPS protocol', () => {
- createComponent({ ...defaultPropsData, httpLink: httpsLink });
+ createComponent({ ...defaultPropsData, httpUrl: httpsUrl });
expect(findCopyHttpUrlButton().props('label')).toContain('HTTPS');
});