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