mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-16 04:25:30 +00:00
Merge branch 'origin/main' into 'next-release/main'
This commit is contained in:
commit
e8328512ab
9 changed files with 69 additions and 117 deletions
|
@ -48,6 +48,7 @@
|
|||
"dind",
|
||||
"Dockle",
|
||||
"doublestar",
|
||||
"emojify",
|
||||
"envsubst",
|
||||
"errgroup",
|
||||
"estree",
|
||||
|
|
|
@ -121,8 +121,7 @@ import IconButton from '~/components/atomic/IconButton.vue';
|
|||
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import type { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
|
||||
import { findStep, isStepFinished, isStepRunning } from '~/utils/helpers';
|
||||
import type { Pipeline, PipelineStep, PipelineWorkflow, Repo, RepoPermissions } from '~/lib/api/types';
|
||||
|
||||
interface LogLine {
|
||||
index: number;
|
||||
|
@ -303,12 +302,12 @@ async function loadLogs() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isStepFinished(step.value)) {
|
||||
if (step.value.state !== 'running' && step.value.state !== 'pending') {
|
||||
loadedStepSlug.value = stepSlug.value;
|
||||
const logs = await apiClient.getLogs(repo.value.id, pipeline.value.number, step.value.id);
|
||||
logs?.forEach((line) => writeLog({ index: line.line, text: line.data, time: line.time }));
|
||||
flushLogs(false);
|
||||
} else if (step.value.state === 'pending' || isStepRunning(step.value)) {
|
||||
} else {
|
||||
loadedStepSlug.value = stepSlug.value;
|
||||
stream.value = apiClient.streamLogs(repo.value.id, pipeline.value.number, step.value.id, (line) => {
|
||||
writeLog({ index: line.line, text: line.data, time: line.time });
|
||||
|
@ -336,6 +335,29 @@ async function deleteLogs() {
|
|||
}
|
||||
}
|
||||
|
||||
function findStep(workflows: PipelineWorkflow[], pid: number): PipelineStep | undefined {
|
||||
return workflows.reduce(
|
||||
(prev, workflow) => {
|
||||
const result = workflow.children.reduce(
|
||||
(prevChild, step) => {
|
||||
if (step.pid === pid) {
|
||||
return step;
|
||||
}
|
||||
|
||||
return prevChild;
|
||||
},
|
||||
undefined as PipelineStep | undefined,
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return prev;
|
||||
},
|
||||
undefined as PipelineStep | undefined,
|
||||
);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadLogs();
|
||||
});
|
||||
|
|
|
@ -87,7 +87,7 @@ function durationAsNumber(durationMs: number): string {
|
|||
}
|
||||
|
||||
export function useDate() {
|
||||
async function setDayjsLocale(locale: string) {
|
||||
async function setDateLocale(locale: string) {
|
||||
currentLocale = locale;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ export function useDate() {
|
|||
toLocaleString,
|
||||
timeAgo,
|
||||
prettyDuration,
|
||||
setDayjsLocale,
|
||||
setDateLocale,
|
||||
durationAsNumber,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import { useStorage } from '@vueuse/core';
|
||||
import { nextTick } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
import { getUserLanguage } from '~/utils/locale';
|
||||
|
||||
import { useDate } from './useDate';
|
||||
|
||||
const { setDayjsLocale } = useDate();
|
||||
export function getUserLanguage(): string {
|
||||
const browserLocale = navigator.language.split('-')[0];
|
||||
const selectedLocale = useStorage('woodpecker:locale', browserLocale).value;
|
||||
|
||||
return selectedLocale;
|
||||
}
|
||||
|
||||
const { setDateLocale } = useDate();
|
||||
const userLanguage = getUserLanguage();
|
||||
const fallbackLocale = 'en';
|
||||
export const i18n = createI18n({
|
||||
|
@ -28,9 +34,9 @@ export const setI18nLanguage = async (lang: string): Promise<void> => {
|
|||
await loadLocaleMessages(lang);
|
||||
}
|
||||
i18n.global.locale.value = lang;
|
||||
await setDayjsLocale(lang);
|
||||
await setDateLocale(lang);
|
||||
};
|
||||
|
||||
loadLocaleMessages(fallbackLocale).catch(console.error);
|
||||
loadLocaleMessages(userLanguage).catch(console.error);
|
||||
setDayjsLocale(userLanguage).catch(console.error);
|
||||
setDateLocale(userLanguage).catch(console.error);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { emojify } from 'node-emoji';
|
||||
import { computed, type Ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { useDate } from '~/compositions/useDate';
|
||||
import { useElapsedTime } from '~/compositions/useElapsedTime';
|
||||
import type { Pipeline } from '~/lib/api/types';
|
||||
import { convertEmojis } from '~/utils/emoji';
|
||||
|
||||
const { toLocaleString, timeAgo, prettyDuration } = useDate();
|
||||
|
||||
|
@ -74,10 +74,10 @@ export default (pipeline: Ref<Pipeline | undefined>) => {
|
|||
return prettyDuration(durationElapsed.value);
|
||||
});
|
||||
|
||||
const message = computed(() => convertEmojis(pipeline.value?.message ?? ''));
|
||||
const message = computed(() => emojify(pipeline.value?.message ?? ''));
|
||||
const shortMessage = computed(() => message.value.split('\n')[0]);
|
||||
|
||||
const prTitleWithDescription = computed(() => convertEmojis(pipeline.value?.title ?? ''));
|
||||
const prTitleWithDescription = computed(() => emojify(pipeline.value?.title ?? ''));
|
||||
const prTitle = computed(() => prTitleWithDescription.value.split('\n')[0]);
|
||||
|
||||
const prettyRef = computed(() => {
|
||||
|
|
|
@ -4,7 +4,29 @@ import { computed, reactive, ref, type Ref } from 'vue';
|
|||
import useApiClient from '~/compositions/useApiClient';
|
||||
import type { Pipeline, PipelineFeed, PipelineWorkflow } from '~/lib/api/types';
|
||||
import { useRepoStore } from '~/store/repos';
|
||||
import { comparePipelines, comparePipelinesWithStatus, isPipelineActive } from '~/utils/helpers';
|
||||
|
||||
/**
|
||||
* Compare two pipelines by creation timestamp.
|
||||
* @param {object} a - A pipeline.
|
||||
* @param {object} b - A pipeline.
|
||||
* @returns {number} 0 if created at the same time, < 0 if b was create before a, > 0 otherwise
|
||||
*/
|
||||
function comparePipelines(a: Pipeline, b: Pipeline): number {
|
||||
return (b.created || -1) - (a.created || -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two pipelines by the status.
|
||||
* Giving pending, running, or started higher priority than other status
|
||||
* @param {object} a - A pipeline.
|
||||
* @param {object} b - A pipeline.
|
||||
* @returns {number} 0 if status same priority, < 0 if b has higher priority, > 0 otherwise
|
||||
*/
|
||||
function comparePipelinesWithStatus(a: Pipeline, b: Pipeline): number {
|
||||
const bPriority = ['pending', 'running', 'started'].includes(b.status) ? 1 : 0;
|
||||
const aPriority = ['pending', 'running', 'started'].includes(a.status) ? 1 : 0;
|
||||
return bPriority - aPriority || comparePipelines(a, b);
|
||||
}
|
||||
|
||||
export const usePipelineStore = defineStore('pipelines', () => {
|
||||
const apiClient = useApiClient();
|
||||
|
@ -87,7 +109,9 @@ export const usePipelineStore = defineStore('pipelines', () => {
|
|||
.filter((pipeline) => repoStore.ownedRepoIds.includes(pipeline.repo_id)),
|
||||
);
|
||||
|
||||
const activePipelines = computed(() => pipelineFeed.value.filter(isPipelineActive));
|
||||
const activePipelines = computed(() =>
|
||||
pipelineFeed.value.filter((pipeline) => ['pending', 'running', 'started'].includes(pipeline.status)),
|
||||
);
|
||||
|
||||
async function loadPipelineFeed() {
|
||||
await repoStore.loadRepos();
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// cSpell:ignore emojify
|
||||
import { emojify } from 'node-emoji';
|
||||
|
||||
export function convertEmojis(input: string): string {
|
||||
return emojify(input);
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
import type { Pipeline, PipelineStep, PipelineWorkflow, Repo } from '~/lib/api/types';
|
||||
|
||||
export function findStep(workflows: PipelineWorkflow[], pid: number): PipelineStep | undefined {
|
||||
return workflows.reduce(
|
||||
(prev, workflow) => {
|
||||
const result = workflow.children.reduce(
|
||||
(prevChild, step) => {
|
||||
if (step.pid === pid) {
|
||||
return step;
|
||||
}
|
||||
|
||||
return prevChild;
|
||||
},
|
||||
undefined as PipelineStep | undefined,
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return prev;
|
||||
},
|
||||
undefined as PipelineStep | undefined,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} step - The process object.
|
||||
* @returns {boolean} true if the process is in a completed state
|
||||
*/
|
||||
export function isStepFinished(step: PipelineStep): boolean {
|
||||
return step.state !== 'running' && step.state !== 'pending';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} step - The process object.
|
||||
* @returns {boolean} true if the process is running
|
||||
*/
|
||||
export function isStepRunning(step: PipelineStep): boolean {
|
||||
return step.state === 'running';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two pipelines by creation timestamp.
|
||||
* @param {object} a - A pipeline.
|
||||
* @param {object} b - A pipeline.
|
||||
* @returns {number} 0 if created at the same time, < 0 if b was create before a, > 0 otherwise
|
||||
*/
|
||||
export function comparePipelines(a: Pipeline, b: Pipeline): number {
|
||||
return (b.created || -1) - (a.created || -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two pipelines by the status.
|
||||
* Giving pending, running, or started higher priority than other status
|
||||
* @param {object} a - A pipeline.
|
||||
* @param {object} b - A pipeline.
|
||||
* @returns {number} 0 if status same priority, < 0 if b has higher priority, > 0 otherwise
|
||||
*/
|
||||
export function comparePipelinesWithStatus(a: Pipeline, b: Pipeline): number {
|
||||
const bPriority = ['pending', 'running', 'started'].includes(b.status) ? 1 : 0;
|
||||
const aPriority = ['pending', 'running', 'started'].includes(a.status) ? 1 : 0;
|
||||
return bPriority - aPriority || comparePipelines(a, b);
|
||||
}
|
||||
|
||||
export function isPipelineActive(pipeline: Pipeline): boolean {
|
||||
return ['pending', 'running', 'started'].includes(pipeline.status);
|
||||
}
|
||||
|
||||
export function repoSlug(ownerOrRepo: string | Repo, name?: string): string {
|
||||
if (typeof ownerOrRepo === 'string') {
|
||||
if (name === undefined) {
|
||||
throw new Error('Please provide a name as well');
|
||||
}
|
||||
|
||||
return `${ownerOrRepo}/${name}`;
|
||||
}
|
||||
|
||||
return `${ownerOrRepo.owner}/${ownerOrRepo.name}`;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import { useStorage } from '@vueuse/core';
|
||||
|
||||
export function getUserLanguage(): string {
|
||||
const browserLocale = navigator.language.split('-')[0];
|
||||
const selectedLocale = useStorage('woodpecker:locale', browserLocale).value;
|
||||
|
||||
return selectedLocale;
|
||||
}
|
||||
|
||||
export function truncate(text: string, length: number): string {
|
||||
if (text.length <= length) {
|
||||
return text;
|
||||
}
|
||||
|
||||
return `${text.slice(0, length)}...`;
|
||||
}
|
Loading…
Reference in a new issue