Stabilize SEO project stage navigation
This commit is contained in:
parent
22ec219383
commit
74abe909bd
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue