refactor(Managers): standardize button group styling and layout across ASNs, Domains, and IPRanges managers for improved UI consistency and user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m50s

This commit is contained in:
2026-02-16 17:42:57 +07:00
parent a80740b802
commit 38ece61b31
3 changed files with 81 additions and 86 deletions
+38 -31
View File
@@ -769,37 +769,44 @@ function ASNsNewManager() {
</td> </td>
<td>{renderCommunityBadge(item.community)}</td> <td>{renderCommunityBadge(item.community)}</td>
<td className="text-end"> <td className="text-end">
{editingAsn === item.asn ? ( <div className="btn-group btn-group-sm" role="group" aria-label={`Действия с ASN ${item.asn}`}>
<> {editingAsn === item.asn ? (
<CommunityAutocompleteInput <>
value={editingValue} <CommunityAutocompleteInput
onChange={setEditingValue} value={editingValue}
communities={communities} onChange={setEditingValue}
onKeyDown={(e) => handleEditKeyDown(e, item.asn)} communities={communities}
className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} onKeyDown={(e) => handleEditKeyDown(e, item.asn)}
style={{ width: '150px' }} className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`}
useShortValue={true} style={{ width: '150px' }}
/> useShortValue={true}
<Tooltip content="Сохранить (Enter)"> />
<button className="btn btn-success btn-icon btn-sm me-1" onClick={() => handleSaveEdit(item.asn)} disabled={!isValidCommunity(editingValue)}><IconCheck size={16} /></button> <Tooltip content="Сохранить (Enter)">
</Tooltip> <button className="btn btn-icon btn-success me-1" onClick={() => handleSaveEdit(item.asn)} disabled={!isValidCommunity(editingValue)} aria-label="Сохранить">
<Tooltip content="Отмена (Esc)"> <IconCheck size={16} />
<button className="btn btn-secondary btn-icon btn-sm" onClick={handleCancelEdit}><IconX size={16} /></button> </button>
</Tooltip> </Tooltip>
</> <Tooltip content="Отмена (Esc)">
) : ( <button className="btn btn-icon btn-secondary" onClick={handleCancelEdit} aria-label="Отмена">
<> <IconX size={16} />
<Tooltip content="Редактировать" position="top"> </button>
<button className="btn btn-outline-primary btn-icon btn-sm me-1" aria-label="Редактировать" onClick={() => handleEdit(item)} title="Редактировать"><IconEdit size={16} /></button> </Tooltip>
</Tooltip> </>
<Tooltip content="Копировать" position="top"> ) : (
<button className="btn btn-outline-secondary btn-icon btn-sm me-1" aria-label="Копировать" onClick={() => copyToClipboard(`${item.asn} ${item.community}`)} title="Копировать"><IconCopy size={16} /></button> <>
</Tooltip> <Tooltip content="Редактировать" position="top">
<Tooltip content="Удалить" position="top"> <button className="btn btn-icon btn-outline-primary me-1" aria-label="Редактировать" onClick={() => handleEdit(item)} title="Редактировать">
<button className="btn btn-outline-danger btn-icon btn-sm" aria-label="Удалить" onClick={() => confirmDelete(item)} title="Удалить"><IconTrash size={16} /></button> <IconEdit size={16} />
</Tooltip> </button>
</> </Tooltip>
)} <Tooltip content="Удалить" position="top">
<button className="btn btn-icon btn-outline-danger" aria-label="Удалить" onClick={() => confirmDelete(item)} title="Удалить">
<IconTrash size={16} />
</button>
</Tooltip>
</>
)}
</div>
</td> </td>
</tr> </tr>
))} ))}
+5 -15
View File
@@ -771,7 +771,7 @@ function DomainsNewManager() {
</div> </div>
</td> </td>
<td className="text-end"> <td className="text-end">
<div className="btn-group"> <div className="btn-group btn-group-sm" role="group" aria-label={`Действия с доменом ${item.domain}`}>
{editingDomain === item.domain ? ( {editingDomain === item.domain ? (
<> <>
<CommunityAutocompleteInput <CommunityAutocompleteInput
@@ -785,7 +785,7 @@ function DomainsNewManager() {
/> />
<Tooltip content="Сохранить (Enter)"> <Tooltip content="Сохранить (Enter)">
<button <button
className="btn btn-success btn-icon btn-sm" className="btn btn-icon btn-success"
onClick={() => handleSaveEdit(item.domain)} onClick={() => handleSaveEdit(item.domain)}
disabled={!isValidCommunity(editingValue)} disabled={!isValidCommunity(editingValue)}
aria-label="Сохранить" aria-label="Сохранить"
@@ -795,7 +795,7 @@ function DomainsNewManager() {
</Tooltip> </Tooltip>
<Tooltip content="Отмена (Esc)"> <Tooltip content="Отмена (Esc)">
<button <button
className="btn btn-secondary btn-icon btn-sm" className="btn btn-icon btn-secondary"
onClick={handleCancelEdit} onClick={handleCancelEdit}
aria-label="Отмена" aria-label="Отмена"
> >
@@ -807,7 +807,7 @@ function DomainsNewManager() {
<> <>
<Tooltip content="Редактировать" position="top"> <Tooltip content="Редактировать" position="top">
<button <button
className="btn btn-outline-primary btn-icon btn-sm" className="btn btn-icon btn-outline-primary"
aria-label="Редактировать" aria-label="Редактировать"
onClick={() => handleEdit(item)} onClick={() => handleEdit(item)}
title="Редактировать" title="Редактировать"
@@ -815,19 +815,9 @@ function DomainsNewManager() {
<IconEdit size={16} /> <IconEdit size={16} />
</button> </button>
</Tooltip> </Tooltip>
<Tooltip content="Копировать" position="top">
<button
className="btn btn-outline-secondary btn-icon btn-sm"
aria-label="Копировать"
onClick={() => copyToClipboard(`${item.domain} ${item.community}`)}
title="Копировать"
>
<IconCopy size={16} />
</button>
</Tooltip>
<Tooltip content="Удалить" position="top"> <Tooltip content="Удалить" position="top">
<button <button
className="btn btn-outline-danger btn-icon btn-sm" className="btn btn-icon btn-outline-danger"
aria-label="Удалить" aria-label="Удалить"
onClick={() => confirmDelete(item)} onClick={() => confirmDelete(item)}
title="Удалить" title="Удалить"
+38 -40
View File
@@ -1005,37 +1005,44 @@ function IPRangesManager() {
</td> </td>
<td>{renderCommunityBadge(item.community)}</td> <td>{renderCommunityBadge(item.community)}</td>
<td className="text-end"> <td className="text-end">
{editingIp === item.ipRange ? ( <div className="btn-group btn-group-sm" role="group" aria-label={`Действия с диапазоном ${item.ipRange}`}>
<> {editingIp === item.ipRange ? (
<CommunityAutocompleteInput <>
value={editingValue} <CommunityAutocompleteInput
onChange={setEditingValue} value={editingValue}
communities={communities} onChange={setEditingValue}
className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} communities={communities}
style={{ width: '150px' }} className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`}
onKeyDown={(e) => handleEditKeyDown(e, item.ipRange)} style={{ width: '150px' }}
useShortValue={true} onKeyDown={(e) => handleEditKeyDown(e, item.ipRange)}
/> useShortValue={true}
<Tooltip content="Сохранить (Enter)"> />
<button className="btn btn-success btn-icon btn-sm me-1" onClick={() => handleSaveEdit(item.ipRange)} disabled={!isValidCommunity(editingValue)}><IconCheck size={16} /></button> <Tooltip content="Сохранить (Enter)">
</Tooltip> <button className="btn btn-icon btn-success" onClick={() => handleSaveEdit(item.ipRange)} disabled={!isValidCommunity(editingValue)} aria-label="Сохранить">
<Tooltip content="Отмена (Esc)"> <IconCheck size={16} />
<button className="btn btn-secondary btn-icon btn-sm" onClick={handleCancelEdit}><IconX size={16} /></button> </button>
</Tooltip> </Tooltip>
</> <Tooltip content="Отмена (Esc)">
) : ( <button className="btn btn-icon btn-secondary" onClick={handleCancelEdit} aria-label="Отмена">
<> <IconX size={16} />
<Tooltip content="Редактировать" position="top"> </button>
<button className="btn btn-outline-primary btn-icon btn-sm me-1" aria-label="Редактировать" onClick={() => handleEdit(item)} title="Редактировать"><IconEdit size={16} /></button> </Tooltip>
</Tooltip> </>
<Tooltip content="Копировать" position="top"> ) : (
<button className="btn btn-outline-secondary btn-icon btn-sm me-1" aria-label="Копировать" onClick={() => copyToClipboard(`${item.ipRange} ${item.community}`)} title="Копировать"><IconCopy size={16} /></button> <>
</Tooltip> <Tooltip content="Редактировать" position="top">
<Tooltip content="Удалить" position="top"> <button className="btn btn-icon btn-outline-primary" aria-label="Редактировать" onClick={() => handleEdit(item)} title="Редактировать">
<button className="btn btn-outline-danger btn-icon btn-sm" aria-label="Удалить" onClick={() => confirmDelete(item)} title="Удалить"><IconTrash size={16} /></button> <IconEdit size={16} />
</Tooltip> </button>
</> </Tooltip>
)} <Tooltip content="Удалить" position="top">
<button className="btn btn-icon btn-outline-danger" aria-label="Удалить" onClick={() => confirmDelete(item)} title="Удалить">
<IconTrash size={16} />
</button>
</Tooltip>
</>
)}
</div>
</td> </td>
</tr> </tr>
))} ))}
@@ -1054,15 +1061,6 @@ function IPRangesManager() {
/> />
</div> </div>
</div> </div>
{/* Пагинация */}
<Pagination
currentPage={currentPage}
totalPages={totalPages}
totalItems={totalItems || filtered.length}
pageSize={pageSize}
onPageChange={setCurrentPage}
/>
<S3MetaBar keys={["ipRanges"]} />
</div> </div>
</div> </div>