mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
cc25bb3dc2
The folder context menu now reads: the content action (check for updates) on top, then the folder operations as one group (new subfolder, rename), then the destructive entry behind its own divider. Gating the three folder entries per page could leave the menu with dangling separators — the recipes sidebar hides all of them and keeps only the update check, which already rendered one stray divider before this change and would have rendered two after it. Add _updateContextMenuSeparators: a divider survives only when a visible entry sits on both sides, and a run of consecutive ones collapses to a single line. The three per-item display toggles fold into one loop. The template order is guarded by a regression test that parses templates/components/context_menu.html, plus behaviour tests for the divider collapsing.
271 lines
15 KiB
HTML
271 lines
15 KiB
HTML
<div id="loraContextMenu" class="context-menu">
|
|
<!-- <div class="context-menu-item" data-action="detail">
|
|
<i class="fas fa-info-circle"></i> Show Details
|
|
</div> -->
|
|
<!-- <div class="context-menu-item" data-action="civitai">
|
|
<i class="fas fa-external-link-alt"></i> View on Civitai
|
|
</div> -->
|
|
<!-- Metadata -->
|
|
<div class="context-menu-item" data-action="refresh-metadata">
|
|
<i class="fas fa-sync"></i> <span>{{ t('loras.contextMenu.refreshMetadata') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="check-updates">
|
|
<i class="fas fa-bell"></i> <span>{{ t('loras.contextMenu.checkUpdates') }}</span>
|
|
</div>
|
|
<div class="context-menu-item has-submenu" data-has-submenu="link-model">
|
|
<i class="fas fa-link"></i>
|
|
<span>{{ t('loras.contextMenu.linkModel') }}</span>
|
|
<i class="fas fa-chevron-right submenu-arrow"></i>
|
|
<div class="context-submenu">
|
|
<div class="context-menu-item" data-action="relink-civitai">
|
|
<i class="fas fa-external-link-alt"></i> <span>{{ t('loras.contextMenu.linkCivitai') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="link-hf">
|
|
<i class="fas fa-robot"></i> <span>{{ t('loras.contextMenu.linkModelSource') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-item" data-action="enrich-hf-llm">
|
|
<i class="fas fa-wand-magic-sparkles"></i> <span>{{ t('loras.contextMenu.enrichHfAgent') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator menu-section-break"></div>
|
|
<!-- Workflow -->
|
|
<div class="context-menu-item" data-action="copyname">
|
|
<i class="fas fa-copy"></i> <span>{{ t('loras.contextMenu.copySyntax') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="sendappend">
|
|
<i class="fas fa-paper-plane"></i> <span>{{ t('loras.contextMenu.sendToWorkflowAppend') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="sendreplace">
|
|
<i class="fas fa-exchange-alt"></i> <span>{{ t('loras.contextMenu.sendToWorkflowReplace') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator menu-section-break"></div>
|
|
<!-- Media / Preview -->
|
|
<div class="context-menu-item" data-action="preview">
|
|
<i class="fas fa-folder-open"></i> <span>{{ t('loras.contextMenu.openExamples') }}</span>
|
|
</div>
|
|
<div class="context-menu-item has-submenu" data-has-submenu="download-examples">
|
|
<i class="fas fa-download"></i>
|
|
<span>{{ t('loras.contextMenu.downloadExamples') }}</span>
|
|
<i class="fas fa-chevron-right submenu-arrow"></i>
|
|
<div class="context-submenu">
|
|
<div class="context-menu-item" data-action="download-examples">
|
|
<i class="fas fa-download"></i> <span>{{ t('loras.contextMenu.downloadMissingExamples') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="download-examples-force">
|
|
<i class="fas fa-redo-alt"></i> <span>{{ t('loras.contextMenu.reprocessExamples') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-item" data-action="replace-preview">
|
|
<i class="fas fa-image"></i> <span>{{ t('loras.contextMenu.replacePreview') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator menu-section-break"></div>
|
|
<!-- Attributes -->
|
|
<div class="context-menu-item" data-action="set-nsfw">
|
|
<i class="fas fa-exclamation-triangle"></i> <span>{{ t('loras.contextMenu.setContentRating') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator menu-section-break"></div>
|
|
<!-- Organization -->
|
|
<div class="context-menu-item" data-action="move">
|
|
<i class="fas fa-folder-open"></i> <span>{{ t('loras.contextMenu.moveToFolder') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<!-- Destructive -->
|
|
<div class="context-menu-item" data-action="exclude">
|
|
<i class="fas fa-eye-slash"></i> <span>{{ t('loras.contextMenu.excludeModel') }}</span>
|
|
</div>
|
|
<div class="context-menu-item delete-item" data-action="delete">
|
|
<i class="fas fa-trash"></i> <span>{{ t('loras.contextMenu.deleteModel') }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="bulkContextMenu" class="context-menu">
|
|
<div class="bulk-context-header">
|
|
<i class="fas fa-th-large"></i>
|
|
<span>{{ t('loras.bulkOperations.selected', {'count': 0}) }}</span>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-section" data-section="metadata">
|
|
<div class="context-menu-section-header">{{ t('loras.bulkOperations.sections.metadata') }}</div>
|
|
<div class="context-menu-item" data-action="refresh-all">
|
|
<i class="fas fa-sync-alt"></i> <span>{{ t('loras.bulkOperations.refreshAll') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="check-updates">
|
|
<i class="fas fa-bell"></i> <span>{{ t('loras.bulkOperations.checkUpdates') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="rematch-metadata">
|
|
<i class="fas fa-link"></i> <span>{{ t('loras.bulkOperations.rematchMetadata') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="reimport-metadata">
|
|
<i class="fas fa-undo-alt"></i> <span>{{ t('loras.bulkOperations.reimportMetadata') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="skip-metadata-refresh">
|
|
<i class="fas fa-ban"></i> <span>{{ t('loras.bulkOperations.skipMetadataRefresh') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="resume-metadata-refresh">
|
|
<i class="fas fa-redo"></i> <span>{{ t('loras.bulkOperations.resumeMetadataRefresh') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="enrich-hf-llm-bulk">
|
|
<i class="fas fa-wand-magic-sparkles"></i> <span>{{ t('loras.bulkOperations.enrichHfAgent') }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-section" data-section="workflow">
|
|
<div class="context-menu-section-header">{{ t('loras.bulkOperations.sections.workflow') }}</div>
|
|
<div class="context-menu-item has-submenu" data-has-submenu="send-to-workflow">
|
|
<i class="fas fa-paper-plane"></i>
|
|
<span>{{ t('loras.bulkOperations.sendToWorkflow') }}</span>
|
|
<i class="fas fa-chevron-right submenu-arrow"></i>
|
|
<div class="context-submenu">
|
|
<div class="context-menu-item" data-action="send-to-workflow-append">
|
|
<i class="fas fa-paper-plane"></i> <span>{{ t('loras.contextMenu.sendToWorkflowAppend') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="send-to-workflow-replace">
|
|
<i class="fas fa-exchange-alt"></i> <span>{{ t('loras.contextMenu.sendToWorkflowReplace') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="copy-all">
|
|
<i class="fas fa-copy"></i> <span>{{ t('loras.bulkOperations.copyAll') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-section" data-section="attributes">
|
|
<div class="context-menu-section-header">{{ t('loras.bulkOperations.sections.attributes') }}</div>
|
|
<div class="context-menu-item" data-action="add-tags">
|
|
<i class="fas fa-tags"></i> <span>{{ t('loras.bulkOperations.addTags') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="set-base-model">
|
|
<i class="fas fa-layer-group"></i> <span>{{ t('loras.bulkOperations.setBaseModel') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="set-favorite">
|
|
<i class="fas fa-star"></i> <span>{{ t('loras.bulkOperations.setFavorite') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="set-content-rating">
|
|
<i class="fas fa-exclamation-triangle"></i> <span>{{ t('loras.bulkOperations.setContentRating') }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-section" data-section="download">
|
|
<div class="context-menu-section-header">{{ t('loras.bulkOperations.sections.download') }}</div>
|
|
<div class="context-menu-item has-submenu" data-has-submenu="download-example-images">
|
|
<i class="fas fa-download"></i>
|
|
<span>{{ t('loras.bulkOperations.downloadExamples') }}</span>
|
|
<i class="fas fa-chevron-right submenu-arrow"></i>
|
|
<div class="context-submenu">
|
|
<div class="context-menu-item" data-action="download-missing-example-images">
|
|
<i class="fas fa-download"></i> <span>{{ t('loras.bulkOperations.downloadMissingExamples') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="download-example-images">
|
|
<i class="fas fa-redo-alt"></i> <span>{{ t('loras.bulkOperations.reprocessExamples') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-item" data-action="download-missing-loras">
|
|
<i class="fas fa-download"></i> <span>{{ t('loras.bulkOperations.downloadMissingLoras') }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-section" data-section="organize">
|
|
<div class="context-menu-section-header">{{ t('loras.bulkOperations.sections.organize') }}</div>
|
|
<div class="context-menu-item" data-action="auto-organize">
|
|
<i class="fas fa-magic"></i> <span>{{ t('loras.bulkOperations.autoOrganize') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="move-all">
|
|
<i class="fas fa-folder-open"></i> <span>{{ t('loras.bulkOperations.moveAll') }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-item delete-item" data-action="delete-all">
|
|
<i class="fas fa-trash"></i> <span>{{ t('loras.bulkOperations.deleteAll') }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="globalContextMenu" class="context-menu">
|
|
<div class="context-menu-item" data-action="download-example-images">
|
|
<i class="fas fa-download"></i> <span>{{ t('globalContextMenu.downloadExampleImages.label') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="check-model-updates">
|
|
<i class="fas fa-sync-alt"></i> <span>{{ t('globalContextMenu.checkModelUpdates.label') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="fetch-missing-licenses">
|
|
<i class="fas fa-shield-alt"></i> <span>{{ t('globalContextMenu.fetchMissingLicenses.label') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="cleanup-example-images-folders">
|
|
<i class="fas fa-trash-restore"></i> <span>{{ t('globalContextMenu.cleanupExampleImages.label') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="manage-excluded-models">
|
|
<i class="fas fa-eye-slash"></i> <span>{{ t('globalContextMenu.manageExcludedModels.label', default='Manage Excluded Models') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-item" data-action="toggle-group-by-model">
|
|
<i class="fas fa-layer-group"></i> <span>{{ t('globalContextMenu.groupByModel.label') }}</span>
|
|
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
|
|
</div>
|
|
<div class="context-menu-item" data-action="rematch-recipes">
|
|
<i class="fas fa-link"></i> <span>{{ t('globalContextMenu.rematchRecipes.label') }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar Folder Context Menu -->
|
|
<!-- Order: the content action (update check) first, then the folder operations
|
|
as one group, then the destructive action behind its own divider. The
|
|
dividers are collapsed by SidebarManager when a group is hidden on the
|
|
current page (recipes keep only the update check). -->
|
|
<div id="sidebarFolderContextMenu" class="context-menu">
|
|
<div class="context-menu-item" data-action="check-folder-updates">
|
|
<i class="fas fa-bell"></i> <span>{{ t('sidebar.folderUpdateCheck.label') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-item" data-action="create-subfolder">
|
|
<i class="fas fa-folder-plus"></i> <span>{{ t('sidebar.newSubfolder') }}</span>
|
|
</div>
|
|
<div class="context-menu-item" data-action="rename-folder">
|
|
<i class="fas fa-i-cursor"></i> <span>{{ t('sidebar.renameFolder') }}</span>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-item delete-item" data-action="delete-folder">
|
|
<i class="fas fa-trash"></i> <span>{{ t('sidebar.deleteFolder') }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar View Options Menu -->
|
|
<div id="sidebarViewOptionsMenu" class="context-menu">
|
|
<div class="context-menu-item" data-action="view-mode-tree">
|
|
<i class="fas fa-sitemap"></i> <span>{{ t('sidebar.treeView') }}</span>
|
|
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
|
|
</div>
|
|
<div class="context-menu-item" data-action="view-mode-list">
|
|
<i class="fas fa-list"></i> <span>{{ t('sidebar.listView') }}</span>
|
|
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
|
|
</div>
|
|
<div class="context-menu-separator"></div>
|
|
<div class="context-menu-item" data-action="toggle-recursive">
|
|
<i class="fas fa-code-branch"></i> <span>{{ t('sidebar.recursiveOn') }}</span>
|
|
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
|
|
</div>
|
|
<div class="context-menu-item" data-action="toggle-empty-folders">
|
|
<i class="fas fa-folder-open"></i> <span>{{ t('sidebar.showEmptyFolders') }}</span>
|
|
<i class="fas fa-check check-indicator" style="margin-left:auto;display:none"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="nsfwLevelSelector" class="nsfw-level-selector">
|
|
<div class="nsfw-level-header">
|
|
<h3>{{ t('modals.contentRating.title') }}</h3>
|
|
<button class="close-nsfw-selector"><i class="fas fa-times"></i></button>
|
|
</div>
|
|
<div class="nsfw-level-content">
|
|
<div class="current-level"><span>{{ t('modals.contentRating.current') }}:</span> <span id="currentNSFWLevel">{{
|
|
t('common.status.unknown') }}</span></div>
|
|
<div class="nsfw-level-options">
|
|
<button class="nsfw-level-btn" data-level="1">{{ t('modals.contentRating.levels.pg') }}</button>
|
|
<button class="nsfw-level-btn" data-level="2">{{ t('modals.contentRating.levels.pg13') }}</button>
|
|
<button class="nsfw-level-btn" data-level="4">{{ t('modals.contentRating.levels.r') }}</button>
|
|
<button class="nsfw-level-btn" data-level="8">{{ t('modals.contentRating.levels.x') }}</button>
|
|
<button class="nsfw-level-btn" data-level="16">{{ t('modals.contentRating.levels.xxx') }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="nodeSelector" class="node-selector">
|
|
<!-- Dynamic node list will be populated here -->
|
|
</div>
|