mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-21 12:00:02 +00:00
Improve linter messages in UI (#4351)
This commit is contained in:
@@ -24,9 +24,11 @@
|
||||
"@vueuse/core": "^11.0.0",
|
||||
"ansi_up": "^6.0.2",
|
||||
"dayjs": "^1.11.12",
|
||||
"dompurify": "^3.2.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"js-base64": "^3.7.7",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^15.0.0",
|
||||
"node-emoji": "^2.1.3",
|
||||
"pinia": "^2.2.1",
|
||||
"prismjs": "^1.29.0",
|
||||
|
18
web/pnpm-lock.yaml
generated
18
web/pnpm-lock.yaml
generated
@@ -29,6 +29,9 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.12
|
||||
version: 1.11.13
|
||||
dompurify:
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0
|
||||
fuse.js:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
@@ -38,6 +41,9 @@ importers:
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
marked:
|
||||
specifier: ^15.0.0
|
||||
version: 15.0.0
|
||||
node-emoji:
|
||||
specifier: ^2.1.3
|
||||
version: 2.1.3
|
||||
@@ -1310,6 +1316,9 @@ packages:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
dompurify@3.2.0:
|
||||
resolution: {integrity: sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ==}
|
||||
|
||||
domutils@3.1.0:
|
||||
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||
|
||||
@@ -1921,6 +1930,11 @@ packages:
|
||||
markdown-table@3.0.3:
|
||||
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
|
||||
|
||||
marked@15.0.0:
|
||||
resolution: {integrity: sha512-0mouKmBROJv/WSHJBPZZyYofUgawMChnD5je/g+aOBXsHDjb/IsnTQj7mnhQZu+qPJmRQ0ecX3mLGEUm3BgwYA==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
|
||||
mdast-util-find-and-replace@3.0.1:
|
||||
resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==}
|
||||
|
||||
@@ -4055,6 +4069,8 @@ snapshots:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
dompurify@3.2.0: {}
|
||||
|
||||
domutils@3.1.0:
|
||||
dependencies:
|
||||
dom-serializer: 2.0.0
|
||||
@@ -4766,6 +4782,8 @@ snapshots:
|
||||
|
||||
markdown-table@3.0.3: {}
|
||||
|
||||
marked@15.0.0: {}
|
||||
|
||||
mdast-util-find-and-replace@3.0.1:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
|
@@ -3,9 +3,9 @@
|
||||
:href="`${docsUrl}`"
|
||||
:title="$t('documentation_for', { topic })"
|
||||
target="_blank"
|
||||
class="text-wp-link-100 hover:text-wp-link-200 cursor-pointer mt-1"
|
||||
class="text-wp-link-100 hover:text-wp-link-200 cursor-pointer"
|
||||
>
|
||||
<Icon name="question" class="!w-4 !h-4" />
|
||||
<Icon name="question" class="!w-5 !h-5" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
18
web/src/components/atomic/RenderMarkdown.vue
Normal file
18
web/src/components/atomic/RenderMarkdown.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<span v-html="contentHTML" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DOMPurify from 'dompurify';
|
||||
import { marked } from 'marked';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
content: string;
|
||||
}>();
|
||||
|
||||
const contentHTML = computed<string>(() => {
|
||||
const dirtyHTML = marked.parse(props.content);
|
||||
return DOMPurify.sanitize(dirtyHTML as string, { USE_PROFILES: { html: true } });
|
||||
});
|
||||
</script>
|
@@ -14,9 +14,9 @@
|
||||
</template>
|
||||
<template #description>
|
||||
<i18n-t keypath="repo.settings.general.pipeline_path.desc" tag="p" class="text-sm text-wp-text-alt-100">
|
||||
<span class="code-box-inline px-1">{{ $t('repo.settings.general.pipeline_path.desc_path_example') }}</span>
|
||||
<span class="code-box-inline">{{ $t('repo.settings.general.pipeline_path.desc_path_example') }}</span>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span class="code-box-inline px-1">/</span>
|
||||
<span class="code-box-inline">/</span>
|
||||
</i18n-t>
|
||||
</template>
|
||||
</InputField>
|
||||
|
@@ -147,6 +147,7 @@ body,
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.code-box-inline {
|
||||
@apply bg-wp-code-200 rounded-md text-wp-code-text-100;
|
||||
.code-box-inline,
|
||||
code:not(pre > code) {
|
||||
@apply bg-wp-code-200 rounded-md text-wp-code-text-100 px-1 py-px;
|
||||
}
|
||||
|
@@ -1,37 +1,47 @@
|
||||
<template>
|
||||
<Panel>
|
||||
<div class="grid justify-center gap-x-4 text-left grid-3-1">
|
||||
<template v-for="(error, i) in pipeline!.errors" :key="i">
|
||||
<Icon
|
||||
name="attention"
|
||||
class="flex-shrink-0 my-1"
|
||||
:class="{
|
||||
'text-wp-state-warn-100': error.is_warning,
|
||||
'text-wp-state-error-100': !error.is_warning,
|
||||
}"
|
||||
/>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span>[{{ error.type }}]</span>
|
||||
<span
|
||||
v-if="isLinterError(error) || isDeprecationError(error) || isBadHabitError(error)"
|
||||
class="whitespace-nowrap"
|
||||
>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span v-if="error.data?.file" class="font-bold">{{ error.data?.file }}: </span>
|
||||
<span>{{ error.data?.field }}</span>
|
||||
</span>
|
||||
<span v-else />
|
||||
<a
|
||||
v-if="isDeprecationError(error) || isBadHabitError(error)"
|
||||
:href="error.data?.docs"
|
||||
target="_blank"
|
||||
class="underline col-span-full col-start-2 md:col-span-auto md:col-start-auto"
|
||||
>
|
||||
{{ error.message }}
|
||||
</a>
|
||||
<span v-else class="col-span-full col-start-2 md:col-span-auto md:col-start-auto">
|
||||
{{ error.message }}
|
||||
</span>
|
||||
<div class="flex flex-col gap-y-4">
|
||||
<template v-for="(error, _index) in pipeline!.errors" :key="_index">
|
||||
<div>
|
||||
<div class="grid grid-cols-[minmax(10rem,auto),3fr]">
|
||||
<span class="flex items-center gap-x-2">
|
||||
<Icon
|
||||
name="attention"
|
||||
class="flex-shrink-0 my-1"
|
||||
:class="{
|
||||
'text-wp-state-warn-100': error.is_warning,
|
||||
'text-wp-state-error-100': !error.is_warning,
|
||||
}"
|
||||
/>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span>
|
||||
<code>{{ error.type }}</code>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="isLinterError(error) || isDeprecationError(error) || isBadHabitError(error)"
|
||||
class="flex items-center gap-x-2 whitespace-nowrap"
|
||||
>
|
||||
<span>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
|
||||
<span v-if="error.data?.file" class="font-bold">{{ error.data?.file }}: </span>
|
||||
<span>{{ error.data?.field }}</span>
|
||||
</span>
|
||||
<DocsLink
|
||||
v-if="isDeprecationError(error) || isBadHabitError(error)"
|
||||
:topic="error.data?.field || ''"
|
||||
:url="error.data?.docs || ''"
|
||||
/>
|
||||
</span>
|
||||
<span v-else />
|
||||
</div>
|
||||
<div class="grid grid-cols-[minmax(10rem,auto),4fr] col-start-2">
|
||||
<span />
|
||||
<span>
|
||||
<RenderMarkdown :content="error.message" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</Panel>
|
||||
@@ -40,7 +50,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { inject, type Ref } from 'vue';
|
||||
|
||||
import DocsLink from '~/components/atomic/DocsLink.vue';
|
||||
import Icon from '~/components/atomic/Icon.vue';
|
||||
import RenderMarkdown from '~/components/atomic/RenderMarkdown.vue';
|
||||
import Panel from '~/components/layout/Panel.vue';
|
||||
import type { Pipeline, PipelineError } from '~/lib/api/types';
|
||||
|
||||
@@ -63,9 +75,3 @@ function isBadHabitError(error: PipelineError): error is PipelineError<{ file?:
|
||||
return error.type === 'bad_habit';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3-1 {
|
||||
grid-template-columns: auto auto auto 1fr;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user