mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-28 19:47:49 +08:00
Improve logging dialogs and word rules layout
This commit is contained in:
@@ -51,8 +51,14 @@ function downloadLogger() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VDialog v-if="visible" v-model="visible" scrollable max-width="72rem" :fullscreen="!display.mdAndUp.value">
|
||||
<VCard>
|
||||
<VDialog
|
||||
v-if="visible"
|
||||
v-model="visible"
|
||||
:scrollable="display.mdAndUp.value"
|
||||
max-width="72rem"
|
||||
:fullscreen="!display.mdAndUp.value"
|
||||
>
|
||||
<VCard class="logging-dialog-card">
|
||||
<VDialogCloseBtn v-model="visible" />
|
||||
<VCardItem>
|
||||
<VCardTitle class="d-inline-flex">
|
||||
@@ -75,9 +81,29 @@ function downloadLogger() {
|
||||
</VCardTitle>
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardText class="pa-0">
|
||||
<VCardText class="logging-dialog-content pa-0">
|
||||
<LoggingView :logfile="`plugins/${props.plugin?.id?.toLowerCase()}.log`" />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (width <= 960px) {
|
||||
.logging-dialog-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.logging-dialog-content {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
inline-size: 100%;
|
||||
min-block-size: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -42,8 +42,14 @@ function allLoggingDownloadUrl() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VDialog v-if="visible" v-model="visible" scrollable max-width="80rem" :fullscreen="!display.mdAndUp.value">
|
||||
<VCard>
|
||||
<VDialog
|
||||
v-if="visible"
|
||||
v-model="visible"
|
||||
:scrollable="display.mdAndUp.value"
|
||||
max-width="80rem"
|
||||
:fullscreen="!display.mdAndUp.value"
|
||||
>
|
||||
<VCard class="logging-dialog-card">
|
||||
<VDialogCloseBtn v-model="visible" />
|
||||
<VCardItem>
|
||||
<VCardTitle class="d-inline-flex">
|
||||
@@ -66,9 +72,29 @@ function allLoggingDownloadUrl() {
|
||||
</VCardTitle>
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardText class="pa-0">
|
||||
<VCardText class="logging-dialog-content pa-0">
|
||||
<LoggingView logfile="moviepilot.log" />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (width <= 960px) {
|
||||
.logging-dialog-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.logging-dialog-content {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
inline-size: 100%;
|
||||
min-block-size: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2109,7 +2109,7 @@ export default {
|
||||
episodeFormatRuleShort: 'Episode rules',
|
||||
customIdentifiers: 'Custom Identifiers',
|
||||
identifiersDesc: 'Add rules to preprocess torrent names or file names to correct identification',
|
||||
identifiersPlaceholder: 'Support regular expressions, special characters need \\ escape, one line for each rule',
|
||||
identifiersPlaceholder: 'Enter one identifier rule per line',
|
||||
identifiersHint: 'Support regular expressions, special characters need \\ escape, one line for each rule',
|
||||
formatTitle: 'Supported configuration formats (mind the spaces):',
|
||||
formatContent:
|
||||
@@ -2123,16 +2123,14 @@ export default {
|
||||
|
||||
customReleaseGroups: 'Custom Release/Subtitle Groups',
|
||||
releaseGroupsDesc: 'Add release/subtitle groups that cannot be identified.',
|
||||
releaseGroupsPlaceholder:
|
||||
'Support regular expressions, special characters need \\ escape, one line for each group',
|
||||
releaseGroupsPlaceholder: 'Enter one release/subtitle group per line',
|
||||
releaseGroupsHint: 'Support regular expressions, special characters need \\ escape, one line for each group',
|
||||
releaseGroupSaveSuccess: 'Custom release/subtitle groups saved successfully',
|
||||
releaseGroupSaveFailed: 'Failed to save custom release/subtitle groups!',
|
||||
|
||||
customization: 'Custom Placeholders',
|
||||
customizationDesc: 'Add custom placeholder regex patterns, use {customization} in rename format.',
|
||||
customizationPlaceholder:
|
||||
'Support regular expressions, special characters need \\ escape, separate multiple matches with new lines',
|
||||
customizationPlaceholder: 'Enter one placeholder regex per line',
|
||||
customizationHint:
|
||||
'Support regular expressions, special characters need \\ escape, separate multiple matches with new lines',
|
||||
customizationSaveSuccess: 'Custom placeholders saved successfully',
|
||||
@@ -2140,8 +2138,7 @@ export default {
|
||||
|
||||
transferExcludeWords: 'File Organization Block Words',
|
||||
excludeWordsDesc: 'Files or directories containing block words will not be organized.',
|
||||
excludeWordsPlaceholder:
|
||||
'Support regular expressions, special characters need \\ escape, one line for each block word',
|
||||
excludeWordsPlaceholder: 'Enter one block word per line',
|
||||
excludeWordsHint: 'Support regular expressions, special characters need \\ escape, one line for each block word',
|
||||
excludeWordsSaveSuccess: 'File organization block words saved successfully',
|
||||
excludeWordsSaveFailed: 'Failed to save file organization block words!',
|
||||
|
||||
@@ -2073,7 +2073,7 @@ export default {
|
||||
episodeFormatRuleShort: '集数规则',
|
||||
customIdentifiers: '自定义识别词',
|
||||
identifiersDesc: '添加规则对种子名或者文件名进行预处理以校正识别',
|
||||
identifiersPlaceholder: '支持正则表达式,特殊字符需要\\转义,一行为一组',
|
||||
identifiersPlaceholder: '每行输入一组识别规则',
|
||||
identifiersHint: '支持正则表达式,特殊字符需要\\转义,一行为一组',
|
||||
formatTitle: '支持的配置格式(注意空格):',
|
||||
formatContent:
|
||||
@@ -2087,21 +2087,21 @@ export default {
|
||||
|
||||
customReleaseGroups: '自定义制作组/字幕组',
|
||||
releaseGroupsDesc: '添加无法识别的制作组/字幕组。',
|
||||
releaseGroupsPlaceholder: '支持正则表达式,特殊字符需要\\转义,一行代表一个制作组/字幕组',
|
||||
releaseGroupsPlaceholder: '每行输入一个制作组/字幕组',
|
||||
releaseGroupsHint: '支持正则表达式,特殊字符需要\\转义,一行代表一个制作组/字幕组',
|
||||
releaseGroupSaveSuccess: '自定义制作组/字幕组保存成功',
|
||||
releaseGroupSaveFailed: '自定义制作组/字幕组保存失败!',
|
||||
|
||||
customization: '自定义占位符',
|
||||
customizationDesc: '添加自定义占位符识别正则,重命名格式中添加{customization}使用。',
|
||||
customizationPlaceholder: '支持正则表达式,特殊字符需要\\转义,多个匹配对象请换行分隔',
|
||||
customizationPlaceholder: '每行输入一个占位符识别正则',
|
||||
customizationHint: '支持正则表达式,特殊字符需要\\转义,多个匹配对象请换行分隔',
|
||||
customizationSaveSuccess: '自定义占位符保存成功',
|
||||
customizationSaveFailed: '自定义占位符保存失败!',
|
||||
|
||||
transferExcludeWords: '文件整理屏蔽词',
|
||||
excludeWordsDesc: '目录名或文件名中包含屏蔽词时不进行整理。',
|
||||
excludeWordsPlaceholder: '支持正则表达式,特殊字符需要\\转义,一行代表一个屏蔽词',
|
||||
excludeWordsPlaceholder: '每行输入一个屏蔽词',
|
||||
excludeWordsHint: '支持正则表达式,特殊字符需要\\转义,一行代表一个屏蔽词',
|
||||
excludeWordsSaveSuccess: '文件整理屏蔽词保存成功',
|
||||
excludeWordsSaveFailed: '文件整理屏蔽词保存失败!',
|
||||
|
||||
@@ -2072,7 +2072,7 @@ export default {
|
||||
episodeFormatRuleShort: '集數規則',
|
||||
customIdentifiers: '自定義識別詞',
|
||||
identifiersDesc: '添加規則對種子名或者文件名進行預處理以校正識別',
|
||||
identifiersPlaceholder: '支持正則表達式,特殊字符需要\\轉義,一行為一組',
|
||||
identifiersPlaceholder: '每行輸入一組識別規則',
|
||||
identifiersHint: '支持正則表達式,特殊字符需要\\轉義,一行為一組',
|
||||
formatTitle: '支持的配置格式(注意空格):',
|
||||
formatContent:
|
||||
@@ -2086,21 +2086,21 @@ export default {
|
||||
|
||||
customReleaseGroups: '自定義製作組/字幕組',
|
||||
releaseGroupsDesc: '添加無法識別的製作組/字幕組。',
|
||||
releaseGroupsPlaceholder: '支持正則表達式,特殊字符需要\\轉義,一行代表一個製作組/字幕組',
|
||||
releaseGroupsPlaceholder: '每行輸入一個製作組/字幕組',
|
||||
releaseGroupsHint: '支持正則表達式,特殊字符需要\\轉義,一行代表一個製作組/字幕組',
|
||||
releaseGroupSaveSuccess: '自定義製作組/字幕組保存成功',
|
||||
releaseGroupSaveFailed: '自定義製作組/字幕組保存失敗!',
|
||||
|
||||
customization: '自定義占位符',
|
||||
customizationDesc: '添加自定義占位符識別正則,重命名格式中添加{customization}使用。',
|
||||
customizationPlaceholder: '支持正則表達式,特殊字符需要\\轉義,多個匹配對象請換行分隔',
|
||||
customizationPlaceholder: '每行輸入一個占位符識別正則',
|
||||
customizationHint: '支持正則表達式,特殊字符需要\\轉義,多個匹配對象請換行分隔',
|
||||
customizationSaveSuccess: '自定義占位符保存成功',
|
||||
customizationSaveFailed: '自定義占位符保存失敗!',
|
||||
|
||||
transferExcludeWords: '文件整理屏蔽詞',
|
||||
excludeWordsDesc: '目錄名或文件名中包含屏蔽詞時不進行整理。',
|
||||
excludeWordsPlaceholder: '支持正則表達式,特殊字符需要\\轉義,一行代表一個屏蔽詞',
|
||||
excludeWordsPlaceholder: '每行輸入一個屏蔽詞',
|
||||
excludeWordsHint: '支持正則表達式,特殊字符需要\\轉義,一行代表一個屏蔽詞',
|
||||
excludeWordsSaveSuccess: '文件整理屏蔽詞保存成功',
|
||||
excludeWordsSaveFailed: '文件整理屏蔽詞保存失敗!',
|
||||
|
||||
@@ -48,7 +48,8 @@ const theme = useTheme()
|
||||
const display = useDisplay()
|
||||
const { useSSE } = useBackground()
|
||||
|
||||
const DEFAULT_LEVELS = ['TRACE', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
|
||||
const DEFAULT_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR']
|
||||
const HIDDEN_LEVELS = ['TRACE', 'CRITICAL']
|
||||
const MAX_LOG_LINES = 600
|
||||
const FLUSH_DELAY = 80
|
||||
const GROUP_GAP_MS = 100
|
||||
@@ -86,12 +87,12 @@ const isTransparentTheme = computed(() => theme.name.value === 'transparent')
|
||||
const normalizedSearchQuery = computed(() => (searchQuery.value ?? '').trim().toLowerCase())
|
||||
const { availableHeight } = useAvailableHeight(96, 320)
|
||||
|
||||
const loggingViewStyle = computed(() => ({
|
||||
blockSize: display.mdAndUp.value ? `${availableHeight.value}px` : '100%',
|
||||
}))
|
||||
const loggingViewStyle = computed(() => (display.mdAndUp.value ? { blockSize: `${availableHeight.value}px` } : {}))
|
||||
|
||||
const levelOptions = computed(() => {
|
||||
const extraLevels = parsedLogs.value.map(item => item.level).filter(level => level && !DEFAULT_LEVELS.includes(level))
|
||||
const extraLevels = parsedLogs.value
|
||||
.map(item => item.level)
|
||||
.filter(level => level && !DEFAULT_LEVELS.includes(level) && !HIDDEN_LEVELS.includes(level))
|
||||
|
||||
return ['ALL', ...DEFAULT_LEVELS, ...new Set(extraLevels)]
|
||||
})
|
||||
@@ -700,6 +701,7 @@ onUnmounted(() => {
|
||||
--logging-record-bg-even: rgba(var(--v-theme-surface-variant), 0.01);
|
||||
--logging-record-bg-odd: rgba(var(--v-theme-surface-variant), 0.005);
|
||||
--logging-text: rgba(var(--v-theme-on-surface), 0.88);
|
||||
--logging-toolbar-control-size: 2rem;
|
||||
--logging-muted: rgba(var(--v-theme-on-surface), 0.56);
|
||||
|
||||
display: flex;
|
||||
@@ -770,7 +772,7 @@ onUnmounted(() => {
|
||||
border: 1px solid rgba(var(--v-theme-on-surface), 0.14);
|
||||
border-radius: var(--app-control-radius);
|
||||
background: transparent;
|
||||
block-size: 2rem;
|
||||
block-size: var(--logging-toolbar-control-size);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -787,7 +789,6 @@ onUnmounted(() => {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.logging-level-toggle :deep(.logging-level-toggle__button--trace),
|
||||
.logging-level-toggle :deep(.logging-level-toggle__button--debug) {
|
||||
color: rgb(var(--v-theme-secondary));
|
||||
}
|
||||
@@ -800,8 +801,7 @@ onUnmounted(() => {
|
||||
color: rgb(var(--v-theme-warning));
|
||||
}
|
||||
|
||||
.logging-level-toggle :deep(.logging-level-toggle__button--error),
|
||||
.logging-level-toggle :deep(.logging-level-toggle__button--critical) {
|
||||
.logging-level-toggle :deep(.logging-level-toggle__button--error) {
|
||||
color: rgb(var(--v-theme-error));
|
||||
}
|
||||
|
||||
@@ -825,6 +825,46 @@ onUnmounted(() => {
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
@media (width >= 960px) {
|
||||
.logging-toolbar {
|
||||
padding-block-start: 0.25rem;
|
||||
}
|
||||
|
||||
.logging-search,
|
||||
.logging-stream-action {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.logging-search :deep(.v-field) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
block-size: var(--logging-toolbar-control-size);
|
||||
min-block-size: var(--logging-toolbar-control-size);
|
||||
}
|
||||
|
||||
.logging-search :deep(.v-field__field),
|
||||
.logging-search :deep(.v-field__input),
|
||||
.logging-search :deep(.v-field__prepend-inner),
|
||||
.logging-search :deep(.v-field__clearable) {
|
||||
align-items: center;
|
||||
min-block-size: var(--logging-toolbar-control-size);
|
||||
}
|
||||
|
||||
.logging-search :deep(.v-field__input) {
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
.logging-search :deep(.v-field__prepend-inner),
|
||||
.logging-search :deep(.v-field__clearable) {
|
||||
padding-block: 0;
|
||||
}
|
||||
|
||||
.logging-stream-action {
|
||||
block-size: var(--logging-toolbar-control-size);
|
||||
inline-size: var(--logging-toolbar-control-size);
|
||||
}
|
||||
}
|
||||
|
||||
.logging-shell {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
@@ -1055,6 +1095,12 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
@media (width <= 960px) {
|
||||
.logging-view {
|
||||
flex: 1 1 auto;
|
||||
block-size: auto;
|
||||
min-block-size: 0;
|
||||
}
|
||||
|
||||
.logging-record {
|
||||
gap: 0.375rem;
|
||||
grid-template-columns: 9.5rem minmax(0, 1fr);
|
||||
|
||||
@@ -182,6 +182,11 @@ const activeGuideContent = computed(() => {
|
||||
return activeTextHint.value
|
||||
})
|
||||
|
||||
// 仅在提示内容能补充行内说明时展示折叠面板,避免捷径弹窗内重复出现相同文案。
|
||||
const shouldShowGuidePanel = computed(
|
||||
() => activeSection.value === 'identifiers' || activeSection.value === 'episodeRules',
|
||||
)
|
||||
|
||||
/** 生成仅供前端拖拽列表使用的稳定规则标识。 */
|
||||
function createEpisodeRuleLocalId() {
|
||||
return `episode-rule-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`
|
||||
@@ -519,16 +524,6 @@ onMounted(() => {
|
||||
:label="t('common.enable')"
|
||||
class="episode-rule-enabled"
|
||||
/>
|
||||
<IconBtn
|
||||
variant="text"
|
||||
color="error"
|
||||
class="episode-rule-delete"
|
||||
:aria-label="t('common.delete')"
|
||||
@click.stop="deleteEpisodeRule(index)"
|
||||
>
|
||||
<VIcon icon="mdi-delete-outline" />
|
||||
<VTooltip activator="parent" location="top">{{ t('common.delete') }}</VTooltip>
|
||||
</IconBtn>
|
||||
</div>
|
||||
|
||||
<VTextField
|
||||
@@ -557,6 +552,16 @@ onMounted(() => {
|
||||
required
|
||||
class="episode-rule-size"
|
||||
/>
|
||||
<IconBtn
|
||||
variant="text"
|
||||
color="error"
|
||||
class="episode-rule-delete"
|
||||
:aria-label="t('common.delete')"
|
||||
@click.stop="deleteEpisodeRule(index)"
|
||||
>
|
||||
<VIcon icon="mdi-delete-outline" />
|
||||
<VTooltip activator="parent" location="top">{{ t('common.delete') }}</VTooltip>
|
||||
</IconBtn>
|
||||
</article>
|
||||
</template>
|
||||
</Draggable>
|
||||
@@ -567,7 +572,12 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<VExpansionPanels v-model="expandedHelp" class="words-help-panels" variant="accordion">
|
||||
<VExpansionPanels
|
||||
v-if="shouldShowGuidePanel"
|
||||
v-model="expandedHelp"
|
||||
class="words-help-panels"
|
||||
variant="accordion"
|
||||
>
|
||||
<VExpansionPanel value="guide" elevation="0">
|
||||
<VExpansionPanelTitle>
|
||||
<template #default>
|
||||
@@ -908,8 +918,10 @@ onMounted(() => {
|
||||
border-radius: var(--app-surface-radius);
|
||||
background: transparent;
|
||||
gap: 0.75rem;
|
||||
grid-template-areas: 'toolbar name pattern size';
|
||||
grid-template-columns: max-content minmax(7rem, 0.8fr) minmax(13rem, 2fr) minmax(7rem, 0.65fr);
|
||||
grid-template-areas:
|
||||
'toolbar name size delete'
|
||||
'pattern pattern pattern pattern';
|
||||
grid-template-columns: max-content minmax(10rem, 1fr) minmax(9rem, 11rem) max-content;
|
||||
padding: 0.85rem;
|
||||
}
|
||||
|
||||
@@ -917,7 +929,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
min-block-size: 3.5rem;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
gap: 0.3rem;
|
||||
grid-area: toolbar;
|
||||
}
|
||||
|
||||
@@ -941,6 +953,12 @@ onMounted(() => {
|
||||
grid-area: size;
|
||||
}
|
||||
|
||||
.episode-rule-delete {
|
||||
align-self: center;
|
||||
grid-area: delete;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.words-empty-state {
|
||||
display: flex;
|
||||
min-block-size: 10rem;
|
||||
@@ -1072,11 +1090,11 @@ onMounted(() => {
|
||||
|
||||
.episode-rule-card {
|
||||
grid-template-areas:
|
||||
'toolbar'
|
||||
'name'
|
||||
'pattern'
|
||||
'size';
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
'toolbar delete'
|
||||
'name name'
|
||||
'pattern pattern'
|
||||
'size size';
|
||||
grid-template-columns: minmax(0, 1fr) max-content;
|
||||
gap: 0.75rem;
|
||||
padding: 0.95rem;
|
||||
}
|
||||
@@ -1086,7 +1104,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.episode-rule-delete {
|
||||
margin-inline-start: auto;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.episode-rule-enabled :deep(.v-label) {
|
||||
|
||||
Reference in New Issue
Block a user