виджет на сайте
Консоль рисует один экран из семи стопкой сложенных панелей и 16 полей. На телефоне это ровно та «слишком длинная простыня», которую отвергло решение о разбиении: единый пункт «Ещё → Виджет на сайте» открывает хаб, а хаб — три коротких редактора-группы, каждый отвечает на один вопрос, который тенант держит в голове.
Не семь экранов (четыре консольные панели — это по одному переключателю; вкладка на чекбокс читается как поломка), не один экран (та самая простыня), не вкладки (бриф говорит «каждый экран, который сохраняет» — значит независимые сохранения). Три — это число по-настоящему разных вопросов: как выглядит, что делает, что можно и что обязательно.
Подписи строк — это сводка текущего конфига, чтобы тенант видел состояние группы, не заходя в неё. Заметка adr/0029 («следующая загрузка страницы») и загрузка/ошибка/повтор живут один раз здесь, на хабе, а не повторяются в каждом редакторе.
Вложенность хаб → редактор — собственная навигация фичи, а не второй уровень списка «Ещё» (у треда из «Диалогов» точно так же есть своя внутренняя навигация). Гейт — site:configure, одно и то же разрешение на строку, GET и PUT: rail-vs-server разрыва здесь нет.
Проверьте соединение и попробуйте ещё раз. Настройки доступны только с правом site:configure, поэтому «попробовать снова» здесь честно.
Единственное место для «не загрузилось / повторить» — хаб. Три редактора не дублируют это состояние: они получают уже загруженный committed-конфиг из общей ViewModel.
Принцип (teaching mode): разбиение консоли на 7 панелей — это information architecture для десктопа; разбиение приложения на 3 экрана — другая IA для другого вьюпорта, по правилу «один связный вопрос на экран», а не по порядку полей на бэкенде. Альтернатива — один экран с TabRow из трёх вкладок и одним «Сохранить» — отклонена: бриф говорит «каждый экран, который сохраняет, шлёт полный объект», а это про несколько независимо сохраняющих экранов, вкладки же схлопнули бы их обратно в единую форму.
Три экрана сохраняют независимо, и каждый PUT обязан нести все 16 полей, иначе сервер сбросит отсутствующие (requireContactConsent помечен [JsonRequired] именно поэтому; любой другой bool при отсутствии биндится в false). Наивное «каждый экран PUT-ит только свои поля» молча выключило бы согласие/приём файлов/привлечение внимания при сохранении любого другого экрана.
Защита структурная: одна общая WidgetConfigViewModel держит committed — полный конфиг (загружен один раз GET-ом, пересеивается из эха каждого PUT). Сохранение редактора строит committed.copy(<свой срез из черновика>) и PUT-ит целиком. Ни один булев никогда не отсутствует в PUT, и несохранённый черновик соседнего экрана не утекает в чужое сохранение.