mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 20:01:02 +00:00
UI improvements (#1640)
This commit is contained in:
parent
277a839157
commit
25e2c8055c
8 changed files with 199 additions and 252 deletions
|
@ -58,7 +58,7 @@ import { inject } from '~/compositions/useInjectProvide';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
pipelineNumber: number;
|
pipelineNumber: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<header class="bg-white dark:bg-dark-gray-900 border-b dark:border-gray-700 text-color">
|
<header class="bg-white dark:bg-dark-gray-900 border-b dark:border-gray-700 text-color">
|
||||||
<FluidContainer class="!py-0">
|
<FluidContainer class="!py-0">
|
||||||
<div class="flex flex-wrap items-center justify-between py-4 <md:flex-row <md:gap-y-4">
|
<div class="flex w-full items-center justify-between py-4 <md:flex-row <md:gap-y-4">
|
||||||
<div
|
<div
|
||||||
class="flex flex-wrap items-center justify-start <md:w-full <md:justify-center"
|
class="flex items-center min-w-0 justify-start <md:justify-center"
|
||||||
:class="{
|
:class="{
|
||||||
'md:flex-1': searchBoxPresent,
|
'md:flex-1': searchBoxPresent,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<IconButton v-if="goBack" icon="back" :title="$t('back')" class="mr-2 <md:hidden" @click="goBack" />
|
<IconButton
|
||||||
<h1 class="flex flex-wrap text-xl text-color items-center gap-x-2">
|
v-if="goBack"
|
||||||
|
icon="back"
|
||||||
|
:title="$t('back')"
|
||||||
|
class="flex-shrink-0 mr-2 <md:hidden"
|
||||||
|
@click="goBack"
|
||||||
|
/>
|
||||||
|
<h1 class="flex text-xl min-w-0 text-color items-center gap-x-2">
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +28,7 @@
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="$slots.titleActions"
|
v-if="$slots.titleActions"
|
||||||
class="flex flex-wrap items-center justify-end gap-x-2 <md:w-full <md:justify-center"
|
class="flex items-center justify-end gap-x-2 <md:w-full <md:justify-center"
|
||||||
:class="{
|
:class="{
|
||||||
'md:flex-1': searchBoxPresent,
|
'md:flex-1': searchBoxPresent,
|
||||||
}"
|
}"
|
||||||
|
@ -31,7 +37,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="enableTabs" class="flex flex-wrap justify-between">
|
<div v-if="enableTabs" class="flex justify-between">
|
||||||
<Tabs class="<md:order-2" />
|
<Tabs class="<md:order-2" />
|
||||||
<div
|
<div
|
||||||
v-if="$slots.titleActions"
|
v-if="$slots.titleActions"
|
||||||
|
@ -50,13 +56,11 @@ import FluidContainer from '~/components/layout/FluidContainer.vue';
|
||||||
|
|
||||||
import Tabs from './Tabs.vue';
|
import Tabs from './Tabs.vue';
|
||||||
|
|
||||||
export interface Props {
|
const props = defineProps<{
|
||||||
goBack?: () => void;
|
goBack?: () => void;
|
||||||
enableTabs?: boolean;
|
enableTabs?: boolean;
|
||||||
search?: string;
|
search?: string;
|
||||||
}
|
}>();
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
defineEmits(['update:search']);
|
defineEmits(['update:search']);
|
||||||
|
|
||||||
const searchBoxPresent = props.search !== undefined;
|
const searchBoxPresent = props.search !== undefined;
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
/>
|
/>
|
||||||
<PipelineStatusIcon :status="workflow.state" class="!h-4 !w-4" />
|
<PipelineStatusIcon :status="workflow.state" class="!h-4 !w-4" />
|
||||||
<span class="truncate">{{ workflow.name }}</span>
|
<span class="truncate">{{ workflow.name }}</span>
|
||||||
|
<PipelineStepDuration
|
||||||
|
v-if="workflow.start_time !== workflow.end_time"
|
||||||
|
:step="workflow"
|
||||||
|
class="mr-1 pr-2px"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default class WoodpeckerClient extends ApiClient {
|
||||||
|
|
||||||
// Deploy triggers a deployment for an existing pipeline using the
|
// Deploy triggers a deployment for an existing pipeline using the
|
||||||
// specified target environment.
|
// specified target environment.
|
||||||
deployPipeline(owner: string, repo: string, pipelineNumber: number, options: DeploymentOptions): Promise<Pipeline> {
|
deployPipeline(owner: string, repo: string, pipelineNumber: string, options: DeploymentOptions): Promise<Pipeline> {
|
||||||
const vars = {
|
const vars = {
|
||||||
...options.variables,
|
...options.variables,
|
||||||
event: 'deployment',
|
event: 'deployment',
|
||||||
|
|
|
@ -15,7 +15,10 @@ export const usePipelineStore = defineStore('pipelines', () => {
|
||||||
function setPipeline(owner: string, repo: string, pipeline: Pipeline) {
|
function setPipeline(owner: string, repo: string, pipeline: Pipeline) {
|
||||||
const _repoSlug = repoSlug(owner, repo);
|
const _repoSlug = repoSlug(owner, repo);
|
||||||
const repoPipelines = pipelines.get(_repoSlug) || new Map();
|
const repoPipelines = pipelines.get(_repoSlug) || new Map();
|
||||||
repoPipelines.set(pipeline.number, { ...(repoPipelines.get(pipeline.number) || {}), ...pipeline });
|
repoPipelines.set(pipeline.number, {
|
||||||
|
...(repoPipelines.get(pipeline.number) || {}),
|
||||||
|
...pipeline,
|
||||||
|
});
|
||||||
pipelines.set(_repoSlug, repoPipelines);
|
pipelines.set(_repoSlug, repoPipelines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
const allPipelines = inject<Ref<Pipeline[]>>('pipelines');
|
const allPipelines = inject<Ref<Pipeline[]>>('pipelines');
|
||||||
const pipelines = computed(() => allPipelines?.value.filter((b) => b.branch === branch.value));
|
const pipelines = computed(() =>
|
||||||
|
allPipelines?.value.filter((b) => b.branch === branch.value && b.event !== 'pull_request'),
|
||||||
|
);
|
||||||
|
|
||||||
return { pipelines, repo };
|
return { pipelines, repo };
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="pipeline.status === 'blocked'" class="flex flex-col flex-grow justify-center items-center p-2">
|
<div v-else-if="pipeline.status === 'blocked'" class="flex flex-col flex-grow justify-center items-center p-2">
|
||||||
<Icon name="status-blocked" class="w-32 h-32 text-color" />
|
<Icon name="status-blocked" class="w-16 h-16 text-color mb-4" />
|
||||||
<p class="text-xl text-color">{{ $t('repo.pipeline.protected.awaits') }}</p>
|
<p class="text-xl text-color mb-4">{{ $t('repo.pipeline.protected.awaits') }}</p>
|
||||||
<div v-if="repoPermissions.push" class="flex mt-2 space-x-4">
|
<div v-if="repoPermissions.push" class="flex mt-2 space-x-4">
|
||||||
<Button
|
<Button
|
||||||
color="green"
|
color="green"
|
||||||
|
@ -49,8 +49,8 @@
|
||||||
</FluidContainer>
|
</FluidContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, inject, PropType, Ref, toRef } from 'vue';
|
import { computed, inject, Ref, toRef } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -65,112 +65,84 @@ import useNotifications from '~/compositions/useNotifications';
|
||||||
import { Pipeline, PipelineStep, Repo, RepoPermissions } from '~/lib/api/types';
|
import { Pipeline, PipelineStep, Repo, RepoPermissions } from '~/lib/api/types';
|
||||||
import { findStep } from '~/utils/helpers';
|
import { findStep } from '~/utils/helpers';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
name: 'Pipeline',
|
stepId?: string | null;
|
||||||
|
}>();
|
||||||
|
|
||||||
components: {
|
const apiClient = useApiClient();
|
||||||
Button,
|
const router = useRouter();
|
||||||
PipelineStepList,
|
const route = useRoute();
|
||||||
Icon,
|
const notifications = useNotifications();
|
||||||
PipelineLog,
|
const i18n = useI18n();
|
||||||
FluidContainer,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
||||||
stepId: {
|
const repo = inject<Ref<Repo>>('repo');
|
||||||
type: String as PropType<string | null>,
|
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
||||||
default: null,
|
if (!repo || !repoPermissions || !pipeline) {
|
||||||
},
|
throw new Error('Unexpected: "repo", "repoPermissions" & "pipeline" should be provided at this place');
|
||||||
},
|
}
|
||||||
|
|
||||||
setup(props) {
|
const stepId = toRef(props, 'stepId');
|
||||||
const apiClient = useApiClient();
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const notifications = useNotifications();
|
|
||||||
const i18n = useI18n();
|
|
||||||
|
|
||||||
const pipeline = inject<Ref<Pipeline>>('pipeline');
|
const defaultStepId = computed(() => {
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
if (!pipeline.value || !pipeline.value.steps || !pipeline.value.steps[0].children) {
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
return null;
|
||||||
if (!repo || !repoPermissions || !pipeline) {
|
}
|
||||||
throw new Error('Unexpected: "repo", "repoPermissions" & "pipeline" should be provided at this place');
|
|
||||||
|
return pipeline.value.steps[0].children[0].pid;
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedStepId = computed({
|
||||||
|
get() {
|
||||||
|
if (stepId.value !== '' && stepId.value !== null && stepId.value !== undefined) {
|
||||||
|
const id = parseInt(stepId.value, 10);
|
||||||
|
const step = pipeline.value?.steps?.reduce(
|
||||||
|
(prev, p) => prev || p.children?.find((c) => c.pid === id),
|
||||||
|
undefined as PipelineStep | undefined,
|
||||||
|
);
|
||||||
|
if (step) {
|
||||||
|
return step.pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return fallback if step-id is provided, but step can not be found
|
||||||
|
return defaultStepId.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepId = toRef(props, 'stepId');
|
// is opened on >= md-screen
|
||||||
|
if (window.innerWidth > 768) {
|
||||||
|
return defaultStepId.value;
|
||||||
|
}
|
||||||
|
|
||||||
const defaultStepId = computed(() => {
|
return null;
|
||||||
if (!pipeline.value || !pipeline.value.steps || !pipeline.value.steps[0].children) {
|
},
|
||||||
return null;
|
set(_selectedStepId: number | null) {
|
||||||
}
|
if (!_selectedStepId) {
|
||||||
|
router.replace({ params: { ...route.params, stepId: '' } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return pipeline.value.steps[0].children[0].pid;
|
router.replace({ params: { ...route.params, stepId: `${_selectedStepId}` } });
|
||||||
});
|
|
||||||
|
|
||||||
const selectedStepId = computed({
|
|
||||||
get() {
|
|
||||||
if (stepId.value !== '' && stepId.value !== null) {
|
|
||||||
const id = parseInt(stepId.value, 10);
|
|
||||||
const step = pipeline.value?.steps?.reduce(
|
|
||||||
(prev, p) => prev || p.children?.find((c) => c.pid === id),
|
|
||||||
undefined as PipelineStep | undefined,
|
|
||||||
);
|
|
||||||
if (step) {
|
|
||||||
return step.pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return fallback if step-id is provided, but step can not be found
|
|
||||||
return defaultStepId.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is opened on >= md-screen
|
|
||||||
if (window.innerWidth > 768) {
|
|
||||||
return defaultStepId.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
set(_selectedStepId: number | null) {
|
|
||||||
if (!_selectedStepId) {
|
|
||||||
router.replace({ params: { ...route.params, stepId: '' } });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
router.replace({ params: { ...route.params, stepId: `${_selectedStepId}` } });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const selectedStep = computed(() => findStep(pipeline.value.steps || [], selectedStepId.value || -1));
|
|
||||||
const error = computed(() => pipeline.value?.error || selectedStep.value?.error);
|
|
||||||
|
|
||||||
const { doSubmit: approvePipeline, isLoading: isApprovingPipeline } = useAsyncAction(async () => {
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.approvePipeline(repo.value.owner, repo.value.name, `${pipeline.value.number}`);
|
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.protected.approve_success'), type: 'success' });
|
|
||||||
});
|
|
||||||
|
|
||||||
const { doSubmit: declinePipeline, isLoading: isDecliningPipeline } = useAsyncAction(async () => {
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.declinePipeline(repo.value.owner, repo.value.name, `${pipeline.value.number}`);
|
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.protected.decline_success'), type: 'success' });
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
repoPermissions,
|
|
||||||
selectedStepId,
|
|
||||||
pipeline,
|
|
||||||
error,
|
|
||||||
isApprovingPipeline,
|
|
||||||
isDecliningPipeline,
|
|
||||||
approvePipeline,
|
|
||||||
declinePipeline,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedStep = computed(() => findStep(pipeline.value.steps || [], selectedStepId.value || -1));
|
||||||
|
const error = computed(() => pipeline.value?.error || selectedStep.value?.error);
|
||||||
|
|
||||||
|
const { doSubmit: approvePipeline, isLoading: isApprovingPipeline } = useAsyncAction(async () => {
|
||||||
|
if (!repo) {
|
||||||
|
throw new Error('Unexpected: Repo is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiClient.approvePipeline(repo.value.owner, repo.value.name, `${pipeline.value.number}`);
|
||||||
|
notifications.notify({ title: i18n.t('repo.pipeline.protected.approve_success'), type: 'success' });
|
||||||
|
});
|
||||||
|
|
||||||
|
const { doSubmit: declinePipeline, isLoading: isDecliningPipeline } = useAsyncAction(async () => {
|
||||||
|
if (!repo) {
|
||||||
|
throw new Error('Unexpected: Repo is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiClient.declinePipeline(repo.value.owner, repo.value.name, `${pipeline.value.number}`);
|
||||||
|
notifications.notify({ title: i18n.t('repo.pipeline.protected.decline_success'), type: 'success' });
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
:fluid-content="activeTab !== 'tasks'"
|
:fluid-content="activeTab !== 'tasks'"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="w-full md:w-auto text-center">{{ $t('repo.pipeline.pipeline', { pipelineId }) }}</span>
|
<span class="flex-shrink-0 text-center">{{ $t('repo.pipeline.pipeline', { pipelineId }) }}</span>
|
||||||
<span class="<md:hidden">-</span>
|
<span class="<md:hidden">-</span>
|
||||||
<span class="w-full md:w-auto text-center truncate">{{ message }}</span>
|
<span class="text-center truncate">{{ message }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #titleActions>
|
<template #titleActions>
|
||||||
|
@ -75,13 +75,14 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { Tooltip } from 'floating-vue';
|
import { Tooltip } from 'floating-vue';
|
||||||
import { computed, defineComponent, inject, onBeforeUnmount, onMounted, provide, Ref, ref, toRef, watch } from 'vue';
|
import { computed, inject, onBeforeUnmount, onMounted, provide, Ref, ref, toRef, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
|
import DeployPipelinePopup from '~/components/layout/popups/DeployPipelinePopup.vue';
|
||||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||||
import Tab from '~/components/layout/scaffold/Tab.vue';
|
import Tab from '~/components/layout/scaffold/Tab.vue';
|
||||||
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
||||||
|
@ -94,150 +95,110 @@ import { useRouteBackOrDefault } from '~/compositions/useRouteBackOrDefault';
|
||||||
import { Repo, RepoPermissions } from '~/lib/api/types';
|
import { Repo, RepoPermissions } from '~/lib/api/types';
|
||||||
import { usePipelineStore } from '~/store/pipelines';
|
import { usePipelineStore } from '~/store/pipelines';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
name: 'PipelineWrapper',
|
repoOwner: string;
|
||||||
|
repoName: string;
|
||||||
|
pipelineId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
components: {
|
const apiClient = useApiClient();
|
||||||
Button,
|
const route = useRoute();
|
||||||
PipelineStatusIcon,
|
const router = useRouter();
|
||||||
Tab,
|
const notifications = useNotifications();
|
||||||
Tooltip,
|
const favicon = useFavicon();
|
||||||
Scaffold,
|
const i18n = useI18n();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const pipelineStore = usePipelineStore();
|
||||||
repoOwner: {
|
const pipelineId = toRef(props, 'pipelineId');
|
||||||
type: String,
|
const repoOwner = toRef(props, 'repoOwner');
|
||||||
required: true,
|
const repoName = toRef(props, 'repoName');
|
||||||
},
|
const repo = inject<Ref<Repo>>('repo');
|
||||||
|
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
||||||
|
if (!repo || !repoPermissions) {
|
||||||
|
throw new Error('Unexpected: "repo" & "repoPermissions" should be provided at this place');
|
||||||
|
}
|
||||||
|
|
||||||
repoName: {
|
const pipeline = pipelineStore.getPipeline(repoOwner, repoName, pipelineId);
|
||||||
type: String,
|
const { since, duration, created } = usePipeline(pipeline);
|
||||||
required: true,
|
provide('pipeline', pipeline);
|
||||||
},
|
|
||||||
|
|
||||||
pipelineId: {
|
const { message } = usePipeline(pipeline);
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props) {
|
const showDeployPipelinePopup = ref(false);
|
||||||
const apiClient = useApiClient();
|
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
const notifications = useNotifications();
|
|
||||||
const favicon = useFavicon();
|
|
||||||
const i18n = useI18n();
|
|
||||||
|
|
||||||
const pipelineStore = usePipelineStore();
|
async function loadPipeline(): Promise<void> {
|
||||||
const pipelineId = toRef(props, 'pipelineId');
|
if (!repo) {
|
||||||
const repoOwner = toRef(props, 'repoOwner');
|
throw new Error('Unexpected: Repo is undefined');
|
||||||
const repoName = toRef(props, 'repoName');
|
}
|
||||||
const repo = inject<Ref<Repo>>('repo');
|
|
||||||
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
|
await pipelineStore.loadPipeline(repo.value.owner, repo.value.name, parseInt(pipelineId.value, 10));
|
||||||
if (!repo || !repoPermissions) {
|
|
||||||
throw new Error('Unexpected: "repo" & "repoPermissions" should be provided at this place');
|
favicon.updateStatus(pipeline.value?.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { doSubmit: cancelPipeline, isLoading: isCancelingPipeline } = useAsyncAction(async () => {
|
||||||
|
if (!repo) {
|
||||||
|
throw new Error('Unexpected: Repo is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pipeline.value?.steps) {
|
||||||
|
throw new Error('Unexpected: Pipeline steps not loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: is selectedStepId right?
|
||||||
|
// const step = findStep(pipeline.value.steps, selectedStepId.value || 2);
|
||||||
|
|
||||||
|
// if (!step) {
|
||||||
|
// throw new Error('Unexpected: Step not found');
|
||||||
|
// }
|
||||||
|
|
||||||
|
await apiClient.cancelPipeline(repo.value.owner, repo.value.name, parseInt(pipelineId.value, 10));
|
||||||
|
notifications.notify({ title: i18n.t('repo.pipeline.actions.cancel_success'), type: 'success' });
|
||||||
|
});
|
||||||
|
|
||||||
|
const { doSubmit: restartPipeline, isLoading: isRestartingPipeline } = useAsyncAction(async () => {
|
||||||
|
if (!repo) {
|
||||||
|
throw new Error('Unexpected: Repo is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiClient.restartPipeline(repo.value.owner, repo.value.name, pipelineId.value, { fork: true });
|
||||||
|
notifications.notify({ title: i18n.t('repo.pipeline.actions.restart_success'), type: 'success' });
|
||||||
|
// TODO: directly send to newest pipeline?
|
||||||
|
await router.push({ name: 'repo', params: { repoName: repo.value.name, repoOwner: repo.value.owner } });
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(loadPipeline);
|
||||||
|
watch([repoName, repoOwner, pipelineId], loadPipeline);
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
favicon.updateStatus('default');
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeTab = computed({
|
||||||
|
get() {
|
||||||
|
if (route.name === 'repo-pipeline-changed-files') {
|
||||||
|
return 'changed-files';
|
||||||
}
|
}
|
||||||
|
|
||||||
const pipeline = pipelineStore.getPipeline(repoOwner, repoName, pipelineId);
|
if (route.name === 'repo-pipeline-config') {
|
||||||
const { since, duration, created } = usePipeline(pipeline);
|
return 'config';
|
||||||
provide('pipeline', pipeline);
|
|
||||||
|
|
||||||
const { message } = usePipeline(pipeline);
|
|
||||||
|
|
||||||
const showDeployPipelinePopup = ref(false);
|
|
||||||
|
|
||||||
async function loadPipeline(): Promise<void> {
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await pipelineStore.loadPipeline(repo.value.owner, repo.value.name, parseInt(pipelineId.value, 10));
|
|
||||||
|
|
||||||
favicon.updateStatus(pipeline.value?.status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { doSubmit: cancelPipeline, isLoading: isCancelingPipeline } = useAsyncAction(async () => {
|
return 'tasks';
|
||||||
if (!repo) {
|
},
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
set(tab: string) {
|
||||||
}
|
if (tab === 'tasks') {
|
||||||
|
router.replace({ name: 'repo-pipeline' });
|
||||||
|
}
|
||||||
|
|
||||||
if (!pipeline.value?.steps) {
|
if (tab === 'changed-files') {
|
||||||
throw new Error('Unexpected: Pipeline steps not loaded');
|
router.replace({ name: 'repo-pipeline-changed-files' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is selectedStepId right?
|
if (tab === 'config') {
|
||||||
// const step = findStep(pipeline.value.steps, selectedStepId.value || 2);
|
router.replace({ name: 'repo-pipeline-config' });
|
||||||
|
}
|
||||||
// if (!step) {
|
|
||||||
// throw new Error('Unexpected: Step not found');
|
|
||||||
// }
|
|
||||||
|
|
||||||
await apiClient.cancelPipeline(repo.value.owner, repo.value.name, parseInt(pipelineId.value, 10));
|
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.actions.cancel_success'), type: 'success' });
|
|
||||||
});
|
|
||||||
|
|
||||||
const { doSubmit: restartPipeline, isLoading: isRestartingPipeline } = useAsyncAction(async () => {
|
|
||||||
if (!repo) {
|
|
||||||
throw new Error('Unexpected: Repo is undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
await apiClient.restartPipeline(repo.value.owner, repo.value.name, pipelineId.value, { fork: true });
|
|
||||||
notifications.notify({ title: i18n.t('repo.pipeline.actions.restart_success'), type: 'success' });
|
|
||||||
// TODO: directly send to newest pipeline?
|
|
||||||
await router.push({ name: 'repo', params: { repoName: repo.value.name, repoOwner: repo.value.owner } });
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(loadPipeline);
|
|
||||||
watch([repo, pipelineId], loadPipeline);
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
favicon.updateStatus('default');
|
|
||||||
});
|
|
||||||
|
|
||||||
const activeTab = computed({
|
|
||||||
get() {
|
|
||||||
if (route.name === 'repo-pipeline-changed-files') {
|
|
||||||
return 'changed-files';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route.name === 'repo-pipeline-config') {
|
|
||||||
return 'config';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'tasks';
|
|
||||||
},
|
|
||||||
set(tab: string) {
|
|
||||||
if (tab === 'tasks') {
|
|
||||||
router.replace({ name: 'repo-pipeline' });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab === 'changed-files') {
|
|
||||||
router.replace({ name: 'repo-pipeline-changed-files' });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab === 'config') {
|
|
||||||
router.replace({ name: 'repo-pipeline-config' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
repoPermissions,
|
|
||||||
pipeline,
|
|
||||||
repo,
|
|
||||||
message,
|
|
||||||
isCancelingPipeline,
|
|
||||||
isRestartingPipeline,
|
|
||||||
showDeployPipelinePopup,
|
|
||||||
activeTab,
|
|
||||||
since,
|
|
||||||
duration,
|
|
||||||
cancelPipeline,
|
|
||||||
restartPipeline,
|
|
||||||
goBack: useRouteBackOrDefault({ name: 'repo' }),
|
|
||||||
created,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const goBack = useRouteBackOrDefault({ name: 'repo' });
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue