Upload files to "Modules"
This commit is contained in:
@ -7,143 +7,146 @@ GLOBAL_TOTAL_PROGRESS = {"completed": 0, "total": 0} # Tracks progress across a
|
|||||||
GLOBAL_HIGHLIGHTS = {} # Tracks highlighted actions
|
GLOBAL_HIGHLIGHTS = {} # Tracks highlighted actions
|
||||||
|
|
||||||
|
|
||||||
def build_submenu(menu_title, actions, module=None):
|
def build_submenu(menu_title, actions=None, module=None):
|
||||||
"""
|
"""
|
||||||
Builds a submenu and tracks progress across all nested submenus.
|
Builds a submenu dynamically by extracting functions from the given module,
|
||||||
Automatically adds an 'All' option to execute all actions.
|
or using a provided `actions` dictionary for pre-defined submenus.
|
||||||
|
Includes an `[ALL]` option to execute all functions or submenus on the page.
|
||||||
|
Allows actions to be unmarked and highlighted.
|
||||||
"""
|
"""
|
||||||
# Initialize global action status for this submenu if not already set
|
if not actions and not module:
|
||||||
|
raise ValueError("No module or actions provided to extract submenu items.")
|
||||||
|
|
||||||
|
# If actions are not provided, dynamically extract from the module
|
||||||
|
if not actions:
|
||||||
|
actions = {
|
||||||
|
str(idx + 1): {
|
||||||
|
"description": func.__name__.replace("_", " ").title(),
|
||||||
|
"function": func,
|
||||||
|
}
|
||||||
|
for idx, (name, func) in enumerate(module.items())
|
||||||
|
if (
|
||||||
|
callable(func)
|
||||||
|
and func.__module__ == module["__name__"] # Ensure the function is from this module
|
||||||
|
and "submenu" not in func.__name__ # Exclude functions with 'submenu' in their name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reassign sequential numbering starting at 1
|
||||||
|
numbered_actions = {str(idx + 1): action for idx, action in enumerate(actions.values())}
|
||||||
|
|
||||||
|
# Add the ALL option with key "ALL"
|
||||||
|
numbered_actions["ALL"] = {
|
||||||
|
"description": f"Run All {menu_title}",
|
||||||
|
"function": lambda: run_all_actions(numbered_actions, module, GLOBAL_ACTION_STATUS[menu_title]),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize global action status and highlights for this submenu
|
||||||
if menu_title not in GLOBAL_ACTION_STATUS:
|
if menu_title not in GLOBAL_ACTION_STATUS:
|
||||||
GLOBAL_ACTION_STATUS[menu_title] = {key: False for key in actions} # False means not completed
|
GLOBAL_ACTION_STATUS[menu_title] = {key: False for key in numbered_actions}
|
||||||
GLOBAL_HIGHLIGHTS[menu_title] = {key: False for key in actions} # False means not highlighted
|
GLOBAL_TOTAL_PROGRESS["total"] += len(numbered_actions) - 1 # Exclude the ALL option from the progress count
|
||||||
|
|
||||||
# Update global total progress for tracking across all menus
|
if menu_title not in GLOBAL_HIGHLIGHTS:
|
||||||
GLOBAL_TOTAL_PROGRESS["total"] += len(actions)
|
GLOBAL_HIGHLIGHTS[menu_title] = {key: False for key in numbered_actions}
|
||||||
|
|
||||||
# Access the action status and highlight status for this specific submenu
|
|
||||||
action_status = GLOBAL_ACTION_STATUS[menu_title]
|
action_status = GLOBAL_ACTION_STATUS[menu_title]
|
||||||
highlight_status = GLOBAL_HIGHLIGHTS[menu_title]
|
highlight_status = GLOBAL_HIGHLIGHTS[menu_title]
|
||||||
|
|
||||||
# Dynamically add "All" option
|
|
||||||
actions["all"] = {
|
|
||||||
"description": "Run All",
|
|
||||||
"function": lambda: run_all_actions(actions, module, action_status),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure the "all" option is in the dictionaries
|
|
||||||
if "all" not in action_status:
|
|
||||||
action_status["all"] = False
|
|
||||||
if "all" not in highlight_status:
|
|
||||||
highlight_status["all"] = False
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
# Check if all individual actions are complete; if so, mark "ALL" as complete
|
||||||
|
action_status["ALL"] = all(status for key, status in action_status.items() if key != "ALL")
|
||||||
|
|
||||||
clear_screen()
|
clear_screen()
|
||||||
header() # Call the header without arguments
|
header() # Display global app header
|
||||||
print("=====================================")
|
|
||||||
|
print("=" * 70)
|
||||||
print(f" {menu_title} Menu ")
|
print(f" {menu_title} Menu ")
|
||||||
print("=====================================\n")
|
print("=" * 70, "\n")
|
||||||
|
|
||||||
# Display global progress only (not specific to this submenu)
|
for key, action in numbered_actions.items():
|
||||||
global_completed = GLOBAL_TOTAL_PROGRESS["completed"]
|
# Determine the status symbol with color
|
||||||
global_total = GLOBAL_TOTAL_PROGRESS["total"]
|
status = f"{Fore.GREEN}✔️ " if action_status[key] else f"❌"
|
||||||
print(f"Global Progress: {global_completed}/{global_total} tasks completed\n")
|
# Highlight the key and description based on highlight status
|
||||||
|
if key == "ALL":
|
||||||
# Display menu options with status, progress, and highlighting
|
print(f"{Fore.BLUE}[{key}]{Style.RESET_ALL} {status} {action['description']}")
|
||||||
for key, action in actions.items():
|
elif highlight_status[key]:
|
||||||
if key == "all": # Highlight the "All" option in blue
|
print(f"{Style.RESET_ALL}[{key}] {Fore.YELLOW}💡 {action['description']}{Style.RESET_ALL}")
|
||||||
print(f"\033[94m[{key.upper()}] {action['description']}\033[0m")
|
|
||||||
else:
|
else:
|
||||||
# Check the status and highlight of the submenu or action
|
print(f"{Style.RESET_ALL}[{key}] {status} {action['description']}")
|
||||||
if "submenu" in action:
|
|
||||||
submenu_completed = is_submenu_complete(action["submenu"])
|
|
||||||
status = "✔️" if submenu_completed else "❌"
|
|
||||||
else:
|
|
||||||
status = "✔️ " if action_status[key] else "❌"
|
|
||||||
|
|
||||||
if highlight_status[key]: # Highlight in yellow if flagged
|
|
||||||
print(f"\033[93m[{key}] {status} {action['description']}\033[0m")
|
|
||||||
else:
|
|
||||||
print(f"[{key}] {status} {action['description']}")
|
|
||||||
print("[0] Return to Main Menu")
|
print("[0] Return to Main Menu")
|
||||||
print("[q] EXIT\n")
|
print("[q] EXIT\n")
|
||||||
|
|
||||||
# Get user choice
|
# Get user choice
|
||||||
choice = input("Enter your choice: ").strip().lower()
|
choice = input("Enter your choice: ").strip().upper()
|
||||||
|
|
||||||
# Handle highlighting
|
# Handle highlighting (toggle with "!")
|
||||||
if choice.endswith("!") and choice[:-1] in actions:
|
if choice.endswith("!") and choice[:-1] in numbered_actions:
|
||||||
key_to_toggle = choice[:-1]
|
key_to_toggle = choice[:-1]
|
||||||
highlight_status[key_to_toggle] = not highlight_status[key_to_toggle]
|
highlight_status[key_to_toggle] = not highlight_status[key_to_toggle]
|
||||||
if highlight_status[key_to_toggle]:
|
if highlight_status[key_to_toggle]:
|
||||||
print(f"Action [{key_to_toggle}] has been highlighted.")
|
print(f"{Fore.YELLOW}Action [{key_to_toggle}] has been highlighted.")
|
||||||
else:
|
else:
|
||||||
print(f"Highlight removed from action [{key_to_toggle}].")
|
print(f"{Fore.YELLOW}Highlight removed from action [{key_to_toggle}].")
|
||||||
input("Press Enter to continue...")
|
input("Press Enter to continue...")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Handle unchecking of actions
|
# Handle unchecking of actions (with "-")
|
||||||
if choice.startswith("-") and choice[1:] in actions:
|
if choice.startswith("-") and choice[1:] in numbered_actions:
|
||||||
key_to_uncheck = choice[1:]
|
key_to_uncheck = choice[1:]
|
||||||
if action_status[key_to_uncheck]:
|
if action_status[key_to_uncheck]:
|
||||||
action_status[key_to_uncheck] = False
|
action_status[key_to_uncheck] = False
|
||||||
GLOBAL_TOTAL_PROGRESS["completed"] -= 1
|
GLOBAL_TOTAL_PROGRESS["completed"] -= 1
|
||||||
print(f"Unchecked action [{key_to_uncheck}]")
|
print(f"{Fore.RED}Unchecked action [{key_to_uncheck}].")
|
||||||
else:
|
else:
|
||||||
print(f"Action [{key_to_uncheck}] was not completed.")
|
print(f"{Fore.RED}Action [{key_to_uncheck}] was already unchecked.")
|
||||||
input("Press Enter to continue...")
|
input("Press Enter to continue...")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Handle menu choices
|
if choice in numbered_actions:
|
||||||
if choice in actions:
|
if "function" in numbered_actions[choice]:
|
||||||
if choice == "all":
|
# Call the action function
|
||||||
run_all_actions(actions, module, action_status)
|
numbered_actions[choice]["function"]()
|
||||||
action_status["all"] = True # Mark the "All" option as completed
|
if choice != "ALL" and not action_status[choice]: # Exclude ALL from progress tracking here
|
||||||
elif "submenu" in actions[choice]: # Navigate to nested submenu
|
action_status[choice] = True
|
||||||
actions[choice]["submenu"]()
|
|
||||||
# After returning, check if all nested submenu items are done
|
|
||||||
if is_submenu_complete(actions[choice]["submenu"]):
|
|
||||||
if not action_status[choice]:
|
|
||||||
action_status[choice] = True # Mark this submenu as complete
|
|
||||||
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
|
||||||
elif "function" in actions[choice]: # Execute the associated function
|
|
||||||
actions[choice]["function"]()
|
|
||||||
if not action_status[choice]:
|
|
||||||
action_status[choice] = True # Mark the action as completed
|
|
||||||
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
||||||
|
elif "submenu" in numbered_actions[choice]:
|
||||||
# Propagate status updates to the parent menu
|
# Call the nested submenu
|
||||||
propagate_status_to_parent(menu_title)
|
numbered_actions[choice]["submenu"]()
|
||||||
|
if is_submenu_complete(numbered_actions[choice]["submenu"]):
|
||||||
|
if not action_status[choice]:
|
||||||
|
action_status[choice] = True
|
||||||
|
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
||||||
elif choice == "0":
|
elif choice == "0":
|
||||||
print("Returning to main menu...")
|
|
||||||
break
|
break
|
||||||
elif choice in ["q", "exit", "quit"]:
|
elif choice in ["Q", "EXIT", "QUIT"]:
|
||||||
print("Logging out...")
|
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
print("Invalid choice. Please try again.")
|
print(f"{Fore.RED}Invalid choice. Press Enter to continue...")
|
||||||
input("Press Enter to continue...")
|
input()
|
||||||
|
|
||||||
|
|
||||||
# Propagate parent status again after menu completion
|
|
||||||
propagate_status_to_parent(menu_title)
|
|
||||||
|
|
||||||
|
|
||||||
def run_all_actions(actions, module, action_status):
|
def run_all_actions(actions, module, action_status):
|
||||||
"""
|
"""
|
||||||
Executes all actions in the submenu sequentially.
|
Executes all actions in the submenu sequentially, excluding the "ALL" option itself.
|
||||||
"""
|
"""
|
||||||
for key, action in actions.items():
|
for key, action in actions.items():
|
||||||
if key != "all": # Skip the "All" option itself
|
if action["description"].startswith("Run All"): # Skip the "ALL" option
|
||||||
if "function" in action:
|
continue
|
||||||
|
|
||||||
|
if "function" in action:
|
||||||
|
if not action_status[key]:
|
||||||
|
action["function"]()
|
||||||
|
action_status[key] = True
|
||||||
|
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
||||||
|
elif "submenu" in action: # Recursively handle submenus
|
||||||
|
actions[key]["submenu"]()
|
||||||
|
if is_submenu_complete(actions[key]["submenu"]):
|
||||||
if not action_status[key]:
|
if not action_status[key]:
|
||||||
action["function"]()
|
|
||||||
action_status[key] = True
|
action_status[key] = True
|
||||||
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
||||||
elif "submenu" in action: # Recursively handle submenus
|
|
||||||
actions[key]["submenu"]()
|
|
||||||
if is_submenu_complete(actions[key]["submenu"]):
|
|
||||||
if not action_status[key]:
|
|
||||||
action_status[key] = True
|
|
||||||
GLOBAL_TOTAL_PROGRESS["completed"] += 1
|
|
||||||
|
|
||||||
|
|
||||||
def is_submenu_complete(submenu_function):
|
def is_submenu_complete(submenu_function):
|
||||||
|
Reference in New Issue
Block a user