Stabilize SEO project stage navigation

This commit is contained in:
DCCONSTRUCTIONS 2026-07-05 17:41:53 +03:00
parent 22ec219383
commit 74abe909bd
1 changed files with 63 additions and 12 deletions

View File

@ -5706,8 +5706,8 @@ function getPipelineStageAccess(
const marketReady = Boolean(input.marketEnrichment && input.marketEnrichment.state !== "not_ready"); const marketReady = Boolean(input.marketEnrichment && input.marketEnrichment.state !== "not_ready");
const keywordReady = Boolean(input.keywordMap && input.keywordMap.readiness.mappedItemCount > 0); const keywordReady = Boolean(input.keywordMap && input.keywordMap.readiness.mappedItemCount > 0);
const strategyReady = Boolean(input.seoStrategy && input.seoStrategy.state !== "blocked"); const strategyReady = Boolean(input.seoStrategy && input.seoStrategy.state !== "blocked");
const synthesisReady = input.strategySynthesis?.state === "ready"; const synthesisReady = strategyReady && input.strategySynthesis?.state === "ready";
const qualityReady = input.strategyQualityReview?.state === "ready"; const qualityReady = synthesisReady && input.strategyQualityReview?.state === "ready";
if (stageIndex === 0) { if (stageIndex === 0) {
return { reason: "Импортируй сайт или выбери уже созданный проект.", status: "open", unlocked: true }; return { reason: "Импортируй сайт или выбери уже созданный проект.", status: "open", unlocked: true };
@ -5784,6 +5784,18 @@ function getPipelineStageAccess(
}; };
} }
function getPreferredProjectStageIndex(input: Parameters<typeof getPipelineStageAccess>[1]) {
const stageAccess = pipeline.map((_, stageIndex) => getPipelineStageAccess(stageIndex, input));
if (stageAccess[7]?.unlocked) return 7;
if (stageAccess[6]?.unlocked) return 6;
if (stageAccess[5]?.unlocked) return 5;
if (stageAccess[4]?.unlocked) return 4;
if (stageAccess[3]?.unlocked) return 3;
if (stageAccess[2]?.unlocked) return 2;
return 1;
}
function getAuditIssueCounts(issues: AuditIssue[]) { function getAuditIssueCounts(issues: AuditIssue[]) {
return issues.reduce( return issues.reduce(
(counts, issue) => { (counts, issue) => {
@ -14481,6 +14493,14 @@ export function App() {
const activeSeoStrategy = activeProject ? (seoStrategies[activeProject.id] ?? null) : null; const activeSeoStrategy = activeProject ? (seoStrategies[activeProject.id] ?? null) : null;
const activeStrategySynthesis = activeProject ? (strategySyntheses[activeProject.id] ?? null) : null; const activeStrategySynthesis = activeProject ? (strategySyntheses[activeProject.id] ?? null) : null;
const activeStrategyQualityReview = activeProject ? (strategyQualityReviews[activeProject.id] ?? null) : null; const activeStrategyQualityReview = activeProject ? (strategyQualityReviews[activeProject.id] ?? null) : null;
const activeLiveSemanticAnalysis = activeProject ? (semanticAnalyses[activeProject.id] ?? null) : null;
const activeLiveContextReviewRaw = activeProject ? (contextReviews[activeProject.id] ?? null) : null;
const activeLiveContextReview =
activeLiveSemanticAnalysis && activeLiveContextReviewRaw?.semanticRunId === activeLiveSemanticAnalysis.runId
? activeLiveContextReviewRaw
: null;
const activeLiveMarketEnrichment = activeProject ? (marketEnrichments[activeProject.id] ?? null) : null;
const activeLiveKeywordMap = activeProject ? (keywordMaps[activeProject.id] ?? null) : null;
const activeProjectScanScopeCounts = activeProjectScanSummary ? getScanScopeCounts(activeProjectScanSummary) : null; const activeProjectScanScopeCounts = activeProjectScanSummary ? getScanScopeCounts(activeProjectScanSummary) : null;
const activeProjectSelectedWorkspaceScopeItems = activeProjectScanSummary const activeProjectSelectedWorkspaceScopeItems = activeProjectScanSummary
? getSelectedWorkspaceScopeItems(activeProjectScanSummary) ? getSelectedWorkspaceScopeItems(activeProjectScanSummary)
@ -14562,12 +14582,12 @@ export function App() {
const visibleProjects = activeStageIndex === 0 ? projects : activeProject ? [activeProject] : []; const visibleProjects = activeStageIndex === 0 ? projects : activeProject ? [activeProject] : [];
const stageAccessList = pipeline.map((_, stageIndex) => const stageAccessList = pipeline.map((_, stageIndex) =>
getPipelineStageAccess(stageIndex, { getPipelineStageAccess(stageIndex, {
contextReview: activeContextReview, contextReview: activeLiveContextReview,
hasProject: Boolean(activeProject), hasProject: Boolean(activeProject),
keywordMap: activeKeywordMap, keywordMap: activeLiveKeywordMap,
marketEnrichment: activeMarketEnrichment, marketEnrichment: activeLiveMarketEnrichment,
scan: activeProjectScanSummary, scan: activeProjectScanSummary,
semanticAnalysis: activeSemanticAnalysis, semanticAnalysis: activeLiveSemanticAnalysis,
seoStrategy: activeSeoStrategy, seoStrategy: activeSeoStrategy,
strategyQualityReview: activeStrategyQualityReview, strategyQualityReview: activeStrategyQualityReview,
strategySynthesis: activeStrategySynthesis strategySynthesis: activeStrategySynthesis
@ -14966,6 +14986,7 @@ export function App() {
disabled={isSavingActiveKeywordContextSnapshot} disabled={isSavingActiveKeywordContextSnapshot}
menuClassName="keyword-context-profile-menu" menuClassName="keyword-context-profile-menu"
onChange={(snapshotId) => { onChange={(snapshotId) => {
clearProjectActionFeedback();
setActiveKeywordContextSnapshotIds((currentIds) => ({ setActiveKeywordContextSnapshotIds((currentIds) => ({
...currentIds, ...currentIds,
[activeProject.id]: snapshotId [activeProject.id]: snapshotId
@ -15221,11 +15242,41 @@ export function App() {
</div> </div>
) : null; ) : null;
function clearProjectActionFeedback() {
setProjectActionProjectId(null);
setProjectActionError(null);
setProjectActionMessage(null);
}
function getProjectPipelineAccessInput(projectId: string): Parameters<typeof getPipelineStageAccess>[1] {
const semanticAnalysis = semanticAnalyses[projectId] ?? null;
const contextReviewRaw = contextReviews[projectId] ?? null;
const contextReview =
semanticAnalysis && contextReviewRaw?.semanticRunId === semanticAnalysis.runId ? contextReviewRaw : null;
return {
contextReview,
hasProject: true,
keywordMap: keywordMaps[projectId] ?? null,
marketEnrichment: marketEnrichments[projectId] ?? null,
scan: scanSummaries[projectId],
semanticAnalysis,
seoStrategy: seoStrategies[projectId] ?? null,
strategyQualityReview: strategyQualityReviews[projectId] ?? null,
strategySynthesis: strategySyntheses[projectId] ?? null
};
}
function getPreferredStageIndexForProject(projectId: string) {
return getPreferredProjectStageIndex(getProjectPipelineAccessInput(projectId));
}
function openProjectScanStage(project: ProjectSummary) { function openProjectScanStage(project: ProjectSummary) {
if (editingProjectId === project.id || pendingDeleteProjectId === project.id) { if (editingProjectId === project.id || pendingDeleteProjectId === project.id) {
return; return;
} }
clearProjectActionFeedback();
setActiveProjectId(project.id); setActiveProjectId(project.id);
setActiveStageIndex(1); setActiveStageIndex(1);
setIsProjectMenuOpen(false); setIsProjectMenuOpen(false);
@ -15239,17 +15290,20 @@ export function App() {
} }
function openProjectFromMenu(project: ProjectSummary) { function openProjectFromMenu(project: ProjectSummary) {
const nextStageIndex = activeProjectId === project.id ? activeStageIndex : 1; const nextStageIndex =
activeProjectId === project.id && isWorkPanelOpen ? activeStageIndex : getPreferredStageIndexForProject(project.id);
clearProjectActionFeedback();
setActiveProjectId(project.id); setActiveProjectId(project.id);
setActiveStageIndex(nextStageIndex); setActiveStageIndex(nextStageIndex);
setIsProjectMenuOpen(false); setIsProjectMenuOpen(false);
setIsStageRailOpen(true); setIsStageRailOpen(true);
setIsWorkPanelOpen(false); setIsWorkPanelOpen(true);
setIsWorkPanelFullscreen(false); setIsWorkPanelFullscreen(false);
} }
function closeActiveProject() { function closeActiveProject() {
clearProjectActionFeedback();
setActiveProjectId(null); setActiveProjectId(null);
setActiveStageIndex(0); setActiveStageIndex(0);
setIsProjectMenuOpen(false); setIsProjectMenuOpen(false);
@ -15279,10 +15333,7 @@ export function App() {
return; return;
} }
if (!projectActionProjectId) { clearProjectActionFeedback();
setProjectActionError(null);
setProjectActionMessage(null);
}
setActiveStageIndex(stageIndex); setActiveStageIndex(stageIndex);
setIsStageRailOpen(true); setIsStageRailOpen(true);