diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-20 21:10:33 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-20 21:10:33 +0300 |
commit | 1cb90c3b4f04d42fa30f7903b10b32721c5fadac (patch) | |
tree | 7fcc5031b249c936a73dfbd4fe2594b1e0a2943d /app/assets/javascripts | |
parent | e45c8a7e74d4c1a1f7e12504df3611f797620166 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
11 files changed, 284 insertions, 8 deletions
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js index 88be64d0a1a..a8c0b064595 100644 --- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js +++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js @@ -41,11 +41,18 @@ export const deleteDraft = ({ commit, getters }, draft) => }) .catch(() => flash(__('An error occurred while deleting the comment'))); -export const fetchDrafts = ({ commit, getters }) => +export const fetchDrafts = ({ commit, getters, state, dispatch }) => service .fetchDrafts(getters.getNotesData.draftsPath) .then((res) => res.data) .then((data) => commit(types.SET_BATCH_COMMENTS_DRAFTS, data)) + .then(() => { + state.drafts.forEach((draft) => { + if (!draft.line_code) { + dispatch('convertToDiscussion', draft.discussion_id, { root: true }); + } + }); + }) .catch(() => flash(__('An error occurred while fetching pending comments'))); export const publishSingleDraft = ({ commit, dispatch, getters }, draftId) => { diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 6a3f5993a22..de4f950b32d 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -181,7 +181,6 @@ export default { plainDiffPath: (state) => state.diffs.plainDiffPath, emailPatchPath: (state) => state.diffs.emailPatchPath, retrievingBatches: (state) => state.diffs.retrievingBatches, - codequalityDiff: (state) => state.diffs.codequalityDiff, }), ...mapState('diffs', [ 'showTreeList', diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 283dbc6031c..cb74c7dc7cd 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -1,6 +1,7 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; import { mapActions, mapGetters, mapState } from 'vuex'; +import { mapInline, mapParallel } from 'ee_else_ce/diffs/components/diff_row_utils'; import DiffFileDrafts from '~/batch_comments/components/diff_file_drafts.vue'; import draftCommentsMixin from '~/diffs/mixins/draft_comments'; import { diffViewerModes } from '~/ide/constants'; @@ -15,7 +16,6 @@ import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_ import { IMAGE_DIFF_POSITION_TYPE } from '../constants'; import { getDiffMode } from '../store/utils'; import DiffDiscussions from './diff_discussions.vue'; -import { mapInline, mapParallel } from './diff_row_utils'; import DiffView from './diff_view.vue'; import ImageDiffOverlay from './image_diff_overlay.vue'; import InlineDiffView from './inline_diff_view.vue'; @@ -55,6 +55,7 @@ export default { 'isParallelView', 'getCommentFormForDiffFile', 'diffLines', + 'fileLineCodequality', ]), ...mapGetters(['getNoteableData', 'noteableType', 'getUserData']), diffMode() { diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 676c9a3c7bc..121e45502fd 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -202,6 +202,9 @@ export default { externalUrlLabel() { return sprintf(__('View on %{url}'), { url: this.diffFile.formatted_external_url }); }, + showCodequalityBadge() { + return this.codequalityDiff?.length > 0 && !this.glFeatures.codequalityMrDiffAnnotations; + }, }, methods: { ...mapActions('diffs', [ @@ -334,7 +337,7 @@ export default { /> <code-quality-badge - v-if="codequalityDiff.length" + v-if="showCodequalityBadge" :file-name="filePath" :codequality-diff="codequalityDiff" class="gl-mr-2" diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue index d4a1a9e0e46..74b97ef01f9 100644 --- a/app/assets/javascripts/diffs/components/diff_row.vue +++ b/app/assets/javascripts/diffs/components/diff_row.vue @@ -24,6 +24,8 @@ import * as utils from './diff_row_utils'; export default { components: { DiffGutterAvatars, + CodeQualityGutterIcon: () => + import('ee_component/diffs/components/code_quality_gutter_icon.vue'), }, directives: { GlTooltip: GlTooltipDirective, @@ -89,6 +91,20 @@ export default { if (!this.line.right) return {}; return this.fileLineCoverage(this.filePath, this.line.right.new_line); }, + showCodequalityLeft() { + return ( + this.glFeatures.codequalityMrDiffAnnotations && + this.inline && + this.line.left?.codequality?.length > 0 + ); + }, + showCodequalityRight() { + return ( + this.glFeatures.codequalityMrDiffAnnotations && + !this.inline && + this.line.right?.codequality?.length > 0 + ); + }, classNameMapCellLeft() { return utils.classNameMapCell({ line: this.line.left, @@ -269,6 +285,12 @@ export default { :class="[...parallelViewLeftLineType, coverageStateLeft.class]" class="diff-td line-coverage left-side" ></div> + <div class="diff-td line-codequality left-side" :class="[...parallelViewLeftLineType]"> + <code-quality-gutter-icon + v-if="showCodequalityLeft" + :codequality="line.left.codequality" + /> + </div> <div :id="line.left.line_code" :key="line.left.line_code" @@ -299,6 +321,11 @@ export default { :class="emptyCellLeftClassMap" ></div> <div + v-if="inline" + class="diff-td line-codequality left-side empty-cell" + :class="emptyCellLeftClassMap" + ></div> + <div class="diff-td line_content with-coverage left-side empty-cell" :class="[emptyCellLeftClassMap, { parallel: !inline }]" ></div> @@ -371,6 +398,15 @@ export default { class="diff-td line-coverage right-side" ></div> <div + class="diff-td line-codequality right-side" + :class="[line.right.type, { hll: isHighlighted, hll: isCommented }]" + > + <code-quality-gutter-icon + v-if="showCodequalityRight" + :codequality="line.right.codequality" + /> + </div> + <div :id="line.right.line_code" :key="line.right.rich_text" :class="[ @@ -406,6 +442,10 @@ export default { :class="emptyCellRightClassMap" ></div> <div + class="diff-td line-codequality right-side empty-cell" + :class="emptyCellRightClassMap" + ></div> + <div class="diff-td line_content with-coverage right-side empty-cell" :class="[emptyCellRightClassMap, { parallel: !inline }]" ></div> diff --git a/app/assets/javascripts/diffs/components/diff_view.vue b/app/assets/javascripts/diffs/components/diff_view.vue index 43cfa22073f..cc8c8139770 100644 --- a/app/assets/javascripts/diffs/components/diff_view.vue +++ b/app/assets/javascripts/diffs/components/diff_view.vue @@ -43,6 +43,7 @@ export default { }, computed: { ...mapGetters('diffs', ['commitId']), + ...mapState('diffs', ['codequalityDiff']), ...mapState({ selectedCommentPosition: ({ notes }) => notes.selectedCommentPosition, selectedCommentPositionHover: ({ notes }) => notes.selectedCommentPositionHover, @@ -56,6 +57,9 @@ export default { this.diffLines, ); }, + hasCodequalityChanges() { + return this.codequalityDiff?.files?.[this.diffFile.file_path]?.length > 0; + }, }, methods: { ...mapActions(['setSelectedCommentPosition']), @@ -98,7 +102,7 @@ export default { <template> <div - :class="[$options.userColorScheme, { inline }]" + :class="[$options.userColorScheme, { inline, 'with-codequality': hasCodequalityChanges }]" :data-commit-id="commitId" class="diff-grid diff-table code diff-wrap-lines js-syntax-highlight text-file" > diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index 78ccfbaa558..a536db5c417 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -136,6 +136,11 @@ export const fileLineCoverage = (state) => (file, line) => { return {}; }; +// This function is overwritten for the inline codequality feature in EE +export const fileLineCodequality = () => () => { + return null; +}; + /** * Returns index of a currently selected diff in diffFiles * @returns {number} diff --git a/app/assets/javascripts/diffs/store/modules/index.js b/app/assets/javascripts/diffs/store/modules/index.js index 03d11e60745..169502a957b 100644 --- a/app/assets/javascripts/diffs/store/modules/index.js +++ b/app/assets/javascripts/diffs/store/modules/index.js @@ -1,7 +1,7 @@ import * as actions from 'ee_else_ce/diffs/store/actions'; +import * as getters from 'ee_else_ce/diffs/store/getters'; import createState from 'ee_else_ce/diffs/store/modules/diff_state'; import mutations from 'ee_else_ce/diffs/store/mutations'; -import * as getters from '../getters'; export default () => ({ namespaced: true, diff --git a/app/assets/javascripts/releases/components/app_index_apollo_client.vue b/app/assets/javascripts/releases/components/app_index_apollo_client.vue new file mode 100644 index 00000000000..be4d7d8543c --- /dev/null +++ b/app/assets/javascripts/releases/components/app_index_apollo_client.vue @@ -0,0 +1,155 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import createFlash from '~/flash'; +import { getParameterByName } from '~/lib/utils/common_utils'; +import { __ } from '~/locale'; +import { PAGE_SIZE } from '~/releases/constants'; +import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql'; +import { convertAllReleasesGraphQLResponse } from '~/releases/util'; +import ReleaseBlock from './release_block.vue'; +import ReleaseSkeletonLoader from './release_skeleton_loader.vue'; +import ReleasesEmptyState from './releases_empty_state.vue'; + +export default { + name: 'ReleasesIndexApolloClientApp', + components: { + GlButton, + ReleaseBlock, + ReleaseSkeletonLoader, + ReleasesEmptyState, + }, + inject: { + projectPath: { + default: '', + }, + newReleasePath: { + default: '', + }, + }, + apollo: { + graphqlResponse: { + query: allReleasesQuery, + variables() { + return this.queryVariables; + }, + update(data) { + return { data }; + }, + error(error) { + this.hasError = true; + + createFlash({ + message: this.$options.i18n.errorMessage, + captureError: true, + error, + }); + }, + }, + }, + data() { + return { + hasError: false, + cursors: { + before: getParameterByName('before'), + after: getParameterByName('after'), + }, + }; + }, + computed: { + queryVariables() { + let paginationParams = { first: PAGE_SIZE }; + if (this.cursors.after) { + paginationParams = { + after: this.cursors.after, + first: PAGE_SIZE, + }; + } else if (this.cursors.before) { + paginationParams = { + before: this.cursors.before, + last: PAGE_SIZE, + }; + } + + return { + fullPath: this.projectPath, + ...paginationParams, + }; + }, + isLoading() { + return this.$apollo.queries.graphqlResponse.loading; + }, + releases() { + if (!this.graphqlResponse || this.hasError) { + return []; + } + + return convertAllReleasesGraphQLResponse(this.graphqlResponse).data; + }, + shouldRenderEmptyState() { + return !this.releases.length && !this.hasError && !this.isLoading; + }, + shouldRenderSuccessState() { + return this.releases.length && !this.isLoading && !this.hasError; + }, + shouldRenderLoadingIndicator() { + return this.isLoading && !this.hasError; + }, + }, + created() { + this.updateQueryParamsFromUrl(); + + window.addEventListener('popstate', this.updateQueryParamsFromUrl); + }, + destroyed() { + window.removeEventListener('popstate', this.updateQueryParamsFromUrl); + }, + methods: { + updateQueryParamsFromUrl() { + this.cursors.before = getParameterByName('before'); + this.cursors.after = getParameterByName('after'); + }, + }, + i18n: { + newRelease: __('New release'), + errorMessage: __('An error occurred while fetching the releases. Please try again.'), + }, +}; +</script> +<template> + <div class="flex flex-column mt-2"> + <div class="gl-align-self-end gl-mb-3"> + <gl-button + v-if="newReleasePath" + :href="newReleasePath" + :aria-describedby="shouldRenderEmptyState && 'releases-description'" + category="primary" + variant="success" + >{{ $options.i18n.newRelease }}</gl-button + > + </div> + + <release-skeleton-loader v-if="shouldRenderLoadingIndicator" /> + + <releases-empty-state v-else-if="shouldRenderEmptyState" /> + + <div v-else-if="shouldRenderSuccessState"> + <release-block + v-for="(release, index) in releases" + :key="index" + :release="release" + :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" + /> + </div> + </div> +</template> +<style> +.linked-card::after { + width: 1px; + content: ' '; + border: 1px solid #e5e5e5; + height: 17px; + top: 100%; + position: absolute; + left: 32px; +} +</style> diff --git a/app/assets/javascripts/releases/components/releases_empty_state.vue b/app/assets/javascripts/releases/components/releases_empty_state.vue new file mode 100644 index 00000000000..800497c186a --- /dev/null +++ b/app/assets/javascripts/releases/components/releases_empty_state.vue @@ -0,0 +1,44 @@ +<script> +import { GlEmptyState, GlLink } from '@gitlab/ui'; +import { __ } from '~/locale'; + +export default { + name: 'ReleasesEmptyState', + components: { + GlEmptyState, + GlLink, + }, + inject: { + documentationPath: { + default: '', + }, + illustrationPath: { + default: '', + }, + }, + i18n: { + emptyStateTitle: __('Getting started with releases'), + emptyStateText: __( + "Releases are based on Git tags and mark specific points in a project's development history. They can contain information about the type of changes and can also deliver binaries, like compiled versions of your software.", + ), + releasesDocumentation: __('Releases documentation'), + moreInformation: __('More information'), + }, +}; +</script> +<template> + <gl-empty-state :title="$options.i18n.emptyStateTitle" :svg-path="illustrationPath"> + <template #description> + <span id="releases-description"> + {{ $options.i18n.emptyStateText }} + <gl-link + :href="documentationPath" + :aria-label="$options.i18n.releasesDocumentation" + target="_blank" + > + {{ $options.i18n.moreInformation }} + </gl-link> + </span> + </template> + </gl-empty-state> +</template> diff --git a/app/assets/javascripts/releases/mount_index.js b/app/assets/javascripts/releases/mount_index.js index bb21ec7c43f..57f9f968423 100644 --- a/app/assets/javascripts/releases/mount_index.js +++ b/app/assets/javascripts/releases/mount_index.js @@ -1,14 +1,32 @@ import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import Vuex from 'vuex'; +import createDefaultClient from '~/lib/graphql'; import ReleaseIndexApp from './components/app_index.vue'; +import ReleaseIndexApollopClientApp from './components/app_index_apollo_client.vue'; import createStore from './stores'; import createIndexModule from './stores/modules/index'; -Vue.use(Vuex); - export default () => { const el = document.getElementById('js-releases-page'); + if (window.gon?.features?.releasesIndexApolloClient) { + Vue.use(VueApollo); + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + return new Vue({ + el, + apolloProvider, + provide: { ...el.dataset }, + render: (h) => h(ReleaseIndexApollopClientApp), + }); + } + + Vue.use(Vuex); + return new Vue({ el, store: createStore({ |