mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-14 09:43:22 -03:00
feat(delete): shorten undo window to 20s and make undo toast dismissible
This commit is contained in:
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "Gibt {size} frei",
|
||||
"title": "Modell löschen",
|
||||
"message": "Sind Sie sicher, dass Sie dieses Modell und alle zugehörigen Dateien löschen möchten?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "Die Datei wird nach 20 Sekunden endgültig gelöscht, sofern Sie nicht rückgängig machen."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "Diese Aktion kann 30 Sekunden lang rückgängig gemacht werden."
|
||||
"recoverableWarning": "Diese Aktion kann 20 Sekunden lang rückgängig gemacht werden."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "Modell ausschließen",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "Kopieren fehlgeschlagen"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "Rückgängig",
|
||||
"deleted": "Gelöscht: {name}",
|
||||
"deletedBulk": "{count} Element(e) gelöscht",
|
||||
"expired": "Undo-Fenster abgelaufen. Das Element wurde endgültig gelöscht.",
|
||||
"failed": "Rückgängig machen fehlgeschlagen: {error}",
|
||||
"restored": "Element wiederhergestellt"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "Fehler beim Laden der Elemente",
|
||||
|
||||
+2
-2
@@ -1280,10 +1280,10 @@
|
||||
"freesSpace": "Frees {size}",
|
||||
"title": "Delete Model",
|
||||
"message": "Are you sure you want to delete this model and all associated files?",
|
||||
"recoverableWarning": "This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "This will permanently delete the file after 20 seconds unless you undo."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "This action can be undone for 30 seconds."
|
||||
"recoverableWarning": "This action can be undone for 20 seconds."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "Exclude Model",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "Libera {size}",
|
||||
"title": "Eliminar modelo",
|
||||
"message": "¿Estás seguro de que quieres eliminar este modelo y todos los archivos asociados?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "El archivo se eliminará permanentemente después de 20 segundos a menos que deshaga la acción."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "Esta acción se puede deshacer durante 30 segundos."
|
||||
"recoverableWarning": "Esta acción se puede deshacer durante 20 segundos."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "Excluir modelo",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "Error al copiar"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "Deshacer",
|
||||
"deleted": "Eliminado: {name}",
|
||||
"deletedBulk": "{count} elemento(s) eliminado(s)",
|
||||
"expired": "La ventana de deshacer ha caducado. El elemento se eliminó permanentemente.",
|
||||
"failed": "No se pudo deshacer: {error}",
|
||||
"restored": "Elemento restaurado"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "Error al cargar elementos",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "Libère {size}",
|
||||
"title": "Supprimer le modèle",
|
||||
"message": "Êtes-vous sûr de vouloir supprimer ce modèle et tous les fichiers associés ?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "Le fichier sera définitivement supprimé après 20 secondes, sauf si vous annulez."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "Cette action peut être annulée pendant 30 secondes."
|
||||
"recoverableWarning": "Cette action peut être annulée pendant 20 secondes."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "Exclure le modèle",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "Échec de la copie"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "Annuler",
|
||||
"deleted": "Supprimé : {name}",
|
||||
"deletedBulk": "{count} élément(s) supprimé(s)",
|
||||
"expired": "La fenêtre d'annulation a expiré. L'élément a été définitivement supprimé.",
|
||||
"failed": "Échec de l'annulation : {error}",
|
||||
"restored": "Élément restauré"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "Échec du chargement des éléments",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "מפנה {size}",
|
||||
"title": "מחק מודל",
|
||||
"message": "האם אתה בטוח שברצונך למחוק מודל זה וכל הקבצים הנלווים?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "הקובץ יימחק לצמיתות לאחר 20 שניות, אלא אם תבטלו את הפעולה."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "ניתן לבטל פעולה זו תוך 30 שניות."
|
||||
"recoverableWarning": "ניתן לבטל פעולה זו תוך 20 שניות."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "החרג מודל",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "ההעתקה נכשלה"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "בטל",
|
||||
"deleted": "נמחק: {name}",
|
||||
"deletedBulk": "{count} פריטים נמחקו",
|
||||
"expired": "חלון הביטול פג. הפריט נמחק לצמיתות.",
|
||||
"failed": "הביטול נכשל: {error}",
|
||||
"restored": "הפריט שוחזר"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "טעינת הפריטים נכשלה",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "{size} を解放します",
|
||||
"title": "モデルを削除",
|
||||
"message": "このモデルと関連するすべてのファイルを削除してもよろしいですか?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "元に戻さない場合、このファイルは20秒後に完全に削除されます。"
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "この操作は30秒以内であれば元に戻せます。"
|
||||
"recoverableWarning": "この操作は20秒以内であれば元に戻せます。"
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "モデルを除外",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "コピーに失敗しました"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "元に戻す",
|
||||
"deleted": "{name} を削除しました",
|
||||
"deletedBulk": "{count} 個のアイテムを削除しました",
|
||||
"expired": "元に戻せる時間が経過しました。アイテムは完全に削除されました。",
|
||||
"failed": "元に戻せませんでした: {error}",
|
||||
"restored": "アイテムを復元しました"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "アイテムの読み込みに失敗しました",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "{size} 확보",
|
||||
"title": "모델 삭제",
|
||||
"message": "이 모델과 모든 관련 파일을 삭제하시겠습니까?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "실행 취소하지 않으면 20초 후에 파일이 영구적으로 삭제됩니다."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "이 작업은 30초 이내에 실행 취소할 수 있습니다."
|
||||
"recoverableWarning": "이 작업은 20초 이내에 실행 취소할 수 있습니다."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "모델 제외",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "복사 실패"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "실행 취소",
|
||||
"deleted": "{name} 삭제됨",
|
||||
"deletedBulk": "{count}개 항목 삭제됨",
|
||||
"expired": "실행 취소 기간이 만료되었습니다. 항목이 영구적으로 삭제되었습니다.",
|
||||
"failed": "실행 취소 실패: {error}",
|
||||
"restored": "항목이 복원되었습니다"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "항목 로딩 실패",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "Освобождает {size}",
|
||||
"title": "Удалить модель",
|
||||
"message": "Вы уверены, что хотите удалить эту модель и все связанные файлы?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "Файл будет удалён навсегда через 20 секунд, если вы не отмените действие."
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "Это действие можно отменить в течение 30 секунд."
|
||||
"recoverableWarning": "Это действие можно отменить в течение 20 секунд."
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "Исключить модель",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "Копирование не удалось"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "Отменить",
|
||||
"deleted": "Удалено: {name}",
|
||||
"deletedBulk": "Удалено: {count} шт.",
|
||||
"expired": "Время отмены истекло. Элемент был удалён навсегда.",
|
||||
"failed": "Не удалось отменить: {error}",
|
||||
"restored": "Элемент восстановлен"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "Не удалось загрузить элементы",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "释放 {size}",
|
||||
"title": "删除模型",
|
||||
"message": "你确定要删除此模型及所有相关文件吗?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "如果不撤销,文件将在 20 秒后被永久删除。"
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "此操作可在 30 秒内撤销。"
|
||||
"recoverableWarning": "此操作可在 20 秒内撤销。"
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "排除模型",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "复制失败"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "撤销",
|
||||
"deleted": "已删除 {name}",
|
||||
"deletedBulk": "已删除 {count} 个项目",
|
||||
"expired": "撤销窗口已过期,项目已被永久删除。",
|
||||
"failed": "撤销失败:{error}",
|
||||
"restored": "项目已恢复"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "加载项目失败",
|
||||
|
||||
+9
-9
@@ -1277,13 +1277,13 @@
|
||||
}
|
||||
},
|
||||
"deleteModel": {
|
||||
"freesSpace": "[TODO: Translate] Frees {size}",
|
||||
"freesSpace": "釋放 {size}",
|
||||
"title": "刪除模型",
|
||||
"message": "您確定要刪除此模型及所有相關檔案嗎?",
|
||||
"recoverableWarning": "[TODO: Translate] This will permanently delete the file after 30 seconds unless you undo."
|
||||
"recoverableWarning": "如果未復原,檔案將在 20 秒後被永久刪除。"
|
||||
},
|
||||
"deleteRecipe": {
|
||||
"recoverableWarning": "此操作可在 30 秒內復原。"
|
||||
"recoverableWarning": "此操作可在 20 秒內復原。"
|
||||
},
|
||||
"excludeModel": {
|
||||
"title": "排除模型",
|
||||
@@ -2120,12 +2120,12 @@
|
||||
"copyFailed": "複製失敗"
|
||||
},
|
||||
"undo": {
|
||||
"action": "[TODO: Translate] Undo",
|
||||
"deleted": "[TODO: Translate] Deleted {name}",
|
||||
"deletedBulk": "[TODO: Translate] Deleted {count} item(s)",
|
||||
"expired": "[TODO: Translate] Undo window expired. The item was permanently deleted.",
|
||||
"failed": "[TODO: Translate] Undo failed: {error}",
|
||||
"restored": "[TODO: Translate] Item restored"
|
||||
"action": "復原",
|
||||
"deleted": "已刪除 {name}",
|
||||
"deletedBulk": "已刪除 {count} 個項目",
|
||||
"expired": "復原視窗已過期,項目已被永久刪除。",
|
||||
"failed": "復原失敗:{error}",
|
||||
"restored": "項目已還原"
|
||||
},
|
||||
"virtual": {
|
||||
"loadFailed": "載入項目失敗",
|
||||
|
||||
@@ -43,7 +43,7 @@ from ..utils import settings_paths
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Undo window in seconds before a staged batch becomes purge-eligible.
|
||||
PENDING_DELETE_TTL_SECONDS = 30
|
||||
PENDING_DELETE_TTL_SECONDS = 20
|
||||
# Hidden staging directory name placed inside each deleted model's own folder
|
||||
# (sibling of the model artifacts) and under the settings dir for recipes.
|
||||
PENDING_DELETE_DIR_NAME = ".lm-pending-delete"
|
||||
|
||||
@@ -107,6 +107,24 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.toast-close-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 0 4px;
|
||||
background: transparent;
|
||||
color: var(--text-color);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1.1em;
|
||||
line-height: 1;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.toast-close-btn:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.toast {
|
||||
|
||||
@@ -236,11 +236,11 @@ export function showToast(key, params = {}, type = 'info', fallback = null) {
|
||||
* @param {Object} [options]
|
||||
* @param {string} [options.actionText] - Label for the action button (button omitted when empty)
|
||||
* @param {Function} [options.onAction] - Callback invoked at most once on button click
|
||||
* @param {number} [options.durationMs=30000] - How long the toast stays visible
|
||||
* @param {number} [options.durationMs=20000] - How long the toast stays visible
|
||||
* @param {boolean} [options.countdown=true] - Show a ticking `(N)s` countdown
|
||||
*/
|
||||
export function showActionToast(key, params = {}, type = 'info', options = {}) {
|
||||
const { actionText, onAction, durationMs = 30000, countdown = true } = options;
|
||||
const { actionText, onAction, durationMs = 20000, countdown = true } = options;
|
||||
|
||||
const isPlainMessage = typeof key === 'string' && /\s/.test(key);
|
||||
const message = isPlainMessage ? key : translate(key, params);
|
||||
@@ -295,6 +295,20 @@ export function showActionToast(key, params = {}, type = 'info', options = {}) {
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Manual close button: hides the toast early without firing onAction. The
|
||||
// backend undo window keeps running and the batch is purged when it expires.
|
||||
const closeBtn = document.createElement('button');
|
||||
closeBtn.type = 'button';
|
||||
closeBtn.className = 'toast-close-btn';
|
||||
closeBtn.textContent = '×';
|
||||
closeBtn.setAttribute('aria-label', translate('common.actions.close'));
|
||||
closeBtn.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
clearCountdown();
|
||||
dismiss();
|
||||
});
|
||||
toast.append(closeBtn);
|
||||
}
|
||||
|
||||
export function restoreFolderFilter() {
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('translate() with real en.json locale', () => {
|
||||
installWindowI18n();
|
||||
|
||||
expect(translate('modals.deleteModel.recoverableWarning')).toBe(
|
||||
'This will permanently delete the file after 30 seconds unless you undo.',
|
||||
'This will permanently delete the file after 20 seconds unless you undo.',
|
||||
);
|
||||
expect(translate('modals.deleteModel.freesSpace', { size: '1.2 MB' })).toBe(
|
||||
'Frees 1.2 MB',
|
||||
|
||||
@@ -133,14 +133,14 @@ describe('UI helper DOM utilities', () => {
|
||||
|
||||
const countdown = toast.querySelector('.toast-countdown');
|
||||
expect(countdown).not.toBeNull();
|
||||
expect(countdown.textContent).toBe('(30s)');
|
||||
expect(countdown.textContent).toBe('(20s)');
|
||||
|
||||
// Ticking one second updates the countdown text
|
||||
vi.advanceTimersByTime(1000);
|
||||
expect(countdown.textContent).toBe('(29s)');
|
||||
expect(countdown.textContent).toBe('(19s)');
|
||||
|
||||
// Drain remaining timers so no state leaks into other tests
|
||||
vi.advanceTimersByTime(30000);
|
||||
vi.advanceTimersByTime(20000);
|
||||
});
|
||||
|
||||
it('invokes onAction once and dismisses immediately when the button is clicked', async () => {
|
||||
@@ -186,6 +186,34 @@ describe('UI helper DOM utilities', () => {
|
||||
expect(onAction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('dismisses the toast via the close button without firing onAction', async () => {
|
||||
vi.useFakeTimers();
|
||||
translateMock.mockReturnValue('Deleted Demo Model');
|
||||
|
||||
const { showActionToast } = await import(UI_HELPERS_MODULE);
|
||||
|
||||
const onAction = vi.fn();
|
||||
showActionToast('toast.undo.deleted', {}, 'success', {
|
||||
actionText: 'Undo',
|
||||
onAction,
|
||||
});
|
||||
|
||||
const toast = document.querySelector('.toast-container .toast');
|
||||
const countdown = toast.querySelector('.toast-countdown');
|
||||
toast.querySelector('.toast-close-btn').click();
|
||||
|
||||
expect(onAction).not.toHaveBeenCalled();
|
||||
expect(toast.classList.contains('show')).toBe(false);
|
||||
|
||||
// Advancing past the full duration must not tick the countdown further,
|
||||
// throw, or re-dismiss the already-dismissed toast
|
||||
vi.advanceTimersByTime(60000);
|
||||
expect(countdown.textContent).toBe('(20s)');
|
||||
|
||||
toast.dispatchEvent(new Event('transitionend', { bubbles: true }));
|
||||
expect(document.querySelector('.toast-container .toast')).toBeNull();
|
||||
});
|
||||
|
||||
it('dismisses the toast when the countdown reaches zero', async () => {
|
||||
vi.useFakeTimers();
|
||||
translateMock.mockReturnValue('Deleted Demo Model');
|
||||
|
||||
Reference in New Issue
Block a user