Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5ee120f467
commit
cefe554b7c
30 changed files with 136 additions and 132 deletions
|
@ -3,7 +3,7 @@ import $ from 'jquery';
|
||||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||||
import Icon from '~/vue_shared/components/icon.vue';
|
import Icon from '~/vue_shared/components/icon.vue';
|
||||||
import tooltip from '~/vue_shared/directives/tooltip';
|
import tooltip from '~/vue_shared/directives/tooltip';
|
||||||
import { activityBarViews } from '../constants';
|
import { leftSidebarViews } from '../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -26,7 +26,7 @@ export default {
|
||||||
$(e.currentTarget).tooltip('hide');
|
$(e.currentTarget).tooltip('hide');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
activityBarViews,
|
leftSidebarViews,
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export default {
|
||||||
<button
|
<button
|
||||||
v-tooltip
|
v-tooltip
|
||||||
:class="{
|
:class="{
|
||||||
active: currentActivityView === $options.activityBarViews.edit,
|
active: currentActivityView === $options.leftSidebarViews.edit.name,
|
||||||
}"
|
}"
|
||||||
:title="s__('IDE|Edit')"
|
:title="s__('IDE|Edit')"
|
||||||
:aria-label="s__('IDE|Edit')"
|
:aria-label="s__('IDE|Edit')"
|
||||||
|
@ -45,7 +45,7 @@ export default {
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
type="button"
|
type="button"
|
||||||
class="ide-sidebar-link js-ide-edit-mode"
|
class="ide-sidebar-link js-ide-edit-mode"
|
||||||
@click.prevent="changedActivityView($event, $options.activityBarViews.edit)"
|
@click.prevent="changedActivityView($event, $options.leftSidebarViews.edit.name)"
|
||||||
>
|
>
|
||||||
<icon name="code" />
|
<icon name="code" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -54,7 +54,7 @@ export default {
|
||||||
<button
|
<button
|
||||||
v-tooltip
|
v-tooltip
|
||||||
:class="{
|
:class="{
|
||||||
active: currentActivityView === $options.activityBarViews.review,
|
active: currentActivityView === $options.leftSidebarViews.review.name,
|
||||||
}"
|
}"
|
||||||
:title="s__('IDE|Review')"
|
:title="s__('IDE|Review')"
|
||||||
:aria-label="s__('IDE|Review')"
|
:aria-label="s__('IDE|Review')"
|
||||||
|
@ -62,7 +62,7 @@ export default {
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
type="button"
|
type="button"
|
||||||
class="ide-sidebar-link js-ide-review-mode"
|
class="ide-sidebar-link js-ide-review-mode"
|
||||||
@click.prevent="changedActivityView($event, $options.activityBarViews.review)"
|
@click.prevent="changedActivityView($event, $options.leftSidebarViews.review.name)"
|
||||||
>
|
>
|
||||||
<icon name="file-modified" />
|
<icon name="file-modified" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -71,7 +71,7 @@ export default {
|
||||||
<button
|
<button
|
||||||
v-tooltip
|
v-tooltip
|
||||||
:class="{
|
:class="{
|
||||||
active: currentActivityView === $options.activityBarViews.commit,
|
active: currentActivityView === $options.leftSidebarViews.commit.name,
|
||||||
}"
|
}"
|
||||||
:title="s__('IDE|Commit')"
|
:title="s__('IDE|Commit')"
|
||||||
:aria-label="s__('IDE|Commit')"
|
:aria-label="s__('IDE|Commit')"
|
||||||
|
@ -79,7 +79,7 @@ export default {
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
type="button"
|
type="button"
|
||||||
class="ide-sidebar-link js-ide-commit-mode qa-commit-mode-tab"
|
class="ide-sidebar-link js-ide-commit-mode qa-commit-mode-tab"
|
||||||
@click.prevent="changedActivityView($event, $options.activityBarViews.commit)"
|
@click.prevent="changedActivityView($event, $options.leftSidebarViews.commit.name)"
|
||||||
>
|
>
|
||||||
<icon name="commit" />
|
<icon name="commit" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import LoadingButton from '~/vue_shared/components/loading_button.vue';
|
||||||
import CommitMessageField from './message_field.vue';
|
import CommitMessageField from './message_field.vue';
|
||||||
import Actions from './actions.vue';
|
import Actions from './actions.vue';
|
||||||
import SuccessMessage from './success_message.vue';
|
import SuccessMessage from './success_message.vue';
|
||||||
import { activityBarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants';
|
import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -41,7 +41,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
currentViewIsCommitView() {
|
currentViewIsCommitView() {
|
||||||
return this.currentActivityView === activityBarViews.commit;
|
return this.currentActivityView === leftSidebarViews.commit.name;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -57,7 +57,7 @@ export default {
|
||||||
|
|
||||||
lastCommitMsg() {
|
lastCommitMsg() {
|
||||||
this.isCompact =
|
this.isCompact =
|
||||||
this.currentActivityView !== activityBarViews.commit && this.lastCommitMsg === '';
|
this.currentActivityView !== leftSidebarViews.commit.name && this.lastCommitMsg === '';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -67,7 +67,7 @@ export default {
|
||||||
if (this.currentViewIsCommitView) {
|
if (this.currentViewIsCommitView) {
|
||||||
this.isCompact = !this.isCompact;
|
this.isCompact = !this.isCompact;
|
||||||
} else {
|
} else {
|
||||||
this.updateActivityBarView(activityBarViews.commit)
|
this.updateActivityBarView(leftSidebarViews.commit.name)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.isCompact = false;
|
this.isCompact = false;
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,19 +4,19 @@ import { GlSkeletonLoading } from '@gitlab/ui';
|
||||||
import IdeTree from './ide_tree.vue';
|
import IdeTree from './ide_tree.vue';
|
||||||
import ResizablePanel from './resizable_panel.vue';
|
import ResizablePanel from './resizable_panel.vue';
|
||||||
import ActivityBar from './activity_bar.vue';
|
import ActivityBar from './activity_bar.vue';
|
||||||
import CommitSection from './repo_commit_section.vue';
|
import RepoCommitSection from './repo_commit_section.vue';
|
||||||
import CommitForm from './commit_sidebar/form.vue';
|
import CommitForm from './commit_sidebar/form.vue';
|
||||||
import IdeReview from './ide_review.vue';
|
import IdeReview from './ide_review.vue';
|
||||||
import SuccessMessage from './commit_sidebar/success_message.vue';
|
import SuccessMessage from './commit_sidebar/success_message.vue';
|
||||||
import IdeProjectHeader from './ide_project_header.vue';
|
import IdeProjectHeader from './ide_project_header.vue';
|
||||||
import { activityBarViews } from '../constants';
|
import { leftSidebarViews } from '../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
GlSkeletonLoading,
|
GlSkeletonLoading,
|
||||||
ResizablePanel,
|
ResizablePanel,
|
||||||
ActivityBar,
|
ActivityBar,
|
||||||
CommitSection,
|
RepoCommitSection,
|
||||||
IdeTree,
|
IdeTree,
|
||||||
CommitForm,
|
CommitForm,
|
||||||
IdeReview,
|
IdeReview,
|
||||||
|
@ -28,7 +28,7 @@ export default {
|
||||||
...mapGetters(['currentProject', 'someUncommittedChanges']),
|
...mapGetters(['currentProject', 'someUncommittedChanges']),
|
||||||
showSuccessMessage() {
|
showSuccessMessage() {
|
||||||
return (
|
return (
|
||||||
this.currentActivityView === activityBarViews.edit &&
|
this.currentActivityView === leftSidebarViews.edit.name &&
|
||||||
(this.lastCommitMsg && !this.someUncommittedChanges)
|
(this.lastCommitMsg && !this.someUncommittedChanges)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
|
||||||
import CommitFilesList from './commit_sidebar/list.vue';
|
import CommitFilesList from './commit_sidebar/list.vue';
|
||||||
import EmptyState from './commit_sidebar/empty_state.vue';
|
import EmptyState from './commit_sidebar/empty_state.vue';
|
||||||
import consts from '../stores/modules/commit/constants';
|
import consts from '../stores/modules/commit/constants';
|
||||||
import { activityBarViews, stageKeys } from '../constants';
|
import { leftSidebarViews, stageKeys } from '../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -37,7 +37,7 @@ export default {
|
||||||
watch: {
|
watch: {
|
||||||
hasChanges() {
|
hasChanges() {
|
||||||
if (!this.hasChanges) {
|
if (!this.hasChanges) {
|
||||||
this.updateActivityBarView(activityBarViews.edit);
|
this.updateActivityBarView(leftSidebarViews.edit.name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import flash from '~/flash';
|
||||||
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
|
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
|
||||||
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
|
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
|
||||||
import {
|
import {
|
||||||
activityBarViews,
|
leftSidebarViews,
|
||||||
viewerTypes,
|
viewerTypes,
|
||||||
FILE_VIEW_MODE_EDITOR,
|
FILE_VIEW_MODE_EDITOR,
|
||||||
FILE_VIEW_MODE_PREVIEW,
|
FILE_VIEW_MODE_PREVIEW,
|
||||||
|
@ -100,7 +100,7 @@ export default {
|
||||||
if (oldVal.key !== this.file.key) {
|
if (oldVal.key !== this.file.key) {
|
||||||
this.initEditor();
|
this.initEditor();
|
||||||
|
|
||||||
if (this.currentActivityView !== activityBarViews.edit) {
|
if (this.currentActivityView !== leftSidebarViews.edit.name) {
|
||||||
this.setFileViewMode({
|
this.setFileViewMode({
|
||||||
file: this.file,
|
file: this.file,
|
||||||
viewMode: FILE_VIEW_MODE_EDITOR,
|
viewMode: FILE_VIEW_MODE_EDITOR,
|
||||||
|
@ -109,7 +109,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
currentActivityView() {
|
currentActivityView() {
|
||||||
if (this.currentActivityView !== activityBarViews.edit) {
|
if (this.currentActivityView !== leftSidebarViews.edit.name) {
|
||||||
this.setFileViewMode({
|
this.setFileViewMode({
|
||||||
file: this.file,
|
file: this.file,
|
||||||
viewMode: FILE_VIEW_MODE_EDITOR,
|
viewMode: FILE_VIEW_MODE_EDITOR,
|
||||||
|
|
|
@ -11,12 +11,6 @@ export const FILE_VIEW_MODE_PREVIEW = 'preview';
|
||||||
export const PERMISSION_CREATE_MR = 'createMergeRequestIn';
|
export const PERMISSION_CREATE_MR = 'createMergeRequestIn';
|
||||||
export const PERMISSION_READ_MR = 'readMergeRequest';
|
export const PERMISSION_READ_MR = 'readMergeRequest';
|
||||||
|
|
||||||
export const activityBarViews = {
|
|
||||||
edit: 'ide-tree',
|
|
||||||
commit: 'commit-section',
|
|
||||||
review: 'ide-review',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const viewerTypes = {
|
export const viewerTypes = {
|
||||||
mr: 'mrdiff',
|
mr: 'mrdiff',
|
||||||
edit: 'editor',
|
edit: 'editor',
|
||||||
|
@ -47,6 +41,12 @@ export const diffViewerErrors = Object.freeze({
|
||||||
stored_externally: 'server_side_but_stored_externally',
|
stored_externally: 'server_side_but_stored_externally',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const leftSidebarViews = {
|
||||||
|
edit: { name: 'ide-tree', keepAlive: false },
|
||||||
|
review: { name: 'ide-review', keepAlive: false },
|
||||||
|
commit: { name: 'repo-commit-section', keepAlive: false },
|
||||||
|
};
|
||||||
|
|
||||||
export const rightSidebarViews = {
|
export const rightSidebarViews = {
|
||||||
pipelines: { name: 'pipelines-list', keepAlive: true },
|
pipelines: { name: 'pipelines-list', keepAlive: true },
|
||||||
jobsDetail: { name: 'jobs-detail', keepAlive: false },
|
jobsDetail: { name: 'jobs-detail', keepAlive: false },
|
||||||
|
|
|
@ -2,7 +2,7 @@ import flash from '~/flash';
|
||||||
import { __ } from '~/locale';
|
import { __ } from '~/locale';
|
||||||
import service from '../../services';
|
import service from '../../services';
|
||||||
import * as types from '../mutation_types';
|
import * as types from '../mutation_types';
|
||||||
import { activityBarViews, PERMISSION_READ_MR } from '../../constants';
|
import { leftSidebarViews, PERMISSION_READ_MR } from '../../constants';
|
||||||
|
|
||||||
export const getMergeRequestsForBranch = (
|
export const getMergeRequestsForBranch = (
|
||||||
{ commit, state, getters },
|
{ commit, state, getters },
|
||||||
|
@ -187,7 +187,7 @@ export const openMergeRequest = (
|
||||||
)
|
)
|
||||||
.then(mrChanges => {
|
.then(mrChanges => {
|
||||||
if (mrChanges.changes.length) {
|
if (mrChanges.changes.length) {
|
||||||
dispatch('updateActivityBarView', activityBarViews.review);
|
dispatch('updateActivityBarView', leftSidebarViews.review.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
mrChanges.changes.forEach((change, ind) => {
|
mrChanges.changes.forEach((change, ind) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { getChangesCountForFiles, filePathMatches } from './utils';
|
import { getChangesCountForFiles, filePathMatches } from './utils';
|
||||||
import {
|
import {
|
||||||
activityBarViews,
|
leftSidebarViews,
|
||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
PERMISSION_READ_MR,
|
PERMISSION_READ_MR,
|
||||||
PERMISSION_CREATE_MR,
|
PERMISSION_CREATE_MR,
|
||||||
|
@ -74,9 +74,11 @@ export const getOpenFile = state => path => state.openFiles.find(f => f.path ===
|
||||||
export const lastOpenedFile = state =>
|
export const lastOpenedFile = state =>
|
||||||
[...state.changedFiles, ...state.stagedFiles].sort((a, b) => b.lastOpenedAt - a.lastOpenedAt)[0];
|
[...state.changedFiles, ...state.stagedFiles].sort((a, b) => b.lastOpenedAt - a.lastOpenedAt)[0];
|
||||||
|
|
||||||
export const isEditModeActive = state => state.currentActivityView === activityBarViews.edit;
|
export const isEditModeActive = state => state.currentActivityView === leftSidebarViews.edit.name;
|
||||||
export const isCommitModeActive = state => state.currentActivityView === activityBarViews.commit;
|
export const isCommitModeActive = state =>
|
||||||
export const isReviewModeActive = state => state.currentActivityView === activityBarViews.review;
|
state.currentActivityView === leftSidebarViews.commit.name;
|
||||||
|
export const isReviewModeActive = state =>
|
||||||
|
state.currentActivityView === leftSidebarViews.review.name;
|
||||||
|
|
||||||
export const someUncommittedChanges = state =>
|
export const someUncommittedChanges = state =>
|
||||||
Boolean(state.changedFiles.length || state.stagedFiles.length);
|
Boolean(state.changedFiles.length || state.stagedFiles.length);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import router from '../../../ide_router';
|
||||||
import service from '../../../services';
|
import service from '../../../services';
|
||||||
import * as types from './mutation_types';
|
import * as types from './mutation_types';
|
||||||
import consts from './constants';
|
import consts from './constants';
|
||||||
import { activityBarViews } from '../../../constants';
|
import { leftSidebarViews } from '../../../constants';
|
||||||
import eventHub from '../../../eventhub';
|
import eventHub from '../../../eventhub';
|
||||||
|
|
||||||
export const updateCommitMessage = ({ commit }, message) => {
|
export const updateCommitMessage = ({ commit }, message) => {
|
||||||
|
@ -189,7 +189,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dispatch('updateActivityBarView', activityBarViews.edit, { root: true });
|
dispatch('updateActivityBarView', leftSidebarViews.edit.name, { root: true });
|
||||||
dispatch('updateViewer', 'editor', { root: true });
|
dispatch('updateViewer', 'editor', { root: true });
|
||||||
|
|
||||||
if (rootGetters.activeFile) {
|
if (rootGetters.activeFile) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { activityBarViews } from '../../../constants';
|
import { leftSidebarViews } from '../../../constants';
|
||||||
import { __ } from '~/locale';
|
import { __ } from '~/locale';
|
||||||
|
|
||||||
export const templateTypes = () => [
|
export const templateTypes = () => [
|
||||||
|
@ -22,6 +22,6 @@ export const templateTypes = () => [
|
||||||
|
|
||||||
export const showFileTemplatesBar = (_, getters, rootState) => name =>
|
export const showFileTemplatesBar = (_, getters, rootState) => name =>
|
||||||
getters.templateTypes.find(t => t.name === name) &&
|
getters.templateTypes.find(t => t.name === name) &&
|
||||||
rootState.currentActivityView === activityBarViews.edit;
|
rootState.currentActivityView === leftSidebarViews.edit.name;
|
||||||
|
|
||||||
export default () => {};
|
export default () => {};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { activityBarViews, viewerTypes } from '../constants';
|
import { leftSidebarViews, viewerTypes } from '../constants';
|
||||||
import { DEFAULT_THEME } from '../lib/themes';
|
import { DEFAULT_THEME } from '../lib/themes';
|
||||||
|
|
||||||
export default () => ({
|
export default () => ({
|
||||||
|
@ -21,7 +21,7 @@ export default () => ({
|
||||||
entries: {},
|
entries: {},
|
||||||
viewer: viewerTypes.edit,
|
viewer: viewerTypes.edit,
|
||||||
delayViewerUpdated: false,
|
delayViewerUpdated: false,
|
||||||
currentActivityView: activityBarViews.edit,
|
currentActivityView: leftSidebarViews.edit.name,
|
||||||
unusedSeal: true,
|
unusedSeal: true,
|
||||||
fileFindVisible: false,
|
fileFindVisible: false,
|
||||||
links: {},
|
links: {},
|
||||||
|
|
|
@ -1006,14 +1006,6 @@ pre.light-well {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.with-pipeline-status) {
|
|
||||||
.icon-wrapper:first-of-type {
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
margin-left: $gl-padding-32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ci-status-link {
|
.ci-status-link {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ module Ci
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :eager_load_job_artifacts, -> { includes(:job_artifacts) }
|
scope :eager_load_job_artifacts, -> { includes(:job_artifacts) }
|
||||||
|
scope :eager_load_job_artifacts_archive, -> { includes(:job_artifacts_archive) }
|
||||||
|
|
||||||
scope :eager_load_everything, -> do
|
scope :eager_load_everything, -> do
|
||||||
includes(
|
includes(
|
||||||
|
|
|
@ -8,7 +8,12 @@ class PipelineDetailsEntity < PipelineEntity
|
||||||
end
|
end
|
||||||
|
|
||||||
expose :details do
|
expose :details do
|
||||||
expose :artifacts, using: BuildArtifactEntity
|
expose :artifacts do |pipeline, options|
|
||||||
|
rel = pipeline.artifacts
|
||||||
|
rel = rel.eager_load_job_artifacts_archive if options.fetch(:preload_job_artifacts_archive, true)
|
||||||
|
|
||||||
|
BuildArtifactEntity.represent(rel, options)
|
||||||
|
end
|
||||||
expose :manual_actions, using: BuildActionEntity
|
expose :manual_actions, using: BuildActionEntity
|
||||||
expose :scheduled_actions, using: BuildActionEntity
|
expose :scheduled_actions, using: BuildActionEntity
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,10 @@ class PipelineSerializer < BaseSerializer
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def represent(resource, opts = {})
|
def represent(resource, opts = {})
|
||||||
if resource.is_a?(ActiveRecord::Relation)
|
if resource.is_a?(ActiveRecord::Relation)
|
||||||
|
# We don't want PipelineDetailsEntity to preload the job_artifacts_archive
|
||||||
|
# because we do it with preloaded_relations in a more optimal way
|
||||||
|
# if the given resource is a collection of multiple pipelines.
|
||||||
|
opts[:preload_job_artifacts_archive] = false
|
||||||
resource = resource.preload(preloaded_relations)
|
resource = resource.preload(preloaded_relations)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
= render 'shared/projects/list', projects: @projects, pipeline_status: Feature.enabled?(:dashboard_pipeline_status, default_enabled: true), user: current_user
|
= render 'shared/projects/list', projects: @projects, user: current_user
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
- is_explore_page = defined?(explore_page) && explore_page
|
- is_explore_page = defined?(explore_page) && explore_page
|
||||||
= render 'shared/projects/list', projects: projects, user: current_user, explore_page: is_explore_page, pipeline_status: Feature.enabled?(:dashboard_pipeline_status, default_enabled: true)
|
= render 'shared/projects/list', projects: projects, user: current_user, explore_page: is_explore_page
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description
|
- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description
|
||||||
- cache_key = project_list_cache_key(project, pipeline_status: pipeline_status)
|
- cache_key = project_list_cache_key(project, pipeline_status: pipeline_status)
|
||||||
- updated_tooltip = time_ago_with_tooltip(project.last_activity_date)
|
- updated_tooltip = time_ago_with_tooltip(project.last_activity_date)
|
||||||
- show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project)
|
|
||||||
- css_controls_class = compact_mode ? [] : ["flex-lg-row", "justify-content-lg-between"]
|
- css_controls_class = compact_mode ? [] : ["flex-lg-row", "justify-content-lg-between"]
|
||||||
- css_controls_class << "with-pipeline-status" if show_pipeline_status_icon
|
|
||||||
- avatar_container_class = project.creator && use_creator_avatar ? '' : 'rect-avatar'
|
- avatar_container_class = project.creator && use_creator_avatar ? '' : 'rect-avatar'
|
||||||
|
|
||||||
%li.project-row.d-flex{ class: css_class }
|
%li.project-row.d-flex{ class: css_class }
|
||||||
|
@ -62,11 +60,6 @@
|
||||||
|
|
||||||
.controls.d-flex.flex-sm-column.align-items-center.align-items-sm-end.flex-wrap.flex-shrink-0.text-secondary{ class: css_controls_class.join(" ") }
|
.controls.d-flex.flex-sm-column.align-items-center.align-items-sm-end.flex-wrap.flex-shrink-0.text-secondary{ class: css_controls_class.join(" ") }
|
||||||
.icon-container.d-flex.align-items-center
|
.icon-container.d-flex.align-items-center
|
||||||
- if show_pipeline_status_icon
|
|
||||||
- pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref)
|
|
||||||
%span.icon-wrapper.pipeline-status
|
|
||||||
= render 'ci/status/icon', status: project.last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path
|
|
||||||
|
|
||||||
= render_if_exists 'shared/projects/archived', project: project
|
= render_if_exists 'shared/projects/archived', project: project
|
||||||
- if stars
|
- if stars
|
||||||
= link_to project_starrers_path(project),
|
= link_to project_starrers_path(project),
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Remove CI status from Projects Dashboard
|
||||||
|
merge_request: 25225
|
||||||
|
author: George Thomas @thegeorgeous
|
||||||
|
type: removed
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Fix N+1 queries caused by loading job artifacts archive in pipeline details
|
||||||
|
entity
|
||||||
|
merge_request: 25250
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -171,7 +171,17 @@ describe Projects::PipelinesController do
|
||||||
|
|
||||||
def create_build(pipeline, stage, stage_idx, name, user = nil)
|
def create_build(pipeline, stage, stage_idx, name, user = nil)
|
||||||
status = %w[created running pending success failed canceled].sample
|
status = %w[created running pending success failed canceled].sample
|
||||||
create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status, user: user)
|
create(
|
||||||
|
:ci_build,
|
||||||
|
:artifacts,
|
||||||
|
artifacts_expire_at: 2.days.from_now,
|
||||||
|
pipeline: pipeline,
|
||||||
|
stage: stage,
|
||||||
|
stage_idx: stage_idx,
|
||||||
|
name: name,
|
||||||
|
status: status,
|
||||||
|
user: user
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,8 @@ shared_examples "installing applications on a cluster" do
|
||||||
page.within('.js-cluster-application-row-elastic_stack') do
|
page.within('.js-cluster-application-row-elastic_stack') do
|
||||||
click_button 'Install'
|
click_button 'Install'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows status transition' do
|
it 'shows status transition' do
|
||||||
|
|
|
@ -152,61 +152,6 @@ describe 'Dashboard Projects' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with a pipeline', :clean_gitlab_redis_shared_state do
|
|
||||||
let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
# Since the cache isn't updated when a new pipeline is created
|
|
||||||
# we need the pipeline to advance in the pipeline since the cache was created
|
|
||||||
# by visiting the login page.
|
|
||||||
pipeline.succeed
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'shows that the last pipeline passed' do
|
|
||||||
visit dashboard_projects_path
|
|
||||||
|
|
||||||
page.within('.controls') do
|
|
||||||
expect(page).to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
|
|
||||||
expect(page).to have_css('.ci-status-link')
|
|
||||||
expect(page).to have_css('.ci-status-icon-success')
|
|
||||||
expect(page).to have_link('Pipeline: passed')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
shared_examples 'hidden pipeline status' do
|
|
||||||
it 'does not show the pipeline status' do
|
|
||||||
visit dashboard_projects_path
|
|
||||||
|
|
||||||
page.within('.controls') do
|
|
||||||
expect(page).not_to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
|
|
||||||
expect(page).not_to have_css('.ci-status-link')
|
|
||||||
expect(page).not_to have_css('.ci-status-icon-success')
|
|
||||||
expect(page).not_to have_link('Pipeline: passed')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'guest user of project and project has private pipelines' do
|
|
||||||
let(:guest_user) { create(:user) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
project.update(public_builds: false)
|
|
||||||
project.add_guest(guest_user)
|
|
||||||
sign_in(guest_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'hidden pipeline status'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when dashboard_pipeline_status is disabled' do
|
|
||||||
before do
|
|
||||||
stub_feature_flags(dashboard_pipeline_status: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'hidden pipeline status'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'last push widget', :use_clean_rails_memory_store_caching do
|
context 'last push widget', :use_clean_rails_memory_store_caching do
|
||||||
before do
|
before do
|
||||||
event = create(:push_event, project: project, author: user)
|
event = create(:push_event, project: project, author: user)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import createState from '~/ide/stores/state';
|
import createState from '~/ide/stores/state';
|
||||||
import { activityBarViews } from '~/ide/constants';
|
import { leftSidebarViews } from '~/ide/constants';
|
||||||
import * as getters from '~/ide/stores/modules/file_templates/getters';
|
import * as getters from '~/ide/stores/modules/file_templates/getters';
|
||||||
|
|
||||||
describe('IDE file templates getters', () => {
|
describe('IDE file templates getters', () => {
|
||||||
|
@ -17,7 +17,7 @@ describe('IDE file templates getters', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true if template is found and currentActivityView is edit', () => {
|
it('returns true if template is found and currentActivityView is edit', () => {
|
||||||
rootState.currentActivityView = activityBarViews.edit;
|
rootState.currentActivityView = leftSidebarViews.edit.name;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getters.showFileTemplatesBar(
|
getters.showFileTemplatesBar(
|
||||||
|
@ -31,7 +31,7 @@ describe('IDE file templates getters', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false if template is found and currentActivityView is not edit', () => {
|
it('returns false if template is found and currentActivityView is not edit', () => {
|
||||||
rootState.currentActivityView = activityBarViews.commit;
|
rootState.currentActivityView = leftSidebarViews.commit.name;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getters.showFileTemplatesBar(
|
getters.showFileTemplatesBar(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import store from '~/ide/stores';
|
import store from '~/ide/stores';
|
||||||
import { activityBarViews } from '~/ide/constants';
|
import { leftSidebarViews } from '~/ide/constants';
|
||||||
import ActivityBar from '~/ide/components/activity_bar.vue';
|
import ActivityBar from '~/ide/components/activity_bar.vue';
|
||||||
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
|
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
|
||||||
import { resetStore } from '../helpers';
|
import { resetStore } from '../helpers';
|
||||||
|
@ -34,19 +34,19 @@ describe('IDE activity bar', () => {
|
||||||
it('calls updateActivityBarView with edit value on click', () => {
|
it('calls updateActivityBarView with edit value on click', () => {
|
||||||
vm.$el.querySelector('.js-ide-edit-mode').click();
|
vm.$el.querySelector('.js-ide-edit-mode').click();
|
||||||
|
|
||||||
expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.edit);
|
expect(vm.updateActivityBarView).toHaveBeenCalledWith(leftSidebarViews.edit.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls updateActivityBarView with commit value on click', () => {
|
it('calls updateActivityBarView with commit value on click', () => {
|
||||||
vm.$el.querySelector('.js-ide-commit-mode').click();
|
vm.$el.querySelector('.js-ide-commit-mode').click();
|
||||||
|
|
||||||
expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.commit);
|
expect(vm.updateActivityBarView).toHaveBeenCalledWith(leftSidebarViews.commit.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls updateActivityBarView with review value on click', () => {
|
it('calls updateActivityBarView with review value on click', () => {
|
||||||
vm.$el.querySelector('.js-ide-review-mode').click();
|
vm.$el.querySelector('.js-ide-review-mode').click();
|
||||||
|
|
||||||
expect(vm.updateActivityBarView).toHaveBeenCalledWith(activityBarViews.review);
|
expect(vm.updateActivityBarView).toHaveBeenCalledWith(leftSidebarViews.review.name);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ describe('IDE activity bar', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets commit item active', done => {
|
it('sets commit item active', done => {
|
||||||
vm.$store.state.currentActivityView = activityBarViews.commit;
|
vm.$store.state.currentActivityView = leftSidebarViews.commit.name;
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(vm.$el.querySelector('.js-ide-commit-mode').classList).toContain('active');
|
expect(vm.$el.querySelector('.js-ide-commit-mode').classList).toContain('active');
|
||||||
|
|
|
@ -4,7 +4,7 @@ import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
|
||||||
import { projectData } from 'spec/ide/mock_data';
|
import { projectData } from 'spec/ide/mock_data';
|
||||||
import store from '~/ide/stores';
|
import store from '~/ide/stores';
|
||||||
import CommitForm from '~/ide/components/commit_sidebar/form.vue';
|
import CommitForm from '~/ide/components/commit_sidebar/form.vue';
|
||||||
import { activityBarViews } from '~/ide/constants';
|
import { leftSidebarViews } from '~/ide/constants';
|
||||||
import { resetStore } from '../../helpers';
|
import { resetStore } from '../../helpers';
|
||||||
|
|
||||||
describe('IDE commit form', () => {
|
describe('IDE commit form', () => {
|
||||||
|
@ -71,7 +71,7 @@ describe('IDE commit form', () => {
|
||||||
vm.$el.querySelector('.btn-primary').click();
|
vm.$el.querySelector('.btn-primary').click();
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(store.state.currentActivityView).toBe(activityBarViews.commit);
|
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -79,7 +79,7 @@ describe('IDE commit form', () => {
|
||||||
|
|
||||||
it('collapses if lastCommitMsg is set to empty and current view is not commit view', done => {
|
it('collapses if lastCommitMsg is set to empty and current view is not commit view', done => {
|
||||||
store.state.lastCommitMsg = 'abc';
|
store.state.lastCommitMsg = 'abc';
|
||||||
store.state.currentActivityView = activityBarViews.edit;
|
store.state.currentActivityView = leftSidebarViews.edit.name;
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
// if commit message is set, form is uncollapsed
|
// if commit message is set, form is uncollapsed
|
||||||
|
@ -133,7 +133,7 @@ describe('IDE commit form', () => {
|
||||||
vm.$el.querySelector('.btn-primary').click();
|
vm.$el.querySelector('.btn-primary').click();
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(store.state.currentActivityView).toBe(activityBarViews.commit);
|
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
|
||||||
expect(vm.isCompact).toBe(false);
|
expect(vm.isCompact).toBe(false);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Vue from 'vue';
|
||||||
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||||
import store from '~/ide/stores';
|
import store from '~/ide/stores';
|
||||||
import ideSidebar from '~/ide/components/ide_side_bar.vue';
|
import ideSidebar from '~/ide/components/ide_side_bar.vue';
|
||||||
import { activityBarViews } from '~/ide/constants';
|
import { leftSidebarViews } from '~/ide/constants';
|
||||||
import { resetStore } from '../helpers';
|
import { resetStore } from '../helpers';
|
||||||
import { projectData } from '../mock_data';
|
import { projectData } from '../mock_data';
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ describe('IdeSidebar', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders commit component', done => {
|
it('renders commit component', done => {
|
||||||
vm.$store.state.currentActivityView = activityBarViews.commit;
|
vm.$store.state.currentActivityView = leftSidebarViews.commit.name;
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(vm.$el.querySelector('.multi-file-commit-panel-section')).not.toBeNull();
|
expect(vm.$el.querySelector('.multi-file-commit-panel-section')).not.toBeNull();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import axios from '~/lib/utils/axios_utils';
|
||||||
import store from '~/ide/stores';
|
import store from '~/ide/stores';
|
||||||
import repoEditor from '~/ide/components/repo_editor.vue';
|
import repoEditor from '~/ide/components/repo_editor.vue';
|
||||||
import Editor from '~/ide/lib/editor';
|
import Editor from '~/ide/lib/editor';
|
||||||
import { activityBarViews, FILE_VIEW_MODE_EDITOR, FILE_VIEW_MODE_PREVIEW } from '~/ide/constants';
|
import { leftSidebarViews, FILE_VIEW_MODE_EDITOR, FILE_VIEW_MODE_PREVIEW } from '~/ide/constants';
|
||||||
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
|
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
|
||||||
import setTimeoutPromise from '../../helpers/set_timeout_promise_helper';
|
import setTimeoutPromise from '../../helpers/set_timeout_promise_helper';
|
||||||
import { file, resetStore } from '../helpers';
|
import { file, resetStore } from '../helpers';
|
||||||
|
@ -359,7 +359,7 @@ describe('RepoEditor', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides tabs in review mode', done => {
|
it('hides tabs in review mode', done => {
|
||||||
vm.$store.state.currentActivityView = activityBarViews.review;
|
vm.$store.state.currentActivityView = leftSidebarViews.review.name;
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(vm.$el.querySelector('.nav-links')).toBe(null);
|
expect(vm.$el.querySelector('.nav-links')).toBe(null);
|
||||||
|
@ -369,7 +369,7 @@ describe('RepoEditor', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides tabs in commit mode', done => {
|
it('hides tabs in commit mode', done => {
|
||||||
vm.$store.state.currentActivityView = activityBarViews.commit;
|
vm.$store.state.currentActivityView = leftSidebarViews.commit.name;
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(vm.$el.querySelector('.nav-links')).toBe(null);
|
expect(vm.$el.querySelector('.nav-links')).toBe(null);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import actions, {
|
||||||
openMergeRequest,
|
openMergeRequest,
|
||||||
} from '~/ide/stores/actions/merge_request';
|
} from '~/ide/stores/actions/merge_request';
|
||||||
import service from '~/ide/services';
|
import service from '~/ide/services';
|
||||||
import { activityBarViews, PERMISSION_READ_MR } from '~/ide/constants';
|
import { leftSidebarViews, PERMISSION_READ_MR } from '~/ide/constants';
|
||||||
import { resetStore } from '../../helpers';
|
import { resetStore } from '../../helpers';
|
||||||
|
|
||||||
const TEST_PROJECT = 'abcproject';
|
const TEST_PROJECT = 'abcproject';
|
||||||
|
@ -470,7 +470,7 @@ describe('IDE store merge request actions', () => {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(
|
expect(store.dispatch).toHaveBeenCalledWith(
|
||||||
'updateActivityBarView',
|
'updateActivityBarView',
|
||||||
activityBarViews.review,
|
leftSidebarViews.review.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
testMergeRequestChanges.changes.forEach((change, i) => {
|
testMergeRequestChanges.changes.forEach((change, i) => {
|
||||||
|
|
|
@ -173,5 +173,44 @@ describe PipelineDetailsEntity do
|
||||||
expect(subject[:triggered].first[:project]).not_to be_nil
|
expect(subject[:triggered].first[:project]).not_to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when pipeline has expiring archive artifacts' do
|
||||||
|
let(:pipeline) { create(:ci_empty_pipeline) }
|
||||||
|
let!(:build_1) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_1') }
|
||||||
|
let!(:build_2) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_2') }
|
||||||
|
let!(:build_3) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_3') }
|
||||||
|
|
||||||
|
let(:names) { subject[:details][:artifacts].map { |a| a[:name] } }
|
||||||
|
|
||||||
|
context 'and preload_job_artifacts_archive is not defined in the options' do
|
||||||
|
it 'defaults to true and eager loads the job_artifacts_archive' do
|
||||||
|
recorder = ActiveRecord::QueryRecorder.new do
|
||||||
|
expect(names).to match_array(%w[build_1 build_2 build_3])
|
||||||
|
end
|
||||||
|
|
||||||
|
expected_queries = Gitlab.ee? ? 42 : 29
|
||||||
|
|
||||||
|
# This makes only one query to fetch all job artifacts
|
||||||
|
expect(recorder.count).to eq(expected_queries)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and preload_job_artifacts_archive is set to false' do
|
||||||
|
let(:entity) do
|
||||||
|
described_class.represent(pipeline, request: request, preload_job_artifacts_archive: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not eager load the job_artifacts_archive' do
|
||||||
|
recorder = ActiveRecord::QueryRecorder.new do
|
||||||
|
expect(names).to match_array(%w[build_1 build_2 build_3])
|
||||||
|
end
|
||||||
|
|
||||||
|
expected_queries = Gitlab.ee? ? 44 : 31
|
||||||
|
|
||||||
|
# This makes one query for each job artifact
|
||||||
|
expect(recorder.count).to eq(expected_queries)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue