broadfield-dev commited on
Commit
3af898b
·
verified ·
1 Parent(s): 4e11156

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -49
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import gradio as gr
2
  import re
3
  import json
@@ -98,7 +100,7 @@ def escape_html_for_markdown(text):
98
  return text.replace("&", "&").replace("<", "<").replace(">", ">")
99
 
100
  def _infer_lang_from_filename(filename):
101
- if not filename: return "text" # Changed from "plaintext" to "text" for gr.Code compatibility
102
  if '.' in filename:
103
  ext = filename.split('.')[-1].lower()
104
  mapping = {
@@ -110,17 +112,17 @@ def _infer_lang_from_filename(filename):
110
  'c': 'c', 'h': 'c', 'cpp': 'cpp', 'hpp': 'cpp', 'cs': 'csharp', 'java': 'java',
111
  'rb': 'ruby', 'php': 'php', 'go': 'go', 'rs': 'rust', 'swift': 'swift', 'kt': 'kotlin', 'kts': 'kotlin',
112
  'sql': 'sql', 'dockerfile': 'docker', 'tf': 'terraform', 'hcl': 'terraform',
113
- 'txt': 'text', 'log': 'text', 'ini': 'ini', 'conf': 'text', 'cfg': 'text', # Changed plaintext to text
114
- 'csv': 'text', 'tsv': 'text', 'err': 'text', # Changed plaintext to text
115
- '.env': 'text', '.gitignore': 'text', '.npmrc': 'text', '.gitattributes': 'text', # Changed plaintext to text
116
  'makefile': 'makefile',
117
  }
118
- return mapping.get(ext, "text") # Changed default to text
119
  base_filename = os.path.basename(filename)
120
  if base_filename == 'Dockerfile': return 'docker'
121
  if base_filename == 'Makefile': return 'makefile'
122
- if base_filename.startswith('.'): return 'text' # Changed plaintext to text
123
- return "text" # Changed default to text
124
 
125
  def _clean_filename(filename_line_content):
126
  text = filename_line_content.strip()
@@ -141,7 +143,7 @@ def _parse_and_update_state_cache(latest_bot_message_content, current_files_stat
141
 
142
  structure_match = structure_pattern.search(content)
143
  if structure_match:
144
- structure_block_state = {"filename": "File Structure (from AI)", "language": structure_match.group("struct_lang") or "text", "code": structure_match.group("structure_code").strip(), "is_binary": False, "is_structure_block": True} # Changed plaintext to text
145
 
146
  current_message_proposed_filenames = []
147
  for match in file_pattern.finditer(content):
@@ -200,7 +202,7 @@ def _export_selected_logic(selected_filenames, space_line_name_for_md, parsed_bl
200
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
201
  output_lines.append(content)
202
  else:
203
- lang = block.get('language', 'text') or 'text' # Changed plaintext to text
204
  output_lines.extend([f"{bbb}{lang}", content, bbb])
205
  output_lines.append("")
206
  exported_content_count += 1
@@ -257,7 +259,7 @@ def _generate_ui_outputs_from_cache(owner, space_name):
257
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
258
  preview_md_lines.append(f"\n`{escape_html_for_markdown(content.strip())}`\n")
259
  else:
260
- lang = block.get('language', 'text') or 'text' # Changed plaintext to text
261
  preview_md_lines.append(f"\n{bbb}{lang}\n{content.strip()}\n{bbb}\n")
262
  preview_md_val = "\n".join(preview_md_lines)
263
 
@@ -593,12 +595,21 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
593
  global parsed_code_blocks_state_cache
594
 
595
  _status = "Applying changes..."
 
596
  yield _status, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="*Applying changes...*")
597
- # Explicitly yield None for the other 15 outputs initially
598
- yield None, None, None, None, None, None, None, None, None, None, None, None, None, None, None # Ensure 16 None values
 
599
 
600
  if not changeset:
601
- return "No changes to apply.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="No changes were staged.")
 
 
 
 
 
 
 
602
 
603
  first_action = changeset[0] if changeset else None
604
  is_exclusive_duplicate = first_action and first_action.get('type') == 'DUPLICATE_SPACE'
@@ -615,8 +626,10 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
615
  private=change.get("private", False)
616
  )
617
  _status_reload = f"{status_message} | Attempting to load the new Space [{change['target_repo_id']}]..."
 
618
  yield gr.update(value=_status_reload), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
619
 
 
620
  target_repo_id = change['target_repo_id']
621
  new_owner, new_space_name = target_repo_id.split('/', 1) if '/' in target_repo_id else (None, target_repo_id)
622
 
@@ -664,18 +677,20 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
664
 
665
  runtime_status_md = handle_refresh_space_status(hf_api_key, new_owner, new_space_name)
666
 
 
667
  yield (
668
- gr.update(value=final_overall_status), gr.update(value=_formatted), gr.update(value=_detected), _download,
669
- gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
670
- [], gr.update(value="*No changes proposed.*"),
671
- owner_update, space_update, file_browser_update, iframe_update,
672
- gr.update(value=runtime_status_md)
673
  )
674
 
675
  else:
676
  reload_error = "Cannot load new Space state: Owner or Space Name missing after duplication."
677
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
678
  final_overall_status = status_message + f" | Reload Status: {reload_error}"
 
679
  yield (
680
  gr.update(value=final_overall_status), gr.update(value=_formatted), gr.update(value=_detected), _download,
681
  gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
@@ -705,10 +720,18 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
705
  if not delete_repo_id_target or delete_repo_id_target != current_repo_id:
706
  final_overall_status = f"DELETE_SPACE Error: Action blocked. Cannot delete '{delete_repo_id_target}'. Only deletion of the currently loaded space ('{current_repo_id}') is permitted via AI action."
707
  print(f"Blocked DELETE_SPACE action via confirm: requested '{delete_repo_id_target}', current '{current_repo_id}'.")
 
 
 
 
 
 
 
708
  else:
709
  status_message = build_logic_delete_space(hf_api_key, delete_owner, delete_space)
710
  final_overall_status = status_message
711
  if "Successfully" in status_message:
 
712
  parsed_code_blocks_state_cache = []
713
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
714
  owner_update = gr.update(value="")
@@ -722,7 +745,7 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
722
  space_update = gr.update()
723
  file_browser_update = gr.update()
724
  iframe_update = gr.update()
725
- runtime_status_update = handle_refresh_space_status(hf_api_key, owner_name, space_name)
726
 
727
 
728
  cleared_changeset = []
@@ -883,14 +906,15 @@ def update_models_dropdown(provider_select):
883
  def handle_detect_user_and_list_spaces(hf_api_key_ui):
884
  _status = "Detecting user from token..."
885
  # Yield initial state: update status, clear owner/space fields, clear list display, clear duplicate fields
886
- yield (gr.update(value=_status), gr.update(value=""), gr.update(value=""), gr.update(value="*Listing spaces...*"), gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value=""), gr.update(value=""), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
 
887
 
888
 
889
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
890
  if token_err:
891
  _status = f"Detection Error: {token_err}"
892
  # Yield error status, keep fields cleared, update list display error
893
- yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value="*Could not list spaces due to token error.*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
894
  return
895
 
896
  try:
@@ -907,7 +931,8 @@ def handle_detect_user_and_list_spaces(hf_api_key_ui):
907
  else:
908
  list_spaces_update = gr.update(value=list_spaces_md)
909
 
910
- yield (gr.update(value=_status), owner_update, gr.update(value=""), list_spaces_update, gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value=""), gr.update(value=""), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
 
911
 
912
 
913
  except Exception as e:
@@ -915,7 +940,8 @@ def handle_detect_user_and_list_spaces(hf_api_key_ui):
915
  print(f"Error in handle_detect_user: {e}")
916
  import traceback
917
  traceback.print_exc()
918
- yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value="*Could not list spaces due to user detection error.*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
 
919
 
920
 
921
  def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
@@ -926,56 +952,64 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
926
  _changeset_clear = []
927
  _changeset_summary_clear = "*No changes proposed.*"
928
  _confirm_ui_hidden = gr.update(visible=False)
929
- _list_spaces_display_placeholder = "*List of spaces will appear here.*"
930
  _target_owner_clear, _target_space_clear, _target_private_clear = gr.update(value=""), gr.update(value=""), gr.update(value=False)
931
 
932
 
 
933
  yield (
934
  gr.update(value=_formatted_md_val), gr.update(value=_detected_preview_val), gr.update(value=_status_val), _file_browser_update,
935
  gr.update(value=ui_owner_name), gr.update(value=ui_space_name),
936
  _iframe_html_update, _download_btn_update, gr.update(value=_build_status_clear),
937
  gr.update(value=_edit_status_clear), gr.update(value=_runtime_status_clear),
938
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
939
- gr.update(value=_list_spaces_display_placeholder), _target_owner_clear, _target_space_clear, _target_private_clear
940
  )
941
 
942
  owner_to_use = ui_owner_name
943
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
944
  if token_err:
945
  _status_val = f"Load Error: {token_err}"
946
- yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
 
947
  return
948
  if not owner_to_use:
949
  try:
950
  user_info = build_logic_whoami(token=token)
951
  owner_to_use = user_info.get('name')
952
  if not owner_to_use: raise Exception("Could not find user name from token.")
953
- yield gr.update(value=owner_to_use), gr.update(value=f"Loading Space: {owner_to_use}/{ui_space_name} (Auto-detected owner)..."), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
954
  except Exception as e:
955
  _status_val = f"Load Error: Error auto-detecting owner: {e}"
956
- yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
 
957
  return
958
 
959
  if not owner_to_use or not ui_space_name:
960
  _status_val = "Load Error: Owner and Space Name are required."
961
- yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
 
962
  return
963
 
964
  sdk, file_list, err = get_space_repository_info(hf_api_key_ui, ui_space_name, owner_to_use)
965
 
966
- yield gr.update(value=owner_to_use), gr.update(value=ui_space_name), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
 
967
 
968
  if err:
969
  _status_val = f"Load Error: {err}"
970
  parsed_code_blocks_state_cache = []
971
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(owner_to_use, ui_space_name)
 
972
  yield (
973
  gr.update(value=_formatted), gr.update(value=_detected), gr.update(value=_status_val),
974
- gr.update(visible=False, choices=[], value=None),
975
- gr.update(), gr.update(),
976
- gr.update(value=None, visible=False),
977
- _download, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
978
- gr.update(value=_list_spaces_display_placeholder), gr.update(value=""), gr.update(value=""), gr.update(value=False)
979
  )
980
  return
981
 
@@ -1004,13 +1038,16 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
1004
 
1005
  runtime_status_md = handle_refresh_space_status(hf_api_key_ui, owner_to_use, ui_space_name)
1006
 
 
1007
  yield (
1008
- gr.update(value=_formatted), gr.update(value=_detected), gr.update(value=_status_val),
1009
- file_browser_update,
1010
- gr.update(), gr.update(),
1011
- iframe_update,
1012
- _download, gr.update(), gr.update(), gr.update(value=runtime_status_md), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
1013
- gr.update(value=_list_spaces_display_placeholder), gr.update(value=""), gr.update(value=""), gr.update(value=False)
 
 
1014
  )
1015
 
1016
  def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, space_sdk_ui, is_private_ui, formatted_markdown_content):
@@ -1021,10 +1058,10 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1021
  _changeset_summary_clear = "*Manual build initiated, changes plan cleared.*"
1022
  _confirm_ui_hidden = gr.update(visible=False)
1023
 
 
1024
  yield (gr.update(value=_build_status), _iframe_html, _file_browser_update, gr.update(value=ui_owner_name_part), gr.update(value=ui_space_name_part),
1025
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
1026
- gr.update(), gr.update(), gr.update(), gr.update())
1027
-
1028
 
1029
  if not ui_space_name_part or "/" in ui_space_name_part:
1030
  _build_status = f"Build Error: Invalid Space Name '{ui_space_name_part}'."
@@ -1129,11 +1166,11 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1129
 
1130
  def handle_load_file_for_editing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path):
1131
  if not selected_file_path:
1132
- return "", "Select a file.", "", gr.update(language="text") # Changed plaintext to text
1133
 
1134
  content, err = get_space_file_content(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path)
1135
  if err:
1136
- return "", f"Load Error: {err}", "", gr.update(language="text") # Changed plaintext to text
1137
 
1138
  lang = _infer_lang_from_filename(selected_file_path)
1139
  commit_msg = f"Update {selected_file_path}"
@@ -1176,9 +1213,9 @@ def handle_commit_file_changes(hf_api_key_ui, ui_space_name_part, ui_owner_name_
1176
 
1177
  def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path):
1178
  if not ui_owner_name_part or not ui_space_name_part:
1179
- return "Delete Error: Cannot delete file. Please load a space first.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update() # Changed plaintext to text
1180
  if not file_to_delete_path:
1181
- return "Delete Error: No file selected to delete.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update() # Changed plaintext to text
1182
 
1183
  status_msg = build_logic_delete_space_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path)
1184
 
@@ -1192,7 +1229,7 @@ def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, fi
1192
  parsed_code_blocks_state_cache = [b for b in parsed_code_blocks_state_cache if b["filename"] != file_to_delete_path]
1193
  file_content_editor_update = gr.update(value="")
1194
  commit_message_update = gr.update(value="")
1195
- editor_lang_update = gr.update(language="text") # Changed plaintext to text
1196
  file_list, _ = list_space_files_for_browsing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part)
1197
  file_browser_update = gr.update(choices=sorted(file_list or []), value=None)
1198
 
@@ -1290,7 +1327,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1290
  return "Duplicate Error: Target Owner and Target Space Name are required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1291
  if "/" in target_space_name:
1292
  return "Duplicate Error: Target Space Name should not contain '/'. Use Target Owner field for the owner part.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1293
- global parsed_code_blocks_state_cache
1294
 
1295
  source_repo_id = f"{source_owner}/{source_space_name}"
1296
  target_repo_id = f"{target_owner}/{target_space_name}"
@@ -1312,6 +1349,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1312
 
1313
  if err_list:
1314
  reload_error = f"Error reloading file list after duplication: {err_list}"
 
1315
  parsed_code_blocks_state_cache = []
1316
  _file_browser_update = gr.update(visible=False, choices=[], value=None)
1317
  _iframe_html_update = gr.update(value=None, visible=False)
@@ -1323,6 +1361,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1323
  is_binary = lang == "binary" or (err_get is not None)
1324
  code = f"[Error loading content: {err_get}]" if err_get else (content or "")
1325
  loaded_files.append({"filename": file_path, "code": code, "language": lang, "is_binary": is_binary, "is_structure_block": False})
 
1326
  parsed_code_blocks_state_cache = loaded_files
1327
 
1328
  _file_browser_update = gr.update(visible=True, choices=sorted([f["filename"] for f in parsed_code_blocks_state_cache if not f.get("is_structure_block")] or []), value=None)
 
1
+ ### File: app.py
2
+ ```python
3
  import gradio as gr
4
  import re
5
  import json
 
100
  return text.replace("&", "&").replace("<", "<").replace(">", ">")
101
 
102
  def _infer_lang_from_filename(filename):
103
+ if not filename: return "text"
104
  if '.' in filename:
105
  ext = filename.split('.')[-1].lower()
106
  mapping = {
 
112
  'c': 'c', 'h': 'c', 'cpp': 'cpp', 'hpp': 'cpp', 'cs': 'csharp', 'java': 'java',
113
  'rb': 'ruby', 'php': 'php', 'go': 'go', 'rs': 'rust', 'swift': 'swift', 'kt': 'kotlin', 'kts': 'kotlin',
114
  'sql': 'sql', 'dockerfile': 'docker', 'tf': 'terraform', 'hcl': 'terraform',
115
+ 'txt': 'text', 'log': 'text', 'ini': 'ini', 'conf': 'text', 'cfg': 'text',
116
+ 'csv': 'text', 'tsv': 'text', 'err': 'text',
117
+ '.env': 'text', '.gitignore': 'text', '.npmrc': 'text', '.gitattributes': 'text',
118
  'makefile': 'makefile',
119
  }
120
+ return mapping.get(ext, "text")
121
  base_filename = os.path.basename(filename)
122
  if base_filename == 'Dockerfile': return 'docker'
123
  if base_filename == 'Makefile': return 'makefile'
124
+ if base_filename.startswith('.'): return 'text'
125
+ return "text"
126
 
127
  def _clean_filename(filename_line_content):
128
  text = filename_line_content.strip()
 
143
 
144
  structure_match = structure_pattern.search(content)
145
  if structure_match:
146
+ structure_block_state = {"filename": "File Structure (from AI)", "language": structure_match.group("struct_lang") or "text", "code": structure_match.group("structure_code").strip(), "is_binary": False, "is_structure_block": True}
147
 
148
  current_message_proposed_filenames = []
149
  for match in file_pattern.finditer(content):
 
202
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
203
  output_lines.append(content)
204
  else:
205
+ lang = block.get('language', 'text') or 'text'
206
  output_lines.extend([f"{bbb}{lang}", content, bbb])
207
  output_lines.append("")
208
  exported_content_count += 1
 
259
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
260
  preview_md_lines.append(f"\n`{escape_html_for_markdown(content.strip())}`\n")
261
  else:
262
+ lang = block.get('language', 'text') or 'text'
263
  preview_md_lines.append(f"\n{bbb}{lang}\n{content.strip()}\n{bbb}\n")
264
  preview_md_val = "\n".join(preview_md_lines)
265
 
 
595
  global parsed_code_blocks_state_cache
596
 
597
  _status = "Applying changes..."
598
+ # Yield initial status, hide confirm UI, clear summary
599
  yield _status, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="*Applying changes...*")
600
+ # Yield None for the other 15 outputs that are part of this generator's outputs list
601
+ yield None, None, None, None, None, None, None, None, None, None, None, None, None, None, None # 15 None values
602
+
603
 
604
  if not changeset:
605
+ # This case should be prevented by hiding the button, but safety first
606
+ yield (
607
+ "No changes to apply.", # status_output
608
+ gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="No changes were staged."), # Hide confirm UI, clear summary
609
+ None, None, None, None, None, None, None, None, None, None, None # 15 None values
610
+ )
611
+ return
612
+
613
 
614
  first_action = changeset[0] if changeset else None
615
  is_exclusive_duplicate = first_action and first_action.get('type') == 'DUPLICATE_SPACE'
 
626
  private=change.get("private", False)
627
  )
628
  _status_reload = f"{status_message} | Attempting to load the new Space [{change['target_repo_id']}]..."
629
+ # Yield status update only
630
  yield gr.update(value=_status_reload), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
631
 
632
+
633
  target_repo_id = change['target_repo_id']
634
  new_owner, new_space_name = target_repo_id.split('/', 1) if '/' in target_repo_id else (None, target_repo_id)
635
 
 
677
 
678
  runtime_status_md = handle_refresh_space_status(hf_api_key, new_owner, new_space_name)
679
 
680
+ # Final yield after loading the new space
681
  yield (
682
+ gr.update(value=final_overall_status), gr.update(value=_formatted), gr.update(value=_detected), _download, # Status, markdown, preview, download
683
+ gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), # Hide confirm UI
684
+ [], gr.update(value="*No changes proposed.*"), # Clear changeset state and display
685
+ owner_update, space_update, file_browser_update, iframe_update, # Update space/owner fields, file browser, iframe
686
+ gr.update(value=runtime_status_md) # Update runtime status
687
  )
688
 
689
  else:
690
  reload_error = "Cannot load new Space state: Owner or Space Name missing after duplication."
691
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
692
  final_overall_status = status_message + f" | Reload Status: {reload_error}"
693
+ # Keep old UI fields, clear file browser/iframe
694
  yield (
695
  gr.update(value=final_overall_status), gr.update(value=_formatted), gr.update(value=_detected), _download,
696
  gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
 
720
  if not delete_repo_id_target or delete_repo_id_target != current_repo_id:
721
  final_overall_status = f"DELETE_SPACE Error: Action blocked. Cannot delete '{delete_repo_id_target}'. Only deletion of the currently loaded space ('{current_repo_id}') is permitted via AI action."
722
  print(f"Blocked DELETE_SPACE action via confirm: requested '{delete_repo_id_target}', current '{current_repo_id}'.")
723
+ _formatted, _detected, _download = _generate_ui_outputs_from_cache(owner_name, space_name)
724
+ owner_update = gr.update()
725
+ space_update = gr.update()
726
+ file_browser_update = gr.update()
727
+ iframe_update = gr.update()
728
+ runtime_status_update = handle_refresh_space_status(hf_api_key, owner_name, space_name) # Refresh status after failed delete attempt
729
+
730
  else:
731
  status_message = build_logic_delete_space(hf_api_key, delete_owner, delete_space)
732
  final_overall_status = status_message
733
  if "Successfully" in status_message:
734
+ global parsed_code_blocks_state_cache
735
  parsed_code_blocks_state_cache = []
736
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
737
  owner_update = gr.update(value="")
 
745
  space_update = gr.update()
746
  file_browser_update = gr.update()
747
  iframe_update = gr.update()
748
+ runtime_status_update = handle_refresh_space_status(hf_api_key, owner_name, space_name) # Refresh status after failed delete attempt
749
 
750
 
751
  cleared_changeset = []
 
906
  def handle_detect_user_and_list_spaces(hf_api_key_ui):
907
  _status = "Detecting user from token..."
908
  # Yield initial state: update status, clear owner/space fields, clear list display, clear duplicate fields
909
+ # outputs list: [status_output, owner_name_input, space_name_input, list_spaces_display, file_browser_dropdown, space_iframe_display, formatted_space_output_display, detected_files_display, build_status_display, edit_status_display, space_runtime_status_display, changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button, target_owner_input, target_space_name_input, target_private_checkbox] (19 items)
910
+ yield (gr.update(value=_status), gr.update(value=""), gr.update(value=""), gr.update(value="*Listing spaces...*"), gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value="*Load or create a space to see its definition.*"), gr.update(value="*A preview of the latest file versions will appear here.*"), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
911
 
912
 
913
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
914
  if token_err:
915
  _status = f"Detection Error: {token_err}"
916
  # Yield error status, keep fields cleared, update list display error
917
+ yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value=f"*Could not list spaces due to token error: {token_err}*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
918
  return
919
 
920
  try:
 
931
  else:
932
  list_spaces_update = gr.update(value=list_spaces_md)
933
 
934
+ # Final yield: Update status, owner, list spaces, keep others cleared/defaulted
935
+ yield (gr.update(value=_status), owner_update, gr.update(value=""), list_spaces_update, gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value="*Load or create a space to see its definition.*"), gr.update(value="*A preview of the latest file versions will appear here.*"), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
936
 
937
 
938
  except Exception as e:
 
940
  print(f"Error in handle_detect_user: {e}")
941
  import traceback
942
  traceback.print_exc()
943
+ # Final yield on error: Update status, keep others cleared/defaulted, list spaces error
944
+ yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value=f"*Could not list spaces due to user detection error: {e}*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
945
 
946
 
947
  def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
 
952
  _changeset_clear = []
953
  _changeset_summary_clear = "*No changes proposed.*"
954
  _confirm_ui_hidden = gr.update(visible=False)
955
+ _list_spaces_display_placeholder = gr.update(value="*List of spaces will appear here.*")
956
  _target_owner_clear, _target_space_clear, _target_private_clear = gr.update(value=""), gr.update(value=""), gr.update(value=False)
957
 
958
 
959
+ # outputs list: [formatted_space_output_display, detected_files_preview, status_output, file_browser_dropdown, owner_name_input, space_name_input, space_iframe_display, download_button, build_status_display, edit_status_display, space_runtime_status_display, changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button, list_spaces_display, target_owner_input, target_space_name_input, target_private_checkbox] (20 items)
960
  yield (
961
  gr.update(value=_formatted_md_val), gr.update(value=_detected_preview_val), gr.update(value=_status_val), _file_browser_update,
962
  gr.update(value=ui_owner_name), gr.update(value=ui_space_name),
963
  _iframe_html_update, _download_btn_update, gr.update(value=_build_status_clear),
964
  gr.update(value=_edit_status_clear), gr.update(value=_runtime_status_clear),
965
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
966
+ _list_spaces_display_placeholder, _target_owner_clear, _target_space_clear, _target_private_clear
967
  )
968
 
969
  owner_to_use = ui_owner_name
970
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
971
  if token_err:
972
  _status_val = f"Load Error: {token_err}"
973
+ # Yield only status and keep others as initial state
974
+ yield (gr.update(), gr.update(), gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
975
  return
976
  if not owner_to_use:
977
  try:
978
  user_info = build_logic_whoami(token=token)
979
  owner_to_use = user_info.get('name')
980
  if not owner_to_use: raise Exception("Could not find user name from token.")
981
+ # Yield updated owner and status, keep others as initial state
982
+ yield (gr.update(), gr.update(), gr.update(value=f"Loading Space: {owner_to_use}/{ui_space_name} (Auto-detected owner)..."), gr.update(), gr.update(value=owner_to_use), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
983
  except Exception as e:
984
  _status_val = f"Load Error: Error auto-detecting owner: {e}"
985
+ # Yield only status and keep others as initial state
986
+ yield (gr.update(), gr.update(), gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
987
  return
988
 
989
  if not owner_to_use or not ui_space_name:
990
  _status_val = "Load Error: Owner and Space Name are required."
991
+ # Yield only status and keep others as initial state
992
+ yield (gr.update(), gr.update(), gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
993
  return
994
 
995
  sdk, file_list, err = get_space_repository_info(hf_api_key_ui, ui_space_name, owner_to_use)
996
 
997
+ # Yield updated owner and space textboxes, keep others as initial state
998
+ yield (gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=owner_to_use), gr.update(value=ui_space_name), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
999
+
1000
 
1001
  if err:
1002
  _status_val = f"Load Error: {err}"
1003
  parsed_code_blocks_state_cache = []
1004
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(owner_to_use, ui_space_name)
1005
+ # Yield final state on error
1006
  yield (
1007
  gr.update(value=_formatted), gr.update(value=_detected), gr.update(value=_status_val),
1008
+ gr.update(visible=False, choices=[], value=None), # Clear and hide file browser
1009
+ gr.update(), gr.update(), # Keep owner/space textboxes
1010
+ gr.update(value=None, visible=False), # Hide iframe
1011
+ _download, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), # Build/Edit/Runtime status (from initial clear state), Changeset, Confirm UI
1012
+ gr.update(value="*List of spaces will appear here.*"), gr.update(value=""), gr.update(value=""), gr.update(value=False) # List Spaces and Duplicate fields (from initial clear state)
1013
  )
1014
  return
1015
 
 
1038
 
1039
  runtime_status_md = handle_refresh_space_status(hf_api_key_ui, owner_to_use, ui_space_name)
1040
 
1041
+ # Final yield after success
1042
  yield (
1043
+ gr.update(value=_formatted), gr.update(value=_detected), gr.update(value=_status_val), # Markdown, preview, status
1044
+ file_browser_update, # File browser
1045
+ gr.update(), gr.update(), # Keep owner/space textboxes
1046
+ iframe_update, # Iframe
1047
+ _download, # Download button
1048
+ gr.update(), gr.update(), gr.update(value=runtime_status_md), # Build/Edit status (from initial clear state), Runtime status
1049
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), # Changeset, Confirm UI (from initial clear state)
1050
+ gr.update(value="*List of spaces will appear here.*"), gr.update(value=""), gr.update(value=""), gr.update(value=False) # List Spaces and Duplicate fields (from initial clear state)
1051
  )
1052
 
1053
  def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, space_sdk_ui, is_private_ui, formatted_markdown_content):
 
1058
  _changeset_summary_clear = "*Manual build initiated, changes plan cleared.*"
1059
  _confirm_ui_hidden = gr.update(visible=False)
1060
 
1061
+ # Outputs list: [build_status_display, space_iframe_display, file_browser_dropdown, owner_name_input, space_name_input, changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button, formatted_space_output_display, detected_files_preview, download_button, space_runtime_status_display] (14 items)
1062
  yield (gr.update(value=_build_status), _iframe_html, _file_browser_update, gr.update(value=ui_owner_name_part), gr.update(value=ui_space_name_part),
1063
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
1064
+ gr.update(), gr.update(), gr.update(), gr.update()) # Initial yield
 
1065
 
1066
  if not ui_space_name_part or "/" in ui_space_name_part:
1067
  _build_status = f"Build Error: Invalid Space Name '{ui_space_name_part}'."
 
1166
 
1167
  def handle_load_file_for_editing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path):
1168
  if not selected_file_path:
1169
+ return "", "Select a file.", "", gr.update(language="text")
1170
 
1171
  content, err = get_space_file_content(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path)
1172
  if err:
1173
+ return "", f"Load Error: {err}", "", gr.update(language="text")
1174
 
1175
  lang = _infer_lang_from_filename(selected_file_path)
1176
  commit_msg = f"Update {selected_file_path}"
 
1213
 
1214
  def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path):
1215
  if not ui_owner_name_part or not ui_space_name_part:
1216
+ return "Delete Error: Cannot delete file. Please load a space first.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update()
1217
  if not file_to_delete_path:
1218
+ return "Delete Error: No file selected to delete.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update()
1219
 
1220
  status_msg = build_logic_delete_space_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path)
1221
 
 
1229
  parsed_code_blocks_state_cache = [b for b in parsed_code_blocks_state_cache if b["filename"] != file_to_delete_path]
1230
  file_content_editor_update = gr.update(value="")
1231
  commit_message_update = gr.update(value="")
1232
+ editor_lang_update = gr.update(language="text")
1233
  file_list, _ = list_space_files_for_browsing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part)
1234
  file_browser_update = gr.update(choices=sorted(file_list or []), value=None)
1235
 
 
1327
  return "Duplicate Error: Target Owner and Target Space Name are required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1328
  if "/" in target_space_name:
1329
  return "Duplicate Error: Target Space Name should not contain '/'. Use Target Owner field for the owner part.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1330
+
1331
 
1332
  source_repo_id = f"{source_owner}/{source_space_name}"
1333
  target_repo_id = f"{target_owner}/{target_space_name}"
 
1349
 
1350
  if err_list:
1351
  reload_error = f"Error reloading file list after duplication: {err_list}"
1352
+ global parsed_code_blocks_state_cache
1353
  parsed_code_blocks_state_cache = []
1354
  _file_browser_update = gr.update(visible=False, choices=[], value=None)
1355
  _iframe_html_update = gr.update(value=None, visible=False)
 
1361
  is_binary = lang == "binary" or (err_get is not None)
1362
  code = f"[Error loading content: {err_get}]" if err_get else (content or "")
1363
  loaded_files.append({"filename": file_path, "code": code, "language": lang, "is_binary": is_binary, "is_structure_block": False})
1364
+ global parsed_code_blocks_state_cache
1365
  parsed_code_blocks_state_cache = loaded_files
1366
 
1367
  _file_browser_update = gr.update(visible=True, choices=sorted([f["filename"] for f in parsed_code_blocks_state_cache if not f.get("is_structure_block")] or []), value=None)