add login register and create cluster api

This commit is contained in:
behrooz
2025-08-29 19:57:59 +03:30
parent e4d83eb1bf
commit 24e362cdba
4 changed files with 133 additions and 72 deletions

View File

@@ -47,7 +47,7 @@ export default function DashboardLayout() {
}
>
<Layers size={18} />
Create Cluster
List Cluster
</NavLink>
<div className="pt-4 border-t border-gray-200">

View File

@@ -1,11 +1,15 @@
import { useState } from 'react'
import { Link } from 'react-router-dom'
import { Download, Trash2 } from 'lucide-react'
import { Download, Feather, Trash2 } from 'lucide-react'
import type { FormEvent } from 'react'
interface Cluster {
id: string
name: string
Name: string
ControlPlane: string
PlatformVersion: string
Cpu: string
Memory: string
clusterId: string
status: string
version: string
@@ -15,15 +19,30 @@ interface Cluster {
export default function CreateCluster() {
const [clusters, setClusters] = useState<Cluster[]>(() => {
fetch('http://localhost:8082/clusters', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `${localStorage.getItem('auth:token') || ''}`
},
}).then(async (res) => {
if (res.ok) {
const data = await res.json()
setClusters(data.clusters || [])
return data.clusters || []
//localStorage.setItem('clusters', JSON.stringify(data.clusters || []))
} else {
const data = await res.json()
console.error(data.message || 'Failed to fetch clusters')
}
}).catch(() => {
console.error('Failed to fetch clusters')
})
const saved = localStorage.getItem('clusters')
if (saved) {
return JSON.parse(saved)
}
return [
{ id: '1', name: 'dev-cluster', clusterId: '680d172c', status: 'Healthy', version: 'v1.28.0', alerts: '0', endpoint: 'https://dev-cluster.example.com' },
{ id: '2', name: 'prod-cluster', clusterId: 'd02b06fe', status: 'Healthy', version: 'v1.28.0', alerts: '0', endpoint: 'https://prod-cluster.example.com' },
{ id: '3', name: 'test-prod', clusterId: '937261be', status: 'Healthy', version: 'v1.28.0', alerts: '0', endpoint: 'https://test-prod.example.com' },
]
return []
})
const [showModal, setShowModal] = useState(false)
@@ -32,34 +51,51 @@ export default function CreateCluster() {
namespace: '',
controlPlane: 'Kubernetes (k8s)',
kubernetesVersion: 'v1.31.6 (recommended)',
cpu: 1,
memory: 2048
Cpu: 1,
Memory: 1024
})
const handleSubmit = (e: FormEvent) => {
e.preventDefault()
const newCluster: Cluster = {
id: Date.now().toString(),
name: formData.clusterName,
const newCluster: Cluster = {
Name: formData.clusterName,
clusterId: Math.random().toString(36).substr(2, 8),
status: 'Creating',
version: formData.kubernetesVersion.split(' ')[0],
alerts: '0',
endpoint: `https://${formData.clusterName}.example.com`
}
ControlPlane: formData.controlPlane,
Cpu: formData.Cpu.toString(),
Memory: formData.Memory.toString(),
PlatformVersion: formData.kubernetesVersion.split(' ')[0]
}
const updatedClusters = [...clusters, newCluster]
setClusters(updatedClusters)
localStorage.setItem('clusters', JSON.stringify(updatedClusters))
setShowModal(false)
setFormData({
clusterName: '',
namespace: '',
controlPlane: 'Kubernetes (k8s)',
kubernetesVersion: 'v1.31.6 (recommended)',
cpu: 1,
memory: 2048
})
fetch('http://localhost:8082/createcluster', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': localStorage.getItem('auth:token') || '' },
body: JSON.stringify(newCluster),
}).then(async (res) => {
if (res.ok) {
const data = await res.json()
console.log(data)
} else {
const data = await res.json()
console.log(data)
// setError(data.message || 'Login failed')
}
}).catch(() => {
//setError('Login failed')
})
// const updatedClusters = [...clusters, newCluster]
// setClusters(updatedClusters)
// localStorage.setItem('clusters', JSON.stringify(updatedClusters))
// setShowModal(false)
// setFormData({
// clusterName: '',
// namespace: '',
// controlPlane: 'Kubernetes (k8s)',
// kubernetesVersion: 'v1.31.6 (recommended)',
// Cpu: 1,
// Memory: 2048
// })
}
const downloadKubeconfig = (clusterId: string) => {
@@ -138,7 +174,7 @@ users:
to={`/app/clusters/${cluster.id}`}
className="text-sm font-medium text-blue-600 hover:text-blue-900"
>
{cluster.name}
{cluster.Name}
</Link>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{cluster.clusterId}</td>
@@ -202,18 +238,7 @@ users:
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Namespace
</label>
<input
type="text"
value={formData.namespace}
onChange={(e) => setFormData({...formData, namespace: e.target.value})}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
</div>
</div>
@@ -256,14 +281,14 @@ users:
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
CPU (cores)
Cpu (cores)
</label>
<input
type="number"
min="1"
max="8"
value={formData.cpu}
onChange={(e) => setFormData({...formData, cpu: parseInt(e.target.value)})}
value={formData.Cpu}
onChange={(e) => setFormData({...formData, Cpu: parseInt(e.target.value)})}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
@@ -276,8 +301,8 @@ users:
min="1024"
max="16384"
step="1024"
value={formData.memory}
onChange={(e) => setFormData({...formData, memory: parseInt(e.target.value)})}
value={formData.Memory}
onChange={(e) => setFormData({...formData, Memory: parseInt(e.target.value)})}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>

View File

@@ -5,22 +5,38 @@ import Button from '../components/ui/button'
export default function Login() {
const navigate = useNavigate()
const [email, setEmail] = useState('')
const [username, setusername] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState<string | null>(null)
function onSubmit(e: FormEvent) {
e.preventDefault()
setError(null)
const usersString = localStorage.getItem('auth:users')
const users: Array<{ email: string; password: string }> = usersString ? JSON.parse(usersString) : []
const match = users.find((u) => u.email === email && u.password === password)
if (!match) {
setError('Invalid credentials')
return
}
localStorage.setItem('auth:user', JSON.stringify({ email }))
navigate('/app')
fetch('http://localhost:8082/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(async (res) => {
if (res.ok) {
const data = await res.json()
localStorage.setItem('auth:token', data.token)
navigate('/app')
} else {
const data = await res.json()
setError(data.message || 'Login failed')
}
}).catch(() => {
setError('Login failed')
})
// const usersString = localStorage.getItem('auth:users')
// const users: Array<{ username: string; password: string }> = usersString ? JSON.parse(usersString) : []
// const match = users.find((u) => u.username === username && u.password === password)
// if (!match) {
// setError('Invalid credentials')
// return
// }
// localStorage.setItem('auth:user', JSON.stringify({ username }))
}
return (
@@ -29,13 +45,13 @@ export default function Login() {
<h1 className="text-xl font-semibold mb-4">Login</h1>
<form className="space-y-4" onSubmit={onSubmit}>
<div className="space-y-1">
<label className="text-sm font-medium" htmlFor="email">Email</label>
<label className="text-sm font-medium" htmlFor="username">username</label>
<input
id="email"
type="email"
id="username"
type="username"
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={email}
onChange={(e) => setEmail(e.target.value)}
value={username}
onChange={(e) => setusername(e.target.value)}
required
/>
</div>

View File

@@ -6,6 +6,7 @@ import Button from '../components/ui/button'
export default function Register() {
const navigate = useNavigate()
const [email, setEmail] = useState('')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [confirm, setConfirm] = useState('')
const [error, setError] = useState<string | null>(null)
@@ -13,20 +14,28 @@ export default function Register() {
function onSubmit(e: FormEvent) {
e.preventDefault()
setError(null)
if (password !== confirm) {
setError('Passwords do not match')
return
}
const usersString = localStorage.getItem('auth:users')
const users: Array<{ email: string; password: string }> = usersString ? JSON.parse(usersString) : []
if (users.some((u) => u.email === email)) {
setError('Email already registered')
return
}
users.push({ email, password })
localStorage.setItem('auth:users', JSON.stringify(users))
localStorage.setItem('auth:user', JSON.stringify({ email }))
navigate('/app')
fetch('http://localhost:8082/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, email, password }),
}).then(async (res) => {
if (res.ok) {
navigate('/login')
} else {
const data = await res.json()
// throw new Error(data.message || 'Registration failed')
setError(data.message || 'Registration failed')
}
}).catch(() => {
setError('Registration failed')
})
}
return (
@@ -45,6 +54,17 @@ export default function Register() {
required
/>
</div>
<div className="space-y-1">
<label className="text-sm font-medium" htmlFor="username">Username</label>
<input
id="username"
type="username"
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
</div>
<div className="space-y-1">
<label className="text-sm font-medium" htmlFor="password">Password</label>
<input