Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-20 21:10:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-20 21:10:33 +0300
commit1cb90c3b4f04d42fa30f7903b10b32721c5fadac (patch)
tree7fcc5031b249c936a73dfbd4fe2594b1e0a2943d /app/assets/javascripts
parente45c8a7e74d4c1a1f7e12504df3611f797620166 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js9
-rw-r--r--app/assets/javascripts/diffs/components/app.vue1
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue3
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue5
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue40
-rw-r--r--app/assets/javascripts/diffs/components/diff_view.vue6
-rw-r--r--app/assets/javascripts/diffs/store/getters.js5
-rw-r--r--app/assets/javascripts/diffs/store/modules/index.js2
-rw-r--r--app/assets/javascripts/releases/components/app_index_apollo_client.vue155
-rw-r--r--app/assets/javascripts/releases/components/releases_empty_state.vue44
-rw-r--r--app/assets/javascripts/releases/mount_index.js22
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({