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

295 lines
12 KiB
TypeScript

import React, { useCallback } from 'react';
import { GenericPageData } from '../../pageInterface';
import { FaGoogle, FaMicrosoft, FaLink, FaSync, FaPlug } from 'react-icons/fa';
import { useConnections } from '../../../../hooks/useConnections';
// Helper function to convert attribute definitions to column config
const attributesToColumns = (attributes: any[]) => {
return attributes.map(attr => ({
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: attr.filterable !== false,
searchable: attr.searchable !== false,
filterOptions: attr.filterOptions
}));
};
// Hook factory function for connections data
const createConnectionsHook = () => {
return () => {
const {
connections,
fetchConnections,
deleteConnection,
createGoogleConnectionAndAuth,
createMicrosoftConnectionAndAuth,
connectWithPopup,
refreshMicrosoftToken,
refreshGoogleToken,
isConnecting,
isLoading,
error,
attributes,
permissions,
pagination
} = useConnections();
const generatedColumns = attributes && attributes.length > 0
? attributesToColumns(attributes)
: undefined;
// Refetch function for pagination-aware refresh
const refetch = useCallback(async (params?: any) => {
await fetchConnections(params);
}, [fetchConnections]);
// Handle connection deletion
const handleDelete = useCallback(async (connectionId: string) => {
try {
await deleteConnection(connectionId);
// Refresh connections after deletion - FormGenerator will handle pagination
// by calling refetch with current pagination params via its useEffect
return true;
} catch (error) {
console.error('Failed to delete connection:', error);
return false;
}
}, [deleteConnection]);
// Handle single connection deletion for FormGenerator
const handleDeleteSingle = useCallback(async (connection: any) => {
const success = await handleDelete(connection.id);
if (success) {
refetch();
}
}, [handleDelete, refetch]);
// Handle multiple connection deletion for FormGenerator
const handleDeleteMultiple = useCallback(async (selectedConnections: any[]) => {
const connectionIds = selectedConnections.map(conn => conn.id);
const results = await Promise.all(
connectionIds.map(id => handleDelete(id))
);
const allSuccessful = results.every(result => result);
if (allSuccessful) {
refetch();
}
}, [handleDelete, refetch]);
return {
data: connections,
loading: isLoading,
error: error,
refetch,
// Operations
handleDelete,
// FormGenerator specific handlers
onDelete: handleDeleteSingle,
onDeleteMultiple: handleDeleteMultiple,
connectWithPopup,
createGoogleConnectionAndAuth,
createMicrosoftConnectionAndAuth,
// Token refresh operations
refreshMicrosoftToken,
refreshGoogleToken,
// Loading states
isConnecting,
deletingConnections: new Set(), // Placeholder for consistency with other pages
refreshingConnections: new Set<string>(), // Track which connections are refreshing
// Attributes and permissions for dynamic column/button generation
attributes,
permissions,
columns: generatedColumns, // Return generated columns
pagination
};
};
};
export const connectionsPageData: GenericPageData = {
id: 'basedata-connections',
path: 'basedata/connections',
name: 'connections.title',
description: 'connections.title',
// Parent page
parentPath: 'basedata',
// Visual
icon: FaLink,
title: 'connections.title',
subtitle: 'connections.subtitle',
// Header buttons - Create Google and Microsoft connections
headerButtons: [
{
id: 'add-google-connection',
label: 'connections.add_google_button',
icon: FaGoogle,
variant: 'primary',
onClick: async (hookData: any) => {
if (!hookData) {
console.error('No hookData available for Google connection creation');
return;
}
if (!hookData.createGoogleConnectionAndAuth) {
console.error('createGoogleConnectionAndAuth function not found in hookData', hookData);
return;
}
try {
await hookData.createGoogleConnectionAndAuth();
// Refresh connections after creation
if (hookData?.refetch) {
await hookData.refetch();
}
} catch (error) {
console.error('Failed to create Google connection:', error);
}
},
// Only show if user has create permission
disabled: (hookData: any) => {
if (!hookData?.permissions) return { disabled: false };
const hasCreate = hookData.permissions.create !== 'n' && hookData.permissions.view;
return { disabled: !hasCreate, message: 'No permission to create connections' };
}
},
{
id: 'add-microsoft-connection',
label: 'connections.add_microsoft_button',
icon: FaMicrosoft,
variant: 'primary',
onClick: async (hookData: any) => {
if (!hookData) {
console.error('No hookData available for Microsoft connection creation');
return;
}
if (!hookData.createMicrosoftConnectionAndAuth) {
console.error('createMicrosoftConnectionAndAuth function not found in hookData', hookData);
return;
}
try {
await hookData.createMicrosoftConnectionAndAuth();
// Refresh connections after creation
if (hookData?.refetch) {
await hookData.refetch();
}
} catch (error) {
console.error('Failed to create Microsoft connection:', error);
}
},
// Only show if user has create permission
disabled: (hookData: any) => {
if (!hookData?.permissions) return { disabled: false };
const hasCreate = hookData.permissions.create !== 'n' && hookData.permissions.view;
return { disabled: !hasCreate, message: 'No permission to create connections' };
}
}
],
// Content sections - using generic table approach
content: [
{
id: 'connections-table',
type: 'table',
tableConfig: {
hookFactory: createConnectionsHook,
// Columns are generated dynamically from attributes via hookData.columns
// Standard action buttons
actionButtons: [
{
type: 'delete',
title: 'connections.action.delete',
idField: 'id',
operationName: 'handleDelete',
loadingStateName: 'deletingConnections',
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 connections' };
}
}
],
// Custom action buttons (entity-specific)
customActions: [
{
id: 'connect',
icon: React.createElement(FaPlug),
title: 'connections.action.connect',
onClick: async (row: any, hookData: any) => {
if (hookData?.connectWithPopup) {
await hookData.connectWithPopup(row.id);
}
},
// Only show connect button if status is not 'active'
visible: (row: any) => row.status !== 'active',
disabled: (_row: any, hookData: any) => {
if (!hookData?.permissions) return { disabled: false, message: '' };
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
return { disabled: !hasUpdate, message: 'No permission to connect' };
},
loading: (_row: any, hookData: any) => hookData?.isConnecting || false
},
{
id: 'refresh',
icon: React.createElement(FaSync),
title: 'connections.action.refresh',
onClick: async (row: any, hookData: any) => {
// Determine which refresh function to use based on authority
if (row.authority === 'msft' && hookData?.refreshMicrosoftToken) {
await hookData.refreshMicrosoftToken(row.id);
if (hookData?.refetch) await hookData.refetch();
} else if (row.authority === 'google' && hookData?.refreshGoogleToken) {
await hookData.refreshGoogleToken(row.id);
if (hookData?.refetch) await hookData.refetch();
}
},
// Only show refresh button if status is 'active' (already connected)
visible: (row: any) => row.status === 'active',
disabled: (_row: any, hookData: any) => {
if (!hookData?.permissions) return { disabled: false, message: '' };
const hasUpdate = hookData.permissions.update !== 'n' && hookData.permissions.view;
return { disabled: !hasUpdate, message: 'No permission to refresh token' };
},
loading: (row: any, hookData: any) => hookData?.refreshingConnections?.has(row.id) || false
}
],
searchable: true,
filterable: true,
sortable: true,
resizable: true,
pagination: true,
pageSize: 10,
className: 'connections-table'
}
}
],
// Page behavior
persistent: false,
preload: false,
preserveState: true, // Keep page mounted and prevent refetching
moduleEnabled: true,
// Sidebar - will be shown as subpage under Administration
// No drag and drop for connections
dragDropConfig: {
enabled: false
},
// Lifecycle hooks
onActivate: async () => {
if (import.meta.env.DEV) console.log('Connections activated');
},
onLoad: async () => {
if (import.meta.env.DEV) console.log('Connections loaded - can initialize connections list here');
},
onUnload: async () => {
if (import.meta.env.DEV) console.log('Connections unloaded - cleanup connections references');
}
};