diff options
Diffstat (limited to 'app/assets/javascripts/repository')
23 files changed, 293 insertions, 113 deletions
diff --git a/app/assets/javascripts/repository/commits_service.js b/app/assets/javascripts/repository/commits_service.js index e26036b5620..1e0de045d39 100644 --- a/app/assets/javascripts/repository/commits_service.js +++ b/app/assets/javascripts/repository/commits_service.js @@ -24,7 +24,7 @@ const addRequestedOffset = (offset) => { const removeLeadingSlash = (path) => path.replace(/^\//, ''); -const fetchData = (projectPath, path, ref, offset) => { +const fetchData = (projectPath, path, ref, offset, refType) => { if (fetchedBatches.includes(offset) || offset < 0) { return []; } @@ -41,12 +41,12 @@ const fetchData = (projectPath, path, ref, offset) => { ); return axios - .get(url, { params: { format: 'json', offset } }) + .get(url, { params: { format: 'json', offset, ref_type: refType } }) .then(({ data }) => normalizeData(data, path)) .catch(() => createAlert({ message: I18N_COMMIT_DATA_FETCH_ERROR })); }; -export const loadCommits = async (projectPath, path, ref, offset) => { +export const loadCommits = async (projectPath, path, ref, offset, refType) => { if (isRequested(offset)) { return []; } @@ -54,7 +54,7 @@ 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)); - const commits = await fetchData(projectPath, path, ref, offset); + const commits = await fetchData(projectPath, path, ref, offset, refType); 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 d79ccde61a8..99b861ca104 100644 --- a/app/assets/javascripts/repository/components/blob_button_group.vue +++ b/app/assets/javascripts/repository/components/blob_button_group.vue @@ -76,6 +76,11 @@ export default { type: Boolean, required: true, }, + isUsingLfs: { + type: Boolean, + required: false, + default: false, + }, }, computed: { replaceModalTitle() { @@ -148,6 +153,7 @@ export default { :can-push-code="canPushCode" :can-push-to-branch="canPushToBranch" :empty-repo="emptyRepo" + :is-using-lfs="isUsingLfs" /> </div> </template> diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index 969036f84b7..6f9f0a81dfd 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -21,7 +21,13 @@ import projectInfoQuery from '../queries/project_info.query.graphql'; import getRefMixin from '../mixins/get_ref'; import userInfoQuery from '../queries/user_info.query.graphql'; import applicationInfoQuery from '../queries/application_info.query.graphql'; -import { DEFAULT_BLOB_INFO, TEXT_FILE_TYPE, LFS_STORAGE, LEGACY_FILE_TYPES } from '../constants'; +import { + DEFAULT_BLOB_INFO, + TEXT_FILE_TYPE, + LFS_STORAGE, + LEGACY_FILE_TYPES, + CODEOWNERS_FILE_NAME, +} from '../constants'; import BlobButtonGroup from './blob_button_group.vue'; import ForkSuggestion from './fork_suggestion.vue'; import { loadViewer } from './blob_viewers'; @@ -32,6 +38,7 @@ export default { BlobButtonGroup, BlobContent, GlLoadingIcon, + CodeownersValidation: () => import('ee_component/blob/components/codeowners_validation.vue'), GlButton, ForkSuggestion, WebIdeLink, @@ -76,12 +83,15 @@ export default { project: { query: blobInfoQuery, variables() { - return { + const queryVariables = { projectPath: this.projectPath, filePath: this.path, - ref: this.originalBranch || this.ref, - shouldFetchRawText: Boolean(this.glFeatures.highlightJs), + ref: this.currentRef, + refType: this.refType?.toUpperCase() || null, + shouldFetchRawText: true, }; + + return queryVariables; }, result({ data }) { const blob = data.project?.repository?.blobs?.nodes[0] || {}; @@ -130,6 +140,11 @@ export default { type: String, required: true, }, + refType: { + type: String, + required: false, + default: null, + }, }, data() { return { @@ -163,6 +178,12 @@ export default { return nodes[0] || {}; }, + currentRef() { + return this.originalBranch || this.ref; + }, + isCodeownersFile() { + return this.path.includes(CODEOWNERS_FILE_NAME); + }, viewer() { const { richViewer, simpleViewer } = this.blobInfo; return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer; @@ -185,8 +206,7 @@ export default { ); }, shouldLoadLegacyViewer() { - const isTextFile = this.viewer.fileType === TEXT_FILE_TYPE && !this.glFeatures.highlightJs; - return isTextFile || LEGACY_FILE_TYPES.includes(this.blobInfo.fileType) || this.useFallback; + return LEGACY_FILE_TYPES.includes(this.blobInfo.fileType) || this.useFallback; }, legacyViewerLoaded() { return ( @@ -213,7 +233,9 @@ export default { const { createMergeRequestIn, forkProject } = this.userPermissions; const { canModifyBlob } = this.blobInfo; - return this.isLoggedIn && !canModifyBlob && createMergeRequestIn && forkProject; + return ( + this.isLoggedIn && !this.isUsingLfs && !canModifyBlob && createMergeRequestIn && forkProject + ); }, forkPath() { const forkPaths = { @@ -259,8 +281,12 @@ export default { const type = this.activeViewerType; this.isLoadingLegacyViewer = true; + + const newUrl = new URL(this.blobInfo.webPath, window.location.origin); + newUrl.searchParams.set('format', 'json'); + newUrl.searchParams.set('viewer', type); axios - .get(`${this.blobInfo.webPath}?format=json&viewer=${type}`) + .get(newUrl.pathname + newUrl.search) .then(async ({ data: { html, binary } }) => { this.isRenderingLegacyTextViewer = true; @@ -343,7 +369,7 @@ export default { :active-viewer-type="viewer.type" :has-render-error="hasRenderError" :show-path="false" - :override-copy="glFeatures.highlightJs" + :override-copy="true" @viewer-changed="handleViewerChanged" @copy="onCopy" > @@ -382,6 +408,7 @@ export default { :is-locked="Boolean(pathLockedByUser)" :can-lock="canLock" :show-fork-suggestion="showForkSuggestion" + :is-using-lfs="isUsingLfs" @fork="setForkTarget('view')" /> </template> @@ -391,6 +418,12 @@ export default { :fork-path="forkPath" @cancel="setForkTarget(null)" /> + <codeowners-validation + v-if="isCodeownersFile" + :current-ref="currentRef" + :project-path="projectPath" + :file-path="path" + /> <blob-content v-if="!blobViewer" class="js-syntax-highlight" @@ -416,12 +449,12 @@ export default { :code-navigation-path="blobInfo.codeNavigationPath" :blob-path="blobInfo.path" :path-prefix="blobInfo.projectBlobPathRoot" - :wrap-text-nodes="glFeatures.highlightJs" + :wrap-text-nodes="true" /> </div> <ai-genie v-if="explainCodeAvailable" - container-id="fileHolder" + container-selector=".file-content" :file-path="path" class="gl-ml-7" /> diff --git a/app/assets/javascripts/repository/components/blob_viewers/image_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/image_viewer.vue index 014f1abc121..9a8bb8e4aa6 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/image_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_viewers/image_viewer.vue @@ -8,7 +8,7 @@ export default { }, data() { return { - url: this.blob.rawPath, + url: this.blob.externalStorageUrl || this.blob.rawPath, alt: this.blob.name, }; }, diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js index 368f42e0064..d434700b29f 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/index.js +++ b/app/assets/javascripts/repository/components/blob_viewers/index.js @@ -1,4 +1,6 @@ -const viewers = { +import { TEXT_FILE_TYPE, JSON_LANGUAGE } from '../../constants'; + +export const viewers = { csv: () => import('./csv_viewer.vue'), download: () => import('./download_viewer.vue'), image: () => import('./image_viewer.vue'), @@ -18,7 +20,7 @@ const viewers = { export const loadViewer = (type, isUsingLfs, hljsWorkerEnabled, language) => { let viewer = viewers[type]; - if (hljsWorkerEnabled && language === 'json') { + if (hljsWorkerEnabled && language === JSON_LANGUAGE && type === TEXT_FILE_TYPE) { // The New Source Viewer currently only supports JSON files. // More language support will be added in: https://gitlab.com/gitlab-org/gitlab/-/issues/415753 viewer = () => import('~/vue_shared/components/source_viewer/source_viewer_new.vue'); diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index d498be0b2bb..b347f97a5ae 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -1,7 +1,8 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import { GlDisclosureDropdown, GlModalDirective } from '@gitlab/ui'; import permissionsQuery from 'shared_queries/repository/permissions.query.graphql'; -import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; +import { joinPaths, escapeFileUrl, buildURLwithRefType } from '~/lib/utils/url_utility'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import { __ } from '~/locale'; import getRefMixin from '../mixins/get_ref'; @@ -49,6 +50,11 @@ export default { required: false, default: '', }, + refType: { + type: String, + required: false, + default: null, + }, canCollaborate: { type: Boolean, required: false, @@ -141,14 +147,17 @@ export default { return acc.concat({ name, path, - to, + to: buildURLwithRefType({ path: to, refType: this.refType }), }); }, [ { name: this.projectShortPath, path: '/', - to: `/-/tree/${this.escapedRef}/`, + to: buildURLwithRefType({ + path: joinPaths('/-/tree', this.escapedRef), + refType: this.refType, + }), }, ], ); diff --git a/app/assets/javascripts/repository/components/delete_blob_modal.vue b/app/assets/javascripts/repository/components/delete_blob_modal.vue index cbdf6ef9ccd..97171a3282b 100644 --- a/app/assets/javascripts/repository/components/delete_blob_modal.vue +++ b/app/assets/javascripts/repository/components/delete_blob_modal.vue @@ -1,8 +1,18 @@ <script> -import { GlModal, GlFormGroup, GlFormInput, GlFormTextarea, GlToggle, GlForm } from '@gitlab/ui'; +import { + GlModal, + GlFormGroup, + GlFormInput, + GlFormTextarea, + GlToggle, + GlForm, + GlSprintf, + GlLink, +} from '@gitlab/ui'; import csrf from '~/lib/utils/csrf'; -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; import validation from '~/vue_shared/directives/validation'; +import { helpPagePath } from '~/helpers/help_page_helper'; import { SECONDARY_OPTIONS_TEXT, COMMIT_LABEL, @@ -28,8 +38,19 @@ export default { GlFormTextarea, GlToggle, GlForm, + GlSprintf, + GlLink, }, i18n: { + LFS_WARNING_TITLE: __("The file you're about to delete is tracked by LFS"), + LFS_WARNING_PRIMARY_CONTENT: s__( + 'BlobViewer|If you delete the file, it will be removed from the branch %{branch}.', + ), + LFS_WARNING_SECONDARY_CONTENT: s__( + 'BlobViewer|This file will still take up space in your LFS storage. %{linkStart}How do I remove tracked objects from Git LFS?%{linkEnd}', + ), + LFS_CONTINUE_TEXT: __('Continue…'), + LFS_CANCEL_TEXT: __('Cancel'), PRIMARY_OPTIONS_TEXT: __('Delete file'), SECONDARY_OPTIONS_TEXT, COMMIT_LABEL, @@ -79,6 +100,11 @@ export default { type: Boolean, required: true, }, + isUsingLfs: { + type: Boolean, + required: false, + default: false, + }, }, data() { const form = { @@ -91,6 +117,7 @@ export default { }, }; return { + lfsWarningDismissed: false, loading: false, createNewMr: true, error: '', @@ -99,7 +126,7 @@ export default { }, computed: { primaryOptions() { - return { + const defaultOptions = { text: this.$options.i18n.PRIMARY_OPTIONS_TEXT, attributes: { variant: 'danger', @@ -107,6 +134,13 @@ export default { disabled: this.loading || !this.form.state, }, }; + + const lfsWarningOptions = { + text: this.$options.i18n.LFS_CONTINUE_TEXT, + attributes: { variant: 'confirm' }, + }; + + return this.showLfsWarning ? lfsWarningOptions : defaultOptions; }, cancelOptions() { return { @@ -139,14 +173,39 @@ export default { (hasFirstLineExceedMaxLength || hasOtherLineExceedMaxLength) ); }, - /* eslint-enable dot-notation */ + showLfsWarning() { + return this.isUsingLfs && !this.lfsWarningDismissed; + }, + title() { + return this.showLfsWarning ? this.$options.i18n.LFS_WARNING_TITLE : this.modalTitle; + }, + showDeleteForm() { + return !this.isUsingLfs || (this.isUsingLfs && this.lfsWarningDismissed); + }, }, methods: { show() { this.$refs[this.modalId].show(); + this.lfsWarningDismissed = false; + }, + cancel() { + this.$refs[this.modalId].hide(); }, - submitForm(e) { + async handleContinueLfsWarning() { + this.lfsWarningDismissed = true; + await this.$nextTick(); + this.$refs.message?.$el.focus(); + }, + async handlePrimaryAction(e) { e.preventDefault(); // Prevent modal from closing + + if (this.showLfsWarning) { + this.lfsWarningDismissed = true; + await this.$nextTick(); + this.$refs.message?.$el.focus(); + return; + } + this.form.showValidation = true; if (!this.form.state) { @@ -158,6 +217,7 @@ export default { this.$refs.form.$el.submit(); }, }, + deleteLfsHelpPath: helpPagePath('topics/git/lfs/index', { anchor: 'removing-objects-from-lfs' }), }; </script> @@ -165,67 +225,86 @@ export default { <gl-modal :ref="modalId" v-bind="$attrs" - data-testid="modal-delete" :modal-id="modalId" - :title="modalTitle" + :title="title" :action-primary="primaryOptions" :action-cancel="cancelOptions" - @primary="submitForm" + @primary="handlePrimaryAction" > - <gl-form ref="form" novalidate :action="deletePath" method="post"> - <input type="hidden" name="_method" value="delete" /> - <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - <template v-if="emptyRepo"> - <input type="hidden" name="branch_name" :value="originalBranch" class="js-branch-name" /> - </template> - <template v-else> - <input type="hidden" name="original_branch" :value="originalBranch" /> - <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" - :invalid-feedback="form.fields['commit_message'].feedback" - > - <gl-form-textarea - 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 + <div v-if="showLfsWarning"> + <p> + <gl-sprintf :message="$options.i18n.LFS_WARNING_PRIMARY_CONTENT"> + <template #branch> + <code>{{ targetBranch }}</code> + </template> + </gl-sprintf> + </p> + + <p> + <gl-sprintf :message="$options.i18n.LFS_WARNING_SECONDARY_CONTENT"> + <template #link="{ content }"> + <gl-link :href="$options.deleteLfsHelpPath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + </div> + <div v-if="showDeleteForm"> + <gl-form ref="form" novalidate :action="deletePath" method="post"> + <input type="hidden" name="_method" value="delete" /> + <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> + <template v-if="emptyRepo"> + <input type="hidden" name="branch_name" :value="originalBranch" class="js-branch-name" /> + </template> + <template v-else> + <input type="hidden" name="original_branch" :value="originalBranch" /> + <input + v-if="createNewMr || !canPushToBranch" + type="hidden" + name="create_merge_request" + value="1" /> - <p v-if="showHint" class="form-text gl-text-gray-600" data-testid="hint"> - {{ $options.i18n.COMMIT_MESSAGE_HINT }} - </p> - </gl-form-group> - <gl-form-group - v-if="canPushCode" - :label="$options.i18n.TARGET_BRANCH_LABEL" - label-for="branch_name" - :invalid-feedback="form.fields['branch_name'].feedback" - > - <gl-form-input - v-model="form.fields['branch_name'].value" - v-validation:[form.showValidation] - :state="form.fields['branch_name'].state" + <gl-form-group + :label="$options.i18n.COMMIT_LABEL" + label-for="commit_message" + :invalid-feedback="form.fields['commit_message'].feedback" + > + <gl-form-textarea + ref="message" + 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 + /> + <p v-if="showHint" class="form-text gl-text-gray-600" data-testid="hint"> + {{ $options.i18n.COMMIT_MESSAGE_HINT }} + </p> + </gl-form-group> + <gl-form-group + v-if="canPushCode" + :label="$options.i18n.TARGET_BRANCH_LABEL" + label-for="branch_name" + :invalid-feedback="form.fields['branch_name'].feedback" + > + <gl-form-input + v-model="form.fields['branch_name'].value" + v-validation:[form.showValidation] + :state="form.fields['branch_name'].state" + :disabled="loading" + name="branch_name" + required + /> + </gl-form-group> + <gl-toggle + v-if="showCreateNewMrToggle" + v-model="createNewMr" :disabled="loading" - name="branch_name" - required + :label="$options.i18n.TOGGLE_CREATE_MR_LABEL" /> - </gl-form-group> - <gl-toggle - v-if="showCreateNewMrToggle" - v-model="createNewMr" - :disabled="loading" - :label="$options.i18n.TOGGLE_CREATE_MR_LABEL" - /> - </template> - </gl-form> + </template> + </gl-form> + </div> </gl-modal> </template> diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue index bdc9ed210ed..fa51ef30546 100644 --- a/app/assets/javascripts/repository/components/last_commit.vue +++ b/app/assets/javascripts/repository/components/last_commit.vue @@ -43,6 +43,7 @@ export default { return { projectPath: this.projectPath, ref: this.ref, + refType: this.refType?.toUpperCase(), path: this.currentPath.replace(/^\//, ''), }; }, @@ -69,6 +70,11 @@ export default { required: false, default: '', }, + refType: { + type: String, + required: false, + default: null, + }, }, data() { return { diff --git a/app/assets/javascripts/repository/components/preview/index.vue b/app/assets/javascripts/repository/components/preview/index.vue index 90949536cc1..bdcacd80b30 100644 --- a/app/assets/javascripts/repository/components/preview/index.vue +++ b/app/assets/javascripts/repository/components/preview/index.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui'; import SafeHtml from '~/vue_shared/directives/safe_html'; diff --git a/app/assets/javascripts/repository/components/table/header.vue b/app/assets/javascripts/repository/components/table/header.vue index 9d30aa88155..f99cfea2e6e 100644 --- a/app/assets/javascripts/repository/components/table/header.vue +++ b/app/assets/javascripts/repository/components/table/header.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <template> <thead> <tr> diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue index 46d546c2ee4..557e9cd168f 100644 --- a/app/assets/javascripts/repository/components/table/index.vue +++ b/app/assets/javascripts/repository/components/table/index.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import { GlSkeletonLoader, GlButton } from '@gitlab/ui'; import { sprintf, __ } from '~/locale'; diff --git a/app/assets/javascripts/repository/components/table/parent_row.vue b/app/assets/javascripts/repository/components/table/parent_row.vue index 8a081944600..0bc22253bd2 100644 --- a/app/assets/javascripts/repository/components/table/parent_row.vue +++ b/app/assets/javascripts/repository/components/table/parent_row.vue @@ -1,5 +1,6 @@ <script> import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui'; +import { joinPaths, buildURLwithRefType } from '~/lib/utils/url_utility'; export default { components: { @@ -8,6 +9,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, + inject: ['refType'], props: { commitRef: { type: String, @@ -31,7 +33,9 @@ export default { return splitArray.map((p) => encodeURIComponent(p)).join('/'); }, parentRoute() { - return { path: `/-/tree/${this.commitRef}/${this.parentPath}` }; + const path = joinPaths('/-/tree', this.commitRef, this.parentPath); + + return buildURLwithRefType({ path, refType: this.refType }); }, }, methods: { diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index 6dd059a349f..c839d7a53cd 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import { GlBadge, @@ -12,11 +13,10 @@ import { import { escapeRegExp } from 'lodash'; import SafeHtml from '~/vue_shared/directives/safe_html'; import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql'; -import { escapeFileUrl } from '~/lib/utils/url_utility'; +import { buildURLwithRefType, joinPaths } from '~/lib/utils/url_utility'; 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'; import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql'; import getRefMixin from '../../mixins/get_ref'; @@ -36,7 +36,8 @@ export default { GlHoverLoad: GlHoverLoadDirective, SafeHtml, }, - mixins: [getRefMixin, glFeatureFlagMixin()], + mixins: [getRefMixin], + inject: ['refType'], props: { commitInfo: { type: Object, @@ -117,14 +118,18 @@ export default { return this.commitInfo; }, routerLinkTo() { - const blobRouteConfig = { path: `/-/blob/${this.escapedRef}/${escapeFileUrl(this.path)}` }; - const treeRouteConfig = { path: `/-/tree/${this.escapedRef}/${escapeFileUrl(this.path)}` }; - if (this.isBlob) { - return blobRouteConfig; + return buildURLwithRefType({ + path: joinPaths('/-/blob', this.escapedRef, this.path), + refType: this.refType, + }); + } else if (this.isFolder) { + return buildURLwithRefType({ + path: joinPaths('/-/tree', this.escapedRef, this.path), + refType: this.refType, + }); } - - return this.isFolder ? treeRouteConfig : null; + return null; }, isBlob() { return this.type === 'blob'; @@ -159,6 +164,7 @@ export default { this.apolloQuery(paginatedTreeQuery, { projectPath: this.projectPath, ref: this.ref, + refType: this.refType?.toUpperCase() || null, path: this.path, nextPageCursor: '', pageSize: TREE_PAGE_SIZE, @@ -169,7 +175,8 @@ export default { projectPath: this.projectPath, filePath: this.path, ref: this.ref, - shouldFetchRawText: Boolean(this.glFeatures.highlightJs), + refType: this.refType?.toUpperCase() || null, + shouldFetchRawText: true, }); }, apolloQuery(query, variables) { diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index 0c9b46344c5..dd2cfddc94e 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -27,6 +27,7 @@ export default { query: projectPathQuery, }, }, + inject: ['refType'], props: { path: { type: String, @@ -99,6 +100,7 @@ export default { variables: { projectPath: this.projectPath, ref: this.ref, + refType: this.refType?.toUpperCase(), path: originalPath, nextPageCursor: this.nextPageCursor, pageSize: TREE_PAGE_SIZE, @@ -171,7 +173,7 @@ export default { } }, loadCommitData(rowNumber) { - loadCommits(this.projectPath, this.path, this.ref, rowNumber) + loadCommits(this.projectPath, this.path, this.ref, rowNumber, this.refType) .then(this.setCommitData) .catch(() => {}); }, diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js index b711f671850..3079ef0bfbb 100644 --- a/app/assets/javascripts/repository/constants.js +++ b/app/assets/javascripts/repository/constants.js @@ -83,6 +83,8 @@ export const DEFAULT_BLOB_INFO = { }, }; +export const JSON_LANGUAGE = 'json'; +export const OPENAPI_FILE_TYPE = 'openapi'; export const TEXT_FILE_TYPE = 'text'; export const LFS_STORAGE = 'lfs'; @@ -114,3 +116,5 @@ export const POLLING_INTERVAL_BACKOFF = 2; export const CONFLICTS_MODAL_ID = 'fork-sync-conflicts-modal'; export const FORK_UPDATED_EVENT = 'fork:updated'; + +export const CODEOWNERS_FILE_NAME = 'CODEOWNERS'; diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index c1e0104c6ac..9753173ac30 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -1,5 +1,6 @@ import { GlButton } from '@gitlab/ui'; import Vue from 'vue'; +// eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { parseBoolean } from '~/lib/utils/common_utils'; import { joinPaths, escapeFileUrl, visitUrl } from '~/lib/utils/url_utility'; @@ -121,6 +122,7 @@ export default function setupVueRepositoryList() { return h(LastCommit, { props: { currentPath: this.$route.params.path, + refType: this.$route.query.ref_type, }, }); }, @@ -207,6 +209,7 @@ export default function setupVueRepositoryList() { return h(Breadcrumbs, { props: { currentPath: this.$route.params.path, + refType: this.$route.query.ref_type, canCollaborate: parseBoolean(canCollaborate), canEditTree: parseBoolean(canEditTree), canPushCode: parseBoolean(canPushCode), @@ -228,20 +231,12 @@ export default function setupVueRepositoryList() { const treeHistoryLinkEl = document.getElementById('js-tree-history-link'); const { historyLink } = treeHistoryLinkEl.dataset; - let { isProjectOverview } = treeHistoryLinkEl.dataset; - - const isProjectOverviewAfterEach = router.afterEach(() => { - isProjectOverview = false; - isProjectOverviewAfterEach(); - }); // eslint-disable-next-line no-new new Vue({ el: treeHistoryLinkEl, router, render(h) { - if (parseBoolean(isProjectOverview) && !this.$route.params.path) return null; - return h( GlButton, { diff --git a/app/assets/javascripts/repository/mixins/highlight_mixin.js b/app/assets/javascripts/repository/mixins/highlight_mixin.js index 822a8b4ee38..5b6f68681bb 100644 --- a/app/assets/javascripts/repository/mixins/highlight_mixin.js +++ b/app/assets/javascripts/repository/mixins/highlight_mixin.js @@ -8,7 +8,6 @@ import { splitIntoChunks } from '~/vue_shared/components/source_viewer/workers/h import LineHighlighter from '~/blob/line_highlighter'; import languageLoader from '~/content_editor/services/highlight_js_language_loader'; import Tracking from '~/tracking'; -import { TEXT_FILE_TYPE } from '../constants'; /* * This mixin is intended to be used as an interface between our highlight worker and Vue components @@ -37,8 +36,8 @@ export default { this.trackEvent(EVENT_LABEL_FALLBACK, language); this?.onError(); }, - initHighlightWorker({ rawTextBlob, language, simpleViewer, fileType }) { - if (simpleViewer?.fileType !== TEXT_FILE_TYPE || !this.glFeatures.highlightJsWorker) return; + initHighlightWorker({ rawTextBlob, language, fileType }) { + if (language !== 'json' || !this.glFeatures.highlightJsWorker) return; if (this.isUnsupportedLanguage(language)) { this.handleUnsupportedLanguage(language); diff --git a/app/assets/javascripts/repository/mixins/preload.js b/app/assets/javascripts/repository/mixins/preload.js index 30c36dee48f..473317ecf5d 100644 --- a/app/assets/javascripts/repository/mixins/preload.js +++ b/app/assets/javascripts/repository/mixins/preload.js @@ -18,13 +18,13 @@ export default { methods: { preload(path = '/', next) { this.loadingPath = path.replace(/^\//, ''); - return this.$apollo .query({ query: paginatedTreeQuery, variables: { projectPath: this.projectPath, ref: this.ref, + refType: this.refType?.toUpperCase(), path: this.loadingPath, nextPageCursor: '', pageSize: 100, diff --git a/app/assets/javascripts/repository/pages/blob.vue b/app/assets/javascripts/repository/pages/blob.vue index c09e2133936..89bfba79a37 100644 --- a/app/assets/javascripts/repository/pages/blob.vue +++ b/app/assets/javascripts/repository/pages/blob.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> // This file is in progress and behind a feature flag, please see the following issue for more: // https://gitlab.com/gitlab-org/gitlab/-/issues/323200 @@ -31,11 +32,15 @@ export default { type: String, required: true, }, + refType: { + type: String, + required: false, + default: null, + }, }, limitedContainerElements: document.querySelectorAll(`.${LIMITED_CONTAINER_WIDTH_CLASS}`), }; </script> - <template> - <blob-content-viewer :path="path" :project-path="projectPath" /> + <blob-content-viewer :path="path" :project-path="projectPath" :ref-type="refType" /> </template> diff --git a/app/assets/javascripts/repository/pages/index.vue b/app/assets/javascripts/repository/pages/index.vue index 0e53235779c..0e46871cee1 100644 --- a/app/assets/javascripts/repository/pages/index.vue +++ b/app/assets/javascripts/repository/pages/index.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import { updateElementsVisibility } from '../utils/dom'; import TreePage from './tree.vue'; @@ -6,6 +7,13 @@ export default { components: { TreePage, }, + props: { + refType: { + type: String, + required: false, + default: null, + }, + }, mounted() { this.updateProjectElements(true); }, @@ -21,5 +29,5 @@ export default { </script> <template> - <tree-page path="/" /> + <tree-page path="/" :ref-type="refType" /> </template> diff --git a/app/assets/javascripts/repository/pages/tree.vue b/app/assets/javascripts/repository/pages/tree.vue index 6bf674eb3f1..0d35bfa679f 100644 --- a/app/assets/javascripts/repository/pages/tree.vue +++ b/app/assets/javascripts/repository/pages/tree.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <script> import TreeContent from 'jh_else_ce/repository/components/tree_content.vue'; import preloadMixin from '../mixins/preload'; @@ -8,12 +9,22 @@ export default { TreeContent, }, mixins: [preloadMixin], + provide() { + return { + refType: this.refType, + }; + }, props: { path: { type: String, required: false, default: '/', }, + refType: { + type: String, + required: false, + default: '', + }, }, computed: { isRoot() { diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js index 0a675e14eb5..5f73912ed2b 100644 --- a/app/assets/javascripts/repository/router.js +++ b/app/assets/javascripts/repository/router.js @@ -13,15 +13,19 @@ export default function createRouter(base, baseRef) { component: TreePage, props: (route) => ({ path: route.params.path?.replace(/^\//, '') || '/', + refType: route.query.ref_type || null, }), }; const blobPathRoute = { component: BlobPage, - props: (route) => ({ - path: route.params.path, - projectPath: base, - }), + props: (route) => { + return { + path: route.params.path, + projectPath: base, + refType: route.query.ref_type || null, + }; + }, }; const router = new VueRouter({ @@ -56,6 +60,9 @@ export default function createRouter(base, baseRef) { path: '/', name: 'projectRoot', component: IndexPage, + props: { + refType: 'HEADS', + }, }, ], }); diff --git a/app/assets/javascripts/repository/utils/ref_switcher_utils.js b/app/assets/javascripts/repository/utils/ref_switcher_utils.js index bcad4a2c822..f3d21971771 100644 --- a/app/assets/javascripts/repository/utils/ref_switcher_utils.js +++ b/app/assets/javascripts/repository/utils/ref_switcher_utils.js @@ -28,7 +28,7 @@ export function generateRefDestinationPath(projectRootPath, ref, selectedRef) { [, refType, actualRef] = matches; } if (refType) { - url.searchParams.set('ref_type', refType); + url.searchParams.set('ref_type', refType.toLowerCase()); } else { url.searchParams.delete('ref_type'); } |