Merge pull request '«Назад» из документа возвращает панель «Первичные документы» организации (#197, AURORA-1682)' (#198) from feat/197-back-to-primary-docs into main
This commit is contained in:
commit
ec783c8ec0
2
openspec/changes/back-to-primary-docs/.openspec.yaml
Normal file
2
openspec/changes/back-to-primary-docs/.openspec.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-10-27
|
||||
20
openspec/changes/back-to-primary-docs/design.md
Normal file
20
openspec/changes/back-to-primary-docs/design.md
Normal file
@ -0,0 +1,20 @@
|
||||
## Context
|
||||
|
||||
AURORA-1682, RSHB/arm-core#197. Панель «Первичные документы» открывалась локальным состоянием `ConsolidationPage`
|
||||
(`drawerOpen`), ЮЛ панели — в сторе (`current_legal_entity_id`). «Назад» из документа (`navigate(-1)`) монтирует страницу
|
||||
консолидации заново, и панель закрыта.
|
||||
|
||||
## Decisions made without discussion
|
||||
|
||||
- **2026-10-27, R-1.** Открытая панель хранится в адресе (`?entity=<legal_entity_id>`), а не в сторе или sessionStorage.
|
||||
Обоснование: выбранная версия уже живёт в `?version=` (ConsoleTable), история браузера сама возвращает адрес с панелью,
|
||||
а ссылку с панелью можно переслать. Цена ошибки: если параметр не нужен в адресе — заменить на состояние в сторе
|
||||
(правка в `ConsolidationsList.tsx` и двух функциях `utils/consolidations.ts`).
|
||||
- **2026-10-27, R-2.** Открытие и закрытие панели заменяют запись истории (`replace: true`), как выбор версии. Обоснование:
|
||||
иначе «Назад» браузера после закрытия панели снова открывал бы её. Цена ошибки: низкая — одна опция `setSearchParams`.
|
||||
- **2026-10-27, R-3.** Режим «Все документы организации» в адрес не входит: после «Назад» панель открыта столом
|
||||
консолидации. Обоснование: в задаче речь о возврате к панели организации; переключатель и без того сбрасывается при каждом
|
||||
открытии панели. Цена ошибки: низкая — добавить второй параметр адреса.
|
||||
- **2026-10-27, R-4.** Панель открывается, только когда ЮЛ из адреса уже в сторе (`current_legal_entity_id === entity`).
|
||||
Обоснование: стор обновляется эффектом после первого рендера — без условия панель на мгновение показала бы прежнее ЮЛ и
|
||||
запросила бы его файлы. Цена ошибки: нет (поведение для пользователя то же).
|
||||
38
openspec/changes/back-to-primary-docs/proposal.md
Normal file
38
openspec/changes/back-to-primary-docs/proposal.md
Normal file
@ -0,0 +1,38 @@
|
||||
## Why
|
||||
|
||||
AURORA-1682 (замечание тестирования 16.10.2026, п. 1; чек-лист Циликова 23.10.2026, строка 9): аналитик открывает документ
|
||||
из панели «Первичные документы» организации, проверяет его и нажимает «Назад» — открывается карточка консолидации без
|
||||
панели, и для следующего документа панель приходится открывать заново. Панель открывалась локальным состоянием страницы
|
||||
консолидации (`drawerOpen`), а «Назад» (`navigate(-1)`) монтирует страницу заново.
|
||||
|
||||
## What Changes
|
||||
|
||||
Репозиторий — только arm-core (`web/`), эндпоинты без изменений.
|
||||
|
||||
- Открытая панель «Первичные документы» хранится в адресе экрана консолидации параметром `?entity=<legal_entity_id>`
|
||||
рядом с `?version=`; открытие и закрытие панели заменяют текущую запись истории (как выбор версии). Расчёт параметров —
|
||||
`panelEntity` / `withPanelEntity` (`web/src/utils/consolidations.ts`), закреплён тестом.
|
||||
- «Назад» из документа, открытого из панели, возвращает на адрес с `?entity=` — панель той же организации открыта.
|
||||
Переключатель документа (AURORA-1692) и прямая ссылка ведут себя как прежде.
|
||||
- Дельты: `document-review-ui` — MODIFIED «Переключатель документа» (сценарий «Назад после перебора документов»);
|
||||
`primary-files-ui` — ADDED «Открытая панель в адресе экрана консолидации».
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Режим «Все документы организации» в адрес не попадает: после «Назад» панель открывается столом консолидации, как при
|
||||
обычном открытии.
|
||||
- Изменения бэкенда и DBML.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `document-review-ui`: MODIFIED «Переключатель документа».
|
||||
- `primary-files-ui`: ADDED «Открытая панель в адресе экрана консолидации».
|
||||
|
||||
## Impact
|
||||
|
||||
`web/src/layouts/ConsolidationsList.tsx`, `web/src/widgets/ConsoleLegalEntities/ConsoleLegalEntities.tsx`,
|
||||
`web/src/utils/consolidations.ts` (+ тест). Ссылки на экран консолидации с `?entity=` открывают панель этой организации.
|
||||
@ -0,0 +1,20 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Переключатель документа
|
||||
В шапке экрана документа SHALL быть выпадающий список «Документ» с документами файлов того же ЮЛ в той же консолидации,
|
||||
что и файл открытого документа (файл вне консолидации — все файлы ЮЛ): у пункта имя файла, вторая строка (тип · формат ·
|
||||
дата) и статус; пункты, которые нельзя открыть, неактивны. Выбор пункта SHALL открывать `/documents/:document_id`
|
||||
выбранного документа заменой текущей записи истории браузера, без новой записи: кнопка «Назад» экрана и браузера
|
||||
возвращает на экран, с которого открыт первый документ, а не к предыдущему выбранному. Если первый документ открыт из
|
||||
панели «Первичные документы» консолидации, «Назад» SHALL открывать экран консолидации с этой панелью той же организации.
|
||||
|
||||
#### Scenario: Назад после перебора документов
|
||||
- **WHEN** аналитик открыл документ из панели «Первичные документы» организации в карточке консолидации, выбрал в списке
|
||||
«Документ» подряд ещё два документа и нажал «Назад»
|
||||
- **THEN** открыт экран консолидации с той же выбранной версией и открытой панелью «Первичные документы» той же
|
||||
организации
|
||||
|
||||
#### Scenario: Документ открыт прямой ссылкой
|
||||
- **WHEN** документ открыт прямой ссылкой в новой вкладке, аналитик выбрал в списке «Документ» другой документ и нажал
|
||||
«Назад» экрана
|
||||
- **THEN** открыт список групп компаний `/groups`
|
||||
@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Открытая панель в адресе экрана консолидации
|
||||
Открытая панель «Первичные документы» SHALL храниться в адресе экрана консолидации `/groups/:group_id` параметром
|
||||
`?entity=<legal_entity_id>` рядом с `?version=`. Клик по организации в панели «Организации» SHALL добавлять параметр,
|
||||
закрытие панели — убирать его; оба перехода SHALL заменять текущую запись истории браузера, без новой записи. Адрес с
|
||||
`?entity=` SHALL открывать панель этой организации. Режим «Все документы организации» в адрес не входит: панель,
|
||||
открытая по адресу, показывает стол консолидации.
|
||||
|
||||
#### Scenario: Возврат из документа
|
||||
- **WHEN** аналитик открыл панель организации, перешёл по ссылке документа и вернулся «Назад»
|
||||
- **THEN** открыт экран консолидации с той же версией и панелью «Первичные документы» той же организации
|
||||
|
||||
#### Scenario: Закрытая панель не возвращается
|
||||
- **WHEN** аналитик открыл панель организации, закрыл её и нажал «Назад» браузера
|
||||
- **THEN** открыт экран, с которого пришли на экран консолидации, панель не открывается снова
|
||||
11
openspec/changes/back-to-primary-docs/tasks.md
Normal file
11
openspec/changes/back-to-primary-docs/tasks.md
Normal file
@ -0,0 +1,11 @@
|
||||
## 1. «Назад» на панель «Первичные документы» (AURORA-1682, RSHB/arm-core#197)
|
||||
|
||||
- [x] 1.1 `web/src/utils/consolidations.ts`: `panelEntity`, `withPanelEntity` — ЮЛ панели в `?entity=`; тест в
|
||||
`consolidations.test.ts`.
|
||||
- [x] 1.2 `web/src/layouts/ConsolidationsList.tsx`: панель открыта по `?entity=` (когда ЮЛ из адреса уже в сторе),
|
||||
открытие и закрытие — `setSearchParams(…, { replace: true })`; `ConsoleLegalEntities` передаёт id ЮЛ строки.
|
||||
- [x] 1.3 Дельты `document-review-ui` (MODIFIED «Переключатель документа») и `primary-files-ui` (ADDED «Открытая панель
|
||||
в адресе экрана консолидации»).
|
||||
- [x] 1.4 Проверка в браузере: панель организации → документ → переключить 2–3 документа → «Назад» — карточка
|
||||
консолидации с панелью той же организации; закрыть панель → «Назад» браузера не открывает её снова; сверка с макетом
|
||||
[39], [41].
|
||||
@ -4,8 +4,9 @@ import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { ApiError } from '../api/client';
|
||||
import PageTitle from '../components/PageTitle';
|
||||
import { fetchOneCompanyGroup } from '../services/api/directories/company_groups';
|
||||
import { setSelectedVersion } from '../store/slices/consolidations/consolidationsSlice';
|
||||
import { useAppDispatch } from '../store/store';
|
||||
import { setSelectedLegalEntity, setSelectedVersion } from '../store/slices/consolidations/consolidationsSlice';
|
||||
import { useAppDispatch, useAppSelector } from '../store/store';
|
||||
import { panelEntity, withPanelEntity } from '../utils/consolidations';
|
||||
import { ConsoleLegalEntitiesTable } from '../widgets/ConsoleLegalEntities/ConsoleLegalEntities';
|
||||
import { ConsoleTableWidget } from '../widgets/ConsoleTable/ConsoleTable';
|
||||
import { DocumentsDrawer } from '../widgets/FilesDrawer/FilesDrawer';
|
||||
@ -17,12 +18,16 @@ function errorText(e: unknown): string {
|
||||
}
|
||||
|
||||
export function ConsolidationPage() {
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [reloadKey, setReloadKey] = useState(0);
|
||||
const { group_id } = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const versionParam = searchParams.get('version');
|
||||
// открытая панель «Первичные документы» — в адресе (?entity=): «Назад» из документа возвращает с той же панелью
|
||||
const entityParam = panelEntity(searchParams);
|
||||
// панель открывается, когда ЮЛ из адреса уже в сторе: иначе на первом рендере она показала бы прежнее ЮЛ
|
||||
const panelOpen = useAppSelector((s) => entityParam !== null && s.consolidations.current_legal_entity_id === entityParam);
|
||||
const dispatch = useAppDispatch();
|
||||
const setPanelEntity = (entityId: string | null) => setSearchParams((params) => withPanelEntity(params, entityId), { replace: true });
|
||||
|
||||
const [comGroupName, setComGroupName] = useState('');
|
||||
const [locationPath, setLocationPath] = useState('Отчётность>');
|
||||
@ -48,6 +53,11 @@ export function ConsolidationPage() {
|
||||
dispatch(setSelectedVersion(versionParam));
|
||||
}, [dispatch, versionParam]);
|
||||
|
||||
// ЮЛ панели следует за ?entity=; закрытие панели выбор не сбрасывает (панель скрыта, ЮЛ без запроса не перечитывается)
|
||||
useEffect(() => {
|
||||
if (entityParam) dispatch(setSelectedLegalEntity(entityParam));
|
||||
}, [dispatch, entityParam]);
|
||||
|
||||
// уход со страницы сбрасывает выбор (при смене группы ?version= пропадает из URL — выбор сбросит эффект выше)
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@ -97,18 +107,13 @@ export function ConsolidationPage() {
|
||||
flexDirection: 'column',
|
||||
minHeight: 0,
|
||||
}}>
|
||||
<ConsoleLegalEntitiesTable
|
||||
reloadKey={reloadKey}
|
||||
onDrawerOpen={() => {
|
||||
setDrawerOpen(true);
|
||||
}}
|
||||
/>
|
||||
<ConsoleLegalEntitiesTable reloadKey={reloadKey} onDrawerOpen={setPanelEntity} />
|
||||
</div>
|
||||
</main>
|
||||
<DocumentsDrawer
|
||||
open={drawerOpen}
|
||||
open={panelOpen}
|
||||
onClose={() => {
|
||||
setDrawerOpen(false);
|
||||
setPanelEntity(null);
|
||||
setReloadKey((k) => k + 1);
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -16,12 +16,14 @@ import {
|
||||
isLockedBy,
|
||||
isValidReason,
|
||||
manualTransitions,
|
||||
panelEntity,
|
||||
parseInWorkOnly,
|
||||
rememberCounterPairsShown,
|
||||
reportTabNavigation,
|
||||
resolveLeaveAfterFetch,
|
||||
shouldWarnCounterPairs,
|
||||
versionLabel,
|
||||
withPanelEntity,
|
||||
} from './consolidations';
|
||||
|
||||
const lock = (userId: string): LockOut => ({
|
||||
@ -143,6 +145,24 @@ describe('вкладки отчёта (AURORA-1851)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('панель «Первичные документы» в адресе (AURORA-1682)', () => {
|
||||
it('открытие добавляет ?entity= к выбранной версии, исходные параметры не меняются', () => {
|
||||
const params = new URLSearchParams('version=v1&in_work_only=true');
|
||||
const next = withPanelEntity(params, 'le1');
|
||||
expect(next.toString()).toBe('version=v1&in_work_only=true&entity=le1');
|
||||
expect(params.toString()).toBe('version=v1&in_work_only=true');
|
||||
});
|
||||
|
||||
it('закрытие убирает ?entity=, версия остаётся', () => {
|
||||
expect(withPanelEntity(new URLSearchParams('version=v1&entity=le1'), null).toString()).toBe('version=v1');
|
||||
});
|
||||
|
||||
it('организация панели читается из адреса', () => {
|
||||
expect(panelEntity(new URLSearchParams('version=v1&entity=le1'))).toBe('le1');
|
||||
expect(panelEntity(new URLSearchParams('version=v1'))).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
const pair = (holder: string, missing: string): CounterPairOut => ({
|
||||
holder_id: holder,
|
||||
holder_name: `H${holder}`,
|
||||
|
||||
@ -100,6 +100,23 @@ export const reportTabNavigation = (pathname: string, activeKey: string, newKey:
|
||||
options: { replace: true },
|
||||
});
|
||||
|
||||
/** Параметр адреса экрана консолидации с ЮЛ открытой панели «Первичные документы» (AURORA-1682). */
|
||||
const PANEL_ENTITY_PARAM = 'entity';
|
||||
|
||||
/** ЮЛ открытой панели «Первичные документы» из адреса; панель закрыта — `null`. */
|
||||
export const panelEntity = (params: URLSearchParams): string | null => params.get(PANEL_ENTITY_PARAM);
|
||||
|
||||
/**
|
||||
* Параметры адреса с открытой (`entityId`) или закрытой (`null`) панелью «Первичные документы»; исходные не меняются.
|
||||
* Панель живёт в адресе, как выбранная версия: «Назад» из документа возвращает на консолидацию с той же панелью.
|
||||
*/
|
||||
export function withPanelEntity(params: URLSearchParams, entityId: string | null): URLSearchParams {
|
||||
const next = new URLSearchParams(params);
|
||||
if (entityId === null) next.delete(PANEL_ENTITY_PARAM);
|
||||
else next.set(PANEL_ENTITY_PARAM, entityId);
|
||||
return next;
|
||||
}
|
||||
|
||||
/** Статусы, в которых версия закрыта для правок: модалку о парах без встречных записей не показываем. */
|
||||
export const FINISHED_STATUSES: readonly ConsStatus[] = ['VERIFIED', 'CANCELLED', 'ARCHIVED', 'REJECTED'];
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { ColumnSettings, DataTable, useFilteredRows, useVisibleColumns } from '.
|
||||
import { useTableFilters } from '../../components/GenericTable/useTableFilters';
|
||||
import { downloadChecklistCsv } from '../../services/api/consolidations';
|
||||
import { getVersionCard } from '../../services/api/consolidations';
|
||||
import { setSelectedLegalEntity, setSelectedVersion } from '../../store/slices/consolidations/consolidationsSlice';
|
||||
import { setSelectedVersion } from '../../store/slices/consolidations/consolidationsSlice';
|
||||
import { useAppDispatch, useAppSelector } from '../../store/store';
|
||||
import type { IVersionCard, MemberRow } from '../../types/consolidations/version_members';
|
||||
import { saveBlob } from '../../utils/download';
|
||||
@ -15,7 +15,7 @@ import { membersConfig } from './config';
|
||||
import { normalizeData } from './normalize';
|
||||
import { checklistFilename, responsibleName } from './panelInfo';
|
||||
|
||||
export function ConsoleLegalEntitiesTable({ onDrawerOpen, reloadKey }: { onDrawerOpen: () => void; reloadKey: number }) {
|
||||
export function ConsoleLegalEntitiesTable({ onDrawerOpen, reloadKey }: { onDrawerOpen: (entityId: string) => void; reloadKey: number }) {
|
||||
const dispatch = useAppDispatch();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const consolidation_id = useAppSelector((s) => s.consolidations.current_version_id);
|
||||
@ -60,8 +60,7 @@ export function ConsoleLegalEntitiesTable({ onDrawerOpen, reloadKey }: { onDrawe
|
||||
const onRow = (row: MemberRow) => ({
|
||||
onClick: () => {
|
||||
dispatch(setSelectedVersion(row.version_id));
|
||||
dispatch(setSelectedLegalEntity(row.id));
|
||||
onDrawerOpen();
|
||||
onDrawerOpen(row.id);
|
||||
},
|
||||
});
|
||||
if (consolidationData === null) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user