Puzzle: support history images & partial generation

Allow history-generated image paths to be submitted where Data URLs were previously required and avoid treating partial/result-page generations as blocking the whole draft. Backend: resolve history /generated-* references via resolve_puzzle_reference_image_as_data_url and convert to PuzzleDownloadedImage; add PuzzleDownloadedImage::from_resolved_reference_image; extend draft handling to apply generated level metadata (auto-naming) and normalize generation_status to treat levels with images as ready. API: add shouldAutoNameLevel to action contracts and use it to request/refine generated level names. Spacetime/module and mappers: normalize completed level statuses when saving/reading so result-page background or per-level generation doesn't mask completed drafts. Frontend: expose resolver helpers, only mark a work as generating when no usable cover or ready level exists, keep level controls enabled during UI-background regeneration, and add tests covering history-image submission, auto-naming, and UI-background/partial-generation behaviors.
This commit is contained in:
2026-05-19 10:02:13 +08:00
parent 5e03b3d2f2
commit 7b37271f17
16 changed files with 653 additions and 73 deletions

View File

@@ -300,7 +300,11 @@ import { PublishShareModal } from '../common/PublishShareModal';
import type { PublishShareModalPayload } from '../common/publishShareModalModel';
import { UnifiedModal } from '../common/UnifiedModal';
import { resolveCreativeAgentTargetSelectionStage } from '../creative-agent/creativeAgentViewModel';
import type { CreationWorkShelfItem } from '../custom-world-home/creationWorkShelf';
import {
isPersistedPuzzleDraftGenerating,
resolvePuzzleWorkCoverImageSrc,
type CreationWorkShelfItem,
} from '../custom-world-home/creationWorkShelf';
import {
isBigFishGalleryEntry,
isEdutainmentGalleryEntry,
@@ -3403,9 +3407,12 @@ export function PlatformEntryFlowShellImpl({
const notice = getDraftGenerationNotice(
getGenerationNoticeShelfKeys(item),
);
const isNoticeGenerating =
notice?.status === 'generating' &&
(item.source.kind !== 'puzzle' ||
!resolvePuzzleWorkCoverImageSrc(item.source.item));
return {
isGenerating:
notice?.status === 'generating' || item.isGenerating === true,
isGenerating: isNoticeGenerating || item.isGenerating === true,
hasUnreadUpdate: notice?.status === 'ready' && !notice.seen,
};
},
@@ -6495,7 +6502,10 @@ export function PlatformEntryFlowShellImpl({
}
}
if (payload.action === 'generate_puzzle_images') {
if (
payload.action === 'generate_puzzle_images' ||
payload.action === 'generate_puzzle_ui_background'
) {
void executePuzzleBackgroundAction(payload);
return;
}
@@ -8748,13 +8758,16 @@ export function PlatformEntryFlowShellImpl({
buildPuzzleResultWorkId(item.sourceSessionId),
buildPuzzleResultProfileId(item.sourceSessionId),
]);
const isMarkedGenerating = isDraftNoticeGenerating('puzzle', [
const hasGeneratingNotice = isDraftNoticeGenerating('puzzle', [
item.workId,
item.profileId,
item.sourceSessionId,
buildPuzzleResultWorkId(item.sourceSessionId),
buildPuzzleResultProfileId(item.sourceSessionId),
]) || isPersistedDraftGenerating(item.generationStatus);
]);
const isMarkedGenerating =
(hasGeneratingNotice && !resolvePuzzleWorkCoverImageSrc(item)) ||
isPersistedPuzzleDraftGenerating(item);
setPuzzleOperation(null);
setPuzzleRun(null);
setPuzzleRuntimeAuthMode('default');