feat : ajout de la lecture des logs symfony et docker (#3)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Reviewed-on: #3 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #3.
This commit is contained in:
113
frontend/components/ui/LogModal.vue
Normal file
113
frontend/components/ui/LogModal.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue: boolean
|
||||
title: string
|
||||
content: string
|
||||
loading?: boolean
|
||||
showLevelFilter?: boolean
|
||||
}>(), {
|
||||
loading: false,
|
||||
showLevelFilter: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
(e: 'refresh', lines: number, level: string): void
|
||||
}>()
|
||||
|
||||
const selectedLines = ref(100)
|
||||
const selectedLevel = ref('')
|
||||
|
||||
const lineOptions = [50, 100, 500, 1000]
|
||||
|
||||
const copied = ref(false)
|
||||
|
||||
function refresh() {
|
||||
emit('refresh', selectedLines.value, selectedLevel.value)
|
||||
}
|
||||
|
||||
async function copyLogs() {
|
||||
if (!props.content) return
|
||||
await navigator.clipboard.writeText(props.content)
|
||||
copied.value = true
|
||||
setTimeout(() => { copied.value = false }, 2000)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (open) => {
|
||||
if (open) {
|
||||
copied.value = false
|
||||
refresh()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppModal
|
||||
:model-value="modelValue"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
max-width="2xl"
|
||||
>
|
||||
<template #title>{{ title }}</template>
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-xs text-neutral-400">{{ t('logs.lines') }}</label>
|
||||
<select
|
||||
v-model="selectedLines"
|
||||
class="rounded-md border border-neutral-300 px-2 py-1 text-sm"
|
||||
@change="refresh"
|
||||
>
|
||||
<option v-for="n in lineOptions" :key="n" :value="n">{{ n }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="showLevelFilter" class="flex items-center gap-2">
|
||||
<label class="text-xs text-neutral-400">{{ t('logs.level') }}</label>
|
||||
<select
|
||||
v-model="selectedLevel"
|
||||
class="rounded-md border border-neutral-300 px-2 py-1 text-sm"
|
||||
@change="refresh"
|
||||
>
|
||||
<option value="">{{ t('logs.levelAll') }}</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
<option value="WARNING">WARNING</option>
|
||||
<option value="INFO">INFO</option>
|
||||
<option value="DEBUG">DEBUG</option>
|
||||
</select>
|
||||
</div>
|
||||
<MalioButtonIcon
|
||||
icon="mdi:refresh"
|
||||
:aria-label="t('logs.refresh')"
|
||||
icon-size="18"
|
||||
@click="refresh"
|
||||
/>
|
||||
</div>
|
||||
<MalioButtonIcon
|
||||
:icon="copied ? 'mdi:check' : 'mdi:content-copy'"
|
||||
:aria-label="t('logs.copy')"
|
||||
icon-size="18"
|
||||
:button-class="copied ? 'text-green-500' : ''"
|
||||
@click="copyLogs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<pre
|
||||
v-if="content"
|
||||
class="max-h-96 overflow-auto rounded-lg bg-neutral-900 p-4 text-xs text-green-400 font-mono whitespace-pre-wrap"
|
||||
>{{ content }}</pre>
|
||||
|
||||
<p v-else-if="!loading" class="text-center text-neutral-400 py-8">
|
||||
{{ t('logs.noContent') }}
|
||||
</p>
|
||||
|
||||
<template #footer>
|
||||
<MalioButton
|
||||
:label="t('applications.form.cancel')"
|
||||
variant="tertiary"
|
||||
@click="emit('update:modelValue', false)"
|
||||
/>
|
||||
</template>
|
||||
</AppModal>
|
||||
</template>
|
||||
@@ -2,9 +2,7 @@
|
||||
<NuxtLink
|
||||
:to="to"
|
||||
class="group/link relative flex items-center transition-colors hover:text-primary-500"
|
||||
:class="linkClasses"
|
||||
:active-class="exact ? '' : activeClass"
|
||||
:exact-active-class="exact ? activeClass : ''"
|
||||
:class="[linkClasses, isActive ? activeClass : '']"
|
||||
>
|
||||
<Icon :name="icon" :size="sub ? '20' : '24'" class="flex-shrink-0" />
|
||||
<span
|
||||
@@ -33,6 +31,15 @@ const props = defineProps<{
|
||||
exact?: boolean
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const isActive = computed(() => {
|
||||
if (props.exact) {
|
||||
return route.path === props.to
|
||||
}
|
||||
return route.path === props.to || route.path.startsWith(props.to + '/')
|
||||
})
|
||||
|
||||
const activeClass = computed(() => {
|
||||
if (props.collapsed) {
|
||||
return '!text-primary-500 bg-primary-500/10'
|
||||
|
||||
Reference in New Issue
Block a user