feat: Implement community badge rendering and enhance community suggestions in ASNs, Domains, and IPRanges managers for improved user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m9s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m9s
This commit is contained in:
@@ -48,6 +48,18 @@ function ASNsNewManager() {
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const renderCommunityBadge = (value) => {
|
||||
const v = String(value ?? '').trim();
|
||||
if (!v) return <span className="badge bg-blue-lt text-blue">—</span>;
|
||||
const meta = communities.find(c => c.value === v);
|
||||
const color = (meta?.color || 'blue').toLowerCase().replace(/[^a-z-]/g, '');
|
||||
const cls = `badge bg-${color}-lt text-${color}`;
|
||||
const title = meta ? `${meta.name ? meta.name + ' — ' : ''}${meta.description || ''}${meta.tags && meta.tags.length ? ' (' + meta.tags.join(', ') + ')' : ''}` : '';
|
||||
return (
|
||||
<span className={cls} title={title}>{v}</span>
|
||||
);
|
||||
};
|
||||
|
||||
const isValidAsn = (value) => /^[0-9]+$/.test(String(value).trim());
|
||||
// Допускаем как числовые, так и строковые (AS:NNN) community
|
||||
const isValidCommunity = (value) => /^(\d+|\d+:\d+)$/.test(String(value).trim());
|
||||
@@ -423,7 +435,7 @@ function ASNsNewManager() {
|
||||
{paginatedItems.map((item) => (
|
||||
<tr key={item.asn} className={editingAsn === item.asn ? 'table-info' : ''}>
|
||||
<td>{item.asn}</td>
|
||||
<td><span className="badge bg-blue-lt text-blue">{item.community}</span></td>
|
||||
<td>{renderCommunityBadge(item.community)}</td>
|
||||
<td className="text-end">
|
||||
{editingAsn === item.asn ? (
|
||||
<>
|
||||
@@ -543,9 +555,12 @@ function ASNsNewManager() {
|
||||
)}
|
||||
{/* Общий список подсказок community */}
|
||||
<datalist id="community-options">
|
||||
{communities.map(c => (
|
||||
<option key={c.value} value={c.value}>{c.name ? `${c.name} — ${c.value}` : c.value}</option>
|
||||
))}
|
||||
{communities.map(c => {
|
||||
const label = `${c.name ? c.name + ' — ' : ''}${c.value}${c.description ? ' — ' + c.description : ''}${c.tags && c.tags.length ? ' (' + c.tags.join(', ') + ')' : ''}`;
|
||||
return (
|
||||
<option key={c.value} value={c.value} label={label}>{label}</option>
|
||||
);
|
||||
})}
|
||||
</datalist>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -48,6 +48,18 @@ function DomainsNewManager() {
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const renderCommunityBadge = (value) => {
|
||||
const v = String(value ?? '').trim();
|
||||
if (!v) return <span className="badge bg-blue-lt text-blue">—</span>;
|
||||
const meta = communities.find(c => c.value === v);
|
||||
const color = (meta?.color || 'blue').toLowerCase().replace(/[^a-z-]/g, '');
|
||||
const cls = `badge bg-${color}-lt text-${color}`;
|
||||
const title = meta ? `${meta.name ? meta.name + ' — ' : ''}${meta.description || ''}${meta.tags && meta.tags.length ? ' (' + meta.tags.join(', ') + ')' : ''}` : '';
|
||||
return (
|
||||
<span className={cls} title={title}>{v}</span>
|
||||
);
|
||||
};
|
||||
|
||||
const isValidDomain = (value) => {
|
||||
const v = String(value).trim().toLowerCase();
|
||||
// Простой валидатор FQDN: sub.domain.tld
|
||||
@@ -429,7 +441,7 @@ function DomainsNewManager() {
|
||||
{paginatedItems.map((item) => (
|
||||
<tr key={item.domain} className={editingDomain === item.domain ? 'table-info' : ''}>
|
||||
<td>{item.domain}</td>
|
||||
<td><span className="badge bg-blue-lt text-blue">{item.community}</span></td>
|
||||
<td>{renderCommunityBadge(item.community)}</td>
|
||||
<td className="text-end">
|
||||
{editingDomain === item.domain ? (
|
||||
<>
|
||||
@@ -549,9 +561,12 @@ function DomainsNewManager() {
|
||||
)}
|
||||
{/* Общий список подсказок community */}
|
||||
<datalist id="community-options">
|
||||
{communities.map(c => (
|
||||
<option key={c.value} value={c.value}>{c.name ? `${c.name} — ${c.value}` : c.value}</option>
|
||||
))}
|
||||
{communities.map(c => {
|
||||
const label = `${c.name ? c.name + ' — ' : ''}${c.value}${c.description ? ' — ' + c.description : ''}${c.tags && c.tags.length ? ' (' + c.tags.join(', ') + ')' : ''}`;
|
||||
return (
|
||||
<option key={c.value} value={c.value} label={label}>{label}</option>
|
||||
);
|
||||
})}
|
||||
</datalist>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -48,6 +48,18 @@ function IPRangesManager() {
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const renderCommunityBadge = (value) => {
|
||||
const v = String(value ?? '').trim();
|
||||
if (!v) return <span className="badge bg-blue-lt text-blue">—</span>;
|
||||
const meta = communities.find(c => c.value === v);
|
||||
const color = (meta?.color || 'blue').toLowerCase().replace(/[^a-z-]/g, '');
|
||||
const cls = `badge bg-${color}-lt text-${color}`;
|
||||
const title = meta ? `${meta.name ? meta.name + ' — ' : ''}${meta.description || ''}${meta.tags && meta.tags.length ? ' (' + meta.tags.join(', ') + ')' : ''}` : '';
|
||||
return (
|
||||
<span className={cls} title={title}>{v}</span>
|
||||
);
|
||||
};
|
||||
|
||||
const isValidIPv4 = (ip) => {
|
||||
const octets = ip.split('.');
|
||||
if (octets.length !== 4) return false;
|
||||
@@ -438,7 +450,7 @@ function IPRangesManager() {
|
||||
{paginatedItems.map((item) => (
|
||||
<tr key={item.ipRange} className={editingIp === item.ipRange ? 'table-info' : ''}>
|
||||
<td>{item.ipRange}</td>
|
||||
<td><span className="badge bg-blue-lt text-blue">{item.community}</span></td>
|
||||
<td>{renderCommunityBadge(item.community)}</td>
|
||||
<td className="text-end">
|
||||
{editingIp === item.ipRange ? (
|
||||
<>
|
||||
@@ -563,9 +575,12 @@ function IPRangesManager() {
|
||||
)}
|
||||
{/* Общий список подсказок community */}
|
||||
<datalist id="community-options">
|
||||
{communities.map(c => (
|
||||
<option key={c.value} value={c.value}>{c.name ? `${c.name} — ${c.value}` : c.value}</option>
|
||||
))}
|
||||
{communities.map(c => {
|
||||
const label = `${c.name ? c.name + ' — ' : ''}${c.value}${c.description ? ' — ' + c.description : ''}${c.tags && c.tags.length ? ' (' + c.tags.join(', ') + ')' : ''}`;
|
||||
return (
|
||||
<option key={c.value} value={c.value} label={label}>{label}</option>
|
||||
);
|
||||
})}
|
||||
</datalist>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user