diff --git a/docs/program-role-widget/README.md b/docs/program-role-widget/README.md new file mode 100644 index 000000000..a11a4498d --- /dev/null +++ b/docs/program-role-widget/README.md @@ -0,0 +1,99 @@ + + +# Ролевая аналитика программы: DEV + +Исходная Angular-база: `99c8813a66f89560a946eab7d1de73ab2925d0f5`. +Контракт backend подготовлен от `ed5244bd4a098bd0f1cee0f5e380dd67bdd61a96`. +Ветка обоих репозиториев: `feature/dev-program-role-analytics-widget`. +Точные итоговые SHA и связанные Draft PR указаны в описаниях PR. + +Актуальный результат доработки: [композиция, новости, окончательные проверки и локальная интеграция](followup/README.md). + +## Источники и границы доступа + +| Показатель | Фактический источник | Доступ / изменение | +| ------------------------------ | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| Роль | Менеджеры текущей PartnerProgram → Expert.programs → PartnerProgramUserProfile | Backend определяет роль по авторизованному пользователю; Angular использует контекстные флаги. Добавлен `is_user_expert` в detail | +| Проект участника | Project.leader либо Collaborator, через PartnerProgramProject текущей программы | Новый read-only `participant_project`; лидер и член команды видят один проект. Legacy `current_application` не изменён | +| Кейс | Системное поле с точным `name="case"`, его значение на текущей PartnerProgramProject | Без поиска по label, выбора первого варианта и связи другой программы | +| Этапы | submitted + общий `_solution_rows` backend | Без баллов, имён экспертов и закрытых результатов | +| Участники / без проектов | Общий `_get_participant_metrics`: distinct user, Exists для лидера и Collaborator текущей программы | Только организатор; черновики означают наличие проекта | +| Проекты / отправленные решения | Общий `_get_solution_metrics`: связи PartnerProgramProject / submitted-связи | Только организатор; это не число отправивших пользователей | +| Назначено / осталось | ProjectExpertAssignment текущего эксперта и программы + `annotated_assignment_queryset` | Только эксперт; незавершённый not_ready входит в остаток | +| Срок | `datetime_evaluation_ends` | Локальные часы обновляются раз в секунду без HTTP polling | + +GET `/programs/{id}/analytics-widget/` возвращает только одну ролевую ветвь. +Manager-only endpoints не используются участником или экспертом. Отсутствие member-роли не скрывает виджет менеджера/эксперта; закрытые новости, контакты и материалы сохраняют прежние ограничения. + +Нарушение правила одной команды возвращает 409 и состояние «Данные проекта требуют проверки». Нет выбора проекта, dropdown, произвольного первого проекта или исправления пользовательских данных. + +## Поведение + +- Участник: кейс, название и переход к проекту; текущая «Проверка» без галочки, конечное серверное состояние «Оценён» завершает все три этапа. Черновик — «Не отправлен». Без проекта доступна существующая явная команда создания заявки, если срок подачи открыт. До нажатия бизнес-действия не выполняются. +- Distributed: оценённость определяет общая серверная аналитика по всем назначениям; частично заполненный проект не завершён, допустимый ноль считается внесённой оценкой. Неотправленное решение остаётся not_ready. +- Open: сохранено текущее правило основной аналитики — наличие ProjectScore по критерию этой программы означает evaluated. Виджет не вводит более строгого или нового критерия. У эксперта нет выдуманных назначений: оба счётчика «—», одна строка «Свободное оценивание…» со сроком и доступным переходом. +- Неконкурсные программы не имитируют обязательную сдачу: этапы и отправленные решения неприменимы. Персональные distributed-счётчики нейтральны; свободное оценивание сохраняется. +- «Без проектов»: доля рассчитывается до округления; ≤10% зелёная, ≤25% жёлтая, выше красная. При нуле участников — «—» и нейтральный цвет. `19 / 248 = 7,7%`; полная подсказка «19 из 248 участников без проекта». +- Дедлайн: сначала нет назначений / всё завершено; затем отсутствие срока, >48 часов, ≤48 часов, наступление срока. До суток — часы, до часа — минуты. Точная дата, время и часовой пояс доступны в подсказке. +- Ошибки API не превращаются в нули. Retry только для сетевой/серверной ошибки; 401/403/404/409 имеют контролируемый текст. Смена программы, пользователя, роли и logout очищают данные и отменяют прежний запрос; поздние ответы отбрасываются. +- После успешного создания связи, изменения полей/кейса, сдачи решения и оценки существующая EventBus передаёт `ProgramWidgetChanged`. Неуспешная операция не инициирует обновление. + +Архитектура: domain-модель → repository port/HTTP adapter → use-case → локальный сервис состояния → отдельный компонент страницы. Общие SoonCard и Modal, React, зависимости и CI не меняются. + +## Геометрия и visual smoke + +Измерена исходная страница на DEV-базе, а не иллюстрация из задания. Chromium, viewport 1280 × 1000, DPR 1, масштаб 100%, загружен существующий шрифт Mont. + +| Элемент | x до / после | y до / после | Ширина до / после | Высота до / после | +| ----------- | ----------------------- | --------------------- | ----------------------- | ----------------------- | +| Карточка | 285,828125 / 285,828125 | 262,59375 / 262,59375 | 157 / 157 | 140,984375 / 140,984375 | +| О программе | 471,15625 / 471,15625 | 262,59375 / 262,59375 | 413,328125 / 413,328125 | 106,59375 / 106,59375 | + +CSS фиксирует высоту 140,9844 px; фактическое значение Chromium — 140,984375 px. Подписи метрик 10 px. Многоточием сокращаются только динамические названия; MatTooltip доступен при hover и клавиатурном фокусе. Срок эксперта занимает две строки: подпись и полное значение с единицей времени. Служебные статусы видны целиком. Внутренней прокрутки нет. + +В окончательной доработке проверены [23 состояния](followup/geometry.json), все три роли и их нулевые состояния, полный срок без наведения, hover/focus, Retry и адаптивные границы. [Актуальные скриншоты и кропы без масштабирования](followup/README.md#скриншоты). Измерения: [исходные](baseline-geometry.json), [окончательные](followup/geometry.json). Скриншоты ниже сохранены как история первоначальной реализации. + +Fixture smoke использует TestBed и не вызывает API. Отдельно выполнена [реальная локальная интеграционная проверка](followup/README.md#локальная-интеграция): вход, новости, кейс, сдача, оценка 0, переходы и ошибки на отдельной PostgreSQL БД. Живой DEV и PROD не использовались. + +### Скриншоты + +Исходная страница: + +![До](screenshots/before-1280.png) + +| Участник | Организатор | Эксперт | +| ----------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------- | +| ![Участник](screenshots/participant-1280.png) | ![Организатор](screenshots/organizer-1280.png) | ![Эксперт](screenshots/expert-1280.png) | +| ![Нет проекта](screenshots/participant-zero-1280.png) | ![Нет участников](screenshots/organizer-zero-1280.png) | ![Нет назначений](screenshots/expert-zero-1280.png) | + +### Воспроизведение локального smoke + +```sh +npm exec -- ng build social_platform --configuration development --browser docs/program-role-widget/smoke/page.ts --ts-config docs/program-role-widget/smoke/tsconfig.json --index docs/program-role-widget/smoke/index.html --output-path tmp/current +node docs/program-role-widget/smoke/serve.cjs 4302 +``` + +Открыть `http://localhost:4302/?view=participant` при указанном viewport. Полный перечень `view` приведён в [отчёте доработки](followup/README.md#скриншоты). Fixtures находятся вне production entry point и не входят в обычную сборку приложения. + +## Первоначальные проверки 14.09.2026 (история) + +Ниже результаты до доработки композиции. [Окончательные проверки и сравнение полных suite на base/head](followup/README.md#окончательные-проверки-angular) заменяют их при приёмке. + +| Команда | Фактический результат | +| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Targeted Vitest, команда ниже | 37 файлов, 337 тестов PASS, включая 61 новый теста виджета | +| `npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1` | 365 файлов / 1540 тестов PASS; exit 1 из-за unhandled `ngx-autosize: window is not defined` после teardown `profile-mid-side.component.spec.ts`. Полный прогон выполнен до последних уточнений; последние изменения перепроверены targeted | +| `npm run lint:ts` | 0 ошибок, 6 существующих предупреждений в logger/chat-message/message-input | +| Scoped Stylelint нового SCSS | PASS | +| Scoped Prettier изменённых TS/HTML и документации | PASS | +| `npm run build:pr` | PASS, Angular strict compilation; существующие Sass deprecation warnings. Генерируемый Windows sprite восстановлен, в diff не включён | +| `git diff --check` | PASS | + +```sh +npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1 projects/social_platform/src/app/api/program projects/social_platform/src/app/api/project/facades/edit/project-additional.service.spec.ts projects/social_platform/src/app/ui/pages/program/detail/main/role-widget projects/social_platform/src/app/ui/widgets/detail/services/program/detail-program-info.service.spec.ts projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.spec.ts projects/social_platform/src/app/infrastructure/repository/program/program.repository.spec.ts +npm exec -- stylelint projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.scss +``` + +Для будущего DEV-развёртывания сначала нужен backend с GET-контрактом и `is_user_expert`, затем этот Angular. При отсутствии endpoint показывается контролируемое состояние недоступности. Merge и deploy не выполнены. + +Окончательные [адаптивные границы](followup/responsive.json), [Retry](followup/retry.json), [hover кейса](followup/screenshots/long-hover.png) и [клавиатурный focus проекта](followup/screenshots/long-focus.png) проверены повторно после доработки. diff --git a/docs/program-role-widget/baseline-geometry.json b/docs/program-role-widget/baseline-geometry.json new file mode 100644 index 000000000..46e051f00 --- /dev/null +++ b/docs/program-role-widget/baseline-geometry.json @@ -0,0 +1,25 @@ +{ + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "viewport": [1280, 1000] +} diff --git a/docs/program-role-widget/followup/README.md b/docs/program-role-widget/followup/README.md new file mode 100644 index 000000000..f23234a36 --- /dev/null +++ b/docs/program-role-widget/followup/README.md @@ -0,0 +1,117 @@ + + +# Доработка ролевого виджета: DEV, 14.09.2026 + +Продолжение существующих Draft PR [Angular #348](https://github.com/PROCOLLAB-github/procollab/pull/348) и [backend #742](https://github.com/PROCOLLAB-github/api/pull/742). Angular base: `99c8813a66f89560a946eab7d1de73ab2925d0f5`, предыдущий head: `f9ee3c397acf0fc6ed643246b44760fa82705313`. Точный head этого коммита указан в PR. Backend base: `ed5244bd4a098bd0f1cee0f5e380dd67bdd61a96`, head без изменений: `3d84c7f4090985e4f42a13654e8fb05856f65cb3`. + +## Исправления + +- Организатор с `isUserManager=true`, `isUserMember=false` получает и видит новости. Условие `member || manager` одинаково в загрузке и шаблоне списка. Созданная новость появляется в том же списке. Четыре регрессионных теста страницы используют настоящий шаблон, фасад страницы и NewsInfoService: организатор, участник, эксперт без member/manager и посторонний пользователь. Правила операций с новостями не менялись. +- Заголовок и вторичный бейдж разведены по горизонтали. Данные и нижнее действие занимают отдельные зоны; значения 14 px полужирные, подписи метрик 10 px / 12 px. Использованы существующие шрифты и цвета. Нижняя зона высотой 22 px одинакова во всех состояниях. +- Кейс и проект — две выровненные строки. Только длинные динамические названия получают ellipsis и доступный MatTooltip. Между маркерами этапов добавлена тонкая линия. Текущая «Проверка» не имеет галочки; конечный серверный `evaluated` завершает всю цепочку. +- Организатор: «Сдано решений» с контролируемым переносом, числа второй строки выровнены. Рядом с «Без проектов» маленькая цветная точка и вторичный процент вместо тесного разделителя. Формула и пороги неизменны: `19 / 248 = 7,7%`, зелёный. +- Эксперт: два счётчика, один статусный блок. Активный срок показан двумя строками: «До конца оценивания» и «2 дня», «5 часов» либо «25 минут». Полные русские единицы времени и склонения, без ellipsis. Нулевые, завершённые и просроченные состояния полностью видны. В open показаны режим и оставшееся время один раз, счётчики «—». + +Серверные источники и правила описаны в [основной документации](../README.md#источники-и-границы-доступа). В этом follow-up backend-код, React, `current_application`, права команд/сдачи, правила оценивания, shared Modal/SoonCard, зависимости, миграции и workflows не изменялись. + +## Геометрия + +Chromium, Mont загружен, DPR 1, масштаб 100%. Размеры исходной страницы проверены по воспроизводимой сборке DEV-базы. Нет transform/zoom карточки, расширения колонки или внутренней прокрутки. + +| Viewport | Карточка до и после (x; y; w; h), CSS px | «О программе» до и после (x; y; w; h) | +| ----------- | ---------------------------------------- | ------------------------------------------- | +| 1280 × 1000 | 285,828125; 262,59375; 157; 140,984375 | 471,15625; 262,59375; 413,328125; 106,59375 | +| 1440 × 1000 | 365,828125; 262,59375; 157; 140,984375 | 551,15625; 262,59375; 413,328125; 106,59375 | +| 1000 × 1000 | Карточка скрыта, как на базе | 197,5; 277,59375; 139,5; 161,1875 | + +Все 23 состояния при 1280 имеют одинаковые card/About/footer rect. [Измерения и текстовые DOM Range](geometry.json), [1000/1440](responsive.json), [fixture Retry](retry.json), [реальный HTTP 503 → Retry](integration-retry.json). Проверены сами скриншоты, а не только scrollHeight: служебные подписи, статусы и единицы времени видны целиком. Метрики шрифта Mont выходят примерно на 1 px за собственный line-height; overflow у строк видимый, это не отсечение глифов. Динамические названия намеренно сокращены; полное значение доступно при hover/focus. + +## Скриншоты + +Полная страница при 100%: [участник](screenshots/participant-page.png), [организатор](screenshots/organizer-page.png), [эксперт](screenshots/expert-page.png), [исходная страница](../screenshots/before-1280.png). + +![Полная страница эксперта, 1280 × 1000](screenshots/expert-page.png) + +Кропы ниже получены из исходных PNG без увеличения, уменьшения и обработки: 158 × 143 физических px, целочисленная рамка вокруг дробного CSS rect 157 × 140,984375. Они дополняют полные страницы. + +| Участник | Организатор | Эксперт | +| ----------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------- | +| ![Проверка](screenshots/participant-card.png) | ![19 из 248](screenshots/organizer-card.png) | ![Дни](screenshots/expert-card.png) | +| ![Нет проекта](screenshots/participant-zero-card.png) | ![Нули](screenshots/organizer-zero-card.png) | ![Нет назначений](screenshots/expert-zero-card.png) | +| ![Оценён](screenshots/participant-evaluated-card.png) | ![Большие числа](screenshots/organizer-large-card.png) | ![Часы](screenshots/expert-hours-card.png) | +| ![Не отправлен](screenshots/draft-card.png) | ![Жёлтый](screenshots/organizer-yellow-card.png) | ![Минуты](screenshots/expert-minutes-card.png) | + +Полный перечень `view` воспроизводимого smoke: `participant`, `participant-submitted`, `participant-evaluated`, `participant-zero`, `draft`, `long`, `participant-no-case`, `organizer`, `organizer-zero`, `organizer-large`, `organizer-yellow`, `organizer-red`, `expert`, `expert-zero`, `expert-complete`, `expert-hours`, `expert-minutes`, `expert-overdue`, `expert-missing`, `expert-open`, `loading`, `error`, `forbidden`. Для каждого сохранены `-page.png` и `-card.png` в [screenshots](screenshots). Команда сборки fixture smoke — в [README](../README.md#воспроизведение-локального-smoke). + +Отдельно: [hover кейса без клавиатурного фокуса](screenshots/long-hover.png), [клавиатурный focus проекта и полная подсказка](screenshots/long-focus.png), [свободное оценивание](screenshots/expert-open-page.png), [просрочка](screenshots/expert-overdue-page.png). + +## Окончательные проверки Angular + +Все production TS/HTML/SCSS и тесты этого follow-up присутствовали в окончательном полном прогоне. После него менялись только документация/артефакты; восстановлен генерируемый Windows sprite. + +| Проверка | Результат | +| ------------------------------------- | ------------------------------------------------------------------------------------------------- | +| Targeted Vitest, команда ниже | **39 файлов, 349 тестов PASS**, exit 0 | +| Full Vitest, итоговая версия | **367 файлов, 1560 тестов прошли; 1 unhandled error, exit 1**. Не считается успешным полным suite | +| Full Vitest, исходный base `99c8813…` | **361 файл, 1489 тестов прошли; 1 unhandled error, exit 1** | +| `npm run lint:ts` | 0 ошибок, 6 предупреждений: logger/chat-message/message-input | +| Scoped Stylelint и Prettier | PASS | +| `npm run build:pr` | PASS; Angular strict compilation, существующие Sass deprecation warnings | +| `git diff --check` | PASS | + +### Сравнение ошибки full suite + +Два полных запуска на одной Windows-машине: Node **24.18.0**, npm **11.16.0**, Vitest **3.2.6**, ngx-autosize **2.0.4**. Оба worktree используют junction к одному неизменённому `node_modules`; команда и параметры одинаковы. База — отдельный detached worktree на точном SHA, её исходники не редактировались. + +```sh +npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1 +``` + +В обоих прогонах `ReferenceError: window is not defined`, цепочка `WindowRef.nativeWindow → AutosizeDirective._addWindowResizeHandler → _onTextAreaFound → _findNestedTextArea → Timeout`, после teardown. Vitest связывает поздний callback с `news-form.component.spec.ts` на head и `profile-mid-side.component.spec.ts` на base. Разные относительные префиксы путей обусловлены размещением worktree. Это подтверждает воспроизведение ошибки без изменений PR; точная причина таймера не исследовалась и не исправлялась. Ошибки не подавлялись, тесты не отключались. + +Точные выводы с stack trace, итогами и exit code: [head](full-head-result.txt), [base](full-base-result.txt). Время: head 400,37 s, base 407,93 s. Разница в количестве тестов между base и текущим PR — 71. + +```sh +npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1 projects/social_platform/src/app/api/program projects/social_platform/src/app/api/project/facades/edit/project-additional.service.spec.ts projects/social_platform/src/app/ui/pages/program/detail/main projects/social_platform/src/app/ui/widgets/detail/services/program/detail-program-info.service.spec.ts projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.spec.ts projects/social_platform/src/app/infrastructure/repository/program/program.repository.spec.ts +npm run lint:ts +npm exec -- stylelint projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.scss +npm exec -- prettier --check <изменённые TS/HTML/SCSS и документы> +npm run build:pr +git diff --check +``` + +## Backend: CI и локальные результаты + +Повторно проверен [Backend PostgreSQL CI run 34849441959](https://github.com/PROCOLLAB-github/api/actions/runs/34849441959): **completed / success**, `headSha=3d84c7f4090985e4f42a13654e8fb05856f65cb3`, точное совпадение с актуальным head PR #742. Проверки Lint и Tests также success. Backend-код в этом follow-up не менялся; искусственного коммита нет. + +Ранее выполненные локальные результаты относятся к этому же backend head и не заменяются результатом CI: + +- Targeted Django: **120/120 PASS**. +- Full PostgreSQL: **849 тестов, 1 failure** в `feed.tests.test_feed_api.FeedAPITests.test_feed_returns_project_news_as_news_content` (`project` вместо `news`). Отдельный запуск этого теста на исходном DEV SHA прошёл; причина сбоя полного прогона **не установлена**. Посторонний feed-код не исправлялся. +- Full SQLite: **849 тестов, OK, skipped=4**, но процесс завершился с ошибкой удаления тестовой БД **WinError 32** после тестов. +- Mypy не начал проверку: `mypy.ini` объединяет две строки plugins в один import. Конфигурация не менялась. + +## Локальная интеграция + +Это отдельная проверка реальной связки: Angular AppComponent/APP_CONFIG и реальные маршруты/сервисы на `localhost:4304`, Django текущего backend head на `localhost:8009`, PostgreSQL 18. Создана отдельная БД `procollab_widget_integration_f348_20260914` с синтетическими пользователями и Angular-моделями. DEV/PROD API и данные не использовались. Только локальный environment направлен на этот API; frontend-сервисы не подменялись fixtures. Для писем использован locmem backend из `settings_ci`; внешние письма не отправлялись. + +| Сценарий | Фактический результат | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Организатор без member | Виджет 3 участника / 1 проект / 0 сдано / 1 без проекта, 33,3%; существующая новость видна. Созданная через форму новость появляется в списке — [скрин](screenshots/integration-manager-news.png) | +| Переход организатора | Открылась действующая `/office/program/2/analytics`, данные основной аналитики загрузились | +| Смена программы | У того же организатора переход с программы 2 на пустую 3 заменил счётчики на 0 и процент на «—» | +| Лидер и член команды | Оба видят project 1 / programLinkId 1, один case и этап. Нижнее действие открывает `/office/projects/1?programLinkId=1`; у члена команды нет ссылки редактирования — [лидер](screenshots/integration-leader.png), [член команды](screenshots/integration-teammate.png) | +| Изменение case | Через «перейти в заявку» → данные для конкурсов → Новый кейс → сохранить черновик. При возврате виджет показывает сохранённое значение — [скрин](screenshots/integration-case-updated.png) | +| Сдача | Заполненный тестовый проект отправлен через действующую форму и подтверждение. Реальный submitted стал true, виджет перешёл в «Проверка» — [скрин](screenshots/integration-submitted.png) | +| Эксперт без member | Виджет 1 / 1, срок «2 дня»; закрытого списка новостей нет. Нижнее действие открыло `/office/program/2/projects-rating` с назначенным проектом — [скрин](screenshots/integration-expert.png) | +| Оценка 0 | В действующей форме введён допустимый 0, подтверждён и сохранён. После возврата счётчики 1 / 0 и «Все проекты оценены» — [скрин](screenshots/integration-expert-complete.png). Член команды видит три галочки «Оценён» — [скрин](screenshots/integration-evaluated.png) | +| Нулевые состояния | Реальный участник без проекта — [скрин](screenshots/integration-participant-zero.png); эксперт с ролью в другой программе и без назначений — 0 / 0, «Нет назначенных проектов» — [скрин](screenshots/integration-expert-zero.png) | +| Logout / другой пользователь | Logout переводит на /auth/login, карточка отсутствует. Следующий вход загружает только данные нового пользователя | +| Посторонний пользователь | Прежний рекламный блок; виджета и закрытых новостей нет — [скрин](screenshots/integration-outsider.png) | +| Ошибка / Retry | Локальный тестовый middleware временно возвращал **503 только для analytics-widget**. После штатных ограниченных HTTP retries: безопасный текст и «Повторить», без raw body. После снятия fault и нажатия кнопки реальные данные загрузились — [ошибка](screenshots/integration-error.png), [успех](screenshots/integration-retry-success.png). Rect совпал | + +Тестовое окружение потребовало двух дополнений синтетических fixtures: обязательные поля проекта перед сдачей и MailingSchema #2 для локального уведомления оценки. До добавления шаблона API возвращал `MailingSchema matching query does not exist`; после добавления повторное подтверждение в UI прошло успешно. Это подготовка изолированных данных, не изменение правил или production-кода. + +Ограничения: живой DEV не проверялся. Последующая [диагностика `PUT /projects/NaN/ → 404`](../nan-diagnostic/README.md) установила чтение ID из root ActivatedRoute и воспроизвела тот же дефект на точном base и head; новый вход виджета его не усиливает. Обычное название и case сохраняются явной кнопкой, но удаление презентации оставляет старый URL даже после сообщения об успехе: отдельная [задача P1 редактора](../nan-diagnostic/editor-task.md), препятствие для его дальнейшего релиза. Код редактора в этом follow-up не исправлялся. Многопрограммный проект, все пограничные комбинации доступа и поздние ответы проверены автоматическими тестами; браузерный интеграционный сценарий не повторяет каждую комбинацию. Обновление EventBus без ухода со страницы проверено unit-тестами; в браузере подтверждён результат после возврата из существующих редакторов. + +Для будущего DEV-развёртывания сначала нужен backend #742 с read-only контрактом и `is_user_expert`, затем Angular #348. Merge, deploy и действия с PROD не выполнялись. diff --git a/docs/program-role-widget/followup/full-base-result.txt b/docs/program-role-widget/followup/full-base-result.txt new file mode 100644 index 000000000..3435f96bf --- /dev/null +++ b/docs/program-role-widget/followup/full-base-result.txt @@ -0,0 +1,39 @@ +Node 24.18.0; npm 11.16.0; Vitest 3.2.6; ngx-autosize 2.0.4 +Command: npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1 +Exit code: 1 + +⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯ + +Vitest caught 1 unhandled error during the test run. +This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +ReferenceError: window is not defined + ❯ WindowRef.get nativeWindow [as nativeWindow] ../../../procollab/projects/ngx-autosize/src/lib/window-ref.service.ts:5:3 + ❯ ../../../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:122:20 + ❯ NoopNgZone.runOutsideAngular ../../../../../%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B/PROCOLLAB-dev/procollab/node_modules/@angular/core/fesm2022/debug_node.mjs:8168:16 + ❯ AutosizeDirective._addWindowResizeHandler ../../../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:120:16 + ❯ AutosizeDirective._onTextAreaFound ../../../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:108:5 + ❯ AutosizeDirective._findNestedTextArea ../../../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:103:9 + ❯ Timeout._onTimeout ../../../procollab/node_modules/ngx-autosize/fesm2015/ngx-autosize.mjs:80:16 + 79| return; + 80| } + 81| this.textAreaEl.style['overflow-y'] = 'hidden'; + | ^ + 82| this._onTextAreaFound(); + 83| } + ❯ listOnTimeout node:internal/timers:605:17 + ❯ processTimers node:internal/timers:541:7 + +This error originated in "projects/social_platform/src/app/ui/pages/profile/detail/main/components/profile-mid-side/profile-mid-side.component.spec.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes: +- cancel timeouts using clearTimeout and clearInterval +- wait for promises to resolve using the await keyword +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + + + Test Files 361 passed (361) + Tests 1489 passed (1489) + Errors 1 error + Start at 20:46:44 + Duration 407.93s (transform 16.63s, setup 251.51s, collect 245.48s, tests 88.04s, environment 799.85s, prepare 87.49s) diff --git a/docs/program-role-widget/followup/full-head-result.txt b/docs/program-role-widget/followup/full-head-result.txt new file mode 100644 index 000000000..45748f57f --- /dev/null +++ b/docs/program-role-widget/followup/full-head-result.txt @@ -0,0 +1,39 @@ +Node 24.18.0; npm 11.16.0; Vitest 3.2.6; ngx-autosize 2.0.4 +Command: npm exec -- vitest run --pool=forks --maxWorkers=4 --minWorkers=1 +Exit code: 1 + +⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯ + +Vitest caught 1 unhandled error during the test run. +This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +ReferenceError: window is not defined + ❯ WindowRef.get nativeWindow [as nativeWindow] ../procollab/projects/ngx-autosize/src/lib/window-ref.service.ts:5:3 + ❯ ../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:122:20 + ❯ NoopNgZone.runOutsideAngular ../../../%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B/PROCOLLAB-dev/procollab/node_modules/@angular/core/fesm2022/debug_node.mjs:8168:16 + ❯ AutosizeDirective._addWindowResizeHandler ../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:120:16 + ❯ AutosizeDirective._onTextAreaFound ../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:108:5 + ❯ AutosizeDirective._findNestedTextArea ../procollab/projects/ngx-autosize/src/lib/autosize.directive.ts:103:9 + ❯ Timeout._onTimeout ../procollab/node_modules/ngx-autosize/fesm2015/ngx-autosize.mjs:80:16 + 79| return; + 80| } + 81| this.textAreaEl.style['overflow-y'] = 'hidden'; + | ^ + 82| this._onTextAreaFound(); + 83| } + ❯ listOnTimeout node:internal/timers:605:17 + ❯ processTimers node:internal/timers:541:7 + +This error originated in "projects/social_platform/src/app/ui/widgets/news-form/news-form.component.spec.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes: +- cancel timeouts using clearTimeout and clearInterval +- wait for promises to resolve using the await keyword +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + + + Test Files 367 passed (367) + Tests 1560 passed (1560) + Errors 1 error + Start at 20:36:02 + Duration 400.37s (transform 16.05s, setup 237.19s, collect 227.56s, tests 103.88s, environment 789.01s, prepare 85.69s) diff --git a/docs/program-role-widget/followup/geometry.json b/docs/program-role-widget/followup/geometry.json new file mode 100644 index 000000000..0307f8565 --- /dev/null +++ b/docs/program-role-widget/followup/geometry.json @@ -0,0 +1,3639 @@ +[ + { + "view": "participant", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейс:Цифровой сервисПроект:StudyFlow✓ОтправленПроверкаОценёнОткрыть →" + }, + { + "view": "participant-submitted", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейс:Цифровой сервисПроект:StudyFlowОтправленПроверкаОценёнОткрыть →" + }, + { + "view": "participant-evaluated", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейс:Цифровой сервисПроект:StudyFlow✓Отправлен✓Проверка✓ОценёнОткрыть →" + }, + { + "view": "participant-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 307.59375, + "height": 14, + "left": 294.828125, + "right": 429.296875, + "top": 293.59375, + "width": 134.46875, + "x": 294.828125, + "y": 293.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 307.59375, + "height": 14, + "left": 294.828125, + "right": 433.828125, + "top": 293.59375, + "width": 139, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Кейсы не предусмотрены", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 324.59375, + "height": 14, + "left": 294.828125, + "right": 382.265625, + "top": 310.59375, + "width": 87.4375, + "x": 294.828125, + "y": 310.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 324.59375, + "height": 14, + "left": 294.828125, + "right": 433.828125, + "top": 310.59375, + "width": 139, + "x": 294.828125, + "y": 310.59375 + }, + "text": "Проект не подан", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 319.90625, + "right": 408.734375, + "top": 378.578125, + "width": 88.828125, + "x": 319.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 319.90625, + "right": 408.734375, + "top": 377.578125, + "width": 88.828125, + "x": 319.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": " Создать заявку → ", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейсы не предусмотреныПроект не поданОтправленПроверкаОценён Создать заявку → " + }, + { + "view": "draft", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейс:Цифровой сервисПроект:StudyFlow Не отправлен ОтправленПроверкаОценёнОткрыть →" + }, + { + "view": "long", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейс:Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Проект:Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект ✓ОтправленПроверкаОценёнОткрыть →" + }, + { + "view": "participant-no-case", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 307.59375, + "height": 14, + "left": 294.828125, + "right": 429.296875, + "top": 293.59375, + "width": 134.46875, + "x": 294.828125, + "y": 293.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 307.59375, + "height": 14, + "left": 294.828125, + "right": 433.828125, + "top": 293.59375, + "width": 139, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Кейсы не предусмотрены", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаучастникКейсы не предусмотреныПроект:StudyFlow✓ОтправленПроверкаОценёнОткрыть →" + }, + { + "view": "organizer", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 348.578125, + "top": 292.59375, + "width": 53.75, + "x": 294.828125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Участники", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 412.421875, + "top": 292.59375, + "width": 45.09375, + "x": 367.328125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Проекты", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 294.828125, + "right": 328.734375, + "top": 326.59375, + "width": 33.90625, + "x": 294.828125, + "y": 326.59375 + }, + { + "bottom": 340.59375, + "height": 14, + "left": 328.734375, + "right": 328.734375, + "top": 326.59375, + "width": 0, + "x": 328.734375, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 294.828125, + "right": 341.4375, + "top": 338.59375, + "width": 46.609375, + "x": 294.828125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 327.59375, + "width": 66.5, + "x": 294.828125, + "y": 327.59375 + }, + "text": "Сданорешений", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 367.328125, + "right": 384.671875, + "top": 326.59375, + "width": 17.34375, + "x": 367.328125, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 367.328125, + "right": 416.21875, + "top": 338.59375, + "width": 48.890625, + "x": 367.328125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 327.59375, + "width": 66.5, + "x": 367.328125, + "y": 327.59375 + }, + "text": "Без проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаорганизаторУчастники 248 Проекты 61 Сданорешений 54 Без проектов197,7%Открыть →" + }, + { + "view": "organizer-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 348.578125, + "top": 292.59375, + "width": 53.75, + "x": 294.828125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Участники", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 412.421875, + "top": 292.59375, + "width": 45.09375, + "x": 367.328125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Проекты", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 294.828125, + "right": 328.734375, + "top": 326.59375, + "width": 33.90625, + "x": 294.828125, + "y": 326.59375 + }, + { + "bottom": 340.59375, + "height": 14, + "left": 328.734375, + "right": 328.734375, + "top": 326.59375, + "width": 0, + "x": 328.734375, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 294.828125, + "right": 341.4375, + "top": 338.59375, + "width": 46.609375, + "x": 294.828125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 327.59375, + "width": 66.5, + "x": 294.828125, + "y": 327.59375 + }, + "text": "Сданорешений", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 367.328125, + "right": 384.671875, + "top": 326.59375, + "width": 17.34375, + "x": 367.328125, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 367.328125, + "right": 416.21875, + "top": 338.59375, + "width": 48.890625, + "x": 367.328125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 327.59375, + "width": 66.5, + "x": 367.328125, + "y": 327.59375 + }, + "text": "Без проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаорганизаторУчастники 0 Проекты 0 Сданорешений 0 Без проектов0—Открыть →" + }, + { + "view": "organizer-large", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 348.578125, + "top": 292.59375, + "width": 53.75, + "x": 294.828125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Участники", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 412.421875, + "top": 292.59375, + "width": 45.09375, + "x": 367.328125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Проекты", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 294.828125, + "right": 328.734375, + "top": 326.59375, + "width": 33.90625, + "x": 294.828125, + "y": 326.59375 + }, + { + "bottom": 340.59375, + "height": 14, + "left": 328.734375, + "right": 328.734375, + "top": 326.59375, + "width": 0, + "x": 328.734375, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 294.828125, + "right": 341.4375, + "top": 338.59375, + "width": 46.609375, + "x": 294.828125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 327.59375, + "width": 66.5, + "x": 294.828125, + "y": 327.59375 + }, + "text": "Сданорешений", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 367.328125, + "right": 384.671875, + "top": 326.59375, + "width": 17.34375, + "x": 367.328125, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 367.328125, + "right": 416.21875, + "top": 338.59375, + "width": 48.890625, + "x": 367.328125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 327.59375, + "width": 66.5, + "x": 367.328125, + "y": 327.59375 + }, + "text": "Без проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаорганизаторУчастники 987,7 млн Проекты 61 Сданорешений 54 Без проектов190,0%Открыть →" + }, + { + "view": "organizer-yellow", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 348.578125, + "top": 292.59375, + "width": 53.75, + "x": 294.828125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Участники", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 412.421875, + "top": 292.59375, + "width": 45.09375, + "x": 367.328125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Проекты", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 294.828125, + "right": 328.734375, + "top": 326.59375, + "width": 33.90625, + "x": 294.828125, + "y": 326.59375 + }, + { + "bottom": 340.59375, + "height": 14, + "left": 328.734375, + "right": 328.734375, + "top": 326.59375, + "width": 0, + "x": 328.734375, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 294.828125, + "right": 341.4375, + "top": 338.59375, + "width": 46.609375, + "x": 294.828125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 327.59375, + "width": 66.5, + "x": 294.828125, + "y": 327.59375 + }, + "text": "Сданорешений", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 367.328125, + "right": 384.671875, + "top": 326.59375, + "width": 17.34375, + "x": 367.328125, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 367.328125, + "right": 416.21875, + "top": 338.59375, + "width": 48.890625, + "x": 367.328125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 327.59375, + "width": 66.5, + "x": 367.328125, + "y": 327.59375 + }, + "text": "Без проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаорганизаторУчастники 248 Проекты 61 Сданорешений 54 Без проектов4016,1%Открыть →" + }, + { + "view": "organizer-red", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 348.578125, + "top": 292.59375, + "width": 53.75, + "x": 294.828125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Участники", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 412.421875, + "top": 292.59375, + "width": 45.09375, + "x": 367.328125, + "y": 292.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 305.59375, + "height": 12, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Проекты", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 294.828125, + "right": 328.734375, + "top": 326.59375, + "width": 33.90625, + "x": 294.828125, + "y": 326.59375 + }, + { + "bottom": 340.59375, + "height": 14, + "left": 328.734375, + "right": 328.734375, + "top": 326.59375, + "width": 0, + "x": 328.734375, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 294.828125, + "right": 341.4375, + "top": 338.59375, + "width": 46.609375, + "x": 294.828125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 327.59375, + "width": 66.5, + "x": 294.828125, + "y": 327.59375 + }, + "text": "Сданорешений", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 340.59375, + "height": 14, + "left": 367.328125, + "right": 384.671875, + "top": 326.59375, + "width": 17.34375, + "x": 367.328125, + "y": 326.59375 + }, + { + "bottom": 352.59375, + "height": 14, + "left": 367.328125, + "right": 416.21875, + "top": 338.59375, + "width": 48.890625, + "x": 367.328125, + "y": 338.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 351.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 327.59375, + "width": 66.5, + "x": 367.328125, + "y": 327.59375 + }, + "text": "Без проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаорганизаторУчастники 248 Проекты 61 Сданорешений 54 Без проектов9036,3%Открыть →" + }, + { + "view": "expert", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 354.59375, + "height": 14, + "left": 294.828125, + "right": 407.859375, + "top": 340.59375, + "width": 113.03125, + "x": 294.828125, + "y": 340.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 353.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 341.59375, + "width": 139, + "x": 294.828125, + "y": 341.59375 + }, + "text": "До конца оценивания", + "textOverflow": "clip" + }, + { + "font": "12px", + "lines": [ + { + "bottom": 369.59375, + "height": 17, + "left": 294.828125, + "right": 326.5, + "top": 352.59375, + "width": 31.671875, + "x": 294.828125, + "y": 352.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 369.59375, + "height": 16, + "left": 294.828125, + "right": 433.828125, + "top": 353.59375, + "width": 139, + "x": 294.828125, + "y": 353.59375 + }, + "text": "2 дня", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 3 До конца оценивания2 дняОткрыть →" + }, + { + "view": "expert-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 356.59375, + "height": 14, + "left": 294.828125, + "right": 384.28125, + "top": 342.59375, + "width": 89.453125, + "x": 294.828125, + "y": 342.59375 + }, + { + "bottom": 368.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 354.59375, + "width": 48.890625, + "x": 294.828125, + "y": 354.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 367.59375, + "height": 24, + "left": 294.828125, + "right": 433.828125, + "top": 343.59375, + "width": 139, + "x": 294.828125, + "y": 343.59375 + }, + "text": "Нет назначенных проектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 0 Осталосьоценить 0 Нет назначенных проектовОткрыть →" + }, + { + "view": "expert-complete", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 362.59375, + "height": 14, + "left": 294.828125, + "right": 409.125, + "top": 348.59375, + "width": 114.296875, + "x": 294.828125, + "y": 348.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 361.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 349.59375, + "width": 139, + "x": 294.828125, + "y": 349.59375 + }, + "text": "Все проекты оценены", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 0 Все проекты оцененыОткрыть →" + }, + { + "view": "expert-hours", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 354.59375, + "height": 14, + "left": 294.828125, + "right": 407.859375, + "top": 340.59375, + "width": 113.03125, + "x": 294.828125, + "y": 340.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 353.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 341.59375, + "width": 139, + "x": 294.828125, + "y": 341.59375 + }, + "text": "До конца оценивания", + "textOverflow": "clip" + }, + { + "font": "12px", + "lines": [ + { + "bottom": 369.59375, + "height": 17, + "left": 294.828125, + "right": 341.5625, + "top": 352.59375, + "width": 46.734375, + "x": 294.828125, + "y": 352.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 369.59375, + "height": 16, + "left": 294.828125, + "right": 433.828125, + "top": 353.59375, + "width": 139, + "x": 294.828125, + "y": 353.59375 + }, + "text": "5 часов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 3 До конца оценивания5 часовОткрыть →" + }, + { + "view": "expert-minutes", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 354.59375, + "height": 14, + "left": 294.828125, + "right": 407.859375, + "top": 340.59375, + "width": 113.03125, + "x": 294.828125, + "y": 340.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 353.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 341.59375, + "width": 139, + "x": 294.828125, + "y": 341.59375 + }, + "text": "До конца оценивания", + "textOverflow": "clip" + }, + { + "font": "12px", + "lines": [ + { + "bottom": 369.59375, + "height": 17, + "left": 294.828125, + "right": 348.59375, + "top": 352.59375, + "width": 53.765625, + "x": 294.828125, + "y": 352.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 369.59375, + "height": 16, + "left": 294.828125, + "right": 433.828125, + "top": 353.59375, + "width": 139, + "x": 294.828125, + "y": 353.59375 + }, + "text": "25 минут", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 3 До конца оценивания25 минутОткрыть →" + }, + { + "view": "expert-overdue", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 362.59375, + "height": 14, + "left": 294.828125, + "right": 418.15625, + "top": 348.59375, + "width": 123.328125, + "x": 294.828125, + "y": 348.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 361.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 349.59375, + "width": 139, + "x": 294.828125, + "y": 349.59375 + }, + "text": "Срок оценивания истёк", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 3 Срок оценивания истёкОткрыть →" + }, + { + "view": "expert-missing", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 362.59375, + "height": 14, + "left": 294.828125, + "right": 400.5, + "top": 348.59375, + "width": 105.671875, + "x": 294.828125, + "y": 348.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 361.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 349.59375, + "width": 139, + "x": 294.828125, + "y": 349.59375 + }, + "text": "Срок не установлен", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов 7 Осталосьоценить 3 Срок не установленОткрыть →" + }, + { + "view": "expert-open", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 294.828125, + "right": 351.859375, + "top": 292.59375, + "width": 57.03125, + "x": 294.828125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 351.859375, + "right": 351.859375, + "top": 292.59375, + "width": 0, + "x": 351.859375, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 294.828125, + "right": 343.71875, + "top": 304.59375, + "width": 48.890625, + "x": 294.828125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 294.828125, + "right": 361.328125, + "top": 293.59375, + "width": 66.5, + "x": 294.828125, + "y": 293.59375 + }, + "text": "Назначенопроектов", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 306.59375, + "height": 14, + "left": 367.328125, + "right": 418, + "top": 292.59375, + "width": 50.671875, + "x": 367.328125, + "y": 292.59375 + }, + { + "bottom": 306.59375, + "height": 14, + "left": 418, + "right": 418, + "top": 292.59375, + "width": 0, + "x": 418, + "y": 292.59375 + }, + { + "bottom": 318.59375, + "height": 14, + "left": 367.328125, + "right": 409.40625, + "top": 304.59375, + "width": 42.078125, + "x": 367.328125, + "y": 304.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 317.59375, + "height": 24, + "left": 367.328125, + "right": 433.828125, + "top": 293.59375, + "width": 66.5, + "x": 367.328125, + "y": 293.59375 + }, + "text": "Осталосьоценить", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 354.59375, + "height": 14, + "left": 294.828125, + "right": 419.375, + "top": 340.59375, + "width": 124.546875, + "x": 294.828125, + "y": 340.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 353.59375, + "height": 12, + "left": 294.828125, + "right": 433.828125, + "top": 341.59375, + "width": 139, + "x": 294.828125, + "y": 341.59375 + }, + "text": "Свободное оценивание", + "textOverflow": "clip" + }, + { + "font": "12px", + "lines": [ + { + "bottom": 369.59375, + "height": 17, + "left": 294.828125, + "right": 390.140625, + "top": 352.59375, + "width": 95.3125, + "x": 294.828125, + "y": 352.59375 + } + ], + "overflow": "visible", + "rect": { + "bottom": 369.59375, + "height": 16, + "left": 294.828125, + "right": 433.828125, + "top": 353.59375, + "width": 139, + "x": 294.828125, + "y": 353.59375 + }, + "text": "Осталось 2 дня", + "textOverflow": "clip" + }, + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.90625, + "right": 390.75, + "top": 378.578125, + "width": 52.84375, + "x": 337.90625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.90625, + "right": 390.75, + "top": 377.578125, + "width": 52.84375, + "x": 337.90625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Открыть →", + "textOverflow": "clip" + } + ], + "text": "аналитикаэкспертНазначенопроектов — Осталосьоценить — Свободное оцениваниеОсталось 2 дняОткрыть →" + }, + { + "view": "loading", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "", + "textOverflow": "clip" + } + ], + "text": "аналитика " + }, + { + "view": "error", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [ + { + "bottom": 391.578125, + "height": 13, + "left": 337.15625, + "right": 391.5, + "top": 378.578125, + "width": 54.34375, + "x": 337.15625, + "y": 378.578125 + }, + { + "bottom": 391.578125, + "height": 14, + "left": 337.15625, + "right": 391.5, + "top": 377.578125, + "width": 54.34375, + "x": 337.15625, + "y": 377.578125 + } + ], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "Повторить", + "textOverflow": "clip" + } + ], + "text": "аналитика Не удалось загрузитьПовторить" + }, + { + "view": "forbidden", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "footer": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "scale": 1, + "serviceText": [ + { + "font": "10px", + "lines": [], + "overflow": "visible", + "rect": { + "bottom": 395.578125, + "height": 22, + "left": 294.828125, + "right": 433.828125, + "top": 373.578125, + "width": 139, + "x": 294.828125, + "y": 373.578125 + }, + "text": "", + "textOverflow": "clip" + } + ], + "text": "аналитика Нет доступа" + } +] diff --git a/docs/program-role-widget/followup/integration-retry.json b/docs/program-role-widget/followup/integration-retry.json new file mode 100644 index 000000000..37969f22e --- /dev/null +++ b/docs/program-role-widget/followup/integration-retry.json @@ -0,0 +1,29 @@ +{ + "fault": "Injected HTTP 503 in local middleware; all other requests use real backend", + "before": { + "rect": { + "bottom": 436.578125, + "height": 140.984375, + "left": 278.328125, + "right": 435.328125, + "top": 295.59375, + "width": 157, + "x": 278.328125, + "y": 295.59375 + }, + "text": "аналитика Не удалось загрузитьПовторить" + }, + "after": { + "rect": { + "bottom": 436.578125, + "height": 140.984375, + "left": 278.328125, + "right": 435.328125, + "top": 295.59375, + "width": 157, + "x": 278.328125, + "y": 295.59375 + }, + "text": "аналитикаучастникКейс не выбранПроект не поданОтправленПроверкаОценён Создать заявку → " + } +} diff --git a/docs/program-role-widget/followup/responsive.json b/docs/program-role-widget/followup/responsive.json new file mode 100644 index 000000000..8567f38f6 --- /dev/null +++ b/docs/program-role-widget/followup/responsive.json @@ -0,0 +1,96 @@ +[ + { + "width": 1000, + "version": "before", + "about": { + "bottom": 438.78125, + "height": 161.1875, + "left": 197.5, + "right": 337, + "top": 277.59375, + "width": 139.5, + "x": 197.5, + "y": 277.59375 + }, + "card": null, + "dpr": 1, + "fonts": "loaded", + "scale": 1, + "viewport": [1000, 1000] + }, + { + "width": 1000, + "version": "after", + "about": { + "bottom": 438.78125, + "height": 161.1875, + "left": 197.5, + "right": 337, + "top": 277.59375, + "width": 139.5, + "x": 197.5, + "y": 277.59375 + }, + "card": null, + "dpr": 1, + "fonts": "loaded", + "scale": 1, + "viewport": [1000, 1000] + }, + { + "width": 1440, + "version": "before", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 551.15625, + "right": 964.484375, + "top": 262.59375, + "width": 413.328125, + "x": 551.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 365.828125, + "right": 522.828125, + "top": 262.59375, + "width": 157, + "x": 365.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "scale": 1, + "viewport": [1440, 1000] + }, + { + "width": 1440, + "version": "after", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 551.15625, + "right": 964.484375, + "top": 262.59375, + "width": 413.328125, + "x": 551.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 365.828125, + "right": 522.828125, + "top": 262.59375, + "width": 157, + "x": 365.828125, + "y": 262.59375 + }, + "dpr": 1, + "fonts": "loaded", + "scale": 1, + "viewport": [1440, 1000] + } +] diff --git a/docs/program-role-widget/followup/retry.json b/docs/program-role-widget/followup/retry.json new file mode 100644 index 000000000..8ac69c4c1 --- /dev/null +++ b/docs/program-role-widget/followup/retry.json @@ -0,0 +1,28 @@ +{ + "before": { + "rect": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "text": "аналитика Не удалось загрузитьПовторить" + }, + "after": { + "rect": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "text": "аналитикаучастникКейс:Цифровой сервисПроект:StudyFlow✓ОтправленПроверкаОценёнОткрыть →" + } +} diff --git a/docs/program-role-widget/followup/screenshots/after-1000.png b/docs/program-role-widget/followup/screenshots/after-1000.png new file mode 100644 index 000000000..ff712d249 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/after-1000.png differ diff --git a/docs/program-role-widget/followup/screenshots/after-1440.png b/docs/program-role-widget/followup/screenshots/after-1440.png new file mode 100644 index 000000000..035d4f69b Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/after-1440.png differ diff --git a/docs/program-role-widget/followup/screenshots/before-1000.png b/docs/program-role-widget/followup/screenshots/before-1000.png new file mode 100644 index 000000000..3f1da5ab6 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/before-1000.png differ diff --git a/docs/program-role-widget/followup/screenshots/before-1440.png b/docs/program-role-widget/followup/screenshots/before-1440.png new file mode 100644 index 000000000..95901645c Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/before-1440.png differ diff --git a/docs/program-role-widget/followup/screenshots/draft-card.png b/docs/program-role-widget/followup/screenshots/draft-card.png new file mode 100644 index 000000000..d5f860c21 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/draft-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/draft-page.png b/docs/program-role-widget/followup/screenshots/draft-page.png new file mode 100644 index 000000000..501e965ca Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/draft-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/error-card.png b/docs/program-role-widget/followup/screenshots/error-card.png new file mode 100644 index 000000000..bbf276be4 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/error-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/error-page.png b/docs/program-role-widget/followup/screenshots/error-page.png new file mode 100644 index 000000000..b0607c104 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/error-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-card.png b/docs/program-role-widget/followup/screenshots/expert-card.png new file mode 100644 index 000000000..3291bd870 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-complete-card.png b/docs/program-role-widget/followup/screenshots/expert-complete-card.png new file mode 100644 index 000000000..52df0227f Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-complete-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-complete-page.png b/docs/program-role-widget/followup/screenshots/expert-complete-page.png new file mode 100644 index 000000000..7a8610b58 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-complete-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-hours-card.png b/docs/program-role-widget/followup/screenshots/expert-hours-card.png new file mode 100644 index 000000000..4d078d72c Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-hours-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-hours-page.png b/docs/program-role-widget/followup/screenshots/expert-hours-page.png new file mode 100644 index 000000000..23e9fe2d0 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-hours-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-minutes-card.png b/docs/program-role-widget/followup/screenshots/expert-minutes-card.png new file mode 100644 index 000000000..5b22b6db1 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-minutes-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-minutes-page.png b/docs/program-role-widget/followup/screenshots/expert-minutes-page.png new file mode 100644 index 000000000..da556b61a Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-minutes-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-missing-card.png b/docs/program-role-widget/followup/screenshots/expert-missing-card.png new file mode 100644 index 000000000..301e427cc Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-missing-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-missing-page.png b/docs/program-role-widget/followup/screenshots/expert-missing-page.png new file mode 100644 index 000000000..213384d5c Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-missing-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-open-card.png b/docs/program-role-widget/followup/screenshots/expert-open-card.png new file mode 100644 index 000000000..999aacd1a Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-open-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-open-page.png b/docs/program-role-widget/followup/screenshots/expert-open-page.png new file mode 100644 index 000000000..605831798 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-open-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-overdue-card.png b/docs/program-role-widget/followup/screenshots/expert-overdue-card.png new file mode 100644 index 000000000..df6042be7 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-overdue-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-overdue-page.png b/docs/program-role-widget/followup/screenshots/expert-overdue-page.png new file mode 100644 index 000000000..d09e4f2ee Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-overdue-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-page.png b/docs/program-role-widget/followup/screenshots/expert-page.png new file mode 100644 index 000000000..e3f19af6f Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-zero-card.png b/docs/program-role-widget/followup/screenshots/expert-zero-card.png new file mode 100644 index 000000000..c1b56f8bf Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-zero-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/expert-zero-page.png b/docs/program-role-widget/followup/screenshots/expert-zero-page.png new file mode 100644 index 000000000..ade975c69 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/expert-zero-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/forbidden-card.png b/docs/program-role-widget/followup/screenshots/forbidden-card.png new file mode 100644 index 000000000..f8133b31a Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/forbidden-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/forbidden-page.png b/docs/program-role-widget/followup/screenshots/forbidden-page.png new file mode 100644 index 000000000..9678ff5ab Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/forbidden-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-case-updated.png b/docs/program-role-widget/followup/screenshots/integration-case-updated.png new file mode 100644 index 000000000..a8daf8338 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-case-updated.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-error.png b/docs/program-role-widget/followup/screenshots/integration-error.png new file mode 100644 index 000000000..f24427bf0 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-error.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-evaluated.png b/docs/program-role-widget/followup/screenshots/integration-evaluated.png new file mode 100644 index 000000000..113472ec6 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-evaluated.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-expert-complete.png b/docs/program-role-widget/followup/screenshots/integration-expert-complete.png new file mode 100644 index 000000000..b011ccaca Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-expert-complete.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-expert-zero.png b/docs/program-role-widget/followup/screenshots/integration-expert-zero.png new file mode 100644 index 000000000..d51d559d5 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-expert-zero.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-expert.png b/docs/program-role-widget/followup/screenshots/integration-expert.png new file mode 100644 index 000000000..793cca6aa Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-expert.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-leader.png b/docs/program-role-widget/followup/screenshots/integration-leader.png new file mode 100644 index 000000000..78af30e62 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-leader.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-manager-news.png b/docs/program-role-widget/followup/screenshots/integration-manager-news.png new file mode 100644 index 000000000..c7acb808b Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-manager-news.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-outsider.png b/docs/program-role-widget/followup/screenshots/integration-outsider.png new file mode 100644 index 000000000..cf00b8706 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-outsider.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-participant-zero.png b/docs/program-role-widget/followup/screenshots/integration-participant-zero.png new file mode 100644 index 000000000..bc18dcc5e Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-participant-zero.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-retry-success.png b/docs/program-role-widget/followup/screenshots/integration-retry-success.png new file mode 100644 index 000000000..f00e15ab3 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-retry-success.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-submitted.png b/docs/program-role-widget/followup/screenshots/integration-submitted.png new file mode 100644 index 000000000..e9a9aa692 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-submitted.png differ diff --git a/docs/program-role-widget/followup/screenshots/integration-teammate.png b/docs/program-role-widget/followup/screenshots/integration-teammate.png new file mode 100644 index 000000000..84e30b3f0 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/integration-teammate.png differ diff --git a/docs/program-role-widget/followup/screenshots/loading-card.png b/docs/program-role-widget/followup/screenshots/loading-card.png new file mode 100644 index 000000000..c628b271f Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/loading-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/loading-page.png b/docs/program-role-widget/followup/screenshots/loading-page.png new file mode 100644 index 000000000..67eb519e1 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/loading-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/long-card.png b/docs/program-role-widget/followup/screenshots/long-card.png new file mode 100644 index 000000000..bc1618072 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/long-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/long-focus.png b/docs/program-role-widget/followup/screenshots/long-focus.png new file mode 100644 index 000000000..d58319d96 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/long-focus.png differ diff --git a/docs/program-role-widget/followup/screenshots/long-hover.png b/docs/program-role-widget/followup/screenshots/long-hover.png new file mode 100644 index 000000000..9c0185b05 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/long-hover.png differ diff --git a/docs/program-role-widget/followup/screenshots/long-page.png b/docs/program-role-widget/followup/screenshots/long-page.png new file mode 100644 index 000000000..bb00c9063 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/long-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-card.png b/docs/program-role-widget/followup/screenshots/organizer-card.png new file mode 100644 index 000000000..d68e11dd7 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-large-card.png b/docs/program-role-widget/followup/screenshots/organizer-large-card.png new file mode 100644 index 000000000..4a39d33f2 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-large-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-large-page.png b/docs/program-role-widget/followup/screenshots/organizer-large-page.png new file mode 100644 index 000000000..93fa48037 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-large-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-page.png b/docs/program-role-widget/followup/screenshots/organizer-page.png new file mode 100644 index 000000000..4107ed1ac Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-red-card.png b/docs/program-role-widget/followup/screenshots/organizer-red-card.png new file mode 100644 index 000000000..30af1fc23 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-red-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-red-page.png b/docs/program-role-widget/followup/screenshots/organizer-red-page.png new file mode 100644 index 000000000..a0b908fdf Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-red-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-yellow-card.png b/docs/program-role-widget/followup/screenshots/organizer-yellow-card.png new file mode 100644 index 000000000..40bc60755 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-yellow-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-yellow-page.png b/docs/program-role-widget/followup/screenshots/organizer-yellow-page.png new file mode 100644 index 000000000..f6193e8d6 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-yellow-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-zero-card.png b/docs/program-role-widget/followup/screenshots/organizer-zero-card.png new file mode 100644 index 000000000..15a944f23 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-zero-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/organizer-zero-page.png b/docs/program-role-widget/followup/screenshots/organizer-zero-page.png new file mode 100644 index 000000000..9b2b10996 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/organizer-zero-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-card.png b/docs/program-role-widget/followup/screenshots/participant-card.png new file mode 100644 index 000000000..ab4c9389c Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-evaluated-card.png b/docs/program-role-widget/followup/screenshots/participant-evaluated-card.png new file mode 100644 index 000000000..a61e53c6c Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-evaluated-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-evaluated-page.png b/docs/program-role-widget/followup/screenshots/participant-evaluated-page.png new file mode 100644 index 000000000..a14976d03 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-evaluated-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-no-case-card.png b/docs/program-role-widget/followup/screenshots/participant-no-case-card.png new file mode 100644 index 000000000..3305ec418 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-no-case-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-no-case-page.png b/docs/program-role-widget/followup/screenshots/participant-no-case-page.png new file mode 100644 index 000000000..1c48f0962 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-no-case-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-page.png b/docs/program-role-widget/followup/screenshots/participant-page.png new file mode 100644 index 000000000..beb1c15cd Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-submitted-card.png b/docs/program-role-widget/followup/screenshots/participant-submitted-card.png new file mode 100644 index 000000000..8d20b0f85 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-submitted-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-submitted-page.png b/docs/program-role-widget/followup/screenshots/participant-submitted-page.png new file mode 100644 index 000000000..662d96bac Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-submitted-page.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-zero-card.png b/docs/program-role-widget/followup/screenshots/participant-zero-card.png new file mode 100644 index 000000000..a7f834d77 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-zero-card.png differ diff --git a/docs/program-role-widget/followup/screenshots/participant-zero-page.png b/docs/program-role-widget/followup/screenshots/participant-zero-page.png new file mode 100644 index 000000000..0014bdeb0 Binary files /dev/null and b/docs/program-role-widget/followup/screenshots/participant-zero-page.png differ diff --git a/docs/program-role-widget/nan-diagnostic/README.md b/docs/program-role-widget/nan-diagnostic/README.md new file mode 100644 index 000000000..84e72d1ab --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/README.md @@ -0,0 +1,92 @@ + + +# Диагностика PUT /projects/NaN/ — 14.09.2026 + +Ошибка воспроизведена на точном Angular base и head, в том числе при новом входе из виджета. В проверенных сценариях #348 её не усиливает. Выбран вариант Б из задания: код редактора не меняется, подготовлена [отдельная задача P1](editor-task.md). **Несохранение удаления презентации и ложное сообщение об успехе — препятствие для дальнейшего релиза редактора.** Это отдельный существующий дефект, а не исправление или регрессия виджета. + +## Версии и изоляция + +| Репозиторий | Base / origin/dev при проверке | Проверенный head | +| ------------------- | ------------------------------------------ | ------------------------------------------ | +| Angular, Draft #348 | `99c8813a66f89560a946eab7d1de73ab2925d0f5` | `239e3a5eafe653291daf95930ecac9824314f365` | +| Backend, Draft #742 | `ed5244bd4a098bd0f1cee0f5e380dd67bdd61a96` | `3d84c7f4090985e4f42a13654e8fb05856f65cb3` | + +`git fetch origin`, локальные/удалённые SHA и состояние обоих Draft PR проверены. Рабочие деревья перед диагностикой чистые. Base запущен из отдельного detached worktree. Этот follow-up добавляет только документацию и артефакты; проверенный production-код Angular остаётся кодом `239e3a5…`. Backend не изменён. + +Оба Angular используют Node **24.18.0**, npm **11.16.0**, один неизменённый `node_modules` через junction. Head обслуживался на `localhost:4314`, base на `localhost:4315`, один backend head на `localhost:8010`. Только новая локальная PostgreSQL БД `procollab_widget_nan_20260914`, без DEV/PROD данных. + +Перед каждым из семи прогонов восстанавливались одинаковые синтетические данные: лидер 11, член команды 12, программа 21, проект **31**, связь **73**, системный `case`, исходные название/описание, `draft=true`, `submitted=false`, исходный кейс. В файловой паре дополнительно восстанавливались один и тот же `UserFile`, URL и физический тестовый файл. Связь не сдавалась. Для обычного поля использовано новое непустое название, для кейса — второй явно выбранный вариант. + +Наблюдение добавлено отдельной локальной точкой входа Angular, одинаковой на base/head: обёртки оригинальных методов логируют arguments/stack, `ActivatedRoute`, XHR send/loadend, уничтожение компонента/подписок и события виджета. Аргументы и возвращаемые значения оригинальных вызовов сохранены; ID, обработчики ошибок и запросы не подменялись. Production-файлы не редактировались. Локальные environment/index исключают внешние интеграции и направляют API в 8010. Для удаления файла только внешний CDN-транспорт заменён локальным файловым хранилищем; реальные `FileView`, авторизация, удаление `UserFile` и обновление `Project` работают на backend head. Живой CDN не проверялся. + +## Причина и initiator + +Место появления неверного ID: [project-form-autosave.service.ts:47](../../../projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts) в проверенной версии (путь из корня репозитория: `projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts`). + +```ts +const projectId = Number(this.route.snapshot.params["projectId"]); +``` + +Сервис предоставлен в root и внедряет root `ActivatedRoute`. В реальном runtime у него `route === route.root`, `params={}`. ID существует на дочернем маршруте `office → "" → projects → :projectId/edit`, где `params={projectId:"31"}`. Поэтому получается `Number(undefined) === NaN`. Это не путаница с `programLinkId=73` и не отсутствие разрешённого проекта. + +Цепочка при открытии, подтверждённая стеком и source maps: + +1. `ProjectEditComponent.ngAfterViewInit` (`edit.component.ts:146`). +2. `ProjectsEditInfoService.loadProgramTagsAndProject` → `route.data.subscribe` (`projects-edit-info.service.ts:381,390`). +3. `ProjectFormService.initializeProjectData` → `projectForm.patchValue` (`project-form.service.ts:63`), с обычным `emitEvent=true`. +4. Инициализация пустой `presentationAddress` попадает в `valueChanges → filter(value => !value) → concatMap` cleanup-autosave; он не отличает заполнение формы из API от пользовательского удаления. +5. `ProjectFormAutosaveService:47,50` → `UpdateFormUseCase.execute:19` → `ProjectRepository.update:132` → `ProjectHttpAdapter.putUpdate:34` → `ApiService.put` → XHR `PUT /projects/NaN/`, body `{"presentation_address":"","draft":true}`, HTTP 404. + +При настоящем удалении цепочка начинается с `UploadFileComponent.onRemove`, успешного `DELETE /files/?link=…`, затем `onChange("")` (`upload-file.component.ts:158`) и той же подписки autosave. После повторного открытия уже удалённого файла DELETE возвращает 404; существующий error-handler тоже очищает control, запуская тот же NaN PUT. + +Сохранены исходные браузерные XHR-стеки (лимит 100 frames), отдельные use-case/adapter стеки и их source-map frames: [head — открытие](head-existing-initiator.txt), [base — открытие](base-existing-initiator.txt), [head — удаление](head-file-initiator.txt), [base — удаление](base-file-initiator.txt). XHR-стек занят глубокой RxJS-цепочкой; отдельные стеки границ use-case/adapter показывают исходные методы приложения и связываются по времени, ID и payload. Приложены [точный диагностический observer](observer.ts.txt) и [выдержка backend-лога DELETE](file-delete-results.txt); это артефакты документации, не подключённый код приложения. + +## Сценарии и сохранение + +Все действия выполнены через реальный UI лидером проекта / участником программы. После открытия, изменения и выхода использованы одинаковые **10-секундные окна наблюдения**. API читался отдельным авторизованным запросом после этих окон; фактические абсолютные timestamps сохранены. Время между инструментальными шагами не было побайтно одинаковым. В head-existing/head-case штатный refresh обработал 401 истёкшего токена перед успешным сохранением полей; при head-file он обработал 401 DELETE. Это отмечено в evidence и не скрыто как одинаковая полная сетевая последовательность. + +| Прогон | Вход и полный маршрут редактора | NaN / результат | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| head-widget | `/office/program/21` → виджет «Открыть» → `/office/projects/31?programLinkId=73` → существующее «редактировать» → `/office/projects/31/edit?editingStep=main` | 1 PUT при инициализации пустой презентации; после смены названия новых PUT нет; явное сохранение `/projects/31/` 200 | +| head-existing | `/office/projects/31` → «редактировать» → `/office/projects/31/edit?editingStep=main` | Те же 1 NaN при открытии и успешное явное сохранение названия | +| base-existing | Тот же существующий путь, порт 4315 | Те же 1 NaN при открытии и успешное явное сохранение названия | +| head-case | `/office/program/21` → существующее «перейти в заявку» → `/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73` | 1 NaN при инициализации основной формы; выбранный кейс сохраняется через `/programs/partner-program-projects/73/fields/` 200 | +| base-case | Тот же существующий путь и query, порт 4315 | Те же 1 NaN и успешное сохранение кейса связи 73 | +| head-file | Существующий путь на main; презентация и обложка изначально непустые | 0 NaN при открытии, по 1 NaN на каждое из двух удалений; очистка ссылки не сохраняется даже явной кнопкой | +| base-file | Тот же путь и исходный физический файл | Те же запросы и та же несохранённая очистка | + +Вход через карточку не создаёт нового editor-route: существующая ссылка «редактировать» снимает query `programLinkId` с detail; текущий legacy-контекст в этом сценарии разрешает связь 73. Канонический вход программы сохраняет `programLinkId=73` в editor query. NaN в обоих случаях возникает из root params, до сохранения кейса. + +Повторные GET `/projects/31/` и `/programs/partner-program-projects/73/fields/` подтвердили: + +- Название: после изменения и ожидания исходное; после «сохранить черновик», выхода и ожидания — новое. Автосохранение обычного названия не предусмотрено данным binding. +- Кейс: до явного сохранения исходный, после него — новый, именно на связи 73. NaN не является запросом сохранения кейса. +- Презентация: до удаления URL существует, GET файла 200. После удаления control пустой, DELETE 204, GET файла 404, но GET проекта сохраняет старый URL. После ухода и повторного открытия он остаётся тем же; поле показывает **«Файл успешно загружен»**. +- Повторная очистка и **явное сохранение** показывают **«данные успешно сохранены»** и получают 200 для `/projects/31/`, однако `presentation_address` отсутствует в payload, а ответ и последующий GET по-прежнему содержат удалённый URL. Причина: `ProjectFormService.getFormValue` (`project-form.service.ts:132`) вызывает `stripNullish`; `utils/stripNull.ts:26` удаляет пустые строки из payload. В итоге NaN PUT был единственной попыткой записать очистку поля. Это подтверждённая потеря изменения и ложный общий успех для данного сценария, а не предполагаемая потеря любых данных. + +[Все 7 timelines, payload, route trees и 23 контрольных чтения API](evidence.json). [Состояние после повторного открытия на head](head-file-reopened.png) и [на base](base-file-reopened.png): оба скриншота viewport 1280 × 720, показывают тот же удалённый файл как загруженный. У head во время получения полного снимка инструмент изменил viewport; для восстановления отображения сделан дополнительный reload. Он не изменял данные и не создал PUT; итоговый артефакт — обычный viewport-снимок. Вывод об удалении установлен до этого по API и повторён на base. + +## Lifecycle и связь с виджетом + +Cleanup-autosave не использует debounce/таймер; `concatMap` стартует на emission, включая начальный `patchValue`. Очередь `project-autosave-queue` была пустой во всех загрузках. Код constructor/online flush прочитан: это отдельный root callback; offline/reconnect с непустой очередью в этом задании не моделировался и не объявляется проверенным. + +При уходе через навигацию и после явного сохранения зафиксированы `ProjectEditComponent.ngOnDestroy` и уничтожение двух binding активной формы через `takeUntilDestroyed(destroyRef)`. В каждом 10-секундном окне после destroy — **0 новых PUT**. Это проверка подписок формы редактора, а не утверждение об уничтожении root-сервисов и всех созданных в приложении форм. Указанная ошибка не вызвана поздним callback после уничтожения редактора в этих сценариях; обобщение на произвольные сетевые гонки не делается. + +На head `ProgramWidgetChanged` происходит после успешного сохранения программных полей, позже NaN. Ни одного дополнительного NaN после этого события не было. На base, где нового события/виджета нет, причина, payload и влияние на сохранение те же. Подписка очистки файлов не зависит от EventBus виджета. + +## Выполненные проверки и ограничения + +Две локальные diagnostic-сборки **PASS** (Angular development / strict compilation): + +```sh +# В head worktree; временный entrypoint наблюдает оригинальные методы. +npm exec -- ng build social_platform --configuration development --browser tmp/nan-trace.ts --ts-config tmp/nan-tsconfig.json --index tmp/nan-index.html --output-path tmp/nan-head +# В detached worktree точного base, те же entrypoint/env/dependencies. +npm exec -- ng build social_platform --configuration development --browser tmp/nan-trace.ts --ts-config tmp/nan-tsconfig.json --index tmp/nan-index.html --output-path tmp/nan-base +``` + +Проверка собранных логов: 7 прогонов, 23 GET-checkpoints, ожидаемое число NaN/404, root params и leaf ID, пустая очередь, отсутствие PUT в окнах после destroy, отсутствие `presentation_address` в явном файловом save — **PASS**. Это диагностика уже существующей ошибки, не регрессионный тест исправления. + +Production-код не менялся, поэтому targeted/full suite, lint:ts и production build заново не запускались. Предыдущие результаты относятся к тому же коду `239e3a5…`: targeted 349 PASS; full head 1560 / base 1489 тестов прошли, оба процесса exit 1 из-за известного ngx-autosize teardown. Это не объявляется зелёным full suite; его расследование не повторялось. [Команды и прежние точные результаты](../followup/README.md#сравнение-ошибки-full-suite). + +В этом follow-up проверены scoped Prettier для изменённых Markdown/JSON и `git diff --check`. Глобальный pre-commit с `stylelint --fix` по всем SCSS не запускался для коммита документации, чтобы не форматировать посторонний код. React/current_application/права/композиция виджета/новости и backend production-файлы не изменялись. Merge, deploy и действия с PROD не выполнялись. [Отдельная задача редактора](editor-task.md) подготовлена без создания нового PR или автоматического исправления данных. diff --git a/docs/program-role-widget/nan-diagnostic/base-existing-initiator.txt b/docs/program-role-widget/nan-diagnostic/base-existing-initiator.txt new file mode 100644 index 000000000..a15f1717c --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/base-existing-initiator.txt @@ -0,0 +1,419 @@ +Captured XHR.send initiator, observer wrapper preserves the original call. +UTC: 2026-09-14T19:17:46.729Z +Editor: http://localhost:4315/office/projects/31/edit?editingStep=main +Request: {"method":"PUT","url":"http://localhost:8010/projects/NaN/","body":"{\"presentation_address\":\"\",\"draft\":true}"} + +Original browser stack: +Error: xhr-send + at trace (http://localhost:4315/main.js:10334:165) + at XMLHttpRequest.send (http://localhost:4315/main.js:10387:5) + at _Observable._subscribe (http://localhost:4315/chunk-WMEL3WYA.js:2062:13) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at source.subscribe.isComplete (http://localhost:4315/chunk-ZP5P7HJ4.js:2809:45) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at _Observable._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1816:18) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2805:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2847:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2398:23 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2579:14 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2579:14 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:40) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at _Observable._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1816:18) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at mergeInternals (http://localhost:4315/chunk-ZP5P7HJ4.js:2184:10) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2200:42 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at subscribeForRetry (http://localhost:4315/chunk-ZP5P7HJ4.js:2646:25) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2684:5 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2530:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2565:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2847:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + +Source map frames (original order): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:68:5 +../../../procollab/node_modules/@angular/common/fesm2022/module.mjs:2769:13 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:14:51 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../../../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../../../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:10:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/catchError.js:9:27 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:19:44 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:14:57 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../../../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../../../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:50:12 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeMap.js:13:44 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/filter.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:24:35 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:65:13 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/take.js:10:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/throwIfEmpty.js:7:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 + +update-use-case: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: update-use-case + at trace (http://localhost:4315/main.js:10334:165) + at UpdateFormUseCase.execute (http://localhost:4315/main.js:10358:3) + at http://localhost:4315/chunk-ZSGD6X4R.js:87:37 + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:15) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:1209:20 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at EventEmitter_.next (http://localhost:4315/chunk-ZP5P7HJ4.js:1202:5) + at EventEmitter_.emit (http://localhost:4315/chunk-ZP5P7HJ4.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4315/chunk-XUER7G37.js:2110:25) + at FormControl2.setValue (http://localhost:4315/chunk-XUER7G37.js:3269:10) + at FormControl2.patchValue (http://localhost:4315/chunk-XUER7G37.js:3272:10) + at http://localhost:4315/chunk-XUER7G37.js:2538:17 + at Array.forEach () + at FormGroup.patchValue (http://localhost:4315/chunk-XUER7G37.js:2535:24) + at _ProjectFormService.initializeProjectData (http://localhost:4315/chunk-ZSGD6X4R.js:211:22) + at ProjectFormService.initializeProjectData (http://localhost:4315/main.js:10354:23) + at Object.next (http://localhost:4315/chunk-YXGISKNY.js:1433:31) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at BehaviorSubject._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1320:40) + at BehaviorSubject._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at BehaviorSubject._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1249:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at BehaviorSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at SafeSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2824:34 + at SafeSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at _ProjectsEditInfoService.loadProgramTagsAndProject (http://localhost:4315/chunk-YXGISKNY.js:1432:86) + at _ProjectEditComponent.ngAfterViewInit (http://localhost:4315/chunk-SI5XYAQR.js:416:34) + at callHookInternal (http://localhost:4315/chunk-ZP5P7HJ4.js:6042:10) + at callHook (http://localhost:4315/chunk-ZP5P7HJ4.js:6057:7) + at callHooks (http://localhost:4315/chunk-ZP5P7HJ4.js:6031:9) + at executeInitAndCheckHooks (http://localhost:4315/chunk-ZP5P7HJ4.js:6000:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11343:11) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInComponent (http://localhost:4315/chunk-ZP5P7HJ4.js:11412:3) + at detectChangesInChildComponents (http://localhost:4315/chunk-ZP5P7HJ4.js:11467:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11323:7) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInComponent (http://localhost:4315/chunk-ZP5P7HJ4.js:11412:3) + at detectChangesInChildComponents (http://localhost:4315/chunk-ZP5P7HJ4.js:11467:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11323:7) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewWhileDirty (http://localhost:4315/chunk-ZP5P7HJ4.js:11208:5) + at detectChangesInternal (http://localhost:4315/chunk-ZP5P7HJ4.js:11197:5) + at _ApplicationRef.synchronizeOnce (http://localhost:4315/chunk-ZP5P7HJ4.js:17317:9) + at _ApplicationRef.synchronize (http://localhost:4315/chunk-ZP5P7HJ4.js:17280:12) + at _ApplicationRef.tickImpl (http://localhost:4315/chunk-ZP5P7HJ4.js:17248:12) + at _ApplicationRef._tick (http://localhost:4315/chunk-ZP5P7HJ4.js:17237:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:23433:21 + at NoopNgZone.run (http://localhost:4315/chunk-ZP5P7HJ4.js:9803:15) + at _ChangeDetectionSchedulerImpl.tick (http://localhost:4315/chunk-ZP5P7HJ4.js:23431:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:23394:102 + at http://localhost:4315/chunk-ZP5P7HJ4.js:9493:5 + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:40:3 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/api/project/facades/edit/project-form.service.ts:63:22 +tmp/nan-trace.ts:36:23 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:390:35 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:381:8 +projects/social_platform/src/app/ui/pages/projects/edit/edit.component.ts:146:34 + +http-adapter: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: http-adapter + at trace (http://localhost:4315/main.js:10334:165) + at ProjectHttpAdapter.putUpdate (http://localhost:4315/main.js:10363:3) + at _ProjectRepository.update (http://localhost:4315/main.js:8885:32) + at _UpdateFormUseCase.execute (http://localhost:4315/chunk-ZSGD6X4R.js:51:39) + at UpdateFormUseCase.execute (http://localhost:4315/main.js:10359:26) + at http://localhost:4315/chunk-ZSGD6X4R.js:87:37 + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:15) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:1209:20 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at EventEmitter_.next (http://localhost:4315/chunk-ZP5P7HJ4.js:1202:5) + at EventEmitter_.emit (http://localhost:4315/chunk-ZP5P7HJ4.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4315/chunk-XUER7G37.js:2110:25) + at FormControl2.setValue (http://localhost:4315/chunk-XUER7G37.js:3269:10) + at FormControl2.patchValue (http://localhost:4315/chunk-XUER7G37.js:3272:10) + at http://localhost:4315/chunk-XUER7G37.js:2538:17 + at Array.forEach () + at FormGroup.patchValue (http://localhost:4315/chunk-XUER7G37.js:2535:24) + at _ProjectFormService.initializeProjectData (http://localhost:4315/chunk-ZSGD6X4R.js:211:22) + at ProjectFormService.initializeProjectData (http://localhost:4315/main.js:10354:23) + at Object.next (http://localhost:4315/chunk-YXGISKNY.js:1433:31) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at BehaviorSubject._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1320:40) + at BehaviorSubject._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at BehaviorSubject._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1249:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at BehaviorSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at SafeSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2824:34 + at SafeSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at _ProjectsEditInfoService.loadProgramTagsAndProject (http://localhost:4315/chunk-YXGISKNY.js:1432:86) + at _ProjectEditComponent.ngAfterViewInit (http://localhost:4315/chunk-SI5XYAQR.js:416:34) + at callHookInternal (http://localhost:4315/chunk-ZP5P7HJ4.js:6042:10) + at callHook (http://localhost:4315/chunk-ZP5P7HJ4.js:6057:7) + at callHooks (http://localhost:4315/chunk-ZP5P7HJ4.js:6031:9) + at executeInitAndCheckHooks (http://localhost:4315/chunk-ZP5P7HJ4.js:6000:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11343:11) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInComponent (http://localhost:4315/chunk-ZP5P7HJ4.js:11412:3) + at detectChangesInChildComponents (http://localhost:4315/chunk-ZP5P7HJ4.js:11467:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11323:7) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4315/chunk-ZP5P7HJ4.js:11389:7) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11289:5) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4315/chunk-ZP5P7HJ4.js:11419:3) + at detectChangesInComponent (http://localhost:4315/chunk-ZP5P7HJ4.js:11412:3) + at detectChangesInChildComponents (http://localhost:4315/chunk-ZP5P7HJ4.js:11467:5) + at refreshView (http://localhost:4315/chunk-ZP5P7HJ4.js:11323:7) + at detectChangesInView (http://localhost:4315/chunk-ZP5P7HJ4.js:11436:5) + at detectChangesInViewWhileDirty (http://localhost:4315/chunk-ZP5P7HJ4.js:11208:5) + at detectChangesInternal (http://localhost:4315/chunk-ZP5P7HJ4.js:11197:5) + at _ApplicationRef.synchronizeOnce (http://localhost:4315/chunk-ZP5P7HJ4.js:17317:9) + at _ApplicationRef.synchronize (http://localhost:4315/chunk-ZP5P7HJ4.js:17280:12) + at _ApplicationRef.tickImpl (http://localhost:4315/chunk-ZP5P7HJ4.js:17248:12) + at _ApplicationRef._tick (http://localhost:4315/chunk-ZP5P7HJ4.js:17237:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:23433:21 + at NoopNgZone.run (http://localhost:4315/chunk-ZP5P7HJ4.js:9803:15) + at _ChangeDetectionSchedulerImpl.tick (http://localhost:4315/chunk-ZP5P7HJ4.js:23431:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:23394:102 + at http://localhost:4315/chunk-ZP5P7HJ4.js:9493:5 + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:45:3 +projects/social_platform/src/app/infrastructure/repository/project/project.repository.ts:132:32 +projects/social_platform/src/app/api/project/use-cases/update-form.use-case.ts:19:39 +tmp/nan-trace.ts:41:26 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/api/project/facades/edit/project-form.service.ts:63:22 +tmp/nan-trace.ts:36:23 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:390:35 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:381:8 +projects/social_platform/src/app/ui/pages/projects/edit/edit.component.ts:146:34 diff --git a/docs/program-role-widget/nan-diagnostic/base-file-initiator.txt b/docs/program-role-widget/nan-diagnostic/base-file-initiator.txt new file mode 100644 index 000000000..039c2da3f --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/base-file-initiator.txt @@ -0,0 +1,343 @@ +Captured XHR.send initiator, observer wrapper preserves the original call. +UTC: 2026-09-14T19:33:13.940Z +Editor: http://localhost:4315/office/projects/31/edit?editingStep=main +Request: {"method":"PUT","url":"http://localhost:8010/projects/NaN/","body":"{\"presentation_address\":\"\",\"draft\":true}"} + +Original browser stack: +Error: xhr-send + at trace (http://localhost:4315/main.js:10334:165) + at XMLHttpRequest.send (http://localhost:4315/main.js:10387:5) + at _Observable._subscribe (http://localhost:4315/chunk-WMEL3WYA.js:2062:13) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at source.subscribe.isComplete (http://localhost:4315/chunk-ZP5P7HJ4.js:2809:45) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at _Observable._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1816:18) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2805:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2847:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2398:23 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2579:14 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2579:14 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:40) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at _Observable._subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:1816:18) + at _Observable._trySubscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:949:19) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:113 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at mergeInternals (http://localhost:4315/chunk-ZP5P7HJ4.js:2184:10) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2200:42 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at subscribeForRetry (http://localhost:4315/chunk-ZP5P7HJ4.js:2646:25) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2684:5 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2530:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2565:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2847:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at _Observable.subscribe (http://localhost:4315/chunk-ZP5P7HJ4.js:941:5) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2048:12 + at OperatorSubscriber. (http://localhost:4315/chunk-ZP5P7HJ4.js:1013:18) + at http://localhost:4315/chunk-ZP5P7HJ4.js:943:42 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + +Source map frames (original order): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:68:5 +../../../procollab/node_modules/@angular/common/fesm2022/module.mjs:2769:13 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:14:51 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../../../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../../../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:10:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/catchError.js:9:27 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:19:44 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:14:57 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../../../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../../../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:50:12 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeMap.js:13:44 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/filter.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:24:35 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:65:13 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/take.js:10:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/throwIfEmpty.js:7:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../../../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../../../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../../../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 + +update-use-case: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: update-use-case + at trace (http://localhost:4315/main.js:10334:165) + at UpdateFormUseCase.execute (http://localhost:4315/main.js:10358:3) + at http://localhost:4315/chunk-ZSGD6X4R.js:87:37 + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:15) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:1209:20 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at EventEmitter_.next (http://localhost:4315/chunk-ZP5P7HJ4.js:1202:5) + at EventEmitter_.emit (http://localhost:4315/chunk-ZP5P7HJ4.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4315/chunk-XUER7G37.js:2110:25) + at FormControl2.setValue (http://localhost:4315/chunk-XUER7G37.js:3269:10) + at updateControl (http://localhost:4315/chunk-XUER7G37.js:2829:11) + at _UploadFileComponent.onChange (http://localhost:4315/chunk-XUER7G37.js:2817:40) + at Object.next (http://localhost:4315/chunk-EZFPE73M.js:313:14) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2567:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2532:20 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2650:20 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at innerFrom.subscribe.innerComplete (http://localhost:4315/chunk-ZP5P7HJ4.js:2161:20) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at source.subscribe.isUnsub (http://localhost:4315/chunk-ZP5P7HJ4.js:2850:18) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4315/chunk-ZP5P7HJ4.js:2809:137) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at XMLHttpRequest.onLoad (http://localhost:4315/chunk-WMEL3WYA.js:1978:22) + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:40:3 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/ui/primitives/upload-file/upload-file.component.ts:158:16 + +http-adapter: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: http-adapter + at trace (http://localhost:4315/main.js:10334:165) + at ProjectHttpAdapter.putUpdate (http://localhost:4315/main.js:10363:3) + at _ProjectRepository.update (http://localhost:4315/main.js:8885:32) + at _UpdateFormUseCase.execute (http://localhost:4315/chunk-ZSGD6X4R.js:51:39) + at UpdateFormUseCase.execute (http://localhost:4315/main.js:10359:26) + at http://localhost:4315/chunk-ZSGD6X4R.js:87:37 + at doInnerSub (http://localhost:4315/chunk-ZP5P7HJ4.js:2156:15) + at outerNext (http://localhost:4315/chunk-ZP5P7HJ4.js:2151:54) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:1209:20 + at errorContext (http://localhost:4315/chunk-ZP5P7HJ4.js:738:5) + at EventEmitter_.next (http://localhost:4315/chunk-ZP5P7HJ4.js:1202:5) + at EventEmitter_.emit (http://localhost:4315/chunk-ZP5P7HJ4.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4315/chunk-XUER7G37.js:2110:25) + at FormControl2.setValue (http://localhost:4315/chunk-XUER7G37.js:3269:10) + at updateControl (http://localhost:4315/chunk-XUER7G37.js:2829:11) + at _UploadFileComponent.onChange (http://localhost:4315/chunk-XUER7G37.js:2817:40) + at Object.next (http://localhost:4315/chunk-EZFPE73M.js:313:14) + at ConsumerObserver.next (http://localhost:4315/chunk-ZP5P7HJ4.js:825:25) + at SafeSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at SafeSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2567:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2532:20 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2650:20 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2348:124 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at innerFrom.subscribe.innerComplete (http://localhost:4315/chunk-ZP5P7HJ4.js:2161:20) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at http://localhost:4315/chunk-ZP5P7HJ4.js:2049:18 + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:796:22) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at source.subscribe.isUnsub (http://localhost:4315/chunk-ZP5P7HJ4.js:2850:18) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4315/chunk-ZP5P7HJ4.js:2809:137) + at OperatorSubscriber._next (http://localhost:4315/chunk-ZP5P7HJ4.js:1034:9) + at OperatorSubscriber.next (http://localhost:4315/chunk-ZP5P7HJ4.js:769:12) + at XMLHttpRequest.onLoad (http://localhost:4315/chunk-WMEL3WYA.js:1978:22) + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:45:3 +projects/social_platform/src/app/infrastructure/repository/project/project.repository.ts:132:32 +projects/social_platform/src/app/api/project/use-cases/update-form.use-case.ts:19:39 +tmp/nan-trace.ts:41:26 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/ui/primitives/upload-file/upload-file.component.ts:158:16 diff --git a/docs/program-role-widget/nan-diagnostic/base-file-reopened.png b/docs/program-role-widget/nan-diagnostic/base-file-reopened.png new file mode 100644 index 000000000..b1baf1794 Binary files /dev/null and b/docs/program-role-widget/nan-diagnostic/base-file-reopened.png differ diff --git a/docs/program-role-widget/nan-diagnostic/editor-task.md b/docs/program-role-widget/nan-diagnostic/editor-task.md new file mode 100644 index 000000000..d1c93a8d6 --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/editor-task.md @@ -0,0 +1,39 @@ + + +# P1: восстановить сохранение очистки файлов проекта в Angular-редакторе + +**Отдельная задача редактора, не регрессия #348. Препятствие для дальнейшего релиза редактора:** пользователь удаляет презентацию, файл исчезает, но ссылка проекта не очищается. Даже «сохранить черновик» показывает успех, оставляя ссылку на недоступный файл. Эффект воспроизведён на Angular base `99c8813a66f89560a946eab7d1de73ab2925d0f5` и head `239e3a5eafe653291daf95930ecac9824314f365` при одном backend `3d84c7f4090985e4f42a13654e8fb05856f65cb3`. + +## Воспроизведение + +1. Только локальные Angular/backend и отдельная тестовая БД. Подготовить лидера, доступный для редактирования черновик проекта 31, связь программы 73, непустую презентацию с принадлежащим лидеру `UserFile` и реальным локальным файлом. Оставить обложку и остальные обязательные поля заполненными. +2. Открыть `/office/projects/31`, нажать «редактировать». Маршрут `/office/projects/31/edit?editingStep=main`. При непустых файловых полях начального NaN нет. +3. Нажать корзину презентации. Штатный `DELETE /files/?link=…` возвращает 204, поле пустое. Единственная попытка записать очистку — `PUT /projects/NaN/`, body `{"presentation_address":"","draft":true}`, 404. +4. Через 10 секунд перечитать проект и файл: проект содержит прежний URL, файл возвращает 404. Уйти через «проекты», ждать 10 секунд, повторно открыть редактор. Поле показывает «Файл успешно загружен» по устаревшему URL. +5. Повторно очистить поле и нажать «сохранить черновик». DELETE уже удалённого файла возвращает 404, существующий обработчик всё равно очищает control. Снова NaN PUT. Явный PUT `/projects/31/` возвращает 200, UI показывает «данные успешно сохранены», но payload не содержит `presentation_address`. Последующий GET всё ещё содержит старый URL. +6. Восстановить исходные данные/файл и повторить на точном base. Результат тот же. Новый виджет не нужен для воспроизведения. + +Дополнительный простой сценарий фонового запроса: открыть тот же редактор с изначально пустой презентацией — начальный `patchValue` запускает такой же NaN PUT без действий пользователя. В этом варианте запрос лишний, а изменение обычного непустого названия и кейса успешно сохраняется явной кнопкой. + +## Установленная причина + +- Root `ProjectFormAutosaveService` читает `projectId` из root `ActivatedRoute.params={}` (`project-form-autosave.service.ts:47`), хотя ID 31 лежит на leaf `:projectId/edit`. Получается `Number(undefined)`. +- Binding реагирует и на начальную загрузку пустого файла (`ProjectFormService.initializeProjectData`, `patchValue`), и на пользовательское удаление. Неверный запрос не имеет видимого пользователю состояния ошибки; 404 не попадает в очередь сетевых ошибок. +- Общий явный save вызывает `getFormValue → stripNullish`, который исключает пустую строку. Поэтому он не дублирует неудачную очистку и не восстанавливает согласованность ссылки/файла. +- Backend удаляет файл и `UserFile` отдельно от URL в `Project`. Проверенный локальный CDN-транспорт удалял физический файл; реальные авторизация и модели backend не подменялись. Production CDN и его восстановление не проверялись. + +## Требования к отдельному исправлению + +Передать в cleanup-autosave проверенный ID редактируемого проекта из соответствующего контекста; не подставлять 0/первый ID и не маскировать пропуск сохранения. Отделить инициализацию формы от пользовательской очистки. Сохранять намеренную очистку полей в явном save, не меняя глобальную семантику `stripNullish` для чужих форм без анализа. Обеспечить согласованное удаление ссылки/файла и корректную обратную связь об ошибке; не отключать autosave целиком. Точные изменения порядка операций и компенсации выбрать при реализации и проверить на отказах. + +Не ремонтировать чужие данные и не менять React, current_application, права лидера/участника, программные связи, правила подачи или виджет. Реальная браузерная проверка в этой диагностике выполнена для презентации; аналогичный binding обложки виден в коде, но отдельное удаление обложки ещё требуется проверить. + +## Приёмка и регрессионные проверки + +- Реальная вложенная маршрутизация и DI-scope в тесте: правильный ID для первого/следующего проекта, разные projectId/programLinkId; начальная загрузка пустых файлов не отправляет cleanup PUT. Не ограничиваться mock ActivatedRoute с ID прямо в root. +- Удаление презентации и обложки, явное сохранение пустого значения, API-readback после ухода/повторного открытия; ни одной сохранённой ссылки на удалённый файл и ложного сообщения об успехе. +- Отказы DELETE/PUT, offline/reconnect/очередь, смена проекта, уничтожение компонента и поздние ответы: ошибка видима, изменения не теряются, запрос не уходит к другому проекту. +- Существующие сохранение обычного поля, case связи текущей программы и разрешённая сдача работают; права члена команды не расширены. +- Targeted-тесты причины, полный Angular suite, lint и build на окончательной версии. Известную ngx-autosize teardown ошибку отдельно отразить, не подавлять. + +[Диагностика, семь прогонов, исходные стеки, payload, API-readback и скриншоты](README.md). diff --git a/docs/program-role-widget/nan-diagnostic/evidence.json b/docs/program-role-widget/nan-diagnostic/evidence.json new file mode 100644 index 000000000..957060a57 --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/evidence.json @@ -0,0 +1,6915 @@ +{ + "runs": { + "head-widget": { + "nanRequests": 1, + "afterDestroy": [ + { + "time": 1789413269083, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413087608, + "url": "http://localhost:4314/auth/login", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413087719, + "url": "http://localhost:4314/auth/login", + "detail": { + "destination": "/auth/login", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "auth", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "login", + "params": {}, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413095666, + "url": "http://localhost:4314/auth/login", + "detail": { + "tag": "BUTTON", + "text": "Не согласен", + "href": null, + "class": "button text-body-12 button--outline button--big" + } + }, + { + "kind": "ui-click", + "time": 1789413095748, + "url": "http://localhost:4314/auth/login", + "detail": { + "tag": "BUTTON", + "text": "войти", + "href": null, + "class": "button text-body-12 auth__button-typography button--inline button--big" + } + }, + { + "kind": "navigation-start", + "time": 1789413095915, + "url": "http://localhost:4314/auth/login", + "detail": { + "destination": "/office", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "auth", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "login", + "params": {}, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413096022, + "url": "http://localhost:4314/office/program/all", + "detail": { + "destination": "/office", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "all", + "params": {}, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "boot", + "time": 1789413096617, + "url": "http://localhost:4314/office/program/21", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413096929, + "url": "http://localhost:4314/office/program/21", + "detail": { + "destination": "/office/program/21", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413188806, + "url": "http://localhost:4314/office/program/21", + "detail": { + "tag": "A", + "text": "Открыть →", + "href": "/office/projects/31?programLinkId=73", + "class": "ng-star-inserted" + } + }, + { + "kind": "navigation-start", + "time": 1789413188808, + "url": "http://localhost:4314/office/program/21", + "detail": { + "destination": "/office/projects/31?programLinkId=73", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413189489, + "url": "http://localhost:4314/office/projects/31?programLinkId=73", + "detail": { + "destination": "/office/projects/31?programLinkId=73", + "tree": { + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413189648, + "url": "http://localhost:4314/office/projects/31?programLinkId=73", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413189649, + "url": "http://localhost:4314/office/projects/31?programLinkId=73", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": { + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413189940, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413189950, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413189952, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789413189955, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413189957, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413189959, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "control-emission", + "time": 1789413189962, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413190050, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-change", + "time": 1789413237506, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "INPUT", + "type": "text", + "value": "Название после явного сохранения" + } + }, + { + "kind": "ui-click", + "time": 1789413268417, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789413268424, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "widget-event", + "time": 1789413268675, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "type": "ProgramWidgetChanged", + "payload": {}, + "occurredAt": "2026-09-14T19:14:28.675Z" + } + }, + { + "kind": "update-use-case", + "time": 1789413268677, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413268679, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413268681, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Название после явного сохранения\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789413268684, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789413268925, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413268931, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Название после явного сохранения\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"avatar\":null}],\"partners\":[],\"leader\":11,\"draf" + } + }, + { + "kind": "editor-destroy", + "time": 1789413269083, + "url": "http://localhost:4314/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789413269085, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789413269087, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789413269091, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "head-existing": { + "nanRequests": 1, + "afterDestroy": [ + { + "time": 1789413402236, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413339501, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413340137, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413340560, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413340561, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413340862, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413340867, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413340873, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789413340875, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413340877, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413340881, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "control-emission", + "time": 1789413340882, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413340921, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789413401483, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789413401486, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "xhr-end", + "time": 1789413401516, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 401, + "response": "{\"detail\":\"Given token not valid for any token type\",\"code\":\"token_not_valid\",\"messages\":[{\"token_class\":\"AccessToken\",\"token_type\":\"access\",\"message\":\"Token is invalid or expired\"}]}" + } + }, + { + "kind": "xhr-send", + "time": 1789413401644, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "widget-event", + "time": 1789413401775, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "type": "ProgramWidgetChanged", + "payload": {}, + "occurredAt": "2026-09-14T19:16:41.775Z" + } + }, + { + "kind": "update-use-case", + "time": 1789413401776, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413401778, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413401781, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Название после явного сохранения\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789413401783, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789413402088, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413402096, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Название после явного сохранения\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"avatar\":null}],\"partners\":[],\"leader\":11,\"draf" + } + }, + { + "kind": "editor-destroy", + "time": 1789413402236, + "url": "http://localhost:4314/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789413402238, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789413402240, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789413402245, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "base-existing": { + "nanRequests": 1, + "afterDestroy": [ + { + "time": 1789413574202, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413451860, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413452471, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413466346, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "Не согласен", + "href": null, + "class": "button text-body-12 button--outline button--big" + } + }, + { + "kind": "ui-click", + "time": 1789413466426, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413466428, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413466705, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413466718, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413466720, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789413466723, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413466725, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413466729, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "control-emission", + "time": 1789413466731, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413466783, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789413573694, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789413573699, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "update-use-case", + "time": 1789413573836, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413573838, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Название после явного сохранения", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413573840, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Название после явного сохранения\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789413573842, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789413574043, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413574052, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Название после явного сохранения\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"avatar\":null}],\"partners\":[],\"leader\":11,\"draf" + } + }, + { + "kind": "editor-destroy", + "time": 1789413574202, + "url": "http://localhost:4315/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789413574205, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789413574207, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789413574211, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "head-case": { + "nanRequests": 1, + "afterDestroy": [ + { + "time": 1789413738613, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413681168, + "url": "http://localhost:4314/office/program/21", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413681524, + "url": "http://localhost:4314/office/program/21", + "detail": { + "destination": "/office/program/21", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413682047, + "url": "http://localhost:4314/office/program/21", + "detail": { + "tag": "BUTTON", + "text": "перейти в заявку", + "href": null, + "class": "button text-body-12 bar__add-project button--inline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413682051, + "url": "http://localhost:4314/office/program/21", + "detail": { + "destination": "/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413682596, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "destination": "/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "tree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413682608, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "projectId": 31, + "presentation": "", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413682613, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789413682615, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413682617, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413682622, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "control-emission", + "time": 1789413682625, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413682700, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789413694831, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "tag": "BUTTON", + "text": "спасибо, понятно", + "href": null, + "class": "button text-body-12 button--inline button--medium" + } + }, + { + "kind": "ui-click", + "time": 1789413737685, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789413737689, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Изменённый кейс\"}]" + } + }, + { + "kind": "xhr-end", + "time": 1789413737716, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 401, + "response": "{\"detail\":\"Given token not valid for any token type\",\"code\":\"token_not_valid\",\"messages\":[{\"token_class\":\"AccessToken\",\"token_type\":\"access\",\"message\":\"Token is invalid or expired\"}]}" + } + }, + { + "kind": "xhr-send", + "time": 1789413737831, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Изменённый кейс\"}]" + } + }, + { + "kind": "widget-event", + "time": 1789413737965, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "type": "ProgramWidgetChanged", + "payload": {}, + "occurredAt": "2026-09-14T19:22:17.965Z" + } + }, + { + "kind": "update-use-case", + "time": 1789413737966, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413737969, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413737971, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Исходный проект диагностики\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789413737974, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789413738222, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413738226, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Исходный проект диагностики\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"avatar\":null}],\"partners\":[],\"leader\":11,\"draft\":tr" + } + }, + { + "kind": "editor-destroy", + "time": 1789413738613, + "url": "http://localhost:4314/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789413738616, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789413738618, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789413738623, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "base-case": { + "nanRequests": 1, + "afterDestroy": [ + { + "time": 1789413843408, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413785629, + "url": "http://localhost:4315/office/program/21", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413785934, + "url": "http://localhost:4315/office/program/21", + "detail": { + "destination": "/office/program/21", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413786382, + "url": "http://localhost:4315/office/program/21", + "detail": { + "tag": "BUTTON", + "text": "перейти в заявку", + "href": null, + "class": "button text-body-12 bar__add-project button--inline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413786384, + "url": "http://localhost:4315/office/program/21", + "detail": { + "destination": "/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "program", + "params": {}, + "query": {}, + "children": [ + { + "path": ":programId", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "programId": "21" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413786796, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "destination": "/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "tree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413786809, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "projectId": 31, + "presentation": "", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413786811, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789413786814, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413786815, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413786820, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "control-emission", + "time": 1789413786822, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413786872, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789413798965, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "tag": "BUTTON", + "text": "спасибо, понятно", + "href": null, + "class": "button text-body-12 button--inline button--medium" + } + }, + { + "kind": "ui-click", + "time": 1789413842538, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789413842541, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Изменённый кейс\"}]" + } + }, + { + "kind": "update-use-case", + "time": 1789413842689, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789413842690, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789413842693, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Исходный проект диагностики\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789413842695, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789413842892, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "additional", + "fromProgram": "true", + "programLinkId": "73" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789413842895, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=additional&fromProgram=true&programLinkId=73", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Исходный проект диагностики\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"avatar\":null}],\"partners\":[],\"leader\":11,\"draft\":tr" + } + }, + { + "kind": "editor-destroy", + "time": 1789413843408, + "url": "http://localhost:4315/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789413843410, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789413843411, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789413843416, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "head-file": { + "nanRequests": 2, + "afterDestroy": [ + { + "time": 1789414173652, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + }, + { + "time": 1789414315485, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789413909191, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789413909733, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789413910272, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789413910274, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789413910543, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789413910557, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "http://localhost:8010/nan-files/presentation.pdf", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789413910560, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "http://localhost:8010/nan-files/presentation.pdf", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "control-emission", + "time": 1789413910561, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414137599, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "I", + "text": "", + "href": null, + "class": "file__basket" + } + }, + { + "kind": "control-emission", + "time": 1789414137883, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789414137884, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414137885, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414137888, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414137913, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789414173353, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "A", + "text": "проекты", + "href": "/office/projects", + "class": "sidebar-nav__item text-body-12 ng-star-inserted sidebar-nav__item--active" + } + }, + { + "kind": "navigation-start", + "time": 1789414173354, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "editor-destroy", + "time": 1789414173652, + "url": "http://localhost:4314/office/projects/dashboard", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789414173654, + "url": "http://localhost:4314/office/projects/dashboard", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789414173656, + "url": "http://localhost:4314/office/projects/dashboard", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789414173664, + "url": "http://localhost:4314/office/projects/dashboard", + "detail": { + "destination": "/office/projects", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "dashboard", + "params": {}, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "boot", + "time": 1789414197835, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789414198351, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414198840, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789414198841, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789414199091, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789414199104, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "http://localhost:8010/nan-files/presentation.pdf", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789414199107, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "http://localhost:8010/nan-files/presentation.pdf", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "control-emission", + "time": 1789414199108, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "boot", + "time": 1789414301747, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789414302160, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789414302392, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "http://localhost:8010/nan-files/presentation.pdf", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789414302396, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "http://localhost:8010/nan-files/presentation.pdf", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "control-emission", + "time": 1789414302398, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414308677, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "I", + "text": "", + "href": null, + "class": "file__basket" + } + }, + { + "kind": "control-emission", + "time": 1789414308867, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789414308868, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414308869, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414308872, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414308893, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789414314747, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789414314749, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "widget-event", + "time": 1789414314877, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "type": "ProgramWidgetChanged", + "payload": {}, + "occurredAt": "2026-09-14T19:31:54.877Z" + } + }, + { + "kind": "update-use-case", + "time": 1789414314879, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414314881, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414314886, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Исходный проект диагностики\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414314889, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789414315090, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789414315094, + "url": "http://localhost:4314/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Исходный проект диагностики\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"http://localhost:8010/nan-files/presentation.pdf\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"ava" + } + }, + { + "kind": "editor-destroy", + "time": 1789414315485, + "url": "http://localhost:4314/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789414315487, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789414315489, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789414315494, + "url": "http://localhost:4314/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + }, + "base-file": { + "nanRequests": 2, + "afterDestroy": [ + { + "time": 1789414417755, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + }, + { + "time": 1789414474749, + "requestsWithin10s": 0, + "bindingDestroyCount": 2 + } + ], + "rootRoute": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + }, + "timeline": [ + { + "kind": "boot", + "time": 1789414366016, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789414366526, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414366956, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789414366957, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789414367151, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789414367160, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "http://localhost:8010/nan-files/presentation.pdf", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789414367163, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "http://localhost:8010/nan-files/presentation.pdf", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "control-emission", + "time": 1789414367164, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414393803, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "I", + "text": "", + "href": null, + "class": "file__basket" + } + }, + { + "kind": "control-emission", + "time": 1789414393937, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789414393938, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414393938, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414393940, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414393962, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789414417390, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "A", + "text": "проекты", + "href": "/office/projects", + "class": "sidebar-nav__item text-body-12 ng-star-inserted sidebar-nav__item--active" + } + }, + { + "kind": "navigation-start", + "time": 1789414417391, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "editor-destroy", + "time": 1789414417755, + "url": "http://localhost:4315/office/projects/dashboard", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789414417757, + "url": "http://localhost:4315/office/projects/dashboard", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789414417759, + "url": "http://localhost:4315/office/projects/dashboard", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789414417767, + "url": "http://localhost:4315/office/projects/dashboard", + "detail": { + "destination": "/office/projects", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "dashboard", + "params": {}, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "boot", + "time": 1789414443728, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "queueEntries": 0 + } + }, + { + "kind": "navigation-end", + "time": 1789414444383, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414444816, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "tag": "BUTTON", + "text": "редактировать", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "navigation-start", + "time": 1789414444817, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "navigation-end", + "time": 1789414445043, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31/edit?editingStep=main", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "initialize-project", + "time": 1789414445051, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "projectId": 31, + "presentation": "http://localhost:8010/nan-files/presentation.pdf", + "cover": "http://localhost:4314/assets/images/office/profile/detail/cover.png" + } + }, + { + "kind": "control-emission", + "time": 1789414445054, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "http://localhost:8010/nan-files/presentation.pdf", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "control-emission", + "time": 1789414445056, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "coverImageAddress", + "value": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "ui-click", + "time": 1789414468301, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "I", + "text": "", + "href": null, + "class": "file__basket" + } + }, + { + "kind": "control-emission", + "time": 1789414468493, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "field": "presentationAddress", + "value": "", + "params": {}, + "rootRoute": true, + "routeTree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "update-use-case", + "time": 1789414468495, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414468496, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": "NaN", + "data": { + "presentationAddress": "", + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414468498, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "body": "{\"presentation_address\":\"\",\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414468523, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/NaN/", + "status": 404, + "response": "\n\n\n\n Not Found\n\n\n

Not Found

The requested resource was not found on this server.

\n\n\n" + } + }, + { + "kind": "ui-click", + "time": 1789414474117, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "tag": "BUTTON", + "text": "сохранить черновик", + "href": null, + "class": "button text-body-12 button--outline button--medium" + } + }, + { + "kind": "xhr-send", + "time": 1789414474122, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "body": "[{\"field_id\":1,\"value_text\":\"Исходный кейс\"}]" + } + }, + { + "kind": "update-use-case", + "time": 1789414474304, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "http-adapter", + "time": 1789414474307, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "id": 31, + "data": { + "name": "Исходный проект диагностики", + "region": "Москва", + "links": [], + "industryId": 1, + "description": "Исходное описание для одинаковых прогонов base и head", + "coverImageAddress": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "targetAudience": "Локальные тестовые пользователи", + "problem": "Диагностика существующего автосохранения", + "achievements": [], + "draft": true + } + } + }, + { + "kind": "xhr-send", + "time": 1789414474311, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "body": "{\"name\":\"Исходный проект диагностики\",\"region\":\"Москва\",\"links\":[],\"industry_id\":1,\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"cover_image_address\":\"http://localhost:4314/assets/images/office/profile/detail/cover.png\",\"target_audience\":\"Локальные тестовые пользователи\",\"problem\":\"Диагностика существующего автосохранения\",\"achievements\":[],\"draft\":true}" + } + }, + { + "kind": "xhr-end", + "time": 1789414474314, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/programs/partner-program-projects/73/fields/", + "status": 200, + "response": "{\"detail\":\"Значения успешно обновлены\"}" + } + }, + { + "kind": "navigation-start", + "time": 1789414474601, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "office", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": "projects", + "params": {}, + "query": { + "editingStep": "main" + }, + "children": [ + { + "path": ":projectId/edit", + "params": { + "projectId": "31" + }, + "query": { + "editingStep": "main" + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "kind": "xhr-end", + "time": 1789414474610, + "url": "http://localhost:4315/office/projects/31/edit?editingStep=main", + "detail": { + "method": "PUT", + "url": "http://localhost:8010/projects/31/", + "status": 200, + "response": "{\"id\":31,\"name\":\"Исходный проект диагностики\",\"description\":\"Исходное описание для одинаковых прогонов base и head\",\"short_description\":\"Исходное описание для одинаковых прогонов base и head\",\"achievements\":[],\"goals\":[],\"links\":[],\"region\":\"Москва\",\"industry\":1,\"industry_id\":1,\"presentation_address\":\"http://localhost:8010/nan-files/presentation.pdf\",\"image_address\":null,\"collaborators\":[{\"user_id\":11,\"first_name\":\"Лидер\",\"last_name\":\"Диагностика\",\"role\":\"Основатель\",\"skills\":[],\"avatar\":null},{\"user_id\":12,\"first_name\":\"Участник\",\"last_name\":\"Диагностика\",\"role\":\"Participant\",\"skills\":[],\"ava" + } + }, + { + "kind": "editor-destroy", + "time": 1789414474749, + "url": "http://localhost:4315/office/projects/31", + "detail": {} + }, + { + "kind": "binding-destroy", + "time": 1789414474750, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "presentationAddress" + } + }, + { + "kind": "binding-destroy", + "time": 1789414474751, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "field": "coverImageAddress" + } + }, + { + "kind": "navigation-end", + "time": 1789414474755, + "url": "http://localhost:4315/office/projects/31", + "detail": { + "destination": "/office/projects/31", + "tree": { + "params": {}, + "query": {}, + "children": [ + { + "path": "office", + "params": {}, + "query": {}, + "children": [ + { + "path": "", + "params": {}, + "query": {}, + "children": [ + { + "path": "projects", + "params": {}, + "query": {}, + "children": [ + { + "path": ":projectId", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [ + { + "path": "", + "params": { + "projectId": "31" + }, + "query": {}, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + } + ] + } + }, + "apiCheckpoints": [ + { + "checkpoint": "head-widget-open-10s", + "time": 1789413220483, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-widget-name-unsaved-10s", + "time": 1789413259390, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-widget-name-saved-after-exit-10s", + "time": 1789413293739, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Название после явного сохранения", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-existing-open-10s", + "time": 1789413363657, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-existing-name-unsaved-10s", + "time": 1789413393046, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-existing-name-saved-after-exit-10s", + "time": 1789413426988, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Название после явного сохранения", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-existing-open-10s", + "time": 1789413488962, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-existing-name-unsaved-10s", + "time": 1789413515804, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-existing-name-saved-after-exit-10s", + "time": 1789413598068, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Название после явного сохранения", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-case-unsaved-10s", + "time": 1789413729611, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-case-saved-after-exit-10s", + "time": 1789413765782, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Изменённый кейс" + }, + { + "checkpoint": "base-case-unsaved-10s", + "time": 1789413836861, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-case-saved-after-exit-10s", + "time": 1789413867031, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "", + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Изменённый кейс" + }, + { + "checkpoint": "head-file-filled-open-10s", + "time": 1789413932921, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 200, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-file-cleared-10s", + "time": 1789414157406, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-file-left-10s", + "time": 1789414191510, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-file-reopened-10s", + "time": 1789414221825, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "head-file-explicit-saved-10s", + "time": 1789414341421, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-file-filled-open-10s", + "time": 1789414388680, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 200, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-file-cleared-10s", + "time": 1789414413200, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-file-left-10s", + "time": 1789414435814, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-file-reopened-10s", + "time": 1789414464143, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + }, + { + "checkpoint": "base-file-explicit-saved-10s", + "time": 1789414498247, + "project_status": 200, + "fields_status": 200, + "id": 31, + "name": "Исходный проект диагностики", + "description": "Исходное описание для одинаковых прогонов base и head", + "presentation_address": "http://localhost:8010/nan-files/presentation.pdf", + "presentation_http_status": 404, + "cover_image_address": "http://localhost:4314/assets/images/office/profile/detail/cover.png", + "draft": true, + "program_link_id": 73, + "submitted": false, + "case": "Исходный кейс" + } + ] +} diff --git a/docs/program-role-widget/nan-diagnostic/file-delete-results.txt b/docs/program-role-widget/nan-diagnostic/file-delete-results.txt new file mode 100644 index 000000000..cf6ffcc5d --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/file-delete-results.txt @@ -0,0 +1,5 @@ +2026-09-14 22:28:57.626 | WARNING | daphne.management.commands.runserver:log_action:178 - HTTP DELETE /files/?link=http://localhost:8010/nan-files/presentation.pdf 401 [0.01, 127.0.0.1:57431] +2026-09-14 22:28:57.869 | INFO | daphne.management.commands.runserver:log_action:168 - HTTP DELETE /files/?link=http://localhost:8010/nan-files/presentation.pdf 204 [0.13, 127.0.0.1:57431] +2026-09-14 22:31:48.864 | WARNING | daphne.management.commands.runserver:log_action:176 - HTTP DELETE /files/?link=http://localhost:8010/nan-files/presentation.pdf 404 [0.18, 127.0.0.1:62734] +2026-09-14 22:33:13.933 | INFO | daphne.management.commands.runserver:log_action:168 - HTTP DELETE /files/?link=http://localhost:8010/nan-files/presentation.pdf 204 [0.12, 127.0.0.1:60086] +2026-09-14 22:34:28.487 | WARNING | daphne.management.commands.runserver:log_action:176 - HTTP DELETE /files/?link=http://localhost:8010/nan-files/presentation.pdf 404 [0.18, 127.0.0.1:57028] diff --git a/docs/program-role-widget/nan-diagnostic/head-existing-initiator.txt b/docs/program-role-widget/nan-diagnostic/head-existing-initiator.txt new file mode 100644 index 000000000..dd994e004 --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/head-existing-initiator.txt @@ -0,0 +1,419 @@ +Captured XHR.send initiator, observer wrapper preserves the original call. +UTC: 2026-09-14T19:15:40.881Z +Editor: http://localhost:4314/office/projects/31/edit?editingStep=main +Request: {"method":"PUT","url":"http://localhost:8010/projects/NaN/","body":"{\"presentation_address\":\"\",\"draft\":true}"} + +Original browser stack: +Error: xhr-send + at trace (http://localhost:4314/main.js:10340:165) + at XMLHttpRequest.send (http://localhost:4314/main.js:10393:5) + at _Observable._subscribe (http://localhost:4314/chunk-ZGRXBWU5.js:2062:13) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at source.subscribe.isComplete (http://localhost:4314/chunk-2P7KZKYS.js:2809:45) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at _Observable._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1816:18) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2805:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2847:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2398:23 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2579:14 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2579:14 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:40) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at _Observable._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1816:18) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at mergeInternals (http://localhost:4314/chunk-2P7KZKYS.js:2184:10) + at http://localhost:4314/chunk-2P7KZKYS.js:2200:42 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at subscribeForRetry (http://localhost:4314/chunk-2P7KZKYS.js:2646:25) + at http://localhost:4314/chunk-2P7KZKYS.js:2684:5 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2530:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2565:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2847:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + +Source map frames (original order): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:68:5 +../procollab/node_modules/@angular/common/fesm2022/module.mjs:2769:13 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:14:51 +../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:10:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/catchError.js:9:27 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:19:44 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:14:57 +../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:50:12 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeMap.js:13:44 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/filter.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:24:35 +../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:65:13 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/take.js:10:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/throwIfEmpty.js:7:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 + +update-use-case: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: update-use-case + at trace (http://localhost:4314/main.js:10340:165) + at UpdateFormUseCase.execute (http://localhost:4314/main.js:10364:3) + at http://localhost:4314/chunk-5HWQWVJ2.js:87:37 + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:15) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:1209:20 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at EventEmitter_.next (http://localhost:4314/chunk-2P7KZKYS.js:1202:5) + at EventEmitter_.emit (http://localhost:4314/chunk-2P7KZKYS.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4314/chunk-DDR2VGWS.js:2110:25) + at FormControl2.setValue (http://localhost:4314/chunk-DDR2VGWS.js:3269:10) + at FormControl2.patchValue (http://localhost:4314/chunk-DDR2VGWS.js:3272:10) + at http://localhost:4314/chunk-DDR2VGWS.js:2538:17 + at Array.forEach () + at FormGroup.patchValue (http://localhost:4314/chunk-DDR2VGWS.js:2535:24) + at _ProjectFormService.initializeProjectData (http://localhost:4314/chunk-5HWQWVJ2.js:211:22) + at ProjectFormService.initializeProjectData (http://localhost:4314/main.js:10360:23) + at Object.next (http://localhost:4314/chunk-BNVGB4N2.js:1433:31) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at BehaviorSubject._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1320:40) + at BehaviorSubject._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at BehaviorSubject._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:1249:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at BehaviorSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at SafeSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2824:34 + at SafeSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at _ProjectsEditInfoService.loadProgramTagsAndProject (http://localhost:4314/chunk-BNVGB4N2.js:1432:86) + at _ProjectEditComponent.ngAfterViewInit (http://localhost:4314/chunk-KT3HSD7Z.js:416:34) + at callHookInternal (http://localhost:4314/chunk-2P7KZKYS.js:6042:10) + at callHook (http://localhost:4314/chunk-2P7KZKYS.js:6057:7) + at callHooks (http://localhost:4314/chunk-2P7KZKYS.js:6031:9) + at executeInitAndCheckHooks (http://localhost:4314/chunk-2P7KZKYS.js:6000:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11343:11) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInComponent (http://localhost:4314/chunk-2P7KZKYS.js:11412:3) + at detectChangesInChildComponents (http://localhost:4314/chunk-2P7KZKYS.js:11467:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11323:7) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInComponent (http://localhost:4314/chunk-2P7KZKYS.js:11412:3) + at detectChangesInChildComponents (http://localhost:4314/chunk-2P7KZKYS.js:11467:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11323:7) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewWhileDirty (http://localhost:4314/chunk-2P7KZKYS.js:11208:5) + at detectChangesInternal (http://localhost:4314/chunk-2P7KZKYS.js:11197:5) + at _ApplicationRef.synchronizeOnce (http://localhost:4314/chunk-2P7KZKYS.js:17317:9) + at _ApplicationRef.synchronize (http://localhost:4314/chunk-2P7KZKYS.js:17280:12) + at _ApplicationRef.tickImpl (http://localhost:4314/chunk-2P7KZKYS.js:17248:12) + at _ApplicationRef._tick (http://localhost:4314/chunk-2P7KZKYS.js:17237:12) + at http://localhost:4314/chunk-2P7KZKYS.js:23433:21 + at NoopNgZone.run (http://localhost:4314/chunk-2P7KZKYS.js:9803:15) + at _ChangeDetectionSchedulerImpl.tick (http://localhost:4314/chunk-2P7KZKYS.js:23431:19) + at http://localhost:4314/chunk-2P7KZKYS.js:23394:102 + at http://localhost:4314/chunk-2P7KZKYS.js:9498:7 + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:40:3 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/api/project/facades/edit/project-form.service.ts:63:22 +tmp/nan-trace.ts:36:23 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:390:35 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:381:8 +projects/social_platform/src/app/ui/pages/projects/edit/edit.component.ts:146:34 + +http-adapter: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: http-adapter + at trace (http://localhost:4314/main.js:10340:165) + at ProjectHttpAdapter.putUpdate (http://localhost:4314/main.js:10369:3) + at _ProjectRepository.update (http://localhost:4314/main.js:8891:32) + at _UpdateFormUseCase.execute (http://localhost:4314/chunk-5HWQWVJ2.js:51:39) + at UpdateFormUseCase.execute (http://localhost:4314/main.js:10365:26) + at http://localhost:4314/chunk-5HWQWVJ2.js:87:37 + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:15) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:1209:20 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at EventEmitter_.next (http://localhost:4314/chunk-2P7KZKYS.js:1202:5) + at EventEmitter_.emit (http://localhost:4314/chunk-2P7KZKYS.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4314/chunk-DDR2VGWS.js:2110:25) + at FormControl2.setValue (http://localhost:4314/chunk-DDR2VGWS.js:3269:10) + at FormControl2.patchValue (http://localhost:4314/chunk-DDR2VGWS.js:3272:10) + at http://localhost:4314/chunk-DDR2VGWS.js:2538:17 + at Array.forEach () + at FormGroup.patchValue (http://localhost:4314/chunk-DDR2VGWS.js:2535:24) + at _ProjectFormService.initializeProjectData (http://localhost:4314/chunk-5HWQWVJ2.js:211:22) + at ProjectFormService.initializeProjectData (http://localhost:4314/main.js:10360:23) + at Object.next (http://localhost:4314/chunk-BNVGB4N2.js:1433:31) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at BehaviorSubject._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1320:40) + at BehaviorSubject._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at BehaviorSubject._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:1249:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at BehaviorSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at SafeSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2824:34 + at SafeSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at AnonymousSubject.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at _ProjectsEditInfoService.loadProgramTagsAndProject (http://localhost:4314/chunk-BNVGB4N2.js:1432:86) + at _ProjectEditComponent.ngAfterViewInit (http://localhost:4314/chunk-KT3HSD7Z.js:416:34) + at callHookInternal (http://localhost:4314/chunk-2P7KZKYS.js:6042:10) + at callHook (http://localhost:4314/chunk-2P7KZKYS.js:6057:7) + at callHooks (http://localhost:4314/chunk-2P7KZKYS.js:6031:9) + at executeInitAndCheckHooks (http://localhost:4314/chunk-2P7KZKYS.js:6000:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11343:11) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInComponent (http://localhost:4314/chunk-2P7KZKYS.js:11412:3) + at detectChangesInChildComponents (http://localhost:4314/chunk-2P7KZKYS.js:11467:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11323:7) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInEmbeddedViews (http://localhost:4314/chunk-2P7KZKYS.js:11389:7) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11289:5) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewIfAttached (http://localhost:4314/chunk-2P7KZKYS.js:11419:3) + at detectChangesInComponent (http://localhost:4314/chunk-2P7KZKYS.js:11412:3) + at detectChangesInChildComponents (http://localhost:4314/chunk-2P7KZKYS.js:11467:5) + at refreshView (http://localhost:4314/chunk-2P7KZKYS.js:11323:7) + at detectChangesInView (http://localhost:4314/chunk-2P7KZKYS.js:11436:5) + at detectChangesInViewWhileDirty (http://localhost:4314/chunk-2P7KZKYS.js:11208:5) + at detectChangesInternal (http://localhost:4314/chunk-2P7KZKYS.js:11197:5) + at _ApplicationRef.synchronizeOnce (http://localhost:4314/chunk-2P7KZKYS.js:17317:9) + at _ApplicationRef.synchronize (http://localhost:4314/chunk-2P7KZKYS.js:17280:12) + at _ApplicationRef.tickImpl (http://localhost:4314/chunk-2P7KZKYS.js:17248:12) + at _ApplicationRef._tick (http://localhost:4314/chunk-2P7KZKYS.js:17237:12) + at http://localhost:4314/chunk-2P7KZKYS.js:23433:21 + at NoopNgZone.run (http://localhost:4314/chunk-2P7KZKYS.js:9803:15) + at _ChangeDetectionSchedulerImpl.tick (http://localhost:4314/chunk-2P7KZKYS.js:23431:19) + at http://localhost:4314/chunk-2P7KZKYS.js:23394:102 + at http://localhost:4314/chunk-2P7KZKYS.js:9498:7 + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:45:3 +projects/social_platform/src/app/infrastructure/repository/project/project.repository.ts:132:32 +projects/social_platform/src/app/api/project/use-cases/update-form.use-case.ts:19:39 +tmp/nan-trace.ts:41:26 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/api/project/facades/edit/project-form.service.ts:63:22 +tmp/nan-trace.ts:36:23 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:390:35 +projects/social_platform/src/app/api/project/facades/edit/projects-edit-info.service.ts:381:8 +projects/social_platform/src/app/ui/pages/projects/edit/edit.component.ts:146:34 diff --git a/docs/program-role-widget/nan-diagnostic/head-file-initiator.txt b/docs/program-role-widget/nan-diagnostic/head-file-initiator.txt new file mode 100644 index 000000000..3b5ae8252 --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/head-file-initiator.txt @@ -0,0 +1,345 @@ +Captured XHR.send initiator, observer wrapper preserves the original call. +UTC: 2026-09-14T19:28:57.888Z +Editor: http://localhost:4314/office/projects/31/edit?editingStep=main +Request: {"method":"PUT","url":"http://localhost:8010/projects/NaN/","body":"{\"presentation_address\":\"\",\"draft\":true}"} + +Original browser stack: +Error: xhr-send + at trace (http://localhost:4314/main.js:10340:165) + at XMLHttpRequest.send (http://localhost:4314/main.js:10393:5) + at _Observable._subscribe (http://localhost:4314/chunk-ZGRXBWU5.js:2062:13) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at source.subscribe.isComplete (http://localhost:4314/chunk-2P7KZKYS.js:2809:45) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at _Observable._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1816:18) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2805:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2847:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2398:23 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2579:14 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2579:14 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:40) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at _Observable._subscribe (http://localhost:4314/chunk-2P7KZKYS.js:1816:18) + at _Observable._trySubscribe (http://localhost:4314/chunk-2P7KZKYS.js:949:19) + at http://localhost:4314/chunk-2P7KZKYS.js:943:113 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at mergeInternals (http://localhost:4314/chunk-2P7KZKYS.js:2184:10) + at http://localhost:4314/chunk-2P7KZKYS.js:2200:42 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at subscribeForRetry (http://localhost:4314/chunk-2P7KZKYS.js:2646:25) + at http://localhost:4314/chunk-2P7KZKYS.js:2684:5 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2530:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2565:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2847:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at _Observable.subscribe (http://localhost:4314/chunk-2P7KZKYS.js:941:5) + at http://localhost:4314/chunk-2P7KZKYS.js:2048:12 + at OperatorSubscriber. (http://localhost:4314/chunk-2P7KZKYS.js:1013:18) + at http://localhost:4314/chunk-2P7KZKYS.js:943:42 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + +Source map frames (original order): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:68:5 +../procollab/node_modules/@angular/common/fesm2022/module.mjs:2769:13 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:14:51 +../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/switchMap.js:10:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/catchError.js:9:27 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/finalize.js:5:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:19:44 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:14:57 +../procollab/node_modules/rxjs/dist/esm/internal/operators/OperatorSubscriber.js:13:21 +../procollab/node_modules/rxjs/dist/esm/internal/Subscriber.js:31:18 +../procollab/node_modules/rxjs/dist/esm/internal/observable/innerFrom.js:51:24 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:37:25 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:31:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeInternals.js:50:12 +../procollab/node_modules/rxjs/dist/esm/internal/operators/mergeMap.js:13:44 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/filter.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:24:35 +../procollab/node_modules/rxjs/dist/esm/internal/operators/retry.js:65:13 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/take.js:10:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/throwIfEmpty.js:7:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/tap.js:15:20 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:22:9 +../procollab/node_modules/rxjs/dist/esm/internal/operators/map.js:6:16 +../procollab/node_modules/rxjs/dist/esm/internal/util/lift.js:10:28 +../procollab/node_modules/rxjs/dist/esm/internal/Observable.js:26:30 +../procollab/node_modules/rxjs/dist/esm/internal/util/errorContext.js:19:9 + +update-use-case: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: update-use-case + at trace (http://localhost:4314/main.js:10340:165) + at UpdateFormUseCase.execute (http://localhost:4314/main.js:10364:3) + at http://localhost:4314/chunk-5HWQWVJ2.js:87:37 + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:15) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:1209:20 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at EventEmitter_.next (http://localhost:4314/chunk-2P7KZKYS.js:1202:5) + at EventEmitter_.emit (http://localhost:4314/chunk-2P7KZKYS.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4314/chunk-DDR2VGWS.js:2110:25) + at FormControl2.setValue (http://localhost:4314/chunk-DDR2VGWS.js:3269:10) + at updateControl (http://localhost:4314/chunk-DDR2VGWS.js:2829:11) + at _UploadFileComponent.onChange (http://localhost:4314/chunk-DDR2VGWS.js:2817:40) + at Object.next (http://localhost:4314/chunk-MNLNWENM.js:313:14) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2567:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2532:20 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2650:20 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerComplete (http://localhost:4314/chunk-2P7KZKYS.js:2161:20) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4314/chunk-2P7KZKYS.js:2809:137) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at source.subscribe.isUnsub (http://localhost:4314/chunk-2P7KZKYS.js:2850:18) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4314/chunk-2P7KZKYS.js:2809:137) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at XMLHttpRequest.onLoad (http://localhost:4314/chunk-ZGRXBWU5.js:1978:22) + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:40:3 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/ui/primitives/upload-file/upload-file.component.ts:158:16 + +http-adapter: {"id":"NaN","data":{"presentationAddress":"","draft":true}} +Error: http-adapter + at trace (http://localhost:4314/main.js:10340:165) + at ProjectHttpAdapter.putUpdate (http://localhost:4314/main.js:10369:3) + at _ProjectRepository.update (http://localhost:4314/main.js:8891:32) + at _UpdateFormUseCase.execute (http://localhost:4314/chunk-5HWQWVJ2.js:51:39) + at UpdateFormUseCase.execute (http://localhost:4314/main.js:10365:26) + at http://localhost:4314/chunk-5HWQWVJ2.js:87:37 + at doInnerSub (http://localhost:4314/chunk-2P7KZKYS.js:2156:15) + at outerNext (http://localhost:4314/chunk-2P7KZKYS.js:2151:54) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:1209:20 + at errorContext (http://localhost:4314/chunk-2P7KZKYS.js:738:5) + at EventEmitter_.next (http://localhost:4314/chunk-2P7KZKYS.js:1202:5) + at EventEmitter_.emit (http://localhost:4314/chunk-2P7KZKYS.js:9431:13) + at FormControl2.updateValueAndValidity (http://localhost:4314/chunk-DDR2VGWS.js:2110:25) + at FormControl2.setValue (http://localhost:4314/chunk-DDR2VGWS.js:3269:10) + at updateControl (http://localhost:4314/chunk-DDR2VGWS.js:2829:11) + at _UploadFileComponent.onChange (http://localhost:4314/chunk-DDR2VGWS.js:2817:40) + at Object.next (http://localhost:4314/chunk-MNLNWENM.js:313:14) + at ConsumerObserver.next (http://localhost:4314/chunk-2P7KZKYS.js:825:25) + at SafeSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:796:22) + at SafeSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2567:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2532:20 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2650:20 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2348:124 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerComplete (http://localhost:4314/chunk-2P7KZKYS.js:2161:20) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at http://localhost:4314/chunk-2P7KZKYS.js:2049:18 + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4314/chunk-2P7KZKYS.js:2809:137) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at source.subscribe.isUnsub (http://localhost:4314/chunk-2P7KZKYS.js:2850:18) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at innerFrom.subscribe.innerSubscriber (http://localhost:4314/chunk-2P7KZKYS.js:2809:137) + at OperatorSubscriber._next (http://localhost:4314/chunk-2P7KZKYS.js:1034:9) + at OperatorSubscriber.next (http://localhost:4314/chunk-2P7KZKYS.js:769:12) + at XMLHttpRequest.onLoad (http://localhost:4314/chunk-ZGRXBWU5.js:1978:22) + +Mapped application frames (original order, framework frames omitted here): +tmp/nan-trace.ts:19:142 +tmp/nan-trace.ts:45:3 +projects/social_platform/src/app/infrastructure/repository/project/project.repository.ts:132:32 +projects/social_platform/src/app/api/project/use-cases/update-form.use-case.ts:19:39 +tmp/nan-trace.ts:41:26 +projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service.ts:50:14 +projects/social_platform/src/app/ui/primitives/upload-file/upload-file.component.ts:158:16 diff --git a/docs/program-role-widget/nan-diagnostic/head-file-reopened.png b/docs/program-role-widget/nan-diagnostic/head-file-reopened.png new file mode 100644 index 000000000..4f4722c68 Binary files /dev/null and b/docs/program-role-widget/nan-diagnostic/head-file-reopened.png differ diff --git a/docs/program-role-widget/nan-diagnostic/observer.ts.txt b/docs/program-role-widget/nan-diagnostic/observer.ts.txt new file mode 100644 index 000000000..18dc688ac --- /dev/null +++ b/docs/program-role-widget/nan-diagnostic/observer.ts.txt @@ -0,0 +1,87 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { Router, NavigationStart, NavigationEnd } from '@angular/router'; +import { AppComponent } from '../projects/social_platform/src/app/app.component'; +import { APP_CONFIG } from '../projects/social_platform/src/app/app.config'; +import { ProjectFormAutosaveService } from '../projects/social_platform/src/app/api/project/facades/edit/project-form-autosave.service'; +import { ProjectFormService } from '../projects/social_platform/src/app/api/project/facades/edit/project-form.service'; +import { UpdateFormUseCase } from '../projects/social_platform/src/app/api/project/use-cases/update-form.use-case'; +import { ProjectHttpAdapter } from '../projects/social_platform/src/app/infrastructure/adapters/project/project-http.adapter'; +import { ProjectEditComponent } from '../projects/social_platform/src/app/ui/pages/projects/edit/edit.component'; +import { EventBus } from '../projects/social_platform/src/app/domain/shared/event-bus'; + +// Diagnostic-only observer wrappers: original methods/arguments/results are preserved. +// No production files, IDs, subscriptions, retry rules or API results are replaced. +(Error as any).stackTraceLimit = 100; +let sequence = 0; +let router: Router | undefined; +const routeTree = (route: any): any => route ? ({path:route.routeConfig?.path, params:route.snapshot.params, query:route.snapshot.queryParams, children:route.children.map(routeTree)}) : null; +function trace(kind:string, detail:any = {}, stack = false) { + const body = JSON.stringify({seq:++sequence, time:Date.now(), elapsed:performance.now(), kind, url:location.href, detail, ...(stack?{stack:new Error(kind).stack}: {})}, (_key, value)=>typeof value==='number' && !Number.isFinite(value)?String(value):value); + console.info('[NAN-DIAG] '+body); + fetch('/__nan_trace', {method:'POST',headers:{'Content-Type':'application/json'},body,keepalive:true}).catch(()=>{}); +} +trace('boot',{queueEntries:JSON.parse(localStorage.getItem('project-autosave-queue')??'[]').length}); + +const originalBind = ProjectFormAutosaveService.prototype.bindDraftCleanupAutosave; +ProjectFormAutosaveService.prototype.bindDraftCleanupAutosave = function(control, field, destroyRef) { + const route = (this as any).route; + trace('bind',{field,rootRoute:route===route.root,params:route.snapshot.params}); + const subscription = control?.valueChanges.subscribe(value=>trace('control-emission',{field,value,params:route.snapshot.params,rootRoute:route===route.root,routeTree:routeTree(route.root)},!value)); + destroyRef.onDestroy(()=>{subscription?.unsubscribe();trace('binding-destroy',{field});}); + return originalBind.call(this,control,field,destroyRef); +}; +const originalInit = ProjectFormService.prototype.initializeProjectData; +ProjectFormService.prototype.initializeProjectData = function(project) { + trace('initialize-project',{projectId:project.id,presentation:project.presentationAddress,cover:project.coverImageAddress},true); + return originalInit.call(this,project); +}; +const originalExecute = UpdateFormUseCase.prototype.execute; +UpdateFormUseCase.prototype.execute = function(command) { + trace('update-use-case',command,true); + return originalExecute.call(this,command); +}; +const originalPut = ProjectHttpAdapter.prototype.putUpdate; +ProjectHttpAdapter.prototype.putUpdate = function(id,data) { + trace('http-adapter',{id,data},true); + return originalPut.call(this,id,data); +}; +const originalDestroy = ProjectEditComponent.prototype.ngOnDestroy; +ProjectEditComponent.prototype.ngOnDestroy = function() { + trace('editor-destroy'); + return originalDestroy.call(this); +}; +const originalEmit = EventBus.prototype.emit; +EventBus.prototype.emit = function(event) { + if (event.type==='ProgramWidgetChanged') trace('widget-event',event,true); + return originalEmit.call(this,event); +}; +const originalOpen = XMLHttpRequest.prototype.open; +const originalSend = XMLHttpRequest.prototype.send; +const requests = new WeakMap(); +XMLHttpRequest.prototype.open = function(method:string,url:string|URL,...rest:any[]) { + requests.set(this,{method,url:String(url)}); + return (originalOpen as any).call(this,method,url,...rest); +}; +XMLHttpRequest.prototype.send = function(body) { + const request = requests.get(this); + if (request && /\/(projects|programs)\//.test(request.url) && request.method!=='GET') { + trace('xhr-send',{...request,body},true); + this.addEventListener('loadend',()=>trace('xhr-end',{...request,status:this.status,response:this.responseText?.slice(0,600)}),{once:true}); + } + return originalSend.call(this,body); +}; +document.addEventListener('click',event=>{ + const element = (event.target as HTMLElement).closest('a,button,.file__basket'); + if (element) trace('ui-click',{tag:element.tagName,text:element.textContent?.trim().slice(0,100),href:element.getAttribute('href'),class:element.className}); +},true); +document.addEventListener('change',event=>{ + const input = event.target as HTMLInputElement; + if (location.pathname.includes('/office/projects/')) trace('ui-change',{tag:input.tagName,type:input.type,value:input.value}); +},true); +bootstrapApplication(AppComponent,APP_CONFIG).then(app=>{ + router=app.injector.get(Router); + router.events.subscribe(event=>{ + if (event instanceof NavigationStart || event instanceof NavigationEnd) + trace(event instanceof NavigationStart?'navigation-start':'navigation-end',{destination:event.url,tree:routeTree(router?.routerState.root)}); + }); +}).catch(console.error); diff --git a/docs/program-role-widget/responsive-smoke.json b/docs/program-role-widget/responsive-smoke.json new file mode 100644 index 000000000..77856dfa6 --- /dev/null +++ b/docs/program-role-widget/responsive-smoke.json @@ -0,0 +1,84 @@ +[ + { + "width": 1000, + "version": "before", + "about": { + "bottom": 438.78125, + "height": 161.1875, + "left": 197.5, + "right": 337, + "top": 277.59375, + "width": 139.5, + "x": 197.5, + "y": 277.59375 + }, + "card": null, + "viewport": [1000, 1000] + }, + { + "width": 1000, + "version": "after", + "about": { + "bottom": 438.78125, + "height": 161.1875, + "left": 197.5, + "right": 337, + "top": 277.59375, + "width": 139.5, + "x": 197.5, + "y": 277.59375 + }, + "card": null, + "viewport": [1000, 1000] + }, + { + "width": 1440, + "version": "before", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 551.15625, + "right": 964.484375, + "top": 262.59375, + "width": 413.328125, + "x": 551.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 365.828125, + "right": 522.828125, + "top": 262.59375, + "width": 157, + "x": 365.828125, + "y": 262.59375 + }, + "viewport": [1440, 1000] + }, + { + "width": 1440, + "version": "after", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 551.15625, + "right": 964.484375, + "top": 262.59375, + "width": 413.328125, + "x": 551.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 365.828125, + "right": 522.828125, + "top": 262.59375, + "width": 157, + "x": 365.828125, + "y": 262.59375 + }, + "viewport": [1440, 1000] + } +] diff --git a/docs/program-role-widget/screenshots/before-1280.png b/docs/program-role-widget/screenshots/before-1280.png new file mode 100644 index 000000000..9fae5ebeb Binary files /dev/null and b/docs/program-role-widget/screenshots/before-1280.png differ diff --git a/docs/program-role-widget/screenshots/expert-1280.png b/docs/program-role-widget/screenshots/expert-1280.png new file mode 100644 index 000000000..d6b79713f Binary files /dev/null and b/docs/program-role-widget/screenshots/expert-1280.png differ diff --git a/docs/program-role-widget/screenshots/expert-zero-1280.png b/docs/program-role-widget/screenshots/expert-zero-1280.png new file mode 100644 index 000000000..6ab03a560 Binary files /dev/null and b/docs/program-role-widget/screenshots/expert-zero-1280.png differ diff --git a/docs/program-role-widget/screenshots/long-case-focus-1280.png b/docs/program-role-widget/screenshots/long-case-focus-1280.png new file mode 100644 index 000000000..8585e4b34 Binary files /dev/null and b/docs/program-role-widget/screenshots/long-case-focus-1280.png differ diff --git a/docs/program-role-widget/screenshots/long-project-focus-1280.png b/docs/program-role-widget/screenshots/long-project-focus-1280.png new file mode 100644 index 000000000..99ddf1665 Binary files /dev/null and b/docs/program-role-widget/screenshots/long-project-focus-1280.png differ diff --git a/docs/program-role-widget/screenshots/organizer-1280.png b/docs/program-role-widget/screenshots/organizer-1280.png new file mode 100644 index 000000000..e26815a84 Binary files /dev/null and b/docs/program-role-widget/screenshots/organizer-1280.png differ diff --git a/docs/program-role-widget/screenshots/organizer-zero-1280.png b/docs/program-role-widget/screenshots/organizer-zero-1280.png new file mode 100644 index 000000000..e8d925e0e Binary files /dev/null and b/docs/program-role-widget/screenshots/organizer-zero-1280.png differ diff --git a/docs/program-role-widget/screenshots/participant-1280.png b/docs/program-role-widget/screenshots/participant-1280.png new file mode 100644 index 000000000..79013e893 Binary files /dev/null and b/docs/program-role-widget/screenshots/participant-1280.png differ diff --git a/docs/program-role-widget/screenshots/participant-zero-1280.png b/docs/program-role-widget/screenshots/participant-zero-1280.png new file mode 100644 index 000000000..dcebe04ba Binary files /dev/null and b/docs/program-role-widget/screenshots/participant-zero-1280.png differ diff --git a/docs/program-role-widget/smoke-results.json b/docs/program-role-widget/smoke-results.json new file mode 100644 index 000000000..3b5ca6a41 --- /dev/null +++ b/docs/program-role-widget/smoke-results.json @@ -0,0 +1,497 @@ +[ + { + "view": "participant", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "участниканалитикаКейс: Цифровой сервисПроект: StudyFlow✓ОтправленПроверкаОценёнОткрыть →", + "viewport": [1280, 1000] + }, + { + "view": "organizer", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "организатораналитикаУчастники 248 Проекты 61 Отправленныерешения 54 Без проектов197,7%Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "expert", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "экспертаналитикаНазначенопроектов 7 Осталосьоценить 3 До конца оценивания — 2 дн Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "participant-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "участниканалитикаКейсы не предусмотреныПроект не поданОтправленПроверкаОценён Создать заявку → ", + "viewport": [1280, 1000] + }, + { + "view": "organizer-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "организатораналитикаУчастники 0 Проекты 0 Отправленныерешения 0 Без проектов0—Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "expert-zero", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "экспертаналитикаНазначенопроектов 0 Осталосьоценить 0 Нет назначенных проектов Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "loading", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": " аналитика", + "viewport": [1280, 1000] + }, + { + "view": "error", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": " аналитикаНе удалось загрузитьПовторить", + "viewport": [1280, 1000] + }, + { + "view": "forbidden", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": " аналитикаНет доступа", + "viewport": [1280, 1000] + }, + { + "view": "draft", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "участниканалитикаКейс: Цифровой сервисПроект: StudyFlow Не отправлен ОтправленПроверкаОценёнОткрыть →", + "viewport": [1280, 1000] + }, + { + "view": "long", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "участниканалитикаКейс: Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Цифровой сервис Проект: Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект Международный технологический проект ✓ОтправленПроверкаОценёнОткрыть →", + "viewport": [1280, 1000] + }, + { + "view": "organizer-large", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "организатораналитикаУчастники 987,7 млн Проекты 61 Отправленныерешения 54 Без проектов190,0%Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "expert-open", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "экспертаналитикаНазначенопроектов — Осталосьоценить — Свободное оценивание. До конца оценивания — 2 дн Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "expert-overdue", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "экспертаналитикаНазначенопроектов 7 Осталосьоценить 3 Срок оценивания истёк Открыть →", + "viewport": [1280, 1000] + }, + { + "view": "expert-complete", + "about": { + "bottom": 369.1875, + "height": 106.59375, + "left": 471.15625, + "right": 884.484375, + "top": 262.59375, + "width": 413.328125, + "x": 471.15625, + "y": 262.59375 + }, + "card": { + "bottom": 403.578125, + "height": 140.984375, + "left": 285.828125, + "right": 442.828125, + "top": 262.59375, + "width": 157, + "x": 285.828125, + "y": 262.59375 + }, + "dpr": 1, + "scale": 1, + "scroll": { + "clientHeight": 139, + "clientWidth": 155, + "height": 139, + "width": 155 + }, + "text": "экспертаналитикаНазначенопроектов 7 Осталосьоценить 0 Все проекты оценены Открыть →", + "viewport": [1280, 1000] + } +] diff --git a/docs/program-role-widget/smoke/index.html b/docs/program-role-widget/smoke/index.html new file mode 100644 index 000000000..acdfe8dfb --- /dev/null +++ b/docs/program-role-widget/smoke/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/docs/program-role-widget/smoke/page.ts b/docs/program-role-widget/smoke/page.ts new file mode 100644 index 000000000..2cea4b45f --- /dev/null +++ b/docs/program-role-widget/smoke/page.ts @@ -0,0 +1,283 @@ +/** @format */ + +import "@angular/compiler"; +import { Component, signal, provideZonelessChangeDetection, ApplicationRef } from "@angular/core"; +import { TestBed } from "@angular/core/testing"; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from "@angular/platform-browser-dynamic/testing"; +import { provideRouter } from "@angular/router"; +import { provideHttpClient } from "@angular/common/http"; +import { provideHttpClientTesting } from "@angular/common/http/testing"; +import { FormGroup } from "@angular/forms"; +import { of } from "rxjs"; +import { API_URL, PRODUCTION } from "@corelib"; +import { ProfileControlPanelComponent, SidebarComponent } from "@uilib"; +import { DeatilComponent } from "@ui/widgets/detail/detail.component"; +import { DetailInfoService } from "@ui/widgets/detail/services/detail-info.service"; +import { DetailProfileInfoService } from "@ui/widgets/detail/services/profile/detail-profile-info.service"; +import { DetailProgramInfoService } from "@ui/widgets/detail/services/program/detail-program-info.service"; +import { DetailProjectInfoService } from "@ui/widgets/detail/services/project/detail-project-info.service"; +import { ProjectFormService } from "@api/project/project-form.service"; +import { ProjectAdditionalService } from "@api/project/facades/edit/project-additional.service"; +import { ChatStateService } from "@domain/shared/chat-state.service"; +import { Program } from "@domain/program/program.model"; +import { User } from "@domain/auth/user.model"; +import { ExpandService } from "@api/expand/expand.service"; +import { ProgramDetailMainComponent } from "@pages/program/detail/main/main.component"; +import { ProgramDetailMainService } from "@api/program/facades/detail/program-detail-main-info.service"; +import { ProgramDetailMainUIInfoService } from "@api/program/facades/detail/ui/program-detail-main-ui-info.service"; +import { NewsInfoService } from "@api/news/news-info.service"; + +import { ProgramRoleWidgetComponent } from "@pages/program/detail/main/role-widget/program-role-widget.component"; +import { ProgramRoleWidgetService } from "@api/program/facades/detail/program-role-widget.service"; +const view = new URLSearchParams(location.search).get("view") || "participant"; +const role = view.startsWith("organizer") + ? "organizer" + : view.startsWith("expert") + ? "expert" + : "participant"; +const empty = view.endsWith("zero"); +const widgetData: any = { programId: 12, role, isCompetitive: true }; +widgetData.participant = { + participantProject: empty + ? null + : { + id: 5, + name: view === "long" ? "Международный технологический проект ".repeat(15) : "StudyFlow", + programLinkId: 34, + }, + caseProvided: !empty && view !== "participant-no-case", + caseName: + empty || view === "participant-no-case" + ? null + : view === "long" + ? "Цифровой сервис ".repeat(15) + : "Цифровой сервис", + stage: empty + ? "none" + : view === "draft" + ? "not_submitted" + : view === "participant-submitted" + ? "submitted" + : view === "participant-evaluated" + ? "evaluated" + : "review", + submissionOpen: true, +}; +widgetData.organizer = { + participants: empty ? 0 : view === "organizer-large" ? 987654321 : 248, + projects: empty ? 0 : 61, + submittedSolutions: empty ? 0 : 54, + participantsWithoutProject: empty + ? 0 + : view === "organizer-yellow" + ? 40 + : view === "organizer-red" + ? 90 + : 19, +}; +widgetData.expert = { + mode: view === "expert-open" ? "open" : "distributed", + assigned: view === "expert-open" ? null : empty ? 0 : 7, + remaining: view === "expert-open" ? null : empty || view === "expert-complete" ? 0 : 3, + evaluationEnds: + view === "expert-missing" + ? null + : new Date( + Date.now() + + (view === "expert-overdue" + ? -86400000 + : view === "expert-hours" + ? 5 * 3600000 + : view === "expert-minutes" + ? 25 * 60000 + : 2 * 86400000), + ).toISOString(), +}; +const widgetState = signal( + view === "loading" + ? { status: "loading" } + : view === "error" + ? { status: "failure", error: "network" } + : view === "forbidden" + ? { status: "failure", error: "forbidden" } + : { status: "success", data: widgetData }, +); +const noop = () => {}; +const closed = (extra: object = {}) => + new Proxy(extra, { get: (target, key) => Reflect.get(target, key) ?? signal(false) }); +const user = Object.assign(new User(), { + id: 7, + firstName: "Анна", + lastName: "Иванова", + avatar: "", + personal: { avatar: "" }, +}); +const program = Object.assign(Program.default(), { + id: 12, + name: "Технологические команды", + description: "Программа для развития технологических проектов и совместной работы участников.", + isUserMember: role === "participant", + isUserManager: role === "organizer", + isUserExpert: role === "expert", + links: [], + materials: [], + imageAddress: "", + welcomeAcknowledgedAt: "2026-09-01T00:00:00Z", +}); +const mainUI = new ProgramDetailMainUIInfoService(); +mainUI.applyFormatingProgramData(program); +mainUI.registeredProgramModal.set(false); + +@Component({ + selector: "smoke-shell", + imports: [SidebarComponent], + styleUrl: "../../../projects/social_platform/src/app/ui/pages/office/office.component.scss", + styles: [":host { display:block; height:100%; }"], + template: `
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
`, +}) +class SmokeShell { + nav = [ + { name: "Лента", icon: "feed", link: "/office/feed" }, + { name: "Проекты", icon: "folder", link: "/office/projects" }, + { name: "Программы", icon: "folder", link: "/office/program" }, + ]; +} + +TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); +async function main() { + TestBed.configureTestingModule({ + imports: [ + SmokeShell, + ProfileControlPanelComponent, + DeatilComponent, + ProgramDetailMainComponent, + ], + providers: [ + provideRouter([]), + provideZonelessChangeDetection(), + provideHttpClient(), + provideHttpClientTesting(), + { provide: API_URL, useValue: "" }, + { provide: PRODUCTION, useValue: false }, + { provide: ProjectFormService, useValue: { getForm: () => new FormGroup({}) } }, + { provide: ChatStateService, useValue: { userOnlineStatusCache: of({}) } }, + { + provide: DetailProgramInfoService, + useValue: { applicationPending: signal(false), addNewProject: noop }, + }, + { provide: ProgramDetailMainUIInfoService, useValue: mainUI }, + { + provide: ProjectAdditionalService, + useValue: { + isSend$: signal({ status: "initial" }), + errorAssignProjectToProgramModalMessage: signal(null), + }, + }, + { provide: NewsInfoService, useValue: { news: signal([]) } }, + ], + }); + TestBed.overrideComponent(DeatilComponent, { + set: { + providers: [ + { + provide: DetailInfoService, + useValue: closed({ + info: signal(program), + listType: signal("program"), + userType: signal(1), + isUserMember: signal(true), + initializationDetail: noop, + destroy: noop, + }), + }, + { provide: DetailProfileInfoService, useValue: closed() }, + { + provide: DetailProgramInfoService, + useValue: closed({ applicationLabel: signal("создать заявку") }), + }, + { provide: DetailProjectInfoService, useValue: closed() }, + { provide: ProjectAdditionalService, useValue: {} }, + ], + }, + }); + TestBed.overrideComponent(ProgramDetailMainComponent, { + set: { + providers: [ + { + provide: ProgramDetailMainService, + useValue: { initializationProgramDetailMain: noop, initScroll: noop, destroy: noop }, + }, + { provide: ExpandService, useValue: closed() }, + ], + }, + }); + TestBed.overrideComponent(ProgramRoleWidgetComponent, { + set: { + providers: [ + { + provide: ProgramRoleWidgetService, + useValue: { + state: widgetState, + retry: () => widgetState.set({ status: "success", data: widgetData }), + programId: signal(12), + }, + }, + ], + }, + }); + await TestBed.compileComponents(); + const mount = (component: any, slot: HTMLElement) => { + const fixture = TestBed.createComponent(component); + fixture.nativeElement.removeAttribute("id"); + slot.append(fixture.nativeElement); + fixture.detectChanges(); + fixture.autoDetectChanges(); + return fixture; + }; + mount(SmokeShell, document.body); + const panel = TestBed.createComponent(ProfileControlPanelComponent); + panel.componentRef.setInput("user", user); + panel.componentRef.setInput("invites", []); + document.getElementById("panel-slot")!.append(panel.nativeElement); + panel.detectChanges(); + const header = mount(DeatilComponent, document.getElementById("page-slot")!); + mount( + ProgramDetailMainComponent, + header.nativeElement.querySelector(".detail__body") ?? header.nativeElement, + ); + await TestBed.inject(ApplicationRef).whenStable(); + document.body.dataset["ready"] = "true"; +} +main().catch(error => { + console.error(error); + document.body.dataset["error"] = String(error); +}); diff --git a/docs/program-role-widget/smoke/serve.cjs b/docs/program-role-widget/smoke/serve.cjs new file mode 100644 index 000000000..604766c55 --- /dev/null +++ b/docs/program-role-widget/smoke/serve.cjs @@ -0,0 +1,35 @@ +/** @format */ + +// Only local, compiled visual fixtures. No application API or business writes. +const http = require("node:http"); +const fs = require("node:fs"); +const path = require("node:path"); +const root = path.resolve("tmp/current/browser"); +const mime = { + ".html": "text/html", + ".js": "text/javascript", + ".css": "text/css", + ".svg": "image/svg+xml", + ".png": "image/png", + ".woff2": "font/woff2", +}; +http + .createServer((req, res) => { + const pathname = decodeURIComponent(new URL(req.url, "http://localhost").pathname); + const file = path.resolve(root, "." + (pathname === "/" ? "/index.html" : pathname)); + if (!file.startsWith(root + path.sep)) { + res.writeHead(403); + res.end(); + return; + } + fs.readFile(file, (error, data) => { + if (error) { + res.writeHead(404); + res.end(); + return; + } + res.setHeader("Content-Type", mime[path.extname(file)] || "application/octet-stream"); + res.end(data); + }); + }) + .listen(Number(process.argv[2] || 4302), "127.0.0.1"); diff --git a/docs/program-role-widget/smoke/tsconfig.json b/docs/program-role-widget/smoke/tsconfig.json new file mode 100644 index 000000000..caaa56b2c --- /dev/null +++ b/docs/program-role-widget/smoke/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "types": [], + "strict": true, + "noImplicitAny": false, + "noImplicitReturns": false + }, + "files": ["./page.ts"] +} diff --git a/projects/social_platform/src/app/api/program/facades/detail/program-detail-main-info.service.ts b/projects/social_platform/src/app/api/program/facades/detail/program-detail-main-info.service.ts index 5455debde..489db28a9 100644 --- a/projects/social_platform/src/app/api/program/facades/detail/program-detail-main-info.service.ts +++ b/projects/social_platform/src/app/api/program/facades/detail/program-detail-main-info.service.ts @@ -95,8 +95,8 @@ export class ProgramDetailMainService { this.programDetailMainUIInfoService.applyFormatingProgramData(program); }), concatMap(program => { - // Новости программы доступны только участникам программы. - if (program.isUserMember) { + // Видимость списка и загрузка совпадают; эксперт сам по себе доступ не получает. + if (program.isUserMember || program.isUserManager) { return this.fetchNews(0, this.fetchLimit()); } else { return of( diff --git a/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.spec.ts b/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.spec.ts new file mode 100644 index 000000000..1693072ba --- /dev/null +++ b/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.spec.ts @@ -0,0 +1,131 @@ +/** @format */ + +import { TestBed } from "@angular/core/testing"; +import { signal } from "@angular/core"; +import { ActivatedRoute, convertToParamMap } from "@angular/router"; +import { BehaviorSubject, Subject } from "rxjs"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { AuthInfoService } from "@api/auth/facades/auth-info.service"; +import { GetProgramRoleWidgetUseCase } from "../../use-cases/get-program-role-widget.use-case"; +import { ProgramDetailMainUIInfoService } from "./ui/program-detail-main-ui-info.service"; +import { ProgramRoleWidgetService } from "./program-role-widget.service"; +import { Program } from "@domain/program/program.model"; +import { ProgramRoleWidget, ProgramWidgetError } from "@domain/program/program-role-widget.model"; +import { fail, ok, Result } from "@domain/shared/result.type"; +import { EventBus } from "@domain/shared/event-bus"; + +describe("ProgramRoleWidgetService", () => { + let service: ProgramRoleWidgetService; + const profile = signal<{ id: number } | null>({ id: 7 }); + const program = signal(Object.assign(Program.default(), { id: 12, isUserMember: true })); + let params: BehaviorSubject>; + let responses: Subject>[]; + const result = (id = 12): ProgramRoleWidget => ({ + programId: id, + isCompetitive: true, + role: "participant", + participant: { + participantProject: null, + caseProvided: false, + caseName: null, + stage: "none", + submissionOpen: true, + }, + }); + beforeEach(() => { + profile.set({ id: 7 }); + program.set(Object.assign(Program.default(), { id: 12, isUserMember: true })); + params = new BehaviorSubject(convertToParamMap({ programId: 12 })); + responses = []; + TestBed.configureTestingModule({ + providers: [ + ProgramRoleWidgetService, + { provide: AuthInfoService, useValue: { profile } }, + { provide: ProgramDetailMainUIInfoService, useValue: { program } }, + { + provide: ActivatedRoute, + useValue: { snapshot: { paramMap: params.value }, paramMap: params }, + }, + { + provide: GetProgramRoleWidgetUseCase, + useValue: { + execute: vi.fn(() => { + const response = new Subject>(); + responses.push(response); + return response; + }), + }, + }, + ], + }); + service = TestBed.inject(ProgramRoleWidgetService); + TestBed.flushEffects(); + }); + it("starts loading and returns server data", () => { + expect(service.state().status).toBe("loading"); + responses[0].next(ok(result())); + expect(service.state()).toEqual({ status: "success", data: result() }); + }); + it("does not replace a failure with zero and permits explicit retry", () => { + responses[0].next(fail("network")); + expect(service.state()).toEqual({ status: "failure", error: "network", previous: undefined }); + service.retry(); + expect(responses).toHaveLength(2); + responses[1].next(ok(result())); + expect(service.state().status).toBe("success"); + }); + it.each(["forbidden", "unauthorized", "not_found", "integrity"] as const)( + "does not retry %s", + error => { + responses[0].next(fail(error)); + service.retry(); + expect(responses).toHaveLength(1); + }, + ); + it("clears on route changes before the resolver and ignores late responses", () => { + responses[0].next(ok(result())); + params.next(convertToParamMap({ programId: 13 })); + expect(service.state().status).toBe("loading"); + TestBed.flushEffects(); + responses[0].next(ok(result())); + expect(service.state().status).toBe("loading"); + program.set(Object.assign(new Program(), program(), { id: 13 })); + TestBed.flushEffects(); + responses[1].next(ok(result(13))); + expect(service.state()).toMatchObject({ status: "success", data: { programId: 13 } }); + }); + it("clears immediately on user and role changes", () => { + responses[0].next(ok(result())); + profile.set({ id: 8 }); + expect(service.state().status).toBe("loading"); + TestBed.flushEffects(); + responses[0].next(ok(result())); + expect(service.state().status).toBe("loading"); + program.set(Object.assign(new Program(), program(), { isUserExpert: true })); + TestBed.flushEffects(); + expect(responses).toHaveLength(3); + }); + it("refreshes on successful domain changes and cancels on logout", () => { + responses[0].next(ok(result())); + const events = TestBed.inject(EventBus); + events.emit({ type: "ProgramWidgetChanged", payload: {}, occurredAt: new Date() }); + expect(responses).toHaveLength(2); + events.emit({ type: "LoggedOut", payload: {}, occurredAt: new Date() }); + responses[1].next(ok(result())); + expect(service.state()).toMatchObject({ status: "failure", error: "unauthorized" }); + profile.set({ id: 8 }); + TestBed.flushEffects(); + expect(responses).toHaveLength(3); + }); + it("does not request data for an unrelated user", () => { + program.set(Object.assign(Program.default(), { id: 12 })); + TestBed.flushEffects(); + expect(responses).toHaveLength(1); + responses[0].next(ok(result())); + expect(service.state()).toMatchObject({ status: "failure", error: "forbidden" }); + }); + it("rejects mismatched program data", () => { + responses[0].next(ok(result(14))); + expect(service.state()).toMatchObject({ status: "failure", error: "not_found" }); + }); +}); diff --git a/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.ts b/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.ts new file mode 100644 index 000000000..715dc8a43 --- /dev/null +++ b/projects/social_platform/src/app/api/program/facades/detail/program-role-widget.service.ts @@ -0,0 +1,97 @@ +/** @format */ + +import { computed, DestroyRef, effect, inject, Injectable, signal, untracked } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { AuthInfoService } from "@api/auth/facades/auth-info.service"; +import { ProgramDetailMainUIInfoService } from "./ui/program-detail-main-ui-info.service"; +import { GetProgramRoleWidgetUseCase } from "../../use-cases/get-program-role-widget.use-case"; +import { programWidgetRole } from "../../program-widget-presentation"; +import { ProgramRoleWidget, ProgramWidgetError } from "@domain/program/program-role-widget.model"; +import { AsyncState, failure, loading, success } from "@domain/shared/async-state"; +import { EventBus } from "@domain/shared/event-bus"; +import { Subscription } from "rxjs"; +import { User } from "@domain/auth/user.model"; + +/** Локальный запрос без кэша/polling. Старый ответ не переживает смену контекста или logout. */ +@Injectable() +export class ProgramRoleWidgetService { + private readonly auth = inject(AuthInfoService); + private readonly programUI = inject(ProgramDetailMainUIInfoService); + private readonly request = inject(GetProgramRoleWidgetUseCase); + private readonly route = inject(ActivatedRoute); + private readonly destroyRef = inject(DestroyRef); + private readonly events = inject(EventBus); + private readonly routeId = signal(Number(this.route.snapshot.paramMap.get("programId"))); + private readonly rawState = signal>(loading()); + private readonly loadedKey = signal(""); + private readonly loggedOutProfile = signal(undefined); + private activeRequest?: Subscription; + private version = 0; + private readonly key = computed(() => { + const program = this.programUI.program(); + const profile = this.auth.profile(); + const userId = profile !== this.loggedOutProfile() ? profile?.id : null; + const role = programWidgetRole(program); + return userId && role && program?.id === this.routeId() + ? `${program.id}:${userId}:${role}` + : ""; + }); + readonly state = computed>(() => { + if (!this.auth.profile()?.id || this.auth.profile() === this.loggedOutProfile()) + return failure("unauthorized"); + const program = this.programUI.program(); + if (program && !programWidgetRole(program)) return failure("forbidden"); + return this.key() && this.loadedKey() === this.key() + ? this.rawState() + : loading(); + }); + readonly programId = computed(() => this.programUI.program()?.id ?? 0); + + constructor() { + this.route.paramMap + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(params => this.routeId.set(Number(params.get("programId")))); + effect(() => { + const key = this.key(); + untracked(() => this.load(key)); + }); + this.events + .on("LoggedOut") + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.loggedOutProfile.set(this.auth.profile()); + this.load(""); + }); + this.events + .on("ProgramWidgetChanged") + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => this.load(this.key())); + this.destroyRef.onDestroy(() => { + this.version++; + this.activeRequest?.unsubscribe(); + }); + } + retry(): void { + const state = this.state(); + if (state.status === "failure" && state.error === "network") this.load(this.key()); + } + private load(key: string): void { + const version = ++this.version; + this.activeRequest?.unsubscribe(); + this.loadedKey.set(key); + this.rawState.set(loading()); + if (!key) return; + const programId = this.programId(); + this.activeRequest = this.request.execute(programId).subscribe(result => { + if (version !== this.version || key !== this.key()) return; + this.rawState.set( + result.ok + ? result.value.programId === programId + ? success(result.value) + : failure("not_found") + : failure(result.error), + ); + }); + } +} diff --git a/projects/social_platform/src/app/api/program/program-widget-presentation.spec.ts b/projects/social_platform/src/app/api/program/program-widget-presentation.spec.ts new file mode 100644 index 000000000..03f5fb9ca --- /dev/null +++ b/projects/social_platform/src/app/api/program/program-widget-presentation.spec.ts @@ -0,0 +1,141 @@ +/** @format */ + +import { describe, expect, it } from "vitest"; +import { + expertWidgetPresentation, + participantSteps, + programWidgetRole, + withoutProjectPresentation, +} from "./program-widget-presentation"; +import { Program } from "@domain/program/program.model"; +import { ExpertWidget } from "@domain/program/program-role-widget.model"; + +describe("Program widget presentation", () => { + it("uses only program roles with organizer/expert/member priority", () => { + const program = Program.default(); + expect(programWidgetRole(program)).toBeNull(); + program.isUserMember = true; + expect(programWidgetRole(program)).toBe("participant"); + program.isUserExpert = true; + expect(programWidgetRole(program)).toBe("expert"); + program.isUserMember = false; + expect(programWidgetRole(program)).toBe("expert"); + program.isUserManager = true; + expect(programWidgetRole(program)).toBe("organizer"); + }); + it.each([ + [0, 0, "—", "neutral"], + [0, 100, "0,0%", "green"], + [10, 100, "10,0%", "green"], + [1001, 10000, "10,0%", "yellow"], + [25, 100, "25,0%", "yellow"], + [2501, 10000, "25,0%", "red"], + [19, 248, "7,7%", "green"], + ])("formats %i/%i before rounding for colour", (count, total, percentage, tone) => { + expect( + withoutProjectPresentation({ + participants: Number(total), + participantsWithoutProject: Number(count), + projects: 0, + submittedSolutions: 0, + }), + ).toEqual({ percentage, tone, description: `${count} из ${total} участников без проекта` }); + }); + const now = Date.parse("2026-09-01T12:00:00Z"); + const expert: ExpertWidget = { + mode: "distributed", + assigned: 7, + remaining: 3, + evaluationEnds: null, + }; + it.each([ + [49 * 3600000, "green", "3 дня"], + [48 * 3600000, "yellow", "2 дня"], + [23 * 3600000, "yellow", "23 ч"], + [59 * 60000, "yellow", "59 мин"], + [1, "yellow", "1 мин"], + [0, "red", "Срок оценивания истёк"], + [-1, "red", "Срок оценивания истёк"], + ])("handles deadline distance %i", (delta, tone, text) => { + const result = expertWidgetPresentation( + { ...expert, evaluationEnds: new Date(now + Number(delta)).toISOString() }, + true, + now, + ); + expect(result.tone).toBe(tone); + expect(result.text).toContain(text); + }); + it("uses absolute instants across timezones", () => + expect( + expertWidgetPresentation( + { ...expert, evaluationEnds: "2026-09-01T15:00:00+03:00" }, + true, + now, + ).tone, + ).toBe("red")); + it("keeps missing deadline neutral", () => + expect(expertWidgetPresentation(expert, true, now).text).toBe("Срок не установлен")); + it.each([ + [25, "25 минут"], + [21, "21 минута"], + [22, "22 минуты"], + [11, "11 минут"], + [300, "5 часов"], + ])("keeps the full duration and unit for %i minutes", (minutes, value) => { + const result = expertWidgetPresentation( + { ...expert, evaluationEnds: new Date(now + Number(minutes) * 60000).toISOString() }, + true, + now, + ); + expect(result.label).toBe("До конца оценивания"); + expect(result.value).toBe(value); + expect(result.countdown).toBe(true); + }); + it("prioritizes no assignments and completion even after deadline", () => { + const overdue = { ...expert, evaluationEnds: new Date(now - 1000).toISOString() }; + expect( + expertWidgetPresentation({ ...overdue, assigned: 0, remaining: 0 }, true, now), + ).toMatchObject({ text: "Нет назначенных проектов", tone: "neutral" }); + expect(expertWidgetPresentation({ ...overdue, remaining: 0 }, true, now)).toMatchObject({ + text: "Все проекты оценены", + tone: "green", + }); + }); + it("does not fabricate personal work in open mode", () => { + const result = expertWidgetPresentation( + { ...expert, mode: "open", assigned: null, remaining: null }, + true, + now, + ); + expect(result.text).toContain("Свободное оценивание"); + expect(result.text).not.toContain("Все проекты оценены"); + }); + it("does not imply mandatory submission in noncompetitive programs", () => + expect(expertWidgetPresentation(expert, false, now).text).toBe("Без обязательной сдачи")); + it("retains open evaluation and its deadline in noncompetitive programs", () => { + const result = expertWidgetPresentation( + { + ...expert, + mode: "open", + assigned: null, + remaining: null, + evaluationEnds: new Date(now).toISOString(), + }, + false, + now, + ); + expect(result.text).toBe("Свободное оценивание. Срок оценивания истёк"); + }); + it.each(["none", "not_submitted", "not_applicable"] as const)( + "keeps inactive stages for %s", + stage => + expect(participantSteps(stage).every(step => !step.current && !step.completed)).toBe(true), + ); + it("distinguishes current and completed stages", () => { + expect(participantSteps("submitted").map(s => s.completed)).toEqual([false, false, false]); + expect(participantSteps("review").map(s => s.completed)).toEqual([true, false, false]); + expect(participantSteps("evaluated").map(s => s.completed)).toEqual([true, true, true]); + for (const stage of ["submitted", "review", "evaluated"] as const) + expect(participantSteps(stage).filter(s => s.current && s.completed)).toHaveLength(0); + }); +}); diff --git a/projects/social_platform/src/app/api/program/program-widget-presentation.ts b/projects/social_platform/src/app/api/program/program-widget-presentation.ts new file mode 100644 index 000000000..ca1040f59 --- /dev/null +++ b/projects/social_platform/src/app/api/program/program-widget-presentation.ts @@ -0,0 +1,123 @@ +/** @format */ + +import { + ExpertWidget, + OrganizerWidget, + ParticipantStage, + ProgramWidgetRole, +} from "@domain/program/program-role-widget.model"; +import { Program } from "@domain/program/program.model"; + +export type WidgetTone = "neutral" | "green" | "yellow" | "red"; + +export interface ExpertWidgetStatus { + label: string | null; + value: string; + text: string; + countdown: boolean; + tone: WidgetTone; + tooltip: string; +} + +/** Полные единицы времени остаются видимыми; склонение учитывает 11–14 и 21/22. */ +function durationText(count: number, forms: [string, string, string]): string { + const plural = new Intl.PluralRules("ru-RU").select(count); + return `${count} ${forms[plural === "one" ? 0 : plural === "few" ? 1 : 2]}`; +} + +/** Только контекстные флаги; глобальная роль пользователя и наличие назначений не подходят. */ +export function programWidgetRole(program: Program | undefined): ProgramWidgetRole | null { + return program?.isUserManager + ? "organizer" + : program?.isUserExpert + ? "expert" + : program?.isUserMember + ? "participant" + : null; +} + +/** Цвет рассчитывается до округления. Нулевой знаменатель — неприменимая доля. */ +export function withoutProjectPresentation(metrics: OrganizerWidget) { + const { participants: total, participantsWithoutProject: count } = metrics; + const percentage = total > 0 ? (count / total) * 100 : null; + const tone: WidgetTone = + percentage === null + ? "neutral" + : percentage <= 10 + ? "green" + : percentage <= 25 + ? "yellow" + : "red"; + return { + tone, + percentage: percentage === null ? "—" : `${percentage.toFixed(1).replace(".", ",")}%`, + description: `${count} из ${total} участников без проекта`, + }; +} + +/** Состояния работы имеют приоритет над дедлайном; open не создаёт персональный остаток. */ +export function expertWidgetPresentation( + expert: ExpertWidget, + competitive: boolean, + now: number, +): ExpertWidgetStatus { + const deadline = expert.evaluationEnds ? Date.parse(expert.evaluationEnds) : NaN; + const tooltip = Number.isFinite(deadline) + ? new Intl.DateTimeFormat("ru-RU", { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + timeZoneName: "short", + }).format(deadline) + : ""; + const modeLabel = expert.mode === "open" ? "Свободное оценивание" : null; + const status = ( + value: string, + tone: WidgetTone, + date = "", + label = modeLabel, + countdown = false, + ): ExpertWidgetStatus => ({ + label, + value, + text: label ? `${label}. ${value}` : value, + tone, + tooltip: date, + countdown, + }); + // Неконкурсная программа не подразумевает сдачу; свободное оценивание остаётся доступным. + if (!competitive && expert.mode === "distributed") + return status("Без обязательной сдачи", "neutral"); + if (expert.mode === "distributed") { + if (expert.assigned === 0) return status("Нет назначенных проектов", "neutral"); + if (expert.remaining === 0) return status("Все проекты оценены", "green"); + } + if (!Number.isFinite(deadline)) return status("Срок не установлен", "neutral"); + const remaining = deadline - now; + if (remaining <= 0) return status("Срок оценивания истёк", "red", tooltip); + const duration = + remaining < 3600000 + ? durationText(Math.ceil(remaining / 60000), ["минута", "минуты", "минут"]) + : remaining < 86400000 + ? durationText(Math.ceil(remaining / 3600000), ["час", "часа", "часов"]) + : durationText(Math.ceil(remaining / 86400000), ["день", "дня", "дней"]); + return status( + modeLabel ? `Осталось ${duration}` : duration, + remaining <= 48 * 3600000 ? "yellow" : "green", + tooltip, + modeLabel ?? "До конца оценивания", + true, + ); +} + +/** Проверка остаётся текущей без галочки; серверный evaluated завершает всю цепочку. */ +export function participantSteps(stage: ParticipantStage) { + const current = ["submitted", "review", "evaluated"].indexOf(stage); + return ["Отправлен", "Проверка", "Оценён"].map((label, index) => ({ + label, + current: stage !== "evaluated" && current === index, + completed: stage === "evaluated" || index < current, + })); +} diff --git a/projects/social_platform/src/app/api/program/program-widget-refresh.spec.ts b/projects/social_platform/src/app/api/program/program-widget-refresh.spec.ts new file mode 100644 index 000000000..4fec07113 --- /dev/null +++ b/projects/social_platform/src/app/api/program/program-widget-refresh.spec.ts @@ -0,0 +1,63 @@ +/** @format */ + +import { TestBed } from "@angular/core/testing"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { Subject } from "rxjs"; +import { EventBus } from "@domain/shared/event-bus"; +import { ProgramRepositoryPort } from "@domain/program/ports/program.repository.port"; +import { ProjectProgramRepositoryPort } from "@domain/project/ports/project-program.repository.port"; +import { ProjectRatingRepositoryPort } from "@domain/project/ports/project-rating.repository.port"; +import { Project } from "@domain/project/project.model"; +import { ApplyProjectToProgramUseCase } from "./use-cases/apply-project-to-program.use-case"; +import { RateProjectUseCase } from "./use-cases/rate-project.use-case"; +import { SubmitCompetitiveProjectUseCase } from "@api/project/use-cases/submit-competitive-project.use-case"; +import { UpdateProgramLinkFieldsUseCase } from "@api/project/use-cases/update-program-link-fields.use-case"; + +describe("Program widget refresh after business operations", () => { + let response: Subject; + const changed = vi.fn(); + beforeEach(() => { + response = new Subject(); + changed.mockClear(); + const operation = () => response; + TestBed.configureTestingModule({ + providers: [ + { + provide: ProgramRepositoryPort, + useValue: { applyProjectToProgram: operation, submitCompettetiveProject: operation }, + }, + { provide: ProjectProgramRepositoryPort, useValue: { updateProgramLinkFields: operation } }, + { + provide: ProjectRatingRepositoryPort, + useValue: { rate: operation, formValuesToDTO: () => [] }, + }, + ], + }); + TestBed.inject(EventBus).on("ProgramWidgetChanged").subscribe(changed); + }); + const operations = [ + [ + "project link", + () => + TestBed.inject(ApplyProjectToProgramUseCase).execute(12, { + project: { id: 5 } as Project, + programFieldValues: [], + }), + ], + ["case/fields", () => TestBed.inject(UpdateProgramLinkFieldsUseCase).execute(34, [])], + ["submission", () => TestBed.inject(SubmitCompetitiveProjectUseCase).execute(34)], + ["evaluation", () => TestBed.inject(RateProjectUseCase).execute(5, [], {})], + ] as const; + it.each(operations)("refreshes after successful %s, never before response", (_, run) => { + run().subscribe(); + expect(changed).not.toHaveBeenCalled(); + response.next({}); + response.complete(); + expect(changed).toHaveBeenCalledOnce(); + }); + it.each(operations)("does not refresh after failed %s", (_, run) => { + run().subscribe(); + response.error(new Error("request failed")); + expect(changed).not.toHaveBeenCalled(); + }); +}); diff --git a/projects/social_platform/src/app/api/program/use-cases/apply-project-to-program.use-case.ts b/projects/social_platform/src/app/api/program/use-cases/apply-project-to-program.use-case.ts index 398cb6182..83e6cdf39 100644 --- a/projects/social_platform/src/app/api/program/use-cases/apply-project-to-program.use-case.ts +++ b/projects/social_platform/src/app/api/program/use-cases/apply-project-to-program.use-case.ts @@ -1,7 +1,9 @@ /** @format */ +import { EventBus } from "@domain/shared/event-bus"; + import { inject, Injectable } from "@angular/core"; -import { catchError, map, Observable, of } from "rxjs"; +import { catchError, map, Observable, of, tap } from "rxjs"; import { ProgramRepositoryPort } from "@domain/program/ports/program.repository.port"; import { fail, ok, Result } from "@domain/shared/result.type"; import { ApplyToProgramDTO } from "@domain/program/dto/apply-to-program.model"; @@ -9,6 +11,7 @@ import { ApplyToProgramDTO } from "@domain/program/dto/apply-to-program.model"; /** Сценарий: подать проект в программу; ошибка → `apply_project_to_program_error`. */ @Injectable({ providedIn: "root" }) export class ApplyProjectToProgramUseCase { + private readonly events = inject(EventBus); private readonly programRepositoryPort = inject(ProgramRepositoryPort); execute( @@ -16,6 +19,9 @@ export class ApplyProjectToProgramUseCase { dto: ApplyToProgramDTO, ): Observable> { return this.programRepositoryPort.applyProjectToProgram(programId, dto).pipe( + tap(() => + this.events.emit({ type: "ProgramWidgetChanged", payload: {}, occurredAt: new Date() }), + ), map(result => ok(result)), catchError(error => of(fail({ kind: "apply_project_to_program_error" as const, cause: error })), diff --git a/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.spec.ts b/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.spec.ts new file mode 100644 index 000000000..710e61413 --- /dev/null +++ b/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.spec.ts @@ -0,0 +1,49 @@ +/** @format */ + +import { TestBed } from "@angular/core/testing"; +import { HttpErrorResponse } from "@angular/common/http"; +import { of, throwError } from "rxjs"; +import { describe, expect, it, vi } from "vitest"; +import { ProgramRepositoryPort } from "@domain/program/ports/program.repository.port"; +import { GetProgramRoleWidgetUseCase } from "./get-program-role-widget.use-case"; + +describe("GetProgramRoleWidgetUseCase", () => { + it.each([ + [0, "network"], + [500, "network"], + [401, "unauthorized"], + [403, "forbidden"], + [404, "not_found"], + [409, "integrity"], + ])("maps status %i without leaking body", (status, kind) => { + TestBed.configureTestingModule({ + providers: [ + { + provide: ProgramRepositoryPort, + useValue: { + getRoleWidget: () => + throwError( + () => + new HttpErrorResponse({ status: Number(status), error: { secret: "raw body" } }), + ), + }, + }, + ], + }); + TestBed.inject(GetProgramRoleWidgetUseCase) + .execute(12) + .subscribe(result => expect(result).toEqual({ ok: false, error: kind })); + }); + it("uses the narrow endpoint port, never the manager API", () => { + const repository = { + getRoleWidget: vi.fn(() => of({ programId: 12, role: "expert" })), + getManagerOverview: vi.fn(), + }; + TestBed.configureTestingModule({ + providers: [{ provide: ProgramRepositoryPort, useValue: repository }], + }); + TestBed.inject(GetProgramRoleWidgetUseCase).execute(12).subscribe(); + expect(repository.getRoleWidget).toHaveBeenCalledWith(12); + expect(repository.getManagerOverview).not.toHaveBeenCalled(); + }); +}); diff --git a/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.ts b/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.ts new file mode 100644 index 000000000..65b602fa6 --- /dev/null +++ b/projects/social_platform/src/app/api/program/use-cases/get-program-role-widget.use-case.ts @@ -0,0 +1,33 @@ +/** @format */ + +import { HttpErrorResponse } from "@angular/common/http"; +import { inject, Injectable } from "@angular/core"; +import { ProgramRepositoryPort } from "@domain/program/ports/program.repository.port"; +import { ProgramRoleWidget, ProgramWidgetError } from "@domain/program/program-role-widget.model"; +import { fail, ok, Result } from "@domain/shared/result.type"; +import { catchError, map, Observable, of } from "rxjs"; + +/** Ошибки не содержат raw body и не превращаются в нулевые метрики. */ +@Injectable({ providedIn: "root" }) +export class GetProgramRoleWidgetUseCase { + private readonly repository = inject(ProgramRepositoryPort); + execute(programId: number): Observable> { + return this.repository.getRoleWidget(programId).pipe( + map(data => ok(data)), + catchError((error: unknown) => { + const status = error instanceof HttpErrorResponse ? error.status : 0; + const kind: ProgramWidgetError = + status === 401 + ? "unauthorized" + : status === 403 + ? "forbidden" + : status === 404 + ? "not_found" + : status === 409 + ? "integrity" + : "network"; + return of(fail(kind)); + }), + ); + } +} diff --git a/projects/social_platform/src/app/api/program/use-cases/rate-project.use-case.ts b/projects/social_platform/src/app/api/program/use-cases/rate-project.use-case.ts index 23f5e0de2..0b323babe 100644 --- a/projects/social_platform/src/app/api/program/use-cases/rate-project.use-case.ts +++ b/projects/social_platform/src/app/api/program/use-cases/rate-project.use-case.ts @@ -1,7 +1,9 @@ /** @format */ +import { EventBus } from "@domain/shared/event-bus"; + import { inject, Injectable } from "@angular/core"; -import { catchError, map, Observable, of } from "rxjs"; +import { catchError, map, Observable, of, tap } from "rxjs"; import { ProjectRatingRepositoryPort } from "@domain/project/ports/project-rating.repository.port"; import { ProjectRatingCriterion } from "@domain/project/project-rating-criterion"; import { fail, ok, Result } from "@domain/shared/result.type"; @@ -9,6 +11,7 @@ import { fail, ok, Result } from "@domain/shared/result.type"; /** Сценарий: выставить оценку проекту (эксперт); ошибка → `rate_project_error`. */ @Injectable({ providedIn: "root" }) export class RateProjectUseCase { + private readonly events = inject(EventBus); private readonly projectRatingRepositoryPort = inject(ProjectRatingRepositoryPort); execute( @@ -19,6 +22,9 @@ export class RateProjectUseCase { const dto = this.projectRatingRepositoryPort.formValuesToDTO(criteria, outputVals); return this.projectRatingRepositoryPort.rate(projectId, dto).pipe( + tap(() => + this.events.emit({ type: "ProgramWidgetChanged", payload: {}, occurredAt: new Date() }), + ), map(() => ok(undefined)), catchError(error => of(fail({ kind: "rate_project_error" as const, cause: error }))), ); diff --git a/projects/social_platform/src/app/api/project/use-cases/submit-competitive-project.use-case.ts b/projects/social_platform/src/app/api/project/use-cases/submit-competitive-project.use-case.ts index 322ec83b7..ef2d757b1 100644 --- a/projects/social_platform/src/app/api/project/use-cases/submit-competitive-project.use-case.ts +++ b/projects/social_platform/src/app/api/project/use-cases/submit-competitive-project.use-case.ts @@ -1,7 +1,9 @@ /** @format */ +import { EventBus } from "@domain/shared/event-bus"; + import { inject, Injectable } from "@angular/core"; -import { catchError, map, Observable, of } from "rxjs"; +import { catchError, map, Observable, of, tap } from "rxjs"; import { ProgramRepositoryPort } from "@domain/program/ports/program.repository.port"; import { Project } from "@domain/project/project.model"; import { fail, ok, Result } from "@domain/shared/result.type"; @@ -9,12 +11,16 @@ import { fail, ok, Result } from "@domain/shared/result.type"; /** Сценарий: подать проект на конкурс программы; ошибка → `submit_competitive_project_error`. */ @Injectable({ providedIn: "root" }) export class SubmitCompetitiveProjectUseCase { + private readonly events = inject(EventBus); private readonly programRepositoryPort = inject(ProgramRepositoryPort); execute( relationId: number, ): Observable> { return this.programRepositoryPort.submitCompettetiveProject(relationId).pipe( + tap(() => + this.events.emit({ type: "ProgramWidgetChanged", payload: {}, occurredAt: new Date() }), + ), map(project => ok(project)), catchError(error => of(fail({ kind: "submit_competitive_project_error" as const, cause: error })), diff --git a/projects/social_platform/src/app/api/project/use-cases/update-program-link-fields.use-case.ts b/projects/social_platform/src/app/api/project/use-cases/update-program-link-fields.use-case.ts index 9f3b29aeb..b8f1b369e 100644 --- a/projects/social_platform/src/app/api/project/use-cases/update-program-link-fields.use-case.ts +++ b/projects/social_platform/src/app/api/project/use-cases/update-program-link-fields.use-case.ts @@ -1,7 +1,9 @@ /** @format */ +import { EventBus } from "@domain/shared/event-bus"; + import { inject, Injectable } from "@angular/core"; -import { catchError, map, Observable, of } from "rxjs"; +import { catchError, map, Observable, of, tap } from "rxjs"; import { ProjectProgramRepositoryPort } from "@domain/project/ports/project-program.repository.port"; import { ProjectNewAdditionalProgramFields } from "@domain/program/partner-program-fields.model"; import { ProgramLinkFieldsError } from "@domain/project/program-link-fields.model"; @@ -11,6 +13,7 @@ import { fail, ok, Result } from "@domain/shared/result.type"; /** Partial update of additional values for exactly one program-project link. */ @Injectable({ providedIn: "root" }) export class UpdateProgramLinkFieldsUseCase { + private readonly events = inject(EventBus); private readonly projectProgramRepositoryPort = inject(ProjectProgramRepositoryPort); execute( @@ -18,6 +21,9 @@ export class UpdateProgramLinkFieldsUseCase { newValues: ProjectNewAdditionalProgramFields[], ): Observable> { return this.projectProgramRepositoryPort.updateProgramLinkFields(programLinkId, newValues).pipe( + tap(() => + this.events.emit({ type: "ProgramWidgetChanged", payload: {}, occurredAt: new Date() }), + ), map(() => ok(undefined)), catchError(error => of(fail(mapProgramLinkFieldsError(error)))), ); diff --git a/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts b/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts index 0cd3f4c67..4fca3c076 100644 --- a/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts +++ b/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts @@ -1,6 +1,7 @@ /** @format */ import { HttpParams } from "@angular/common/http"; +import { ProgramRoleWidget } from "../program-role-widget.model"; import { Observable } from "rxjs"; import { ApiPagination } from "../../other/api-pagination.model"; import { Program, ProgramDataSchema } from "../program.model"; @@ -27,6 +28,7 @@ import { /** Порт репозитория программ: список/детали/создание/регистрация, проекты/участники/фильтры. */ export abstract class ProgramRepositoryPort { + abstract getRoleWidget(programId: number): Observable; abstract getAll( skip: number, take: number, diff --git a/projects/social_platform/src/app/domain/program/program-role-widget.model.ts b/projects/social_platform/src/app/domain/program/program-role-widget.model.ts new file mode 100644 index 000000000..c59feb313 --- /dev/null +++ b/projects/social_platform/src/app/domain/program/program-role-widget.model.ts @@ -0,0 +1,49 @@ +/** + * Read-only данные Angular-проектов; legacy currentApplication не используется. + * + * @format + */ + +export type ProgramWidgetRole = "organizer" | "expert" | "participant"; +export type ParticipantStage = + | "none" + | "not_submitted" + | "submitted" + | "review" + | "evaluated" + | "not_applicable"; +export interface ParticipantWidget { + participantProject: { id: number; name: string; programLinkId: number } | null; + caseProvided: boolean; + caseName: string | null; + stage: ParticipantStage; + submissionOpen: boolean; +} +export interface OrganizerWidget { + participants: number; + projects: number; + submittedSolutions: number | null; + participantsWithoutProject: number; +} +export interface ExpertWidget { + mode: "open" | "distributed"; + assigned: number | null; + remaining: number | null; + evaluationEnds: string | null; +} +interface WidgetContext { + programId: number; + isCompetitive: boolean; +} +export type ProgramRoleWidget = WidgetContext & + ( + | { role: "participant"; participant: ParticipantWidget } + | { role: "organizer"; organizer: OrganizerWidget } + | { role: "expert"; expert: ExpertWidget } + ); +export type ProgramWidgetError = + | "network" + | "forbidden" + | "unauthorized" + | "not_found" + | "integrity"; diff --git a/projects/social_platform/src/app/domain/program/program.model.ts b/projects/social_platform/src/app/domain/program/program.model.ts index ae846cc77..e62c06603 100644 --- a/projects/social_platform/src/app/domain/program/program.model.ts +++ b/projects/social_platform/src/app/domain/program/program.model.ts @@ -31,6 +31,7 @@ export class Program { likesCount!: number; isUserLiked!: boolean; isUserManager!: boolean; + isUserExpert?: boolean; isUserMember!: boolean; currentApplication!: ProgramCurrentApplication | null; welcomeAcknowledgedAt!: string | null; diff --git a/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts b/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts index 385b8e6be..8be0062c3 100644 --- a/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts +++ b/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts @@ -1,6 +1,7 @@ /** @format */ import { inject, Injectable } from "@angular/core"; +import { ProgramRoleWidget } from "@domain/program/program-role-widget.model"; import { ApiService } from "@corelib"; import { Observable } from "rxjs"; import { HttpParams } from "@angular/common/http"; @@ -30,6 +31,9 @@ import { /** HTTP-адаптер программ: `/programs`, `/auth/public-users` (детали, проекты, участники, фильтры, регистрация). */ @Injectable({ providedIn: "root" }) export class ProgramHttpAdapter { + getRoleWidget(programId: number): Observable { + return this.apiService.get(`${this.PROGRAMS_URL}/${programId}/analytics-widget/`); + } private readonly PROGRAMS_URL = "/programs"; private readonly AUTH_PUBLIC_USERS_URL = "/auth/public-users"; private readonly apiService = inject(ApiService); diff --git a/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts b/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts index cb07aa6b5..5ad0f713e 100644 --- a/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts +++ b/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts @@ -1,6 +1,7 @@ /** @format */ import { HttpParams } from "@angular/common/http"; +import { ProgramRoleWidget } from "@domain/program/program-role-widget.model"; import { inject, Injectable } from "@angular/core"; import { map, Observable, tap, throwError } from "rxjs"; import { User } from "@domain/auth/user.model"; @@ -35,6 +36,9 @@ import { /** Репозиторий программ: `EntityCache` для `getOne`, остальное — passthrough. */ @Injectable({ providedIn: "root" }) export class ProgramRepository implements ProgramRepositoryPort { + getRoleWidget(programId: number): Observable { + return this.programAdapter.getRoleWidget(programId); + } private readonly programAdapter = inject(ProgramHttpAdapter); private readonly entityCache = new EntityCache(5 * 60 * 1000); private readonly eventBus = inject(EventBus); diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.html b/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.html index 8dafbcb17..8363c9905 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.html +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.html @@ -4,7 +4,7 @@
- @if (!program()!.isUserMember && !program()!.isUserManager) { + @if (!program()!.isUserMember && !program()!.isUserManager && !program()!.isUserExpert) {
1000) {
@@ -56,17 +55,19 @@

о программе

(addNews)="onAddNews($event)" > } - @for (n of news(); track n.id) { - + @if (program()!.isUserMember || program()!.isUserManager) { + @for (n of news(); track n.id) { + + } }
diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.ts b/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.ts index b9cd5d07a..285fe23e1 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.ts +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/main.component.ts @@ -17,7 +17,7 @@ import { RouterModule } from "@angular/router"; import { ButtonComponent, IconComponent } from "@ui/primitives"; import { ModalComponent } from "@ui/primitives/modal/modal.component"; import { MatProgressBarModule } from "@angular/material/progress-bar"; -import { SoonCardComponent } from "@ui/primitives/soon-card/soon-card.component"; +import { ProgramRoleWidgetComponent } from "./role-widget/program-role-widget.component"; import { NewsFormComponent } from "@ui/widgets/news-form/news-form.component"; import { NewsCardComponent } from "@ui/widgets/news-card/news-card.component"; import { ParseBreaksPipe, ParseLinksPipe } from "@corelib"; @@ -44,7 +44,7 @@ import { ProgramLinksComponent } from "@ui/widgets/program-links/program-links.c ParseLinksPipe, ModalComponent, MatProgressBarModule, - SoonCardComponent, + ProgramRoleWidgetComponent, NewsFormComponent, ModalComponent, MatProgressBarModule, diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/main.roles.spec.ts b/projects/social_platform/src/app/ui/pages/program/detail/main/main.roles.spec.ts new file mode 100644 index 000000000..3f9e31b43 --- /dev/null +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/main.roles.spec.ts @@ -0,0 +1,173 @@ +/** @format */ + +import { Component, input, output } from "@angular/core"; +import { TestBed } from "@angular/core/testing"; +import { ActivatedRoute, provideRouter } from "@angular/router"; +import { By } from "@angular/platform-browser"; +import { BehaviorSubject, of } from "rxjs"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { ProgramDetailMainComponent } from "./main.component"; +import { ProgramRoleWidgetComponent } from "./role-widget/program-role-widget.component"; +import { NewsFormComponent } from "@ui/widgets/news-form/news-form.component"; +import { NewsCardComponent } from "@ui/widgets/news-card/news-card.component"; +import { ProgramDetailMainService } from "@api/program/facades/detail/program-detail-main-info.service"; +import { ProgramDetailMainUIInfoService } from "@api/program/facades/detail/ui/program-detail-main-ui-info.service"; +import { NewsInfoService } from "@api/news/news-info.service"; +import { ExpandService } from "@api/expand/expand.service"; +import { ProjectAdditionalService } from "@api/project/facades/edit/project-additional.service"; +import { LoadingService } from "@api/shared/loading.service"; +import { FetchNewsUseCase } from "@api/program/use-cases/fetch-news.use-case"; +import { AddNewsUseCase } from "@api/program/use-cases/add-news.use-case"; +import { ReadNewsUseCase } from "@api/program/use-cases/read-news.use-case"; +import { DeleteNewsUseCase } from "@api/program/use-cases/delete-news.use-case"; +import { EditNewsUseCase } from "@api/program/use-cases/edit-news.use-case"; +import { ToggleLikeUseCase } from "@api/program/use-cases/toggle-like.use-case"; +import { AcknowledgeProgramWelcomeUseCase } from "@api/program/use-cases/acknowledge-program-welcome.use-case"; +import { Program } from "@domain/program/program.model"; +import { FeedNews } from "@domain/news/project-news.model"; +import { ok } from "@domain/shared/result.type"; +import { signal } from "@angular/core"; + +@Component({ selector: "app-news-form", template: "Форма новости" }) +class NewsFormStub { + pending = input(false); + addNews = output<{ text: string; files: string[] }>(); +} +@Component({ selector: "app-news-card", template: "{{ feedItem().text }}" }) +class NewsCardStub { + feedItem = input.required(); + resourceLink = input(); + isOwner = input(false); + like = output(); + edited = output(); + delete = output(); +} +@Component({ selector: "app-program-role-widget", template: "Виджет" }) +class WidgetStub {} + +describe("Program page: program-scoped news and role visibility", () => { + const news = { ...FeedNews.default(), id: 1, text: "Существующая новость", files: [] }; + const added = { ...news, id: 2, text: "Созданная организатором новость" }; + const fetch = vi.fn(), + add = vi.fn(); + let data: BehaviorSubject<{ data: Program }>; + + beforeEach(async () => { + vi.useFakeTimers(); + data = new BehaviorSubject({ data: Program.default() }); + fetch.mockReset().mockReturnValue(of(ok({ count: 1, results: [news] }))); + add.mockReset().mockReturnValue(of(ok(added))); + vi.spyOn(ProgramDetailMainService.prototype, "initScroll").mockImplementation(() => {}); + await TestBed.configureTestingModule({ + imports: [ProgramDetailMainComponent], + providers: [ + provideRouter([]), + ProgramDetailMainUIInfoService, + NewsInfoService, + { + provide: ActivatedRoute, + useValue: { + params: of({ programId: 12 }), + queryParams: of({}), + data, + snapshot: { params: { programId: 12 } }, + }, + }, + { provide: LoadingService, useValue: { hide: vi.fn() } }, + { provide: FetchNewsUseCase, useValue: { execute: fetch } }, + { provide: AddNewsUseCase, useValue: { execute: add } }, + { + provide: ProjectAdditionalService, + useValue: { + isSend$: signal({ status: "initial" }), + errorAssignProjectToProgramModalMessage: signal(null), + }, + }, + ...[ + ReadNewsUseCase, + DeleteNewsUseCase, + EditNewsUseCase, + ToggleLikeUseCase, + AcknowledgeProgramWelcomeUseCase, + ].map(provide => ({ provide, useValue: {} })), + ], + }) + .overrideComponent(ProgramDetailMainComponent, { + remove: { + imports: [NewsFormComponent, NewsCardComponent, ProgramRoleWidgetComponent], + providers: [ExpandService], + }, + add: { + imports: [NewsFormStub, NewsCardStub, WidgetStub], + providers: [ + { + provide: ExpandService, + useValue: { + descriptionExpandable: signal(false), + readFullDescription: signal(false), + checkExpandable: vi.fn(), + }, + }, + ], + }, + }) + .compileComponents(); + }); + afterEach(() => { + vi.runOnlyPendingTimers(); + TestBed.resetTestingModule(); + vi.restoreAllMocks(); + vi.useRealTimers(); + }); + function render(role: Partial) { + data.next({ + data: { + ...Program.default(), + id: 12, + isUserMember: false, + isUserManager: false, + isUserExpert: false, + welcomeAcknowledgedAt: "2026-09-01T00:00:00Z", + ...role, + }, + }); + const fixture = TestBed.createComponent(ProgramDetailMainComponent); + fixture.componentInstance["appWidth"] = 1280; + fixture.detectChanges(); + return fixture; + } + it("loads and shows both existing and newly created news for manager without member role", () => { + const f = render({ isUserManager: true }); + expect(fetch).toHaveBeenCalledExactlyOnceWith(10, 0, 12); + expect(f.nativeElement.textContent).toContain(news.text); + const form = f.debugElement.query(By.directive(NewsFormStub)); + expect(form).toBeTruthy(); + form.componentInstance.addNews.emit({ text: added.text, files: [] }); + f.detectChanges(); + expect(add).toHaveBeenCalledExactlyOnceWith(12, { text: added.text, files: [] }); + expect(f.nativeElement.textContent).toContain(added.text); + expect(f.nativeElement.querySelectorAll("app-news-card")).toHaveLength(2); + }); + it("keeps member news without granting the creation form", () => { + const f = render({ isUserMember: true }); + expect(fetch).toHaveBeenCalledOnce(); + expect(f.nativeElement.textContent).toContain(news.text); + expect(f.nativeElement.querySelector("app-news-form")).toBeNull(); + }); + it("shows expert widget without requesting or revealing member/manager news", () => { + const f = render({ isUserExpert: true }); + TestBed.inject(NewsInfoService).applyAddNews(news); + f.detectChanges(); + expect(f.nativeElement.querySelector("app-program-role-widget")).toBeTruthy(); + expect(f.nativeElement.querySelector("app-news-card,app-news-form")).toBeNull(); + expect(fetch).not.toHaveBeenCalled(); + }); + it("preserves advertisement and no internal content for an unrelated user", () => { + const f = render({}); + expect(f.nativeElement.querySelector(".program__advertisement")).toBeTruthy(); + expect( + f.nativeElement.querySelector("app-program-role-widget,app-news-card,app-news-form"), + ).toBeNull(); + expect(fetch).not.toHaveBeenCalled(); + }); +}); diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.html b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.html new file mode 100644 index 000000000..3de919221 --- /dev/null +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.html @@ -0,0 +1,201 @@ + + +
+
+

аналитика

+ {{ data() ? roleNames[data()!.role] : " " }} +
+ @if (data(); as data) { +
+ @switch (data.role) { + @case ("participant") { + @let participant = data.participant; + @let project = participant.participantProject; + @let caseText = + participant.caseProvided + ? participant.caseName + ? "Кейс: " + participant.caseName + : "Кейс не выбран" + : "Кейсы не предусмотрены"; +
+ @if (participant.caseName) { + + Кейс:{{ participant.caseName }} + + } @else { + {{ caseText }} + } + @if (project) { + + Проект:{{ project.name }} + + } @else { + Проект не подан + } +
+
+ @if (participant.stage === "not_submitted") { + Не отправлен + } + @if (participant.stage === "not_applicable") { + Сдача не предусмотрена + } +
+
    + @for (step of steps(participant.stage); track step.label) { +
  1. + + {{ step.label }} +
  2. + } +
+ } + @case ("organizer") { + @let metrics = data.organizer; + @let ratio = withoutProject(metrics); +
+
+
Участники
+
+ {{ count(metrics.participants) }} +
+
+
+
Проекты
+
+ {{ count(metrics.projects) }} +
+
+
+
Сдано
решений
+
+ {{ count(metrics.submittedSolutions) }} +
+
+
+
Без проектов
+
+ {{ count(metrics.participantsWithoutProject) }} + {{ ratio.percentage }} +
+
+
+ } + @case ("expert") { +
+
+
Назначено
проектов
+
+ {{ count(data.expert.assigned) }} +
+
+
+
Осталось
оценить
+
+ {{ count(data.expert.remaining) }} +
+
+
+ @if (expertState(); as status) { +

+ @if (status.label) { + {{ status.label }} + } + {{ status.value }} +

+ } + } + } +
+
+ @switch (data.role) { + @case ("organizer") { + Открыть → + } + @case ("expert") { + Открыть → + } + @case ("participant") { + @if (data.participant.participantProject; as project) { + Открыть → + } @else if (data.participant.submissionOpen) { + + } @else { + Срок подачи закрыт + } + } + } +
+ } @else if (state(); as state) { + @if (state.status === "failure") { +

{{ errorMessages[state.error] }}

+
+ @if (state.error === "network") { + + } +
+ } @else { +
+ +
+
+ } + } +
diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.scss b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.scss new file mode 100644 index 000000000..d809a58b6 --- /dev/null +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.scss @@ -0,0 +1,294 @@ +:host { + display: block; + width: 157px; +} + +.widget { + box-sizing: border-box; + display: grid; + grid-template-rows: 18px minmax(0, 1fr) 22px; + row-gap: 5px; + width: 100%; + + // Исходная карточка при 100%: 157 × 140.984375 CSS px (Mont, desktop). + height: 140.9844px; + padding: 7px 8px; + font-size: 10px; + line-height: 13px; + color: var(--black); + background: var(--light-white); + border: 0.5px solid var(--medium-grey-for-outline); + border-radius: var(--rounded-lg); + + &__header { + display: flex; + gap: 5px; + align-items: center; + justify-content: space-between; + } + + &__badge { + min-height: 12px; + padding: 1px 4px; + font-size: 8px; + line-height: 12px; + color: var(--accent); + background: var(--accent-light); + border-radius: 8px; + } + + h3 { + font-size: 12px; + font-weight: 600; + line-height: 15px; + color: var(--accent); + } + + &__body { + min-width: 0; + min-height: 0; + } + + &__ellipsis { + display: block; + min-width: 0; + overflow: hidden; + color: var(--black); + text-overflow: ellipsis; + white-space: nowrap; + } + + &__project-lines { + display: grid; + gap: 3px; + line-height: 14px; + } + + &__detail-row { + display: flex; + gap: 3px; + min-width: 0; + color: var(--black); + } + + &__label { + flex-shrink: 0; + color: var(--grey-for-text); + } + + &__empty { + color: var(--grey-for-text); + } + + &__stage-state { + height: 12px; + margin-top: 3px; + font-size: 10px; + line-height: 12px; + color: var(--grey-for-text); + } + + &__steps { + display: flex; + justify-content: space-between; + padding: 0; + margin: 0; + list-style: none; + } + + &__steps li { + position: relative; + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + font-size: 8px; + line-height: 11px; + color: var(--grey-for-text); + } + + &__steps li:not(:last-child)::after { + position: absolute; + top: 6px; + left: 50%; + width: 100%; + height: 1px; + content: ""; + background: var(--medium-grey-for-outline); + } + + &__steps li.widget__step--complete::after { + background: var(--accent); + } + + &__dot { + position: relative; + z-index: 1; + display: block; + width: 12px; + height: 12px; + margin-bottom: 3px; + line-height: 12px; + text-align: center; + background: var(--medium-grey-for-outline); + border: 1px solid transparent; + border-radius: 50%; + } + + &__step--complete .widget__dot { + color: var(--light-white); + background: var(--accent); + } + + &__step--current .widget__dot { + background: var(--light-white); + border-color: var(--accent); + } + + &__steps .widget__step--current { + color: var(--accent); + } + + &__metrics { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 4px 6px; + margin: 0; + } + + dt { + font-size: 10px; + line-height: 12px; + color: var(--grey-for-text); + } + + dd { + margin: 0; + overflow: hidden; + font-size: 14px; + font-weight: 600; + line-height: 18px; + text-overflow: ellipsis; + white-space: nowrap; + } + + &__metrics--organizer > div:nth-child(n + 3) dt { + min-height: 24px; + } + + &__without span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + } + + &__without { + display: flex; + gap: 4px; + align-items: center; + } + + &__without small { + display: flex; + flex-shrink: 0; + gap: 3px; + align-items: center; + font-size: 9px; + font-weight: 400; + line-height: 12px; + } + + &__without i { + width: 3px; + height: 3px; + background: currentcolor; + border-radius: 50%; + } + + &__expert-state { + display: grid; + align-content: center; + min-height: 28px; + margin-top: 6px; + font-size: 10px; + line-height: 12px; + } + + &__status-label { + color: var(--grey-for-text); + } + + &__status-value--time { + font-size: 12px; + font-weight: 600; + line-height: 16px; + } + + &__footer { + display: flex; + align-items: center; + justify-content: center; + border-top: 0.5px solid var(--medium-grey-for-outline); + } + + &__footer a, + &__footer button { + padding: 0; + font: inherit; + color: var(--accent); + text-align: center; + cursor: pointer; + background: transparent; + border: 0; + } + + &__footer span { + font-size: 9px; + color: var(--grey-for-text); + } + + &__footer button:disabled { + cursor: default; + opacity: 0.5; + } + + &__error { + display: grid; + place-items: center; + text-align: center; + } + + &__skeleton { + display: grid; + gap: 7px; + padding: 6px 0; + } + + &__skeleton span { + background: var(--medium-grey-for-outline); + border-radius: 4px; + } + + [data-tone="green"] { + color: var(--green-dark); + } + + [data-tone="yellow"] { + color: var(--gold-dark); + } + + [data-tone="red"] { + color: var(--red-dark); + } + + [data-tone="neutral"] { + color: var(--grey-for-text); + } + + a:focus-visible, + button:focus-visible, + [tabindex]:focus-visible { + outline: 1px solid var(--accent); + outline-offset: 1px; + } +} diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.spec.ts b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.spec.ts new file mode 100644 index 000000000..591a77eb1 --- /dev/null +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.spec.ts @@ -0,0 +1,200 @@ +/** @format */ + +import { TestBed } from "@angular/core/testing"; +import { signal } from "@angular/core"; +import { provideRouter } from "@angular/router"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { ProgramRoleWidgetComponent } from "./program-role-widget.component"; +import { ProgramRoleWidgetService } from "@api/program/facades/detail/program-role-widget.service"; +import { DetailProgramInfoService } from "@ui/widgets/detail/services/program/detail-program-info.service"; +import { AsyncState, failure, loading, success } from "@domain/shared/async-state"; +import { ProgramRoleWidget, ProgramWidgetError } from "@domain/program/program-role-widget.model"; + +describe("ProgramRoleWidgetComponent", () => { + const state = signal>(loading()); + const retry = vi.fn(), + create = vi.fn(); + const participant: ProgramRoleWidget = { + role: "participant", + programId: 12, + isCompetitive: true, + participant: { + participantProject: { id: 5, name: "Длинное название ".repeat(20), programLinkId: 34 }, + caseProvided: true, + caseName: "Кейс ".repeat(30), + stage: "review", + submissionOpen: true, + }, + }; + beforeEach(async () => { + retry.mockClear(); + create.mockClear(); + state.set(loading()); + TestBed.configureTestingModule({ + imports: [ProgramRoleWidgetComponent], + providers: [ + provideRouter([]), + { + provide: DetailProgramInfoService, + useValue: { addNewProject: create, applicationPending: signal(false) }, + }, + ], + }); + TestBed.overrideComponent(ProgramRoleWidgetComponent, { + set: { + providers: [ + { provide: ProgramRoleWidgetService, useValue: { state, retry, programId: signal(12) } }, + ], + }, + }); + await TestBed.compileComponents(); + }); + function render(data?: ProgramRoleWidget) { + if (data) state.set(success(data)); + const fixture = TestBed.createComponent(ProgramRoleWidgetComponent); + fixture.detectChanges(); + return fixture; + } + it("shows skeleton without bogus zero counters", () => { + const f = render(); + expect(f.nativeElement.querySelector(".widget__skeleton")).toBeTruthy(); + expect(f.nativeElement.querySelector("dd")).toBeNull(); + }); + it("opens the exact project from both name and action and retains full accessible names", () => { + const f = render(participant); + const links = f.nativeElement.querySelectorAll("a"); + expect(links).toHaveLength(2); + for (const link of links) + expect(link.getAttribute("href")).toBe("/office/projects/5?programLinkId=34"); + expect(links[0].textContent).toContain(participant.participant.participantProject!.name); + expect(f.nativeElement.querySelector('[aria-current="step"]').textContent).toContain( + "Проверка", + ); + expect(f.nativeElement.querySelectorAll(".widget__step--complete")).toHaveLength(1); + }); + it("does not create or submit automatically and uses existing explicit action", () => { + const f = render({ + ...participant, + participant: { ...participant.participant, participantProject: null, stage: "none" }, + }); + expect(create).not.toHaveBeenCalled(); + f.nativeElement.querySelector("button").click(); + expect(create).toHaveBeenCalledWith(12); + }); + it("renders the server-evaluated project as a completed chain", () => { + const f = render({ + ...participant, + participant: { ...participant.participant, stage: "evaluated" }, + }); + expect(f.nativeElement.querySelectorAll(".widget__step--complete")).toHaveLength(3); + expect(f.nativeElement.querySelector('[aria-current="step"]')).toBeNull(); + }); + it("has no broken action when submission is closed", () => { + const f = render({ + ...participant, + participant: { + ...participant.participant, + participantProject: null, + stage: "none", + submissionOpen: false, + }, + }); + expect(f.nativeElement.querySelector("button,a")).toBeNull(); + expect(f.nativeElement.textContent).toContain("Срок подачи закрыт"); + }); + it("keeps a draft project link usable after submission closes", () => { + const f = render({ + ...participant, + participant: { ...participant.participant, stage: "not_submitted", submissionOpen: false }, + }); + expect(f.nativeElement.textContent).toContain("Не отправлен"); + expect(f.nativeElement.querySelectorAll("a")).toHaveLength(2); + }); + it("shows four organizer counters and one inline percentage", () => { + const f = render({ + role: "organizer", + programId: 12, + isCompetitive: true, + organizer: { + participants: 248, + projects: 61, + submittedSolutions: 54, + participantsWithoutProject: 19, + }, + }); + expect(f.nativeElement.querySelectorAll("dd")).toHaveLength(4); + expect(f.nativeElement.textContent).toContain("7,7%"); + expect(f.nativeElement.querySelector("a").getAttribute("href")).toBe( + "/office/program/12/analytics", + ); + }); + it("shows only two expert counters and the real evaluation route", () => { + const f = render({ + role: "expert", + programId: 12, + isCompetitive: true, + expert: { + mode: "distributed", + assigned: 0, + remaining: 0, + evaluationEnds: "2020-01-01T00:00:00Z", + }, + }); + expect(f.nativeElement.querySelectorAll("dd")).toHaveLength(2); + expect(f.nativeElement.textContent).toContain("Нет назначенных проектов"); + expect(f.nativeElement.querySelector("a").getAttribute("href")).toBe( + "/office/program/12/projects-rating", + ); + }); + it("renders open counters as inapplicable", () => { + const f = render({ + role: "expert", + programId: 12, + isCompetitive: true, + expert: { mode: "open", assigned: null, remaining: null, evaluationEnds: null }, + }); + expect( + [...f.nativeElement.querySelectorAll("dd")].map((e: any) => e.textContent.trim()), + ).toEqual(["—", "—"]); + expect(f.nativeElement.textContent).toContain("Свободное оценивание"); + }); + it("updates across the deadline and releases its local clock on destroy", () => { + vi.useFakeTimers(); + const now = Date.parse("2026-09-01T12:00:00Z"); + vi.setSystemTime(now); + try { + const f = render({ + role: "expert", + programId: 12, + isCompetitive: true, + expert: { + mode: "distributed", + assigned: 1, + remaining: 1, + evaluationEnds: new Date(now + 1000).toISOString(), + }, + }); + expect(f.nativeElement.textContent).toContain("1 мин"); + vi.advanceTimersByTime(1000); + f.detectChanges(); + expect(f.nativeElement.textContent).toContain("Срок оценивания истёк"); + const lastTick = f.componentInstance.now(); + f.destroy(); + vi.advanceTimersByTime(1000); + expect(f.componentInstance.now()).toBe(lastTick); + } finally { + vi.useRealTimers(); + } + }); + it("retries only network failure and never displays raw body", () => { + state.set(failure("network")); + const f = render(); + expect(f.nativeElement.textContent).toContain("Не удалось загрузить"); + f.nativeElement.querySelector("button").click(); + expect(retry).toHaveBeenCalledOnce(); + state.set(failure("forbidden")); + f.detectChanges(); + expect(f.nativeElement.querySelector("button")).toBeNull(); + expect(f.nativeElement.textContent).toContain("Нет доступа"); + }); +}); diff --git a/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.ts b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.ts new file mode 100644 index 000000000..96ef889e3 --- /dev/null +++ b/projects/social_platform/src/app/ui/pages/program/detail/main/role-widget/program-role-widget.component.ts @@ -0,0 +1,80 @@ +/** @format */ + +import { + ChangeDetectionStrategy, + Component, + computed, + DestroyRef, + inject, + signal, +} from "@angular/core"; +import { RouterLink } from "@angular/router"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { AppRoutes } from "@api/paths/app-routes"; +import { ProgramRoleWidgetService } from "@api/program/facades/detail/program-role-widget.service"; +import { + expertWidgetPresentation, + participantSteps, + withoutProjectPresentation, +} from "@api/program/program-widget-presentation"; +import { DetailProgramInfoService } from "@ui/widgets/detail/services/program/detail-program-info.service"; + +/** Компактный виджет только страницы программы. Габариты соответствуют исходному SoonCard. */ +@Component({ + selector: "app-program-role-widget", + imports: [RouterLink, MatTooltipModule], + providers: [ProgramRoleWidgetService], + templateUrl: "./program-role-widget.component.html", + styleUrl: "./program-role-widget.component.scss", + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ProgramRoleWidgetComponent { + readonly service = inject(ProgramRoleWidgetService); + private readonly applicationAction = inject(DetailProgramInfoService); + readonly applicationPending = this.applicationAction.applicationPending; + readonly state = this.service.state; + readonly data = computed(() => { + const state = this.state(); + return state.status === "success" ? state.data : null; + }); + readonly roleNames = { organizer: "организатор", expert: "эксперт", participant: "участник" }; + readonly routes = AppRoutes; + readonly steps = participantSteps; + readonly withoutProject = withoutProjectPresentation; + readonly now = signal(Date.now()); + readonly expertState = computed(() => { + const data = this.data(); + return data?.role === "expert" + ? expertWidgetPresentation(data.expert, data.isCompetitive, this.now()) + : null; + }); + readonly errorMessages = { + network: "Не удалось загрузить", + forbidden: "Нет доступа", + unauthorized: "Войдите в аккаунт", + not_found: "Программа недоступна", + integrity: "Данные проекта требуют проверки", + }; + constructor() { + // Только локальные часы: никаких повторных HTTP-запросов. Пересечение дедлайна ≤1 с. + const clock = setInterval(() => this.now.set(Date.now()), 1000); + inject(DestroyRef).onDestroy(() => clearInterval(clock)); + } + count(value: number | null): string { + return value === null + ? "—" + : new Intl.NumberFormat("ru-RU", { + notation: value >= 10000 ? "compact" : "standard", + maximumFractionDigits: 1, + }).format(value); + } + createApplication(): void { + const data = this.data(); + if ( + data?.role === "participant" && + !data.participant.participantProject && + data.participant.submissionOpen + ) + this.applicationAction.addNewProject(data.programId); + } +}