import React, { useState } from 'react' import { useEntities } from '../../contexts/EntityContext' import axios from 'axios' import { FaBook, FaSearch, FaFilter, FaGlobe, FaCopy, FaCheckCircle, FaExclamationCircle, FaDatabase, FaSyncAlt, FaPaperPlane, FaPlusCircle, FaEdit, FaTrash, } from 'react-icons/fa' import { useLocalization } from '@/utils/hooks/useLocalization' interface EndpointType { id: string name: string method: string path: string description?: string type: 'generated' operationType?: string entityName?: string } interface TestResult { success: boolean status: number data?: unknown error?: unknown timestamp: string } interface ParameterInput { name: string value: string type: 'path' | 'query' | 'body' required: boolean description?: string } const CrudEndpointManager: React.FC = () => { const { generatedEndpoints } = useEntities() const { translate } = useLocalization() const [searchTerm, setSearchTerm] = useState('') const [filterMethod, setFilterMethod] = useState<'all' | 'GET' | 'POST' | 'PUT' | 'DELETE'>('all') const [selectedEndpoint, setSelectedEndpoint] = useState(null) const [testResults, setTestResults] = useState>({}) const [loadingEndpoints, setLoadingEndpoints] = useState>(new Set()) const [parameterValues, setParameterValues] = useState>>({}) const [requestBodies, setRequestBodies] = useState>({}) // Only show generated CRUD endpoints const allEndpoints: EndpointType[] = [ ...generatedEndpoints .filter((e) => e.isActive) .map((e) => ({ id: e.id, name: `${e.entityName} ${e.operationType}`, method: e.method, path: e.path, description: `${e.operationType} operation for ${e.entityName} entity`, type: 'generated' as const, operationType: e.operationType, entityName: e.entityName, })), ] const filteredEndpoints = allEndpoints.filter((endpoint) => { const matchesSearch = endpoint.name.toLowerCase().includes(searchTerm.toLowerCase()) || endpoint.path.toLowerCase().includes(searchTerm.toLowerCase()) || (endpoint.description || '').toLowerCase().includes(searchTerm.toLowerCase()) const matchesMethodFilter = filterMethod === 'all' || endpoint.method === filterMethod return matchesSearch && matchesMethodFilter }) const getMethodColor = (method: string) => { switch (method) { case 'GET': return 'bg-blue-100 text-blue-800 border-blue-200' case 'POST': return 'bg-green-100 text-green-800 border-green-200' case 'PUT': return 'bg-yellow-100 text-yellow-800 border-yellow-200' case 'DELETE': return 'bg-red-100 text-red-800 border-red-200' default: return 'bg-slate-100 text-slate-800 border-slate-200' } } const getResponseExample = (endpoint: EndpointType) => { switch (endpoint.operationType) { case 'GetList': case 'GetPaged': return { data: [ { id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', name: 'Sample Item', creationTime: '2024-01-15T10:30:00Z', }, ], totalCount: 1, pageSize: 10, currentPage: 1, } case 'GetById': return { id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', name: 'Sample Item', creationTime: '2024-01-15T10:30:00Z', lastModificationTime: '2024-01-15T10:30:00Z', } case 'Create': case 'Update': return { id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', name: 'Sample Item', creationTime: '2024-01-15T10:30:00Z', lastModificationTime: '2024-01-15T10:30:00Z', } case 'Delete': return { success: true, message: 'Item deleted successfully', } default: return { message: 'Hello from API!', timestamp: '2024-01-15T10:30:00Z', success: true, } } } const getRequestExample = (endpoint: EndpointType) => { if (endpoint.operationType === 'Create' || endpoint.operationType === 'Update') { return { Name: 'New Item', Description: 'Item description', IsActive: true, } } return null } const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text) } // Get required parameters for each endpoint type const getEndpointParameters = (endpoint: EndpointType): ParameterInput[] => { const parameters: ParameterInput[] = [] const currentValues = parameterValues[endpoint.id] || {} switch (endpoint.operationType) { case 'GetById': case 'Update': case 'Delete': parameters.push({ name: 'id', value: currentValues.id || '3fa85f64-5717-4562-b3fc-2c963f66afa6', type: 'path', required: true, description: 'Unique identifier for the entity', }) break case 'GetList': case 'GetPaged': parameters.push( { name: 'SkipCount', value: currentValues.SkipCount || '0', type: 'query', required: false, description: 'Number of records to skip', }, { name: 'MaxResultCount', value: currentValues.MaxResultCount || '10', type: 'query', required: false, description: 'Maximum number of records to return', }, ) break } return parameters } // Check if endpoint needs request body const needsRequestBody = (endpoint: EndpointType): boolean => { return endpoint.operationType === 'Create' || endpoint.operationType === 'Update' } // Update parameter value const updateParameterValue = (endpointId: string, paramName: string, value: string) => { setParameterValues((prev) => ({ ...prev, [endpointId]: { ...prev[endpointId], [paramName]: value, }, })) } // Update request body const updateRequestBody = (endpointId: string, body: string) => { setRequestBodies((prev) => ({ ...prev, [endpointId]: body, })) } // Initialize default values for endpoint when first opened const initializeEndpointDefaults = (endpoint: EndpointType) => { if (!parameterValues[endpoint.id]) { const parameters = getEndpointParameters(endpoint) const defaultValues: Record = {} parameters.forEach((param) => { defaultValues[param.name] = param.value }) setParameterValues((prev) => ({ ...prev, [endpoint.id]: defaultValues, })) } if (!requestBodies[endpoint.id] && needsRequestBody(endpoint)) { const example = getRequestExample(endpoint) if (example) { setRequestBodies((prev) => ({ ...prev, [endpoint.id]: JSON.stringify(example, null, 2), })) } } } // Get current request body for endpoint const getCurrentRequestBody = (endpoint: EndpointType): string => { const stored = requestBodies[endpoint.id] if (stored) return stored const example = getRequestExample(endpoint) return example ? JSON.stringify(example, null, 2) : '' } const testEndpoint = async (endpoint: EndpointType) => { const endpointId = endpoint.id // Add to loading set setLoadingEndpoints((prev) => new Set(prev).add(endpointId)) try { let url = '' const method = endpoint.method let data = null // For generated endpoints, use the Crud API url = `${import.meta.env.VITE_API_URL}/api/app/crudendpoint/${endpoint.entityName}` // Get parameters and modify URL based on operation type const parameters = getEndpointParameters(endpoint) const pathParams = parameters.filter((p) => p.type === 'path') const queryParams = parameters.filter((p) => p.type === 'query') // Handle path parameters if (pathParams.length > 0) { const idParam = pathParams.find((p) => p.name === 'id') if (idParam) { url += `/${idParam.value}` } } // Handle query parameters if (queryParams.length > 0) { const queryString = queryParams .filter((p) => p.value.trim() !== '') .map((p) => `${p.name}=${encodeURIComponent(p.value)}`) .join('&') if (queryString) { url += `?${queryString}` } } // Handle request body if (needsRequestBody(endpoint)) { const requestBodyText = getCurrentRequestBody(endpoint) try { data = requestBodyText ? JSON.parse(requestBodyText) : getRequestExample(endpoint) } catch (e) { throw new Error(`Invalid JSON in request body: ${e}`) } } const config = { method, url, timeout: 10000, headers: { 'Content-Type': 'application/json', }, data: data || undefined, } const response = await axios(config) setTestResults((prev) => ({ ...prev, [endpointId]: { success: true, status: response.status, data: response.data, timestamp: new Date().toISOString(), }, })) } catch (error: unknown) { const axiosError = error as { response?: { status?: number; data?: unknown } message?: string } setTestResults((prev) => ({ ...prev, [endpointId]: { success: false, status: axiosError.response?.status || 0, error: axiosError.response?.data || axiosError.message, timestamp: new Date().toISOString(), }, })) } finally { // Remove from loading set setLoadingEndpoints((prev) => { const newSet = new Set(prev) newSet.delete(endpointId) return newSet }) } } const stats = { total: allEndpoints.length, custom: 0, // No more custom endpoints generated: generatedEndpoints.filter((e) => e.isActive).length, byMethod: { GET: allEndpoints.filter((e) => e.method === 'GET').length, POST: allEndpoints.filter((e) => e.method === 'POST').length, PUT: allEndpoints.filter((e) => e.method === 'PUT').length, DELETE: allEndpoints.filter((e) => e.method === 'DELETE').length, }, } return (

{translate('::App.DeveloperKit.CrudEndpoints')}

{translate('::App.DeveloperKit.Endpoint.Description')}

{translate('::App.DeveloperKit.Endpoint.SwaggerCompatible')}
{/* Stats Cards */}

{translate('::App.DeveloperKit.Endpoint.GeneratedCrud')}

{stats.generated}

{translate('::App.DeveloperKit.Endpoint.GetCount')}

{stats.byMethod.GET}

{translate('::App.DeveloperKit.Endpoint.PostCount')}

{stats.byMethod.POST}

{translate('::App.DeveloperKit.Endpoint.PutCount')}

{stats.byMethod.PUT}

{translate('::App.DeveloperKit.Endpoint.DeleteCount')}

{stats.byMethod.DELETE}

{/* Filters */}
setSearchTerm(e.target.value)} className="w-full pl-10 pr-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors" />
{/* Endpoints List */} {filteredEndpoints.length > 0 ? (
{filteredEndpoints.map((endpoint) => (
{ const newSelectedEndpoint = selectedEndpoint === endpoint.id ? null : endpoint.id setSelectedEndpoint(newSelectedEndpoint) if (newSelectedEndpoint === endpoint.id) { initializeEndpointDefaults(endpoint) } }} >
{/* Sol taraf */}
{endpoint.method}

{endpoint.name}

{endpoint.path}
{/* Sağ taraf */}
{endpoint.type === 'generated' && ( {translate('::App.DeveloperKit.Endpoint.AutoGenerated')} )}
{translate('::App.DeveloperKit.Endpoint.Active')}
{endpoint.description && (

{endpoint.description}

)}
{/* Expanded Details */} {selectedEndpoint === endpoint.id && (
{/* Request Details */}

{translate('::App.DeveloperKit.Endpoint.RequestTitle')}

{endpoint.method} {endpoint.path}
{/* Parameters Section */} {getEndpointParameters(endpoint).length > 0 && (
{getEndpointParameters(endpoint).map((param) => (
{param.name} {param.type} {param.required && ( {translate('::App.DeveloperKit.Endpoint.RequiredLabel')} )}
{param.description && (

{param.description}

)} updateParameterValue(endpoint.id, param.name, e.target.value) } placeholder={`Enter ${param.name}`} className="w-full px-3 py-2 text-sm border border-slate-300 rounded focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
))}
)} {/* Request Body Section */} {needsRequestBody(endpoint) && (