fix ui data 2

This commit is contained in:
TronoSfera 2026-03-02 20:09:00 +03:00
parent cd3bcf29c2
commit a9704d77b0
3 changed files with 167 additions and 33 deletions

View file

@ -275,6 +275,25 @@
flex-wrap: wrap;
}
.config-head-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
align-items: center;
}
.btn-icon-only {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
padding: 0;
display: inline-grid;
place-items: center;
font-size: 1.06rem;
line-height: 1;
}
.muted {
color: var(--muted);
margin: 0.45rem 0 0;
@ -1229,18 +1248,56 @@
background: transparent;
}
.config-actions-row {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
}
.config-panel-flat .config-content .table-wrap table {
min-width: 640px;
}
.config-controls-bar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.6rem;
flex-wrap: wrap;
}
.config-controls-summary {
color: var(--muted);
font-size: 0.86rem;
}
.config-controls-actions {
display: inline-flex;
align-items: center;
gap: 0.45rem;
flex-wrap: wrap;
margin-left: auto;
}
.config-control-btn {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
padding: 0;
display: inline-grid;
place-items: center;
font-size: 1.05rem;
line-height: 1;
}
.config-control-btn-loadall {
width: auto;
min-width: 58px;
padding: 0 0.62rem;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.33rem;
font-size: 0.9rem;
font-weight: 700;
letter-spacing: 0.01em;
}
.block {
border: 1px solid var(--line);
border-radius: 12px;
@ -2918,6 +2975,13 @@
.filter-action {
margin-left: 0;
}
.config-controls-summary {
width: 100%;
}
.config-controls-actions {
width: 100%;
margin-left: 0;
}
.topbar {
flex-direction: column;
align-items: flex-start;

View file

@ -153,7 +153,7 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
);
}
function FilterToolbar({ filters, onOpen, onRemove, onEdit, getChipLabel }) {
function FilterToolbar({ filters, onOpen, onRemove, onEdit, getChipLabel, hideAction = false }) {
return (
<div className="filter-toolbar">
<div className="filter-chips">
@ -190,11 +190,13 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
<span className="chip-placeholder">Фильтры не заданы</span>
)}
</div>
{!hideAction ? (
<div className="filter-action">
<button className="btn secondary" type="button" onClick={onOpen}>
Фильтр
</button>
</div>
) : null}
</div>
);
}

View file

@ -1,4 +1,4 @@
import { KNOWN_CONFIG_TABLE_KEYS, OPERATOR_LABELS, TABLE_SERVER_CONFIG } from "../../shared/constants.js";
import { KNOWN_CONFIG_TABLE_KEYS, OPERATOR_LABELS, PAGE_SIZE, TABLE_SERVER_CONFIG } from "../../shared/constants.js";
import { boolLabel, fmtDate, listPreview, normalizeReferenceMeta, roleLabel, statusKindLabel, statusLabel } from "../../shared/utils.js";
function fmtBalance(value) {
@ -57,7 +57,6 @@ export function ConfigSection(props) {
loadAllRows,
FilterToolbarComponent,
DataTableComponent,
TablePagerComponent,
StatusLineComponent,
IconButtonComponent,
UserAvatarComponent,
@ -65,10 +64,24 @@ export function ConfigSection(props) {
const FilterToolbar = FilterToolbarComponent;
const DataTable = DataTableComponent;
const TablePager = TablePagerComponent;
const StatusLine = StatusLineComponent;
const IconButton = IconButtonComponent;
const UserAvatar = UserAvatarComponent;
const canOpenFilter = Boolean(configActiveKey);
const canRefresh = Boolean(configActiveKey);
const canCreateRecord = Boolean(canCreateInConfig && configActiveKey);
const canLoadAllRows = Boolean(
configActiveKey &&
activeConfigTableState.total > 0 &&
!activeConfigTableState.showAll &&
activeConfigTableState.rows.length < activeConfigTableState.total
);
const canLoadPrev = Boolean(configActiveKey && !activeConfigTableState.showAll && activeConfigTableState.offset > 0);
const canLoadNext = Boolean(
configActiveKey &&
!activeConfigTableState.showAll &&
activeConfigTableState.offset + PAGE_SIZE < activeConfigTableState.total
);
return (
<>
@ -83,32 +96,33 @@ export function ConfigSection(props) {
</p>
) : null}
</div>
<div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap" }}>
<div className="config-head-actions">
{configActiveKey === "otp_sessions" ? (
<button className="btn secondary" type="button" onClick={onRefreshSmsProviderHealth}>
Баланс
</button>
) : null}
<button className="btn secondary" type="button" onClick={() => loadCurrentConfigTable(true)}>
Обновить
<button
className="btn secondary btn-icon-only"
type="button"
onClick={() => openFilterModal(configActiveKey)}
disabled={!canOpenFilter}
title="Фильтр"
aria-label="Фильтр"
>
</button>
</div>
</div>
<div className="config-layout">
<div className="config-panel config-panel-flat">
<div className="config-content">
{canCreateInConfig && configActiveKey ? (
<div className="config-actions-row">
<button className="btn" type="button" onClick={() => openCreateRecordModal(configActiveKey)}>
Добавить
</button>
</div>
) : null}
<FilterToolbar
filters={activeConfigTableState.filters}
onOpen={() => openFilterModal(configActiveKey)}
onRemove={(index) => removeFilterChip(configActiveKey, index)}
onEdit={(index) => openFilterEditModal(configActiveKey, index)}
hideAction
getChipLabel={(clause) => {
const fieldDef = getFieldDef(configActiveKey, clause.field);
return (
@ -584,12 +598,66 @@ export function ConfigSection(props) {
)}
/>
) : null}
<TablePager
tableState={activeConfigTableState}
onPrev={() => loadPrevPage(configActiveKey)}
onNext={() => loadNextPage(configActiveKey)}
onLoadAll={() => loadAllRows(configActiveKey)}
/>
<div className="pager table-footer-bar config-controls-bar">
<div className="config-controls-summary">
{activeConfigTableState.showAll
? "Всего: " + activeConfigTableState.total + " • показаны все записи"
: "Всего: " + activeConfigTableState.total + " • смещение: " + activeConfigTableState.offset}
</div>
<div className="config-controls-actions">
<button
className="btn secondary config-control-btn config-control-btn-loadall"
type="button"
onClick={() => loadAllRows(configActiveKey)}
disabled={!canLoadAllRows}
title={"Загрузить все " + activeConfigTableState.total}
aria-label={"Загрузить все " + activeConfigTableState.total}
>
<span aria-hidden="true"></span>
<span>{activeConfigTableState.total}</span>
</button>
<button
className="btn secondary btn-icon-only config-control-btn"
type="button"
onClick={() => loadCurrentConfigTable(true)}
disabled={!canRefresh}
title="Обновить"
aria-label="Обновить"
>
</button>
<button
className="btn secondary btn-icon-only config-control-btn"
type="button"
onClick={() => openCreateRecordModal(configActiveKey)}
disabled={!canCreateRecord}
title="Добавить"
aria-label="Добавить"
>
+
</button>
<button
className="btn secondary btn-icon-only config-control-btn"
type="button"
onClick={() => loadPrevPage(configActiveKey)}
disabled={!canLoadPrev}
title="Назад"
aria-label="Назад"
>
</button>
<button
className="btn secondary btn-icon-only config-control-btn"
type="button"
onClick={() => loadNextPage(configActiveKey)}
disabled={!canLoadNext}
title="Вперед"
aria-label="Вперед"
>
</button>
</div>
</div>
<StatusLine status={getStatus(configActiveKey)} />
</div>
</div>