search
This commit is contained in:
parent
7a24d3cb98
commit
29f76c9e9d
@ -1,4 +1,4 @@
|
|||||||
# Data Identification Manager : Personal Edition
|
# Data Identification Manager
|
||||||
|
|
||||||
An Electron-based desktop application that uses AI to help you search and understand your files through natural language queries.
|
An Electron-based desktop application that uses AI to help you search and understand your files through natural language queries.
|
||||||
|
|
||||||
|
@ -277,6 +277,28 @@ export function setupIpcHandlers() {
|
|||||||
return { success: false, error: err.message };
|
return { success: false, error: err.message };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('meilisearch-get-documents', async (_: unknown, indexName: string) => {
|
||||||
|
try {
|
||||||
|
const documents = await (global as any).meilisearchService.getDocuments(indexName);
|
||||||
|
return { success: true, data: documents };
|
||||||
|
} catch (error) {
|
||||||
|
const err = error as Error;
|
||||||
|
console.error('Error getting documents from Meilisearch:', err);
|
||||||
|
return { success: false, error: err.message };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('meilisearch-search', async (_: unknown, indexName: string, query: string) => {
|
||||||
|
try {
|
||||||
|
const results = await (global as any).meilisearchService.search(indexName, query);
|
||||||
|
return { success: true, data: results };
|
||||||
|
} catch (error) {
|
||||||
|
const err = error as Error;
|
||||||
|
console.error('Error searching Meilisearch:', err);
|
||||||
|
return { success: false, error: err.message };
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default setupIpcHandlers;
|
export default setupIpcHandlers;
|
||||||
|
@ -14,170 +14,14 @@ const slugify = (str: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { platform } = require('os');
|
const { platform } = require('os');
|
||||||
|
import MeilisearchService from './services/meilisearchService';
|
||||||
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();
|
const meilisearchService = new MeilisearchService();
|
||||||
(global as any).meilisearchService = meilisearchService;
|
(global as any).meilisearchService = meilisearchService;
|
||||||
|
|
||||||
|
// Initialize IPC handlers immediately
|
||||||
|
setupIpcHandlers();
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
|
@ -84,6 +84,9 @@ contextBridge.exposeInMainWorld('electron', {
|
|||||||
ipcRenderer.removeListener(channel, onProgress);
|
ipcRenderer.removeListener(channel, onProgress);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
meilisearchSearch: async (indexName: string, query: string): Promise<{ success: boolean; data: any[] }> =>
|
||||||
|
ipcRenderer.invoke('meilisearch-search', indexName, query),
|
||||||
|
|
||||||
// Window Controls
|
// Window Controls
|
||||||
minimizeWindow: () => ipcRenderer.invoke('window-minimize'),
|
minimizeWindow: () => ipcRenderer.invoke('window-minimize'),
|
||||||
|
@ -1,13 +1,89 @@
|
|||||||
import { MeiliSearch } from 'meilisearch'
|
import { MeiliSearch } from 'meilisearch';
|
||||||
|
import slugify from 'slugify';
|
||||||
|
const { platform } = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
const spawn = require('child_process').spawn;
|
||||||
|
|
||||||
class MeilisearchService {
|
class MeilisearchService {
|
||||||
private client: MeiliSearch;
|
private client: MeiliSearch;
|
||||||
|
private binaryPath: string;
|
||||||
|
private serverProcess: any | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.client = new MeiliSearch({
|
this.client = new MeiliSearch({
|
||||||
host: 'http://localhost:7700',
|
host: 'http://localhost:7700',
|
||||||
});
|
});
|
||||||
this.createIndex('files'); // Ensure the index exists
|
this.binaryPath = this.getBinaryPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// Implement methods for adding, removing, and updating documents and collections
|
||||||
@ -68,17 +144,26 @@ class MeilisearchService {
|
|||||||
public async getDocuments(indexName: string): Promise<any[]> {
|
public async getDocuments(indexName: string): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const index = this.client.index(indexName);
|
const index = this.client.index(indexName);
|
||||||
const { hits } = await index.search(''); // Empty search to get all documents
|
const documents = await index.getDocuments();
|
||||||
return hits;
|
return documents.results;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to get documents from index ${indexName}:`, error);
|
console.error(`Failed to get documents from index ${indexName}:`, error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private slugifyPath(path):string {
|
||||||
|
return path
|
||||||
|
.toLowerCase() // Convert to lowercase
|
||||||
|
.replace(/[\\\/:*?"<>|]/g, '-') // Replace invalid characters with a dash
|
||||||
|
.replace(/\s+/g, '-') // Replace spaces with a dash
|
||||||
|
.replace(/-+/g, '-') // Replace multiple dashes with a single dash
|
||||||
|
.replace(/^-+|-+$/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
public async search(indexName: string, query: string): Promise<any[]> {
|
public async search(indexName: string, query: string): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const index = this.client.index(indexName);
|
console.log(indexName)
|
||||||
|
const index = this.client.index(this.slugifyPath(indexName));
|
||||||
const { hits } = await index.search(query);
|
const { hits } = await index.search(query);
|
||||||
return hits;
|
return hits;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;" />
|
||||||
<title>Data Identification Manager : Personal Edition</title>
|
<title>Data Identification Manager</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
12
electron-file-search/package-lock.json
generated
12
electron-file-search/package-lock.json
generated
@ -26,7 +26,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-markdown": "^9.0.3",
|
"react-markdown": "^9.0.3",
|
||||||
"react-virtuoso": "^4.12.5",
|
"react-virtuoso": "^4.12.5",
|
||||||
"rehype-highlight": "^7.0.2"
|
"rehype-highlight": "^7.0.2",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.16",
|
"@types/node": "^20.11.16",
|
||||||
@ -8910,6 +8911,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/slugify": {
|
||||||
|
"version": "1.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
|
||||||
|
"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/smart-buffer": {
|
"node_modules/smart-buffer": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-markdown": "^9.0.3",
|
"react-markdown": "^9.0.3",
|
||||||
"react-virtuoso": "^4.12.5",
|
"react-virtuoso": "^4.12.5",
|
||||||
"rehype-highlight": "^7.0.2"
|
"rehype-highlight": "^7.0.2",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "com.electron-file-search",
|
"appId": "com.electron-file-search",
|
||||||
|
@ -154,7 +154,7 @@ function AppContent() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
startIcon={<UpgradeTwoTone />}
|
startIcon={<UpgradeTwoTone />}
|
||||||
@ -250,7 +250,7 @@ function AppContent() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Enterprise
|
Enterprise
|
||||||
</Button>
|
</Button>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -266,20 +266,7 @@ function AppContent() {
|
|||||||
Data Identification Manager
|
Data Identification Manager
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className="window-controls">
|
<div className="window-controls">
|
||||||
<Chip
|
|
||||||
label="Personal Edition (Free)"
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
sx={{
|
|
||||||
bgcolor: 'primary.main', // or 'secondary.main', 'error.main', etc.
|
|
||||||
color: 'primary.contrastText',
|
|
||||||
borderRadius: 1,
|
|
||||||
height: 'auto',
|
|
||||||
'& .MuiChip-label': {
|
|
||||||
padding: '4px 8px',
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<button
|
<button
|
||||||
className="control-button"
|
className="control-button"
|
||||||
onClick={() => window.electron.closeWindow()}
|
onClick={() => window.electron.closeWindow()}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
|
||||||
Button,
|
Button,
|
||||||
Modal,
|
Modal,
|
||||||
TextField,
|
TextField,
|
||||||
@ -29,54 +28,67 @@ interface FileData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{ field: 'id', headerName: 'ID', width: 50 },
|
|
||||||
{ field: 'filePath', headerName: 'File Path', width: 250 },
|
{ field: 'filePath', headerName: 'File Path', width: 250 },
|
||||||
{ field: 'fileName', headerName: 'File Name', width: 150 },
|
{ field: 'fileName', headerName: 'File Name', width: 150 },
|
||||||
{ field: 'fileExtension', headerName: 'File Extension', width: 100 },
|
{ field: 'fileExtension', headerName: 'File Extension', width: 100 },
|
||||||
|
{
|
||||||
|
field: 'size',
|
||||||
|
headerName: 'Size',
|
||||||
|
width: 100,
|
||||||
|
valueFormatter: (value:any) => {
|
||||||
|
console.log("params.value:", value); // Debugging lin
|
||||||
|
// Ensure the value is a number
|
||||||
|
const bytes = typeof value === 'number' ? value : 0;
|
||||||
|
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
|
||||||
|
const k = 1024;
|
||||||
|
const dm = 2;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
{ field: 'createdAt', headerName: 'Created At', width: 150 },
|
{ field: 'createdAt', headerName: 'Created At', width: 150 },
|
||||||
{ field: 'modifiedAt', headerName: 'Modified At', width: 150 },
|
{ field: 'modifiedAt', headerName: 'Modified At', width: 150 },
|
||||||
{ field: 'accessedAt', headerName: 'Accessed 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 DirectorySearchModal: React.FC<DirectorySearchModalProps> = ({ dir, open, onClose, modalId }) => {
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [rows, setRows] = useState<FileData[]>([]);
|
const [rows, setRows] = useState<FileData[]>([]);
|
||||||
|
|
||||||
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setSearchQuery(event.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchFileData = async () => {
|
handleSearchChange({ target: { value: '*' } } as any);
|
||||||
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();
|
const handleSearchChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
}, [dir]);
|
const query = event.target.value;
|
||||||
|
setSearchQuery(query);
|
||||||
const filteredRows = rows.filter((row) => {
|
|
||||||
return (
|
window.electron.meilisearchSearch(dir, query)
|
||||||
row.filePath.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
.then((response: { success: boolean; data: any[]; error?: string }) => {
|
||||||
row.fileName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
if (response.success && response.data) {
|
||||||
row.fileExtension.toLowerCase().includes(searchQuery.toLowerCase())
|
const fileData: FileData[] = response.data.map((doc: any, index: number) => ({
|
||||||
);
|
id: doc.name,
|
||||||
});
|
filePath: doc.name,
|
||||||
|
fileName: doc.fileName,
|
||||||
|
fileExtension: doc.extension,
|
||||||
|
size: doc.size, // Ensure size is not undefined
|
||||||
|
createdAt: doc.createdAt,
|
||||||
|
modifiedAt: doc.modifiedAt,
|
||||||
|
accessedAt: doc.accessedAt,
|
||||||
|
}));
|
||||||
|
setRows(fileData);
|
||||||
|
} else {
|
||||||
|
console.error('Error searching Meilisearch:', response.error);
|
||||||
|
setRows([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -131,19 +143,47 @@ const DirectorySearchModal: React.FC<DirectorySearchModalProps> = ({ dir, open,
|
|||||||
</Box>
|
</Box>
|
||||||
<div style={{ height: 400, width: '100%' }}>
|
<div style={{ height: 400, width: '100%' }}>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
rows={filteredRows}
|
rows={rows}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
checkboxSelection
|
checkboxSelection
|
||||||
|
rowCount={rows.length}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="error"
|
color="primary"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
sx={{ mt: 2 }}
|
sx={{ mt: 2, m:1 }}
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="warning"
|
||||||
|
onClick={onClose}
|
||||||
|
disabled
|
||||||
|
sx={{ mt: 2, m:1 }}
|
||||||
|
>
|
||||||
|
Move To
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="warning"
|
||||||
|
onClick={onClose}
|
||||||
|
disabled
|
||||||
|
sx={{ mt: 2, m:1 }}
|
||||||
|
>
|
||||||
|
Copy To
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
onClick={onClose}
|
||||||
|
disabled
|
||||||
|
sx={{ mt: 2, m:1 }}
|
||||||
|
>
|
||||||
|
Clean From System
|
||||||
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
2
electron-file-search/src/electron.d.ts
vendored
2
electron-file-search/src/electron.d.ts
vendored
@ -19,7 +19,7 @@ declare global {
|
|||||||
sources: DocumentMetadata[];
|
sources: DocumentMetadata[];
|
||||||
}>;
|
}>;
|
||||||
getLLMConfig: () => Promise<LLMConfig>;
|
getLLMConfig: () => Promise<LLMConfig>;
|
||||||
|
meilisearchSearch: (indexName: string, query: string) => Promise<{ success: boolean; data: any[] }>;
|
||||||
// Vector Store Operations
|
// Vector Store Operations
|
||||||
getDocuments: () => Promise<{ success: boolean; data?: DocumentMetadata[]; error?: string }>;
|
getDocuments: () => Promise<{ success: boolean; data?: DocumentMetadata[]; error?: string }>;
|
||||||
addDocument: (content: string, metadata: DocumentMetadata) => Promise<void>;
|
addDocument: (content: string, metadata: DocumentMetadata) => Promise<void>;
|
||||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -6,7 +6,8 @@
|
|||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mui/x-data-grid": "^7.26.0",
|
"@mui/x-data-grid": "^7.26.0",
|
||||||
"meilisearch": "^0.48.2"
|
"meilisearch": "^0.48.2",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
@ -537,6 +538,15 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/slugify": {
|
||||||
|
"version": "1.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
|
||||||
|
"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stylis": {
|
"node_modules/stylis": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mui/x-data-grid": "^7.26.0",
|
"@mui/x-data-grid": "^7.26.0",
|
||||||
"meilisearch": "^0.48.2"
|
"meilisearch": "^0.48.2",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user