ui-nyla/src/core/PageManager/data/pages/automations.ts
2026-01-23 21:05:36 +01:00

282 lines
10 KiB
TypeScript

import { useCallback } from 'react';
import { GenericPageData } from '../../pageInterface';
import { FaCog, FaPlus } from 'react-icons/fa';
import { useAutomations, useAutomationOperations } from '../../../../hooks/useAutomations';
// Helper function to convert attribute definitions to column config
const attributesToColumns = (attributes: any[]) => {
return attributes
.filter(attr => {
// Exclude template and complex fields from table display
const attrNameLower = attr.name.toLowerCase();
const excludedColumns = ['template', 'executionlogs', 'execution_logs'];
return !excludedColumns.includes(attrNameLower);
})
.map(attr => {
const attrNameLower = attr.name.toLowerCase();
const isDateField = attr.type === 'date' ||
/(date|Date|timestamp|Timestamp|created|Created|updated|Updated|at|At)$/i.test(attr.name);
const column: any = {
key: attr.name,
label: attr.label || attr.name,
type: attr.type || 'string',
width: attr.width || 200,
minWidth: attr.minWidth || 100,
maxWidth: attr.maxWidth || 400,
sortable: attr.sortable !== false,
filterable: isDateField ? false : (attr.filterable !== false),
searchable: attr.searchable !== false,
filterOptions: attr.filterOptions
};
// Format schedule field
if (attrNameLower === 'schedule') {
column.formatter = (value: any) => {
if (!value) return '-';
const scheduleLabels: Record<string, string> = {
'0 */4 * * *': 'Every 4 hours',
'0 22 * * *': 'Daily at 22:00',
'0 10 * * 1': 'Weekly Monday 10:00'
};
return scheduleLabels[value] || value;
};
}
// Format active field as badge
if (attrNameLower === 'active') {
column.type = 'boolean';
}
// Format placeholders as count
if (attrNameLower === 'placeholders') {
column.formatter = (value: any) => {
if (!value) return '-';
let obj;
if (typeof value === 'string') {
try {
obj = JSON.parse(value);
} catch {
return '-';
}
} else if (typeof value === 'object') {
obj = value;
} else {
return '-';
}
const count = Object.keys(obj).length;
return `${count} placeholder${count !== 1 ? 's' : ''}`;
};
}
return column;
});
};
// Hook factory function for automations data
const createAutomationsHook = () => {
return () => {
const {
automations,
loading,
error,
refetch,
removeOptimistically,
updateOptimistically,
attributes,
permissions,
pagination,
fetchAutomationById,
generateEditFieldsFromAttributes,
generateCreateFieldsFromAttributes,
ensureAttributesLoaded
} = useAutomations();
const {
handleAutomationDelete,
handleAutomationCreate,
handleAutomationUpdate,
handleAutomationExecute,
handleAutomationToggleActive,
deletingAutomations,
creatingAutomation,
executingAutomations,
deleteError,
createError,
updateError
} = useAutomationOperations();
const generatedColumns = attributes && attributes.length > 0
? attributesToColumns(attributes)
: undefined;
// Handle single automation deletion
const handleDeleteSingle = useCallback(async (automation: any) => {
const success = await handleAutomationDelete(automation.id);
if (success) {
refetch();
}
}, [handleAutomationDelete, refetch]);
// Handle multiple automation deletion
const handleDeleteMultiple = useCallback(async (selectedAutomations: any[]) => {
const results = await Promise.all(
selectedAutomations.map(a => handleAutomationDelete(a.id))
);
const allSuccessful = results.every(result => result);
if (allSuccessful) {
refetch();
}
}, [handleAutomationDelete, refetch]);
// Wrapped create handler
const wrappedHandleAutomationCreate = useCallback(async (formData: any) => {
return await handleAutomationCreate(formData);
}, [handleAutomationCreate]);
return {
data: automations,
loading,
error,
refetch,
removeOptimistically,
updateOptimistically,
// Operations
handleDelete: handleAutomationDelete,
handleDeleteMultiple,
handleAutomationCreate: wrappedHandleAutomationCreate,
handleAutomationUpdate,
handleAutomationExecute,
handleAutomationToggleActive,
// FormGenerator specific handlers
onDelete: handleDeleteSingle,
onDeleteMultiple: handleDeleteMultiple,
// Loading states
deletingAutomations,
creatingAutomation,
executingAutomations,
// Error states
deleteError,
createError,
updateError,
// Attributes and permissions
attributes,
permissions,
pagination,
columns: generatedColumns,
// Functions for EditActionButton
fetchAutomationById,
generateEditFieldsFromAttributes,
generateCreateFieldsFromAttributes,
ensureAttributesLoaded
};
};
};
export const automationsPageData: GenericPageData = {
id: 'workflows-automations',
path: 'workflows/automations',
name: 'automations.title',
description: 'automations.description',
// Parent page - under 'workflows' group
parentPath: 'workflows',
// Visual
icon: FaCog,
title: 'automations.title',
subtitle: 'automations.subtitle',
// Header buttons
headerButtons: [
{
id: 'new-automation',
label: 'automations.new_button',
icon: FaPlus,
variant: 'primary',
formConfig: {
fields: [], // Fields will be generated dynamically from attributes
popupTitle: 'automations.modal.create.title',
popupSize: 'large',
createOperationName: 'handleAutomationCreate',
successMessage: 'automations.create.success',
errorMessage: 'automations.create.error'
}
}
],
// Content sections - using generic table approach
content: [
{
id: 'automations-table',
type: 'table',
tableConfig: {
hookFactory: createAutomationsHook,
// Columns are generated dynamically from attributes via hookData.columns
actionButtons: [
{
type: 'play',
title: 'automations.action.execute',
idField: 'id',
operationName: 'handleAutomationExecute',
loadingStateName: 'executingAutomations',
disabled: (hookData: any) => {
if (!hookData?.permissions) return { disabled: false };
const hasExecute = hookData.permissions.update !== 'n' && hookData.permissions.view;
return { disabled: !hasExecute, message: 'No permission to execute automations' };
}
},
{
type: 'edit',
title: 'automations.action.edit',
idField: 'id',
nameField: 'label',
operationName: 'handleAutomationUpdate',
loadingStateName: 'updatingAutomations',
fetchItemFunctionName: 'fetchAutomationById',
disabled: (hookData: any) => {
if (!hookData?.permissions) return { disabled: false };
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
return { disabled: !hasUpdate, message: 'No permission to edit automations' };
}
},
{
type: 'delete',
title: 'automations.action.delete',
idField: 'id',
operationName: 'handleDelete',
loadingStateName: 'deletingAutomations',
disabled: (hookData: any) => {
if (!hookData?.permissions) return { disabled: false };
const hasDelete = hookData.permissions.delete !== 'n' && hookData.permissions.view;
return { disabled: !hasDelete, message: 'No permission to delete automations' };
}
}
],
searchable: true,
filterable: true,
sortable: true,
resizable: true,
pagination: true,
pageSize: 10,
className: 'automations-table'
}
}
],
// Page behavior
persistent: false,
preload: false,
preserveState: true,
moduleEnabled: true,
// Lifecycle hooks
onActivate: async () => {
if (import.meta.env.DEV) console.log('Automations activated');
},
onLoad: async () => {
if (import.meta.env.DEV) console.log('Automations loaded');
},
onUnload: async () => {
if (import.meta.env.DEV) console.log('Automations unloaded');
}
};