Refactor NewModuleModal to comment out health_status field and improve code readability. Update TenantDetails to fetch modules based on tenant ID and adjust ModulesTab to handle module data more effectively. Modify module service to accept tenant ID for fetching modules. Clean up unused code in RolesTable and UsersTable components by removing header text.
This commit is contained in:
parent
dd71820ac9
commit
c656594154
@ -30,7 +30,7 @@ const newModuleSchema = z.object({
|
||||
.min(1, 'runtime_language is required')
|
||||
.max(50, 'runtime_language must be at most 50 characters'),
|
||||
framework: z.string().max(50, 'framework must be at most 50 characters').optional().nullable(),
|
||||
webhookurl: z.string().max(500, "webhookurl must be at most 500 characters").url("Invalid URL format").nullable(),
|
||||
webhookurl: z.string().max(500, "webhookurl must be at most 500 characters").url("Invalid URL format").nullable(),
|
||||
base_url: z
|
||||
.string()
|
||||
.min(1, 'base_url is required')
|
||||
@ -49,7 +49,7 @@ const newModuleSchema = z.object({
|
||||
min_replicas: z.number().int().min(1, 'min_replicas must be at least 1').max(50, 'min_replicas must be at most 50').optional().nullable(),
|
||||
max_replicas: z.number().int().min(1, 'max_replicas must be at least 1').max(50, 'max_replicas must be at most 50').optional().nullable(),
|
||||
last_health_check: z.string().optional().nullable(),
|
||||
health_status: z.string().max(20, 'health_status must be at most 20 characters').optional().nullable(),
|
||||
// health_status: z.string().max(20, 'health_status must be at most 20 characters').optional().nullable(),
|
||||
consecutive_failures: z.number().int().optional().nullable(),
|
||||
registered_by: z.string().uuid().optional().nullable(),
|
||||
tenant_id: z.string().uuid().optional().nullable(),
|
||||
@ -96,7 +96,7 @@ export const NewModuleModal = ({
|
||||
min_replicas: null,
|
||||
max_replicas: null,
|
||||
last_health_check: null,
|
||||
health_status: null,
|
||||
// health_status: null,
|
||||
consecutive_failures: null,
|
||||
registered_by: null,
|
||||
tenant_id: null,
|
||||
@ -126,7 +126,7 @@ export const NewModuleModal = ({
|
||||
min_replicas: null,
|
||||
max_replicas: null,
|
||||
last_health_check: null,
|
||||
health_status: null,
|
||||
// health_status: null,
|
||||
consecutive_failures: null,
|
||||
registered_by: null,
|
||||
tenant_id: null,
|
||||
@ -274,52 +274,52 @@ export const NewModuleModal = ({
|
||||
<p className="text-sm text-[#ef4444]">{errors.root.message}</p>
|
||||
</div>
|
||||
)}
|
||||
{!apiKey && (
|
||||
<div className="flex flex-col gap-0">
|
||||
{/* Basic Information Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Basic Information</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Module ID"
|
||||
required
|
||||
placeholder="Enter module ID (e.g., my-module)"
|
||||
error={errors.module_id?.message}
|
||||
{...register('module_id')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
|
||||
<div className="flex flex-col gap-0">
|
||||
{/* Basic Information Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Basic Information</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Module ID"
|
||||
required
|
||||
placeholder="Enter module ID (e.g., my-module)"
|
||||
error={errors.module_id?.message}
|
||||
{...register('module_id')}
|
||||
/>
|
||||
<FormField
|
||||
label="Module Name"
|
||||
required
|
||||
placeholder="Enter module name"
|
||||
error={errors.name?.message}
|
||||
{...register('name')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
|
||||
<FormField
|
||||
label="Module Name"
|
||||
required
|
||||
placeholder="Enter module name"
|
||||
error={errors.name?.message}
|
||||
{...register('name')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<FormField
|
||||
label="Description"
|
||||
placeholder="Enter module description (optional)"
|
||||
error={errors.description?.message}
|
||||
{...register('description')}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
label="Description"
|
||||
placeholder="Enter module description (optional)"
|
||||
error={errors.description?.message}
|
||||
{...register('description')}
|
||||
/>
|
||||
|
||||
{/* <div className="flex gap-5">
|
||||
{/* <div className="flex gap-5">
|
||||
<div className="flex-1"> */}
|
||||
<FormField
|
||||
label="Version"
|
||||
required
|
||||
placeholder="e.g., 1.0.0"
|
||||
error={errors.version?.message}
|
||||
{...register('version')}
|
||||
/>
|
||||
{/* </div> */}
|
||||
{/* <div className="flex-1">
|
||||
<FormField
|
||||
label="Version"
|
||||
required
|
||||
placeholder="e.g., 1.0.0"
|
||||
error={errors.version?.message}
|
||||
{...register('version')}
|
||||
/>
|
||||
{/* </div> */}
|
||||
{/* <div className="flex-1">
|
||||
<FormSelect
|
||||
label="Status"
|
||||
placeholder="Select Status"
|
||||
@ -330,151 +330,152 @@ export const NewModuleModal = ({
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Runtime Information Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Runtime Information</h3>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
{/* Runtime Information Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Runtime Information</h3>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Runtime Language"
|
||||
required
|
||||
placeholder="e.g., Node.js, Python, Java"
|
||||
error={errors.runtime_language?.message}
|
||||
{...register('runtime_language')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Framework"
|
||||
placeholder="e.g., Express, Django, Spring (optional)"
|
||||
error={errors.framework?.message}
|
||||
{...register('framework')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Webhook URL"
|
||||
placeholder="e.g., https://example.com/webhook"
|
||||
error={errors.webhookurl?.message}
|
||||
{...register('webhookurl')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* URL Configuration Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">URL Configuration</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<FormField
|
||||
label="Runtime Language"
|
||||
label="Base URL"
|
||||
required
|
||||
placeholder="e.g., Node.js, Python, Java"
|
||||
error={errors.runtime_language?.message}
|
||||
{...register('runtime_language')}
|
||||
type="url"
|
||||
placeholder="https://example.com"
|
||||
error={errors.base_url?.message}
|
||||
{...register('base_url')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
|
||||
<FormField
|
||||
label="Framework"
|
||||
placeholder="e.g., Express, Django, Spring (optional)"
|
||||
error={errors.framework?.message}
|
||||
{...register('framework')}
|
||||
label="Health Endpoint"
|
||||
required
|
||||
placeholder="/health"
|
||||
error={errors.health_endpoint?.message}
|
||||
{...register('health_endpoint')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Webhook URL"
|
||||
placeholder="e.g., https://example.com/webhook"
|
||||
error={errors.webhookurl?.message}
|
||||
{...register('webhookurl')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* URL Configuration Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">URL Configuration</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<FormField
|
||||
label="Base URL"
|
||||
required
|
||||
type="url"
|
||||
placeholder="https://example.com"
|
||||
error={errors.base_url?.message}
|
||||
{...register('base_url')}
|
||||
/>
|
||||
{/* Resource Configuration Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Resource Configuration (Optional)</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="CPU Request"
|
||||
placeholder="e.g., 100m, 0.5"
|
||||
error={errors.cpu_request?.message}
|
||||
{...register('cpu_request')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="CPU Limit"
|
||||
placeholder="e.g., 500m, 1"
|
||||
error={errors.cpu_limit?.message}
|
||||
{...register('cpu_limit')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
label="Health Endpoint"
|
||||
required
|
||||
placeholder="/health"
|
||||
error={errors.health_endpoint?.message}
|
||||
{...register('health_endpoint')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Memory Request"
|
||||
placeholder="e.g., 128Mi, 512Mi"
|
||||
error={errors.memory_request?.message}
|
||||
{...register('memory_request')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Memory Limit"
|
||||
placeholder="e.g., 256Mi, 1Gi"
|
||||
error={errors.memory_limit?.message}
|
||||
{...register('memory_limit')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Resource Configuration Section */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-[#0f1724] mb-3">Resource Configuration (Optional)</h3>
|
||||
<div className="flex flex-col gap-0">
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="CPU Request"
|
||||
placeholder="e.g., 100m, 0.5"
|
||||
error={errors.cpu_request?.message}
|
||||
{...register('cpu_request')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="CPU Limit"
|
||||
placeholder="e.g., 500m, 1"
|
||||
error={errors.cpu_limit?.message}
|
||||
{...register('cpu_limit')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Memory Request"
|
||||
placeholder="e.g., 128Mi, 512Mi"
|
||||
error={errors.memory_request?.message}
|
||||
{...register('memory_request')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Memory Limit"
|
||||
placeholder="e.g., 256Mi, 1Gi"
|
||||
error={errors.memory_limit?.message}
|
||||
{...register('memory_limit')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Min Replicas"
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
step="1"
|
||||
placeholder="1"
|
||||
error={errors.min_replicas?.message}
|
||||
{...register('min_replicas', {
|
||||
setValueAs: (value) => {
|
||||
if (value === '' || value === null || value === undefined) return null;
|
||||
const num = Number(value);
|
||||
return isNaN(num) ? null : num;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Max Replicas"
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
step="1"
|
||||
placeholder="5"
|
||||
error={errors.max_replicas?.message}
|
||||
{...register('max_replicas', {
|
||||
setValueAs: (value) => {
|
||||
if (value === '' || value === null || value === undefined) return null;
|
||||
const num = Number(value);
|
||||
return isNaN(num) ? null : num;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Min Replicas"
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
step="1"
|
||||
placeholder="1"
|
||||
error={errors.min_replicas?.message}
|
||||
{...register('min_replicas', {
|
||||
setValueAs: (value) => {
|
||||
if (value === '' || value === null || value === undefined) return null;
|
||||
const num = Number(value);
|
||||
return isNaN(num) ? null : num;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
label="Max Replicas"
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
step="1"
|
||||
placeholder="5"
|
||||
error={errors.max_replicas?.message}
|
||||
{...register('max_replicas', {
|
||||
setValueAs: (value) => {
|
||||
if (value === '' || value === null || value === undefined) return null;
|
||||
const num = Number(value);
|
||||
return isNaN(num) ? null : num;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</Modal >
|
||||
);
|
||||
|
||||
@ -288,7 +288,7 @@ export const RolesTable = ({ tenantId, showHeader = true, compact = false }: Rol
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]">Roles</h3>
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]"></h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<FilterDropdown
|
||||
label="Scope"
|
||||
|
||||
@ -330,7 +330,7 @@ export const UsersTable = ({ tenantId, showHeader = true, compact = false }: Use
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]">Users</h3>
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]"></h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<FilterDropdown
|
||||
label="Status"
|
||||
|
||||
@ -10,8 +10,6 @@ import {
|
||||
History,
|
||||
CreditCard,
|
||||
Edit,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
Settings,
|
||||
Image as ImageIcon,
|
||||
} from 'lucide-react';
|
||||
@ -25,8 +23,10 @@ import {
|
||||
import { UsersTable, RolesTable } from '@/components/superadmin';
|
||||
import { tenantService } from '@/services/tenant-service';
|
||||
import { auditLogService } from '@/services/audit-log-service';
|
||||
import type { Tenant, AssignedModule } from '@/types/tenant';
|
||||
import { moduleService } from '@/services/module-service';
|
||||
import type { Tenant } from '@/types/tenant';
|
||||
import type { AuditLog } from '@/types/audit-log';
|
||||
import type { MyModule } from '@/types/module';
|
||||
import { formatDate } from '@/utils/format-date';
|
||||
|
||||
type TabType = 'overview' | 'users' | 'roles' | 'modules' | 'settings' | 'license' | 'audit-logs' | 'billing';
|
||||
@ -278,10 +278,8 @@ const TenantDetails = (): ReactElement => {
|
||||
{activeTab === 'roles' && id && (
|
||||
<RolesTable tenantId={id} compact={true} />
|
||||
)}
|
||||
{activeTab === 'modules' && tenant && (
|
||||
<ModulesTab
|
||||
modules={tenant.assignedModules || []}
|
||||
/>
|
||||
{activeTab === 'modules' && id && (
|
||||
<ModulesTab tenantId={id} />
|
||||
)}
|
||||
{activeTab === 'settings' && tenant && (
|
||||
<SettingsTab tenant={tenant} />
|
||||
@ -386,31 +384,51 @@ const OverviewTab = ({ tenant, stats }: OverviewTabProps): ReactElement => {
|
||||
|
||||
// Modules Tab Component
|
||||
interface ModulesTabProps {
|
||||
modules: AssignedModule[];
|
||||
tenantId: string;
|
||||
}
|
||||
|
||||
const ModulesTab = ({ modules }: ModulesTabProps): ReactElement => {
|
||||
const [enabledModules, setEnabledModules] = useState<Set<string>>(new Set());
|
||||
const ModulesTab = ({ tenantId }: ModulesTabProps): ReactElement => {
|
||||
const [modules, setModules] = useState<MyModule[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize enabled modules (assuming all are enabled by default)
|
||||
setEnabledModules(new Set(modules.map((m) => m.id)));
|
||||
}, [modules]);
|
||||
|
||||
const toggleModule = (moduleId: string): void => {
|
||||
setEnabledModules((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(moduleId)) {
|
||||
next.delete(moduleId);
|
||||
// Fetch modules for this tenant
|
||||
const fetchModules = async (): Promise<void> => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
const response = await moduleService.getMyModules(tenantId);
|
||||
if (response.success && response.data) {
|
||||
setModules(response.data);
|
||||
} else {
|
||||
next.add(moduleId);
|
||||
setError('Failed to load modules');
|
||||
}
|
||||
return next;
|
||||
});
|
||||
// TODO: Call API to enable/disable module
|
||||
} catch (err: any) {
|
||||
setError(err?.response?.data?.error?.message || 'Failed to load modules');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: Column<AssignedModule>[] = [
|
||||
useEffect(() => {
|
||||
if (tenantId) {
|
||||
fetchModules();
|
||||
}
|
||||
}, [tenantId]);
|
||||
|
||||
// Launch module handler
|
||||
const handleLaunchModule = async (moduleId: string): Promise<void> => {
|
||||
try {
|
||||
const response = await moduleService.launch(moduleId, tenantId);
|
||||
if (response.success && response.data.launch_url) {
|
||||
window.open(response.data.launch_url, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError(err?.response?.data?.error?.message || 'Failed to launch module');
|
||||
}
|
||||
};
|
||||
|
||||
const columns: Column<MyModule>[] = [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Module Name',
|
||||
@ -423,6 +441,13 @@ const ModulesTab = ({ modules }: ModulesTabProps): ReactElement => {
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'module_id',
|
||||
label: 'Module ID',
|
||||
render: (module) => (
|
||||
<span className="text-sm font-normal text-[#6b7280] font-mono">{module.module_id}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'version',
|
||||
label: 'Version',
|
||||
@ -448,45 +473,47 @@ const ModulesTab = ({ modules }: ModulesTabProps): ReactElement => {
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
label: 'Enabled',
|
||||
key: 'base_url',
|
||||
label: 'Base URL',
|
||||
render: (module) => (
|
||||
<button
|
||||
onClick={() => toggleModule(module.id)}
|
||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${
|
||||
enabledModules.has(module.id)
|
||||
? 'bg-green-50 text-green-700 border border-green-200'
|
||||
: 'bg-gray-50 text-gray-700 border border-gray-200'
|
||||
}`}
|
||||
>
|
||||
{enabledModules.has(module.id) ? (
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
) : (
|
||||
<XCircle className="w-4 h-4" />
|
||||
)}
|
||||
<span>{enabledModules.has(module.id) ? 'Enabled' : 'Disabled'}</span>
|
||||
</button>
|
||||
<span className="text-sm font-normal text-[#6b7280] font-mono truncate max-w-[200px]">
|
||||
{module.base_url || 'N/A'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'created_at',
|
||||
label: 'Registered',
|
||||
key: 'assigned_at',
|
||||
label: 'Assigned At',
|
||||
render: (module) => (
|
||||
<span className="text-sm font-normal text-[#6b7280]">{formatDate(module.created_at)}</span>
|
||||
<span className="text-sm font-normal text-[#6b7280]">{formatDate(module.assigned_at)}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: 'Actions',
|
||||
align: 'right',
|
||||
render: (module) => (
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleLaunchModule(module.id)}
|
||||
className="text-sm text-[#FFC107] hover:text-[#FFC107] font-medium transition-colors cursor-pointer"
|
||||
>
|
||||
Lunch
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]">Modules</h3>
|
||||
</div>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={modules}
|
||||
keyExtractor={(module) => module.id}
|
||||
isLoading={false}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
emptyMessage="No modules assigned to this tenant"
|
||||
/>
|
||||
</div>
|
||||
@ -593,9 +620,9 @@ const AuditLogsTab = ({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
{/* <div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-[#0f1724]">Audit Logs</h3>
|
||||
</div>
|
||||
</div> */}
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={auditLogs}
|
||||
|
||||
@ -75,8 +75,13 @@ export const moduleService = {
|
||||
const response = await apiClient.post<LaunchModuleResponse>(url);
|
||||
return response.data;
|
||||
},
|
||||
getMyModules: async (): Promise<MyModulesResponse> => {
|
||||
const response = await apiClient.get<MyModulesResponse>('/modules/my');
|
||||
getMyModules: async (tenantId?: string | null): Promise<MyModulesResponse> => {
|
||||
const params = new URLSearchParams();
|
||||
if (tenantId) {
|
||||
params.append('tenant_id', tenantId);
|
||||
}
|
||||
const url = `/modules/my${params.toString() ? `?${params.toString()}` : ''}`;
|
||||
const response = await apiClient.get<MyModulesResponse>(url);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user