feat: история согласования по кнопке в строке таблиц заявок

В каждой строке таблиц заявок — кнопка «История согласования»: окно с
той же лентой, что в карточке, без открытия самой заявки. Колонка
действий теперь есть всегда (история у всех строк, корзина — у своих
черновиков).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-09-29 12:42:42 +05:00
parent 153c966f0b
commit ab3593c170
3 changed files with 82 additions and 12 deletions
@@ -29,6 +29,7 @@ import { useRoutedQuery } from '../../shared/usePersistedQuery';
import { IPage, pageKey, pageSignature, readPage, writePage } from './pageCache';
import { Pager } from './Pager';
import { RequestsFilterBar } from './RequestsFilterBar';
import { RequestHistoryDialog } from './RequestHistoryDialog';
import { SortableHeader } from './SortableHeader';
import { filterRows, hasActiveFilters, ISortState, SortKey, sortRows } from './requestsTableFilters';
import { useTableRefinement } from './useTableRefinement';
@@ -237,9 +238,11 @@ const Table: React.FC<{
sort: ISortState;
onSort: (key: SortKey) => void;
onOpen: (request: IMyRequest) => void;
/** Показать историю согласования заявки (окно, без открытия заявки). */
onShowHistory: (request: IMyRequest) => void;
/** Удалить черновик; задан только там, где в таблице бывают свои черновики. */
onDelete?: (request: IMyRequest) => void;
}> = ({ rows, view, statusFilter, sort, onSort, onOpen, onDelete }) => {
}> = ({ rows, view, statusFilter, sort, onSort, onOpen, onShowHistory, onDelete }) => {
const cols = columnsFor(view, statusFilter);
const sortable = (label: string, key: SortKey): React.ReactNode => (
<SortableHeader label={label} sortKey={key} sort={sort} onSort={onSort} />
@@ -297,27 +300,41 @@ const Table: React.FC<{
render: (r) => r.decisionComment || <span className={styles.commentEmpty}>Без комментария</span>
});
}
if (onDelete && rows.some(canDeleteRow)) {
columns.push({
key: 'actions',
title: '',
width: '56px',
render: (r) =>
canDeleteRow(r) ? (
// Действия строки: история согласования — у всех, корзина — только у своих
// черновиков. Клик по всей строке открывает заявку — кнопкам это не нужно,
// поэтому stopPropagation.
const hasDeletable = !!onDelete && rows.some(canDeleteRow);
columns.push({
key: 'actions',
title: '',
// Место под одну или две иконки-кнопки (sm) с зазором.
width: hasDeletable ? '92px' : '56px',
render: (r) => (
<div className={styles.rowActions}>
<IconButton
icon="calendar"
title="История согласования"
size="sm"
onClick={(e) => {
e.stopPropagation();
onShowHistory(r);
}}
/>
{onDelete && canDeleteRow(r) && (
<IconButton
icon="trash"
title="Удалить черновик"
danger
size="sm"
onClick={(e) => {
// Клик по всей строке открывает заявку — кнопке это не нужно.
e.stopPropagation();
onDelete(r);
}}
/>
) : null
});
}
)}
</div>
)
});
return (
<div className={styles.tableWrap}>
@@ -379,6 +396,8 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
const [totalRows, setTotalRows] = React.useState<number>(0);
const [error, setError] = React.useState<string>('');
const [deleteError, setDeleteError] = React.useState<string>('');
// Заявка, чья история согласования открыта в окне; undefined — окно закрыто.
const [historyFor, setHistoryFor] = React.useState<IMyRequest | undefined>(undefined);
// Список перечитается сам: confirmAndDeleteDraft шлёт rp-requests-changed.
const handleDelete = (request: IMyRequest): void => {
@@ -729,11 +748,13 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
sort={sort}
onSort={refinement.onSort}
onOpen={onOpen}
onShowHistory={setHistoryFor}
onDelete={view === 'own:created' ? handleDelete : undefined}
/>
<Pager page={page} totalPages={totalPages} onChange={onPageChange} />
</>
)}
<RequestHistoryDialog request={historyFor} onClose={() => setHistoryFor(undefined)} />
</section>
);
};