diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
commit | aee0a117a889461ce8ced6fcf73207fe017f1d99 (patch) | |
tree | 891d9ef189227a8445d83f35c1b0fc99573f4380 /app/assets/javascripts/repository | |
parent | 8d46af3258650d305f53b819eabf7ab18d22f59e (diff) | |
download | gitlab-ce-14.6.0-rc42.tar.gz |
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/repository')
16 files changed, 144 insertions, 58 deletions
diff --git a/app/assets/javascripts/repository/commits_service.js b/app/assets/javascripts/repository/commits_service.js index 504efaea8cc..5fd9cfd4e53 100644 --- a/app/assets/javascripts/repository/commits_service.js +++ b/app/assets/javascripts/repository/commits_service.js @@ -52,14 +52,9 @@ export const loadCommits = async (projectPath, path, ref, offset) => { } // We fetch in batches of 25, so this ensures we don't refetch - Array.from(Array(COMMIT_BATCH_SIZE)).forEach((_, i) => { - addRequestedOffset(offset - i); - addRequestedOffset(offset + i); - }); + Array.from(Array(COMMIT_BATCH_SIZE)).forEach((_, i) => addRequestedOffset(offset + i)); - // Since a user could scroll either up or down, we want to support lazy loading in both directions - const commitsBatchUp = await fetchData(projectPath, path, ref, offset - COMMIT_BATCH_SIZE); - const commitsBatchDown = await fetchData(projectPath, path, ref, offset); + const commits = await fetchData(projectPath, path, ref, offset); - return commitsBatchUp.concat(commitsBatchDown); + return commits; }; diff --git a/app/assets/javascripts/repository/components/blob_button_group.vue b/app/assets/javascripts/repository/components/blob_button_group.vue index 4e7ca7b17e4..6f540bf8ece 100644 --- a/app/assets/javascripts/repository/components/blob_button_group.vue +++ b/app/assets/javascripts/repository/components/blob_button_group.vue @@ -53,6 +53,10 @@ export default { type: Boolean, required: true, }, + canPushToBranch: { + type: Boolean, + required: true, + }, emptyRepo: { type: Boolean, required: true, @@ -83,6 +87,9 @@ export default { deleteModalTitle() { return sprintf(__('Delete %{name}'), { name: this.name }); }, + lockBtnQASelector() { + return this.canLock ? 'lock_button' : 'disabled_lock_button'; + }, }, }; </script> @@ -98,6 +105,7 @@ export default { :is-locked="isLocked" :can-lock="canLock" data-testid="lock" + :data-qa-selector="lockBtnQASelector" /> <gl-button v-gl-modal="replaceModalId" data-testid="replace"> {{ $options.i18n.replace }} @@ -125,6 +133,7 @@ export default { :target-branch="targetBranch || ref" :original-branch="originalBranch || ref" :can-push-code="canPushCode" + :can-push-to-branch="canPushToBranch" :empty-repo="emptyRepo" /> </div> diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index 2cc5a8a79d2..f3fa4526999 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -106,6 +106,7 @@ export default { ideForkAndEditPath: '', storedExternally: false, canModifyBlob: false, + canCurrentUserPushToBranch: false, rawPath: '', externalStorageUrl: '', replacePath: '', @@ -156,11 +157,18 @@ export default { }, canLock() { const { pushCode, downloadCode } = this.project.userPermissions; + const currentUsername = window.gon?.current_username; + + if (this.pathLockedByUser && this.pathLockedByUser.username !== currentUsername) { + return false; + } return pushCode && downloadCode; }, - isLocked() { - return this.project.pathLocks.nodes.some((node) => node.path === this.path); + pathLockedByUser() { + const pathLock = this.project.pathLocks.nodes.find((node) => node.path === this.path); + + return pathLock ? pathLock.user : null; }, showForkSuggestion() { const { createMergeRequestIn, forkProject } = this.project.userPermissions; @@ -266,9 +274,10 @@ export default { :replace-path="blobInfo.replacePath" :delete-path="blobInfo.webPath" :can-push-code="project.userPermissions.pushCode" + :can-push-to-branch="blobInfo.canCurrentUserPushToBranch" :empty-repo="project.repository.empty" :project-path="projectPath" - :is-locked="isLocked" + :is-locked="Boolean(pathLockedByUser)" :can-lock="canLock" /> </template> diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js index c5209d97abb..8f6f2d15215 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/index.js +++ b/app/assets/javascripts/repository/components/blob_viewers/index.js @@ -3,8 +3,11 @@ export const loadViewer = (type) => { case 'empty': return () => import(/* webpackChunkName: 'blob_empty_viewer' */ './empty_viewer.vue'); case 'text': - return gon.features.refactorTextViewer - ? () => import(/* webpackChunkName: 'blob_text_viewer' */ './text_viewer.vue') + 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'); @@ -12,6 +15,8 @@ export const loadViewer = (type) => { 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; } @@ -21,8 +26,7 @@ export const viewerProps = (type, blob) => { return { text: { content: blob.rawTextBlob, - fileName: blob.name, - readOnly: true, + autoDetect: true, // We'll eventually disable autoDetect and pass the language explicitly to reduce the footprint (https://gitlab.com/gitlab-org/gitlab/-/issues/348145) }, download: { fileName: blob.name, @@ -36,5 +40,9 @@ export const viewerProps = (type, blob) => { video: { url: blob.rawPath, }, + pdf: { + url: blob.rawPath, + fileSize: blob.rawSize, + }, }[type]; }; diff --git a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue new file mode 100644 index 00000000000..803a357df52 --- /dev/null +++ b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue @@ -0,0 +1,50 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import PdfViewer from '~/blob/pdf/pdf_viewer.vue'; +import { __ } from '~/locale'; +import { PDF_MAX_FILE_SIZE, PDF_MAX_PAGE_LIMIT } from '../../constants'; + +export default { + components: { GlButton, PdfViewer }, + i18n: { + tooLargeDescription: __('This PDF is too large to display. Please download to view.'), + tooLargeButtonText: __('Download PDF'), + }, + props: { + url: { + type: String, + required: true, + }, + fileSize: { + type: Number, + required: true, + }, + }, + data() { + return { totalPages: 0 }; + }, + computed: { + tooLargeToDisplay() { + return this.fileSize > PDF_MAX_FILE_SIZE || this.totalPages > PDF_MAX_PAGE_LIMIT; + }, + }, + methods: { + handleOnLoad(totalPages) { + this.totalPages = totalPages; + }, + }, +}; +</script> +<template> + <div> + <pdf-viewer v-if="!tooLargeToDisplay" :pdf="url" @pdflabload="handleOnLoad" /> + + <div v-else class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-p-5"> + <p>{{ $options.i18n.tooLargeDescription }}</p> + + <gl-button icon="download" category="secondary" variant="confirm" :href="url" download>{{ + $options.i18n.tooLargeButtonText + }}</gl-button> + </div> + </div> +</template> diff --git a/app/assets/javascripts/repository/components/blob_viewers/text_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/text_viewer.vue deleted file mode 100644 index 57fc979a56e..00000000000 --- a/app/assets/javascripts/repository/components/blob_viewers/text_viewer.vue +++ /dev/null @@ -1,25 +0,0 @@ -<script> -export default { - components: { - SourceEditor: () => - import(/* webpackChunkName: 'SourceEditor' */ '~/vue_shared/components/source_editor.vue'), - }, - props: { - content: { - type: String, - required: true, - }, - fileName: { - type: String, - required: true, - }, - readOnly: { - type: Boolean, - required: true, - }, - }, -}; -</script> -<template> - <source-editor :value="content" :file-name="fileName" :editor-options="{ readOnly }" /> -</template> diff --git a/app/assets/javascripts/repository/components/delete_blob_modal.vue b/app/assets/javascripts/repository/components/delete_blob_modal.vue index 4a8cedb60b4..0d3dc06c2c8 100644 --- a/app/assets/javascripts/repository/components/delete_blob_modal.vue +++ b/app/assets/javascripts/repository/components/delete_blob_modal.vue @@ -71,6 +71,10 @@ export default { type: Boolean, required: true, }, + canPushToBranch: { + type: Boolean, + required: true, + }, emptyRepo: { type: Boolean, required: true, @@ -176,9 +180,12 @@ export default { </template> <template v-else> <input type="hidden" name="original_branch" :value="originalBranch" /> - <!-- Once "push to branch" permission is made available, will need to add to conditional - Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/335462 --> - <input v-if="createNewMr" type="hidden" name="create_merge_request" value="1" /> + <input + v-if="createNewMr || !canPushToBranch" + type="hidden" + name="create_merge_request" + value="1" + /> <gl-form-group :label="$options.i18n.COMMIT_LABEL" label-for="commit_message" @@ -188,6 +195,7 @@ export default { v-model="form.fields['commit_message'].value" v-validation:[form.showValidation] name="commit_message" + data-qa-selector="commit_message_field" :state="form.fields['commit_message'].state" :disabled="loading" required diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue index 62066973ee6..43e114a91d3 100644 --- a/app/assets/javascripts/repository/components/last_commit.vue +++ b/app/assets/javascripts/repository/components/last_commit.vue @@ -111,7 +111,7 @@ export default { </script> <template> - <div class="info-well d-none d-sm-flex project-last-commit commit p-3"> + <div class="well-segment commit gl-p-5 gl-w-full"> <gl-loading-icon v-if="isLoading" size="md" color="dark" class="m-auto" /> <template v-else-if="commit"> <user-avatar-link diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index bd06c064ab7..8fcec5fb893 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -13,7 +13,7 @@ import { import { escapeRegExp } from 'lodash'; import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql'; import { escapeFileUrl } from '~/lib/utils/url_utility'; -import { TREE_PAGE_SIZE } from '~/repository/constants'; +import { TREE_PAGE_SIZE, ROW_APPEAR_DELAY } from '~/repository/constants'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -128,6 +128,7 @@ export default { return { commit: null, hasRowAppeared: false, + delayedRowAppear: null, }; }, computed: { @@ -202,14 +203,19 @@ export default { rowAppeared() { this.hasRowAppeared = true; + if (this.commitInfo) { + return; + } + if (this.glFeatures.lazyLoadCommits) { - this.$emit('row-appear', { - rowNumber: this.rowNumber, - hasCommit: Boolean(this.commitInfo), - }); + this.delayedRowAppear = setTimeout( + () => this.$emit('row-appear', this.rowNumber), + ROW_APPEAR_DELAY, + ); } }, rowDisappeared() { + clearTimeout(this.delayedRowAppear); this.hasRowAppeared = false; }, }, diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index ffe8d5531f8..130ebf77361 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -3,7 +3,12 @@ import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.g import createFlash from '~/flash'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { __ } from '../../locale'; -import { TREE_PAGE_SIZE, TREE_INITIAL_FETCH_COUNT, TREE_PAGE_LIMIT } from '../constants'; +import { + TREE_PAGE_SIZE, + TREE_INITIAL_FETCH_COUNT, + TREE_PAGE_LIMIT, + COMMIT_BATCH_SIZE, +} from '../constants'; import getRefMixin from '../mixins/get_ref'; import projectPathQuery from '../queries/project_path.query.graphql'; import { readmeFile } from '../utils/readme'; @@ -151,11 +156,19 @@ export default { .concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo) .find(({ hasNextPage }) => hasNextPage); }, - loadCommitData({ rowNumber = 0, hasCommit } = {}) { - if (!this.glFeatures.lazyLoadCommits || hasCommit || isRequested(rowNumber)) { + handleRowAppear(rowNumber) { + if (!this.glFeatures.lazyLoadCommits || isRequested(rowNumber)) { return; } + // Since a user could scroll either up or down, we want to support lazy loading in both directions + this.loadCommitData(rowNumber); + + if (rowNumber - COMMIT_BATCH_SIZE >= 0) { + this.loadCommitData(rowNumber - COMMIT_BATCH_SIZE); + } + }, + loadCommitData(rowNumber) { loadCommits(this.projectPath, this.path, this.ref, rowNumber) .then(this.setCommitData) .catch(() => {}); @@ -182,7 +195,7 @@ export default { :has-more="hasShowMore" :commits="commits" @showMore="handleShowMore" - @row-appear="loadCommitData" + @row-appear="handleRowAppear" /> <file-preview v-if="readme" :blob="readme" /> </div> diff --git a/app/assets/javascripts/repository/components/upload_blob_modal.vue b/app/assets/javascripts/repository/components/upload_blob_modal.vue index 11e5b5608cb..b56c9ce5247 100644 --- a/app/assets/javascripts/repository/components/upload_blob_modal.vue +++ b/app/assets/javascripts/repository/components/upload_blob_modal.vue @@ -24,10 +24,10 @@ import { } from '../constants'; const PRIMARY_OPTIONS_TEXT = __('Upload file'); -const MODAL_TITLE = __('Upload New File'); +const MODAL_TITLE = __('Upload new file'); const REMOVE_FILE_TEXT = __('Remove file'); const NEW_BRANCH_IN_FORK = __( - 'A new branch will be created in your fork and a new merge request will be started.', + 'GitLab will create a branch in your fork and start a merge request.', ); const ERROR_MESSAGE = __('Error uploading file. Please try again.'); diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js index 152fabbd7cc..d01757d6141 100644 --- a/app/assets/javascripts/repository/constants.js +++ b/app/assets/javascripts/repository/constants.js @@ -11,7 +11,7 @@ export const COMMIT_LABEL = __('Commit message'); export const TARGET_BRANCH_LABEL = __('Target branch'); export const TOGGLE_CREATE_MR_LABEL = __('Start a new merge request with these changes'); export const NEW_BRANCH_IN_FORK = __( - 'A new branch will be created in your fork and a new merge request will be started.', + 'GitLab will create a branch in your fork and start a merge request.', ); export const COMMIT_MESSAGE_SUBJECT_MAX_LENGTH = 52; @@ -20,3 +20,8 @@ export const COMMIT_MESSAGE_BODY_MAX_LENGTH = 72; export const LIMITED_CONTAINER_WIDTH_CLASS = 'limit-container-width'; export const I18N_COMMIT_DATA_FETCH_ERROR = __('An error occurred while fetching commit data.'); + +export const PDF_MAX_FILE_SIZE = 10000000; // 10 MB +export const PDF_MAX_PAGE_LIMIT = 50; + +export const ROW_APPEAR_DELAY = 150; diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index 45e026ad695..197b19387cf 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -188,5 +188,5 @@ export default function setupVueRepositoryList() { }, }); - return { router, data: dataset }; + return { router, data: dataset, apolloProvider, projectPath }; } diff --git a/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql index eaebc4ddf17..0851564bb24 100644 --- a/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql +++ b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql @@ -4,6 +4,7 @@ mutation toggleLock($projectPath: ID!, $filePath: String!, $lock: Boolean!) { id pathLocks { nodes { + id path } } diff --git a/app/assets/javascripts/repository/pages/tree.vue b/app/assets/javascripts/repository/pages/tree.vue index cbdc62624d4..6bf674eb3f1 100644 --- a/app/assets/javascripts/repository/pages/tree.vue +++ b/app/assets/javascripts/repository/pages/tree.vue @@ -1,5 +1,5 @@ <script> -import TreeContent from '../components/tree_content.vue'; +import TreeContent from 'jh_else_ce/repository/components/tree_content.vue'; import preloadMixin from '../mixins/preload'; import { updateElementsVisibility } from '../utils/dom'; diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql index cf3892802fd..45d1ba80917 100644 --- a/app/assets/javascripts/repository/queries/blob_info.query.graphql +++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql @@ -9,13 +9,19 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { } pathLocks { nodes { + id path + user { + id + username + } } } repository { empty blobs(paths: [$filePath], ref: $ref) { nodes { + id webPath name size @@ -28,6 +34,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { forkAndEditPath ideForkAndEditPath canModifyBlob + canCurrentUserPushToBranch storedExternally rawPath replacePath |