Commit 76ffde63 authored by Phil Hughes's avatar Phil Hughes

style improvements

fixed multiple requests causing state to be emptied at wrong time
parent 5e79276b
<script>
import Stage from './stage.vue';
export default {
components: {
Stage,
},
props: {
stages: {
type: Array,
required: true,
},
},
};
</script>
<template>
<div style="overflow: auto;">
<stage
v-for="stage in stages"
:key="stage.id"
:stage="stage"
/>
</div>
</template>
<script>
import { mapActions } from 'vuex';
import Icon from '../../../vue_shared/components/icon.vue';
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
import LoadingIcon from '../../../vue_shared/components/loading_icon.vue';
export default {
components: {
Icon,
CiIcon,
LoadingIcon,
},
props: {
stage: {
type: Object,
required: true,
},
},
computed: {
collapseIcon() {
return this.stage.isCollapsed ? 'angle-left' : 'angle-down';
},
},
created() {
this.fetchJobs(this.stage);
},
methods: {
...mapActions('pipelines', ['fetchJobs']),
},
};
</script>
<template>
<div
class="panel panel-default prepend-top-default"
>
<div
class="panel-heading"
@click="() => stage.isCollapsed = !stage.isCollapsed"
>
<ci-icon
:status="stage.status"
/>
<span class="prepend-left-8">
{{ stage.title }}
</span>
<div>
<span class="badge">
{{ stage.jobs.length }}
</span>
</div>
<icon
:name="collapseIcon"
css-classes="pull-right"
/>
</div>
<div
class="panel-body"
v-show="!stage.isCollapsed"
>
<loading-icon
v-if="stage.isLoading && !stage.jobs.length"
/>
<template v-else>
<div
v-for="job in stage.jobs"
:key="job.id"
>
<ci-icon :status="job.status" />
{{ job.name }}
<a
:href="job.build_path"
target="_blank"
>#{{ job.id }}</a>
</div>
</template>
</div>
</div>
</template>
<style scoped>
.panel-heading {
display: flex;
cursor: pointer;
}
.panel-heading .ci-status-icon {
display: flex;
align-items: center;
}
.panel-heading .pull-right {
margin: auto 0 auto auto;
}
</style>
...@@ -31,19 +31,20 @@ export default { ...@@ -31,19 +31,20 @@ export default {
class="multi-file-commit-panel-inner" class="multi-file-commit-panel-inner"
v-if="rightPane" v-if="rightPane"
> >
<keep-alive>
<component :is="rightPane" /> <component :is="rightPane" />
</keep-alive>
</div> </div>
<nav class="ide-activity-bar"> <nav class="ide-activity-bar">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li v-once> <li>
<button <button
v-tooltip v-tooltip
data-container="body" data-container="body"
data-placement="left" data-placement="left"
:title="__('Pipelines')" :title="__('Pipelines')"
class="ide-sidebar-link" class="ide-sidebar-link is-right"
:class="{
active: rightPane === $options.rightSidebarViews.pipelines
}"
type="button" type="button"
@click="setRightPane($options.rightSidebarViews.pipelines)" @click="setRightPane($options.rightSidebarViews.pipelines)"
> >
......
<script> <script>
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '../../../vue_shared/components/icon.vue';
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
import Tabs from '../../../vue_shared/components/tabs/tabs'; import Tabs from '../../../vue_shared/components/tabs/tabs';
import Tab from '../../../vue_shared/components/tabs/tab.vue'; import Tab from '../../../vue_shared/components/tabs/tab.vue';
import JobsList from '../jobs/list.vue';
export default { export default {
components: { components: {
Tabs, Tabs,
Tab, Tab,
Icon, JobsList,
CiIcon,
}, },
computed: { computed: {
...mapGetters('pipelines', ['jobsCount', 'failedJobsCount']), ...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages']),
...mapState('pipelines', ['stages']), ...mapState('pipelines', ['stages']),
}, },
mounted() { created() {
this.fetchStages(); this.fetchStages();
}, },
methods: { methods: {
...@@ -32,46 +30,17 @@ export default { ...@@ -32,46 +30,17 @@ export default {
<template slot="title"> <template slot="title">
Jobs <span class="badge">{{ jobsCount }}</span> Jobs <span class="badge">{{ jobsCount }}</span>
</template> </template>
<div style="overflow: auto;"> <jobs-list
<div :stages="stages"
v-for="stage in stages"
:key="stage.id"
class="panel panel-default"
>
<div
class="panel-heading"
@click="() => stage.isCollapsed = !stage.isCollapsed"
>
<ci-icon :status="stage.status" />
{{ stage.title }}
<span class="badge">
{{ stage.jobs.length }}
</span>
<icon
:name="stage.isCollapsed ? 'angle-left' : 'angle-down'"
css-classes="pull-right"
/> />
</div>
<div
class="panel-body"
v-show="!stage.isCollapsed"
>
<div
v-for="job in stage.jobs"
:key="job.id"
>
<ci-icon :status="job.status" />
{{ job.name }} #{{ job.id }}
</div>
</div>
</div>
</div>
</tab> </tab>
<tab> <tab>
<template slot="title"> <template slot="title">
Failed Jobs <span class="badge">{{ failedJobsCount }}</span> Failed Jobs <span class="badge">{{ failedJobsCount }}</span>
</template> </template>
List all failed jobs here <jobs-list
:stages="failedStages"
/>
</tab> </tab>
</tabs> </tabs>
</div> </div>
......
...@@ -20,7 +20,7 @@ export default { ...@@ -20,7 +20,7 @@ export default {
}; };
}, },
}, },
mounted() { created() {
this.fetchLatestPipeline(); this.fetchLatestPipeline();
}, },
methods: { methods: {
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
<template> <template>
<div> <div>
<loading-icon <loading-icon
v-if="isLoadingPipeline" v-if="isLoadingPipeline && !latestPipeline"
class="prepend-top-default" class="prepend-top-default"
size="2" size="2"
/> />
......
...@@ -35,7 +35,6 @@ export const fetchStages = ({ dispatch, state, rootState }) => { ...@@ -35,7 +35,6 @@ export const fetchStages = ({ dispatch, state, rootState }) => {
Api.pipelineJobs(rootState.currentProjectId, state.latestPipeline.id) Api.pipelineJobs(rootState.currentProjectId, state.latestPipeline.id)
.then(({ data }) => dispatch('receiveStagesSuccess', data)) .then(({ data }) => dispatch('receiveStagesSuccess', data))
.then(() => state.stages.forEach(stage => dispatch('fetchJobs', stage)))
.catch(() => dispatch('receiveStagesError')); .catch(() => dispatch('receiveStagesError'));
}; };
......
export const hasLatestPipeline = state => !state.isLoadingPipeline && !!state.latestPipeline; export const hasLatestPipeline = state => !state.isLoadingPipeline && !!state.latestPipeline;
export const failedStages = state => state.stages.filter(stage => stage.status.label === 'failed');
export const failedJobsCount = state => export const failedJobsCount = state =>
state.stages.reduce( state.stages.reduce(
(acc, stage) => acc + stage.jobs.filter(j => j.status.label === 'failed').length, (acc, stage) => acc + stage.jobs.filter(j => j.status.label === 'failed').length,
......
...@@ -27,13 +27,16 @@ export default { ...@@ -27,13 +27,16 @@ export default {
[types.RECEIVE_STAGES_SUCCESS](state, stages) { [types.RECEIVE_STAGES_SUCCESS](state, stages) {
state.isLoadingJobs = false; state.isLoadingJobs = false;
state.stages = stages.map((stage, i) => ({ state.stages = stages.map((stage, i) => {
const foundStage = state.stages.find(s => s.id === i);
return {
...stage, ...stage,
id: i, id: i,
isCollapsed: false, isCollapsed: foundStage ? foundStage.isCollapsed : false,
isLoading: false, isLoading: foundStage ? foundStage.isLoading : false,
jobs: [], jobs: foundStage ? foundStage.jobs : [],
})); };
});
}, },
[types.REQUEST_JOBS](state, id) { [types.REQUEST_JOBS](state, id) {
state.stages = state.stages.reduce( state.stages = state.stages.reduce(
......
...@@ -32,7 +32,9 @@ export default { ...@@ -32,7 +32,9 @@ export default {
h( h(
'a', 'a',
{ {
attrs: {
href: '#', href: '#',
},
on: { on: {
click: () => this.setTab(i), click: () => this.setTab(i),
}, },
......
...@@ -189,6 +189,10 @@ ...@@ -189,6 +189,10 @@
&.active { &.active {
color: $color-700; color: $color-700;
box-shadow: inset 3px 0 $color-700; box-shadow: inset 3px 0 $color-700;
&.is-right {
box-shadow: inset -3px 0 $color-700;
}
} }
} }
} }
......
...@@ -903,6 +903,13 @@ ...@@ -903,6 +903,13 @@
width: 1px; width: 1px;
background: $white-light; background: $white-light;
} }
&.is-right {
&::after {
right: auto;
left: -1px;
}
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment