f
This commit is contained in:
		
							parent
							
								
									b724e61d7f
								
							
						
					
					
						commit
						7a24d3cb98
					
				
							
								
								
									
										1
									
								
								electron-file-search/data.ms/VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								electron-file-search/data.ms/VERSION
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| 1.10.2 | ||||
							
								
								
									
										
											BIN
										
									
								
								electron-file-search/data.ms/auth/data.mdb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								electron-file-search/data.ms/auth/data.mdb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								electron-file-search/data.ms/auth/lock.mdb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								electron-file-search/data.ms/auth/lock.mdb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1
									
								
								electron-file-search/data.ms/instance-uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								electron-file-search/data.ms/instance-uid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| cd5f7d5b-1d5c-40ec-bb49-885d5809f14f | ||||
							
								
								
									
										
											BIN
										
									
								
								electron-file-search/data.ms/tasks/data.mdb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								electron-file-search/data.ms/tasks/data.mdb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								electron-file-search/data.ms/tasks/lock.mdb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								electron-file-search/data.ms/tasks/lock.mdb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -221,6 +221,62 @@ export function setupIpcHandlers() { | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   // Meilisearch Handlers
 | ||||
|   ipcMain.handle('meilisearch-add-documents', async (_: unknown, indexName: string, documents: any[]) => { | ||||
|     try { | ||||
|       await (global as any).meilisearchService.addDocuments(indexName, documents); | ||||
|       return { success: true }; | ||||
|     } catch (error) { | ||||
|       const err = error as Error; | ||||
|       console.error('Error adding documents to Meilisearch:', err); | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   ipcMain.handle('meilisearch-remove-documents', async (_: unknown, indexName: string, documentIds: string[]) => { | ||||
|     try { | ||||
|       await (global as any).meilisearchService.removeDocuments(indexName, documentIds); | ||||
|       return { success: true }; | ||||
|     } catch (error) { | ||||
|       const err = error as Error; | ||||
|       console.error('Error removing documents from Meilisearch:', err); | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   ipcMain.handle('meilisearch-update-documents', async (_: unknown, indexName: string, documents: any[]) => { | ||||
|     try { | ||||
|       await (global as any).meilisearchService.updateDocuments(indexName, documents); | ||||
|       return { success: true }; | ||||
|     } catch (error) { | ||||
|       const err = error as Error; | ||||
|       console.error('Error updating documents in Meilisearch:', err); | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   ipcMain.handle('meilisearch-create-index', async (_: unknown, indexName: string) => { | ||||
|     try { | ||||
|       await (global as any).meilisearchService.createIndex(indexName); | ||||
|       return { success: true }; | ||||
|     } catch (error) { | ||||
|       const err = error as Error; | ||||
|       console.error('Error creating index in Meilisearch:', err); | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   ipcMain.handle('meilisearch-delete-index', async (_: unknown, indexName: string) => { | ||||
|     try { | ||||
|       await (global as any).meilisearchService.deleteIndex(indexName); | ||||
|       return { success: true }; | ||||
|     } catch (error) { | ||||
|       const err = error as Error; | ||||
|       console.error('Error deleting index in Meilisearch:', err); | ||||
|       return { success: false, error: err.message }; | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export default setupIpcHandlers; | ||||
|  | ||||
| @ -4,10 +4,180 @@ const os = require('os'); | ||||
| const spawn = require('child_process').spawn; | ||||
| const { store: electronStore } = require('./store'); | ||||
| const { setupIpcHandlers } = require('./ipc/handlers'); | ||||
| const { MeiliSearch } = require('meilisearch'); | ||||
| 
 | ||||
| const slugify = (str: string) => { | ||||
|   return str | ||||
|     .toLowerCase() | ||||
|     .replace(/[^a-z0-9]+/g, '-') | ||||
|     .replace(/^-|-$/g, ''); | ||||
| }; | ||||
| 
 | ||||
| const { platform } = require('os'); | ||||
| 
 | ||||
| class MeilisearchService { | ||||
|   private binaryPath: string; | ||||
|   private serverProcess: any | null = null; | ||||
|   private client: any | null = null; | ||||
| 
 | ||||
|   constructor() { | ||||
|     this.binaryPath = this.getBinaryPath(); | ||||
|     this.client = new MeiliSearch({ | ||||
|       host: 'http://127.0.0.1:7700', | ||||
|       apiKey: process.env.MEILISEARCH_MASTER_KEY || 'Damie', | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private getBinaryPath(): string { | ||||
|     const arch = process.arch; | ||||
|     let binaryName: string; | ||||
| 
 | ||||
|     switch (platform()) { | ||||
|       case 'darwin': | ||||
|         binaryName = arch === 'arm64' ? 'meilisearch-macos-arm' : 'meilisearch-macos-x64'; | ||||
|         break; | ||||
|       case 'win32': | ||||
|         binaryName = 'meilisearch-windows.exe'; | ||||
|         break; | ||||
|       case 'linux': | ||||
|         binaryName = arch === 'arm' ? 'meilisearch-linux-arm' : 'meilisearch-linux-x64'; | ||||
|         break; | ||||
|       default: | ||||
|         throw new Error(`Unsupported platform: ${platform()}`); | ||||
|     } | ||||
| 
 | ||||
|     return path.join(__dirname, '..', 'meilisearch_binaries', binaryName); | ||||
|   } | ||||
| 
 | ||||
|   public async startServer(): Promise<void> { | ||||
|     if (this.serverProcess) { | ||||
|       console.log('Meilisearch server is already running.'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     try { | ||||
|       const apiKey = 'Damie'; // Use the system's name as the API key
 | ||||
|       process.env.MEILISEARCH_MASTER_KEY = apiKey; | ||||
| 
 | ||||
|       this.serverProcess = spawn(this.binaryPath, ['--http-addr', '127.0.0.1:7700'], { | ||||
|         env: process.env, // Pass the environment variables to the child process
 | ||||
|       }); | ||||
| 
 | ||||
|       this.serverProcess.stdout?.on('data', (data) => { | ||||
|         console.log(`Meilisearch: ${data}`); | ||||
|       }); | ||||
| 
 | ||||
|       this.serverProcess.stderr?.on('data', (data) => { | ||||
|         console.error(`Meilisearch: ${data}`); | ||||
|       }); | ||||
| 
 | ||||
|       this.serverProcess.on('close', (code) => { | ||||
|         console.log(`Meilisearch server stopped with code ${code}`); | ||||
|         this.serverProcess = null; | ||||
|       }); | ||||
| 
 | ||||
|       this.serverProcess.on('error', (err) => { | ||||
|         console.error('Failed to start Meilisearch server:', err); | ||||
|         this.serverProcess = null; | ||||
|       }); | ||||
| 
 | ||||
|       console.log('Meilisearch server started.'); | ||||
|     } catch (error) { | ||||
|       console.error('Failed to start Meilisearch server:', error); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async stopServer(): Promise<void> { | ||||
|     if (!this.serverProcess) { | ||||
|       console.log('Meilisearch server is not running.'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     this.serverProcess.kill(); | ||||
|     this.serverProcess = null; | ||||
|     console.log('Meilisearch server stopped.'); | ||||
|   } | ||||
| 
 | ||||
|   // Implement methods for adding, removing, and updating documents and collections
 | ||||
|   // using the Meilisearch API.
 | ||||
|   public async addDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|     // TODO: Implement this method
 | ||||
|     console.log(`Adding documents to index ${indexName}`); | ||||
|   } | ||||
| 
 | ||||
|   public async removeDocuments(indexName: string, documentIds: string[]): Promise<void> { | ||||
|     // TODO: Implement this method
 | ||||
|     console.log(`Removing documents from index ${indexName}`); | ||||
|   } | ||||
| 
 | ||||
|   public async updateDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|     // TODO: Implement this method
 | ||||
|     console.log(`Updating documents in index ${indexName}`); | ||||
|   } | ||||
| 
 | ||||
|   public async createIndex(indexName: string): Promise<void> { | ||||
|     const sluggedIndexName = slugify(indexName); | ||||
|     // TODO: Implement this method
 | ||||
|     console.log(`Creating index ${sluggedIndexName}`); | ||||
|     try { | ||||
|       await this.client.createIndex(sluggedIndexName); | ||||
|       console.log(`Index ${sluggedIndexName} created successfully`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to create index ${sluggedIndexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async deleteIndex(indexName: string): Promise<void> { | ||||
|     try { | ||||
|       await this.client.deleteIndex(indexName); | ||||
|       console.log(`Index ${indexName} deleted successfully`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to delete index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async addDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|     try { | ||||
|       const index = await this.client.index(indexName); | ||||
|       await index.addDocuments(documents); | ||||
|       console.log(`Documents added to index ${indexName} successfully`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to add documents to index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async removeDocuments(indexName: string, documentIds: string[]): Promise<void> { | ||||
|     try { | ||||
|       const index = await this.client.index(indexName); | ||||
|       await index.deleteDocuments(documentIds); | ||||
|       console.log(`Documents removed from index ${indexName} successfully`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to remove documents from index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async updateDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|     try { | ||||
|       const index = await this.client.index(indexName); | ||||
|       await index.updateDocuments(documents); | ||||
|       console.log(`Documents updated in index ${indexName} successfully`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to update documents in index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Initialize IPC handlers immediately
 | ||||
| setupIpcHandlers(); | ||||
| 
 | ||||
| const meilisearchService = new MeilisearchService(); | ||||
| (global as any).meilisearchService = meilisearchService; | ||||
| 
 | ||||
| function createWindow() { | ||||
|   const mainWindow = new BrowserWindow({ | ||||
|     width: 1200, | ||||
| @ -123,6 +293,7 @@ function createWindow() { | ||||
| } | ||||
| 
 | ||||
| app.whenReady().then(() => { | ||||
|   meilisearchService.startServer(); | ||||
|   createWindow(); | ||||
| 
 | ||||
|   app.on('activate', () => { | ||||
| @ -167,4 +338,23 @@ ipcMain.handle('open-external', (_, url) => { | ||||
|   return require('electron').shell.openExternal(url); | ||||
| }); | ||||
| 
 | ||||
| // Launch the server
 | ||||
| if (process.env.NODE_ENV !== 'development') { | ||||
|   const serverProcess = spawn('node', [path.join(__dirname, '../scripts/dev.cjs')], { | ||||
|     stdio: 'inherit', | ||||
|   }); | ||||
| 
 | ||||
|   serverProcess.on('close', (code) => { | ||||
|     console.log(`Server process exited with code ${code}`); | ||||
|   }); | ||||
| 
 | ||||
|   serverProcess.on('error', (err) => { | ||||
|     console.error('Failed to start server process:', err); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| app.on('will-quit', () => { | ||||
|   meilisearchService.stopServer(); | ||||
| }); | ||||
| 
 | ||||
| module.exports = app; | ||||
|  | ||||
| @ -26,6 +26,11 @@ contextBridge.exposeInMainWorld('electron', { | ||||
|   addExcludedPath: async (path: string): Promise<void> =>  | ||||
|     ipcRenderer.invoke('add-excluded-path', path), | ||||
|    | ||||
|   createIndex: async (folderPath: string): Promise<{ | ||||
|     answer: string; | ||||
|     sources: DocumentMetadata[]; | ||||
|   }> => ipcRenderer.invoke('meilisearch-create-index', folderPath), | ||||
| 
 | ||||
|   // LLM Operations
 | ||||
|   queryLLM: async (question: string): Promise<{ | ||||
|     answer: string; | ||||
| @ -84,6 +89,9 @@ contextBridge.exposeInMainWorld('electron', { | ||||
|   minimizeWindow: () => ipcRenderer.invoke('window-minimize'), | ||||
|   maximizeWindow: () => ipcRenderer.invoke('window-maximize'), | ||||
|   closeWindow: () => ipcRenderer.invoke('window-close'), | ||||
|   send: (channel: string, data: any) => { | ||||
|     ipcRenderer.send(channel, data); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| // Export types for TypeScript
 | ||||
|  | ||||
| @ -2,6 +2,11 @@ import { FSWatcher } from 'chokidar'; | ||||
| import * as chokidar from 'chokidar'; | ||||
| import Store from 'electron-store'; | ||||
| import { ServiceError } from '../types'; | ||||
| import * as path from 'path'; | ||||
| const fs = require('fs'); | ||||
| const fsPromises = fs.promises; | ||||
| import * as crypto from 'crypto'; | ||||
| import MeilisearchService from './meilisearchService'; | ||||
| 
 | ||||
| const store = new Store<{ | ||||
|   watchedPaths: string[]; | ||||
| @ -11,10 +16,13 @@ const store = new Store<{ | ||||
| class FileSystemService { | ||||
|   private watchers: Map<string, FSWatcher>; | ||||
|   private excludedPaths: Set<string>; | ||||
|   private meilisearchService: MeilisearchService; | ||||
|   private readonly indexName = 'files'; | ||||
| 
 | ||||
|   constructor() { | ||||
|     this.watchers = new Map(); | ||||
|     this.excludedPaths = new Set(store.get('excludedPaths', [])); | ||||
|     this.meilisearchService = new MeilisearchService(); | ||||
| 
 | ||||
|     // Add example paths
 | ||||
|     const examplePaths = [ | ||||
| @ -32,6 +40,49 @@ class FileSystemService { | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private slugify(filePath: string): string { | ||||
|     return filePath | ||||
|       .replace(/[\\/]/g, '-') // Replace path separators with dashes
 | ||||
|       .replace(/[^a-zA-Z0-9_-]+/g, '') // Remove non-alphanumeric characters
 | ||||
|       .toLowerCase(); | ||||
|   } | ||||
| 
 | ||||
|   private async calculateFileHash(filePath: string): Promise<string> { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       try { | ||||
|         const hash = crypto.createHash('sha256'); | ||||
|         const stream = fs.createReadStream(filePath); | ||||
| 
 | ||||
|         if (!stream) { | ||||
|           reject(new Error(`Failed to create read stream for ${filePath}`)); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         stream.on('data', (data: any) => { | ||||
|           try { | ||||
|             hash.update(data); | ||||
|           } catch (dataError) { | ||||
|             reject(new Error(`Failed to update hash with data for ${filePath}: ${dataError}`)); | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         stream.on('end', () => { | ||||
|           try { | ||||
|             resolve(hash.digest('hex')); | ||||
|           } catch (digestError) { | ||||
|             reject(new Error(`Failed to digest hash for ${filePath}: ${digestError}`)); | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         stream.on('error', (streamError: any) => { | ||||
|           reject(new Error(`Read stream error for ${filePath}: ${streamError}`)); | ||||
|         }); | ||||
|       } catch (creationError: any) { | ||||
|         reject(new Error(`Failed to create read stream or hash for ${filePath}: ${creationError}`)); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   public async startWatching(dirPath: string): Promise<void> { | ||||
|     if (this.watchers.has(dirPath)) { | ||||
|       throw new ServiceError(`Already watching directory: ${dirPath}`); | ||||
| @ -39,7 +90,7 @@ class FileSystemService { | ||||
| 
 | ||||
|     const watcher = chokidar.watch(dirPath, { | ||||
|       ignored: [ | ||||
|         /(^|[\/\\])\../, // Ignore dotfiles
 | ||||
|         /(^|[\\/])\../, // Ignore dotfiles
 | ||||
|         '**/node_modules/**', | ||||
|         ...Array.from(this.excludedPaths), | ||||
|       ], | ||||
| @ -47,9 +98,58 @@ class FileSystemService { | ||||
|       ignoreInitial: false, | ||||
|     }); | ||||
| 
 | ||||
|     watcher.on('add', path => { | ||||
|       console.log(`File ${path} has been added`); | ||||
|       // TODO: Process file
 | ||||
|     const indexName = this.slugify(dirPath); | ||||
| 
 | ||||
|     watcher.on('add', async (filePath) => { | ||||
|       console.log(`File ${filePath} has been added`); | ||||
| 
 | ||||
|       try { | ||||
|         const stats = await fs.promises.stat(filePath); | ||||
|         const slug = this.slugify(filePath); | ||||
|         const fileContent = await fs.promises.readFile(filePath, 'utf-8'); | ||||
|         const fileExtension = path.extname(filePath); | ||||
|         const fileName = path.basename(filePath); | ||||
| 
 | ||||
|         const permissions = { | ||||
|           read: !!(stats.mode & fs.constants.S_IRUSR), | ||||
|           write: !!(stats.mode & fs.constants.S_IWUSR), | ||||
|           execute: !!(stats.mode & fs.constants.S_IXUSR), | ||||
|         }; | ||||
| 
 | ||||
|         const document = { | ||||
|           id: slug, | ||||
|           name: filePath, | ||||
|           fileName: fileName, | ||||
|           content: fileContent, | ||||
|           extension: fileExtension, | ||||
|           createdAt: stats.birthtime, | ||||
|           modifiedAt: stats.mtime, | ||||
|           accessedAt: stats.atime, | ||||
|           size: stats.size, | ||||
|           permissions: permissions, | ||||
|         }; | ||||
| 
 | ||||
|         let fileHash: string | undefined; | ||||
|         try { | ||||
|           fileHash = await this.calculateFileHash(filePath); | ||||
|           document['hash'] = fileHash; | ||||
|         } catch (hashError) { | ||||
|           console.error(`Failed to calculate file hash for ${filePath}:`, hashError); | ||||
|         } | ||||
| 
 | ||||
|         if (this.meilisearchService) { | ||||
|           try { | ||||
|             await this.meilisearchService.addDocuments(indexName, [document]); | ||||
|             console.log(`Added document to Meilisearch: ${slug}`); | ||||
|           } catch (meilisearchError) { | ||||
|             console.error(`Failed to add document to Meilisearch:`, meilisearchError); | ||||
|           } | ||||
|         } else { | ||||
|           console.warn('Meilisearch service not initialized.'); | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.error(`Failed to add document to Meilisearch:`, error); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     watcher.on('change', path => { | ||||
|  | ||||
							
								
								
									
										91
									
								
								electron-file-search/electron/services/meilisearchService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								electron-file-search/electron/services/meilisearchService.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| import { MeiliSearch } from 'meilisearch' | ||||
| 
 | ||||
| class MeilisearchService { | ||||
|   private client: MeiliSearch; | ||||
| 
 | ||||
|   constructor() { | ||||
|     this.client = new MeiliSearch({ | ||||
|       host: 'http://localhost:7700', | ||||
|     }); | ||||
|     this.createIndex('files'); // Ensure the index exists
 | ||||
|   } | ||||
| 
 | ||||
|   // Implement methods for adding, removing, and updating documents and collections
 | ||||
|   // using the Meilisearch API.
 | ||||
|   public async addDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|     try { | ||||
|       const index = this.client.index(indexName) | ||||
|       await index.addDocuments(documents) | ||||
|       console.log(`Added ${documents.length} documents to index ${indexName}`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to add documents to index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async removeDocuments(indexName: string, documentIds: string[]): Promise<void> { | ||||
|     try { | ||||
|       const index = this.client.index(indexName) | ||||
|       await index.deleteDocuments(documentIds) | ||||
|       console.log(`Removed documents with IDs ${documentIds.join(',')} from index ${indexName}`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to remove documents from index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async updateDocuments(indexName: string, documents: any[]): Promise<void> { | ||||
|    try { | ||||
|       const index = this.client.index(indexName) | ||||
|       await index.updateDocuments(documents) | ||||
|       console.log(`Updated ${documents.length} documents in index ${indexName}`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to update documents in index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async deleteIndex(indexName: string): Promise<void> { | ||||
|     try { | ||||
|       await this.client.deleteIndex(indexName); | ||||
|       console.log(`Deleted index ${indexName}`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to delete index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async createIndex(indexName: string): Promise<void> { | ||||
|     try { | ||||
|       await this.client.createIndex(indexName); | ||||
|       console.log(`Created index ${indexName}`); | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to create index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async getDocuments(indexName: string): Promise<any[]> { | ||||
|     try { | ||||
|       const index = this.client.index(indexName); | ||||
|       const { hits } = await index.search(''); // Empty search to get all documents
 | ||||
|       return hits; | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to get documents from index ${indexName}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public async search(indexName: string, query: string): Promise<any[]> { | ||||
|     try { | ||||
|       const index = this.client.index(indexName); | ||||
|       const { hits } = await index.search(query); | ||||
|       return hits; | ||||
|     } catch (error) { | ||||
|       console.error(`Failed to search index ${indexName} with query ${query}:`, error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default MeilisearchService; | ||||
| @ -10,6 +10,9 @@ export interface DocumentMetadata { | ||||
|   type: string; | ||||
|   lastModified: number; | ||||
|   size: number; | ||||
|   createdAt?: string; | ||||
|   modifiedAt?: string; | ||||
|   accessedAt?: string; | ||||
|   hasEmbeddings?: boolean; | ||||
|   hasOcr?: boolean; | ||||
| } | ||||
|  | ||||
							
								
								
									
										92
									
								
								electron-file-search/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										92
									
								
								electron-file-search/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -14,15 +14,18 @@ | ||||
|         "@fontsource/roboto": "^5.0.8", | ||||
|         "@mui/icons-material": "^5.15.7", | ||||
|         "@mui/material": "^5.15.7", | ||||
|         "@mui/x-data-grid": "^7.26.0", | ||||
|         "chokidar": "^3.5.3", | ||||
|         "electron-store": "^8.1.0", | ||||
|         "highlight.js": "^11.11.1", | ||||
|         "meilisearch": "^0.48.2", | ||||
|         "ollama": "^0.5.12", | ||||
|         "openai": "^4.82.0", | ||||
|         "openrouter-client": "^1.2.0", | ||||
|         "react": "^18.2.0", | ||||
|         "react-dom": "^18.2.0", | ||||
|         "react-markdown": "^9.0.3", | ||||
|         "react-virtuoso": "^4.12.5", | ||||
|         "rehype-highlight": "^7.0.2" | ||||
|       }, | ||||
|       "devDependencies": { | ||||
| @ -1848,6 +1851,64 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/x-data-grid": { | ||||
|       "version": "7.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.26.0.tgz", | ||||
|       "integrity": "sha512-9RNQeT2OL6jBOCE0MSUH11ol3fV5Zs9MkGxUIAGXcy/Fui0rZRNFO1yLmWDZU5yvskiNmUZJHWV/qXh++ZFarA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.25.7", | ||||
|         "@mui/utils": "^5.16.6 || ^6.0.0", | ||||
|         "@mui/x-internals": "7.26.0", | ||||
|         "clsx": "^2.1.1", | ||||
|         "prop-types": "^15.8.1", | ||||
|         "reselect": "^5.1.1", | ||||
|         "use-sync-external-store": "^1.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@emotion/react": "^11.9.0", | ||||
|         "@emotion/styled": "^11.8.1", | ||||
|         "@mui/material": "^5.15.14 || ^6.0.0", | ||||
|         "@mui/system": "^5.15.14 || ^6.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@emotion/react": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@emotion/styled": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/x-internals": { | ||||
|       "version": "7.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.26.0.tgz", | ||||
|       "integrity": "sha512-VxTCYQcZ02d3190pdvys2TDg9pgbvewAVakEopiOgReKAUhLdRlgGJHcOA/eAuGLyK1YIo26A6Ow6ZKlSRLwMg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.25.7", | ||||
|         "@mui/utils": "^5.16.6 || ^6.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@nodelib/fs.scandir": { | ||||
|       "version": "2.1.5", | ||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||
| @ -6713,6 +6774,12 @@ | ||||
|         "url": "https://opencollective.com/unified" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/meilisearch": { | ||||
|       "version": "0.48.2", | ||||
|       "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.48.2.tgz", | ||||
|       "integrity": "sha512-auDB6grs3f/+dVzzPiAOOFnrVN/L87/+SWZfy56TpimDinWjU4u6Jc2o6lgeLluotpbMOFY1WpTTbqtUdMduQw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/merge2": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", | ||||
| @ -8275,6 +8342,16 @@ | ||||
|         "react-dom": ">=16.6.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-virtuoso": { | ||||
|       "version": "4.12.5", | ||||
|       "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.5.tgz", | ||||
|       "integrity": "sha512-YeCbRRsC9CLf0buD0Rct7WsDbzf+yBU1wGbo05/XjbcN2nJuhgh040m3y3+6HVogTZxEqVm45ac9Fpae4/MxRQ==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "react": ">=16 || >=17 || >= 18 || >= 19", | ||||
|         "react-dom": ">=16 || >=17 || >= 18 || >=19" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/read-cache": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", | ||||
| @ -8431,6 +8508,12 @@ | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/reselect": { | ||||
|       "version": "5.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", | ||||
|       "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/resolve": { | ||||
|       "version": "1.22.10", | ||||
|       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", | ||||
| @ -9594,6 +9677,15 @@ | ||||
|         "punycode": "^2.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/use-sync-external-store": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", | ||||
|       "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/utf8-byte-length": { | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", | ||||
|  | ||||
| @ -19,15 +19,18 @@ | ||||
|     "@fontsource/roboto": "^5.0.8", | ||||
|     "@mui/icons-material": "^5.15.7", | ||||
|     "@mui/material": "^5.15.7", | ||||
|     "@mui/x-data-grid": "^7.26.0", | ||||
|     "chokidar": "^3.5.3", | ||||
|     "electron-store": "^8.1.0", | ||||
|     "highlight.js": "^11.11.1", | ||||
|     "meilisearch": "^0.48.2", | ||||
|     "ollama": "^0.5.12", | ||||
|     "openai": "^4.82.0", | ||||
|     "openrouter-client": "^1.2.0", | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-markdown": "^9.0.3", | ||||
|     "react-virtuoso": "^4.12.5", | ||||
|     "rehype-highlight": "^7.0.2" | ||||
|   }, | ||||
|   "build": { | ||||
|  | ||||
| @ -328,10 +328,9 @@ function AppContent() { | ||||
|               <Tabs value={currentTab} onChange={handleTabChange}> | ||||
|                 <Tab label="Home" /> | ||||
|                 <Tab label="Chat" /> | ||||
|                 <Tab label="Settings" /> | ||||
|                 <Tab disabled label="Scanning" /> | ||||
|                 <Tab disabled label="Reports" /> | ||||
|                 <Tab disabled label="Cleanup" /> | ||||
|                 <Tab label="Settings" /> | ||||
|               </Tabs> | ||||
|             </Box> | ||||
|             <Box sx={{  | ||||
| @ -349,13 +348,10 @@ function AppContent() { | ||||
|                 <ChatPanel messages={messages} /> | ||||
|               </TabPanel> | ||||
|               <TabPanel value={currentTab} index={2}> | ||||
|                 <SettingsPanel /> | ||||
|               </TabPanel> | ||||
|               <TabPanel value={currentTab} index={3}> | ||||
|                 <ScanningPanel /> | ||||
|                 <ReportingPanel /> | ||||
|               </TabPanel> | ||||
|               <TabPanel value={currentTab} index={4}> | ||||
|                 <ReportingPanel /> | ||||
|                 <SettingsPanel /> | ||||
|               </TabPanel> | ||||
|             </Box> | ||||
|           </Box> | ||||
|  | ||||
							
								
								
									
										15
									
								
								electron-file-search/src/components/DirectorySearchModal.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								electron-file-search/src/components/DirectorySearchModal.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| .search-icon { | ||||
|   animation: pulse 2s infinite; | ||||
| } | ||||
| 
 | ||||
| @keyframes pulse { | ||||
|   0% { | ||||
|     transform: scale(1); | ||||
|   } | ||||
|   50% { | ||||
|     transform: scale(1.2); | ||||
|   } | ||||
|   100% { | ||||
|     transform: scale(1); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										152
									
								
								electron-file-search/src/components/DirectorySearchModal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								electron-file-search/src/components/DirectorySearchModal.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| import { | ||||
|   Box, | ||||
|   Typography, | ||||
|   Button, | ||||
|   Modal, | ||||
|   TextField, | ||||
| } from "@mui/material"; | ||||
| import { DataGrid, GridColDef } from '@mui/x-data-grid'; | ||||
| import { Search } from '@mui/icons-material'; | ||||
| import './DirectorySearchModal.css'; | ||||
| 
 | ||||
| interface DirectorySearchModalProps { | ||||
|   dir: string; | ||||
|   open: boolean; | ||||
|   onClose: () => void; | ||||
|   modalId: string; | ||||
| } | ||||
| 
 | ||||
| interface FileData { | ||||
|   id: number; | ||||
|   filePath: string; | ||||
|   fileName: string; | ||||
|   fileExtension: string; | ||||
|   createdAt: string; | ||||
|   modifiedAt: string; | ||||
|   accessedAt: string; | ||||
|   size: number; | ||||
| } | ||||
| 
 | ||||
| const columns: GridColDef[] = [ | ||||
|   { field: 'id', headerName: 'ID', width: 50 }, | ||||
|   { field: 'filePath', headerName: 'File Path', width: 250 }, | ||||
|   { field: 'fileName', headerName: 'File Name', width: 150 }, | ||||
|   { field: 'fileExtension', headerName: 'File Extension', width: 100 }, | ||||
|   { field: 'createdAt', headerName: 'Created At', width: 150 }, | ||||
|   { field: 'modifiedAt', headerName: 'Modified At', width: 150 }, | ||||
|   { field: 'accessedAt', headerName: 'Accessed At', width: 150 }, | ||||
|   { field: 'size', headerName: 'Size', width: 70 }, | ||||
| ]; | ||||
| 
 | ||||
| const DirectorySearchModal: React.FC<DirectorySearchModalProps> = ({ dir, open, onClose, modalId }) => { | ||||
|   const [searchQuery, setSearchQuery] = useState(''); | ||||
|   const [rows, setRows] = useState<FileData[]>([]); | ||||
| 
 | ||||
|   const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||||
|     setSearchQuery(event.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchFileData = async () => { | ||||
|       window.electron.getDocuments().then((response) => { | ||||
|         if (response.success && response.data) { | ||||
|           const filesInDirectory = response.data.filter(doc => doc.path.startsWith(dir)); | ||||
|           const fileData: FileData[] = filesInDirectory.map((doc, index) => ({ | ||||
|             id: index + 1, | ||||
|             filePath: doc.path, | ||||
|             fileName: doc.path.split(/[/\\]/).pop() || '', | ||||
|             fileExtension: doc.path.split('.').pop() || '', | ||||
|             createdAt: doc.createdAt || '', | ||||
|             modifiedAt: doc.modifiedAt || '', | ||||
|             accessedAt: doc.accessedAt || '', | ||||
|             size: doc.size || 0, | ||||
|           })); | ||||
|           setRows(fileData); | ||||
|         } | ||||
|       }); | ||||
|     }; | ||||
| 
 | ||||
|     fetchFileData(); | ||||
|   }, [dir]); | ||||
| 
 | ||||
|   const filteredRows = rows.filter((row) => { | ||||
|     return ( | ||||
|       row.filePath.toLowerCase().includes(searchQuery.toLowerCase()) || | ||||
|       row.fileName.toLowerCase().includes(searchQuery.toLowerCase()) || | ||||
|       row.fileExtension.toLowerCase().includes(searchQuery.toLowerCase()) | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|     <Modal | ||||
|       id={modalId} | ||||
|       open={open} | ||||
|       onClose={onClose} | ||||
|       aria-labelledby={`modal-title-${dir}`} | ||||
|       aria-describedby={`modal-description-${dir}`} | ||||
|     > | ||||
|       <Box | ||||
|         sx={{ | ||||
|           position: "absolute", | ||||
|           top: "50%", | ||||
|           left: "50%", | ||||
|           transform: "translate(-50%, -50%)", | ||||
|           width: '80%', | ||||
|           maxWidth: 1200, | ||||
|           bgcolor: "background.paper", | ||||
|           boxShadow: 24, | ||||
|           p: 4, | ||||
|           borderRadius: 2, | ||||
|         }} | ||||
|       > | ||||
|         <Box | ||||
|           sx={{ | ||||
|             display: 'flex', | ||||
|             alignItems: 'center', | ||||
|             border: '1px solid white', | ||||
|             borderRadius: '4px', | ||||
|             paddingLeft: '8px', | ||||
|             marginBottom: '8px', | ||||
|           }} | ||||
|         > | ||||
|           <Search className="search-icon" sx={{ mr: 1, color: 'white' }} /> | ||||
|           <TextField | ||||
|             placeholder={dir} | ||||
|             variant="standard" | ||||
|             fullWidth | ||||
|             onChange={handleSearchChange} | ||||
|             InputProps={{ | ||||
|               disableUnderline: true, | ||||
|               style: { | ||||
|                 color: 'white', | ||||
|               }, | ||||
|             }} | ||||
|             sx={{ | ||||
|               '& .MuiInputBase-input': { | ||||
|                 color: 'white', | ||||
|               }, | ||||
|             }} | ||||
|           /> | ||||
|         </Box> | ||||
|         <div style={{ height: 400, width: '100%' }}> | ||||
|           <DataGrid | ||||
|             rows={filteredRows} | ||||
|             columns={columns} | ||||
|             checkboxSelection | ||||
|           /> | ||||
|         </div> | ||||
|         <Button | ||||
|           variant="contained" | ||||
|           color="error" | ||||
|           onClick={onClose} | ||||
|           sx={{ mt: 2 }} | ||||
|         > | ||||
|           Close | ||||
|         </Button> | ||||
|       </Box> | ||||
|     </Modal> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default DirectorySearchModal; | ||||
| @ -0,0 +1,39 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { TextField, Button, Box } from '@mui/material'; | ||||
| 
 | ||||
| interface DirectorySearchPanelProps { | ||||
|   folderNameSlugged: string; | ||||
| } | ||||
| 
 | ||||
| const DirectorySearchPanel = ({ folderNameSlugged }: DirectorySearchPanelProps) => { | ||||
|   const [searchQuery, setSearchQuery] = useState(''); | ||||
| 
 | ||||
|   const handleSearchQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||||
|     setSearchQuery(event.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSearch = () => { | ||||
|     // Implement Meilisearch search here
 | ||||
|     console.log(`Searching ${folderNameSlugged} for ${searchQuery}`); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Box sx={{ padding: '16px', display: 'flex', flexDirection: 'column', height: '100%' }}> | ||||
|       <Box sx={{ display: 'flex', gap: '8px', marginBottom: '16px' }}> | ||||
|         <TextField | ||||
|           label="Search" | ||||
|           variant="outlined" | ||||
|           value={searchQuery} | ||||
|           onChange={handleSearchQueryChange} | ||||
|           sx={{ flex: 1 }} | ||||
|         /> | ||||
|         <Button variant="contained" color="primary" onClick={handleSearch}> | ||||
|           Search | ||||
|         </Button> | ||||
|       </Box> | ||||
|       {/* Add search results component here */} | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default DirectorySearchPanel; | ||||
| @ -96,6 +96,8 @@ export default function DirectoryPicker({ onSelect }: DirectoryPickerProps) { | ||||
| 
 | ||||
|   const handleSelect = () => { | ||||
|     onSelect(currentPath); | ||||
|     // Send the meilisearch-create-index event
 | ||||
|     electron.createIndex(currentPath); | ||||
|     handleClose(); | ||||
|   }; | ||||
| 
 | ||||
|  | ||||
| @ -1,24 +1,43 @@ | ||||
| import React from 'react'; | ||||
| import { Box, Typography, List, ListItem, ListItemText, ListItemIcon, IconButton, Tooltip } from '@mui/material'; | ||||
| import { Folder as FolderIcon, Psychology as LLMIcon, ImageSearch as OCRIcon } from '@mui/icons-material'; | ||||
| import { DocumentMetadata } from '../../../electron/types'; | ||||
| import DirectoryPicker from './DirectoryPicker'; | ||||
| import { useFileSystem } from '../../hooks/useFileSystem'; | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import { | ||||
|   Box, | ||||
|   List, | ||||
|   ListItem, | ||||
|   ListItemText, | ||||
|   ListItemIcon, | ||||
|   IconButton, | ||||
|   Tooltip, | ||||
| } from "@mui/material"; | ||||
| import { | ||||
|   Folder as FolderIcon, | ||||
|   Psychology as LLMIcon, | ||||
|   ImageSearch as OCRIcon, | ||||
|   Search as SearchIcon, | ||||
| } from "@mui/icons-material"; | ||||
| import { DocumentMetadata } from "../../../electron/types"; | ||||
| import DirectoryPicker from "./DirectoryPicker"; | ||||
| import { useFileSystem } from "../../hooks/useFileSystem"; | ||||
| import DirectorySearchModal from "../DirectorySearchModal"; | ||||
| 
 | ||||
| interface FileMetadata { | ||||
|   [path: string]: DocumentMetadata; | ||||
| } | ||||
| 
 | ||||
| interface Directory { | ||||
|   name: string; | ||||
|   path: string; | ||||
| } | ||||
| 
 | ||||
| export default function FileExplorer() { | ||||
|   const { watchedDirectories, watchDirectory, unwatchDirectory } = useFileSystem(); | ||||
|   const [fileMetadata, setFileMetadata] = React.useState<FileMetadata>({}); | ||||
|   const [fileMetadata, setFileMetadata] = useState<FileMetadata>({}); | ||||
|   const [openModal, setOpenModal] = useState<{ [key: string]: boolean }>({}); | ||||
| 
 | ||||
|   React.useEffect(() => { | ||||
|     // Get document metadata from electron store
 | ||||
|   useEffect(() => { | ||||
|     window.electron.getDocuments().then((response) => { | ||||
|       if (response.success && response.data) { | ||||
|         const metadata: FileMetadata = {}; | ||||
|         response.data.forEach(doc => { | ||||
|         response.data.forEach((doc) => { | ||||
|           metadata[doc.path] = doc; | ||||
|         }); | ||||
|         setFileMetadata(metadata); | ||||
| @ -36,33 +55,41 @@ export default function FileExplorer() { | ||||
|     await unwatchDirectory(dirPath); | ||||
|   }; | ||||
| 
 | ||||
|   const handleOpenModal = (dir: string) => { | ||||
|     setOpenModal((prev) => ({ ...prev, [dir]: true })); | ||||
|   }; | ||||
| 
 | ||||
|   const handleCloseModal = (dir: string) => { | ||||
|     setOpenModal((prev) => ({ ...prev, [dir]: false })); | ||||
|   }; | ||||
| 
 | ||||
|   const directoryList: Directory[] = watchedDirectories.map((dir) => ({ | ||||
|     name: dir.split(/[/\\]/).pop() || dir, | ||||
|     path: dir, | ||||
|   })); | ||||
| 
 | ||||
|   return ( | ||||
|     <Box sx={{  | ||||
|       display: 'flex',  | ||||
|       flexDirection: 'column', | ||||
|       height: '100%', | ||||
|       overflow: 'hidden' | ||||
|     }}> | ||||
|     <Box | ||||
|       sx={{ | ||||
|         display: "flex", | ||||
|         flexDirection: "column", | ||||
|         height: "100%", | ||||
|         overflow: "hidden", | ||||
|       }} | ||||
|     > | ||||
|       <DirectoryPicker directories={directoryList} onSelect={handleDirectorySelect} /> | ||||
| 
 | ||||
|       <DirectoryPicker onSelect={handleDirectorySelect} /> | ||||
| 
 | ||||
|       <Box sx={{ flex: 1, overflow: 'auto' }}> | ||||
|       <Box sx={{ flex: 1, overflow: "auto" }}> | ||||
|         <List> | ||||
|           {watchedDirectories.map((dir) => ( | ||||
|             <ListItem | ||||
|               key={dir} | ||||
|               secondaryAction={ | ||||
|                 <IconButton  | ||||
|                   edge="end"  | ||||
|                   size="small" | ||||
|                   onClick={() => handleDirectoryRemove(dir)} | ||||
|                 > | ||||
|                   × | ||||
|                 </IconButton> | ||||
|               } | ||||
|             > | ||||
|               <ListItemIcon sx={{ display: 'flex', gap: 0.5 }}> | ||||
|                 <FolderIcon /> | ||||
|           {watchedDirectories.map((dir) => { | ||||
|             const modalId = `modal-${dir}`; | ||||
| 
 | ||||
|             return ( | ||||
|               <ListItem key={dir} sx={{ display: "flex", alignItems: "center" }}> | ||||
|                 <ListItemIcon sx={{ minWidth: 28 }}> | ||||
|                   <FolderIcon fontSize="small" /> | ||||
|                 </ListItemIcon> | ||||
| 
 | ||||
|                 {fileMetadata[dir]?.hasEmbeddings && ( | ||||
|                   <Tooltip title="LLM Embeddings Enabled"> | ||||
|                     <LLMIcon color="primary" fontSize="small" /> | ||||
| @ -73,20 +100,35 @@ export default function FileExplorer() { | ||||
|                     <OCRIcon color="secondary" fontSize="small" /> | ||||
|                   </Tooltip> | ||||
|                 )} | ||||
|               </ListItemIcon> | ||||
|               <ListItemText | ||||
|                 primary={dir.split(/[/\\]/).pop()}  | ||||
|                 secondary={dir} | ||||
|                 secondaryTypographyProps={{ | ||||
|                   sx: {  | ||||
|                     overflow: 'hidden', | ||||
|                     textOverflow: 'ellipsis', | ||||
|                     whiteSpace: 'nowrap' | ||||
|                   } | ||||
|                 }} | ||||
|               /> | ||||
|             </ListItem> | ||||
|           ))} | ||||
| 
 | ||||
|                 <ListItemText | ||||
|                   primary={dir.split(/[/\\]/).pop()} | ||||
|                   secondary={dir} | ||||
|                   secondaryTypographyProps={{ | ||||
|                     sx: { | ||||
|                       overflow: "hidden", | ||||
|                       textOverflow: "ellipsis", | ||||
|                       whiteSpace: "nowrap", | ||||
|                     }, | ||||
|                   }} | ||||
|                 /> | ||||
| 
 | ||||
|                 {/* Search Icon to Open Modal */} | ||||
|                 <Tooltip title="Search"> | ||||
|                   <IconButton color="primary" size="small" onClick={() => handleOpenModal(dir)}> | ||||
|                     <SearchIcon fontSize="small" /> | ||||
|                   </IconButton> | ||||
|                 </Tooltip> | ||||
| 
 | ||||
|                 <DirectorySearchModal | ||||
|                   dir={dir} | ||||
|                   open={!!openModal[dir]} | ||||
|                   onClose={() => handleCloseModal(dir)} | ||||
|                   modalId={modalId} | ||||
|                 /> | ||||
|               </ListItem> | ||||
|             ); | ||||
|           })} | ||||
|         </List> | ||||
|       </Box> | ||||
|     </Box> | ||||
|  | ||||
							
								
								
									
										557
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										557
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,557 @@ | ||||
| { | ||||
|   "name": "test", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "dependencies": { | ||||
|         "@mui/x-data-grid": "^7.26.0", | ||||
|         "meilisearch": "^0.48.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@babel/runtime": { | ||||
|       "version": "7.26.7", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", | ||||
|       "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "regenerator-runtime": "^0.14.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@emotion/cache": { | ||||
|       "version": "11.14.0", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", | ||||
|       "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@emotion/memoize": "^0.9.0", | ||||
|         "@emotion/sheet": "^1.4.0", | ||||
|         "@emotion/utils": "^1.4.2", | ||||
|         "@emotion/weak-memoize": "^0.4.0", | ||||
|         "stylis": "4.2.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@emotion/hash": { | ||||
|       "version": "0.9.2", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", | ||||
|       "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@emotion/memoize": { | ||||
|       "version": "0.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", | ||||
|       "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@emotion/serialize": { | ||||
|       "version": "1.3.3", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", | ||||
|       "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@emotion/hash": "^0.9.2", | ||||
|         "@emotion/memoize": "^0.9.0", | ||||
|         "@emotion/unitless": "^0.10.0", | ||||
|         "@emotion/utils": "^1.4.2", | ||||
|         "csstype": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@emotion/sheet": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", | ||||
|       "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@emotion/unitless": { | ||||
|       "version": "0.10.0", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", | ||||
|       "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@emotion/utils": { | ||||
|       "version": "1.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", | ||||
|       "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@emotion/weak-memoize": { | ||||
|       "version": "0.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", | ||||
|       "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/@mui/core-downloads-tracker": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.3.tgz", | ||||
|       "integrity": "sha512-hlyOzo2ObarllAOeT1ZSAusADE5NZNencUeIvXrdQ1Na+FL1lcznhbxfV5He1KqGiuR8Az3xtCUcYKwMVGFdzg==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/material": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.3.tgz", | ||||
|       "integrity": "sha512-ubtQjplbWneIEU8Y+4b2VA0CDBlyH5I3AmVFGmsLyDe/bf0ubxav5t11c8Afem6rkSFWPlZA2DilxmGka1xiKQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.26.0", | ||||
|         "@mui/core-downloads-tracker": "^6.4.3", | ||||
|         "@mui/system": "^6.4.3", | ||||
|         "@mui/types": "^7.2.21", | ||||
|         "@mui/utils": "^6.4.3", | ||||
|         "@popperjs/core": "^2.11.8", | ||||
|         "@types/react-transition-group": "^4.4.12", | ||||
|         "clsx": "^2.1.1", | ||||
|         "csstype": "^3.1.3", | ||||
|         "prop-types": "^15.8.1", | ||||
|         "react-is": "^19.0.0", | ||||
|         "react-transition-group": "^4.4.5" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@emotion/react": "^11.5.0", | ||||
|         "@emotion/styled": "^11.3.0", | ||||
|         "@mui/material-pigment-css": "^6.4.3", | ||||
|         "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@emotion/react": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@emotion/styled": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@mui/material-pigment-css": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@types/react": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/private-theming": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.3.tgz", | ||||
|       "integrity": "sha512-7x9HaNwDCeoERc4BoEWLieuzKzXu5ZrhRnEM6AUcRXUScQLvF1NFkTlP59+IJfTbEMgcGg1wWHApyoqcksrBpQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.26.0", | ||||
|         "@mui/utils": "^6.4.3", | ||||
|         "prop-types": "^15.8.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@types/react": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/styled-engine": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.3.tgz", | ||||
|       "integrity": "sha512-OC402VfK+ra2+f12Gef8maY7Y9n7B6CZcoQ9u7mIkh/7PKwW/xH81xwX+yW+Ak1zBT3HYcVjh2X82k5cKMFGoQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.26.0", | ||||
|         "@emotion/cache": "^11.13.5", | ||||
|         "@emotion/serialize": "^1.3.3", | ||||
|         "@emotion/sheet": "^1.4.0", | ||||
|         "csstype": "^3.1.3", | ||||
|         "prop-types": "^15.8.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@emotion/react": "^11.4.1", | ||||
|         "@emotion/styled": "^11.3.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@emotion/react": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@emotion/styled": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/system": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.3.tgz", | ||||
|       "integrity": "sha512-Q0iDwnH3+xoxQ0pqVbt8hFdzhq1g2XzzR4Y5pVcICTNtoCLJmpJS3vI4y/OIM1FHFmpfmiEC2IRIq7YcZ8nsmg==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.26.0", | ||||
|         "@mui/private-theming": "^6.4.3", | ||||
|         "@mui/styled-engine": "^6.4.3", | ||||
|         "@mui/types": "^7.2.21", | ||||
|         "@mui/utils": "^6.4.3", | ||||
|         "clsx": "^2.1.1", | ||||
|         "csstype": "^3.1.3", | ||||
|         "prop-types": "^15.8.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@emotion/react": "^11.5.0", | ||||
|         "@emotion/styled": "^11.3.0", | ||||
|         "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@emotion/react": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@emotion/styled": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@types/react": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/types": { | ||||
|       "version": "7.2.21", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", | ||||
|       "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@types/react": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/utils": { | ||||
|       "version": "6.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.3.tgz", | ||||
|       "integrity": "sha512-jxHRHh3BqVXE9ABxDm+Tc3wlBooYz/4XPa0+4AI+iF38rV1/+btJmSUgG4shDtSWVs/I97aDn5jBCt6SF2Uq2A==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.26.0", | ||||
|         "@mui/types": "^7.2.21", | ||||
|         "@types/prop-types": "^15.7.14", | ||||
|         "clsx": "^2.1.1", | ||||
|         "prop-types": "^15.8.1", | ||||
|         "react-is": "^19.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@types/react": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/x-data-grid": { | ||||
|       "version": "7.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.26.0.tgz", | ||||
|       "integrity": "sha512-9RNQeT2OL6jBOCE0MSUH11ol3fV5Zs9MkGxUIAGXcy/Fui0rZRNFO1yLmWDZU5yvskiNmUZJHWV/qXh++ZFarA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.25.7", | ||||
|         "@mui/utils": "^5.16.6 || ^6.0.0", | ||||
|         "@mui/x-internals": "7.26.0", | ||||
|         "clsx": "^2.1.1", | ||||
|         "prop-types": "^15.8.1", | ||||
|         "reselect": "^5.1.1", | ||||
|         "use-sync-external-store": "^1.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@emotion/react": "^11.9.0", | ||||
|         "@emotion/styled": "^11.8.1", | ||||
|         "@mui/material": "^5.15.14 || ^6.0.0", | ||||
|         "@mui/system": "^5.15.14 || ^6.0.0", | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@emotion/react": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@emotion/styled": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@mui/x-internals": { | ||||
|       "version": "7.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.26.0.tgz", | ||||
|       "integrity": "sha512-VxTCYQcZ02d3190pdvys2TDg9pgbvewAVakEopiOgReKAUhLdRlgGJHcOA/eAuGLyK1YIo26A6Ow6ZKlSRLwMg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.25.7", | ||||
|         "@mui/utils": "^5.16.6 || ^6.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/mui-org" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@popperjs/core": { | ||||
|       "version": "2.11.8", | ||||
|       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", | ||||
|       "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/popperjs" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/prop-types": { | ||||
|       "version": "15.7.14", | ||||
|       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", | ||||
|       "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@types/react": { | ||||
|       "version": "19.0.8", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz", | ||||
|       "integrity": "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "csstype": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/react-transition-group": { | ||||
|       "version": "4.4.12", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", | ||||
|       "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "peerDependencies": { | ||||
|         "@types/react": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/clsx": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", | ||||
|       "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/csstype": { | ||||
|       "version": "3.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", | ||||
|       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/dom-helpers": { | ||||
|       "version": "5.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", | ||||
|       "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.8.7", | ||||
|         "csstype": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/js-tokens": { | ||||
|       "version": "4.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", | ||||
|       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/loose-envify": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", | ||||
|       "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "js-tokens": "^3.0.0 || ^4.0.0" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "loose-envify": "cli.js" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/meilisearch": { | ||||
|       "version": "0.48.2", | ||||
|       "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.48.2.tgz", | ||||
|       "integrity": "sha512-auDB6grs3f/+dVzzPiAOOFnrVN/L87/+SWZfy56TpimDinWjU4u6Jc2o6lgeLluotpbMOFY1WpTTbqtUdMduQw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/object-assign": { | ||||
|       "version": "4.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||
|       "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/prop-types": { | ||||
|       "version": "15.8.1", | ||||
|       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", | ||||
|       "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "loose-envify": "^1.4.0", | ||||
|         "object-assign": "^4.1.1", | ||||
|         "react-is": "^16.13.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/prop-types/node_modules/react-is": { | ||||
|       "version": "16.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||
|       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/react": { | ||||
|       "version": "19.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", | ||||
|       "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-dom": { | ||||
|       "version": "19.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", | ||||
|       "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", | ||||
|       "license": "MIT", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "scheduler": "^0.25.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "react": "^19.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-is": { | ||||
|       "version": "19.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", | ||||
|       "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/react-transition-group": { | ||||
|       "version": "4.4.5", | ||||
|       "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", | ||||
|       "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", | ||||
|       "license": "BSD-3-Clause", | ||||
|       "peer": true, | ||||
|       "dependencies": { | ||||
|         "@babel/runtime": "^7.5.5", | ||||
|         "dom-helpers": "^5.0.1", | ||||
|         "loose-envify": "^1.4.0", | ||||
|         "prop-types": "^15.6.2" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "react": ">=16.6.0", | ||||
|         "react-dom": ">=16.6.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/regenerator-runtime": { | ||||
|       "version": "0.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", | ||||
|       "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/reselect": { | ||||
|       "version": "5.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", | ||||
|       "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/scheduler": { | ||||
|       "version": "0.25.0", | ||||
|       "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", | ||||
|       "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/stylis": { | ||||
|       "version": "4.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", | ||||
|       "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", | ||||
|       "license": "MIT", | ||||
|       "peer": true | ||||
|     }, | ||||
|     "node_modules/use-sync-external-store": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", | ||||
|       "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										6
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "@mui/x-data-grid": "^7.26.0", | ||||
|     "meilisearch": "^0.48.2" | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user