refactor: Update Mikrotik config validation logic to improve brace counting accuracy and enhance AutoUrlManager UI with consistent card layouts, larger icons, and refined button styles for better user experience.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m50s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m50s
This commit is contained in:
@@ -39,8 +39,11 @@ function validateMikrotikConfig(config) {
|
|||||||
inBlock = true;
|
inBlock = true;
|
||||||
blockName = line.match(/^\/\w+(\s+\w+)*/)?.[0] || '';
|
blockName = line.match(/^\/\w+(\s+\w+)*/)?.[0] || '';
|
||||||
currentBlockLine = lineNum;
|
currentBlockLine = lineNum;
|
||||||
braceBalance++;
|
// Считаем скобки только один раз для этой строки (чтобы не дублировать подсчёт ниже)
|
||||||
continue;
|
const openBraces = (line.match(/\{/g) || []).length;
|
||||||
|
const closeBraces = (line.match(/\}/g) || []).length;
|
||||||
|
braceBalance += openBraces - closeBraces;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Подсчет фигурных скобок
|
// Подсчет фигурных скобок
|
||||||
|
|||||||
@@ -385,69 +385,53 @@ function AutoUrlManager() {
|
|||||||
{!loading && urls.length > 0 && (
|
{!loading && urls.length > 0 && (
|
||||||
<div className="row g-3 mb-4">
|
<div className="row g-3 mb-4">
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<div className="card card-sm">
|
<div className="card h-100">
|
||||||
<div className="card-body">
|
<div className="card-body d-flex align-items-center">
|
||||||
<div className="row align-items-center">
|
<span className="avatar avatar-lg me-3 bg-blue-lt text-blue border-0">
|
||||||
<div className="col-auto">
|
<IconWorld size={32} />
|
||||||
<span className="avatar avatar-lg bg-blue-lt text-blue">
|
</span>
|
||||||
<IconWorld size={24} />
|
<div>
|
||||||
</span>
|
<div className="h3 mb-0 fw-bold">{stats.total}</div>
|
||||||
</div>
|
<div className="text-muted small">Всего URL</div>
|
||||||
<div className="col">
|
|
||||||
<div className="font-weight-medium">{stats.total}</div>
|
|
||||||
<div className="text-muted small">Всего URL</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<div className="card card-sm">
|
<div className="card h-100">
|
||||||
<div className="card-body">
|
<div className="card-body d-flex align-items-center">
|
||||||
<div className="row align-items-center">
|
<span className="avatar avatar-lg me-3 bg-green-lt text-green border-0">
|
||||||
<div className="col-auto">
|
<IconCheck size={32} />
|
||||||
<span className="avatar avatar-lg bg-green-lt text-green">
|
</span>
|
||||||
<IconCheck size={24} />
|
<div>
|
||||||
</span>
|
<div className="h3 mb-0 fw-bold">{stats.valid}</div>
|
||||||
</div>
|
<div className="text-muted small">Валидных</div>
|
||||||
<div className="col">
|
|
||||||
<div className="font-weight-medium">{stats.valid}</div>
|
|
||||||
<div className="text-muted small">Валидных</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<div className="card card-sm">
|
<div className="card h-100">
|
||||||
<div className="card-body">
|
<div className="card-body d-flex align-items-center">
|
||||||
<div className="row align-items-center">
|
<span className="avatar avatar-lg me-3 bg-red-lt text-red border-0">
|
||||||
<div className="col-auto">
|
<IconAlertCircle size={32} />
|
||||||
<span className="avatar avatar-lg bg-red-lt text-red">
|
</span>
|
||||||
<IconAlertCircle size={24} />
|
<div>
|
||||||
</span>
|
<div className="h3 mb-0 fw-bold">{stats.invalid}</div>
|
||||||
</div>
|
<div className="text-muted small">Невалидных</div>
|
||||||
<div className="col">
|
|
||||||
<div className="font-weight-medium">{stats.invalid}</div>
|
|
||||||
<div className="text-muted small">Невалидных</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-3">
|
<div className="col-md-3">
|
||||||
<div className="card card-sm">
|
<div className="card h-100">
|
||||||
<div className="card-body">
|
<div className="card-body d-flex align-items-center">
|
||||||
<div className="row align-items-center">
|
<span className="avatar avatar-lg me-3 bg-azure-lt text-azure border-0">
|
||||||
<div className="col-auto">
|
<IconLink size={32} />
|
||||||
<span className="avatar avatar-lg bg-orange-lt text-orange">
|
</span>
|
||||||
<IconLink size={24} />
|
<div>
|
||||||
</span>
|
<div className="h3 mb-0 fw-bold">{filteredAndSortedUrls.length}</div>
|
||||||
</div>
|
<div className="text-muted small">Отображается</div>
|
||||||
<div className="col">
|
|
||||||
<div className="font-weight-medium">{filteredAndSortedUrls.length}</div>
|
|
||||||
<div className="text-muted small">Отображается</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -465,8 +449,8 @@ function AutoUrlManager() {
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div className="col-auto">
|
||||||
<div className="input-group" style={{ maxWidth: 300 }}>
|
<div className="input-icon" style={{ maxWidth: 320 }}>
|
||||||
<span className="input-group-text">
|
<span className="input-icon-addon">
|
||||||
<IconSearch size={16} />
|
<IconSearch size={16} />
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
@@ -479,7 +463,7 @@ function AutoUrlManager() {
|
|||||||
/>
|
/>
|
||||||
{searchTerm && (
|
{searchTerm && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-outline-secondary"
|
className="btn btn-icon btn-sm btn-outline-secondary position-absolute top-50 end-0 translate-middle-y me-1"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setSearchTerm('')}
|
onClick={() => setSearchTerm('')}
|
||||||
title="Очистить поиск"
|
title="Очистить поиск"
|
||||||
@@ -490,16 +474,16 @@ function AutoUrlManager() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-auto">
|
<div className="col-auto">
|
||||||
<div className="btn-group">
|
<div className="btn-group btn-group-sm">
|
||||||
<button
|
<button
|
||||||
className={`btn btn-sm ${filterValid === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`}
|
className={`btn ${filterValid === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`}
|
||||||
onClick={() => setFilterValid('all')}
|
onClick={() => setFilterValid('all')}
|
||||||
title="Все записи"
|
title="Все записи"
|
||||||
>
|
>
|
||||||
Все
|
Все
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`btn btn-sm ${filterValid === 'valid' ? 'btn-success' : 'btn-outline-success'}`}
|
className={`btn ${filterValid === 'valid' ? 'btn-success' : 'btn-outline-success'}`}
|
||||||
onClick={() => setFilterValid('valid')}
|
onClick={() => setFilterValid('valid')}
|
||||||
title="Только валидные"
|
title="Только валидные"
|
||||||
>
|
>
|
||||||
@@ -507,7 +491,7 @@ function AutoUrlManager() {
|
|||||||
Валидные
|
Валидные
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`btn btn-sm ${filterValid === 'invalid' ? 'btn-danger' : 'btn-outline-danger'}`}
|
className={`btn ${filterValid === 'invalid' ? 'btn-danger' : 'btn-outline-danger'}`}
|
||||||
onClick={() => setFilterValid('invalid')}
|
onClick={() => setFilterValid('invalid')}
|
||||||
title="Только невалидные"
|
title="Только невалидные"
|
||||||
>
|
>
|
||||||
@@ -647,7 +631,7 @@ function AutoUrlManager() {
|
|||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={originalIndex}
|
key={originalIndex}
|
||||||
className={`${isSelected ? 'table-active' : ''} ${isInvalid ? 'table-danger' : isValid ? 'table-success' : ''}`}
|
className={isSelected ? 'table-active' : ''}
|
||||||
>
|
>
|
||||||
<td>
|
<td>
|
||||||
<input
|
<input
|
||||||
|
|||||||
Reference in New Issue
Block a user