@dbs-portal/module-tenant-management
Version:
Tenant management and multi-tenancy support module
87 lines • 11.1 kB
JavaScript
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