@ -136,9 +136,7 @@ export default class AiSettingsWidget extends OptionsWidget {
this . setupChangeHandler ( '.embedding-dimension-strategy' , 'embeddingDimensionStrategy' ) ;
this . setupChangeHandler ( '.embedding-provider-precedence' , 'embeddingProviderPrecedence' , true ) ;
// Set up sortable behavior for the embedding provider precedence list
this . setupEmbeddingProviderSortable ( ) ;
this . setupAiProviderSortable ( ) ;
// No sortable behavior needed anymore
// Embedding stats refresh button
const $refreshStats = this . $widget . find ( '.embedding-refresh-stats' ) ;
@ -433,369 +431,6 @@ export default class AiSettingsWidget extends OptionsWidget {
}
}
/ * *
* Setup sortable behavior for embedding provider precedence
* /
setupEmbeddingProviderSortable() {
if ( ! this . $widget ) return ;
const $embeddingProviderPrecedence = this . $widget . find ( '.embedding-provider-precedence' ) ;
const $sortableList = this . $widget . find ( '.embedding-provider-sortable' ) ;
const $items = $sortableList . find ( 'li' ) ;
// Make list items draggable
$items . each ( ( index , item ) = > this . setupEmbeddingProviderItemDragHandlers ( $ ( item ) ) ) ;
// Setup the remove buttons
this . setupEmbeddingProviderRemoveHandlers ( ) ;
// Setup disabled providers list restore handlers
this . $widget . find ( '.embedding-provider-disabled li' ) . each ( ( index , item ) = > {
this . setupEmbeddingProviderRestoreHandler ( $ ( item ) ) ;
} ) ;
// Initialize the order based on saved value
this . initializeEmbeddingProviderOrder ( ) ;
}
/ * *
* Setup sortable behavior for AI provider precedence
* /
setupAiProviderSortable() {
if ( ! this . $widget ) return ;
const $aiProviderPrecedence = this . $widget . find ( '.ai-provider-precedence' ) ;
const $sortableList = this . $widget . find ( '.provider-sortable' ) ;
const $items = $sortableList . find ( 'li' ) ;
// Make list items draggable
$items . each ( ( index , item ) = > this . setupAiItemDragHandlers ( $ ( item ) ) ) ;
// Setup the remove buttons
this . setupAiProviderRemoveHandlers ( ) ;
// Setup disabled providers list restore handlers
this . $widget . find ( '.provider-disabled li' ) . each ( ( index , item ) = > {
this . setupAiProviderRestoreHandler ( $ ( item ) ) ;
} ) ;
// Initialize the order based on saved value
this . initializeAiProviderOrder ( ) ;
}
/ * *
* Setup drag handlers for an embedding provider list item
* /
setupEmbeddingProviderItemDragHandlers ( $item : JQuery ) {
if ( ! this . $widget ) return ;
const self = this ;
const $embeddingProviderPrecedence = this . $widget . find ( '.embedding-provider-precedence' ) ;
const $embeddingSortableList = this . $widget . find ( '.embedding-provider-sortable' ) ;
// Setup dragstart handler
$item . on ( 'dragstart' , function ( e : JQuery.DragStartEvent ) {
$ ( this ) . addClass ( 'dragging' ) ;
e . originalEvent ? . dataTransfer ? . setData ( 'text/plain' , '' ) ;
} ) ;
// Setup dragend handler
$item . on ( 'dragend' , function ( ) {
$ ( this ) . removeClass ( 'dragging' ) ;
// Update the hidden input value
const providers = $embeddingSortableList . find ( 'li' ) . map ( function ( ) {
return $ ( this ) . data ( 'provider' ) ;
} ) . get ( ) . join ( ',' ) ;
// Only update if we have providers or if the current value isn't empty
// This prevents setting an empty string when all providers are removed
if ( providers || $embeddingProviderPrecedence . val ( ) ) {
$embeddingProviderPrecedence . val ( providers ) ;
$embeddingProviderPrecedence . trigger ( 'change' ) ;
}
} ) ;
// Additional drag event handlers ...
// All other drag event handlers would be implemented here
}
/ * *
* Setup event handlers for embedding provider remove buttons
* /
setupEmbeddingProviderRemoveHandlers() {
if ( ! this . $widget ) return ;
const self = this ;
const $embeddingProviderPrecedence = this . $widget . find ( '.embedding-provider-precedence' ) ;
const $embeddingSortableList = this . $widget . find ( '.embedding-provider-sortable' ) ;
// Remove any existing handlers to prevent duplicates
this . $widget . find ( '.remove-provider' ) . off ( 'click' ) ;
// Add handlers
this . $widget . find ( '.remove-provider' ) . on ( 'click' , function ( ) {
const $item = $ ( this ) . closest ( 'li' ) ;
const provider = $item . data ( 'provider' ) ;
const providerName = self . getProviderDisplayName ( provider ) ;
// Create a new item for the disabled list
const $disabledItem = $ ( `
< li class = "standard-list-item d-flex align-items-center" data - provider = "${provider}" >
< strong class = "flex-grow-1" > $ { providerName } < / strong >
< button class = "icon-action restore-provider" title = "${t(" ai_llm.restore_provider " ) } " >
< span class = "bx bx-plus" > < / span >
< / button >
< / li >
` );
// Move to disabled list
self . $widget ? . find ( '.embedding-provider-disabled' ) . append ( $disabledItem ) ;
self . setupEmbeddingProviderRestoreHandler ( $disabledItem ) ;
$item . remove ( ) ;
// Update the precedence value
const providers = $embeddingSortableList . find ( 'li' ) . map ( function ( ) {
return $ ( this ) . data ( 'provider' ) ;
} ) . get ( ) . join ( ',' ) ;
$embeddingProviderPrecedence . val ( providers ) ;
$embeddingProviderPrecedence . trigger ( 'change' ) ;
// Show disabled providers container
self . $widget ? . find ( '.disabled-providers-container' ) . show ( ) ;
} ) ;
}
/ * *
* Setup event handler for embedding provider restore button
* /
setupEmbeddingProviderRestoreHandler ( $item : JQuery ) {
if ( ! this . $widget ) return ;
const self = this ;
const $embeddingProviderPrecedence = this . $widget . find ( '.embedding-provider-precedence' ) ;
const $embeddingSortableList = this . $widget . find ( '.embedding-provider-sortable' ) ;
// Remove any existing handlers to prevent duplicates
$item . find ( '.restore-provider' ) . off ( 'click' ) ;
// Add handlers
$item . find ( '.restore-provider' ) . on ( 'click' , function ( ) {
const $disabledItem = $ ( this ) . closest ( 'li' ) ;
const provider = $disabledItem . data ( 'provider' ) ;
const providerName = self . getProviderDisplayName ( provider ) ;
// Create a new item for the active list
const $activeItem = $ ( `
< li class = "standard-list-item d-flex align-items-center" data - provider = "${provider}" draggable = "true" >
< span class = "drag-handle bx bx-dots-vertical-rounded me-2" > < / span >
< strong class = "flex-grow-1" > $ { providerName } < / strong >
< button class = "icon-action remove-provider" title = "${t(" ai_llm.remove_provider " ) } " >
< span class = "bx bx-x" > < / span >
< / button >
< / li >
` );
// Move to active list
$embeddingSortableList . append ( $activeItem ) ;
self . setupEmbeddingProviderItemDragHandlers ( $activeItem ) ;
self . setupEmbeddingProviderRemoveHandlers ( ) ;
$disabledItem . remove ( ) ;
// Update the precedence value
const providers = $embeddingSortableList . find ( 'li' ) . map ( function ( ) {
return $ ( this ) . data ( 'provider' ) ;
} ) . get ( ) . join ( ',' ) ;
$embeddingProviderPrecedence . val ( providers ) ;
$embeddingProviderPrecedence . trigger ( 'change' ) ;
// Hide disabled providers container if it's now empty
if ( self . $widget ? . find ( '.embedding-provider-disabled li' ) . length === 0 ) {
self . $widget ? . find ( '.disabled-providers-container' ) . hide ( ) ;
}
} ) ;
}
/ * *
* Initialize the embedding provider precedence order based on saved values
* /
initializeEmbeddingProviderOrder() {
if ( ! this . $widget ) return ;
const $embeddingProviderPrecedence = this . $widget . find ( '.embedding-provider-precedence' ) ;
const $sortableList = this . $widget . find ( '.embedding-provider-sortable' ) ;
// Get the current value
const savedValue = $embeddingProviderPrecedence . val ( ) as string ;
// If no saved value, don't proceed with initialization to avoid triggering the "empty" change
if ( ! savedValue ) return ;
// Get all available providers
const allProviders = [ 'openai' , 'voyage' , 'ollama' , 'local' ] ;
const savedProviders = savedValue . split ( ',' ) ;
// Clear all items from the disabled list first to avoid duplicates
this . $widget . find ( '.embedding-provider-disabled' ) . empty ( ) ;
// Find disabled providers (providers in allProviders but not in savedProviders)
const disabledProviders = allProviders . filter ( p = > ! savedProviders . includes ( p ) ) ;
// Move saved providers to the end in the correct order
savedProviders . forEach ( provider = > {
const $item = $sortableList . find ( ` li[data-provider=" ${ provider } "] ` ) ;
if ( $item . length ) {
$sortableList . append ( $item ) ; // Move to the end in the correct order
}
} ) ;
// Setup remove click handlers first to ensure they work when simulating clicks
this . setupEmbeddingProviderRemoveHandlers ( ) ;
// Move disabled providers to the disabled list
disabledProviders . forEach ( provider = > {
const $item = $sortableList . find ( ` li[data-provider=" ${ provider } "] ` ) ;
if ( $item . length ) {
// Simulate clicking the remove button to move it to the disabled list
$item . find ( '.remove-provider' ) . trigger ( 'click' ) ;
} else {
// If it's not in the active list already, manually create it in the disabled list
const providerName = this . getProviderDisplayName ( provider ) ;
const $disabledItem = $ ( `
< li class = "standard-list-item d-flex align-items-center" data - provider = "${provider}" >
< strong class = "flex-grow-1" > $ { providerName } < / strong >
< button class = "icon-action restore-provider" title = "${t(" ai_llm.restore_provider " ) } " >
< span class = "bx bx-plus" > < / span >
< / button >
< / li >
` );
this . $widget . find ( '.embedding-provider-disabled' ) . append ( $disabledItem ) ;
// Add restore button handler
this . setupEmbeddingProviderRestoreHandler ( $disabledItem ) ;
}
} ) ;
// Show/hide the disabled providers container
const $disabledContainer = this . $widget . find ( '.disabled-providers-container' ) ;
const hasDisabledProviders = this . $widget . find ( '.embedding-provider-disabled li' ) . length > 0 ;
$disabledContainer . toggle ( hasDisabledProviders ) ;
}
/ * *
* Setup drag handlers for an AI provider list item
* /
setupAiItemDragHandlers ( $item : JQuery ) {
if ( ! this . $widget ) return ;
const self = this ;
const $aiProviderPrecedence = this . $widget . find ( '.ai-provider-precedence' ) ;
const $aiSortableList = this . $widget . find ( '.provider-sortable' ) ;
// Setup dragstart handler
$item . on ( 'dragstart' , function ( e : JQuery.DragStartEvent ) {
$ ( this ) . addClass ( 'dragging' ) ;
e . originalEvent ? . dataTransfer ? . setData ( 'text/plain' , '' ) ;
} ) ;
// Setup dragend handler
$item . on ( 'dragend' , function ( ) {
$ ( this ) . removeClass ( 'dragging' ) ;
// Update the hidden input value
const providers = $aiSortableList . find ( 'li' ) . map ( function ( ) {
return $ ( this ) . data ( 'provider' ) ;
} ) . get ( ) . join ( ',' ) ;
$aiProviderPrecedence . val ( providers ) ;
$aiProviderPrecedence . trigger ( 'change' ) ;
} ) ;
// Additional drag event handlers would go here...
}
/ * *
* Initialize the AI provider precedence order based on saved values
* /
initializeAiProviderOrder() {
if ( ! this . $widget ) return ;
const $aiProviderPrecedence = this . $widget . find ( '.ai-provider-precedence' ) ;
const $aiSortableList = this . $widget . find ( '.provider-sortable' ) ;
// Get the current value
const savedValue = $aiProviderPrecedence . val ( ) as string ;
if ( ! savedValue ) return ;
// Get all available providers
const allProviders = [ 'openai' , 'anthropic' , 'ollama' , 'voyage' ] ;
const savedProviders = savedValue . split ( ',' ) ;
// Clear all items from the disabled list first to avoid duplicates
this . $widget . find ( '.provider-disabled' ) . empty ( ) ;
// Find disabled providers (providers in allProviders but not in savedProviders)
const disabledProviders = allProviders . filter ( p = > ! savedProviders . includes ( p ) ) ;
// Move saved providers to the end in the correct order
savedProviders . forEach ( provider = > {
const $item = $aiSortableList . find ( ` li[data-provider=" ${ provider } "] ` ) ;
if ( $item . length ) {
$aiSortableList . append ( $item ) ; // Move to the end in the correct order
}
} ) ;
// Setup remove click handlers first to ensure they work when simulating clicks
this . setupAiProviderRemoveHandlers ( ) ;
// Move disabled providers to the disabled list
disabledProviders . forEach ( provider = > {
const $item = $aiSortableList . find ( ` li[data-provider=" ${ provider } "] ` ) ;
if ( $item . length ) {
// Simulate clicking the remove button to move it to the disabled list
$item . find ( '.remove-ai-provider' ) . trigger ( 'click' ) ;
} else {
// If it's not in the active list already, manually create it in the disabled list
const providerName = this . getProviderDisplayName ( provider ) ;
const $disabledItem = $ ( `
< li class = "standard-list-item d-flex align-items-center" data - provider = "${provider}" >
< strong class = "flex-grow-1" > $ { providerName } < / strong >
< button class = "icon-action restore-ai-provider" title = "${t(" ai_llm.restore_provider " ) } " >
< span class = "bx bx-plus" > < / span >
< / button >
< / li >
` );
this . $widget . find ( '.provider-disabled' ) . append ( $disabledItem ) ;
// Add restore button handler
this . setupAiProviderRestoreHandler ( $disabledItem ) ;
}
} ) ;
// Show/hide the disabled providers container
const $disabledContainer = this . $widget . find ( '.disabled-ai-providers-container' ) ;
const hasDisabledProviders = this . $widget . find ( '.provider-disabled li' ) . length > 0 ;
$disabledContainer . toggle ( hasDisabledProviders ) ;
}
/ * *
* Setup event handlers for AI provider remove buttons
* /
setupAiProviderRemoveHandlers() {
if ( ! this . $widget ) return ;
// Implementation would go here...
}
/ * *
* Setup event handler for AI provider restore button
* /
setupAiProviderRestoreHandler ( $item : JQuery ) {
if ( ! this . $widget ) return ;
// Implementation would go here...
}
/ * *
* Called when the options have been loaded from the server
* /
@ -836,10 +471,6 @@ export default class AiSettingsWidget extends OptionsWidget {
this . $widget . find ( '.max-notes-per-llm-query' ) . val ( options . maxNotesPerLlmQuery || '3' ) ;
this . $widget . find ( '.embedding-dimension-strategy' ) . val ( options . embeddingDimensionStrategy || 'auto' ) ;
// Initialize sortable lists
this . initializeEmbeddingProviderOrder ( ) ;
this . initializeAiProviderOrder ( ) ;
// Display validation warnings
this . displayValidationWarnings ( ) ;
}