217 lines
5.3 KiB
Vue
217 lines
5.3 KiB
Vue
<template>
|
|
<div>
|
|
<CardWithDetails
|
|
title="Deploys"
|
|
:subtitle="
|
|
candidates.length ? 'Deploys on your bench' : 'No deploys on your bench'
|
|
"
|
|
:show-details="selectedCandidate"
|
|
>
|
|
<div>
|
|
<router-link
|
|
v-for="candidate in candidates"
|
|
class="block cursor-pointer rounded-md px-2.5"
|
|
:class="
|
|
selectedCandidate && selectedCandidate.name === candidate.name
|
|
? 'bg-gray-100'
|
|
: 'hover:bg-gray-50'
|
|
"
|
|
:key="candidate.name"
|
|
:to="`/groups/${benchName}/deploys/${candidate.name}`"
|
|
>
|
|
<ListItem
|
|
:title="`Deploy on ${formatDate(
|
|
candidate.creation,
|
|
'DATETIME_SHORT'
|
|
)}`"
|
|
:subtitle="itemSubtitle(candidate)"
|
|
>
|
|
<template #actions>
|
|
<Badge
|
|
v-if="candidate.status != 'Success'"
|
|
:label="candidate.status"
|
|
>
|
|
</Badge>
|
|
</template>
|
|
</ListItem>
|
|
<div class="border-b"></div>
|
|
</router-link>
|
|
<div class="py-3" v-if="$resources.candidates.hasNextPage">
|
|
<Button
|
|
:loading="$resources.candidates.list.loading"
|
|
loadingText="Loading..."
|
|
@click="$resources.candidates.next()"
|
|
>
|
|
Load more
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<template #details>
|
|
<StepsDetail
|
|
:showDetails="selectedCandidate"
|
|
:loading="$resources.selectedCandidate.loading"
|
|
:steps="getSteps(selectedCandidate)"
|
|
title="Build Log"
|
|
:subtitle="subtitle"
|
|
/>
|
|
</template>
|
|
</CardWithDetails>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { h } from 'vue';
|
|
import StepsDetail from '@/views/general/StepsDetail.vue';
|
|
import CardWithDetails from '@/components/CardWithDetails.vue';
|
|
|
|
export default {
|
|
name: 'BenchDeploys',
|
|
props: ['bench', 'benchName', 'candidateName'],
|
|
components: {
|
|
CardWithDetails,
|
|
StepsDetail
|
|
},
|
|
resources: {
|
|
candidates() {
|
|
return {
|
|
type: 'list',
|
|
pagetype: 'Deploy Candidate',
|
|
url: 'jcloud.api.bench.candidates',
|
|
filters: {
|
|
group: this.benchName
|
|
},
|
|
start: 0,
|
|
auto: true,
|
|
pageLength: 10
|
|
};
|
|
},
|
|
selectedCandidate() {
|
|
return {
|
|
url: 'jcloud.api.bench.candidate',
|
|
params: {
|
|
name: this.candidateName
|
|
},
|
|
auto: true
|
|
};
|
|
}
|
|
},
|
|
mounted() {
|
|
if (this.candidateName && this.selectedCandidate?.status != 'Success') {
|
|
this.$socket.on(`bench_deploy:${this.candidateName}:steps`, this.onSteps);
|
|
this.$socket.on(
|
|
`bench_deploy:${this.candidateName}:finished`,
|
|
this.onStopped
|
|
);
|
|
}
|
|
},
|
|
unmounted() {
|
|
this.$socket.off(`bench_deploy:${this.candidateName}:steps`, this.onSteps);
|
|
this.$socket.off(
|
|
`bench_deploy:${this.candidateName}:finished`,
|
|
this.onStopped
|
|
);
|
|
},
|
|
methods: {
|
|
onSteps(data) {
|
|
if (this.$resources.selectedCandidate?.data.name === data.name) {
|
|
this.$resources.selectedCandidate.data.build_steps = data.steps;
|
|
}
|
|
},
|
|
onStopped() {
|
|
this.$resources.candidates.reload();
|
|
this.$resources.selectedCandidate.reload();
|
|
},
|
|
getSteps(candidate) {
|
|
if (!candidate) return [];
|
|
let steps = candidate.build_steps.map(step => {
|
|
let name = step.stage + ' - ' + step.step;
|
|
let output =
|
|
step.command || step.output
|
|
? `${step.command || ''}\n${step.output || ''}`.trim()
|
|
: '';
|
|
let duration = ['Success', 'Failure'].includes(step.status)
|
|
? step.cached
|
|
? 'Cached'
|
|
: `${step.duration} s`
|
|
: null;
|
|
return {
|
|
name,
|
|
output,
|
|
status: step.status,
|
|
duration,
|
|
completed: step.status == 'Success',
|
|
running: step.status == 'Running'
|
|
};
|
|
});
|
|
|
|
let bench = this.bench;
|
|
let jobs = candidate.jobs.map(job => {
|
|
return {
|
|
name: `Deploy ${job.bench}`,
|
|
output:
|
|
job.status == 'Success'
|
|
? `Deploy completed in ${job.duration.split('.')[0]}`
|
|
: null,
|
|
status: job.status,
|
|
completed: job.status == 'Success',
|
|
running: ['Pending', 'Running'].includes(job.status),
|
|
action: {
|
|
render() {
|
|
return h(
|
|
'Link',
|
|
{
|
|
props: { to: `/groups/${bench?.name}/jobs/${job.name}` },
|
|
class: 'text-sm'
|
|
},
|
|
'Job Log →'
|
|
);
|
|
}
|
|
}
|
|
};
|
|
});
|
|
return [...steps, ...jobs];
|
|
},
|
|
itemSubtitle(candidate) {
|
|
return ['jingrow', ...candidate.apps.filter(d => d !== 'jingrow')].join(
|
|
', '
|
|
);
|
|
}
|
|
},
|
|
computed: {
|
|
selectedCandidate() {
|
|
return this.$resources.selectedCandidate.data;
|
|
},
|
|
subtitle() {
|
|
if (
|
|
this.selectedCandidate &&
|
|
this.selectedCandidate.status == 'Success'
|
|
) {
|
|
let when = this.formatDate(
|
|
this.selectedCandidate.build_end,
|
|
'relative'
|
|
);
|
|
let duration = this.$formatDuration(
|
|
this.selectedCandidate.build_duration
|
|
);
|
|
return `Completed ${when} in ${duration}`;
|
|
} else if (this.selectedCandidate?.status === 'Running') {
|
|
const when = this.formatDate(
|
|
this.selectedCandidate.build_start,
|
|
'relative'
|
|
);
|
|
return `Started ${when}`;
|
|
} else if (this.selectedCandidate?.status === 'Failure') {
|
|
const when = this.formatDate(
|
|
this.selectedCandidate.build_end,
|
|
'relative'
|
|
);
|
|
return `Failed ${when}`;
|
|
}
|
|
},
|
|
candidates() {
|
|
return this.$resources.candidates.data || [];
|
|
}
|
|
}
|
|
};
|
|
</script>
|