Files

137 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Карта: Уведомления (forbion, мобильная веб-версия)
Снято 2026-07-12. Метод по mail/078: структура берётся ИЗ КОДА
(апстрим `nextcloud/notifications`, компоненты `NotificationsApp.vue` / `NotificationItem.vue` /
`ActionButton.vue` / `IconNotification.vue`; на forbion версия 5.0.0-dev.0 — компоненты стабильны
между версиями), живой мобильный web forbion (вьюпорт 390px, аккаунт `cloude`, строго read-only
по mail/073) — для визуальной сверки размещения и порядка. Живой аккаунт `cloude` на момент съёмки
имел **пустую ленту** (empty-state), поэтому структура элемента уведомления и действий снята с кода,
а не с экрана. Пишущих кнопок («Скрыть», «Скрыть все», action-кнопки) НЕ нажимал — dismiss и
выполнение действий это записи (DELETE / произвольный HTTP-метод), а аккаунт реальный рабочий.
Уведомления — НЕ отдельное приложение (нет пункта в шторке приложений и своего URL-роута), а
глобальный **дропдаун-лента в шапке** (компонент `NotificationsApp`, монтируется в `#notifications`).
## Вход
В мобильной вёрстке forbion иконка-триггер (колокольчик) живёт в **шторке приложений**, а не на
плавающей нижней панели. Путь:
- Нижняя панель шелла → `≡` («три полоски», `#open-header-menu-mobile`) открывает шторку
`app-menu--mobile`.
- В шторке — слот `#mobile-header-notifications` (класс `f7-mobile-menu-control-slot`,
`mobile-bottom-slot--overlay`) с кнопкой-колокольчиком (`.notifications-button`,
`aria-label="Уведомления"`, `aria-expanded`).
- Нижняя плавающая панель (общая, зона лида, для ориентира): `<`/`>` (сайдбар-навигация,
`#mobile-header-left-sidebar-button`) · конверт → Почта (`/apps/mail/`) · «карточки» → Задачи
(`/apps/tasks/`) · камера → Конференции (`/apps/spreed/`) · `≡` → шторка приложений.
## Триггер (колокольчик) — `IconNotification`
**Вид:** иконка «колокол». Индикатор состояния (`showDot`):
- точка-бейдж показывается, когда `notifications.length !== 0` **или** когда браузерные разрешения
ещё не запрошены (`webNotificationsGranted === null`);
- значок-предупреждение (`showWarning`) — когда push-уведомления задросселированы политикой
честного использования (`hasThrottledPushNotifications`).
**Действие:** тап → раскрывает дропдаун-ленту (`aria-expanded` false→true), эмит `@opened → onOpen`
(подгрузка/пометка ленты активной). Повторный тап или клик вне (кроме `.popover`) — закрывает.
## Экран: Лента уведомлений (дропдаун `NcHeaderMenu`, класс `header-menu`)
Контейнер `.notification-container` внутри `.header-menu__content`. Тайтл шапки в мобильной
теме — «Уведомления» (`.tooltip-header--notifications`). Два взаимоисключающих состояния:
### Состояние A — есть уведомления (`notifications.length > 0`) — СВЕРЕНО ЖИВЬЁМ у `cloude`
**Тело:** список `<ul class="notification-wrapper">` из элементов `NotificationItem` (см. ниже),
сверху вниз, новые (`notificationId > lastOpenMaxId`) помечены классом `notification--new`.
Если push задросселирован — первым нештатным элементом идёт баннер «Push notifications might be
unreliable» (fairUsePolicy, `key=-2016`).
**Низ:** блок `.dismiss-all` — кнопка **«Скрыть все уведомления»** (tertiary, во всю ширину,
иконка «×»). ⚠️ Пишущая: `onDismissAll``DELETE /ocs/v2.php/apps/notifications/api/v2/notifications`.
**Живая сверка 2026-07-12 (лента `cloude` = 3 уведомления `firstrunwizard`, скриншот 390px):**
- `расхождение вер.:` кнопка **«Скрыть все уведомления»** на forbion (5.0.0-dev.0) показывается
ВСЕГДА, в т.ч. при пустой ленте — в master-коде она под `v-if="notifications.length > 0"`.
Нативный клиент должен ориентироваться на поведение forbion (кнопка всегда), не на master.
- `расхождение вер.:` время в элементе отображается **относительно** («45 минут назад»,
«49 минут назад»), а не в формате «время + длинная дата» из master `NcDateTime`.
- Порядок в строке подтверждён: верхняя строка = [относительное время] … [× «Скрыть»];
ниже слева иконка app, справа subject (жирнее) и, если есть, message (серым, второй строкой).
- Наблюдённые элементы (все `data-app=firstrunwizard`, `objectType` user/app): у всех есть
время + «Скрыть» + иконка + ссылка (`full-subject-link`, не внешняя), rich-subject НЕТ,
action-кнопок НЕТ; у двух из трёх есть `message`. Примеры (приветственные, не приватные):
«Добавьте данные в свой профиль…», «Рекомендованное приложение: Формы», «…: Распознавание».
- `notification--new` в этой выборке не встретился (уведомления не новее `lastOpenMaxId`) —
подсветку нового сверить, когда придёт свежее.
### Состояние B — пусто (empty-state `NcEmptyContent`) — тоже наблюдалось у `cloude` (до догрузки ленты)
Три варианта текста (computed `emptyContentMessage`):
- `webNotificationsGranted === null`**«Запрос разрешений для показа уведомлений в браузере»**
(именно это видел у `cloude` — иконка колокола `bell-outline-icon`);
- задросселированы push → заголовок = subject fairUsePolicy + описание + кнопка «Contact
Nextcloud GmbH ↗» (внешняя ссылка), иконка `icon-alert-outline`;
- иначе → **«Нет уведомлений»** (`No notifications`). При переходе списка из >0 в 0 на ~5 сек
показывается анимация inbox-zero (галочка + конфетти), затем обычный колокол.
## Элемент: `NotificationItem` (`<li class="notification">`, из кода)
data-атрибуты: `data-id`, `data-timestamp`, `data-object-type`, `data-app`.
**Шапка элемента (`.notification-heading`):**
- время (`NcDateTime`, формат «время + длинная дата», `.notification-time`) — если есть timestamp;
- кнопка **«Скрыть»** (`.notification-dismiss-button`, tertiary, иконка «×», `aria-label="Dismiss"`).
⚠️ Пишущая: `onDismissNotification``DELETE …/api/v2/notifications/{id}`, затем `@remove` (убрать из ленты).
**Субъект (заголовок), три варианта рендера:**
- если `externalLink``<a target=_blank>` класс `full-subject-link external`, текст «{subject} ↗»;
- иначе если есть `link` (useLink) → `<a>` на этот линк;
- иначе — просто блок `.notification-subject` без ссылки.
Внутри: опциональная иконка (`img.notification-icon`); если есть `subjectRich` — богатый рендер
`NcRichText` с параметрами (см. Parameters ниже), иначе простой `.subject` с текстом subject.
**Сообщение (`.notification-message`, если есть `message`):** богатый (`messageRich` + autolink)
или простой текст; длинное сворачивается (`.message-container.collapsed` + градиент
`.notification-overflow`), тап по сообщению — разворот (`onClickMessage`).
**Действия (`.notification-actions`):**
- если `notification.actions[]` непусто — ряд `ActionButton` по каждому action;
- иначе, если есть `externalLink` — одна primary-кнопка «Contact Nextcloud GmbH ↗».
## Элемент: `ActionButton` (кнопка действия уведомления)
Поля action (из API): `label`, `link`, `type`, `primary`.
- `type === 'WEB'` (isWebLink) или `primary` → кнопка **primary**; для WEB это прямой `href` (ссылка).
- прочие типы (GET/POST/DELETE/PUT) → кнопка **secondary**.
**Клик (`onClickAction`):** эмит `notifications:action:execute` (приложение может отменить,
`cancelAction`); для WEB — просто переход по ссылке; иначе ⚠️ пишущий вызов
`axios({ method: action.type, url: action.link })`, при успехе — `@remove` (уходит из ленты) +
эмит `notifications:action:executed`. Ошибка → тост «Failed to perform action».
Пример типового уведомления с действиями — приглашение в Talk-беседу: subject + действия
«Присоединиться»/«Отклонить» и т.п. (состав задаёт серверное приложение-источник).
## Параметры rich-subject/message (`Components/Parameters/`)
`NcRichText` подставляет типизированные плейсхолдеры:
- `UserParameter` — пользователь (аватар + имя, кликабельно);
- `FileParameter` — файл (иконка + имя, ссылка на файл);
- `DefaultParameter` — прочие (просто текст).
`расхождение:` в нативном клиенте (`NotificationsRepository`/`NotificationsSheet`) сейчас берётся
только плоский `subject`/`message` (API v2), rich-параметры и иконка app не разворачиваются —
это мой бэклог (см. представление mail/070).
## API (из кода, все через OCS `apps/notifications/api/v2/notifications`)
- `GET …/notifications` — лента (в нативе уже есть, `NotificationsRepository.load`, limit=50);
- `DELETE …/notifications/{id}` — скрыть одно (в нативе есть `dismiss`);
- `DELETE …/notifications` — скрыть все (в нативе НЕТ — бэклог «отметить/скрыть все»);
- `{action.type} {action.link}` — выполнить действие уведомления (в нативе действий НЕТ — бэклог).
Обновление ленты — по ETag (`lastETag`) и, если доступен, через notify_push (`@nextcloud/notify_push`).
## Стили (тема forbion)
Отдельного `_mobile-notifications.css` в теме нет: на вебе лента — дроп в шапке
(`css/components/_header.css`), мобильное размещение колокольчика — слот
`#mobile-header-notifications` в `header__mobile-bottom`/шторке (тема
`css/pages/pages-mobile/_mobile-common.css`). Для нативной ленты держим общий карточный стиль
модулей (`_mobile-common.css` + токены designsystem) — согласовано с лидом (mail/070).
## Открытые вопросы (остаток после живой сверки 2026-07-12)
Закрыто живьём: размещение строки, относительное время, «Скрыть все» всегда видна, состав
простого уведомления (firstrunwizard) — см. «Состояние A». Осталось (нужны уведомления
конкретных типов, которых у `cloude` сейчас нет):
- (?) `notification--new`: подсветка/полоса для СВЕЖЕГО уведомления (в выборке все были старее
`lastOpenMaxId`) — сверить, когда придёт новое.
- (?) Точный порядок и подписи **action-кнопок** для источников с действиями (Talk-приглашение
«Присоединиться/Отклонить», дедлайны Deck/Календаря) — у firstrunwizard действий нет.
- (?) Сворачивание длинного `message` на ширине 390px (высота `.message-container.collapsed`,
градиент `.notification-overflow`, разворот по тапу) — у наблюдённых message короткие.
- (?) Богатый `subjectRich` (`NcRichText` с User/File-параметрами) — у firstrunwizard subject
плоский; сверить на уведомлении с упоминанием пользователя/файла.