Commit ee294618 authored by Matthias Käppler's avatar Matthias Käppler

Merge branch 'blob-show-spec' into 'master'

Blob refactor: Fix/update blob show specs

See merge request gitlab-org/gitlab!78541
parents 84ff263c 9e1369c1
......@@ -42,6 +42,11 @@ export default {
required: false,
default: false,
},
showPath: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
......@@ -55,6 +60,9 @@ export default {
showDefaultActions() {
return !this.hideDefaultActions;
},
isEmpty() {
return this.blob.rawSize === 0;
},
},
watch: {
viewer(newVal, oldVal) {
......@@ -74,7 +82,7 @@ export default {
<div class="js-file-title file-title-flex-parent">
<div class="gl-display-flex">
<table-of-contents class="gl-pr-2" />
<blob-filepath :blob="blob">
<blob-filepath :blob="blob" :show-path="showPath">
<template #filepath-prepend>
<slot name="prepend"></slot>
</template>
......@@ -88,12 +96,13 @@ export default {
<default-actions
v-if="showDefaultActions"
:raw-path="blob.rawPath"
:raw-path="blob.externalStorageUrl || blob.rawPath"
:active-viewer="viewer"
:has-render-error="hasRenderError"
:is-binary="isBinary"
:environment-name="blob.environmentFormattedExternalUrl"
:environment-path="blob.environmentExternalUrlForRouteMap"
:is-empty="isEmpty"
@copy="proxyCopyRequest"
/>
</div>
......
......@@ -48,6 +48,11 @@ export default {
required: false,
default: null,
},
isEmpty: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
downloadUrl() {
......@@ -87,6 +92,7 @@ export default {
icon="copy-to-clipboard"
category="primary"
variant="default"
class="js-copy-blob-source-btn"
/>
<gl-button
v-if="!isBinary"
......@@ -100,6 +106,7 @@ export default {
variant="default"
/>
<gl-button
v-if="!isEmpty"
v-gl-tooltip.hover
:aria-label="$options.BTN_DOWNLOAD_TITLE"
:title="$options.BTN_DOWNLOAD_TITLE"
......
......@@ -15,6 +15,11 @@ export default {
type: Object,
required: true,
},
showPath: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
blobSize() {
......@@ -26,6 +31,13 @@ export default {
showLfsBadge() {
return this.blob.storedExternally && this.blob.externalStorage === 'lfs';
},
fileName() {
if (this.showPath) {
return this.blob.path;
}
return this.blob.name;
},
},
};
</script>
......@@ -33,12 +45,12 @@ export default {
<div class="file-header-content d-flex align-items-center lh-100">
<slot name="filepath-prepend"></slot>
<template v-if="blob.path">
<file-icon :file-name="blob.path" :size="16" aria-hidden="true" css-classes="mr-2" />
<template v-if="fileName">
<file-icon :file-name="fileName" :size="16" aria-hidden="true" css-classes="mr-2" />
<strong
class="file-title-name mr-1 js-blob-header-filepath"
data-qa-selector="file_title_content"
>{{ blob.path }}</strong
>{{ fileName }}</strong
>
</template>
......
......@@ -153,7 +153,7 @@ export default {
},
blobViewer() {
const { fileType } = this.viewer;
return loadViewer(fileType);
return loadViewer(fileType, this.isUsingLfs);
},
viewerProps() {
const { fileType } = this.viewer;
......@@ -185,6 +185,9 @@ export default {
? this.blobInfo.ideForkAndEditPath
: this.blobInfo.forkAndEditPath;
},
isUsingLfs() {
return this.blobInfo.storedExternally && this.blobInfo.externalStorage === 'lfs';
},
},
methods: {
loadLegacyViewer(type) {
......@@ -245,10 +248,11 @@ export default {
<div v-if="blobInfo && !isLoading" class="file-holder">
<blob-header
:blob="blobInfo"
:hide-viewer-switcher="!hasRichViewer || isBinaryFileType"
:hide-viewer-switcher="!hasRichViewer || isBinaryFileType || isUsingLfs"
:is-binary="isBinaryFileType"
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
:show-path="false"
@viewer-changed="switchViewer"
>
<template #actions>
......
export const loadViewer = (type) => {
switch (type) {
case 'empty':
return () => import(/* webpackChunkName: 'blob_empty_viewer' */ './empty_viewer.vue');
case 'text':
return gon.features.highlightJs
? () =>
import(
/* webpackChunkName: 'blob_text_viewer' */ '~/vue_shared/components/source_viewer.vue'
)
: null;
case 'download':
return () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
case 'image':
return () => import(/* webpackChunkName: 'blob_image_viewer' */ './image_viewer.vue');
case 'video':
return () => import(/* webpackChunkName: 'blob_video_viewer' */ './video_viewer.vue');
case 'pdf':
return () => import(/* webpackChunkName: 'blob_pdf_viewer' */ './pdf_viewer.vue');
default:
return null;
const viewers = {
download: () => import('./download_viewer.vue'),
image: () => import('./image_viewer.vue'),
video: () => import('./video_viewer.vue'),
empty: () => import('./empty_viewer.vue'),
text: () => import('~/vue_shared/components/source_viewer.vue'),
pdf: () => import('./pdf_viewer.vue'),
lfs: () => import('./lfs_viewer.vue'),
};
export const loadViewer = (type, isUsingLfs) => {
let viewer = viewers[type];
if (!viewer && isUsingLfs) {
viewer = viewers.lfs;
}
return viewer;
};
export const viewerProps = (type, blob) => {
return {
const props = {
text: {
content: blob.rawTextBlob,
autoDetect: true, // We'll eventually disable autoDetect and pass the language explicitly to reduce the footprint (https://gitlab.com/gitlab-org/gitlab/-/issues/348145)
......@@ -44,5 +40,11 @@ export const viewerProps = (type, blob) => {
url: blob.rawPath,
fileSize: blob.rawSize,
},
}[type];
lfs: {
fileName: blob.name,
filePath: blob.rawPath,
},
};
return props[type] || props[blob.externalStorage];
};
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
i18n: {
lfsText: __(
'This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead.',
),
},
components: {
GlLink,
GlSprintf,
},
props: {
fileName: {
type: String,
required: true,
},
filePath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="gl-text-center gl-py-13 gl-bg-gray-50" data-type="lfs">
<gl-sprintf :message="$options.i18n.lfsText">
<template #link="{ content }">
<gl-link :href="filePath" :download="fileName" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</template>
......@@ -32,6 +32,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) {
archived
storedExternally
externalStorage
externalStorageUrl
rawPath
replacePath
pipelineEditorPath
......
......@@ -115,7 +115,12 @@ export default {
};
</script>
<template>
<div class="file-content code js-syntax-highlight" :class="$options.userColorScheme">
<div
class="file-content code js-syntax-highlight blob-content"
:class="$options.userColorScheme"
data-type="simple"
data-qa-selector="blob_viewer_file_content"
>
<line-numbers :lines="lineNumbers" />
<pre class="code"><code v-safe-html="highlightedContent"></code>
</pre>
......
......@@ -125,7 +125,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def external_storage_url
return unless static_objects_external_storage_enabled?
external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path))
external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path), project)
end
private
......
......@@ -36578,6 +36578,9 @@ msgstr ""
msgid "This content could not be displayed because %{reason}. You can %{options} instead."
msgstr ""
msgid "This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead."
msgstr ""
msgid "This credential has expired"
msgstr ""
......
......@@ -22,6 +22,10 @@ module QA
element :copy_contents_button
end
base.view 'app/assets/javascripts/vue_shared/components/source_viewer.vue' do
element :blob_viewer_file_content
end
base.view 'app/views/projects/blob/_header_content.html.haml' do
element :file_name_content
end
......
......@@ -13,6 +13,7 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
<blob-filepath-stub
blob="[object Object]"
showpath="true"
/>
</div>
......
......@@ -236,7 +236,7 @@ describe('Blob content viewer component', () => {
await waitForPromises();
expect(loadViewer).toHaveBeenCalledWith(viewer);
expect(loadViewer).toHaveBeenCalledWith(viewer, false);
expect(wrapper.findComponent(loadViewerReturnValue).exists()).toBe(true);
},
);
......
import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import LfsViewer from '~/repository/components/blob_viewers/lfs_viewer.vue';
describe('LFS Viewer', () => {
let wrapper;
const DEFAULT_PROPS = {
fileName: 'file_name.js',
filePath: '/some/file/path',
};
const createComponent = () => {
wrapper = shallowMount(LfsViewer, {
propsData: { ...DEFAULT_PROPS },
stubs: { GlSprintf },
});
};
const findLink = () => wrapper.findComponent(GlLink);
beforeEach(() => createComponent());
afterEach(() => wrapper.destroy());
it('renders the correct text', () => {
expect(wrapper.text()).toBe(
'This content could not be displayed because it is stored in LFS. You can download it instead.',
);
});
it('renders download link', () => {
const { filePath, fileName } = DEFAULT_PROPS;
expect(findLink().attributes()).toMatchObject({
target: '_blank',
href: filePath,
download: fileName,
});
});
});
......@@ -17,6 +17,7 @@ export const simpleViewerMock = {
canCurrentUserPushToBranch: true,
archived: false,
storedExternally: false,
externalStorageUrl: '',
externalStorage: 'lfs',
rawPath: 'some_file.js',
replacePath: 'some_file.js/replace',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment