refactor(MikrotikTools): replace gateway input with card-based target selection for improved UI and user interaction
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 3m30s
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 3m30s
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import api from './lib/api.js';
|
import api from './lib/api.js';
|
||||||
import { useNotify } from './components/NotifyProvider.jsx';
|
import { useNotify } from './components/NotifyProvider.jsx';
|
||||||
import GatewayAutocompleteInput from './components/GatewayAutocompleteInput.jsx';
|
|
||||||
import PageHeader from './components/PageHeader.jsx';
|
import PageHeader from './components/PageHeader.jsx';
|
||||||
import TableSkeleton from './components/TableSkeleton.jsx';
|
import TableSkeleton from './components/TableSkeleton.jsx';
|
||||||
import EmptyState from './components/EmptyState.jsx';
|
import EmptyState from './components/EmptyState.jsx';
|
||||||
@@ -366,36 +365,33 @@ function MikrotikTools() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<GatewayAutocompleteInput
|
|
||||||
value={gatewayRef}
|
|
||||||
onChange={setGatewayRef}
|
|
||||||
gateways={gateways}
|
|
||||||
interfaces={interfaces}
|
|
||||||
serverId={serverId || null}
|
|
||||||
placeholder="IP gateway или интерфейс…"
|
|
||||||
onSelectMeta={handleSelectGatewayMeta}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Быстрые цели — чипы */}
|
{/* Цели — карточки в стиле сервера/gateway */}
|
||||||
<div className="d-flex flex-wrap align-items-center gap-1 mt-2">
|
<div className="row row-cards g-1 mt-2">
|
||||||
<span className="text-muted small me-1">Цель:</span>
|
|
||||||
{POPULAR_TARGETS.map(({ id: tid, name, target: tgt, Icon, color }) => {
|
{POPULAR_TARGETS.map(({ id: tid, name, target: tgt, Icon, color }) => {
|
||||||
const isSelected = target === tgt;
|
const isSelected = target === tgt;
|
||||||
const bgClass = color === 'red' ? 'bg-red-lt' : color === 'blue' ? 'bg-blue-lt' : 'bg-orange-lt';
|
const bgClass = color === 'red' ? 'bg-red-lt' : color === 'blue' ? 'bg-blue-lt' : 'bg-orange-lt';
|
||||||
const textClass = color === 'red' ? 'text-red' : color === 'blue' ? 'text-blue' : 'text-orange';
|
const textClass = color === 'red' ? 'text-red' : color === 'blue' ? 'text-blue' : 'text-orange';
|
||||||
return (
|
return (
|
||||||
<button
|
<div className="col-12 col-sm-6 col-md-4" key={tid}>
|
||||||
type="button"
|
<div
|
||||||
key={tid}
|
className={`card card-sm h-100 cursor-pointer ${isSelected ? 'border-primary card-hover' : 'card-hover'}`}
|
||||||
className={`btn btn-sm ${isSelected ? `${bgClass} ${textClass}` : 'btn-outline-secondary'}`}
|
onClick={() => setTarget(tgt)}
|
||||||
onClick={() => setTarget(tgt)}
|
title={tgt}
|
||||||
title={tgt}
|
>
|
||||||
>
|
<div className="card-body py-2 px-2 d-flex align-items-center gap-2">
|
||||||
<Icon size={14} stroke={1.5} className="me-1" />
|
<span className={`avatar avatar-sm ${bgClass} ${textClass}`}>
|
||||||
{name}
|
<Icon size={20} stroke={1.5} />
|
||||||
</button>
|
</span>
|
||||||
|
<div className="flex-grow-1 min-w-0">
|
||||||
|
<div className="fw-semibold text-truncate small">{name}</div>
|
||||||
|
<div className="text-muted small text-truncate">{tgt}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user