version mise à jour par claude , à tester
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Workflow Service
|
||||
* Handles workflow fetching with lazy loading and caching
|
||||
* Workflows are only loaded when first requested (not at startup)
|
||||
*/
|
||||
|
||||
const apiService = require('./api-service').getInstance();
|
||||
const profileManager = require('../config/profile-manager');
|
||||
|
||||
// Cache state
|
||||
let workflowCache = null;
|
||||
let cacheTimestamp = null;
|
||||
const CACHE_TTL = parseInt(process.env.WORKFLOW_CACHE_TTL) || 3600000; // 1 hour in milliseconds
|
||||
|
||||
// Clear cache when profile changes — workflows are per-tenant, so the previous
|
||||
// profile's cache is meaningless after a switch.
|
||||
profileManager.onSwitch(() => clearCache());
|
||||
|
||||
/**
|
||||
* Check if cache is still valid
|
||||
*/
|
||||
function isCacheValid() {
|
||||
if (!workflowCache || !cacheTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const age = now - cacheTimestamp;
|
||||
return age < CACHE_TTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all workflows from API with pagination
|
||||
* Uses high page size (5000) to minimize API calls
|
||||
*/
|
||||
async function fetchAllWorkflows() {
|
||||
// Check cache validity
|
||||
if (isCacheValid()) {
|
||||
console.error('[Workflow] Using cached data');
|
||||
return workflowCache;
|
||||
}
|
||||
|
||||
console.error('[Workflow] Cache expired or empty, fetching from API...');
|
||||
|
||||
try {
|
||||
let allWorkflows = [];
|
||||
let offset = 0;
|
||||
const pageSize = parseInt(process.env.WORKFLOW_PAGE_SIZE) || 5000;
|
||||
const profile = profileManager.getCurrent();
|
||||
const application = profile.application;
|
||||
const tenant = profile.tenant;
|
||||
|
||||
while (true) {
|
||||
const body = [application, tenant, pageSize, offset];
|
||||
|
||||
console.error(`[Workflow] Fetching page: offset=${offset}, pageSize=${pageSize}`);
|
||||
|
||||
// Use AD API (useAdApi=true)
|
||||
const response = await apiService.post('/Workflow/GetByApplication', body, true);
|
||||
|
||||
// Extract entities array from response
|
||||
const workflows = response?.entities || [];
|
||||
|
||||
// Check if response is valid
|
||||
if (!workflows || workflows.length === 0) {
|
||||
console.error('[Workflow] No more workflows to fetch');
|
||||
break;
|
||||
}
|
||||
|
||||
allWorkflows = allWorkflows.concat(workflows);
|
||||
console.error(`[Workflow] Fetched ${workflows.length} workflows (total: ${allWorkflows.length})`);
|
||||
|
||||
// If we got less than page size, we've reached the last page
|
||||
if (workflows.length < pageSize) {
|
||||
console.error('[Workflow] Last page reached');
|
||||
break;
|
||||
}
|
||||
|
||||
offset += pageSize;
|
||||
}
|
||||
|
||||
// Update cache
|
||||
workflowCache = allWorkflows;
|
||||
cacheTimestamp = Date.now();
|
||||
|
||||
console.error(`[Workflow] Successfully cached ${allWorkflows.length} workflows`);
|
||||
return allWorkflows;
|
||||
} catch (error) {
|
||||
console.error('[Workflow] Error fetching workflows:', error.message);
|
||||
throw new Error(`Failed to fetch workflows: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search workflows by query string
|
||||
* @param {string} query - Search query (matches name, description, etc.)
|
||||
* @param {string|null} category - Optional category filter
|
||||
* @param {number} limit - Maximum results to return
|
||||
*/
|
||||
async function searchWorkflows(query, category = null, limit = 50) {
|
||||
const workflows = await fetchAllWorkflows();
|
||||
|
||||
let results = workflows;
|
||||
|
||||
// Filter by query if provided
|
||||
if (query) {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
results = results.filter(w => {
|
||||
const name = (w.name || w.Name || '').toLowerCase();
|
||||
const description = (w.description || w.Description || '').toLowerCase();
|
||||
const code = (w.code || w.Code || '').toLowerCase();
|
||||
|
||||
return name.includes(lowerQuery) ||
|
||||
description.includes(lowerQuery) ||
|
||||
code.includes(lowerQuery);
|
||||
});
|
||||
}
|
||||
|
||||
// Filter by category if provided
|
||||
if (category) {
|
||||
const lowerCategory = category.toLowerCase();
|
||||
results = results.filter(w => {
|
||||
const wfCategory = (w.category || w.Category || '').toLowerCase();
|
||||
return wfCategory.includes(lowerCategory);
|
||||
});
|
||||
}
|
||||
|
||||
// Limit results
|
||||
return results.slice(0, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workflow details by ID
|
||||
* @param {string|number} workflowId - Workflow ID
|
||||
*/
|
||||
async function getWorkflowDetails(workflowId) {
|
||||
const workflows = await fetchAllWorkflows();
|
||||
|
||||
// Try to find by Id, id, Code, code, Name, or name
|
||||
const workflow = workflows.find(w =>
|
||||
w.id === workflowId ||
|
||||
w.Id === workflowId ||
|
||||
w.id === parseInt(workflowId) ||
|
||||
w.Id === parseInt(workflowId) ||
|
||||
w.Code === workflowId ||
|
||||
w.code === workflowId ||
|
||||
w.Name === workflowId ||
|
||||
w.name === workflowId
|
||||
);
|
||||
|
||||
if (!workflow) {
|
||||
throw new Error(`Workflow not found: ${workflowId}`);
|
||||
}
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all workflow categories
|
||||
*/
|
||||
async function listWorkflowCategories() {
|
||||
const workflows = await fetchAllWorkflows();
|
||||
|
||||
// Extract unique categories (try both lowercase and uppercase)
|
||||
const categories = new Set();
|
||||
workflows.forEach(w => {
|
||||
const category = w.category || w.Category;
|
||||
if (category) {
|
||||
categories.add(category);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort alphabetically
|
||||
return Array.from(categories).sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workflow statistics
|
||||
*/
|
||||
async function getWorkflowStats() {
|
||||
const workflows = await fetchAllWorkflows();
|
||||
const categories = await listWorkflowCategories();
|
||||
|
||||
// Count workflows per category
|
||||
const categoryCounts = {};
|
||||
workflows.forEach(w => {
|
||||
const cat = w.category || w.Category || 'Uncategorized';
|
||||
categoryCounts[cat] = (categoryCounts[cat] || 0) + 1;
|
||||
});
|
||||
|
||||
return {
|
||||
total: workflows.length,
|
||||
categories: categories.length,
|
||||
categoryCounts,
|
||||
cacheAge: cacheTimestamp ? Math.floor((Date.now() - cacheTimestamp) / 1000) : null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear workflow cache (force refresh on next request)
|
||||
*/
|
||||
function clearCache() {
|
||||
workflowCache = null;
|
||||
cacheTimestamp = null;
|
||||
console.error('[Workflow] Cache cleared');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache status
|
||||
*/
|
||||
function getCacheStatus() {
|
||||
return {
|
||||
cached: workflowCache !== null,
|
||||
count: workflowCache ? workflowCache.length : 0,
|
||||
timestamp: cacheTimestamp,
|
||||
age: cacheTimestamp ? Math.floor((Date.now() - cacheTimestamp) / 1000) : null,
|
||||
valid: isCacheValid()
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchAllWorkflows,
|
||||
searchWorkflows,
|
||||
getWorkflowDetails,
|
||||
listWorkflowCategories,
|
||||
getWorkflowStats,
|
||||
clearCache,
|
||||
getCacheStatus
|
||||
};
|
||||
Reference in New Issue
Block a user