diff --git a/static/js/components/ContextMenu/GlobalContextMenu.js b/static/js/components/ContextMenu/GlobalContextMenu.js new file mode 100644 index 00000000..6015efee --- /dev/null +++ b/static/js/components/ContextMenu/GlobalContextMenu.js @@ -0,0 +1,24 @@ +import { BaseContextMenu } from './BaseContextMenu.js'; + +export class GlobalContextMenu extends BaseContextMenu { + constructor() { + super('globalContextMenu'); + } + + showMenu(x, y) { + super.showMenu(x, y, null); + } + + handleMenuAction(action, menuItem) { + switch (action) { + case 'placeholder-one': + case 'placeholder-two': + case 'placeholder-three': + console.info(`Global context menu action triggered: ${action}`); + break; + default: + console.warn(`Unhandled global context menu action: ${action}`); + break; + } + } +} diff --git a/static/js/components/ContextMenu/index.js b/static/js/components/ContextMenu/index.js index b6be6ccf..7d01c0f6 100644 --- a/static/js/components/ContextMenu/index.js +++ b/static/js/components/ContextMenu/index.js @@ -2,12 +2,14 @@ export { LoraContextMenu } from './LoraContextMenu.js'; export { RecipeContextMenu } from './RecipeContextMenu.js'; export { CheckpointContextMenu } from './CheckpointContextMenu.js'; export { EmbeddingContextMenu } from './EmbeddingContextMenu.js'; +export { GlobalContextMenu } from './GlobalContextMenu.js'; export { ModelContextMenuMixin } from './ModelContextMenuMixin.js'; import { LoraContextMenu } from './LoraContextMenu.js'; import { RecipeContextMenu } from './RecipeContextMenu.js'; import { CheckpointContextMenu } from './CheckpointContextMenu.js'; import { EmbeddingContextMenu } from './EmbeddingContextMenu.js'; +import { GlobalContextMenu } from './GlobalContextMenu.js'; // Factory method to create page-specific context menu instances export function createPageContextMenu(pageType) { @@ -23,4 +25,8 @@ export function createPageContextMenu(pageType) { default: return null; } +} + +export function createGlobalContextMenu() { + return new GlobalContextMenu(); } \ No newline at end of file diff --git a/static/js/core.js b/static/js/core.js index c2ad6cdb..40eb50b0 100644 --- a/static/js/core.js +++ b/static/js/core.js @@ -16,7 +16,7 @@ import { migrateStorageItems } from './utils/storageHelpers.js'; import { i18n } from './i18n/index.js'; import { onboardingManager } from './managers/OnboardingManager.js'; import { BulkContextMenu } from './components/ContextMenu/BulkContextMenu.js'; -import { createPageContextMenu } from './components/ContextMenu/index.js'; +import { createPageContextMenu, createGlobalContextMenu } from './components/ContextMenu/index.js'; import { initializeEventManagement } from './utils/eventManagementInit.js'; // Core application class @@ -116,6 +116,10 @@ export class AppCore { initializeContextMenus(pageType) { // Create page-specific context menu window.pageContextMenu = createPageContextMenu(pageType); + + if (!window.globalContextMenuInstance) { + window.globalContextMenuInstance = createGlobalContextMenu(); + } } } diff --git a/static/js/utils/eventManagementInit.js b/static/js/utils/eventManagementInit.js index ba9908b9..98055f43 100644 --- a/static/js/utils/eventManagementInit.js +++ b/static/js/utils/eventManagementInit.js @@ -86,29 +86,39 @@ function setupPageUnloadCleanup() { function registerContextMenuEvents() { eventManager.addHandler('contextmenu', 'contextMenu-coordination', (e) => { const card = e.target.closest('.model-card'); - if (!card) { - // Hide all menus if not right-clicking on a card - window.pageContextMenu?.hideMenu(); - window.bulkManager?.bulkContextMenu?.hideMenu(); + const pageContent = e.target.closest('.page-content'); + + if (!pageContent) { + window.globalContextMenuInstance?.hideMenu(); return false; } - - e.preventDefault(); - - // Hide all menus first - window.pageContextMenu?.hideMenu(); - window.bulkManager?.bulkContextMenu?.hideMenu(); - - // Determine which menu to show based on bulk mode and selection state - if (state.bulkMode && card.classList.contains('selected')) { - // Show bulk menu for selected cards in bulk mode - window.bulkManager?.bulkContextMenu?.showMenu(e.clientX, e.clientY, card); - } else if (!state.bulkMode) { - // Show regular menu when not in bulk mode - window.pageContextMenu?.showMenu(e.clientX, e.clientY, card); + + if (card) { + e.preventDefault(); + + // Hide all menus first + window.pageContextMenu?.hideMenu(); + window.bulkManager?.bulkContextMenu?.hideMenu(); + window.globalContextMenuInstance?.hideMenu(); + + // Determine which menu to show based on bulk mode and selection state + if (state.bulkMode && card.classList.contains('selected')) { + // Show bulk menu for selected cards in bulk mode + window.bulkManager?.bulkContextMenu?.showMenu(e.clientX, e.clientY, card); + } else if (!state.bulkMode) { + // Show regular menu when not in bulk mode + window.pageContextMenu?.showMenu(e.clientX, e.clientY, card); + } + } else { + e.preventDefault(); + + window.pageContextMenu?.hideMenu(); + window.bulkManager?.bulkContextMenu?.hideMenu(); + window.globalContextMenuInstance?.hideMenu(); + + window.globalContextMenuInstance?.showMenu(e.clientX, e.clientY, null); } - // Don't show any menu for unselected cards in bulk mode - + return true; // Stop propagation }, { priority: 200, // Higher priority than bulk manager events @@ -125,6 +135,7 @@ function registerGlobalClickHandlers() { if (!e.target.closest('.context-menu')) { window.pageContextMenu?.hideMenu(); window.bulkManager?.bulkContextMenu?.hideMenu(); + window.globalContextMenuInstance?.hideMenu(); } return false; // Allow other handlers to process }, { diff --git a/templates/components/context_menu.html b/templates/components/context_menu.html index b47ed57a..d5ace040 100644 --- a/templates/components/context_menu.html +++ b/templates/components/context_menu.html @@ -84,6 +84,18 @@ +
+