295 lines
12 KiB
TypeScript
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');
|
|
}
|
|
};
|
|
|