Routes güncellemeleri
This commit is contained in:
parent
bbc2c9c1cb
commit
614be0c916
15 changed files with 423 additions and 295 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useEffect, useCallback } from 'react'
|
import React, { useState, useEffect, useCallback } from 'react'
|
||||||
import { useParams, useNavigate } from 'react-router-dom'
|
import { useParams, useNavigate } from 'react-router-dom'
|
||||||
import { useComponents } from '../../contexts/ComponentContext'
|
import { useComponents } from '../../contexts/ComponentContext'
|
||||||
import { FaRegSave, FaArrowLeft, FaExclamationCircle, FaSync } from 'react-icons/fa';
|
import { FaRegSave, FaArrowLeft, FaExclamationCircle, FaSync } from 'react-icons/fa'
|
||||||
import { parseReactCode } from '../../utils/codeParser'
|
import { parseReactCode } from '../../utils/codeParser'
|
||||||
import ComponentPreview from '../../components/componentEditor/ComponentPreview'
|
import ComponentPreview from '../../components/componentEditor/ComponentPreview'
|
||||||
import { EditorState } from '../../@types/componentInfo'
|
import { EditorState } from '../../@types/componentInfo'
|
||||||
|
|
@ -129,7 +129,7 @@ const ComponentEditor: React.FC = () => {
|
||||||
addComponent(componentData)
|
addComponent(componentData)
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(ROUTES_ENUM.protected.saas.developerKitComponents)
|
navigate(ROUTES_ENUM.protected.saas.developerKit.components)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving component:', error)
|
console.error('Error saving component:', error)
|
||||||
alert('Failed to save component. Please try again.')
|
alert('Failed to save component. Please try again.')
|
||||||
|
|
@ -159,7 +159,7 @@ const ComponentEditor: React.FC = () => {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitComponents)}
|
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKit.components)}
|
||||||
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
||||||
>
|
>
|
||||||
<FaArrowLeft className="w-4 h-4" />
|
<FaArrowLeft className="w-4 h-4" />
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ const ComponentManager: React.FC = () => {
|
||||||
<p className="text-slate-600">{translate('::App.DeveloperKit.Component.Description')}</p>
|
<p className="text-slate-600">{translate('::App.DeveloperKit.Component.Description')}</p>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitComponentsNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.componentsNew}
|
||||||
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
|
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
>
|
>
|
||||||
<FaPlus className="w-4 h-4" />
|
<FaPlus className="w-4 h-4" />
|
||||||
|
|
@ -245,7 +245,7 @@ const ComponentManager: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitComponentsEdit.replace(
|
to={ROUTES_ENUM.protected.saas.developerKit.componentsEdit.replace(
|
||||||
':id',
|
':id',
|
||||||
component.id,
|
component.id,
|
||||||
)}
|
)}
|
||||||
|
|
@ -256,7 +256,7 @@ const ComponentManager: React.FC = () => {
|
||||||
<FaRegEdit className="w-4 h-4" />
|
<FaRegEdit className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitComponentsView.replace(
|
to={ROUTES_ENUM.protected.saas.developerKit.componentsView.replace(
|
||||||
':id',
|
':id',
|
||||||
component.id,
|
component.id,
|
||||||
)}
|
)}
|
||||||
|
|
@ -296,7 +296,7 @@ const ComponentManager: React.FC = () => {
|
||||||
</p>
|
</p>
|
||||||
{!searchTerm && filterActive === 'all' && (
|
{!searchTerm && filterActive === 'all' && (
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitComponentsNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.componentsNew}
|
||||||
className="inline-flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
|
className="inline-flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
>
|
>
|
||||||
<FaPlus className="w-4 h-4" />
|
<FaPlus className="w-4 h-4" />
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import React from "react";
|
import React from 'react'
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from 'react-router-dom'
|
||||||
import { useComponents } from "../../contexts/ComponentContext";
|
import { useComponents } from '../../contexts/ComponentContext'
|
||||||
import { useEntities } from "../../contexts/EntityContext";
|
import { useEntities } from '../../contexts/EntityContext'
|
||||||
import { useSystemHealth } from "../../utils/hooks/useDeveloperKit";
|
import { useSystemHealth } from '../../utils/hooks/useDeveloperKit'
|
||||||
import {
|
import {
|
||||||
FaDatabase,
|
FaDatabase,
|
||||||
FaBolt,
|
FaBolt,
|
||||||
|
|
@ -15,15 +15,15 @@ import {
|
||||||
FaArrowRight,
|
FaArrowRight,
|
||||||
FaExclamationCircle,
|
FaExclamationCircle,
|
||||||
FaWifi,
|
FaWifi,
|
||||||
FaWindowClose
|
FaWindowClose,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa'
|
||||||
import { ROUTES_ENUM } from "@/routes/route.constant";
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { useLocalization } from "@/utils/hooks/useLocalization";
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const Dashboard: React.FC = () => {
|
const Dashboard: React.FC = () => {
|
||||||
const { components } = useComponents();
|
const { components } = useComponents()
|
||||||
const { entities, migrations, generatedEndpoints } = useEntities();
|
const { entities, migrations, generatedEndpoints } = useEntities()
|
||||||
const { isOnline, lastCheck, recheckHealth } = useSystemHealth();
|
const { isOnline, lastCheck, recheckHealth } = useSystemHealth()
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const stats = [
|
const stats = [
|
||||||
|
|
@ -32,38 +32,38 @@ const Dashboard: React.FC = () => {
|
||||||
value: entities.filter((e) => e.isActive).length,
|
value: entities.filter((e) => e.isActive).length,
|
||||||
total: entities.length,
|
total: entities.length,
|
||||||
icon: FaDatabase,
|
icon: FaDatabase,
|
||||||
color: "text-blue-600",
|
color: 'text-blue-600',
|
||||||
bgColor: "bg-blue-100",
|
bgColor: 'bg-blue-100',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitEntities,
|
href: ROUTES_ENUM.protected.saas.developerKit.entities,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.Stats.Migrations'),
|
name: translate('::App.DeveloperKit.Dashboard.Stats.Migrations'),
|
||||||
value: migrations.filter((m) => m.status === "pending").length,
|
value: migrations.filter((m) => m.status === 'pending').length,
|
||||||
total: migrations.length,
|
total: migrations.length,
|
||||||
icon: FaBolt,
|
icon: FaBolt,
|
||||||
color: "text-yellow-600",
|
color: 'text-yellow-600',
|
||||||
bgColor: "bg-yellow-100",
|
bgColor: 'bg-yellow-100',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitMigrations,
|
href: ROUTES_ENUM.protected.saas.developerKit.migrations,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.Stats.APIs'),
|
name: translate('::App.DeveloperKit.Dashboard.Stats.APIs'),
|
||||||
value: generatedEndpoints.filter((e) => e.isActive).length,
|
value: generatedEndpoints.filter((e) => e.isActive).length,
|
||||||
total: generatedEndpoints.length,
|
total: generatedEndpoints.length,
|
||||||
icon: FaServer,
|
icon: FaServer,
|
||||||
color: "text-emerald-600",
|
color: 'text-emerald-600',
|
||||||
bgColor: "bg-emerald-100",
|
bgColor: 'bg-emerald-100',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitEndpoints,
|
href: ROUTES_ENUM.protected.saas.developerKit.endpoints,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.Stats.Components'),
|
name: translate('::App.DeveloperKit.Dashboard.Stats.Components'),
|
||||||
value: components?.filter((c) => c.isActive).length,
|
value: components?.filter((c) => c.isActive).length,
|
||||||
total: components?.length,
|
total: components?.length,
|
||||||
icon: FaPuzzlePiece,
|
icon: FaPuzzlePiece,
|
||||||
color: "text-purple-600",
|
color: 'text-purple-600',
|
||||||
bgColor: "bg-purple-100",
|
bgColor: 'bg-purple-100',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitComponents,
|
href: ROUTES_ENUM.protected.saas.developerKit.components,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const developmentFlow = [
|
const developmentFlow = [
|
||||||
{
|
{
|
||||||
|
|
@ -71,54 +71,50 @@ const Dashboard: React.FC = () => {
|
||||||
title: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity'),
|
title: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity'),
|
||||||
description: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity.Desc'),
|
description: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity.Desc'),
|
||||||
icon: FaDatabase,
|
icon: FaDatabase,
|
||||||
color: "bg-blue-600",
|
color: 'bg-blue-600',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitEntitiesNew,
|
href: ROUTES_ENUM.protected.saas.developerKit.entitiesNew,
|
||||||
status: "ready",
|
status: 'ready',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 2,
|
step: 2,
|
||||||
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration'),
|
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration'),
|
||||||
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration.Desc'),
|
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration.Desc'),
|
||||||
icon: FaBolt,
|
icon: FaBolt,
|
||||||
color: "bg-yellow-600",
|
color: 'bg-yellow-600',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitMigrations,
|
href: ROUTES_ENUM.protected.saas.developerKit.migrations,
|
||||||
status: entities.some((e) => e.migrationStatus === "pending")
|
status: entities.some((e) => e.migrationStatus === 'pending') ? 'action-needed' : 'ready',
|
||||||
? "action-needed"
|
|
||||||
: "ready",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 3,
|
step: 3,
|
||||||
title: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration'),
|
title: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration'),
|
||||||
description: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration.Desc'),
|
description: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration.Desc'),
|
||||||
icon: FaCheckCircle,
|
icon: FaCheckCircle,
|
||||||
color: "bg-green-600",
|
color: 'bg-green-600',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitMigrations,
|
href: ROUTES_ENUM.protected.saas.developerKit.migrations,
|
||||||
status: migrations.some((m) => m.status === "pending")
|
status: migrations.some((m) => m.status === 'pending') ? 'action-needed' : 'ready',
|
||||||
? "action-needed"
|
|
||||||
: "ready",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 4,
|
step: 4,
|
||||||
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI'),
|
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI'),
|
||||||
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI.Desc'),
|
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI.Desc'),
|
||||||
icon: FaServer,
|
icon: FaServer,
|
||||||
color: "bg-emerald-600",
|
color: 'bg-emerald-600',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitEndpoints,
|
href: ROUTES_ENUM.protected.saas.developerKit.endpoints,
|
||||||
status: "ready",
|
status: 'ready',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: 5,
|
step: 5,
|
||||||
title: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent'),
|
title: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent'),
|
||||||
description: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent.Desc'),
|
description: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent.Desc'),
|
||||||
icon: FaPuzzlePiece,
|
icon: FaPuzzlePiece,
|
||||||
color: "bg-purple-600",
|
color: 'bg-purple-600',
|
||||||
href: ROUTES_ENUM.protected.saas.developerKitComponentsNew,
|
href: ROUTES_ENUM.protected.saas.developerKit.componentsNew,
|
||||||
status: "ready",
|
status: 'ready',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const recentEntities = entities.slice(0, 3);
|
const recentEntities = entities.slice(0, 3)
|
||||||
const recentMigrations = migrations.slice(0, 3);
|
const recentMigrations = migrations.slice(0, 3)
|
||||||
const recentEndpoints = [
|
const recentEndpoints = [
|
||||||
...generatedEndpoints.map((e) => ({
|
...generatedEndpoints.map((e) => ({
|
||||||
id: e.id,
|
id: e.id,
|
||||||
|
|
@ -130,28 +126,36 @@ const Dashboard: React.FC = () => {
|
||||||
lastModificationTime: e.lastModificationTime,
|
lastModificationTime: e.lastModificationTime,
|
||||||
creationTime: e.creationTime,
|
creationTime: e.creationTime,
|
||||||
})),
|
})),
|
||||||
].slice(0, 3);
|
].slice(0, 3)
|
||||||
|
|
||||||
const systemHealth = [
|
const systemHealth = [
|
||||||
{ name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Frontend'), status: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'), icon: FaCode },
|
{
|
||||||
|
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Frontend'),
|
||||||
|
status: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'),
|
||||||
|
icon: FaCode,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Backend'),
|
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Backend'),
|
||||||
status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Offline'),
|
status: isOnline
|
||||||
|
? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy')
|
||||||
|
: translate('::App.DeveloperKit.Dashboard.SystemHealth.Offline'),
|
||||||
icon: FaServer,
|
icon: FaServer,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Database'),
|
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Database'),
|
||||||
status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Unknown'),
|
status: isOnline
|
||||||
|
? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy')
|
||||||
|
: translate('::App.DeveloperKit.Dashboard.SystemHealth.Unknown'),
|
||||||
icon: FaDatabase,
|
icon: FaDatabase,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Migrations'),
|
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Migrations'),
|
||||||
status: migrations.some((m) => m.status === "failed")
|
status: migrations.some((m) => m.status === 'failed')
|
||||||
? translate('::App.DeveloperKit.Dashboard.SystemHealth.Warning')
|
? translate('::App.DeveloperKit.Dashboard.SystemHealth.Warning')
|
||||||
: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'),
|
: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'),
|
||||||
icon: FaBolt,
|
icon: FaBolt,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
|
|
@ -161,25 +165,21 @@ const Dashboard: React.FC = () => {
|
||||||
<h1 className="text-3xl font-bold text-slate-900 mb-2">
|
<h1 className="text-3xl font-bold text-slate-900 mb-2">
|
||||||
{translate('::App.DeveloperKit.Dashboard.Title')}
|
{translate('::App.DeveloperKit.Dashboard.Title')}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-slate-600">
|
<p className="text-slate-600">{translate('::App.DeveloperKit.Dashboard.Description')}</p>
|
||||||
{translate('::App.DeveloperKit.Dashboard.Description')}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={recheckHealth}
|
onClick={recheckHealth}
|
||||||
className={`flex items-center gap-2 px-3 py-1 rounded-full text-sm font-medium transition-colors duration-200 ${
|
className={`flex items-center gap-2 px-3 py-1 rounded-full text-sm font-medium transition-colors duration-200 ${
|
||||||
isOnline
|
isOnline
|
||||||
? "bg-green-100 text-green-700 hover:bg-green-200"
|
? 'bg-green-100 text-green-700 hover:bg-green-200'
|
||||||
: "bg-red-100 text-red-700 hover:bg-red-200"
|
: 'bg-red-100 text-red-700 hover:bg-red-200'
|
||||||
}`}
|
}`}
|
||||||
title={`Son kontrol: ${lastCheck.toLocaleTimeString()}`}
|
title={`Son kontrol: ${lastCheck.toLocaleTimeString()}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
isOnline
|
isOnline ? 'bg-green-500 animate-pulse' : 'bg-red-500 animate-pulse'
|
||||||
? "bg-green-500 animate-pulse"
|
|
||||||
: "bg-red-500 animate-pulse"
|
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{isOnline ? (
|
{isOnline ? (
|
||||||
|
|
@ -200,7 +200,7 @@ const Dashboard: React.FC = () => {
|
||||||
{/* Stats Grid */}
|
{/* Stats Grid */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
{stats.map((stat) => {
|
{stats.map((stat) => {
|
||||||
const Icon = stat.icon;
|
const Icon = stat.icon
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={stat.name}
|
key={stat.name}
|
||||||
|
|
@ -216,18 +216,14 @@ const Dashboard: React.FC = () => {
|
||||||
<FaArrowRight className="w-4 h-4 text-slate-400 group-hover:text-slate-600 transition-colors" />
|
<FaArrowRight className="w-4 h-4 text-slate-400 group-hover:text-slate-600 transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">
|
<p className="text-sm font-medium text-slate-600">{stat.name}</p>
|
||||||
{stat.name}
|
|
||||||
</p>
|
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">
|
<p className="text-2xl font-bold text-slate-900 mt-1">
|
||||||
{stat.value}
|
{stat.value}
|
||||||
<span className="text-sm font-normal text-slate-500 ml-1">
|
<span className="text-sm font-normal text-slate-500 ml-1">/ {stat.total}</span>
|
||||||
/ {stat.total}
|
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -241,7 +237,7 @@ const Dashboard: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-5 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-5 gap-6">
|
||||||
{developmentFlow.map((flow, index) => {
|
{developmentFlow.map((flow, index) => {
|
||||||
const Icon = flow.icon;
|
const Icon = flow.icon
|
||||||
return (
|
return (
|
||||||
<Link key={flow.step} to={flow.href} className="group relative">
|
<Link key={flow.step} to={flow.href} className="group relative">
|
||||||
<div
|
<div
|
||||||
|
|
@ -258,7 +254,7 @@ const Dashboard: React.FC = () => {
|
||||||
<h3 className="font-semibold text-lg mb-2 text-white">{flow.title}</h3>
|
<h3 className="font-semibold text-lg mb-2 text-white">{flow.title}</h3>
|
||||||
<p className="text-sm opacity-90">{flow.description}</p>
|
<p className="text-sm opacity-90">{flow.description}</p>
|
||||||
|
|
||||||
{flow.status === "action-needed" && (
|
{flow.status === 'action-needed' && (
|
||||||
<div className="absolute -top-2 -right-2">
|
<div className="absolute -top-2 -right-2">
|
||||||
<div className="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center">
|
<div className="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center">
|
||||||
<FaExclamationCircle className="w-4 h-4" />
|
<FaExclamationCircle className="w-4 h-4" />
|
||||||
|
|
@ -273,7 +269,7 @@ const Dashboard: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -284,12 +280,12 @@ const Dashboard: React.FC = () => {
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<FaCog className="w-5 h-5 text-green-500" />
|
<FaCog className="w-5 h-5 text-green-500" />
|
||||||
<h3 className="text-lg font-semibold text-slate-900">
|
<h3 className="text-lg font-semibold text-slate-900">
|
||||||
{translate('::App.DeveloperKit.Dashboard.SystemHealth.Title') }
|
{translate('::App.DeveloperKit.Dashboard.SystemHealth.Title')}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{systemHealth.map((system) => {
|
{systemHealth.map((system) => {
|
||||||
const Icon = system.icon;
|
const Icon = system.icon
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={system.name}
|
key={system.name}
|
||||||
|
|
@ -297,38 +293,36 @@ const Dashboard: React.FC = () => {
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Icon className="w-4 h-4 text-slate-600" />
|
<Icon className="w-4 h-4 text-slate-600" />
|
||||||
<span className="font-medium text-slate-900">
|
<span className="font-medium text-slate-900">{system.name}</span>
|
||||||
{system.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
system.status === "healthy"
|
system.status === 'healthy'
|
||||||
? "bg-green-500"
|
? 'bg-green-500'
|
||||||
: system.status === "warning"
|
: system.status === 'warning'
|
||||||
? "bg-yellow-500"
|
? 'bg-yellow-500'
|
||||||
: system.status === "offline"
|
: system.status === 'offline'
|
||||||
? "bg-red-500"
|
? 'bg-red-500'
|
||||||
: "bg-gray-500"
|
: 'bg-gray-500'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`text-sm capitalize ${
|
className={`text-sm capitalize ${
|
||||||
system.status === "healthy"
|
system.status === 'healthy'
|
||||||
? "text-green-600"
|
? 'text-green-600'
|
||||||
: system.status === "warning"
|
: system.status === 'warning'
|
||||||
? "text-yellow-600"
|
? 'text-yellow-600'
|
||||||
: system.status === "offline"
|
: system.status === 'offline'
|
||||||
? "text-red-600"
|
? 'text-red-600'
|
||||||
: "text-gray-600"
|
: 'text-gray-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{system.status === "offline" ? "Offline" : system.status}
|
{system.status === 'offline' ? 'Offline' : system.status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -340,7 +334,7 @@ const Dashboard: React.FC = () => {
|
||||||
{translate('::App.DeveloperKit.Dashboard.RecentEntities.Title')}
|
{translate('::App.DeveloperKit.Dashboard.RecentEntities.Title')}
|
||||||
</h3>
|
</h3>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntities}
|
to={ROUTES_ENUM.protected.saas.developerKit.entities}
|
||||||
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
||||||
|
|
@ -354,9 +348,7 @@ const Dashboard: React.FC = () => {
|
||||||
className="flex items-center justify-between p-3 bg-slate-50 rounded-lg hover:bg-slate-100 transition-colors"
|
className="flex items-center justify-between p-3 bg-slate-50 rounded-lg hover:bg-slate-100 transition-colors"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-slate-900">
|
<p className="font-medium text-slate-900">{entity.displayName}</p>
|
||||||
{entity.displayName}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-slate-500">
|
<p className="text-sm text-slate-500">
|
||||||
{entity.fields.length} fields • {entity.migrationStatus}
|
{entity.fields.length} fields • {entity.migrationStatus}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -364,15 +356,18 @@ const Dashboard: React.FC = () => {
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
entity.migrationStatus === "applied"
|
entity.migrationStatus === 'applied'
|
||||||
? "bg-green-500"
|
? 'bg-green-500'
|
||||||
: entity.migrationStatus === "pending"
|
: entity.migrationStatus === 'pending'
|
||||||
? "bg-yellow-500"
|
? 'bg-yellow-500'
|
||||||
: "bg-red-500"
|
: 'bg-red-500'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesEdit.replace(':id', entity.id)}
|
to={ROUTES_ENUM.protected.saas.developerKit.entitiesEdit.replace(
|
||||||
|
':id',
|
||||||
|
entity.id,
|
||||||
|
)}
|
||||||
className="text-blue-600 hover:text-blue-700"
|
className="text-blue-600 hover:text-blue-700"
|
||||||
>
|
>
|
||||||
<FaDatabase className="w-4 h-4" />
|
<FaDatabase className="w-4 h-4" />
|
||||||
|
|
@ -383,9 +378,11 @@ const Dashboard: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-8">
|
<div className="text-center py-8">
|
||||||
<FaDatabase className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
<FaDatabase className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
||||||
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Entity')}</p>
|
<p className="text-slate-500 mb-2">
|
||||||
|
{translate('::App.DeveloperKit.Dashboard.Empty.Entity')}
|
||||||
|
</p>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.entitiesNew}
|
||||||
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
Create your first entity
|
Create your first entity
|
||||||
|
|
@ -402,7 +399,7 @@ const Dashboard: React.FC = () => {
|
||||||
{translate('::App.DeveloperKit.Dashboard.RecentMigrations.Title')}
|
{translate('::App.DeveloperKit.Dashboard.RecentMigrations.Title')}
|
||||||
</h3>
|
</h3>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitMigrations}
|
to={ROUTES_ENUM.protected.saas.developerKit.migrations}
|
||||||
className="text-yellow-600 hover:text-yellow-700 text-sm font-medium"
|
className="text-yellow-600 hover:text-yellow-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
||||||
|
|
@ -416,26 +413,23 @@ const Dashboard: React.FC = () => {
|
||||||
className="flex items-center justify-between p-3 bg-slate-50 rounded-lg hover:bg-slate-100 transition-colors"
|
className="flex items-center justify-between p-3 bg-slate-50 rounded-lg hover:bg-slate-100 transition-colors"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-slate-900">
|
<p className="font-medium text-slate-900">{migration.entityName}</p>
|
||||||
{migration.entityName}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-slate-500">
|
<p className="text-sm text-slate-500">
|
||||||
{migration.status} •{" "}
|
{migration.status} • {new Date(migration.creationTime).toLocaleDateString()}
|
||||||
{new Date(migration.creationTime).toLocaleDateString()}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
migration.status === "applied"
|
migration.status === 'applied'
|
||||||
? "bg-green-500"
|
? 'bg-green-500'
|
||||||
: migration.status === "pending"
|
: migration.status === 'pending'
|
||||||
? "bg-yellow-500"
|
? 'bg-yellow-500'
|
||||||
: "bg-red-500"
|
: 'bg-red-500'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitMigrations}
|
to={ROUTES_ENUM.protected.saas.developerKit.migrations}
|
||||||
className="text-yellow-600 hover:text-yellow-700"
|
className="text-yellow-600 hover:text-yellow-700"
|
||||||
>
|
>
|
||||||
<FaBolt className="w-4 h-4" />
|
<FaBolt className="w-4 h-4" />
|
||||||
|
|
@ -446,9 +440,11 @@ const Dashboard: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-8">
|
<div className="text-center py-8">
|
||||||
<FaBolt className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
<FaBolt className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
||||||
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Migration')}</p>
|
<p className="text-slate-500 mb-2">
|
||||||
|
{translate('::App.DeveloperKit.Dashboard.Empty.Migration')}
|
||||||
|
</p>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.entitiesNew}
|
||||||
className="text-yellow-600 hover:text-yellow-700 text-sm font-medium"
|
className="text-yellow-600 hover:text-yellow-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
{translate('::App.DeveloperKit.Dashboard.Action.GenerateMigrations')}
|
{translate('::App.DeveloperKit.Dashboard.Action.GenerateMigrations')}
|
||||||
|
|
@ -465,7 +461,7 @@ const Dashboard: React.FC = () => {
|
||||||
{translate('::App.DeveloperKit.Dashboard.RecentEndpoints.Title')}
|
{translate('::App.DeveloperKit.Dashboard.RecentEndpoints.Title')}
|
||||||
</h3>
|
</h3>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEndpoints}
|
to={ROUTES_ENUM.protected.saas.developerKit.endpoints}
|
||||||
className="text-emerald-600 hover:text-emerald-700 text-sm font-medium"
|
className="text-emerald-600 hover:text-emerald-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
{translate('::App.DeveloperKit.Dashboard.ViewAll')}
|
||||||
|
|
@ -482,33 +478,28 @@ const Dashboard: React.FC = () => {
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-0.5 text-xs font-medium rounded ${
|
className={`px-2 py-0.5 text-xs font-medium rounded ${
|
||||||
endpoint.method === "GET"
|
endpoint.method === 'GET'
|
||||||
? "bg-blue-100 text-blue-800"
|
? 'bg-blue-100 text-blue-800'
|
||||||
: endpoint.method === "POST"
|
: endpoint.method === 'POST'
|
||||||
? "bg-green-100 text-green-800"
|
? 'bg-green-100 text-green-800'
|
||||||
: endpoint.method === "PUT"
|
: endpoint.method === 'PUT'
|
||||||
? "bg-yellow-100 text-yellow-800"
|
? 'bg-yellow-100 text-yellow-800'
|
||||||
: "bg-red-100 text-red-800"
|
: 'bg-red-100 text-red-800'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{endpoint.method}
|
{endpoint.method}
|
||||||
</span>
|
</span>
|
||||||
<p className="font-medium text-slate-900 text-sm">
|
<p className="font-medium text-slate-900 text-sm">{endpoint.name}</p>
|
||||||
{endpoint.name}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500">{endpoint.path}</p>
|
<p className="text-xs text-slate-500">{endpoint.path}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
endpoint.isActive ? "bg-green-500" : "bg-slate-300"
|
endpoint.isActive ? 'bg-green-500' : 'bg-slate-300'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
<Link
|
<Link to="/docs" className="text-emerald-600 hover:text-emerald-700">
|
||||||
to="/docs"
|
|
||||||
className="text-emerald-600 hover:text-emerald-700"
|
|
||||||
>
|
|
||||||
<FaServer className="w-4 h-4" />
|
<FaServer className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -517,9 +508,11 @@ const Dashboard: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-8">
|
<div className="text-center py-8">
|
||||||
<FaServer className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
<FaServer className="w-12 h-12 text-slate-300 mx-auto mb-2" />
|
||||||
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Endpoint')}</p>
|
<p className="text-slate-500 mb-2">
|
||||||
|
{translate('::App.DeveloperKit.Dashboard.Empty.Endpoint')}
|
||||||
|
</p>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEndpointsNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.endpointsNew}
|
||||||
className="text-emerald-600 hover:text-emerald-700 text-sm font-medium"
|
className="text-emerald-600 hover:text-emerald-700 text-sm font-medium"
|
||||||
>
|
>
|
||||||
{translate('::App.DeveloperKit.Dashboard.Action.CreateEntity')}
|
{translate('::App.DeveloperKit.Dashboard.Action.CreateEntity')}
|
||||||
|
|
@ -530,7 +523,7 @@ const Dashboard: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Dashboard;
|
export default Dashboard
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import {
|
||||||
FaPlus,
|
FaPlus,
|
||||||
FaTrashAlt,
|
FaTrashAlt,
|
||||||
FaDatabase,
|
FaDatabase,
|
||||||
FaQuestionCircle
|
FaQuestionCircle,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa'
|
||||||
import { CreateUpdateCustomEntityFieldDto, CustomEntityField } from '@/proxy/developerKit/models'
|
import { CreateUpdateCustomEntityFieldDto, CustomEntityField } from '@/proxy/developerKit/models'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
@ -150,7 +150,7 @@ const EntityEditor: React.FC = () => {
|
||||||
addEntity(entityData)
|
addEntity(entityData)
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(ROUTES_ENUM.protected.saas.developerKitEntities)
|
navigate(ROUTES_ENUM.protected.saas.developerKit.entities)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving entity:', error)
|
console.error('Error saving entity:', error)
|
||||||
alert('Failed to save entity. Please try again.')
|
alert('Failed to save entity. Please try again.')
|
||||||
|
|
@ -176,7 +176,7 @@ const EntityEditor: React.FC = () => {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitEntities)}
|
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKit.entities)}
|
||||||
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
||||||
>
|
>
|
||||||
<FaArrowLeft className="w-4 h-4" />
|
<FaArrowLeft className="w-4 h-4" />
|
||||||
|
|
@ -202,7 +202,9 @@ const EntityEditor: React.FC = () => {
|
||||||
<div className="absolute -top-1 right-4 w-2 h-2 bg-slate-900 rotate-45"></div>
|
<div className="absolute -top-1 right-4 w-2 h-2 bg-slate-900 rotate-45"></div>
|
||||||
<div className="flex items-center gap-2 mb-2">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<FaDatabase className="w-4 h-4 text-blue-400" />
|
<FaDatabase className="w-4 h-4 text-blue-400" />
|
||||||
<h4 className="font-semibold text-blue-200">{translate('::App.DeveloperKit.EntityEditor.Tooltip.Title')}</h4>
|
<h4 className="font-semibold text-blue-200">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Tooltip.Title')}
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-slate-300 leading-relaxed">
|
<p className="text-slate-300 leading-relaxed">
|
||||||
{translate('::App.DeveloperKit.EntityEditor.Tooltip.Content')}
|
{translate('::App.DeveloperKit.EntityEditor.Tooltip.Content')}
|
||||||
|
|
@ -216,7 +218,9 @@ const EntityEditor: React.FC = () => {
|
||||||
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm"
|
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm"
|
||||||
>
|
>
|
||||||
<FaSave className="w-4 h-4" />
|
<FaSave className="w-4 h-4" />
|
||||||
{isSaving ? translate('::App.DeveloperKit.EntityEditor.Saving') : translate('::App.DeveloperKit.EntityEditor.Save')}
|
{isSaving
|
||||||
|
? translate('::App.DeveloperKit.EntityEditor.Saving')
|
||||||
|
: translate('::App.DeveloperKit.EntityEditor.Save')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -224,10 +228,14 @@ const EntityEditor: React.FC = () => {
|
||||||
|
|
||||||
{/* Entity Basic Info */}
|
{/* Entity Basic Info */}
|
||||||
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
|
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">{translate('::App.DeveloperKit.EntityEditor.BasicInfo')}</h2>
|
<h2 className="text-lg font-semibold text-slate-900 mb-4">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.BasicInfo')}
|
||||||
|
</h2>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-slate-700 mb-1">{translate('::App.DeveloperKit.EntityEditor.EntityName')}</label>
|
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.EntityName')}
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
autoFocus
|
autoFocus
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -266,7 +274,9 @@ const EntityEditor: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-slate-700 mb-1">{translate('::App.DeveloperKit.EntityEditor.TableName')} *</label>
|
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.TableName')} *
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={tableName}
|
value={tableName}
|
||||||
|
|
@ -284,7 +294,9 @@ const EntityEditor: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium text-slate-700 mb-1">{translate('::App.DeveloperKit.EntityEditor.Description')}</label>
|
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Description')}
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={description}
|
value={description}
|
||||||
|
|
@ -297,10 +309,14 @@ const EntityEditor: React.FC = () => {
|
||||||
|
|
||||||
{isEditing && (
|
{isEditing && (
|
||||||
<div className="mb-4 p-4 bg-slate-50 rounded-lg border border-slate-200">
|
<div className="mb-4 p-4 bg-slate-50 rounded-lg border border-slate-200">
|
||||||
<h3 className="text-sm font-medium text-slate-700 mb-3">{translate('::App.DeveloperKit.EntityEditor.Status')}</h3>
|
<h3 className="text-sm font-medium text-slate-700 mb-3">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Status')}
|
||||||
|
</h3>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-slate-600">{translate('::App.DeveloperKit.EntityEditor.Status.Migration')}</span>
|
<span className="text-sm text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Status.Migration')}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`text-xs px-2 py-1 rounded-full ${
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
getEntity(id!)?.migrationStatus === 'applied'
|
getEntity(id!)?.migrationStatus === 'applied'
|
||||||
|
|
@ -314,7 +330,9 @@ const EntityEditor: React.FC = () => {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-slate-600">{translate('::App.DeveloperKit.EntityEditor.Status.Endpoint')}</span>
|
<span className="text-sm text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Status.Endpoint')}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`text-xs px-2 py-1 rounded-full ${
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
getEntity(id!)?.endpointStatus === 'applied'
|
getEntity(id!)?.endpointStatus === 'applied'
|
||||||
|
|
@ -338,7 +356,9 @@ const EntityEditor: React.FC = () => {
|
||||||
onChange={(e) => setIsActive(e.target.checked)}
|
onChange={(e) => setIsActive(e.target.checked)}
|
||||||
className="rounded border-slate-300 text-emerald-600 focus:ring-emerald-500"
|
className="rounded border-slate-300 text-emerald-600 focus:ring-emerald-500"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm font-medium text-slate-700">{translate('::App.DeveloperKit.EntityEditor.Active')}</span>
|
<span className="text-sm font-medium text-slate-700">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Active')}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2">
|
<label className="flex items-center gap-2">
|
||||||
<input
|
<input
|
||||||
|
|
@ -372,7 +392,9 @@ const EntityEditor: React.FC = () => {
|
||||||
{/* Entity Fields */}
|
{/* Entity Fields */}
|
||||||
<div className="bg-white rounded-lg border border-slate-200 p-6 shadow-sm">
|
<div className="bg-white rounded-lg border border-slate-200 p-6 shadow-sm">
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="text-lg font-semibold text-slate-900">{translate('::App.DeveloperKit.EntityEditor.Fields')}</h2>
|
<h2 className="text-lg font-semibold text-slate-900">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Fields')}
|
||||||
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={addField}
|
onClick={addField}
|
||||||
className="flex items-center gap-2 bg-blue-600 text-white px-3 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm"
|
className="flex items-center gap-2 bg-blue-600 text-white px-3 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm"
|
||||||
|
|
@ -402,7 +424,9 @@ const EntityEditor: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-slate-700 mb-1">{translate('::App.DeveloperKit.EntityEditor.Type')} *</label>
|
<label className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Type')} *
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
value={field.type}
|
value={field.type}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
|
|
@ -475,7 +499,9 @@ const EntityEditor: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded border-slate-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-slate-300 text-blue-600 focus:ring-blue-500"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm font-medium text-slate-700">{translate('::App.DeveloperKit.EntityEditor.Required')}</span>
|
<span className="text-sm font-medium text-slate-700">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Required')}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2">
|
<label className="flex items-center gap-2">
|
||||||
<input
|
<input
|
||||||
|
|
@ -484,7 +510,9 @@ const EntityEditor: React.FC = () => {
|
||||||
onChange={(e) => updateField(field.id, { isUnique: e.target.checked })}
|
onChange={(e) => updateField(field.id, { isUnique: e.target.checked })}
|
||||||
className="rounded border-slate-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-slate-300 text-blue-600 focus:ring-blue-500"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm font-medium text-slate-700">{translate('::App.DeveloperKit.EntityEditor.Unique')}</span>
|
<span className="text-sm font-medium text-slate-700">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.Unique')}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button
|
||||||
onClick={() => removeField(field.id)}
|
onClick={() => removeField(field.id)}
|
||||||
|
|
@ -503,7 +531,9 @@ const EntityEditor: React.FC = () => {
|
||||||
<div className="text-center py-8 text-slate-500">
|
<div className="text-center py-8 text-slate-500">
|
||||||
<FaDatabase className="w-12 h-12 mx-auto mb-2 text-slate-300" />
|
<FaDatabase className="w-12 h-12 mx-auto mb-2 text-slate-300" />
|
||||||
<p>{translate('::App.DeveloperKit.EntityEditor.NoFields')}</p>
|
<p>{translate('::App.DeveloperKit.EntityEditor.NoFields')}</p>
|
||||||
<p className="text-sm">{translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')}</p>
|
<p className="text-sm">
|
||||||
|
{translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react'
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom'
|
||||||
import { useEntities } from '../../contexts/EntityContext';
|
import { useEntities } from '../../contexts/EntityContext'
|
||||||
import {
|
import {
|
||||||
FaPlus,
|
FaPlus,
|
||||||
FaSearch,
|
FaSearch,
|
||||||
|
|
@ -13,66 +13,72 @@ import {
|
||||||
FaDatabase,
|
FaDatabase,
|
||||||
FaCheckCircle,
|
FaCheckCircle,
|
||||||
FaTable,
|
FaTable,
|
||||||
FaBolt
|
FaBolt,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant';
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization';
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const EntityManager: React.FC = () => {
|
const EntityManager: React.FC = () => {
|
||||||
const { entities, deleteEntity, toggleEntityActiveStatus } = useEntities();
|
const { entities, deleteEntity, toggleEntityActiveStatus } = useEntities()
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [filterActive, setFilterActive] = useState<'all' | 'active' | 'inactive'>('all');
|
const [filterActive, setFilterActive] = useState<'all' | 'active' | 'inactive'>('all')
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const filteredEntities = entities.filter(entity => {
|
const filteredEntities = entities.filter((entity) => {
|
||||||
const matchesSearch = entity.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
const matchesSearch =
|
||||||
entity.displayName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
entity.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
(entity.description || '').toLowerCase().includes(searchTerm.toLowerCase());
|
entity.displayName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
(entity.description || '').toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
|
||||||
const matchesActiveFilter = filterActive === 'all' ||
|
const matchesActiveFilter =
|
||||||
(filterActive === 'active' && entity.isActive) ||
|
filterActive === 'all' ||
|
||||||
(filterActive === 'inactive' && !entity.isActive);
|
(filterActive === 'active' && entity.isActive) ||
|
||||||
|
(filterActive === 'inactive' && !entity.isActive)
|
||||||
|
|
||||||
return matchesSearch && matchesActiveFilter;
|
return matchesSearch && matchesActiveFilter
|
||||||
});
|
})
|
||||||
|
|
||||||
const handleToggleActive = async (id: string) => {
|
const handleToggleActive = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
await toggleEntityActiveStatus(id);
|
await toggleEntityActiveStatus(id)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to toggle entity status:', err);
|
console.error('Failed to toggle entity status:', err)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleDelete = async (id: string, name: string) => {
|
const handleDelete = async (id: string, name: string) => {
|
||||||
if (window.confirm(`Are you sure you want to delete the "${name}" entity?\n\nThis action will permanently remove:\n• The entity and all its fields\n• All related migrations\n• All related API endpoints\n\nThis cannot be undone.`)) {
|
if (
|
||||||
|
window.confirm(
|
||||||
|
`Are you sure you want to delete the "${name}" entity?\n\nThis action will permanently remove:\n• The entity and all its fields\n• All related migrations\n• All related API endpoints\n\nThis cannot be undone.`,
|
||||||
|
)
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
await deleteEntity(id);
|
await deleteEntity(id)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to delete entity:', err);
|
console.error('Failed to delete entity:', err)
|
||||||
alert(translate('::App.DeveloperKit.Entity.DeleteFailed'));
|
alert(translate('::App.DeveloperKit.Entity.DeleteFailed'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const stats = {
|
const stats = {
|
||||||
total: entities.length,
|
total: entities.length,
|
||||||
active: entities.filter(e => e.isActive).length,
|
active: entities.filter((e) => e.isActive).length,
|
||||||
migrationsPending: entities.filter(e => e.migrationStatus === 'pending').length,
|
migrationsPending: entities.filter((e) => e.migrationStatus === 'pending').length,
|
||||||
endpointsApplied: entities.filter(e => e.endpointStatus === 'applied').length
|
endpointsApplied: entities.filter((e) => e.endpointStatus === 'applied').length,
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<div className="flex items-center justify-between mb-8">
|
<div className="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-bold text-slate-900 mb-2">{translate('::App.DeveloperKit.Entity.Title')}</h1>
|
<h1 className="text-3xl font-bold text-slate-900 mb-2">
|
||||||
<p className="text-slate-600">
|
{translate('::App.DeveloperKit.Entity.Title')}
|
||||||
{translate('::App.DeveloperKit.Entity.Description')}
|
</h1>
|
||||||
</p>
|
<p className="text-slate-600">{translate('::App.DeveloperKit.Entity.Description')}</p>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
|
to={ROUTES_ENUM.protected.saas.developerKit.entitiesNew}
|
||||||
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
|
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
|
||||||
>
|
>
|
||||||
<FaPlus className="w-4 h-4" />
|
<FaPlus className="w-4 h-4" />
|
||||||
|
|
@ -85,7 +91,9 @@ const EntityManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Entity.TotalEntities')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Entity.TotalEntities')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
|
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
|
||||||
|
|
@ -96,12 +104,12 @@ const EntityManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Entity.ActiveEntities')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Entity.ActiveEntities')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">
|
<p className="text-2xl font-bold text-slate-900 mt-1">
|
||||||
{stats.active}
|
{stats.active}
|
||||||
<span className="text-sm font-normal text-slate-500 ml-1">
|
<span className="text-sm font-normal text-slate-500 ml-1">/ {stats.total}</span>
|
||||||
/ {stats.total}
|
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-green-100 text-green-600 p-3 rounded-lg">
|
<div className="bg-green-100 text-green-600 p-3 rounded-lg">
|
||||||
|
|
@ -112,7 +120,9 @@ const EntityManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Entity.PendingMigrations')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Entity.PendingMigrations')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.migrationsPending}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.migrationsPending}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
|
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
|
||||||
|
|
@ -123,7 +133,9 @@ const EntityManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Entity.CrudEndpoints')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Entity.CrudEndpoints')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.endpointsApplied}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.endpointsApplied}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg">
|
<div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg">
|
||||||
|
|
@ -155,8 +167,12 @@ const EntityManager: React.FC = () => {
|
||||||
className="px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-transparent transition-colors"
|
className="px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-transparent transition-colors"
|
||||||
>
|
>
|
||||||
<option value="all">{translate('::App.DeveloperKit.Entity.Filter.All')}</option>
|
<option value="all">{translate('::App.DeveloperKit.Entity.Filter.All')}</option>
|
||||||
<option value="active">{translate('::App.DeveloperKit.Entity.Filter.Active')}</option>
|
<option value="active">
|
||||||
<option value="inactive">{translate('::App.DeveloperKit.Entity.Filter.Inactive')}</option>
|
{translate('::App.DeveloperKit.Entity.Filter.Active')}
|
||||||
|
</option>
|
||||||
|
<option value="inactive">
|
||||||
|
{translate('::App.DeveloperKit.Entity.Filter.Inactive')}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -168,7 +184,10 @@ const EntityManager: React.FC = () => {
|
||||||
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
||||||
{filteredEntities.map((entity) => {
|
{filteredEntities.map((entity) => {
|
||||||
return (
|
return (
|
||||||
<div key={entity.id} className="bg-white rounded-lg border border-slate-200 shadow-sm hover:shadow-md transition-all duration-200 group">
|
<div
|
||||||
|
key={entity.id}
|
||||||
|
className="bg-white rounded-lg border border-slate-200 shadow-sm hover:shadow-md transition-all duration-200 group"
|
||||||
|
>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="flex items-start justify-between mb-4">
|
<div className="flex items-start justify-between mb-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
|
@ -180,25 +199,29 @@ const EntityManager: React.FC = () => {
|
||||||
<h3 className="text-lg font-semibold text-slate-900">
|
<h3 className="text-lg font-semibold text-slate-900">
|
||||||
{entity.displayName}
|
{entity.displayName}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-slate-500">{translate('::App.DeveloperKit.Entity.TableLabel')}: {entity.tableName}</p>
|
<p className="text-sm text-slate-500">
|
||||||
|
{translate('::App.DeveloperKit.Entity.TableLabel')}: {entity.tableName}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{entity.description && (
|
{entity.description && (
|
||||||
<p className="text-slate-600 text-sm mb-3">
|
<p className="text-slate-600 text-sm mb-3">{entity.description}</p>
|
||||||
{entity.description}
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center gap-4 text-xs text-slate-500 mb-3">
|
<div className="flex items-center gap-4 text-xs text-slate-500 mb-3">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaCalendarAlt className="w-3 h-3" />
|
<FaCalendarAlt className="w-3 h-3" />
|
||||||
<span>
|
<span>
|
||||||
{translate('::App.DeveloperKit.Entity.Updated')}: {entity.lastModificationTime ? new Date(entity.lastModificationTime).toLocaleDateString() : 'Never'}
|
{translate('::App.DeveloperKit.Entity.Updated')}:{' '}
|
||||||
|
{entity.lastModificationTime
|
||||||
|
? new Date(entity.lastModificationTime).toLocaleDateString()
|
||||||
|
: 'Never'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaDatabase className="w-3 h-3" />
|
<FaDatabase className="w-3 h-3" />
|
||||||
<span>{entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')}</span>
|
<span>
|
||||||
|
{entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -207,17 +230,25 @@ const EntityManager: React.FC = () => {
|
||||||
{/* Entity Fields Preview */}
|
{/* Entity Fields Preview */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="bg-slate-50 rounded-lg p-3">
|
<div className="bg-slate-50 rounded-lg p-3">
|
||||||
<h4 className="text-sm font-medium text-slate-700 mb-2">{translate('::App.DeveloperKit.Entity.FieldsLabel')}:</h4>
|
<h4 className="text-sm font-medium text-slate-700 mb-2">
|
||||||
|
{translate('::App.DeveloperKit.Entity.FieldsLabel')}:
|
||||||
|
</h4>
|
||||||
<div className="grid grid-cols-2 gap-2 text-xs">
|
<div className="grid grid-cols-2 gap-2 text-xs">
|
||||||
{entity.fields.slice(0, 4).map(field => (
|
{entity.fields.slice(0, 4).map((field) => (
|
||||||
<div key={field.id} className="flex items-center gap-2">
|
<div key={field.id} className="flex items-center gap-2">
|
||||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
<span
|
||||||
field.type === 'string' ? 'bg-blue-100 text-blue-700' :
|
className={`px-2 py-1 rounded text-xs font-medium ${
|
||||||
field.type === 'number' || field.type === 'decimal' ? 'bg-green-100 text-green-700' :
|
field.type === 'string'
|
||||||
field.type === 'boolean' ? 'bg-purple-100 text-purple-700' :
|
? 'bg-blue-100 text-blue-700'
|
||||||
field.type === 'date' ? 'bg-orange-100 text-orange-700' :
|
: field.type === 'number' || field.type === 'decimal'
|
||||||
'bg-slate-100 text-slate-700'
|
? 'bg-green-100 text-green-700'
|
||||||
}`}>
|
: field.type === 'boolean'
|
||||||
|
? 'bg-purple-100 text-purple-700'
|
||||||
|
: field.type === 'date'
|
||||||
|
? 'bg-orange-100 text-orange-700'
|
||||||
|
: 'bg-slate-100 text-slate-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{field.type}
|
{field.type}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-slate-600">{field.name}</span>
|
<span className="text-slate-600">{field.name}</span>
|
||||||
|
|
@ -226,7 +257,8 @@ const EntityManager: React.FC = () => {
|
||||||
))}
|
))}
|
||||||
{entity.fields.length > 4 && (
|
{entity.fields.length > 4 && (
|
||||||
<div className="text-slate-500 italic">
|
<div className="text-slate-500 italic">
|
||||||
+{entity.fields.length - 4} {translate('::App.DeveloperKit.Entity.More')}
|
+{entity.fields.length - 4}{' '}
|
||||||
|
{translate('::App.DeveloperKit.Entity.More')}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -236,22 +268,34 @@ const EntityManager: React.FC = () => {
|
||||||
{/* Migration and Endpoint Status */}
|
{/* Migration and Endpoint Status */}
|
||||||
<div className="mb-4 space-y-3">
|
<div className="mb-4 space-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm font-medium text-slate-700">{translate('::App.DeveloperKit.Entity.MigrationStatus')}</span>
|
<span className="text-sm font-medium text-slate-700">
|
||||||
<span className={`text-xs px-2 py-1 rounded-full ${
|
{translate('::App.DeveloperKit.Entity.MigrationStatus')}
|
||||||
entity.migrationStatus === 'applied' ? 'bg-green-100 text-green-700' :
|
</span>
|
||||||
entity.migrationStatus === 'pending' ? 'bg-yellow-100 text-yellow-700' :
|
<span
|
||||||
'bg-red-100 text-red-700'
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
}`}>
|
entity.migrationStatus === 'applied'
|
||||||
|
? 'bg-green-100 text-green-700'
|
||||||
|
: entity.migrationStatus === 'pending'
|
||||||
|
? 'bg-yellow-100 text-yellow-700'
|
||||||
|
: 'bg-red-100 text-red-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{entity.migrationStatus}
|
{entity.migrationStatus}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm font-medium text-slate-700">{translate('::App.DeveloperKit.Entity.EndpointStatus')}</span>
|
<span className="text-sm font-medium text-slate-700">
|
||||||
<span className={`text-xs px-2 py-1 rounded-full ${
|
{translate('::App.DeveloperKit.Entity.EndpointStatus')}
|
||||||
entity.endpointStatus === 'applied' ? 'bg-blue-100 text-blue-700' :
|
</span>
|
||||||
entity.endpointStatus === 'pending' ? 'bg-orange-100 text-orange-700' :
|
<span
|
||||||
'bg-red-100 text-red-700'
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
}`}>
|
entity.endpointStatus === 'applied'
|
||||||
|
? 'bg-blue-100 text-blue-700'
|
||||||
|
: entity.endpointStatus === 'pending'
|
||||||
|
? 'bg-orange-100 text-orange-700'
|
||||||
|
: 'bg-red-100 text-red-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{entity.endpointStatus}
|
{entity.endpointStatus}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -283,7 +327,10 @@ const EntityManager: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesEdit.replace(':id', entity.id)}
|
to={ROUTES_ENUM.protected.saas.developerKit.entitiesEdit.replace(
|
||||||
|
':id',
|
||||||
|
entity.id,
|
||||||
|
)}
|
||||||
className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
|
className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
|
||||||
title={translate('::App.DeveloperKit.Entity.Edit')}
|
title={translate('::App.DeveloperKit.Entity.Edit')}
|
||||||
>
|
>
|
||||||
|
|
@ -300,7 +347,7 @@ const EntityManager: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -310,15 +357,16 @@ const EntityManager: React.FC = () => {
|
||||||
<FaDatabase className="w-8 h-8 text-slate-500" />
|
<FaDatabase className="w-8 h-8 text-slate-500" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-medium text-slate-900 mb-2">
|
<h3 className="text-lg font-medium text-slate-900 mb-2">
|
||||||
{searchTerm || filterActive !== 'all' ? translate('::App.DeveloperKit.Entity.NoEntitiesFound') : translate('::App.DeveloperKit.Entity.NoEntitiesYet')}
|
{searchTerm || filterActive !== 'all'
|
||||||
|
? translate('::App.DeveloperKit.Entity.NoEntitiesFound')
|
||||||
|
: translate('::App.DeveloperKit.Entity.NoEntitiesYet')}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-slate-600 mb-6">
|
<p className="text-slate-600 mb-6">
|
||||||
{searchTerm || filterActive !== 'all'
|
{searchTerm || filterActive !== 'all'
|
||||||
? translate('::App.DeveloperKit.Entity.TryAdjustingFilters')
|
? translate('::App.DeveloperKit.Entity.TryAdjustingFilters')
|
||||||
: translate('::App.DeveloperKit.Entity.CreateFirstEntity')
|
: translate('::App.DeveloperKit.Entity.CreateFirstEntity')}
|
||||||
}
|
|
||||||
</p>
|
</p>
|
||||||
{(!searchTerm && filterActive === 'all') && (
|
{!searchTerm && filterActive === 'all' && (
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
|
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
|
||||||
className="inline-flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
|
className="inline-flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
|
||||||
|
|
@ -331,7 +379,7 @@ const EntityManager: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default EntityManager;
|
export default EntityManager
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import {
|
||||||
FaEye,
|
FaEye,
|
||||||
FaSync,
|
FaSync,
|
||||||
FaTrashAlt,
|
FaTrashAlt,
|
||||||
FaPlus
|
FaPlus,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ const MigrationManager: React.FC = () => {
|
||||||
setGeneratingEndpoints(entityId)
|
setGeneratingEndpoints(entityId)
|
||||||
await generateCrudEndpoints(entityId)
|
await generateCrudEndpoints(entityId)
|
||||||
// Navigate to API Endpoints page after successful generation
|
// Navigate to API Endpoints page after successful generation
|
||||||
navigate(ROUTES_ENUM.protected.saas.developerKitMigrations)
|
navigate(ROUTES_ENUM.protected.saas.developerKit.migrations)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to generate CRUD endpoints:', error)
|
console.error('Failed to generate CRUD endpoints:', error)
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -186,7 +186,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Migration.Total')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Migration.Total')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
|
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
|
||||||
|
|
@ -197,7 +199,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Migration.Pending')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Migration.Pending')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.pending}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.pending}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-yellow-100 text-yellow-600 p-3 rounded-lg">
|
<div className="bg-yellow-100 text-yellow-600 p-3 rounded-lg">
|
||||||
|
|
@ -208,7 +212,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Migration.Applied')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Migration.Applied')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.applied}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.applied}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-green-100 text-green-600 p-3 rounded-lg">
|
<div className="bg-green-100 text-green-600 p-3 rounded-lg">
|
||||||
|
|
@ -219,7 +225,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-600">{translate('::App.DeveloperKit.Migration.Failed')}</p>
|
<p className="text-sm font-medium text-slate-600">
|
||||||
|
{translate('::App.DeveloperKit.Migration.Failed')}
|
||||||
|
</p>
|
||||||
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.failed}</p>
|
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.failed}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-red-100 text-red-600 p-3 rounded-lg">
|
<div className="bg-red-100 text-red-600 p-3 rounded-lg">
|
||||||
|
|
@ -249,14 +257,18 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium text-slate-900">{entity.displayName}</h4>
|
<h4 className="font-medium text-slate-900">{entity.displayName}</h4>
|
||||||
<p className="text-sm text-slate-600">{entity.fields.length} {translate('::App.DeveloperKit.Migration.Fields')}</p>
|
<p className="text-sm text-slate-600">
|
||||||
|
{entity.fields.length} {translate('::App.DeveloperKit.Migration.Fields')}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleGenerateMigration(entity.id)}
|
onClick={() => handleGenerateMigration(entity.id)}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="bg-yellow-600 text-white px-3 py-1 rounded text-sm hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
className="bg-yellow-600 text-white px-3 py-1 rounded text-sm hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{loading ? translate('::App.DeveloperKit.Migration.Generating') : translate('::App.DeveloperKit.Migration.Generate')}
|
{loading
|
||||||
|
? translate('::App.DeveloperKit.Migration.Generating')
|
||||||
|
: translate('::App.DeveloperKit.Migration.Generate')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -334,14 +346,16 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaCalendarAlt className="w-3 h-3" />
|
<FaCalendarAlt className="w-3 h-3" />
|
||||||
<span>
|
<span>
|
||||||
{translate('::App.DeveloperKit.Migration.Created')} {new Date(migration.creationTime).toLocaleDateString()}
|
{translate('::App.DeveloperKit.Migration.Created')}{' '}
|
||||||
|
{new Date(migration.creationTime).toLocaleDateString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{migration.appliedAt && (
|
{migration.appliedAt && (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaCheckCircle className="w-3 h-3" />
|
<FaCheckCircle className="w-3 h-3" />
|
||||||
<span>
|
<span>
|
||||||
{translate('::App.DeveloperKit.Migration.AppliedLabel')} {new Date(migration.appliedAt).toLocaleDateString()}
|
{translate('::App.DeveloperKit.Migration.AppliedLabel')}{' '}
|
||||||
|
{new Date(migration.appliedAt).toLocaleDateString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -367,7 +381,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<FaEye className="w-4 h-4" />
|
<FaEye className="w-4 h-4" />
|
||||||
{translate('::App.DeveloperKit.Migration.ViewSQL')}
|
{translate('::App.DeveloperKit.Migration.ViewSQL')}
|
||||||
{!migration.sqlScript && (
|
{!migration.sqlScript && (
|
||||||
<span className="ml-1 text-xs text-orange-500">({translate('::App.DeveloperKit.Migration.NoSQL')})</span>
|
<span className="ml-1 text-xs text-orange-500">
|
||||||
|
({translate('::App.DeveloperKit.Migration.NoSQL')})
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|
@ -441,7 +457,9 @@ const MigrationManager: React.FC = () => {
|
||||||
{/* SQL Script Preview */}
|
{/* SQL Script Preview */}
|
||||||
{selectedMigration === migration.id && (
|
{selectedMigration === migration.id && (
|
||||||
<div className="mt-4 pt-4 border-t border-slate-200">
|
<div className="mt-4 pt-4 border-t border-slate-200">
|
||||||
<h4 className="font-medium text-slate-900 mb-2">{translate('::App.DeveloperKit.Migration.SQLScriptLabel')}</h4>
|
<h4 className="font-medium text-slate-900 mb-2">
|
||||||
|
{translate('::App.DeveloperKit.Migration.SQLScriptLabel')}
|
||||||
|
</h4>
|
||||||
{migration.sqlScript ? (
|
{migration.sqlScript ? (
|
||||||
<div className="bg-slate-900 rounded-lg p-4 overflow-x-auto">
|
<div className="bg-slate-900 rounded-lg p-4 overflow-x-auto">
|
||||||
<pre className="text-green-400 text-sm">
|
<pre className="text-green-400 text-sm">
|
||||||
|
|
@ -452,7 +470,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
||||||
<div className="flex items-center gap-2 text-yellow-800">
|
<div className="flex items-center gap-2 text-yellow-800">
|
||||||
<FaRegBell className="w-5 h-5" />
|
<FaRegBell className="w-5 h-5" />
|
||||||
<span className="font-medium">{translate('::App.DeveloperKit.Migration.NoSQLScript')}</span>
|
<span className="font-medium">
|
||||||
|
{translate('::App.DeveloperKit.Migration.NoSQLScript')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-yellow-700 text-sm mt-1">
|
<p className="text-yellow-700 text-sm mt-1">
|
||||||
{translate('::App.DeveloperKit.Migration.NoSQLScriptDesc')}
|
{translate('::App.DeveloperKit.Migration.NoSQLScriptDesc')}
|
||||||
|
|
@ -468,7 +488,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
||||||
<div className="flex items-center gap-2 text-red-800 mb-2">
|
<div className="flex items-center gap-2 text-red-800 mb-2">
|
||||||
<FaRegBell className="w-5 h-5" />
|
<FaRegBell className="w-5 h-5" />
|
||||||
<span className="font-medium">{translate('::App.DeveloperKit.Migration.MigrationFailed')}</span>
|
<span className="font-medium">
|
||||||
|
{translate('::App.DeveloperKit.Migration.MigrationFailed')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-red-700 text-sm">{migration.errorMessage}</p>
|
<p className="text-red-700 text-sm">{migration.errorMessage}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -486,7 +508,9 @@ const MigrationManager: React.FC = () => {
|
||||||
<FaBolt className="w-8 h-8 text-slate-500" />
|
<FaBolt className="w-8 h-8 text-slate-500" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-medium text-slate-900 mb-2">
|
<h3 className="text-lg font-medium text-slate-900 mb-2">
|
||||||
{searchTerm || filterStatus !== 'all' ? translate('::App.DeveloperKit.Migration.NoMigrationsFound') : translate('::App.DeveloperKit.Migration.NoMigrationsYet')}
|
{searchTerm || filterStatus !== 'all'
|
||||||
|
? translate('::App.DeveloperKit.Migration.NoMigrationsFound')
|
||||||
|
: translate('::App.DeveloperKit.Migration.NoMigrationsYet')}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-slate-600">
|
<p className="text-slate-600">
|
||||||
{searchTerm || filterStatus !== 'all'
|
{searchTerm || filterStatus !== 'all'
|
||||||
|
|
|
||||||
|
|
@ -19,31 +19,31 @@ const DeveloperLayout: React.FC<DeveloperLayoutProps> = ({ children }) => {
|
||||||
id: 'dashboard',
|
id: 'dashboard',
|
||||||
label: translate('::App.DeveloperKit.Dashboard'),
|
label: translate('::App.DeveloperKit.Dashboard'),
|
||||||
icon: FaTachometerAlt,
|
icon: FaTachometerAlt,
|
||||||
path: ROUTES_ENUM.protected.saas.developerKit,
|
path: ROUTES_ENUM.protected.saas.developerKit.dashboard,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'entities',
|
id: 'entities',
|
||||||
label: translate('::App.DeveloperKit.Entity'),
|
label: translate('::App.DeveloperKit.Entity'),
|
||||||
icon: FaDatabase,
|
icon: FaDatabase,
|
||||||
path: ROUTES_ENUM.protected.saas.developerKitEntities,
|
path: ROUTES_ENUM.protected.saas.developerKit.entities,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'migrations',
|
id: 'migrations',
|
||||||
label: translate('::App.DeveloperKit.Migrations'),
|
label: translate('::App.DeveloperKit.Migrations'),
|
||||||
icon: FaBolt,
|
icon: FaBolt,
|
||||||
path: ROUTES_ENUM.protected.saas.developerKitMigrations,
|
path: ROUTES_ENUM.protected.saas.developerKit.migrations,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'endpoints',
|
id: 'endpoints',
|
||||||
label: translate('::App.DeveloperKit.Endpoints'),
|
label: translate('::App.DeveloperKit.Endpoints'),
|
||||||
icon: FaServer,
|
icon: FaServer,
|
||||||
path: ROUTES_ENUM.protected.saas.developerKitEndpoints,
|
path: ROUTES_ENUM.protected.saas.developerKit.endpoints,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'components',
|
id: 'components',
|
||||||
label: translate('::App.DeveloperKit.Components'),
|
label: translate('::App.DeveloperKit.Components'),
|
||||||
icon: FaPuzzlePiece,
|
icon: FaPuzzlePiece,
|
||||||
path: ROUTES_ENUM.protected.saas.developerKitComponents,
|
path: ROUTES_ENUM.protected.saas.developerKit.components,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Button, Input, Dialog } from '../ui'
|
||||||
import { FaFileAlt } from 'react-icons/fa'
|
import { FaFileAlt } from 'react-icons/fa'
|
||||||
import { ReportTemplateDto } from '@/proxy/reports/models'
|
import { ReportTemplateDto } from '@/proxy/reports/models'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
interface ReportGeneratorProps {
|
interface ReportGeneratorProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
|
|
@ -50,7 +51,7 @@ export const ReportGenerator: React.FC<ReportGeneratorProps> = ({
|
||||||
|
|
||||||
if (reportId) {
|
if (reportId) {
|
||||||
// Yeni sekmede rapor URL'sini aç
|
// Yeni sekmede rapor URL'sini aç
|
||||||
const reportUrl = `/admin/reports/${reportId}`
|
const reportUrl = ROUTES_ENUM.protected.saas.reports.view.replace(':id', reportId)
|
||||||
window.open(reportUrl, '_blank')
|
window.open(reportUrl, '_blank')
|
||||||
onClose() // Modal'ı kapat
|
onClose() // Modal'ı kapat
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ export const ROUTES_ENUM = {
|
||||||
about: '/about',
|
about: '/about',
|
||||||
products: '/products',
|
products: '/products',
|
||||||
checkout: '/checkout',
|
checkout: '/checkout',
|
||||||
success: '/success',
|
|
||||||
payment: '/payment',
|
payment: '/payment',
|
||||||
|
success: '/success',
|
||||||
services: '/services',
|
services: '/services',
|
||||||
demo: '/demo',
|
|
||||||
blog: '/blog',
|
blog: '/blog',
|
||||||
|
blogDetail: '/blog/:id',
|
||||||
|
demo: '/demo',
|
||||||
contact: '/contact',
|
contact: '/contact',
|
||||||
accessDenied: '/access-denied',
|
accessDenied: '/access-denied',
|
||||||
},
|
},
|
||||||
|
|
@ -33,17 +34,23 @@ export const ROUTES_ENUM = {
|
||||||
edit: '/admin/chart/edit/:chartCode',
|
edit: '/admin/chart/edit/:chartCode',
|
||||||
},
|
},
|
||||||
forumManagement: '/admin/forumManagement',
|
forumManagement: '/admin/forumManagement',
|
||||||
developerKit: '/admin/developerkit',
|
developerKit: {
|
||||||
developerKitEntities: '/admin/developerkit/entities',
|
dashboard: '/admin/developerkit',
|
||||||
developerKitEntitiesNew: '/admin/developerkit/entities/new',
|
entities: '/admin/developerkit/entities',
|
||||||
developerKitEntitiesEdit: '/admin/developerkit/entities/edit/:id',
|
entitiesNew: '/admin/developerkit/entities/new',
|
||||||
developerKitMigrations: '/admin/developerkit/migrations',
|
entitiesEdit: '/admin/developerkit/entities/edit/:id',
|
||||||
developerKitEndpoints: '/admin/developerkit/endpoints',
|
migrations: '/admin/developerkit/migrations',
|
||||||
developerKitEndpointsNew: '/admin/developerkit/endpoints/new',
|
endpoints: '/admin/developerkit/endpoints',
|
||||||
developerKitComponents: '/admin/developerkit/components',
|
endpointsNew: '/admin/developerkit/endpoints/new',
|
||||||
developerKitComponentsNew: '/admin/developerkit/components/new',
|
components: '/admin/developerkit/components',
|
||||||
developerKitComponentsView: '/admin/developerkit/components/view/:id',
|
componentsNew: '/admin/developerkit/components/new',
|
||||||
developerKitComponentsEdit: '/admin/developerkit/components/edit/:id',
|
componentsView: '/admin/developerkit/components/view/:id',
|
||||||
|
componentsEdit: '/admin/developerkit/components/edit/:id',
|
||||||
|
},
|
||||||
|
reports: {
|
||||||
|
generator: '/admin/reports/generator',
|
||||||
|
view: '/admin/reports/:id',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
ai: '/admin/ai',
|
ai: '/admin/ai',
|
||||||
|
|
@ -54,7 +61,6 @@ export const ROUTES_ENUM = {
|
||||||
},
|
},
|
||||||
activityLog: '/admin/activityLog',
|
activityLog: '/admin/activityLog',
|
||||||
changeLog: '/admin/changeLog',
|
changeLog: '/admin/changeLog',
|
||||||
|
|
||||||
settings: '/admin/settings',
|
settings: '/admin/settings',
|
||||||
identity: {
|
identity: {
|
||||||
user: {
|
user: {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { GridOptionsEditDto, ListFormCustomizationDto } from '@/proxy/form/model
|
||||||
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
|
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
|
||||||
import { getListFormCustomizations } from '@/services/admin/list-form-customization.service'
|
import { getListFormCustomizations } from '@/services/admin/list-form-customization.service'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
export interface FormEditProps {
|
export interface FormEditProps {
|
||||||
onSubmit: (
|
onSubmit: (
|
||||||
|
|
@ -153,7 +154,7 @@ const FormEdit = () => {
|
||||||
<div className="lg:flex items-center justify-between mb-4 gap-3">
|
<div className="lg:flex items-center justify-between mb-4 gap-3">
|
||||||
<div className="mb-4 lg:mb-0">
|
<div className="mb-4 lg:mb-0">
|
||||||
<h4>
|
<h4>
|
||||||
<Link to={`/admin/list/${listFormCode}`}>
|
<Link to={ROUTES_ENUM.protected.admin.list.replace(':listFormCode', listFormCode)}>
|
||||||
🔙 {listFormCode} - {translate(`::${listFormValues.title}`)}
|
🔙 {listFormCode} - {translate(`::${listFormValues.title}`)}
|
||||||
</Link>
|
</Link>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ import {
|
||||||
FaUserShield,
|
FaUserShield,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { object, string } from 'yup'
|
import { object, string } from 'yup'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
const schema = object().shape({
|
const schema = object().shape({
|
||||||
id: string(),
|
id: string(),
|
||||||
|
|
@ -587,7 +588,10 @@ const OrganizationUnits = () => {
|
||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<ActionLink
|
<ActionLink
|
||||||
href={`/admin/identity/users/${user.id}/details`}
|
href={ROUTES_ENUM.protected.admin.identity.user.detail.replace(
|
||||||
|
':userId',
|
||||||
|
user.id!,
|
||||||
|
)}
|
||||||
className="font-bold"
|
className="font-bold"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
PermissionWithStyle,
|
PermissionWithStyle,
|
||||||
UpdatePermissionDto,
|
UpdatePermissionDto,
|
||||||
} from '@/proxy/admin/models'
|
} from '@/proxy/admin/models'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
const { Tr, Th, Td, THead, TBody } = Table
|
const { Tr, Th, Td, THead, TBody } = Table
|
||||||
|
|
||||||
|
|
@ -249,7 +250,10 @@ const Users = () => {
|
||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<ActionLink
|
<ActionLink
|
||||||
href={`/admin/identity/users/${user.id}/details`}
|
href={ROUTES_ENUM.protected.admin.identity.user.detail.replace(
|
||||||
|
':userId',
|
||||||
|
user.id!,
|
||||||
|
)}
|
||||||
className="font-bold"
|
className="font-bold"
|
||||||
>
|
>
|
||||||
{user.name} {user.surname}
|
{user.name} {user.surname}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom'
|
||||||
import useAccount from '@/utils/hooks/useAccount'
|
import useAccount from '@/utils/hooks/useAccount'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
const VerifyConfirmationCode = () => {
|
const VerifyConfirmationCode = () => {
|
||||||
const { userId, token } = useParams()
|
const { userId, token } = useParams()
|
||||||
|
|
@ -37,7 +38,11 @@ const VerifyConfirmationCode = () => {
|
||||||
<Alert showIcon className="mb-4" type="danger">
|
<Alert showIcon className="mb-4" type="danger">
|
||||||
{error}
|
{error}
|
||||||
</Alert>
|
</Alert>
|
||||||
<Button block variant="solid" onClick={() => navigate('/account/confirm')}>
|
<Button
|
||||||
|
block
|
||||||
|
variant="solid"
|
||||||
|
onClick={() => navigate(ROUTES_ENUM.authenticated.sendConfirmationCode)}
|
||||||
|
>
|
||||||
{translate('::Abp.Account.VerifyConfirmationCode')}
|
{translate('::Abp.Account.VerifyConfirmationCode')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import { addCss, addJs } from '../list/Utils'
|
||||||
import { PermissionResults, RowMode, SimpleItemWithColData } from './types'
|
import { PermissionResults, RowMode, SimpleItemWithColData } from './types'
|
||||||
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from '@/proxy/form/models'
|
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from '@/proxy/form/models'
|
||||||
import { getAccessDeniedPath } from '@/utils/routing'
|
import { getAccessDeniedPath } from '@/utils/routing'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
const useGridData = (props: {
|
const useGridData = (props: {
|
||||||
mode: RowMode
|
mode: RowMode
|
||||||
|
|
@ -125,7 +126,11 @@ const useGridData = (props: {
|
||||||
var result = await dataSource.update(id, data)
|
var result = await dataSource.update(id, data)
|
||||||
if (result.data > 0) {
|
if (result.data > 0) {
|
||||||
if (!isSubForm) {
|
if (!isSubForm) {
|
||||||
navigate(`/form/${listFormCode}/${id}`)
|
navigate(
|
||||||
|
ROUTES_ENUM.protected.admin.formView
|
||||||
|
.replace(':listFormCode', listFormCode)
|
||||||
|
.replace(':id', id!),
|
||||||
|
)
|
||||||
} else if (props.onSubmitAction) {
|
} else if (props.onSubmitAction) {
|
||||||
props.onSubmitAction()
|
props.onSubmitAction()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { setGridPanelColor } from './Utils'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { usePermission } from '@/utils/hooks/usePermission'
|
import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
import { usePWA } from '@/utils/hooks/usePWA'
|
import { usePWA } from '@/utils/hooks/usePWA'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
export interface ISelectBoxData {
|
export interface ISelectBoxData {
|
||||||
value?: string
|
value?: string
|
||||||
|
|
@ -177,9 +178,15 @@ const useFilters = ({
|
||||||
// Kayitli bir filtreyi silmek icin ilgili ekrani ac
|
// Kayitli bir filtreyi silmek icin ilgili ekrani ac
|
||||||
setIsDeleteModalOpen(true)
|
setIsDeleteModalOpen(true)
|
||||||
} else if (itemData.id === 'openPivotGrid') {
|
} else if (itemData.id === 'openPivotGrid') {
|
||||||
navigate(`/pivot/${listFormCode}`)
|
navigate(ROUTES_ENUM.protected.admin.pivot.replace(':listFormCode', listFormCode))
|
||||||
} else if (itemData.id === 'openManage') {
|
} else if (itemData.id === 'openManage') {
|
||||||
window.open(`/admin/listform/edit/${listFormCode}`, isPwaMode ? '_self' : '_blank')
|
window.open(
|
||||||
|
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||||
|
':listFormCode',
|
||||||
|
listFormCode,
|
||||||
|
),
|
||||||
|
isPwaMode ? '_self' : '_blank',
|
||||||
|
)
|
||||||
} else if (itemData.id === 'clearFilter') {
|
} else if (itemData.id === 'clearFilter') {
|
||||||
// gridin bütün filtrelerini temizle
|
// gridin bütün filtrelerini temizle
|
||||||
const grid = gridRef.current?.instance
|
const grid = gridRef.current?.instance
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue