mirror of
https://github.com/TronoSfera/Law.git
synced 2026-05-18 10:03:45 +03:00
fix ui data 2
This commit is contained in:
parent
cd3bcf29c2
commit
a9704d77b0
3 changed files with 167 additions and 33 deletions
|
|
@ -275,6 +275,25 @@
|
||||||
flex-wrap: wrap;
|
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 {
|
.muted {
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
margin: 0.45rem 0 0;
|
margin: 0.45rem 0 0;
|
||||||
|
|
@ -1229,18 +1248,56 @@
|
||||||
background: transparent;
|
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 {
|
.config-panel-flat .config-content .table-wrap table {
|
||||||
min-width: 640px;
|
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 {
|
.block {
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -2918,6 +2975,13 @@
|
||||||
.filter-action {
|
.filter-action {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
.config-controls-summary {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.config-controls-actions {
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
.topbar {
|
.topbar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
return (
|
||||||
<div className="filter-toolbar">
|
<div className="filter-toolbar">
|
||||||
<div className="filter-chips">
|
<div className="filter-chips">
|
||||||
|
|
@ -190,11 +190,13 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
|
||||||
<span className="chip-placeholder">Фильтры не заданы</span>
|
<span className="chip-placeholder">Фильтры не заданы</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="filter-action">
|
{!hideAction ? (
|
||||||
<button className="btn secondary" type="button" onClick={onOpen}>
|
<div className="filter-action">
|
||||||
Фильтр
|
<button className="btn secondary" type="button" onClick={onOpen}>
|
||||||
</button>
|
Фильтр
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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";
|
import { boolLabel, fmtDate, listPreview, normalizeReferenceMeta, roleLabel, statusKindLabel, statusLabel } from "../../shared/utils.js";
|
||||||
|
|
||||||
function fmtBalance(value) {
|
function fmtBalance(value) {
|
||||||
|
|
@ -57,7 +57,6 @@ export function ConfigSection(props) {
|
||||||
loadAllRows,
|
loadAllRows,
|
||||||
FilterToolbarComponent,
|
FilterToolbarComponent,
|
||||||
DataTableComponent,
|
DataTableComponent,
|
||||||
TablePagerComponent,
|
|
||||||
StatusLineComponent,
|
StatusLineComponent,
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
UserAvatarComponent,
|
UserAvatarComponent,
|
||||||
|
|
@ -65,10 +64,24 @@ export function ConfigSection(props) {
|
||||||
|
|
||||||
const FilterToolbar = FilterToolbarComponent;
|
const FilterToolbar = FilterToolbarComponent;
|
||||||
const DataTable = DataTableComponent;
|
const DataTable = DataTableComponent;
|
||||||
const TablePager = TablePagerComponent;
|
|
||||||
const StatusLine = StatusLineComponent;
|
const StatusLine = StatusLineComponent;
|
||||||
const IconButton = IconButtonComponent;
|
const IconButton = IconButtonComponent;
|
||||||
const UserAvatar = UserAvatarComponent;
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -83,32 +96,33 @@ export function ConfigSection(props) {
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap" }}>
|
<div className="config-head-actions">
|
||||||
{configActiveKey === "otp_sessions" ? (
|
{configActiveKey === "otp_sessions" ? (
|
||||||
<button className="btn secondary" type="button" onClick={onRefreshSmsProviderHealth}>
|
<button className="btn secondary" type="button" onClick={onRefreshSmsProviderHealth}>
|
||||||
Баланс
|
Баланс
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : 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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="config-layout">
|
<div className="config-layout">
|
||||||
<div className="config-panel config-panel-flat">
|
<div className="config-panel config-panel-flat">
|
||||||
<div className="config-content">
|
<div className="config-content">
|
||||||
{canCreateInConfig && configActiveKey ? (
|
|
||||||
<div className="config-actions-row">
|
|
||||||
<button className="btn" type="button" onClick={() => openCreateRecordModal(configActiveKey)}>
|
|
||||||
Добавить
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<FilterToolbar
|
<FilterToolbar
|
||||||
filters={activeConfigTableState.filters}
|
filters={activeConfigTableState.filters}
|
||||||
onOpen={() => openFilterModal(configActiveKey)}
|
onOpen={() => openFilterModal(configActiveKey)}
|
||||||
onRemove={(index) => removeFilterChip(configActiveKey, index)}
|
onRemove={(index) => removeFilterChip(configActiveKey, index)}
|
||||||
onEdit={(index) => openFilterEditModal(configActiveKey, index)}
|
onEdit={(index) => openFilterEditModal(configActiveKey, index)}
|
||||||
|
hideAction
|
||||||
getChipLabel={(clause) => {
|
getChipLabel={(clause) => {
|
||||||
const fieldDef = getFieldDef(configActiveKey, clause.field);
|
const fieldDef = getFieldDef(configActiveKey, clause.field);
|
||||||
return (
|
return (
|
||||||
|
|
@ -584,12 +598,66 @@ export function ConfigSection(props) {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<TablePager
|
<div className="pager table-footer-bar config-controls-bar">
|
||||||
tableState={activeConfigTableState}
|
<div className="config-controls-summary">
|
||||||
onPrev={() => loadPrevPage(configActiveKey)}
|
{activeConfigTableState.showAll
|
||||||
onNext={() => loadNextPage(configActiveKey)}
|
? "Всего: " + activeConfigTableState.total + " • показаны все записи"
|
||||||
onLoadAll={() => loadAllRows(configActiveKey)}
|
: "Всего: " + 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)} />
|
<StatusLine status={getStatus(configActiveKey)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue