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:
@@ -7,11 +7,13 @@ import type { ISidebarItem } from '@tnsu/ui-kit';
|
||||
import { ConfirmHost } from '../shared/ui';
|
||||
import {
|
||||
navigate,
|
||||
persistAllTypeId,
|
||||
persistNav,
|
||||
persistOwnTab,
|
||||
persistOwnStatus,
|
||||
persistPage,
|
||||
persistQuery,
|
||||
storedAllTypeId,
|
||||
storedOwnStatus,
|
||||
storedOwnTab,
|
||||
storedPageFor,
|
||||
@@ -34,11 +36,13 @@ import EditFeature from '../features/edit/EditFeature';
|
||||
import { ListView, RequestsTableView } from '../features/myRequests/RequestsTableView';
|
||||
import { OwnTabs } from '../features/myRequests/OwnTabs';
|
||||
import { SearchView } from '../features/myRequests/SearchView';
|
||||
import { getNavCounts, INavCounts } from '../features/myRequests/myRequests.service';
|
||||
import { getLinkedTypes, getNavCounts, INavCounts } from '../features/myRequests/myRequests.service';
|
||||
import { IMyRequest } from '../features/myRequests/models/IMyRequest';
|
||||
import { isEditableStatus } from '../shared/approval';
|
||||
import { hasReportsAccess } from '../shared/reports/reportsAccess';
|
||||
import { ReportsFeature } from '../features/reports/ReportsFeature';
|
||||
import { AllRequestsFeature } from '../features/myRequests/AllRequestsFeature';
|
||||
import { accessibleAllRequestsTypes } from '../shared/approval';
|
||||
|
||||
// Оболочка портала: тёмное боковое меню (разделы) + основная область.
|
||||
// Логики фич тут нет — файл общий, меняется редко.
|
||||
@@ -102,6 +106,33 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
}
|
||||
}, [route.nav, canSeeReports]);
|
||||
|
||||
// Раздел «Все заявки» — виден только тем, кому в админке approval-route
|
||||
// выдан RequestTypeAccess хотя бы на один тип (см. shared/approval/
|
||||
// requestTypeAccess.ts). undefined — ответ ещё не пришёл.
|
||||
const [canSeeAllRequests, setCanSeeAllRequests] = React.useState<boolean | undefined>(undefined);
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
setCanSeeAllRequests(undefined);
|
||||
getLinkedTypes(context)
|
||||
.then((types) => accessibleAllRequestsTypes(context, types))
|
||||
.then((accessible) => {
|
||||
if (!cancelled) setCanSeeAllRequests(accessible.length > 0);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setCanSeeAllRequests(false);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [context, impersonatedEmail]);
|
||||
|
||||
// Та же защита от прямой ссылки, что и у «Отчётов» выше.
|
||||
React.useEffect(() => {
|
||||
if (route.nav === 'allRequests' && canSeeAllRequests === false) {
|
||||
navigate({ mode: 'submit', nav: 'new' }, { replace: true });
|
||||
}
|
||||
}, [route.nav, canSeeAllRequests]);
|
||||
|
||||
// Уникальный код заявки для заголовка Drawer (approve/edit) — сама форма
|
||||
// узнаёт его только после загрузки (см. onCodeLoaded в ApproveFeature/
|
||||
// EditFeature), поэтому не берём route.itemId (это RowID в SharePoint, а не
|
||||
@@ -201,6 +232,19 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Тип заявки в «Все заявки» — из запомненного (см. gotoAllRequestsType
|
||||
// ниже, откуда он и запоминается). Не задан ни разу — undefined, раздел
|
||||
// сам выберет первый доступный тип (см. AllRequestsFeature).
|
||||
if (nav === 'allRequests') {
|
||||
navigate({
|
||||
mode: 'submit',
|
||||
nav,
|
||||
allTypeId: storedAllTypeId(),
|
||||
page: storedPageFor(nav),
|
||||
query: storedQueryFor(nav) || undefined,
|
||||
});
|
||||
return;
|
||||
}
|
||||
navigate({
|
||||
mode: 'submit',
|
||||
nav,
|
||||
@@ -224,6 +268,28 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
});
|
||||
};
|
||||
|
||||
// Переход в «Все заявки» — либо с бокового меню (typeId не задан, раздел сам
|
||||
// выберет тип), либо с кнопки формы (typeId уже известен, см.
|
||||
// gotoAllRequestsForType и SubmitFeature.onOpenAllRequests), либо смена типа
|
||||
// в самом разделе (пикер в AllRequestsFeature). Запоминаем выбор — как и
|
||||
// persistOwnTab, только при явном выборе (в т.ч. том, что раздел сделал
|
||||
// сам по умолчанию), чтобы следующий заход открыл тот же тип.
|
||||
const gotoAllRequestsType = (typeId: number): void => {
|
||||
persistAllTypeId(typeId);
|
||||
navigate({
|
||||
mode: 'submit',
|
||||
nav: 'allRequests',
|
||||
allTypeId: typeId,
|
||||
page: storedPageFor('allRequests'),
|
||||
query: storedQueryFor('allRequests') || undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const gotoAllRequestsForType = (typeId: number): void => {
|
||||
persistNav('allRequests');
|
||||
gotoAllRequestsType(typeId);
|
||||
};
|
||||
|
||||
const setOwnStatus = (ownStatus: string): void => {
|
||||
const normalized = ownStatus || undefined;
|
||||
persistOwnStatus(normalized);
|
||||
@@ -281,6 +347,7 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
listId: request.listId,
|
||||
ownTab: route.ownTab,
|
||||
ownStatus: route.ownStatus,
|
||||
allTypeId: route.allTypeId,
|
||||
// Страница и запрос — часть того же списка под панелью: без них ссылка на
|
||||
// открытую заявку вела бы на первую страницу без поиска.
|
||||
page: route.page,
|
||||
@@ -295,6 +362,7 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
nav: route.nav,
|
||||
ownTab: route.ownTab,
|
||||
ownStatus: route.ownStatus,
|
||||
allTypeId: route.allTypeId,
|
||||
page: route.page,
|
||||
query: route.query,
|
||||
});
|
||||
@@ -324,6 +392,7 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
{ id: 'rework', title: 'Доработка', icon: 'edit', count: navCounts?.rework },
|
||||
{ id: 'own', title: 'Мои заявки', icon: 'clipboard' },
|
||||
{ id: 'search', title: 'Поиск', icon: 'search' },
|
||||
...(canSeeAllRequests ? [{ id: 'allRequests', title: 'Все заявки', icon: 'people' } as ISidebarItem] : []),
|
||||
...(canSeeReports ? [{ id: 'reports', title: 'Отчёты', icon: 'chart' } as ISidebarItem] : []),
|
||||
{ id: 'instructions', title: 'Инструкция пользователя', icon: 'info' },
|
||||
];
|
||||
@@ -413,6 +482,7 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
: undefined
|
||||
}
|
||||
onFormSelected={(formKey) => navigate({ mode: 'create', nav: 'new', formKey })}
|
||||
onOpenAllRequests={gotoAllRequestsForType}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -433,6 +503,19 @@ const RequestPortal: React.FC<IRequestPortalProps> = ({ hasTeamsContext, context
|
||||
|
||||
{route.nav === 'reports' && canSeeReports && <ReportsFeature context={context} />}
|
||||
|
||||
{route.nav === 'allRequests' && canSeeAllRequests && (
|
||||
<AllRequestsFeature
|
||||
context={context}
|
||||
selectedTypeId={route.allTypeId}
|
||||
onTypeChange={gotoAllRequestsType}
|
||||
page={route.page ?? 1}
|
||||
onPageChange={setPage}
|
||||
query={route.query ?? ''}
|
||||
onQueryChange={setQuery}
|
||||
onOpen={openRequest}
|
||||
/>
|
||||
)}
|
||||
|
||||
{LIST_VIEWS[route.nav] !== undefined && (
|
||||
<RequestsTableView
|
||||
context={context}
|
||||
|
||||
Reference in New Issue
Block a user