refactor: use plain text for multi-line messages ni confirm dialog

This commit is contained in:
arabcoders 2026-04-18 20:18:41 +03:00
parent 9d1bde7355
commit 3f6149aaf7
9 changed files with 57 additions and 82 deletions

View file

@ -9,7 +9,7 @@
@after:enter="focusInput" @after:enter="focusInput"
> >
<template #body> <template #body>
<p v-if="state.current?.opts.message"> <p v-if="state.current?.opts.message" class="whitespace-pre-line wrap-break-word">
{{ state.current?.opts.message }} {{ state.current?.opts.message }}
</p> </p>
@ -23,14 +23,6 @@
/> />
</UFormField> </UFormField>
<div
v-else-if="
'confirm' === state.current?.type && (state.current?.opts as ConfirmOptions)?.rawHTML
"
class="max-h-[40vh] overflow-auto text-sm text-default"
v-html="(state.current?.opts as ConfirmOptions)?.rawHTML"
/>
<div <div
v-if=" v-if="
'confirm' === state.current?.type && 'confirm' === state.current?.type &&

View file

@ -52,10 +52,6 @@ export type ConfirmOptions = BaseOptions & {
* Text for the confirm button * Text for the confirm button
*/ */
cancelText?: string; cancelText?: string;
/**
* Raw HTML content to include in the dialog message.
*/
rawHTML?: string;
/** /**
* Optional checkbox-style options to return with the confirmation result. * Optional checkbox-style options to return with the confirmation result.
*/ */

View file

@ -934,15 +934,6 @@ const itemTypeLabel = (item: FileItem): string => {
return item.type === 'file' ? 'File' : ucFirst(item.type); return item.type === 'file' ? 'File' : ucFirst(item.type);
}; };
const escapeHtml = (value: string): string => {
return value
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;');
};
const toggleFilter = async (): Promise<void> => { const toggleFilter = async (): Promise<void> => {
show_filter.value = !show_filter.value; show_filter.value = !show_filter.value;
@ -1060,8 +1051,9 @@ const handleDeleteSelected = async (): Promise<void> => {
return; return;
} }
const rawHTML = const message =
'<ul>' + 'Delete the following items?' +
'\n\n' +
selectedElms.value selectedElms.value
.map((selectedPath) => { .map((selectedPath) => {
const item = items.value.find((entry) => entry.path === selectedPath); const item = items.value.find((entry) => entry.path === selectedPath);
@ -1069,15 +1061,14 @@ const handleDeleteSelected = async (): Promise<void> => {
return ''; return '';
} }
return `<li><strong>${escapeHtml(itemTypeLabel(item))}:</strong> ${escapeHtml(item.name)}</li>`; return `${itemTypeLabel(item)}: ${item.name}`;
}) })
.join('') + .filter(Boolean)
'</ul>'; .join('\n');
const { status } = await dialog.confirmDialog({ const { status } = await dialog.confirmDialog({
title: 'Delete Confirmation', title: 'Delete Confirmation',
message: 'Delete the following items?', message,
rawHTML,
confirmText: 'Delete', confirmText: 'Delete',
cancelText: 'Cancel', cancelText: 'Cancel',
confirmColor: 'error', confirmColor: 'error',

View file

@ -709,15 +709,16 @@ const deleteSelected = async (): Promise<void> => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Conditions', title: 'Delete Selected Conditions',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedIds.value.length}</strong> condition/s?<ul>` + `Delete ${selectedIds.value.length} condition/s?` +
'\n\n' +
selectedIds.value selectedIds.value
.map((id) => { .map((id) => {
const item = filteredItems.value.find((cond) => cond.id === id); const item = filteredItems.value.find((cond) => cond.id === id);
return item ? `<li>${item.id}: ${item.name}</li>` : ''; return item ? `${item.id}: ${item.name}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });

View file

@ -618,15 +618,16 @@ const deleteSelected = async (): Promise<void> => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Fields', title: 'Delete Selected Fields',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedIds.value.length}</strong> field/s?<ul>` + `Delete ${selectedIds.value.length} field/s?` +
'\n\n' +
selectedIds.value selectedIds.value
.map((id) => { .map((id) => {
const item = filteredItems.value.find((field) => field.id === id); const item = filteredItems.value.find((field) => field.id === id);
return item ? `<li>${item.id}: ${item.name}</li>` : ''; return item ? `${item.id}: ${item.name}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });

View file

@ -767,15 +767,16 @@ const deleteSelected = async (): Promise<void> => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Notifications', title: 'Delete Selected Notifications',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedIds.value.length}</strong> notification target/s?<ul>` + `Delete ${selectedIds.value.length} notification target/s?` +
'\n\n' +
selectedIds.value selectedIds.value
.map((id) => { .map((id) => {
const item = filteredTargets.value.find((target) => target.id === id); const item = filteredTargets.value.find((target) => target.id === id);
return item ? `<li>${item.id}: ${item.name}</li>` : ''; return item ? `${item.id}: ${item.name}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });

View file

@ -585,15 +585,16 @@ const deleteSelected = async (): Promise<void> => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Presets', title: 'Delete Selected Presets',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedIds.value.length}</strong> preset/s?<ul>` + `Delete ${selectedIds.value.length} preset/s?` +
'\n\n' +
selectedIds.value selectedIds.value
.map((id) => { .map((id) => {
const item = filteredPresets.value.find((preset) => preset.id === id); const item = filteredPresets.value.find((preset) => preset.id === id);
return item ? `<li>${item.id}: ${prettyName(item.name)}</li>` : ''; return item ? `${item.id}: ${prettyName(item.name)}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });

View file

@ -793,15 +793,16 @@ const deleteSelected = async (): Promise<void> => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Task Definitions', title: 'Delete Selected Task Definitions',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedIds.value.length}</strong> task definition/s?<ul>` + `Delete ${selectedIds.value.length} task definition/s?` +
'\n\n' +
selectedIds.value selectedIds.value
.map((id) => { .map((id) => {
const item = filteredDefinitions.value.find((definition) => definition.id === id); const item = filteredDefinitions.value.find((definition) => definition.id === id);
return item ? `<li>${item.id}: ${item.name || '(Unnamed definition)'}</li>` : ''; return item ? `${item.id}: ${item.name || '(Unnamed definition)'}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });

View file

@ -1000,15 +1000,16 @@ const deleteSelected = async () => {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
title: 'Delete Selected Tasks', title: 'Delete Selected Tasks',
rawHTML: message:
`Delete <strong class="text-red-500">${selectedElms.value.length}</strong> task/s?<ul>` + `Delete ${selectedElms.value.length} task/s?` +
'\n\n' +
selectedElms.value selectedElms.value
.map((id) => { .map((id) => {
const item = tasks.value.find((task) => task.id === id); const item = tasks.value.find((task) => task.id === id);
return item ? `<li>${item.id}: ${item.name}</li>` : ''; return item ? `${item.id}: ${item.name}` : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
confirmText: 'Delete', confirmText: 'Delete',
confirmColor: 'error', confirmColor: 'error',
}); });
@ -1151,15 +1152,16 @@ const runSelected = async () => {
} }
const { status } = await confirmDialog({ const { status } = await confirmDialog({
rawHTML: message:
'Run the following tasks?<ul>' + 'Run the following tasks?' +
'\n\n' +
selectedElms.value selectedElms.value
.map((id) => { .map((id) => {
const item = tasks.value.find((task) => task.id === id); const item = tasks.value.find((task) => task.id === id);
return item ? `<li>${item.name}</li>` : ''; return item ? item.name : '';
}) })
.join('') + .filter(Boolean)
'</ul>', .join('\n'),
}); });
if (true !== status) { if (true !== status) {
@ -1346,24 +1348,13 @@ const generateMeta = async (item: Task) => {
try { try {
const { status } = await confirmDialog({ const { status } = await confirmDialog({
rawHTML: ` message:
<p> `Generate '${item.name}' metadata? You will be notified when it is done.` +
Generate '${item.name}' metadata? you will be notified when it is done. '\n\nThis action will generate:' +
</p> '\n- tvshow.nfo - for media center compatibility' +
<p> '\n- title [id].info.json - yt-dlp metadata file' +
<b>This action will generate:</b> '\n- Thumbnails: poster.jpg, fanart.jpg, thumb.jpg, banner.jpg, icon.jpg, landscape.jpg if they are available.' +
<ul> '\n\nWarning: This will overwrite existing metadata files if they exist.',
<li><strong>tvshow.nfo</strong> - for media center compatibility</li>
<li><strong>title [id].info.json</strong> - yt-dlp metadata file</li>
<li>
<strong>Thumbnails</strong>: poster.jpg, fanart.jpg, thumb.jpg, banner.jpg, icon.jpg, landscape.jpg
<u>if they are available</u>.
</li>
</ul>
</p>
<p class="text-red-500">
<span>Warning</span>: This will overwrite existing metadata files if they exist.
</p>`,
}); });
if (true !== status) { if (true !== status) {