- Исправлен PollSerializer для создания опросов с опциями
- Добавлено поле read_only_fields для корректной валидации
- Реализована отправка WebSocket уведомлений при создании опроса
- Исправлен импорт serialize_message из communications.serialization
- Добавлен обработчик poll_update в UserConsumer для WebSocket событий
- Исправлен эндпоинт /results/ для возврата user_voted_option_ids
- Добавлено поле voters в PollOptionSerializer для списка проголосовавших
- Реализована инициализация poll виджетов после рендера сообщений
- Добавлено игнорирование poll_update в notification-manager
- Исправлены стили для request list badges (height, word-break, flex)
- Восстановлены стили team-wheel (.wheel-focus, .scroll-arc) из git истории
- Реализовано отображение forwarded message info в messageRendererV2
- Множественные улучшения UI и UX для опросов
Fixes: создание опросов, голосование, отображение результатов, список проголосовавших
Изменения:
- Новый endpoint /api/v1/communications/messages/upload-temp/ для загрузки файлов без создания сообщения
- Поле message в MessageAttachment теперь nullable для временных вложений
- Логика перемещения attachments между сообщениями при редактировании
- Frontend использует upload-temp вместо создания временных сообщений
- Celery задача cleanup_orphaned_attachments для очистки забытых файлов (каждый час)
- Исправлена проблема с WebSocket обновлениями при редактировании
- Удалены debug логи после успешного тестирования
Технические детали:
- communications/models.py: добавлено null=True, blank=True к MessageAttachment.message
- communications/migrations/0022: миграция для изменения поля
- api/v1/communications/viewsets.py: новый action upload_temp() + логика перемещения в update()
- static/js/components/chatComposer.js: использование upload-temp вместо upload
- communications/tasks.py: новая Celery задача для очистки старых orphaned attachments
- eusrr_backend/settings.py: добавлен CELERY_BEAT_SCHEDULE с задачей очистки
ГЛУБОКИЙ АУДИТ выявил корневые причины прыжков:
НАЙДЕННЫЕ ПРОБЛЕМЫ:
1. chatMarkRead делал свою прокрутку ПОСЛЕ handleInitialMessages
- mark.scrollIntoView() или autoscroll() в requestAnimationFrame
- Конфликтовал с уже установленной прокруткой
2. Дублирование обработчика кнопки 'вниз':
- chatMarkRead.js: btn.addEventListener
- chat-detail-enhanced.js: scrollBtn.addEventListener
- Два обработчика на одну кнопку!
3. Излишняя сложность в scrollToBottom():
- Вызывал markReadApi.autoscroll() вместо прямой установки
- Дополнительный уровень косвенности = источник багов
ИСПРАВЛЕНИЯ:
1. chatMarkRead НЕ скроллит при инициализации:
- Divider создается, но не скроллится к нему
- Прокрутка управляется ТОЛЬКО из handleInitialMessages
- Единая точка ответственности
2. Убрано дублирование кнопки:
- Удален обработчик из chat-detail-enhanced.js
- Остался только в chatMarkRead.js
3. Упрощен scrollToBottom():
- Прямая установка scrollTop вместо вызова markReadApi
- Поддержка instant режима (без анимации)
- Предсказуемое поведение
4. Добавлены комментарии и документация:
- Пояснено почему НЕ скроллим в chatMarkRead
- Описано назначение каждой функции прокрутки
- Создан полный аудит в docs/completed/SCROLL_CONFLICTS_AUDIT.md
АРХИТЕКТУРА ПРОКРУТКИ:
✅ При загрузке: ТОЛЬКО handleInitialMessages
✅ Кнопка вниз: chatMarkRead.autoscroll()
✅ Новые сообщения: ТОЛЬКО если свое ИЛИ уже внизу
✅ Ввод текста: autoscroll() если внизу
РЕЗУЛЬТАТ:
✅ Нет прыжков - единая точка управления прокруткой
✅ Нет конфликтов - каждая функция делает одно
✅ Нет дублирования - один обработчик на событие
✅ Предсказуемость - прямые вызовы вместо косвенных
Файлы:
- userWebSocket.js: упрощен scrollToBottom
- chatMarkRead.js: убрана автопрокрутка при инициализации
- chat-detail-enhanced.js: убран дублирующий обработчик
- docs/completed/SCROLL_CONFLICTS_AUDIT.md: полный аудит
- Заменен лишний div.container на стандартный container для единообразия
- Заменен класс .card на .ios-card в секции активности для устранения конфликтов стилей
- Добавлен card-list.css в base.html для корректного отображения карточек новостей
- Добавлены CSS правила для правильного поведения .row и колонок в grid-layout
- Исправлена проблема с выходом календаря за границы страницы
- Убраны видимые скроллбары у modal-body и modal-content для чистого UI
НОВОЕ:
- static/js/managers/dataManager.js - централизованное кеширование и дедупликация
- static/js/api/calendarApi.js - обертка над calendar API с кешем (TTL 30s)
- static/js/api/departmentsApi.js - обертка над departments API с кешем (TTL 60s)
ИЗМЕНЕНО:
- calendarWidget.js теперь использует getCalendarEvents() и getMyDepartments()
- Убрано 3x дублирование запроса /api/v1/departments/my-departments/
- Убрано 2-3x дублирование запросов календаря
РЕЗУЛЬТАТ:
- Вместо 10+ API запросов теперь будет 3-4 (с кешем)
- Автоматическая дедупликация одновременных запросов
- Логирование Cache HIT/MISS для отладки
- Добавлен CSRF токен в модальные окна (createDepartmentModal, createChatModal)
- Исправлена работа групповых чатов (group/channel/announcement):
* Добавлена проверка доступа через ChatMembership в views и consumers
* Групповые чаты теперь отображаются в списке
* WebSocket подключается корректно без бесконечных перезагрузок
- API create_chat теперь читает JSON вместо POST данных
- Изменена отправка сообщений: Enter вместо Ctrl+Enter, Shift+Enter для переноса строки
- Добавлен сертификат LDAP (corp-ca.pem)
- Отключен LDAP в локальном .env для разработки (USE_SQLITE=True, LDAP_ENABLED=False)