UNPKG

@dbs-portal/module-tenant-management

Version:

Tenant management and multi-tenancy support module

87 lines 11.1 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * TenantDetail Component - Comprehensive tenant information display */ import React, { useState } from 'react'; import { Card, Row, Col, Descriptions, Tag, Button, Space, Statistic, Progress, Tabs, Alert, Typography, Divider, Tooltip, Badge, List, Avatar } from 'antd'; import { EditOutlined, DeleteOutlined, PoweroffOutlined, CheckCircleOutlined, ExclamationCircleOutlined, DatabaseOutlined, UserOutlined, SettingOutlined, BarChartOutlined, CloudDownloadOutlined, CopyOutlined, ExportOutlined } from '@ant-design/icons'; import { formatDistanceToNow, format } from 'date-fns'; import { useTenant, useTenantAnalytics, useTenantBackups, useActivateTenant, useDeactivateTenant, useDeleteTenant, useTestTenantConnection, useCloneTenant } from '../hooks'; const { Title, Text } = Typography; const { TabPane } = Tabs; export const TenantDetail = ({ tenantId, onEdit, onDelete, className }) => { const [activeTab, setActiveTab] = useState('overview'); // Fetch tenant data const { data: tenant, isLoading, error } = useTenant(tenantId); const { data: analytics } = useTenantAnalytics(tenantId, 'month'); const { data: backups } = useTenantBackups(tenantId); // Mutations const activateMutation = useActivateTenant(); const deactivateMutation = useDeactivateTenant(); const deleteMutation = useDeleteTenant(); const testConnectionMutation = useTestTenantConnection(); const cloneMutation = useCloneTenant(); if (isLoading) { return (_jsx(Card, { className: className, loading: true, children: _jsx("div", { style: { height: 400 } }) })); } if (error || !tenant) { return (_jsx(Card, { className: className, children: _jsx(Alert, { message: "Failed to load tenant", description: error?.message || 'Tenant not found', type: "error", showIcon: true }) })); } const handleToggleStatus = async () => { try { if (tenant.isActive) { await deactivateMutation.mutateAsync(tenant.id); } else { await activateMutation.mutateAsync(tenant.id); } } catch (error) { console.error('Failed to toggle tenant status:', error); } }; const handleDelete = async () => { try { await deleteMutation.mutateAsync(tenant.id); onDelete?.(tenant); } catch (error) { console.error('Failed to delete tenant:', error); } }; const handleTestConnection = async () => { try { await testConnectionMutation.mutateAsync(tenant.id); } catch (error) { console.error('Failed to test connection:', error); } }; const handleClone = async () => { try { await cloneMutation.mutateAsync({ sourceId: tenant.id, newName: `${tenant.name}-copy`, newDisplayName: `${tenant.displayName} (Copy)`, options: { includeSettings: true, includeFeatures: true } }); } catch (error) { console.error('Failed to clone tenant:', error); } }; const getStatusColor = (isActive) => isActive ? 'success' : 'default'; const getStatusIcon = (isActive) => isActive ? _jsx(CheckCircleOutlined, {}) : _jsx(ExclamationCircleOutlined, {}); return (_jsxs("div", { className: className, children: [_jsx(Card, { children: _jsxs(Row, { justify: "space-between", align: "middle", children: [_jsxs(Col, { children: [_jsxs(Space, { children: [_jsx(Title, { level: 3, style: { margin: 0 }, children: tenant.displayName }), _jsx(Tag, { color: getStatusColor(tenant.isActive), icon: getStatusIcon(tenant.isActive), children: tenant.isActive ? 'Active' : 'Inactive' })] }), _jsx(Text, { type: "secondary", children: tenant.name })] }), _jsx(Col, { children: _jsxs(Space, { children: [_jsx(Button, { icon: _jsx(EditOutlined, {}), onClick: () => onEdit?.(tenant), children: "Edit" }), _jsx(Button, { icon: _jsx(CopyOutlined, {}), onClick: handleClone, loading: cloneMutation.isPending, children: "Clone" }), _jsx(Button, { icon: _jsx(PoweroffOutlined, {}), onClick: handleToggleStatus, loading: activateMutation.isPending || deactivateMutation.isPending, type: tenant.isActive ? 'default' : 'primary', children: tenant.isActive ? 'Deactivate' : 'Activate' }), _jsx(Button, { icon: _jsx(DeleteOutlined, {}), danger: true, onClick: handleDelete, loading: deleteMutation.isPending, children: "Delete" })] }) })] }) }), _jsx(Card, { style: { marginTop: 16 }, children: _jsxs(Row, { gutter: 16, children: [_jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Total Users", value: tenant.statistics.userCount, prefix: _jsx(UserOutlined, {}) }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Active Users", value: tenant.statistics.activeUserCount, prefix: _jsx(UserOutlined, {}), valueStyle: { color: '#3f8600' } }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Storage Used", value: tenant.statistics.storageUsed, suffix: "MB", prefix: _jsx(DatabaseOutlined, {}) }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "API Calls", value: tenant.statistics.apiCallCount, prefix: _jsx(BarChartOutlined, {}) }) })] }) }), _jsx(Card, { style: { marginTop: 16 }, children: _jsxs(Tabs, { activeKey: activeTab, onChange: setActiveTab, children: [_jsx(TabPane, { tab: "Overview", children: _jsxs(Descriptions, { bordered: true, column: 2, children: [_jsx(Descriptions.Item, { label: "Tenant ID", children: tenant.id }), _jsx(Descriptions.Item, { label: "Name", children: tenant.name }), _jsx(Descriptions.Item, { label: "Display Name", children: tenant.displayName }), _jsx(Descriptions.Item, { label: "Status", children: _jsx(Tag, { color: getStatusColor(tenant.isActive), children: tenant.isActive ? 'Active' : 'Inactive' }) }), _jsx(Descriptions.Item, { label: "Created", children: format(new Date(tenant.createdAt), 'PPP') }), _jsxs(Descriptions.Item, { label: "Last Updated", children: [formatDistanceToNow(new Date(tenant.updatedAt)), " ago"] }), _jsx(Descriptions.Item, { label: "Connection String", span: 2, children: tenant.connectionString ? (_jsxs(Space, { children: [_jsxs(Text, { code: true, children: [tenant.connectionString.substring(0, 50), "..."] }), _jsx(Button, { size: "small", icon: _jsx(DatabaseOutlined, {}), onClick: handleTestConnection, loading: testConnectionMutation.isPending, children: "Test Connection" })] })) : (_jsx(Text, { type: "secondary", children: "Not configured" })) })] }) }, "overview"), _jsx(TabPane, { tab: "Features", children: _jsx(List, { dataSource: tenant.features, renderItem: (feature) => (_jsxs(List.Item, { children: [_jsx(List.Item.Meta, { avatar: _jsx(Avatar, { icon: feature.isEnabled ? _jsx(CheckCircleOutlined, {}) : _jsx(ExclamationCircleOutlined, {}), style: { backgroundColor: feature.isEnabled ? '#52c41a' : '#ff4d4f' } }), title: feature.displayName, description: _jsxs(Space, { direction: "vertical", size: "small", children: [_jsx(Text, { children: feature.name }), feature.value && (_jsxs(Text, { type: "secondary", children: ["Value: ", JSON.stringify(feature.value)] })), feature.expiresAt && (_jsxs(Text, { type: "warning", children: ["Expires: ", format(new Date(feature.expiresAt), 'PPP')] }))] }) }), _jsx(Tag, { color: feature.isEnabled ? 'success' : 'default', children: feature.isEnabled ? 'Enabled' : 'Disabled' })] })) }) }, "features"), _jsx(TabPane, { tab: "Settings", children: _jsxs(Descriptions, { bordered: true, column: 1, children: [tenant.settings.maxUsers && (_jsx(Descriptions.Item, { label: "Max Users", children: tenant.settings.maxUsers })), tenant.settings.maxStorage && (_jsxs(Descriptions.Item, { label: "Max Storage", children: [tenant.settings.maxStorage, " MB"] })), tenant.settings.allowedDomains && (_jsx(Descriptions.Item, { label: "Allowed Domains", children: tenant.settings.allowedDomains.map(domain => (_jsx(Tag, { children: domain }, domain))) })), tenant.settings.customDomain && (_jsx(Descriptions.Item, { label: "Custom Domain", children: tenant.settings.customDomain })), tenant.settings.theme && (_jsx(Descriptions.Item, { label: "Theme", children: tenant.settings.theme })), tenant.settings.timezone && (_jsx(Descriptions.Item, { label: "Timezone", children: tenant.settings.timezone })), tenant.settings.language && (_jsx(Descriptions.Item, { label: "Language", children: tenant.settings.language }))] }) }, "settings"), _jsx(TabPane, { tab: "Analytics", children: analytics ? (_jsx(Row, { gutter: 16, children: _jsxs(Col, { span: 24, children: [_jsx(Title, { level: 4, children: "Monthly Summary" }), _jsxs(Row, { gutter: 16, children: [_jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Total Users", value: analytics.summary.totalUsers }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Active Users", value: analytics.summary.activeUsers }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Storage Used", value: analytics.summary.storageUsed, suffix: "MB" }) }), _jsx(Col, { span: 6, children: _jsx(Statistic, { title: "Uptime", value: analytics.summary.uptime, suffix: "%", precision: 2 }) })] })] }) })) : (_jsx(Alert, { message: "Analytics data not available", type: "info", showIcon: true })) }, "analytics"), _jsx(TabPane, { tab: "Backups", children: backups && backups.length > 0 ? (_jsx(List, { dataSource: backups, renderItem: (backup) => (_jsx(List.Item, { actions: [ _jsx(Button, { icon: _jsx(CloudDownloadOutlined, {}), size: "small", disabled: backup.status !== 'completed', children: "Download" }, "download"), _jsx(Button, { size: "small", disabled: backup.status !== 'completed', children: "Restore" }, "restore") ], children: _jsx(List.Item.Meta, { title: backup.name, description: _jsxs(Space, { direction: "vertical", size: "small", children: [_jsx(Text, { children: backup.description }), _jsxs(Space, { children: [_jsx(Badge, { status: backup.status === 'completed' ? 'success' : backup.status === 'failed' ? 'error' : backup.status === 'in_progress' ? 'processing' : 'default', text: backup.status.replace('_', ' ').toUpperCase() }), _jsx(Text, { type: "secondary", children: format(new Date(backup.createdAt), 'PPP') }), _jsxs(Text, { type: "secondary", children: [backup.size, " MB"] })] }), backup.progress !== undefined && backup.status === 'in_progress' && (_jsx(Progress, { percent: backup.progress, size: "small" }))] }) }) })) })) : (_jsx(Alert, { message: "No backups found", description: "Create a backup to see it here", type: "info", showIcon: true })) }, "backups")] }) })] })); }; //# sourceMappingURL=TenantDetail.js.map