Add automatic cluster pool allocation.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,8 +16,10 @@ export default function AdminPoolsPage() {
|
||||
const [form, setForm] = useState({
|
||||
name: '',
|
||||
description: '',
|
||||
strategy: 'least-apps' as 'least-apps' | 'round-robin',
|
||||
strategy: 'weighted-resource' as 'least-apps' | 'round-robin' | 'weighted-resource',
|
||||
clusterIds: [] as string[],
|
||||
isDefault: false,
|
||||
priority: 100,
|
||||
});
|
||||
|
||||
const { data: pools = [], isLoading } = useQuery<ClusterPool[]>({
|
||||
@@ -66,7 +68,7 @@ export default function AdminPoolsPage() {
|
||||
const resetForm = () => {
|
||||
setShowForm(false);
|
||||
setEditingPool(null);
|
||||
setForm({ name: '', description: '', strategy: 'least-apps', clusterIds: [] });
|
||||
setForm({ name: '', description: '', strategy: 'weighted-resource', clusterIds: [], isDefault: false, priority: 100 });
|
||||
};
|
||||
|
||||
const startEdit = (pool: ClusterPool) => {
|
||||
@@ -76,6 +78,8 @@ export default function AdminPoolsPage() {
|
||||
description: pool.description || '',
|
||||
strategy: pool.strategy,
|
||||
clusterIds: pool.clusterIds,
|
||||
isDefault: pool.isDefault || false,
|
||||
priority: pool.priority || 100,
|
||||
});
|
||||
setShowForm(true);
|
||||
};
|
||||
@@ -138,10 +142,21 @@ export default function AdminPoolsPage() {
|
||||
value={form.strategy}
|
||||
onChange={(e) => setForm({ ...form, strategy: e.target.value as any })}
|
||||
>
|
||||
<option value="weighted-resource">Weighted Resource — prefer healthy capacity and higher weights</option>
|
||||
<option value="least-apps">Least Apps — deploy to cluster with fewest apps</option>
|
||||
<option value="round-robin">Round Robin — rotate across clusters evenly</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Priority</label>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
className="input-field"
|
||||
value={form.priority}
|
||||
onChange={(e) => setForm({ ...form, priority: Number(e.target.value) || 100 })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -154,6 +169,15 @@ export default function AdminPoolsPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="flex items-center gap-2 text-sm text-gray-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.isDefault}
|
||||
onChange={(e) => setForm({ ...form, isDefault: e.target.checked })}
|
||||
/>
|
||||
Use as default allocator pool
|
||||
</label>
|
||||
|
||||
{/* Cluster selection */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
@@ -195,7 +219,7 @@ export default function AdminPoolsPage() {
|
||||
)}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
{cluster.provider || 'Unknown'} · {cluster.region || 'N/A'}
|
||||
{cluster.provider || 'Unknown'} · {cluster.region || 'N/A'} · weight {cluster.weight || 1}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,6 +230,17 @@ export default function AdminPoolsPage() {
|
||||
}`}>
|
||||
{cluster.status}
|
||||
</span>
|
||||
<span className={`px-2 py-0.5 rounded-full text-xs font-medium ${
|
||||
cluster.healthStatus === 'healthy'
|
||||
? 'bg-green-100 text-green-700'
|
||||
: cluster.healthStatus === 'degraded'
|
||||
? 'bg-yellow-100 text-yellow-700'
|
||||
: cluster.healthStatus === 'unhealthy'
|
||||
? 'bg-red-100 text-red-700'
|
||||
: 'bg-gray-100 text-gray-600'
|
||||
}`}>
|
||||
{cluster.healthStatus || 'unknown'}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
@@ -278,8 +313,14 @@ export default function AdminPoolsPage() {
|
||||
{pool.isActive ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
<span className="badge badge-purple flex items-center gap-1">
|
||||
{pool.strategy === 'least-apps' ? <><BarChart3 className="w-3 h-3" /> Least Apps</> : <><RotateCw className="w-3 h-3" /> Round Robin</>}
|
||||
{pool.strategy === 'weighted-resource'
|
||||
? <><BarChart3 className="w-3 h-3" /> Weighted Resource</>
|
||||
: pool.strategy === 'least-apps'
|
||||
? <><BarChart3 className="w-3 h-3" /> Least Apps</>
|
||||
: <><RotateCw className="w-3 h-3" /> Round Robin</>}
|
||||
</span>
|
||||
{pool.isDefault && <span className="badge badge-blue">Default Pool</span>}
|
||||
<span className="badge badge-gray">Priority {pool.priority || 100}</span>
|
||||
</div>
|
||||
{pool.description && (
|
||||
<p className="text-sm text-gray-500 mb-3">{pool.description}</p>
|
||||
@@ -299,7 +340,7 @@ export default function AdminPoolsPage() {
|
||||
<span>{cluster.status === 'active' ? <CheckCircle className="w-3 h-3" /> : <XCircle className="w-3 h-3" />}</span>
|
||||
<span>{cluster.name}</span>
|
||||
<span className="text-gray-400">
|
||||
({cluster.provider || 'N/A'} · {cluster.region || 'N/A'})
|
||||
({cluster.provider || 'N/A'} · {cluster.region || 'N/A'} · weight {cluster.weight || 1} · {cluster.healthStatus || 'unknown'})
|
||||
</span>
|
||||
</div>
|
||||
)) : (
|
||||
|
||||
Reference in New Issue
Block a user