Files

14 KiB
Raw Permalink Blame History

Карта: Уведомления (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, во всю ширину, иконка «×»). ⚠️ Пишущая: onDismissAllDELETE /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"). ⚠️ Пишущая: onDismissNotificationDELETE …/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 плоский; сверить на уведомлении с упоминанием пользователя/файла.