import React, { useState } from 'react'; import { Package, Play, Pause, RotateCcw, Sliders, } from 'lucide-react'; import { useKccStore, useOperatorRole } from '../store/kccStore'; import { StatusBadge } from '../components/StatusBadge'; import { RolloutStage } from '../contracts'; export const ModulesPage: React.FC = () => { const modules = useKccStore((state) => state.modules); const rollouts = useKccStore((state) => state.rollouts); const organizations = useKccStore((state) => state.organizations); const openConfirmModal = useKccStore((state) => state.openConfirmModal); const triggerRolloutStage = useKccStore((state) => state.triggerRolloutStage); const createRollout = useKccStore((state) => state.createRollout); const { permissions } = useOperatorRole(); const [selectedModuleId, setSelectedModuleId] = useState(modules[0]?.moduleId || 'krona-core'); const selectedModule = modules.find((m) => m.moduleId === selectedModuleId); // Derived rollout defaults for selected module const rolloutVersion = selectedModule?.latestVersion || '1.0.0'; const pilotOrgs = organizations.slice(0, 2).map((o) => o.tenantId); const activeRollout = rollouts.find((r) => r.moduleId === selectedModuleId); const handleStageChange = (stage: RolloutStage, percentage: number) => { if (!activeRollout) return; openConfirmModal({ title: `Смена фазы раскатки: ${activeRollout.moduleName}`, actionName: `rollout.stage_${stage}`, impactSummary: `Конвейер раскатки будет переведен в состояние «${stage}» (${percentage}% трафика).`, targetType: 'rollout', targetId: activeRollout.rolloutId, targetName: activeRollout.moduleName, onConfirm: async (reason) => { await triggerRolloutStage(activeRollout.rolloutId, stage, percentage, reason); }, }); }; const handleCreateRollout = () => { if (!selectedModule) return; openConfirmModal({ title: `Запуск новой раскатки: ${selectedModule.name}`, actionName: `rollout.start_pilot (${rolloutVersion})`, impactSummary: `Будет запущен пилотный этап обновления до версии ${rolloutVersion} для ${pilotOrgs.length} пилотных организаций.`, targetType: 'rollout', targetId: selectedModule.moduleId, targetName: selectedModule.name, onConfirm: async (reason) => { await createRollout( selectedModule.moduleId, rolloutVersion, 'pilot', pilotOrgs, 15, 'Пилотная фаза раскатки обновления', reason ); }, }); }; return (
{/* Header */}

Каталог модулей и Rollout конвейер

Управление манифестами, compatibility core/schema, пилотными организациями и фазовыми релизами

Всего модулей: {modules.length} • Активных раскаток:{' '} {rollouts.length}
{/* Grid: Module Selector + Module Detail & Rollout Manager */}
{/* Left Column: Modules Catalog List */}
Каталог системных модулей
{modules.map((m) => { const isSelected = m.moduleId === selectedModuleId; const hasRollout = rollouts.some((r) => r.moduleId === m.moduleId); return (
setSelectedModuleId(m.moduleId)} className={`p-3 rounded-lg border text-xs cursor-pointer transition-colors space-y-1.5 ${ isSelected ? 'bg-amber-500/15 border-amber-500/40 text-zinc-100' : 'bg-zinc-950/60 border-zinc-800 text-zinc-400 hover:bg-zinc-800/50 hover:text-zinc-200' }`} >
{m.name} v{m.latestVersion}

{m.description}

Тенантов: {m.activeTenantsCount} • Инстансов: {m.instancesCount} {hasRollout && ( Rollout )}
); })}
{/* Right 2 Columns: Module Details & Rollout Controller */}
{selectedModule && ( <> {/* Module Header Card */}
{selectedModule.code} • Категория: {selectedModule.category}

{selectedModule.name}

{selectedModule.description}

Текущая стабильная версия:
v{selectedModule.latestVersion}
Канал релиза:
{selectedModule.rolloutChannel}
Манифест:
v{selectedModule.manifestVersion}
Зависимости:
{selectedModule.dependencies.length > 0 ? selectedModule.dependencies.join(', ') : 'Нет (Базовый)'}
{/* Rollout Control Panel (Сценарий 8) */}

Управление раскаткой (Rollout Pipeline)

{activeRollout && }
{activeRollout ? (
{/* Progress visualizer */}
Целевая версия: v{activeRollout.targetVersion} {activeRollout.percentage}%
Стадия: {activeRollout.stage} Пилотных организаций: {activeRollout.pilotTenantIds.length} Старт: {new Date(activeRollout.startedAt).toLocaleDateString('ru-RU')}
{/* Rollout Action Buttons */}
{activeRollout.stage !== 'paused' ? ( ) : ( )}
) : (

Для модуля {selectedModule.name} нет активных раскаток. Вы можете запустить пилотный релиз новой версии.

)}
{/* Release History & Deployments */}

История релизов и совместимость (Compatibility)

{selectedModule.releaseHistory.map((rel) => (
v{rel.version} {new Date(rel.releasedAt).toLocaleDateString('ru-RU')}

{rel.changelog}

Совместимость с Core: {rel.compatibleCore}
))}
)}
); };