Wire browse-worlds screen to GET /api/worlds

- main_menu.gd: Play button now navigates to world_list.tscn
- world_list.gd: fix invalid theme_override_constants property-path syntax
  (use add_theme_constant_override), fix @onready node paths missing
  /HeaderHBox/, cast Variant dict values to String to avoid type-inference
  errors when cards actually render
- world_list.tscn: wire up Back/Refresh button signal connections (scene
  had zero [connection] blocks, buttons were dead)
- backend: fix real bug where World.visibility enum sent member names
  ("PUBLIC") to Postgres instead of lowercase values, breaking both GET
  and POST /api/worlds/ for any real query
- backend: fix WorldResponse.created_at typed as str instead of datetime,
  causing a second 500 on GET once the enum bug was fixed
- add smoke_test_world_list.gd: headless scene-level smoke test that
  registers a user, instantiates the real scene, and confirms world cards
  render from live backend data (not just an API-level check)
This commit is contained in:
2026-08-19 21:57:39 +00:00
parent 2ba6bc6b9f
commit b3227f5b78
7 changed files with 414 additions and 25 deletions
+6 -6
View File
@@ -10,8 +10,8 @@ extends Control
@onready var world_list: VBoxContainer = $VBoxContainer/ScrollContainer/WorldList
@onready var loading_label: Label = $VBoxContainer/LoadingLabel
@onready var error_label: Label = $VBoxContainer/ErrorLabel
@onready var refresh_button: Button = $VBoxContainer/RefreshButton
@onready var back_button: Button = $VBoxContainer/BackButton
@onready var refresh_button: Button = $VBoxContainer/HeaderHBox/RefreshButton
@onready var back_button: Button = $VBoxContainer/HeaderHBox/BackButton
@onready var empty_label: Label = $VBoxContainer/EmptyLabel
@@ -91,7 +91,7 @@ func _create_world_card(world_dict: Dictionary) -> Control:
var card := VBoxContainer.new()
card.size_flags_horizontal = Control.SIZE_FILL
card.custom_minimum_size = Vector2(0, 80)
card.theme_override_constants/separation = 4
card.add_theme_constant_override("separation", 4)
var name_label := Label.new()
name_label.text = world_dict.get("name", "Unnamed World")
@@ -101,7 +101,7 @@ func _create_world_card(world_dict: Dictionary) -> Control:
name_label.add_theme_font_size_override("font_size", 18)
var desc_label := Label.new()
var description := world_dict.get("description", "")
var description: String = str(world_dict.get("description", ""))
desc_label.text = description if description != "" else "No description."
desc_label.autowrap_mode = TextServer.AUTOWRAP_WORD
desc_label.size_flags_horizontal = Control.SIZE_FILL
@@ -110,8 +110,8 @@ func _create_world_card(world_dict: Dictionary) -> Control:
desc_label.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7, 1.0))
var meta_label := Label.new()
var visibility := world_dict.get("visibility", "public")
var created := world_dict.get("created_at", "")
var visibility: String = str(world_dict.get("visibility", "public"))
var created: String = str(world_dict.get("created_at", ""))
meta_label.text = "Visibility: %s%s" % [visibility, " | Created: " + created if created != "" else ""]
meta_label.autowrap_mode = TextServer.AUTOWRAP_WORD
meta_label.size_flags_horizontal = Control.SIZE_FILL