feat(#1): remove all EE/Business-Edition features from the UI (pure-CE frontend) #5

Open
agent_coder wants to merge 8 commits from feat/1-remove-ee-ui into develop
Collaborator

Summary

Делает фронтенд чистым CE: удалён Mechanism A (edition gating) целиком — никаких BE-фич, upsell/teaser, BE-only путей. Поведение CE-сборки идентично сегодняшнему, но без мёртвых BE-веток, бейджей «Business Feature», баннера «Upgrade to Business Edition» и BE-only вьюх/роутов. Closes #1. Frontend only (app/), бэкенд-gating вне scope.

287 файлов (158 изменено, 129 удалено), 5 логических коммитов по фазам.

Удалён Mechanism A: isBE, init/selectShow/isLimitedToBE, FeatureId/Edition/FeatureState, BEFeatureIndicator/BEOverlay/BETeaserButton (React+AngularJS), withEdition, useLimitToBE/withLimitToBE, limitedFeatureDir + <be-feature-indicator>, UpgradeBEBanner, BE-логотип.
Не тронуто (DO-NOT-TOUCH §2): Mechanism B (useFeatureFlag/withFeatureFlag/useRedirectFeatureFlag, пустой enum FeatureFlag), withHideOnExtension; в useUser свёрнут только константный isBE→false (adminOnlyCE и CE hasAuthorizations→true сохранены).

Фазы: 1) A/B Docker/K8s/Edge вьюхи; 2) Portainer React вьюхи (settings/gitops/templates/wizard/registries/access/activity); 3) структурные+shared+auth (баннер, sidebar, branding, BE-only роуты, teaser-пропсы); 4) AngularJS (LDAP/OAuth/access, BE-only вьюхи+роуты); 5) teardown движка (feature-flags.service/enums/компоненты/директива).

How verified

  • pnpm typecheck — clean
  • pnpm lint — 0 errors (167 warnings = baseline)
  • pnpm test — green: 2112 passed, 5 skipped, 12 todo
  • §9 grep (isBE|isLimitedToBE|BEFeatureIndicator|BEOverlay|BETeaserButton|withLimitToBE|withEdition|FeatureId|be-feature-indicator|limited-feature-dir) → 0 хитов в app/

Judgment calls (вынесено явно)

  • Helm OCI «Business Feature» опция — оставлена (pre-existing, не Mechanism A; убирать = трогать несвязанный Helm-селектор; лёгкий follow-up).
  • Activity Audit — роут portainer.activityLogs сохранён, BE-teaser заменён на CE empty-state (§5).
  • Custom-template variables — отключены в CE (были BE-only, §4).
  • AngularJS auth-контроллеры — оставлен недостижимый AD/OpenLDAP model-код (переплетён с custom-LDAP валидацией) как dead-but-safe, чтобы не регрессировать CE LDAP.
  • Часть now-unused-but-compiling модулей оставлена, чтобы не раздувать scope (ни один не ссылается на Mechanism A).
  • pnpm-lock.yaml НЕ в PR (на develop pre-existing pnpmfileChecksum mismatch; ставил с --no-frozen-lockfile и откатил lock).

Review checklist

  • CE-поведение сохранено (свёрнутые isBE-ветки оставляют CE-путь; нет регрессий видимых CE-юзеру)
  • Mechanism B + §2 DO-NOT-TOUCH целы
  • typecheck/lint/test зелёные

🤖 Generated with Claude Code

## Summary Делает фронтенд чистым CE: удалён Mechanism A (edition gating) целиком — никаких BE-фич, upsell/teaser, BE-only путей. Поведение CE-сборки идентично сегодняшнему, но без мёртвых BE-веток, бейджей «Business Feature», баннера «Upgrade to Business Edition» и BE-only вьюх/роутов. Closes #1. **Frontend only (`app/`)**, бэкенд-gating вне scope. 287 файлов (158 изменено, 129 удалено), 5 логических коммитов по фазам. **Удалён Mechanism A:** `isBE`, init/selectShow/isLimitedToBE, FeatureId/Edition/FeatureState, BEFeatureIndicator/BEOverlay/BETeaserButton (React+AngularJS), withEdition, useLimitToBE/withLimitToBE, limitedFeatureDir + `<be-feature-indicator>`, UpgradeBEBanner, BE-логотип. **Не тронуто (DO-NOT-TOUCH §2):** Mechanism B (useFeatureFlag/withFeatureFlag/useRedirectFeatureFlag, пустой enum FeatureFlag), withHideOnExtension; в useUser свёрнут только константный isBE→false (adminOnlyCE и CE hasAuthorizations→true сохранены). Фазы: 1) A/B Docker/K8s/Edge вьюхи; 2) Portainer React вьюхи (settings/gitops/templates/wizard/registries/access/activity); 3) структурные+shared+auth (баннер, sidebar, branding, BE-only роуты, teaser-пропсы); 4) AngularJS (LDAP/OAuth/access, BE-only вьюхи+роуты); 5) teardown движка (feature-flags.service/enums/компоненты/директива). ## How verified - `pnpm typecheck` — clean - `pnpm lint` — 0 errors (167 warnings = baseline) - `pnpm test` — green: 2112 passed, 5 skipped, 12 todo - §9 grep (isBE|isLimitedToBE|BEFeatureIndicator|BEOverlay|BETeaserButton|withLimitToBE|withEdition|FeatureId|be-feature-indicator|limited-feature-dir) → **0 хитов в app/** ## Judgment calls (вынесено явно) - Helm OCI «Business Feature» опция — оставлена (pre-existing, не Mechanism A; убирать = трогать несвязанный Helm-селектор; лёгкий follow-up). - Activity Audit — роут portainer.activityLogs сохранён, BE-teaser заменён на CE empty-state (§5). - Custom-template variables — отключены в CE (были BE-only, §4). - AngularJS auth-контроллеры — оставлен недостижимый AD/OpenLDAP model-код (переплетён с custom-LDAP валидацией) как dead-but-safe, чтобы не регрессировать CE LDAP. - Часть now-unused-but-compiling модулей оставлена, чтобы не раздувать scope (ни один не ссылается на Mechanism A). - `pnpm-lock.yaml` НЕ в PR (на develop pre-existing pnpmfileChecksum mismatch; ставил с --no-frozen-lockfile и откатил lock). ## Review checklist - [ ] CE-поведение сохранено (свёрнутые isBE-ветки оставляют CE-путь; нет регрессий видимых CE-юзеру) - [ ] Mechanism B + §2 DO-NOT-TOUCH целы - [ ] typecheck/lint/test зелёные 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- state:review reviewed_head=90f51d48b round=3 verdict=approved -->
agent_coder added 5 commits 2026-06-29 06:36:23 +03:00
Remove always-false isBE branches, BE-only teaser controls and the
now-dead imports across the Docker, Kubernetes and Edge-stack React
views. CE behaviour is preserved; only the Business Edition branches,
teasers and BE-only (non-functional) controls are removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse isBE/isLimitedToBE consumers and delete BE-only teaser UI in
settings, gitops, registries, custom templates, environments wizard,
access control, activity logs, registries and home/system views. The
Activity Audit view keeps its route but renders a plain CE empty state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the Upgrade-to-Business banner, BE sidebar items (Licenses, Shared
Credentials, Edge Configurations, Waiting Room, Update & Rollback), BE
branding (BE logo/footer), and BE-only routed views (update-schedules,
EdgeAutoCreateScript, WaitingRoom, TimeWindowDisplay/Picker). Prune the
featureId/feature/BEFeatureID teaser props from shared components
(Switch, SwitchField, BoxSelector, TooltipWithChildren, wizard Option)
and fold isBE in useUser while preserving CE authorization semantics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unwrap be-feature-indicator / limited-feature directives and feature-id
attributes from LDAP/OAuth/access-management templates, delete BE-only
AngularJS views (Active Directory, OpenLDAP, RBAC access-viewer, auth
logs) and remove their registrations/routes and the r2a teaser-prop
allow-lists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete the feature-flags edition machinery (isBE, init/selectShow/
isLimitedToBE, FeatureId/Edition/FeatureState enums, BEFeatureIndicator,
BEOverlay, BETeaserButton, withEdition, useLimitToBE, limitedFeatureDir)
now that all consumers are gone, drop the initFeatureService bootstrap,
and update tests/stories to assert CE-only behaviour. Mechanism B
(runtime FeatureFlag) and withHideOnExtension are left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-06-29 06:36:24 +03:00
agent_coder added 1 commit 2026-06-29 06:48:08 +03:00
Remove the disabled "Installing from an OCI registry is a Portainer
Business Feature" option from the CE Helm repository selector so no
Business Feature teaser remains; CE Helm Repositories options are
unaffected.

Delete the orphaned AutomaticEdgeEnvCreation module (incl.
EnableWaitingRoomSwitch) — its render was already removed from
EdgeComputeSettingsView and nothing imports it anymore.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Collaborator

Внутренний architect-lead цикл сошёлся на b7df90905 (мой review-субагент: APPROVE). Раунд: реализация (ef47503b, 287 файлов, 5 фаз) → ревью APPROVE-with-suggestions (3 нон-блокера) → фикс: убрана Helm OCI «Business Feature» опция (теперь «Business Feature» = 0 в app/) + удалён осиротевший BE-модуль AutomaticEdgeEnvCreation/ → переревью: CE-поведение сохранено (Helm-селектор работает, RelativePathFieldset цел), Mechanism B + §2 DO-NOT-TOUCH целы, висячих роутов/рантайм-поломок AngularJS нет. AD-downgrade edge-case оставлен (недостижим на подлинном CE, задокументирован). typecheck/lint/test зелёные. Голова → b7df90905, review/needs.

Внутренний architect-lead цикл сошёлся на **b7df90905** (мой review-субагент: APPROVE). Раунд: реализация (ef47503b, 287 файлов, 5 фаз) → ревью APPROVE-with-suggestions (3 нон-блокера) → фикс: убрана Helm OCI «Business Feature» опция (теперь «Business Feature» = 0 в app/) + удалён осиротевший BE-модуль AutomaticEdgeEnvCreation/ → переревью: CE-поведение сохранено (Helm-селектор работает, RelativePathFieldset цел), Mechanism B + §2 DO-NOT-TOUCH целы, висячих роутов/рантайм-поломок AngularJS нет. AD-downgrade edge-case оставлен (недостижим на подлинном CE, задокументирован). typecheck/lint/test зелёные. Голова → b7df90905, review/needs.
Collaborator

F1 [suggestion] app/react/portainer/HomeView/HomeView.tsx:68,72 — недовычищенный фронтовый edition-гейт. PR заявляет «Mechanism A удалён целиком», но здесь остались {process.env.PORTAINER_EDITION !== 'CE' && <LicenseNodePanel/>} и {… && <BackupFailedPanel/>} — живой edition-switch, условно рендерящий два BE-only-панеля. В CE ветки всегда ложны (рантайм-регрессии нет — это подтвердили stability/regressions), но это прямой остаток вырезаемого механизма, а компоненты LicenseNodePanel.tsx/BackupFailedPanel.tsx (+ их .test.tsx) висят в дереве, хотя аналогичные BE-компоненты (HelmCertPanel, BackupS3Form, UpgradeBEBanner) в этом же PR удалены целиком.

Fix: удалить обе строки-гейта и импорты (HomeView.tsx:17-18, 68, 72); удалить файлы LicenseNodePanel.tsx/.test.tsx, BackupFailedPanel.tsx/.test.tsx. (Это единственный оставшийся фронтовый PORTAINER_EDITION-гейт; после него тип PORTAINER_EDITION в global.d.ts остаётся лишь build-переменной.)

F1 [suggestion] `app/react/portainer/HomeView/HomeView.tsx:68,72` — недовычищенный фронтовый edition-гейт. PR заявляет «Mechanism A удалён целиком», но здесь остались `{process.env.PORTAINER_EDITION !== 'CE' && <LicenseNodePanel/>}` и `{… && <BackupFailedPanel/>}` — живой edition-switch, условно рендерящий два BE-only-панеля. В CE ветки всегда ложны (рантайм-регрессии нет — это подтвердили stability/regressions), но это прямой остаток вырезаемого механизма, а компоненты `LicenseNodePanel.tsx`/`BackupFailedPanel.tsx` (+ их .test.tsx) висят в дереве, хотя аналогичные BE-компоненты (HelmCertPanel, BackupS3Form, UpgradeBEBanner) в этом же PR удалены целиком. Fix: удалить обе строки-гейта и импорты (HomeView.tsx:17-18, 68, 72); удалить файлы LicenseNodePanel.tsx/.test.tsx, BackupFailedPanel.tsx/.test.tsx. (Это единственный оставшийся фронтовый PORTAINER_EDITION-гейт; после него тип PORTAINER_EDITION в global.d.ts остаётся лишь build-переменной.)
Collaborator

F2 [suggestion] Осиротевшие файлы с нулём импортёров после вырезания gating — мёртвый код на диске (противоречит цели «полного удаления»). Подтверждено grep'ом по basename и полному пути (включая barrel-реэкспорты и тесты):

  • app/react/portainer/system/useUpgradeEditionMutation.ts
  • app/react/components/HubspotForm.tsx
  • app/react/portainer/HomeView/EnvironmentList/HomepageFilter.tsx
  • app/react/portainer/environments/queries/useUpdateEnvironmentsRelationsMutation.ts
  • кластер app/react/portainer/logs/ActivityLogsView/: ActivityLogsTable.tsx, FilterBar.tsx, types.ts, useActivityLogs.ts, useExportMutation.ts (вью выхолощена в заглушку «No activity logs available.», эти файлы ссылаются только друг на друга)
  • поддерево app/react/portainer/settings/SettingsView/ExperimentalFeatures/ (ExperimentalFeatures.tsx, ExperimentalFeaturesForm.tsx, index.ts) + хуки settings/queries/useExperimentalSettings.ts, useExperimentalSettingsMutation.ts (рендер {isBE && <ExperimentalFeatures/>} удалён, потребителей не осталось; интерфейс ExperimentalFeatures в settings/types.ts оставить — он зеркало backend-типа)
  • проверить app/react/portainer/gitops/ComposePathField/PathSelector.tsx — ComposePathField больше его не импортирует (test-coverage отметил как возможный осиротевший; убедиться, что нет других потребителей).

Fix: удалить перечисленные файлы. Перед удалением HomepageFilter.tsx и useUpdateEnvironmentsRelationsMutation.ts убедиться (regressions это подтвердил), что их пропажа из вьюх — намеренная часть cleanup, а не потеря CE-функции.

F2 [suggestion] Осиротевшие файлы с нулём импортёров после вырезания gating — мёртвый код на диске (противоречит цели «полного удаления»). Подтверждено grep'ом по basename и полному пути (включая barrel-реэкспорты и тесты): - `app/react/portainer/system/useUpgradeEditionMutation.ts` - `app/react/components/HubspotForm.tsx` - `app/react/portainer/HomeView/EnvironmentList/HomepageFilter.tsx` - `app/react/portainer/environments/queries/useUpdateEnvironmentsRelationsMutation.ts` - кластер `app/react/portainer/logs/ActivityLogsView/`: `ActivityLogsTable.tsx`, `FilterBar.tsx`, `types.ts`, `useActivityLogs.ts`, `useExportMutation.ts` (вью выхолощена в заглушку «No activity logs available.», эти файлы ссылаются только друг на друга) - поддерево `app/react/portainer/settings/SettingsView/ExperimentalFeatures/` (`ExperimentalFeatures.tsx`, `ExperimentalFeaturesForm.tsx`, `index.ts`) + хуки `settings/queries/useExperimentalSettings.ts`, `useExperimentalSettingsMutation.ts` (рендер `{isBE && <ExperimentalFeatures/>}` удалён, потребителей не осталось; интерфейс ExperimentalFeatures в settings/types.ts оставить — он зеркало backend-типа) - проверить `app/react/portainer/gitops/ComposePathField/PathSelector.tsx` — ComposePathField больше его не импортирует (test-coverage отметил как возможный осиротевший; убедиться, что нет других потребителей). Fix: удалить перечисленные файлы. Перед удалением HomepageFilter.tsx и useUpdateEnvironmentsRelationsMutation.ts убедиться (regressions это подтвердил), что их пропажа из вьюх — намеренная часть cleanup, а не потеря CE-функции.
Collaborator

F3 [suggestion] Одно-вариантные селекторы и мёртвые секции, оставшиеся после удаления BE-опции — мёртвый UI/стейт, внесённый этим diff:

  • app/react/portainer/settings/SettingsView/BackupSettingsView/BackupSettingsPanel.tsx:12-32 — массив options теперь 1 элемент (File), тернар свёрнут до <BackupFileForm/>, но остались useState backupType и <BoxSelector> с единственным выбором. Fix: убрать backupType/setBackupType и , рендерить напрямую; убрать лишние импорты BoxSelector/useState.
  • app/portainer/views/init/admin/initAdmin.html:140-142 (+ initAdminController.js:22,48) — restoreOptions теперь 1 элемент (file), <box-selector> показывает один вариант, ng-if="… === RESTORE_FORM_TYPES.FILE" всегда истинно. Fix: убрать box-selector и ng-if (file-форма безусловна); в контроллере убрать RESTORE_FORM_TYPES, restoreFormType, onChangeRestoreType, restoreOptions.
  • app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts:64-68newEnvironmentTypes = [] (пусто), но в EnvironmentTypeSelectView.tsx остаётся заголовок «Set up new environments» и второй с пустыми опциями. Fix: удалить экспорт newEnvironmentTypes и его spread; убрать второй с подписью.
F3 [suggestion] Одно-вариантные селекторы и мёртвые секции, оставшиеся после удаления BE-опции — мёртвый UI/стейт, внесённый этим diff: - `app/react/portainer/settings/SettingsView/BackupSettingsView/BackupSettingsPanel.tsx:12-32` — массив options теперь 1 элемент (File), тернар свёрнут до `<BackupFileForm/>`, но остались `useState backupType` и `<BoxSelector>` с единственным выбором. Fix: убрать backupType/setBackupType и <BoxSelector>, рендерить <BackupFileForm/> напрямую; убрать лишние импорты BoxSelector/useState. - `app/portainer/views/init/admin/initAdmin.html:140-142` (+ initAdminController.js:22,48) — restoreOptions теперь 1 элемент (file), `<box-selector>` показывает один вариант, `ng-if="… === RESTORE_FORM_TYPES.FILE"` всегда истинно. Fix: убрать box-selector и ng-if (file-форма безусловна); в контроллере убрать RESTORE_FORM_TYPES, restoreFormType, onChangeRestoreType, restoreOptions. - `app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts:64-68` — `newEnvironmentTypes = []` (пусто), но в EnvironmentTypeSelectView.tsx остаётся заголовок «Set up new environments» и второй <EnvironmentSelector options={newEnvironmentTypes}/> с пустыми опциями. Fix: удалить экспорт newEnvironmentTypes и его spread; убрать второй <EnvironmentSelector> с подписью.
Collaborator

F4 [suggestion] Осиротевшие BE-teaser CSS-правила, оставшиеся без классов-потребителей (классы убраны из JSX этим PR, правила в неизменённых CSS остались мёртвыми):

  • app/react/components/BoxSelector/BoxSelectorItem.module.css:41-49 (/* used for BE teaser */ .box-selector-item.limited.business …)
  • app/react/components/form-components/SwitchField/Switch.css:57-71 (.switch.limited, .switch.limited i, .switch.business i)
  • app/react/components/Tip/TooltipWithChildren/TooltipWithChildren.module.css:43-45 (.tooltip-beteaser)
  • app/react/portainer/environments/wizard/components/Option/Option.module.css:28-35 (.teaser/.teaser:hover)
    После их удаления CSS-переменная --BE-only (app/assets/css/theme.css:102,272,443) останется без потребителей.

Fix: удалить перечисленные CSS-блоки и объявления --BE-only в theme.css.

F4 [suggestion] Осиротевшие BE-teaser CSS-правила, оставшиеся без классов-потребителей (классы убраны из JSX этим PR, правила в неизменённых CSS остались мёртвыми): - `app/react/components/BoxSelector/BoxSelectorItem.module.css:41-49` (`/* used for BE teaser */ .box-selector-item.limited.business …`) - `app/react/components/form-components/SwitchField/Switch.css:57-71` (`.switch.limited`, `.switch.limited i`, `.switch.business i`) - `app/react/components/Tip/TooltipWithChildren/TooltipWithChildren.module.css:43-45` (`.tooltip-beteaser`) - `app/react/portainer/environments/wizard/components/Option/Option.module.css:28-35` (`.teaser`/`.teaser:hover`) После их удаления CSS-переменная `--BE-only` (`app/assets/css/theme.css:102,272,443`) останется без потребителей. Fix: удалить перечисленные CSS-блоки и объявления `--BE-only` в theme.css.
Collaborator

F5 [suggestion] app/react/components/BoxSelector/BoxSelectorItem.tsx:46 (+ BoxSelector.tsx handleSelect/перегрузки onChange) — после вырезания gating параметр limitedToBE стал вырожденным: onSelect(value, false) всегда хардкод false, тянется по контракту onSelect/onChange, но ни один из 31 потребителя второй аргумент не читает. Остаток edition-gating-плумбинга.

Fix: убрать второй параметр limitedToBE из контракта BoxSelectorItem.onSelect, handleSelect и перегрузок onChange в BoxSelector.tsx + хардкод false. (Затрагивает неизменённый BoxSelector.tsx; если правка вне scope PR — допустимо оставить, но тогда это осознанный долг.)

F5 [suggestion] `app/react/components/BoxSelector/BoxSelectorItem.tsx:46` (+ BoxSelector.tsx handleSelect/перегрузки onChange) — после вырезания gating параметр `limitedToBE` стал вырожденным: `onSelect(value, false)` всегда хардкод `false`, тянется по контракту onSelect/onChange, но ни один из 31 потребителя <BoxSelector> второй аргумент не читает. Остаток edition-gating-плумбинга. Fix: убрать второй параметр `limitedToBE` из контракта BoxSelectorItem.onSelect, handleSelect и перегрузок onChange в BoxSelector.tsx + хардкод false. (Затрагивает неизменённый BoxSelector.tsx; если правка вне scope PR — допустимо оставить, но тогда это осознанный долг.)
Collaborator

Ревью (head см. маркер) — раунд 1 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый: security, stability, regressions, test-coverage, conventions, documentation, simplification, architecture). Вердикт: CHANGES.

ФУНКЦИОНАЛЬНО ЧИСТО (LGTM): security (удаление gating не выставило в CE-UI ни одного привилегированного пути; реальный контроль на бэке), stability (висячих ссылок на удалённые символы нет, грэп исчерпывающий, билд не ломается), regressions (во всех isBE?BE:CE оставлена именно CE-ветка; CE-роуты/вьюхи/экспорты не вырезаны вместе с BE; снятые тизеры были disabled-заглушками), test-coverage (удалены только BE-тесты, осиротевших нет), documentation (комментарии/JSDoc консистентны).

НО УДАЛЕНИЕ НЕПОЛНОЕ — три аспекта независимо нашли осиротевший мёртвый код, что прямо противоречит цели PR «pure-CE frontend, no dead BE branches, Mechanism A целиком». Открыто (все suggestion, DO):

  • F1 (architecture) — недовычищенный edition-гейт в HomeView.tsx + осиротевшие LicenseNodePanel/BackupFailedPanel.
  • F2 (conventions/test-coverage) — осиротевшие файлы с нулём импортёров (useUpgradeEditionMutation, HubspotForm, HomepageFilter, useUpdateEnvironmentsRelationsMutation, кластер ActivityLogsView, поддерево ExperimentalFeatures, возможно PathSelector).
  • F3 (simplification) — одно-вариантные селекторы/мёртвые секции (BackupSettingsPanel, initAdmin.html restore, newEnvironmentTypes).
  • F4 (conventions) — осиротевшие BE-teaser CSS-правила + переменная --BE-only.
  • F5 (conventions/simplification) — вырожденный параметр limitedToBE в контракте BoxSelector.

Эскалаций нет: всё — конкретные cleanup-задачи, повторяющие уже применённый в PR паттерн полного удаления BE-компонентов. Блокеров нет — функциональная регрессия отсутствует.

Ревью (head см. маркер) — раунд 1 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый: security, stability, regressions, test-coverage, conventions, documentation, simplification, architecture). Вердикт: CHANGES. ФУНКЦИОНАЛЬНО ЧИСТО (LGTM): security (удаление gating не выставило в CE-UI ни одного привилегированного пути; реальный контроль на бэке), stability (висячих ссылок на удалённые символы нет, грэп исчерпывающий, билд не ломается), regressions (во всех `isBE?BE:CE` оставлена именно CE-ветка; CE-роуты/вьюхи/экспорты не вырезаны вместе с BE; снятые тизеры были disabled-заглушками), test-coverage (удалены только BE-тесты, осиротевших нет), documentation (комментарии/JSDoc консистентны). НО УДАЛЕНИЕ НЕПОЛНОЕ — три аспекта независимо нашли осиротевший мёртвый код, что прямо противоречит цели PR «pure-CE frontend, no dead BE branches, Mechanism A целиком». Открыто (все suggestion, DO): - F1 (architecture) — недовычищенный edition-гейт в HomeView.tsx + осиротевшие LicenseNodePanel/BackupFailedPanel. - F2 (conventions/test-coverage) — осиротевшие файлы с нулём импортёров (useUpgradeEditionMutation, HubspotForm, HomepageFilter, useUpdateEnvironmentsRelationsMutation, кластер ActivityLogsView, поддерево ExperimentalFeatures, возможно PathSelector). - F3 (simplification) — одно-вариантные селекторы/мёртвые секции (BackupSettingsPanel, initAdmin.html restore, newEnvironmentTypes). - F4 (conventions) — осиротевшие BE-teaser CSS-правила + переменная --BE-only. - F5 (conventions/simplification) — вырожденный параметр limitedToBE в контракте BoxSelector. Эскалаций нет: всё — конкретные cleanup-задачи, повторяющие уже применённый в PR паттерн полного удаления BE-компонентов. Блокеров нет — функциональная регрессия отсутствует.
agent_reviewer added the review/changes-requested label 2026-06-29 07:01:21 +03:00
vvzvlad removed the review/needs label 2026-06-29 13:48:59 +03:00
agent_coder added 1 commit 2026-06-29 14:14:12 +03:00
F1: drop the two HomeView edition-gate panels + their files (License/BackupFailed).
F2: delete zero-importer orphans (edition mutation, HubspotForm, HomepageFilter,
    relations mutation, ActivityLogsView cluster, ExperimentalFeatures subtree).
F3: collapse single-option selectors (Backup settings, init restore, env types)
    and delete the option files they orphaned.
F4: remove dead BE-teaser CSS rules and the --BE-only variable.
Also drop the orphaned .btn-warninglight BE-teaser variant.
F5 (limitedToBE) intentionally left — it is still read by BoxSelectorAngular.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Collaborator

Раунд 1 отработан.

F1: fixed — убрал из HomeView.tsx обе строки edition-гейта (PORTAINER_EDITION !== 'CE' && <…Panel/>) и импорты; удалил LicenseNodePanel.tsx/.test.tsx, BackupFailedPanel.tsx/.test.tsx. Висячих ссылок не осталось.

F2: fixed (с одним обоснованным исключением) — удалил осиротевшие (0 импортёров, проверено по basename + relative-path + barrel-реэкспортам + тестам): useUpgradeEditionMutation.ts, HubspotForm.tsx, HomepageFilter.tsx, useUpdateEnvironmentsRelationsMutation.ts, кластер ActivityLogsView/ (ActivityLogsTable/FilterBar/types/useActivityLogs/useExportMutation — сама вью-заглушка их не импортирует), поддерево ExperimentalFeatures/ + хуки useExperimentalSettings/useExperimentalSettingsMutation + два повисших реэкспорта из settings/queries/index.ts. Интерфейс ExperimentalFeatures в settings/types.ts оставил (зеркало backend-типа).
Исключение: gitops/ComposePathField/PathSelector.tsx НЕ удалял — у него живой импортёр RelativePathFieldset.tsx (импортирует PathSelector/PathSelectorGitModel, рендерит <PathSelector>), это НЕ осиротевший файл. test-coverage пометил его как «возможный» — по факту потребитель есть.

F3: fixed — BackupSettingsPanel.tsx: убрал backupType/setBackupType и <BoxSelector>, рендерю <BackupFileForm/> напрямую, вычистил импорты. initAdmin.html + initAdminController.js: убрал <box-selector> и всегда-истинный ng-if, инлайнил file-форму, удалил RESTORE_FORM_TYPES/restoreFormType/onChangeRestoreType/restoreOptions. environment-types.ts + EnvironmentTypeSelectView.tsx: убрал пустой newEnvironmentTypes, его spread, второй <EnvironmentSelector> и заголовок «Set up new environments». Как прямое следствие осиротели и удалены два option-файла: BackupSettingsView/backup-options.tsx и init/InitAdminView/restore-options.tsx.

F4: fixed — удалил мёртвые BE-teaser CSS-блоки (.box-selector-item.limited.business, .switch.limited/.switch.business, .tooltip-beteaser, .teaser/:hover) и все три объявления --BE-only в theme.css. Потребителей не осталось.

F5: wontfix — посылка находки неверна: BoxSelectorAngular.ts handleChange(value, limitedToBE) РЕАЛЬНО читает второй аргумент — this.formCtrl.$setValidity(this.radioName, !limitedToBE, this.formCtrl), и он подключён как on-change к react2angular-обёртке BoxSelector. Значит limitedToBE — живой потребитель контракта onChange, а не вырожденный плумбинг. Убирать параметр сломало бы AngularJS form-validity; оставил как есть.

Доп. чистка (нашёл при внутреннем ревью, тот же паттерн): удалил осиротевший BE-teaser-вариант кнопки .btn-warninglight (Button.css) + член юнион-типа 'warninglight' (Button.tsx) — потребителей color="warninglight" ноль.

Проверка на стенде: grep по всем удалённым символам/файлам/классам — ноль живых ссылок; vitest run SettingsView.test.tsx (проверяет отсутствие «Experimental features») — 1/1 passed. Полный tsc не гонял (node_modules ставить не стал) — корректность сборки подтверждена исчерпывающим грепом по импортам/barrel'ам/шаблонам.

Коммит b1b09e5da. Вернул review/needs.

Раунд 1 отработан. F1: fixed — убрал из `HomeView.tsx` обе строки edition-гейта (`PORTAINER_EDITION !== 'CE' && <…Panel/>`) и импорты; удалил `LicenseNodePanel.tsx`/`.test.tsx`, `BackupFailedPanel.tsx`/`.test.tsx`. Висячих ссылок не осталось. F2: fixed (с одним обоснованным исключением) — удалил осиротевшие (0 импортёров, проверено по basename + relative-path + barrel-реэкспортам + тестам): `useUpgradeEditionMutation.ts`, `HubspotForm.tsx`, `HomepageFilter.tsx`, `useUpdateEnvironmentsRelationsMutation.ts`, кластер `ActivityLogsView/` (ActivityLogsTable/FilterBar/types/useActivityLogs/useExportMutation — сама вью-заглушка их не импортирует), поддерево `ExperimentalFeatures/` + хуки `useExperimentalSettings`/`useExperimentalSettingsMutation` + два повисших реэкспорта из `settings/queries/index.ts`. Интерфейс `ExperimentalFeatures` в `settings/types.ts` оставил (зеркало backend-типа). Исключение: `gitops/ComposePathField/PathSelector.tsx` НЕ удалял — у него живой импортёр `RelativePathFieldset.tsx` (импортирует `PathSelector`/`PathSelectorGitModel`, рендерит `<PathSelector>`), это НЕ осиротевший файл. test-coverage пометил его как «возможный» — по факту потребитель есть. F3: fixed — `BackupSettingsPanel.tsx`: убрал `backupType`/`setBackupType` и `<BoxSelector>`, рендерю `<BackupFileForm/>` напрямую, вычистил импорты. `initAdmin.html` + `initAdminController.js`: убрал `<box-selector>` и всегда-истинный `ng-if`, инлайнил file-форму, удалил `RESTORE_FORM_TYPES`/`restoreFormType`/`onChangeRestoreType`/`restoreOptions`. `environment-types.ts` + `EnvironmentTypeSelectView.tsx`: убрал пустой `newEnvironmentTypes`, его spread, второй `<EnvironmentSelector>` и заголовок «Set up new environments». Как прямое следствие осиротели и удалены два option-файла: `BackupSettingsView/backup-options.tsx` и `init/InitAdminView/restore-options.tsx`. F4: fixed — удалил мёртвые BE-teaser CSS-блоки (`.box-selector-item.limited.business`, `.switch.limited`/`.switch.business`, `.tooltip-beteaser`, `.teaser`/`:hover`) и все три объявления `--BE-only` в `theme.css`. Потребителей не осталось. F5: wontfix — посылка находки неверна: `BoxSelectorAngular.ts` `handleChange(value, limitedToBE)` РЕАЛЬНО читает второй аргумент — `this.formCtrl.$setValidity(this.radioName, !limitedToBE, this.formCtrl)`, и он подключён как `on-change` к react2angular-обёртке `BoxSelector`. Значит `limitedToBE` — живой потребитель контракта `onChange`, а не вырожденный плумбинг. Убирать параметр сломало бы AngularJS form-validity; оставил как есть. Доп. чистка (нашёл при внутреннем ревью, тот же паттерн): удалил осиротевший BE-teaser-вариант кнопки `.btn-warninglight` (Button.css) + член юнион-типа `'warninglight'` (Button.tsx) — потребителей `color="warninglight"` ноль. Проверка на стенде: grep по всем удалённым символам/файлам/классам — ноль живых ссылок; `vitest run SettingsView.test.tsx` (проверяет отсутствие «Experimental features») — 1/1 passed. Полный `tsc` не гонял (node_modules ставить не стал) — корректность сборки подтверждена исчерпывающим грепом по импортам/barrel'ам/шаблонам. Коммит b1b09e5da. Вернул `review/needs`.
agent_coder added review/needs and removed review/changes-requested labels 2026-06-29 14:14:40 +03:00
Collaborator

Ревью b1b09e5da — раунд 2 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый).

Вердикт: CHANGES. Раунд 1 закрыт почти полностью:

  • F1–F4 — исправлены и проверены независимо: edition-гейт в HomeView + LicenseNodePanel/BackupFailedPanel(+тесты) удалены; осиротевшие файлы (useUpgradeEditionMutation, HubspotForm, HomepageFilter, useUpdateEnvironmentsRelationsMutation, кластер ActivityLogsView/, поддерево ExperimentalFeatures/, backup-options/restore-options) удалены с нулём импортёров; одно-вариантные селекторы (BackupSettingsPanel, initAdmin restore, EnvironmentTypeSelectView) свёрнуты на CE-путь; мёртвый BE-teaser CSS + --BE-only убраны.
  • F5 — wontfix принят. Посылка находки была неверна: app/portainer/components/BoxSelector/BoxSelectorAngular.ts:24 handleChange(value, limitedToBE) РЕАЛЬНО читает 2-й аргумент — this.formCtrl.$setValidity(this.radioName, !limitedToBE, …) — и подключён через on-change к react2angular-обёртке. Параметр — живой потребитель контракта, не вырожденный плумбинг. Подтверждено двумя аспектами + перепроверено. Не трогать.

Проверки на build-безопасность (раз tsc не гонялся): сквозной грэп всех 136 изменённых файлов + всех удалённых модулей/символов/пропов/Angular-селекторов/CSS — ноль висячих ссылок и сломанного control flow; статический import-resolver по всем 285 оставшимся тест-файлам против 143 удалённых модулей — ноль осиротевших тестов; security (ни одного снятого клиентского гварда — adminOnlyCE цел), regressions (свёртки уронили только BE-gated/teaser-опции — S3 backup/restore, KubeSolo/K8s-install; CE-пути целы), documentation — чисто.

Полное ревью нашло два НОВЫХ остатка того же паттерна «мёртвый BE-код», которые cleanup пропустил в зоне AccessDatatable (после удаления BE-only колонки role). Отвечайте по id (fixed: / wontfix:).

Что сделать

F6 [simplification] Осиротевший файл колонки role.tsx после удаления BE-only колонкиapp/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx
Этот PR убрал import { role } from './role'; из useColumns.ts, и это был единственный потребитель файла в каталоге AccessDatatable/columns/ (barrel'а тут нет; грэп по columns/role в app/ находит только ДРУГИЕ ./role — в users/ListView/UsersDatatable/columns и kubernetes/.../NodesDatatable/columns, это иные файлы). BE-only колонка role осталась мёртвой на диске — ровно тот случай, что F2.
Fix: удалить app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx.

F7 [simplification] Холостой _.compact + мёртвый импорт lodash в useColumnsapp/react/portainer/access-control/AccessManagement/AccessDatatable/columns/useColumns.ts:1,10
PR убрал единственный falsy-способный элемент массива (BE-only role). Оставшийся _.compact([inheritFrom ? inheritedName : name, type]) оборачивает только всегда-истинные результаты helper.accessor(...)_.compact стал no-op, а import _ from 'lodash' — мёртвым весом. Тот же свёрток (compact → обычный массив) кодер уже сделал в параллельных Wizard-файлах (WizardDocker/Kubernetes/Podman), но здесь пропустил.
Fix: return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom]); и удалить import _ from 'lodash';.


Маркер reviewed_head обновлён на b1b09e5da. После правок верните лейбл review/needs.

кодеру НЕ делать — calibration log для оператора (DROP, не задачи):
- [premise-wrong] suggestion [conventions/simplification] F5 (`limitedToBE` как вырожденный плумбинг) — закрыт как wontfix: 2-й аргумент реально потребляется AngularJS-обёрткой (`$setValidity`). Находка раунда 1 была ошибочной по посылке; калибровочный сигнал (был помечен low-medium confidence на «неизменённый BoxSelector.tsx»).
Ревью **b1b09e5da** — раунд 2 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый). **Вердикт: CHANGES.** Раунд 1 закрыт почти полностью: - **F1–F4** — исправлены и проверены независимо: edition-гейт в HomeView + `LicenseNodePanel`/`BackupFailedPanel`(+тесты) удалены; осиротевшие файлы (`useUpgradeEditionMutation`, `HubspotForm`, `HomepageFilter`, `useUpdateEnvironmentsRelationsMutation`, кластер `ActivityLogsView/`, поддерево `ExperimentalFeatures/`, `backup-options`/`restore-options`) удалены с нулём импортёров; одно-вариантные селекторы (BackupSettingsPanel, initAdmin restore, EnvironmentTypeSelectView) свёрнуты на CE-путь; мёртвый BE-teaser CSS + `--BE-only` убраны. - **F5 — wontfix принят.** Посылка находки была неверна: `app/portainer/components/BoxSelector/BoxSelectorAngular.ts:24` `handleChange(value, limitedToBE)` РЕАЛЬНО читает 2-й аргумент — `this.formCtrl.$setValidity(this.radioName, !limitedToBE, …)` — и подключён через `on-change` к react2angular-обёртке. Параметр — живой потребитель контракта, не вырожденный плумбинг. Подтверждено двумя аспектами + перепроверено. Не трогать. Проверки на build-безопасность (раз `tsc` не гонялся): сквозной грэп всех 136 изменённых файлов + всех удалённых модулей/символов/пропов/Angular-селекторов/CSS — **ноль висячих ссылок и сломанного control flow**; статический import-resolver по всем 285 оставшимся тест-файлам против 143 удалённых модулей — **ноль осиротевших тестов**; security (ни одного снятого клиентского гварда — `adminOnlyCE` цел), regressions (свёртки уронили только BE-gated/teaser-опции — S3 backup/restore, KubeSolo/K8s-install; CE-пути целы), documentation — чисто. Полное ревью нашло два НОВЫХ остатка того же паттерна «мёртвый BE-код», которые cleanup пропустил в зоне AccessDatatable (после удаления BE-only колонки `role`). Отвечайте по id (`fixed:` / `wontfix:`). ### Что сделать **F6 [simplification] Осиротевший файл колонки `role.tsx` после удаления BE-only колонки** — `app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx` Этот PR убрал `import { role } from './role';` из `useColumns.ts`, и это был единственный потребитель файла в каталоге `AccessDatatable/columns/` (barrel'а тут нет; грэп по `columns/role` в `app/` находит только ДРУГИЕ `./role` — в `users/ListView/UsersDatatable/columns` и `kubernetes/.../NodesDatatable/columns`, это иные файлы). BE-only колонка `role` осталась мёртвой на диске — ровно тот случай, что F2. Fix: удалить `app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx`. **F7 [simplification] Холостой `_.compact` + мёртвый импорт lodash в `useColumns`** — `app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/useColumns.ts:1,10` PR убрал единственный falsy-способный элемент массива (BE-only `role`). Оставшийся `_.compact([inheritFrom ? inheritedName : name, type])` оборачивает только всегда-истинные результаты `helper.accessor(...)` → `_.compact` стал no-op, а `import _ from 'lodash'` — мёртвым весом. Тот же свёрток (compact → обычный массив) кодер уже сделал в параллельных Wizard-файлах (WizardDocker/Kubernetes/Podman), но здесь пропустил. Fix: `return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom]);` и удалить `import _ from 'lodash';`. --- Маркер `reviewed_head` обновлён на `b1b09e5da`. После правок верните лейбл `review/needs`. ``` кодеру НЕ делать — calibration log для оператора (DROP, не задачи): - [premise-wrong] suggestion [conventions/simplification] F5 (`limitedToBE` как вырожденный плумбинг) — закрыт как wontfix: 2-й аргумент реально потребляется AngularJS-обёрткой (`$setValidity`). Находка раунда 1 была ошибочной по посылке; калибровочный сигнал (был помечен low-medium confidence на «неизменённый BoxSelector.tsx»). ``` <!-- state:review reviewed_head=b1b09e5da round=2 verdict=changes -->
agent_reviewer added review/changes-requested and removed review/needs labels 2026-06-29 14:54:26 +03:00
agent_coder added 1 commit 2026-06-29 15:08:20 +03:00
F6: delete AccessDatatable/columns/role.tsx — the BE-only role column lost its
    only importer when useColumns stopped importing it; zero importers remain.
F7: useColumns wrapped only always-truthy helper.accessor results in _.compact,
    a no-op; return the plain array and drop the now-dead lodash import (same
    collapse already done in the parallel Wizard column files).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Collaborator

Раунд 2: F6 и F7 отработаны.

F6: fixed — удалил app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx. После того как PR убрал import { role } из useColumns.ts, это был единственный потребитель файла; barrel'а в каталоге нет, остальные ./role в дереве — другие файлы (users/, kubernetes/). Ноль импортёров — подтвердил грепом.

F7: fixed — в useColumns.ts убрал _.compact и мёртвый import _ from 'lodash': name/type/inheritedName — все helper.accessor(...), т.е. всегда-истинные, поэтому compact был no-op. Теперь return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom]). Тот же свёрток уже сделан в параллельных Wizard-колонках.

Проверка на стенде: vitest run AccessDatatable12/12 passed; греп подтвердил отсутствие висячих ссылок на ./role и неиспользуемого lodash.

Коммит 90f51d48b. Вернул review/needs.

Раунд 2: F6 и F7 отработаны. F6: fixed — удалил `app/react/portainer/access-control/AccessManagement/AccessDatatable/columns/role.tsx`. После того как PR убрал `import { role }` из `useColumns.ts`, это был единственный потребитель файла; barrel'а в каталоге нет, остальные `./role` в дереве — другие файлы (users/, kubernetes/). Ноль импортёров — подтвердил грепом. F7: fixed — в `useColumns.ts` убрал `_.compact` и мёртвый `import _ from 'lodash'`: `name`/`type`/`inheritedName` — все `helper.accessor(...)`, т.е. всегда-истинные, поэтому `compact` был no-op. Теперь `return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom])`. Тот же свёрток уже сделан в параллельных Wizard-колонках. Проверка на стенде: `vitest run AccessDatatable` — **12/12 passed**; греп подтвердил отсутствие висячих ссылок на `./role` и неиспользуемого lodash. Коммит 90f51d48b. Вернул `review/needs`.
agent_coder added review/needs and removed review/changes-requested labels 2026-06-29 15:08:35 +03:00
Collaborator

Ревью 90f51d48b — раунд 3 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый).

Вердикт: PASS. F6 и F7 закрыты и проверены независимо: AccessDatatable/columns/role.tsx удалён (ноль импортёров columns/role в app/; прочие ./role в дереве — другие файлы), а useColumns.ts теперь return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom]) без _.compact/lodash (все элементы — helper.accessor(...), всегда-истинные, так что compact был no-op). Висячих ссылок нет, билд цел, CE-колонки (inheritedName/name/type) не тронуты. Все 8 аспектов — LGTM. Все находки всех раундов закрыты — готово к мержу.

Маркер reviewed_head обновлён на 90f51d48b.

Ревью **90f51d48b** — раунд 3 (ПОЛНЫЕ 8 аспектов, отдельный субагент на каждый). **Вердикт: PASS.** F6 и F7 закрыты и проверены независимо: `AccessDatatable/columns/role.tsx` удалён (ноль импортёров `columns/role` в `app/`; прочие `./role` в дереве — другие файлы), а `useColumns.ts` теперь `return useMemo(() => [inheritFrom ? inheritedName : name, type], [inheritFrom])` без `_.compact`/lodash (все элементы — `helper.accessor(...)`, всегда-истинные, так что compact был no-op). Висячих ссылок нет, билд цел, CE-колонки (inheritedName/name/type) не тронуты. Все 8 аспектов — LGTM. Все находки всех раундов закрыты — готово к мержу. Маркер `reviewed_head` обновлён на `90f51d48b`. <!-- state:review reviewed_head=90f51d48b round=3 verdict=approved -->
agent_reviewer added review/approved and removed review/needs labels 2026-06-29 15:33:12 +03:00
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/1-remove-ee-ui:feat/1-remove-ee-ui
git checkout feat/1-remove-ee-ui
Sign in to join this conversation.