Skip to content

feat(product): remember active Vue tab across page reloads#120

Merged
biz87 merged 3 commits intobetafrom
feat/111-remember-product-tab
Feb 27, 2026
Merged

feat(product): remember active Vue tab across page reloads#120
biz87 merged 3 commits intobetafrom
feat/111-remember-product-tab

Conversation

@Ibochkarev
Copy link
Copy Markdown
Member

Описание

Реализовано запоминание активной вкладки панели товара при перезагрузке страницы. При переключении вкладки её ключ сохраняется в localStorage, при следующей загрузке страницы восстанавливается последняя активная вкладка. Поведение аналогично ExtJS-вкладкам и управляется системной настройкой ms3_product_remember_tabs.

Тип изменений

  • Новая функциональность (non-breaking change)
  • Исправление бага (non-breaking change)
  • Breaking change (изменение, ломающее обратную совместимость)
  • Рефакторинг (без изменения функциональности)
  • Документация
  • Другое (опишите):

Связанные Issues

Closes #111

Как это было протестировано?

  • Ручное тестирование
  • Автоматические тесты (PHPStan, ESLint)
  • Тестирование на разных версиях PHP/MODX

Конфигурация тестирования:

  • MiniShop3: beta
  • MODX: 3.2.x
  • PHP: 8.2+

Скриншоты (если применимо)

До После
При перезагрузке всегда открывалась первая вкладка Открывается последняя активная вкладка

Чеклист

  • Код соответствует стилю проекта
  • Добавлены/обновлены комментарии в сложных местах
  • Изменения не ломают существующую функциональность
  • Лексиконы добавлены на двух языках (ru/en)
  • PHPStan проходит без новых ошибок
  • ESLint проходит без ошибок (для JS/Vue изменений)
  • Обновлён CHANGELOG.md (для значимых изменений)

Дополнительные заметки

  • Настройка ms3_product_remember_tabs по умолчанию включена (true)
  • Сохраняется ключ вкладки, а не индекс — устойчиво к изменению порядка вкладок
  • При ошибках localStorage (quota, private mode) сохранение игнорируется без падения

- Add product_remember_tabs system setting (default: true)
- Persist active tab key to localStorage on tab change
- Restore saved tab on component mount
- Add ms3_product_remember_tabs config to Vue app

Closes #111
@Ibochkarev Ibochkarev marked this pull request as ready for review February 24, 2026 02:04
@Ibochkarev Ibochkarev requested a review from biz87 February 24, 2026 02:04
Copy link
Copy Markdown
Member

@biz87 biz87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ревью PR #120

Чистый, хорошо ограниченный PR. Функциональность корректна, архитектура правильная.

Что хорошо:

  • Переиспользует существующую настройку ms3_product_remember_tabs
  • Сохранение по ключу вкладки, а не по индексу — устойчиво к реордеру
  • ExtJS (ms3-product-update-tabpanel) и Vue (ms3-product-vue-active-tab) ключи не пересекаются
  • Graceful degradation: try/catch на записи, fallback на tab 0 при невалидном ключе

1. Мигание вкладки при восстановлении (UX)

Текущий порядок в onMounted:

onMounted(() => {
  tabsReady.value = true      // ← Tabs рендерятся с activeTab='0'

  if (props.config.product_remember_tabs) {
    nextTick(() => {           // ← На следующий тик переключаемся на сохранённую
      const savedKey = ...
      activeTab.value = String(idx)
    })
  }
})

Это два цикла рендера: сначала видна первая вкладка, потом переключение. Может быть заметный flash, особенно при восстановлении ExtJS-таба (галерея, ссылки).

tabConfig — computed от props, доступен синхронно в onMounted. Можно инициализировать activeTab до tabsReady = true, тогда nextTick не нужен:

onMounted(() => {
  if (props.config.product_remember_tabs) {
    try {
      const savedKey = localStorage.getItem(STORAGE_KEY)
      if (savedKey) {
        const idx = tabConfig.value.findIndex(t => t.key === savedKey)
        if (idx >= 0) activeTab.value = String(idx)
      }
    } catch (_e) {}
  }

  tabsReady.value = true  // ← Рендерится сразу с правильной вкладкой
})

2. Нет try/catch на чтении localStorage

Запись обёрнута в try/catch, а чтение — нет. В большинстве браузеров getItem не бросает исключений, но для консистентности и на случай строгих security-политик стоит обернуть.

3. Несвязанные изменения в ProductData.vue

Пересортировка импорта и переформатирование toast.add() — formatting-only, не связаны с фичей. Не вредят, но засоряют diff. В идеале отдельным коммитом.

…revert ProductData noise

- Init activeTab before tabsReady so first render shows saved tab (no flash)
- Wrap localStorage.getItem in try/catch for consistency with write
- Revert unrelated ProductData.vue changes (import order, toast.add formatting)
@Ibochkarev Ibochkarev requested a review from biz87 February 25, 2026 01:38
…nent

- Extracted tab restoration logic into a separate function for clarity
- Simplified onMounted lifecycle hook to enhance readability
- Maintained existing functionality for restoring active tab from localStorage
@Ibochkarev Ibochkarev self-assigned this Feb 27, 2026
@biz87 biz87 merged commit 0b23dc4 into beta Feb 27, 2026
@Ibochkarev Ibochkarev deleted the feat/111-remember-product-tab branch March 16, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Запомнить вкладку на странице Редактирование товаров

2 participants