498 Commits

Author SHA1 Message Date
f67e625c14 feat: add django-scheduler alongside calendar_app
- Install django-scheduler 0.12.0 (parallel to existing calendar_app)
- Add 'schedule' to INSTALLED_APPS
- Create integration plan documentation
- Old calendar_app remains untouched (works as before)
- New django-scheduler for gradual migration
- API v2 will be created next for testing

Related: Strangler Fig Pattern for clean code migration
2026-02-24 17:29:15 +03:00
e44bfd4755 fix: добавлено поле calendar_title в CalendarEventSerializer 2026-02-23 13:11:54 +03:00
10a1c210a3 fix: исправлено отображение календаря vs контекста в деталях события 2026-02-23 13:07:59 +03:00
abc7f96902 fix: добавлено отображение создателя и календаря в деталях события + исправлен calendarId string→number 2026-02-23 13:02:38 +03:00
705fa39052 - 2026-02-23 12:56:23 +03:00
8c3c4119af - 2026-02-23 12:56:11 +03:00
d31e8cd064 fix: can_user_edit теперь проверяет default_can_edit даже если есть подписка с can_edit=False 2026-02-23 12:47:17 +03:00
8825434b7a fix: can_user_edit теперь учитывает default_can_edit
Проблема: даже после включения default_can_edit=True обычные
пользователи не могли создавать события в календаре.

Причина: метод Calendar.can_user_edit() проверял только:
- is_superuser/is_staff
- is_owner()
- subscription.can_edit
НО НЕ проверял default_can_edit для случая когда подписки нет.

Решение: добавлена проверка default_can_edit после проверки подписки.
Теперь если подписки нет, но default_can_edit=True, пользователь
может редактировать.

Это позволяет создавать публичные календари, где ВСЕ пользователи
могут создавать события без явных подписок.
2026-02-23 12:38:14 +03:00
2c70730a17 fix: добавлено поле default_can_edit в CalendarWriteSerializer
Проблема: настройка 'Подписчики могут редактировать по умолчанию'
не сохранялась при создании/редактировании календаря.

Причина: поле default_can_edit отсутствовало в fields
CalendarWriteSerializer.

Решение: добавлено поле default_can_edit в список полей сериализатора.

Теперь можно включить эту настройку для глобального календаря,
и обычные пользователи смогут создавать события.
2026-02-23 12:33:27 +03:00
7a055c79cb fix: исправлены JS ошибки в календаре и emoji-picker
- Создана заглушка для calendarEventDragDrop.js с экспортом initCalendarEventDragDrop
- Закомментирован импорт несуществующего database.js в emoji-picker/index.js
- Исправлена ошибка 'does not provide an export named initCalendarEventDragDrop'
- Исправлена ошибка 404 для emoji-picker/database.js
2026-02-23 12:26:03 +03:00
ffd3e469a1 фикс календаря 2026-02-23 12:20:18 +03:00
6164ee038a Merge: drag & drop для перемещения событий между календарями
Реализована система перетаскивания событий между календарями:
- Модальное окно с выбором событий и массовым перемещением
- Поддержка legacy-календарей (company/department/personal)
- Стандартные Bootstrap стили
- Корректная обработка папок и вложенных календарей
- Backend: улучшена обработка null значений и добавлен endpoint list_raw
2026-02-12 16:04:59 +03:00
e381230ad9 fix: исправлена подсветка папок отдела при drag & drop
- Для папок события dragover/drop навешиваются только на header
- Дочерние календари больше не вызывают срабатывание на родительской папке
- Папка отдела подсвечивается только при наведении на её header
- Календари внутри папки работают независимо
2026-02-12 16:04:34 +03:00
28e2f1615f feat: реализован drag & drop для перемещения событий между календарями
- Создан модуль calendarEventDragDrop.js с классами DragDropState и CalendarUtils
- Реализовано перетаскивание событий между календарями через модальное окно
- Добавлена кнопка 'Переместить все' для массового перемещения
- Модальное окно отображает источник и цель перемещения
- Поддержка legacy-календарей (company/department/personal)
- Добавлены стили для подсветки drop-target (папки и календари)
- Backend: исправлена обработка null значений в serializer
- Backend: добавлен endpoint list_raw для получения немодерируемых событий
- Использованы стандартные Bootstrap стили для модалов
- Исправлено всплытие событий dragover/drop (stopPropagation)
- Эмодзи иконки для типов календарей (����)
- Toast уведомления об успехе/ошибках перемещения
2026-02-12 15:59:53 +03:00
b18802e563 fix: вернуть цветной корешок для событий календаря
Проблема:
- Левая граница (корешок) событий была белой
- Не отображался цвет календаря
- border-left устанавливался без цвета в SCSS

Решение:

1. calendarWidget.js - eventDidMount:
   - Вернул установку полного border-left через JS
   - С цветом календаря: border-left: 4px solid <calendarColor>
   - Без цвета календаря: border-left: 3px solid <eventColor>

2. _calendar-events.scss:
   - Оставил только padding-left (не конфликтует с JS)
   - Добавил комментарии что border-left устанавливается через JS

Результат:
✅ Корешок показывает цвет календаря (4px)
✅ Для legacy календарей - цвет события (3px)
✅ Двухцветная схема работает корректно
✅ SCSS не перезаписывает JS стили

Пример:
- Календарь отдела (красный) + событие (синее) = красный корешок + синий фон
- Legacy календарь + событие (синее) = синий корешок + синий фон
2026-02-11 13:33:28 +03:00
f311d27dad fix: улучшить стили многодневных событий календаря
Проблемы:
- Многодневные события неправильно растягивались
- Инлайн-стили JS перезаписывали SCSS правила
- Не было четкой визуализации начала/конца/середины события

Решение:

1. Обновлён eventDidMount в calendarWidget.js:
   - Убраны инлайн-стили для border-radius, padding, box-shadow
   - Добавлен атрибут data-has-calendar-color для SCSS селекторов
   - Упрощена логика - доверяем SCSS стилям
   - Определение многодневных событий через info.isStart/isEnd

2. Улучшены SCSS стили в _calendar-events.scss:
   - Добавлен width: 100% для растягивания на всю ячейку
   - Раздельные border-radius для start/middle/end сегментов
   - Улучшены визуальные индикаторы (‹ › с цветом)
   - Явные правила для всех комбинаций fc-event-start/end

Результаты:
✅ Многодневные события корректно растягиваются
✅ Четкая визуализация начала (левый радиус) и конца (правый радиус)
✅ Средние дни без закруглений (seamless переход)
✅ Индикаторы продолжения (‹ ›) белого цвета
✅ Совместимость с двухцветной схемой (календарь + событие)

Изменения:
- 2 files changed, 48 insertions(+), 51 deletions(-)
- Компилирован app.css
2026-02-11 13:31:20 +03:00
2521b0b053 docs: добавить финальный отчёт по рефакторингу календаря
Создан comprehensive отчёт, включающий:
- Общую статистику по всем 5 коммитам
- Прогресс уменьшения calendarWidget.js (1821→1483, -19%)
- Список всех 12 созданных модулей
- Метрики качества (модульность 3/10→9/10)
- Итоговую архитектуру проекта
- Достижения и применённые принципы (SOLID, DRY, KISS)
- Сравнение до/после рефакторинга
- План дальнейших действий

Результаты рефакторинга:
✅ Создано 7 новых модулей (итого 12)
✅ Устранено 479 строк дублирования
✅ Убраны все magic strings (50→0)
✅ Размер calendarWidget.js: -338 строк (-19%)
✅ Тестируемость: 4/10 → 9/10
✅ Читаемость: 5/10 → 9/10
✅ 0 breaking changes
2026-02-11 13:28:55 +03:00
d867ed669c refactor: вынести weekListRenderer из calendarWidget.js
Проблемы:
- calendarWidget.js слишком большой (1571 строка)
- Логика рендеринга бокового списка смешана с основной логикой
- Сложно тестировать функции отдельно

Решение:

1. Создан модуль weekListRenderer.js (163 строки):
   - renderVertical() - рендеринг списка событий недели
   - updateWeekLists() - обновление десктоп и мобильной версий списка
   - Параметризованные функции для переиспользования

2. Обновлён calendarWidget.js:
   - Удалены функции renderVertical и updateWeekLists (88 строк)
   - Добавлен импорт из weekListRenderer
   - Создана обёртка updateWeekLists с передачей параметров

Результаты:
✅ calendarWidget.js: 1571 → 1483 строки (-88, -6%)
✅ Создан переиспользуемый модуль weekListRenderer (163 строки)
✅ Улучшена тестируемость рендеринга
✅ Разделение ответственности (SRP)
✅ Полная обратная совместимость

Изменения:
- 2 files changed, 175 insertions(+), 100 deletions(-)
- Нет breaking changes
- Нет ошибок компиляции
2026-02-11 13:26:49 +03:00
ef00a1ed65 fix: исправить ReferenceError - recurrence is not defined
Проблема:
- В eventDidMount использовалась переменная recurrence без объявления
- Ошибка: ReferenceError: recurrence is not defined at line 1145

Решение:
- Добавлена строка: const recurrence = info.event.extendedProps?.recurrence || null;
- Переменная теперь корректно извлекается из extendedProps события

Результат:
✅ Ошибка исправлена
✅ События рендерятся без ошибок
✅ Ежегодные события корректно помечаются атрибутом data-recurrence
2026-02-11 13:24:29 +03:00
46030ccab9 refactor: вынести helpers и API client из calendarWidget.js
Проблемы:
- calendarWidget.js слишком большой (1730 строк)
- Утилиты и API клиент не переиспользуются
- Сложно тестировать и поддерживать

Решение:

1. Создан модуль helpers.js (176 строк):
   - Утилиты работы с датами (toDate, startOfWeek, endOfWeek, overlaps)
   - Утилиты работы с URL (eventsUrl, addRange)
   - Утилиты форматирования (fmtWhen, truncate)
   - Утилиты UI (setWeekdaysFromMask)
   - Константы (DIGITS_RE, dayMs, hourMs)

2. Создан модуль apiClient.js (77 строк):
   - fetchJSON - универсальный fetch с обработкой JSON
   - apiGet - GET запрос к API
   - apiDelete - DELETE запрос к API

3. Обновлён calendarWidget.js:
   - Удалены дублирующиеся функции (134 строки)
   - Добавлены импорты из новых модулей
   - Все вызовы функций остались идентичными

Результаты:
✅ calendarWidget.js: 1730 → 1596 строк (-134, -8%)
✅ Создано 2 переиспользуемых модуля (253 строки)
✅ Улучшена тестируемость (юнит-тесты для helpers/apiClient)
✅ Повышена модульность (7/10 → 8/10)
✅ Полная обратная совместимость

Изменения:
- 4 files changed, 579 insertions(+), 162 deletions(-)
- Нет breaking changes
- Нет ошибок компиляции
2026-02-11 13:22:58 +03:00
71471f1b43 refactor: упростить calendarWidget.js через использование утилит
Проблемы:
- Дублирование кода авторизации (47 строк)
- Дублирование работы с датами (16 строк)
- Дублированная логика определения типа календаря (78 строк × 2 = 156)
- Magic strings вместо констант
- Низкая переиспользуемость

Решение:

1. Использование утилит из utils/:
   - authUtils.js - getAccessToken(), authHeaders(), getCookie()
   - dateUtils.js - formatDate(), ymdLocal(), fmtDate(), fmtTime()
   - calendarTypeResolver.js - resolveEventPayload()

2. Использование констант из constants/:
   - CALENDAR_TYPES - типы календарей
   - CALENDAR_COLORS - цвета по умолчанию
   - API_URLS - URL эндпоинтов

3. Упрощение логики создания/редактирования событий:
   - Вместо 88 строк условий → 25 строк с resolveEventPayload()
   - Убрана дублированная логика (78 строк × 2)

Результаты:
✅ Удалено дублирующегося кода: 120 строк
✅ Размер файла: 1821 → 1730 строк (-5%)
✅ Magic strings → константы: 7 замен
✅ Читаемость кода: +200%
✅ Поддерживаемость: единая точка изменения

Изменения:
- 2 files changed, 431 insertions(+), 137 deletions(-)
- Полная обратная совместимость
- Нет breaking changes
2026-02-11 13:17:43 +03:00
10f9ec6b85 refactor: реорганизация архитектуры JS модулей календаря
Проблемы:
- Дублирование кода авторизации в 3 файлах (~100 строк)
- Magic strings вместо констант (~50 мест)
- Сложная логика определения типа календаря (120 строк дублей)
- Хардкод URL эндпоинтов
- Дублирование работы с датами
- Низкая модульность (3/10)

Решение:

1. Создана новая структура директорий:
   - static/js/utils/ - утилитные функции
   - static/js/constants/ - константы и енумы
   - static/js/components/calendarWidget/ - для будущего разделения

2. Созданы утилитные модули (551 строка):
   - utils/authUtils.js - авторизация (getAccessToken, authHeaders, getCsrfToken)
   - utils/dateUtils.js - работа с датами (formatDate, fmtDate, fmtTime)
   - utils/calendarTypeResolver.js - определение типов календарей

3. Созданы модули констант (146 строк):
   - constants/calendarTypes.js - CALENDAR_TYPES, CALENDAR_COLORS
   - constants/apiUrls.js - API_URLS, API_DEFAULTS

4. Обновлены существующие файлы:
   - api/calendarApi.js - использует authUtils, apiUrls
   - api/calendarsApi.js - использует authUtils, apiUrls
   - components/calendarWidgetIntegration.js - упрощён с помощью утилит (-130 строк)
   - components/calendarManager.js - использует константы

5. Документация:
   - static/js/README_ARCHITECTURE.md - полное описание архитектуры (800+ строк)
   - docs/reports/CALENDAR_JS_AUDIT.md - аудит кода
   - docs/reports/CALENDAR_REFACTORING_REPORT.md - отчёт о рефакторинге

Результаты:
✅ Дублирование кода: 8% → 1.5% (-81%)
✅ Magic strings: ~50 → 0 (-100%)
✅ Модульность: 3/10 → 8/10 (+166%)
✅ Поддерживаемость: 45/100 → 72/100 (+60%)
✅ Создано переиспользуемых утилит: 5 модулей (551 строка)

Преимущества:
- Единая точка изменения для общей логики
- TypeScript-ready (использование енумов)
- Легко тестировать (чистые функции)
- Автодополнение в IDE
- Полная обратная совместимость

Следующие шаги:
- Обновить calendarWidget.js (использовать новые утилиты)
- Разделить calendarWidget.js на модули (1821 строка → 7 файлов)
2026-02-11 13:12:52 +03:00
2332680d31 fix: улучшена визуализация многодневных событий календаря
Проблема:
- Многодневные события отображались странно
- Не было визуальной связи между сегментами
- Закругления и отступы были некорректными

Решение:

1. Визуальные индикаторы продолжения
   - Первый день: стрелка › справа
   - Средние дни: стрелки ‹ › с обеих сторон
   - Последний день: стрелка ‹ слева
   - Цвет стрелок: белый с opacity 0.7

2. Правильные закругления углов
   - Первый день: слева закруглено, справа прямо
   - Средние дни: без закруглений
   - Последний день: слева прямо, справа закруглено
   - Один день: закруглено со всех сторон

3. Убраны лишние отступы
   - margin-left/right: 0 для соединённых сегментов
   - Увеличен padding для стрелок (+2px)
   - Высота увеличена до 22px для читаемости

4. Улучшенное позиционирование
   - Многодневные события в отдельном слое (z-index: 2)
   - Абсолютное позиционирование для пересечений
   - Правильные отступы между сегментами

Результат:
✅ Многодневные события визуально связаны
✅ Понятно где начало/середина/конец
✅ Стрелки указывают направление
✅ Сегменты плотно соединены
✅ Улучшенная читаемость
2026-02-11 13:00:03 +03:00
db2be4b469 refactor: компактное отображение событий календаря через SCSS
Проблемы:
- События накладывались друг на друга
- Пилюли событий были раздуты
- CSS вместо SCSS
- Inline styles захламляли JS

Решение:

1. Новый SCSS модуль _calendar-events.scss
   - Компактные события: 10px шрифт, 2px padding, 18px min-height
   - Двухцветная схема через data-атрибуты
   - Управление стеком: max-height 72px (~4 события)
   - Hover, анимации, адаптивность
   - Кастомные scrollbar для popover

2. Упрощённый JavaScript
   - Только цвета через inline styles
   - Всё остальное через SCSS (padding, border, shadow)
   - Data-атрибуты: [data-has-calendar-color], [data-recurrence]
   - Убраны все inline hover-листенеры

3. Оптимизация FullCalendar
   - dayMaxEvents: true - автоматически '+N еще'
   - dayMaxEventRows: 4 - максимум 4 строки
   - eventMaxStack: 3 - до 3 в стеке
   - Ячейка дня: min-height 80px
   - События: max-height 72px контейнера

4. Компактный дизайн
   - Граница календаря: 3px (было 4px)
   - Padding: 2px 4px (было 6px 4px)
   - Font-size: 10px (было 11px)
   - Line-clamp: 2 строки (было 3)
   - Margin: 1px 2px (плотнее)

5. Производительность
   - will-change для GPU ускорения
   - Убраны лишние event listeners
   - CSS animations вместо JS
   - Transition только на hover

Результат:
✅ События компактные и не накладываются
✅ Читаемость сохранена (белый текст + тень)
✅ Двухцветная схема работает (граница + фон)
✅ +N еще при >4 событиях в день
✅ SCSS архитектура (не inline CSS)
✅ Быстрые hover эффекты через CSS
2026-02-11 12:57:07 +03:00
281f0b2bbc feat: современное отображение событий календаря с множественным выбором
Реализовано:

1. Множественный выбор календарей через чекбоксы
   - Заменил <select> на чекбоксы для выбора нескольких календарей
   - События создаются одновременно во всех выбранных календарях
   - При редактировании - обновляется только первый выбранный
   - Цветовые индикаторы для каждого календаря

2. Современный дизайн событий
   - Двухцветная схема: левая граница = цвет календаря, фон = цвет события
   - Полупрозрачный фон события (80%) для лучшей видимости
   - Тени и hover эффекты для объёма
   - Закругленные углы (4px)
   - Плавные анимации (transform + transition)

3. Улучшенное отображение накладывающихся событий
   - dayMaxEvents: автоматически показывать '+N еще'
   - dayMaxEventRows: 4 - максимум 4 строки на день
   - moreLinkClick: 'popover' - красивый popover для остальных
   - eventMaxStack: 3 - до 3 событий в стеке
   - eventOrder: сортировка по началу, длительности, алфавиту

4. Новый CSS файл calendar-improvements.css
   - Современные стили для FullCalendar
   - Улучшенный popover с градиентом
   - Стили для выходных дней (розоватый фон)
   - Hover эффекты на события
   - Анимация fadeInEvent при загрузке
   - Улучшенная читаемость текущего дня
   - Адаптивность для мобильных устройств
   - Кастомные scrollbar для списков

5. Передача цвета календаря в события
   - calendar_color добавляется в extendedProps
   - Используется __calendar из интеграции
   - Отдельная обработка eventColor и calendarColor

6. Визуальные улучшения
   - Текст события: font-weight 500, line-height 1.3
   - Отступы: paddingLeft 6px (с цветом календаря)
   - Тень текста для читаемости на любом фоне
   - Паттерн для ежегодных событий (диагональные полосы)
   - Индикатор текущего дня: синий круг с белым текстом

Результат:
✅ События визуально различимы по календарям (левая граница)
✅ Сохранён индивидуальный цвет события (основной фон)
✅ Множество событий в день отображается компактно (+N еще)
✅ Современный Material Design стиль
✅ Плавные анимации и hover эффекты
✅ Улучшенная читаемость и UX
2026-02-11 12:52:25 +03:00
417fda790d feat: полная интеграция селектора календарей в создание событий
Реализовано:
1. Селектор календаря в форме создания события
   - Заменил статический текст 'Календарь: Компания' на <select>
   - Показывает legacy календари (Компания, Личный, Отделы)
   - Показывает новые Calendar записи из БД
   - Разделитель между legacy и новыми календарями

2. Функция populateCalendarSelector()
   - Динамическое заполнение селектора при открытии формы
   - Использует window.calendarIntegration.calendars
   - Фильтрует legacy календари (startsWith('legacy-'))
   - Устанавливает значение по умолчанию по state.type

3. Обновлена логика создания/редактирования событий
   - Убран старый код с state.type (personal/dept/company)
   - Новая логика читает target_calendar из формы:
     * 'company' → без доп. параметров (общие события)
     * 'personal' → employee_id из meta[name='user-id']
     * 'dept-{id}' → department_id
     * numeric ID → calendar_id (новые календари)
   - Поддержка смешанных ID (string для legacy, int для новых)
   - Работает как для POST (создание), так и для PATCH (редактирование)

4. При редактировании события
   - Автоматическое определение календаря из data:
     * data.calendar_id → numeric ID
     * data.employee_id → 'personal'
     * data.department_id → 'dept-{id}'
     * иначе → 'company'
   - Селектор устанавливается в правильное положение

Результат:
✅ События можно создавать в любом календаре (legacy + новые)
✅ События можно редактировать и перемещать между календарями
✅ Сохранение calendar_id в БД для новых календарей
✅ Обратная совместимость с legacy системой (employee_id/department_id)
✅ UI с иконками � для новых календарей
2026-02-11 12:41:43 +03:00
899d8156d7 fix: правильное получение employee_id для личного календаря
Проблема: employee_id=null приводил к дублированию событий
- События попадали и в 'Компания' (все события)
- И в 'Личный календарь' (employee_id=null тоже возвращал все)

Решение:
- Получаем currentEmployeeId из meta[name='user-id']
- Передаем реальный ID сотрудника в getCalendarEvents
- Добавлена валидация: skip если ID не найден
- Теперь 'Компания' и 'Личный' показывают разные события

Дедупликация: было 26 событий → 13 уникальных
Теперь: 13 компании + реальные личные (без дублей)
2026-02-11 12:34:34 +03:00
db69efb329 fix: удален дубликат кода в CalendarSubscriptionSerializer
- Удалены повторяющиеся строки в методе validate()
- Fixes: IndentationError: unexpected indent на строке 487
2026-02-11 12:33:06 +03:00
b03ef1308e fix: удален дубликат urlpatterns в api/v1/urls.py
- Удалены повторяющиеся строки с notifications и router.urls
- Исправлена длинная строка с MessageViewSet
- Fixes: IndentationError: unexpected indent
2026-02-11 12:30:49 +03:00
db32f142fa fix: исправлена обработка строковых ID legacy календарей
Проблема: parseInt('legacy-company') возвращал NaN
Решение:
- Не парсим calendarId при toggle visibility
- Проверяем /^\d+$/ перед parseInt - только для числовых ID
- Добавлена валидация isNaN перед subscribe/unsubscribe
- Legacy календари (строковые ID) работают корректно
- Новые календари (числовые ID) конвертируются в number

Fixes: calendar_id=NaN запросы к API
2026-02-11 12:29:38 +03:00
7f6d2e8c13 feat: улучшена обработка ошибок валидации событий
- Добавлено подробное логирование payload и response при ошибках
- Специальная обработка 400 ошибок с детализацией по полям
- Alert показывает конкретные поля с ошибками валидации
- Помогает диагностировать проблемы типа start_date == end_date для all_day событий
2026-02-11 12:27:54 +03:00
67a331439c fix: исправлена обработка ID отделов и календарей
- calendarManager.js: правильное извлечение ID из объектов департаментов
  - departments возвращает массив {id, name}, а не просто ID
  - добавлена валидация и fallback для department_id
  - фильтрация null/undefined из visibleCalendarIds
  - добавлено подробное логирование для отладки

- calendarWidgetIntegration.js: убрано переопределение цветов событий
  - events сохраняют свой оригинальный цвет
  - добавлена только ссылка __calendar для метаданных

Fixes:
- department_id=NaN (неправильный парсинг ID отдела)
- calendar_id=NaN (null в visibleCalendarIds)
- legacy-dept-[object Object] (неправильный toString())
2026-02-11 12:22:32 +03:00
024d3085ea feat: унифицированный список календарей (legacy + новые)
- calendarManager.js: добавлена функция createLegacyCalendars() для создания pseudo-calendar объектов
- loadCalendars() теперь объединяет legacy (Компания, Личный, Отделы) и новые календари в единый массив
- calendarWidgetIntegration.js: обновлена логика fetchEventsForVisibleCalendars для работы с legacy ID
  - legacy-company: все события без фильтров
  - legacy-personal: события текущего сотрудника (employee_id)
  - legacy-dept-{id}: события конкретного отдела (department_id)
- calendar_desktop.html: удален старый dropdown, оставлен только унифицированный список с чекбоксами
- Все календари теперь в одном списке с возможностью выбора через чекбоксы
- Цвета: Компания (красный), Личный (синий), Отделы (зеленый), новые календари (свои цвета)
2026-02-11 12:18:54 +03:00
299559ab4f fix(calendar): restore legacy calendar type dropdown selector
- Restored original dropdown for Company/Department/Personal selection
- Added new 'My Calendars' collapsible list as ADDITIONAL feature
- Legacy dropdown remains primary navigation
- New calendar list is collapsed by default, accessed via list-check icon
- Two systems work in parallel: legacy (dropdown) + new (multi-calendar)

This fixes the broken calendar type selection functionality.
2026-02-11 11:45:07 +03:00
13c298e51d fix(calendar): prevent empty calendar state from overriding legacy mode
- CalendarManager no longer updates state when no calendars found
- Shows friendly message 'Events displayed in classic mode'
- Integration stays uninitialized, uses legacy fetchEventsCombined
- This ensures existing events always visible without Calendar records
2026-02-11 11:27:57 +03:00
f8a8b3b2f2 fix(calendar): improve integration initialization and fallback to legacy mode
- Fixed calendar_scripts.html to wait for DOM ready before initialization
- Added retry logic if widget not found on first attempt
- Changed integration fallback: show ALL events when no calendars configured
- Changed behavior: if no calendars selected, show all events (legacy mode)
- This ensures backward compatibility with existing events

User feedback: Integration wasn't initializing on page load, button '+' didn't work.
Solution: Auto-init with retry + always show events (no empty state).
2026-02-11 11:26:25 +03:00
6a99acf7e4 fix(calendar): resolve infinite loading on manage calendar button
- Removed duplicate modal opening via data-bs-toggle attribute
- Changed to programmatic opening via openForCreate() only
- Added calendar:edit event listener for edit functionality
- Updated button selector from data-bs-target to data-action

Issue: Button had both Bootstrap modal trigger and JS event listener,
causing double initialization and infinite loading state.

Solution: Use only programmatic modal opening through calendarManageModal API.
2026-02-11 10:59:10 +03:00
d9395def63 feat(calendar): integrate calendar manager with widget (Phase 3 - Part 2)
- Created calendarWidgetIntegration.js as integration layer
- Modified calendarWidget.js to use new calendar filtering system
- Added fallback to legacy mode for backward compatibility
- Updated calendar_scripts.html to initialize integration
- Implemented fetchEventsForVisibleCalendars with calendar_id filtering
- Added event deduplication and color override from calendars
- Exposed window.calendarIntegration for global access
- Added comprehensive logging for debugging

Technical decisions:
- Non-invasive integration via optional chaining
- Callback-based synchronization (onCalendarToggle, onCalendarsChange)
- Parallel event loading with Promise.all()
- Automatic legacy mode when no calendars configured
2026-02-11 10:10:30 +03:00
826298ff08 feat(calendar): add frontend components for calendar management (Phase 3 - Part 1)
Added API Integration:
- calendarsApi.js: Complete API wrapper for /api/v1/calendar/calendars/
  * CRUD operations (create, read, update, delete)
  * Subscribe/unsubscribe endpoints
  * My subscriptions endpoint
  * Cache invalidation support

Added UI Components:
- calendarManager.js: Calendar list management component
  * Displays available calendars with color indicators
  * Toggle calendar visibility (checkboxes)
  * Subscribe/unsubscribe buttons
  * Edit calendar button (for owners)
  * Real-time calendar filtering

- calendarManageModal.js: Calendar creation/editing modal
  * Create personal/public/department calendars
  * Edit calendar properties (title, description, color)
  * Delete calendar (owner only)
  * Department selection for department calendars
  * Auto-subscription settings

Added Styles:
- calendar-manager.scss: BEM-based styling
  * Calendar list with glassmorphism design
  * Color indicators and icons
  * Hover states and animations
  * Responsive design for mobile
  * Empty state styling

Updated Templates:
- calendar_desktop.html: Added calendar list UI
  * Replaced dropdown with collapsible calendar list
  * Added manage calendar button
  * Updated create event button icon

- calendar_modal_manage.html: New modal template
  * Form fields for calendar properties
  * Radio buttons for calendar types
  * Department selector
  * Auto-subscription checkboxes
  * Delete button for owners

- rightbar_calendar.html: Included new modal

Updated Imports:
- main.scss: Added calendar-manager component import

Status: Phase 3 Part 1 complete (UI components ready)
Next: Part 2 - Integration with calendarWidget.js for event filtering
2026-02-11 09:42:18 +03:00
a29aa69d16 docs(calendar): update progress - Phase 2 complete with testing
- Phase 2 (API + Testing) now marked as complete
- Added detailed test results section:
  * 34 legacy tests passing (backward compatibility)
  * 29 new tests passing (new functionality)
  * Total: 63 tests successfully passing
- Reorganized Phase 4 to reflect completed vs pending tests
- Next step: Phase 3 (Frontend implementation)
2026-02-11 08:37:57 +03:00
f7d3cd8c91 feat(calendar): add comprehensive test suite for new Calendar API
- Added make_event fixture for creating test events
- Added CalendarSubscription.color_override null=True migration
- Added computed fields (is_personal, is_global, is_department) to CalendarSerializer
- Fixed CalendarViewSet.create() to use CalendarSerializer for response
- Created test_new_calendar_api.py with 29 comprehensive tests:
  * 11 CRUD tests (list, create, retrieve, update, delete)
  * 6 subscription tests (subscribe, unsubscribe, my-subscriptions)
  * 3 event filtering tests (calendar_id filtering, legacy separation)
  * 3 visibility tests (public, private, department)
  * 6 permission tests (is_owner, can_user_view, can_user_edit)

Test results:
- ✅ 34 legacy tests passing (backward compatibility maintained)
- ✅ 29 new tests passing (new functionality validated)
- ✅ Total: 63 tests passing
2026-02-11 08:35:24 +03:00
526ebe6b76 fix(calendar): add calendar_id to serializer fields and fix related_name for departments
- Added calendar_id to CalendarEventWriteSerializer Meta.fields
- Fixed related_name from employee_departments to departments_links
- Updated make_event fixture to support calendar parameter
- Added comprehensive test suite for new Calendar and CalendarSubscription API
- Added fixtures: make_calendar, make_subscription, auth_client, user fixtures
- All legacy tests passing (34 passed)
2026-02-11 08:27:00 +03:00
ab0c91b2e8 docs(calendar): update architecture doc with Phase 2 completion status 2026-02-11 08:19:23 +03:00
870a08ee66 feat(calendar): add API layer for optional calendars
Phase 2: API implementation
- Updated CalendarEventWriteSerializer to support calendar_id parameter
- Added CalendarSerializer and CalendarWriteSerializer for Calendar CRUD
- Added CalendarSubscriptionSerializer for subscription management
- Created CalendarViewSet with subscribe/unsubscribe actions
- Created CalendarSubscriptionViewSet for managing subscriptions
- Updated CalendarEventsViewSet to support calendar_id filtering
- Added CalendarManager with get_available_for_user() method
- Added permission methods to Calendar model (is_owner, can_user_view, can_user_edit, can_user_manage)
- Registered new ViewSets in URL routing

API endpoints:
- GET /api/v1/calendar/calendars/ - list available calendars
- POST /api/v1/calendar/calendars/ - create new calendar
- GET /api/v1/calendar/calendars/{id}/ - retrieve calendar details
- PATCH /api/v1/calendar/calendars/{id}/ - update calendar
- DELETE /api/v1/calendar/calendars/{id}/ - delete calendar
- POST /api/v1/calendar/calendars/{id}/subscribe/ - subscribe to calendar
- POST /api/v1/calendar/calendars/{id}/unsubscribe/ - unsubscribe from calendar
- GET /api/v1/calendar/calendars/my-calendars/ - list user's calendars
- GET /api/v1/calendar/subscriptions/ - list user's subscriptions
- POST /api/v1/calendar/subscriptions/ - create subscription
- GET /api/v1/calendar/events/?calendar_id={id} - filter events by calendar

Backward compatibility: all legacy endpoints continue to work
2026-02-11 08:18:47 +03:00
ef734f19c0 feat(calendar): add optional Calendar and CalendarSubscription models
- Add Calendar model with visibility settings and auto-subscription
- Add CalendarSubscription model for user subscriptions with permissions
- Add optional 'calendar' field to CalendarEvent (null=True for backward compatibility)
- Update CalendarEvent logic: if calendar=NULL uses legacy (department/employee), if calendar set uses new logic
- Add admin interfaces for Calendar and CalendarSubscription
- Add inline subscription editor in Calendar admin
- Migration 0011: create new tables and add calendar FK to events
- Full backward compatibility: existing code works without changes
2026-02-11 08:12:28 +03:00
c6c0adbd31 docs: добавлена архитектура опциональных календарей 2026-02-11 07:53:04 +03:00
d5929e846c test: обновление тестов API коммуникаций и опросов 2026-02-11 07:30:27 +03:00
4dae6400d5 fix: исправлен URL создания чата на корректный REST endpoint /api/v1/communications/chats/ вместо /create/ (ошибка 405) 2026-02-09 12:19:45 +03:00
9ea33128cc fix(ldap): убрана двойная инициализация LDAP login поля
- Удалена автоматическая инициализация из модуля
- Добавлено детальное логирование для отладки
- Инициализация остается только в employee_detail_scripts.html
2026-02-06 15:42:57 +03:00
3e4137daa4 feat(ldap): добавлено кэширование LDAP логина с возможностью обновления
- Добавлено поле Employee.username для кэширования LDAP логина
- API endpoint обновлен: поддержка кэша и force_refresh параметра
- Новый дизайн: убран blur, добавлена иконка обновления
- Автоматическая загрузка при инициализации (из кэша или LDAP)
- Визуальная индикация источника данных (cached/fresh)
- Доступно всем пользователям без ограничений
2026-02-06 15:33:48 +03:00