Increase VectorEngine timeouts and add image UI
Add VectorEngine image generation config and raise request timeouts (env + scripts) from 180000 to 1000000ms. Introduce a reusable CreativeImageInputPanel component with tests and wire up mobile keyboard-focus helpers; update generation views and related tests (CustomWorldGenerationView, BarkBattle editor, Match3D, Puzzle flows). Improve API error handling / VectorEngine request guidance (packages/shared http.ts and docs), and apply multiple backend/frontend fixes for puzzle/match3d/prompt handling. Also include extensive docs and decision-log updates describing UI/UX decisions and verification steps.
This commit is contained in:
@@ -544,6 +544,16 @@ fn update_match3d_work_tx(
|
||||
input: Match3DWorkUpdateInput,
|
||||
) -> Result<Match3DWorkSnapshot, String> {
|
||||
let current = find_owned_work(ctx, &input.profile_id, &input.owner_user_id)?;
|
||||
let next = build_updated_match3d_work_row(¤t, &input)?;
|
||||
let snapshot = build_work_snapshot(&next)?;
|
||||
replace_work(ctx, ¤t, next);
|
||||
Ok(snapshot)
|
||||
}
|
||||
|
||||
fn build_updated_match3d_work_row(
|
||||
current: &Match3DWorkProfileRow,
|
||||
input: &Match3DWorkUpdateInput,
|
||||
) -> Result<Match3DWorkProfileRow, String> {
|
||||
let tags = parse_tags(&input.tags_json)?;
|
||||
let config = Match3DCreatorConfigSnapshot {
|
||||
theme_text: clean_string(&input.theme_text, "经典消除"),
|
||||
@@ -563,7 +573,7 @@ fn update_match3d_work_tx(
|
||||
author_display_name: current.author_display_name.clone(),
|
||||
game_name: clean_string(&input.game_name, "未命名抓大鹅"),
|
||||
theme_text: config.theme_text.clone(),
|
||||
summary_text: clean_string(&input.summary_text, "经典消除玩法"),
|
||||
summary_text: input.summary_text.trim().to_string(),
|
||||
tags_json: to_json_string(&tags),
|
||||
cover_image_src: input.cover_image_src.trim().to_string(),
|
||||
cover_asset_id: input.cover_asset_id.trim().to_string(),
|
||||
@@ -576,9 +586,7 @@ fn update_match3d_work_tx(
|
||||
published_at: current.published_at,
|
||||
generated_item_assets_json: current.generated_item_assets_json.clone(),
|
||||
};
|
||||
let snapshot = build_work_snapshot(&next)?;
|
||||
replace_work(ctx, ¤t, next);
|
||||
Ok(snapshot)
|
||||
Ok(next)
|
||||
}
|
||||
|
||||
fn publish_match3d_work_tx(
|
||||
@@ -1881,6 +1889,65 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match3d_work_update_preserves_assets_and_allows_empty_summary() {
|
||||
let existing = Match3DWorkProfileRow {
|
||||
profile_id: "profile-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
source_session_id: "session-1".to_string(),
|
||||
author_display_name: "作者".to_string(),
|
||||
game_name: "水果抓大鹅".to_string(),
|
||||
theme_text: "水果".to_string(),
|
||||
summary_text: "保留描述".to_string(),
|
||||
tags_json: "[\"水果\"]".to_string(),
|
||||
cover_image_src: "/old-cover.png".to_string(),
|
||||
cover_asset_id: "cover-asset-1".to_string(),
|
||||
clear_count: 12,
|
||||
difficulty: 4,
|
||||
config_json: to_json_string(&Match3DCreatorConfigSnapshot {
|
||||
theme_text: "水果".to_string(),
|
||||
reference_image_src: None,
|
||||
clear_count: 12,
|
||||
difficulty: 4,
|
||||
asset_style_id: None,
|
||||
asset_style_label: None,
|
||||
asset_style_prompt: None,
|
||||
generate_click_sound: false,
|
||||
}),
|
||||
publication_status: MATCH3D_PUBLICATION_DRAFT.to_string(),
|
||||
play_count: 2,
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
published_at: None,
|
||||
generated_item_assets_json: Some(
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
};
|
||||
let input = Match3DWorkUpdateInput {
|
||||
profile_id: existing.profile_id.clone(),
|
||||
owner_user_id: existing.owner_user_id.clone(),
|
||||
game_name: existing.game_name.clone(),
|
||||
theme_text: existing.theme_text.clone(),
|
||||
summary_text: " ".to_string(),
|
||||
tags_json: existing.tags_json.clone(),
|
||||
cover_image_src: "/new-cover.png".to_string(),
|
||||
cover_asset_id: existing.cover_asset_id.clone(),
|
||||
clear_count: existing.clear_count,
|
||||
difficulty: existing.difficulty,
|
||||
updated_at_micros: 2,
|
||||
};
|
||||
let next = build_updated_match3d_work_row(&existing, &input).unwrap();
|
||||
|
||||
assert_eq!(next.summary_text, "");
|
||||
assert_eq!(next.cover_image_src, "/new-cover.png");
|
||||
assert_eq!(next.clear_count, 12);
|
||||
assert_eq!(next.difficulty, 4);
|
||||
assert_eq!(
|
||||
next.generated_item_assets_json.as_deref(),
|
||||
existing.generated_item_assets_json.as_deref()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match3d_publish_ready_requires_five_image_views_per_item() {
|
||||
let base_work = Match3DWorkProfileRow {
|
||||
|
||||
Reference in New Issue
Block a user