Add automatic cluster pool allocation.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -227,6 +227,8 @@ export default function AdminClustersPage() {
|
||||
kubeconfig: '',
|
||||
region: '',
|
||||
provider: '',
|
||||
weight: 1,
|
||||
tags: '',
|
||||
isDefault: false,
|
||||
});
|
||||
|
||||
@@ -236,12 +238,16 @@ export default function AdminClustersPage() {
|
||||
});
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: typeof form) => api.post('/clusters', data),
|
||||
mutationFn: (data: typeof form) => api.post('/clusters', {
|
||||
...data,
|
||||
tags: data.tags.split(',').map((tag) => tag.trim()).filter(Boolean),
|
||||
weight: Number(data.weight) || 1,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-clusters'] });
|
||||
toast.success('Cluster added & connection verified ✓');
|
||||
setShowForm(false);
|
||||
setForm({ name: '', description: '', apiServer: '', kubeconfig: '', region: '', provider: '', isDefault: false });
|
||||
setForm({ name: '', description: '', apiServer: '', kubeconfig: '', region: '', provider: '', weight: 1, tags: '', isDefault: false });
|
||||
},
|
||||
onError: (err: any) => {
|
||||
const message = err?.response?.data?.message || 'Failed to add cluster';
|
||||
@@ -333,6 +339,25 @@ export default function AdminClustersPage() {
|
||||
<option value="bare-metal">Bare Metal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Weight</label>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
className="input-field"
|
||||
value={form.weight}
|
||||
onChange={(e) => setForm({ ...form, weight: Number(e.target.value) || 1 })}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Tags</label>
|
||||
<input
|
||||
className="input-field"
|
||||
placeholder="ssd, production, iran"
|
||||
value={form.tags}
|
||||
onChange={(e) => setForm({ ...form, tags: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Description</label>
|
||||
@@ -410,10 +435,39 @@ export default function AdminClustersPage() {
|
||||
}`}>
|
||||
{cluster.status}
|
||||
</span>
|
||||
<span className={`badge ${
|
||||
cluster.healthStatus === 'healthy' ? 'badge-green'
|
||||
: cluster.healthStatus === 'degraded' ? 'badge-yellow'
|
||||
: cluster.healthStatus === 'unhealthy' ? 'badge-red'
|
||||
: 'badge-gray'
|
||||
}`}>
|
||||
health: {cluster.healthStatus || 'unknown'}
|
||||
</span>
|
||||
<span className="badge badge-gray">weight {cluster.weight || 1}</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 truncate">
|
||||
{cluster.provider || 'Unknown'} · {cluster.region || 'N/A'} · {cluster.apiServer}
|
||||
</p>
|
||||
{cluster.healthMessage && (
|
||||
<p className="text-xs text-gray-400 mt-1">
|
||||
{cluster.healthMessage}
|
||||
{cluster.lastHealthCheckedAt ? ` · ${new Date(cluster.lastHealthCheckedAt).toLocaleString()}` : ''}
|
||||
</p>
|
||||
)}
|
||||
{cluster.tags?.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-2">
|
||||
{cluster.tags.map((tag) => (
|
||||
<span key={tag} className="px-2 py-0.5 rounded-full bg-gray-100 text-gray-600 text-xs">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{cluster.availableResources && (
|
||||
<p className="text-xs text-gray-500 mt-2">
|
||||
CPU {cluster.availableResources.totalCpuAllocatable || 'n/a'} · Memory {cluster.availableResources.totalMemoryAllocatable || 'n/a'} · Pods {cluster.availableResources.podCount ?? 'n/a'} · Apps {cluster.availableResources.appCount ?? 'n/a'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0 flex-wrap">
|
||||
|
||||
Reference in New Issue
Block a user