Feature/request type access all requests (#22)
Tests / frontend-test (push) Successful in 1m24s
Tests / frontend-test (push) Successful in 1m24s
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/22
This commit was merged in pull request #22.
This commit is contained in:
@@ -3,6 +3,7 @@ import type { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import {
|
||||
ApprovalQueueKind,
|
||||
filterPendingByQuery,
|
||||
getAllRequestsForType,
|
||||
getApprovalQueue,
|
||||
getApprovalQueueIndex,
|
||||
getLinkedTypes,
|
||||
@@ -50,7 +51,8 @@ export type ListView =
|
||||
| 'own:created'
|
||||
| 'own:approved'
|
||||
| 'own:rejected'
|
||||
| 'own:executed';
|
||||
| 'own:executed'
|
||||
| 'all';
|
||||
|
||||
// Представления, которые строятся на строках маршрута пользователя, и их очередь
|
||||
// в сервисе. Всё, чего здесь нет ('rework'/'own:created'), читается из списка
|
||||
@@ -63,6 +65,9 @@ const QUEUE_BY_VIEW: { [key: string]: ApprovalQueueKind } = {
|
||||
'own:executed': 'executed',
|
||||
};
|
||||
|
||||
// 'all' — заголовок и текст пустоты зависят от выбранного типа заявки
|
||||
// (см. allRequestsType и heading/emptyText ниже), здесь только запасной
|
||||
// вариант на случай, пока тип ещё не выбран/не загрузился.
|
||||
const HEADINGS: Record<ListView, string> = {
|
||||
approvals: 'Ждут вашего согласования',
|
||||
execution: 'Ждут вашего исполнения',
|
||||
@@ -71,6 +76,7 @@ const HEADINGS: Record<ListView, string> = {
|
||||
'own:approved': 'Согласованные мной',
|
||||
'own:rejected': 'Отклонённые мной',
|
||||
'own:executed': 'Выполненные мной',
|
||||
all: 'Все заявки',
|
||||
};
|
||||
|
||||
const EMPTY_TEXTS: Record<ListView, string> = {
|
||||
@@ -81,6 +87,7 @@ const EMPTY_TEXTS: Record<ListView, string> = {
|
||||
'own:approved': 'Вы ещё ничего не согласовали.',
|
||||
'own:rejected': 'Вы ещё ничего не отклоняли.',
|
||||
'own:executed': 'Вы ещё ничего не выполнили.',
|
||||
all: 'Заявок этого типа пока нет.',
|
||||
};
|
||||
|
||||
// Цвет пункта в выпадающем списке фильтра — то же сопоставление статус→цвет,
|
||||
@@ -157,6 +164,8 @@ function columnsFor(view: ListView, statusFilter: string): ITableColumns {
|
||||
if (view === 'approvals' || view === 'execution') return { author: true, status: false };
|
||||
if (view === 'rework') return { author: false, status: false, commentLabel };
|
||||
if (view === 'own:created') return { author: false, status: !statusFilter, commentLabel };
|
||||
// 'all' — заявки всех авторов вперемешку, поэтому нужны и автор, и статус.
|
||||
if (view === 'all') return { author: true, status: true };
|
||||
// История решений: заявка чужая, поэтому нужен автор. Статус — только если он
|
||||
// не предопределён самой вкладкой («Отклонённые мной» — это всегда «Отклонено»,
|
||||
// а вот у согласованных/выполненных заявка могла уйти дальше по маршруту).
|
||||
@@ -185,6 +194,8 @@ export interface IRequestsTableViewProps {
|
||||
onQueryChange: (query: string) => void;
|
||||
/** Клик по строке — открыть заявку (в выезжающей панели). */
|
||||
onOpen: (request: IMyRequest) => void;
|
||||
/** Только при view='all' — тип заявки, чьи заявки показываются целиком (без фильтра по автору). */
|
||||
allRequestsType?: IRequestType;
|
||||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
@@ -330,6 +341,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
query,
|
||||
onQueryChange,
|
||||
onOpen,
|
||||
allRequestsType,
|
||||
}) => {
|
||||
const [types, setTypes] = React.useState<IRequestType[] | undefined>(undefined);
|
||||
const [rows, setRows] = React.useState<IMyRequest[] | undefined>(undefined);
|
||||
@@ -361,7 +373,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
// по чужому totalRows и сбивал страницу на первую — из-за чего запомненная
|
||||
// страница затиралась при каждом переходе по левому меню.
|
||||
// Страница в ключ НЕ входит: totalRows один на всю таблицу, а не на страницу.
|
||||
const dataKey = `${view}|${statusFilter}|${debouncedQuery.trim()}`;
|
||||
const dataKey = `${view}|${statusFilter}|${debouncedQuery.trim()}|${allRequestsType?.id ?? ''}`;
|
||||
const [loadedKey, setLoadedKey] = React.useState<string>('');
|
||||
|
||||
// Страницу при смене запроса здесь НЕ сбрасываем: и запрос, и страница живут
|
||||
@@ -384,7 +396,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
React.useEffect(() => {
|
||||
if (types === undefined) return;
|
||||
let cancelled = false;
|
||||
const cacheKey = pageKey('table', [view, statusFilter, debouncedQuery.trim(), page]);
|
||||
const cacheKey = pageKey('table', [view, statusFilter, debouncedQuery.trim(), page, allRequestsType?.id ?? 0]);
|
||||
|
||||
// Сразу показываем то, что уже загружали для ЭТОЙ вкладки (и этого запроса
|
||||
// и страницы), а обновление идёт фоном. Компонент один на обе вкладки —
|
||||
@@ -422,6 +434,11 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
: getOwnRequests(context, types, page, onPartial);
|
||||
}
|
||||
|
||||
if (view === 'all') {
|
||||
if (!allRequestsType) return { rows: [], totalRows: 0 };
|
||||
return getAllRequestsForType(context, allRequestsType, page, debouncedQuery);
|
||||
}
|
||||
|
||||
const queue = QUEUE_BY_VIEW[view];
|
||||
if (q.length === 0) {
|
||||
// Без поиска — страница уже нарезана и дочитана сервером.
|
||||
@@ -524,7 +541,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
unsubscribe();
|
||||
window.clearInterval(timer);
|
||||
};
|
||||
}, [context, types, view, statusFilter, debouncedQuery, page, dataKey]);
|
||||
}, [context, types, view, statusFilter, debouncedQuery, page, dataKey, allRequestsType]);
|
||||
|
||||
// Все ветки отдают уже нарезанную страницу — просто показываем как есть.
|
||||
const q = debouncedQuery.trim();
|
||||
@@ -561,7 +578,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
<section className={styles.view}>
|
||||
<div className={styles.head}>
|
||||
<h2 className={styles.heading}>
|
||||
{HEADINGS[view]}
|
||||
{view === 'all' && allRequestsType ? `Все заявки: ${allRequestsType.name}` : HEADINGS[view]}
|
||||
{rows && <span className={styles.count}>{total}</span>}
|
||||
</h2>
|
||||
{view === 'own:created' && onStatusFilterChange && (
|
||||
|
||||
Reference in New Issue
Block a user