mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-27 06:39:24 +00:00

* automate feature * Moved all providers to app level to simplify homepage * Circular dependency fixes * You will see that now toolRegistry gets a tool config and a tool settings object. These enable automate to run the tools using as much static code as possible. --------- Co-authored-by: Connor Yoh <connor@stirlingpdf.com>
183 lines
5.2 KiB
TypeScript
183 lines
5.2 KiB
TypeScript
/**
|
|
* Service for managing automation configurations in IndexedDB
|
|
*/
|
|
|
|
export interface AutomationConfig {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
operations: Array<{
|
|
operation: string;
|
|
parameters: any;
|
|
}>;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
class AutomationStorage {
|
|
private dbName = 'StirlingPDF_Automations';
|
|
private dbVersion = 1;
|
|
private storeName = 'automations';
|
|
private db: IDBDatabase | null = null;
|
|
|
|
async init(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
const request = indexedDB.open(this.dbName, this.dbVersion);
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to open automation storage database'));
|
|
};
|
|
|
|
request.onsuccess = () => {
|
|
this.db = request.result;
|
|
resolve();
|
|
};
|
|
|
|
request.onupgradeneeded = (event) => {
|
|
const db = (event.target as IDBOpenDBRequest).result;
|
|
|
|
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
const store = db.createObjectStore(this.storeName, { keyPath: 'id' });
|
|
store.createIndex('name', 'name', { unique: false });
|
|
store.createIndex('createdAt', 'createdAt', { unique: false });
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
async ensureDB(): Promise<IDBDatabase> {
|
|
if (!this.db) {
|
|
await this.init();
|
|
}
|
|
|
|
if (!this.db) {
|
|
throw new Error('Database not initialized');
|
|
}
|
|
|
|
return this.db;
|
|
}
|
|
|
|
async saveAutomation(automation: Omit<AutomationConfig, 'id' | 'createdAt' | 'updatedAt'>): Promise<AutomationConfig> {
|
|
const db = await this.ensureDB();
|
|
const timestamp = new Date().toISOString();
|
|
|
|
const automationWithMeta: AutomationConfig = {
|
|
id: `automation-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
...automation,
|
|
createdAt: timestamp,
|
|
updatedAt: timestamp
|
|
};
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction([this.storeName], 'readwrite');
|
|
const store = transaction.objectStore(this.storeName);
|
|
const request = store.add(automationWithMeta);
|
|
|
|
request.onsuccess = () => {
|
|
resolve(automationWithMeta);
|
|
};
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to save automation'));
|
|
};
|
|
});
|
|
}
|
|
|
|
async updateAutomation(automation: AutomationConfig): Promise<AutomationConfig> {
|
|
const db = await this.ensureDB();
|
|
|
|
const updatedAutomation: AutomationConfig = {
|
|
...automation,
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction([this.storeName], 'readwrite');
|
|
const store = transaction.objectStore(this.storeName);
|
|
const request = store.put(updatedAutomation);
|
|
|
|
request.onsuccess = () => {
|
|
resolve(updatedAutomation);
|
|
};
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to update automation'));
|
|
};
|
|
});
|
|
}
|
|
|
|
async getAutomation(id: string): Promise<AutomationConfig | null> {
|
|
const db = await this.ensureDB();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction([this.storeName], 'readonly');
|
|
const store = transaction.objectStore(this.storeName);
|
|
const request = store.get(id);
|
|
|
|
request.onsuccess = () => {
|
|
resolve(request.result || null);
|
|
};
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to get automation'));
|
|
};
|
|
});
|
|
}
|
|
|
|
async getAllAutomations(): Promise<AutomationConfig[]> {
|
|
const db = await this.ensureDB();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction([this.storeName], 'readonly');
|
|
const store = transaction.objectStore(this.storeName);
|
|
const request = store.getAll();
|
|
|
|
request.onsuccess = () => {
|
|
const automations = request.result || [];
|
|
// Sort by creation date, newest first
|
|
automations.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
resolve(automations);
|
|
};
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to get automations'));
|
|
};
|
|
});
|
|
}
|
|
|
|
async deleteAutomation(id: string): Promise<void> {
|
|
const db = await this.ensureDB();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction([this.storeName], 'readwrite');
|
|
const store = transaction.objectStore(this.storeName);
|
|
const request = store.delete(id);
|
|
|
|
request.onsuccess = () => {
|
|
resolve();
|
|
};
|
|
|
|
request.onerror = () => {
|
|
reject(new Error('Failed to delete automation'));
|
|
};
|
|
});
|
|
}
|
|
|
|
async searchAutomations(query: string): Promise<AutomationConfig[]> {
|
|
const automations = await this.getAllAutomations();
|
|
|
|
if (!query.trim()) {
|
|
return automations;
|
|
}
|
|
|
|
const lowerQuery = query.toLowerCase();
|
|
return automations.filter(automation =>
|
|
automation.name.toLowerCase().includes(lowerQuery) ||
|
|
(automation.description && automation.description.toLowerCase().includes(lowerQuery)) ||
|
|
automation.operations.some(op => op.operation.toLowerCase().includes(lowerQuery))
|
|
);
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const automationStorage = new AutomationStorage(); |