From c3c0e8cef54a3c06bc5f44307eefc250059b6bd0 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Tue, 28 Oct 2025 10:50:48 -0400 Subject: [PATCH 1/3] Add profile support to Go Note Go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements multiple profile support allowing quick switching between different GNG configurations. Features: - Save/load named profiles with all settings - Quick shortcuts (:1, :2, :3, :4) for default profiles (roam, work, assistant, guest) - Automatic backup before profile switching - List, view current, and delete profiles - Profile init command to set up defaults Use cases: - Switch between personal/work note-taking systems - Different assistant configurations - Guest mode with safe settings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PROFILES.md | 91 +++++++++++++++++++ gonotego/command_center/commands.py | 1 + gonotego/command_center/profile_commands.py | 89 +++++++++++++++++++ gonotego/settings/profiles.py | 96 +++++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 PROFILES.md create mode 100644 gonotego/command_center/profile_commands.py create mode 100644 gonotego/settings/profiles.py diff --git a/PROFILES.md b/PROFILES.md new file mode 100644 index 0000000..962a312 --- /dev/null +++ b/PROFILES.md @@ -0,0 +1,91 @@ +# Go Note Go Profiles + +Profiles allow you to quickly switch between different Go Note Go configurations. Each profile stores a complete snapshot of all settings. + +## Quick Start + +### Initialize Default Profiles + +First, set up your settings the way you want them, then run: +``` +:profile init +``` + +This creates four default profiles: +- `roam` (shortcut: `:1`) +- `work` (shortcut: `:2`) +- `assistant` (shortcut: `:3`) +- `guest` (shortcut: `:4`) + +### Switch Between Profiles + +Use the numeric shortcuts: +``` +:1 # Switch to roam profile +:2 # Switch to work profile +:3 # Switch to assistant profile +:4 # Switch to guest profile +``` + +Or use the full command: +``` +:profile load roam +``` + +## Commands + +### Save a Profile +``` +:profile save +``` +Saves your current settings as a named profile. + +### Load a Profile +``` +:profile load +``` +Loads all settings from the specified profile. Your current settings are automatically backed up to the `backup` profile before loading. + +### List Profiles +``` +:profile list +``` +Shows all saved profiles. + +### Current Profile +``` +:profile current +``` +Shows which profile is currently active. + +### Delete a Profile +``` +:profile delete +``` +Deletes a saved profile. + +## Example Use Cases + +### Personal vs Work +- Profile 1 (roam): Personal Roam graph with your personal account +- Profile 2 (work): Work Roam graph or different note-taking system + +### Different Assistants +- Profile 3 (assistant): Connected to your personal assistant +- Profile 4 (guest): Safe settings for letting others try your GNG + +### Different Upload Destinations +Switch between different note-taking systems (Roam, RemNote, Notion, etc.) with a single command. + +## How It Works + +- Each profile is stored as a JSON blob in Redis containing all setting values +- When you load a profile, your current settings are automatically backed up +- The `backup` profile always contains your most recent settings before the last profile switch +- Settings include: uploader type, credentials, custom command paths, API keys, etc. + +## Safety + +- Your current settings are always backed up to `backup` before loading a new profile +- The secure_settings.py file is never modified - profiles only affect Redis settings +- You can always revert to your previous settings by running `:profile load backup` diff --git a/gonotego/command_center/commands.py b/gonotego/command_center/commands.py index 8f3ebea..d4b2431 100644 --- a/gonotego/command_center/commands.py +++ b/gonotego/command_center/commands.py @@ -8,6 +8,7 @@ from gonotego.command_center import assistant_commands # noqa: F401 from gonotego.command_center import custom_commands # noqa: F401 from gonotego.command_center import note_commands # noqa: F401 +from gonotego.command_center import profile_commands # noqa: F401 from gonotego.command_center import settings_commands # noqa: F401 from gonotego.command_center import system_commands # noqa: F401 from gonotego.command_center import twitter_commands # noqa: F401 diff --git a/gonotego/command_center/profile_commands.py b/gonotego/command_center/profile_commands.py new file mode 100644 index 0000000..8771926 --- /dev/null +++ b/gonotego/command_center/profile_commands.py @@ -0,0 +1,89 @@ +# Profile commands for switching between Go Note Go configurations. + +from gonotego.command_center import registry +from gonotego.command_center import system_commands +from gonotego.settings import profiles + +register_command = registry.register_command +say = system_commands.say + + +# Predefined profile shortcuts +PROFILE_SHORTCUTS = { + '1': 'roam', + '2': 'work', + '3': 'assistant', + '4': 'guest', +} + + +@register_command('{}') +def load_profile_shortcut(shortcut): + """Load a profile using numeric shortcut (e.g., :1 for roam).""" + if shortcut not in PROFILE_SHORTCUTS: + return # Not a profile shortcut, let other commands handle it + + profile_name = PROFILE_SHORTCUTS[shortcut] + result = profiles.load_profile(profile_name) + + if result is None: + say(f'Profile {profile_name} not found. Creating from current settings.') + profiles.save_profile(profile_name) + say(f'Saved current settings as {profile_name}.') + else: + say(f'Loaded profile: {profile_name}') + + +@register_command('profile save {}') +def save_profile(profile_name): + """Save current settings as a named profile.""" + profiles.save_profile(profile_name) + say(f'Saved profile: {profile_name}') + + +@register_command('profile load {}') +def load_profile(profile_name): + """Load a named profile.""" + result = profiles.load_profile(profile_name) + if result is None: + say(f'Profile not found: {profile_name}') + else: + say(f'Loaded profile: {profile_name}') + + +@register_command('profile list') +def list_profiles(): + """List all saved profiles.""" + profile_names = profiles.list_profiles() + if not profile_names: + say('No profiles saved.') + else: + say(f'Profiles: {", ".join(profile_names)}') + + +@register_command('profile current') +def current_profile(): + """Show the currently active profile.""" + current = profiles.get_current_profile() + if current is None: + say('No profile currently active.') + else: + say(f'Current profile: {current}') + + +@register_command('profile delete {}') +def delete_profile(profile_name): + """Delete a saved profile.""" + profiles.delete_profile(profile_name) + say(f'Deleted profile: {profile_name}') + + +@register_command('profile init') +def init_default_profiles(): + """Initialize default profiles (roam, work, assistant, guest) from current settings.""" + current_settings = profiles.get_all_settings() + + for shortcut, profile_name in PROFILE_SHORTCUTS.items(): + profiles.save_profile(profile_name) + + say('Initialized default profiles: roam, work, assistant, guest') diff --git a/gonotego/settings/profiles.py b/gonotego/settings/profiles.py new file mode 100644 index 0000000..d12fdbb --- /dev/null +++ b/gonotego/settings/profiles.py @@ -0,0 +1,96 @@ +"""Profile management for Go Note Go settings. + +Profiles allow switching between different configurations (roam, work, assistant, guest). +Each profile stores a complete snapshot of all settings. +""" +import json +from gonotego.settings import settings +from gonotego.settings import secure_settings +from gonotego.common import interprocess + +PROFILES_KEY = 'GoNoteGo:profiles' +CURRENT_PROFILE_KEY = 'GoNoteGo:current_profile' +BACKUP_PROFILE_KEY = 'GoNoteGo:backup_profile' + + +def get_redis_key(profile_name): + """Get Redis key for a specific profile.""" + return f'{PROFILES_KEY}:{profile_name}' + + +def get_all_settings(): + """Get all current settings as a dict.""" + settings_dict = {} + # Get all setting names from secure_settings + setting_names = [s for s in dir(secure_settings) if not s.startswith('_')] + for key in setting_names: + settings_dict[key] = settings.get(key) + return settings_dict + + +def save_profile(profile_name): + """Save current settings to a named profile.""" + r = interprocess.get_redis_client() + current_settings = get_all_settings() + settings_json = json.dumps(current_settings) + r.set(get_redis_key(profile_name), settings_json) + return current_settings + + +def load_profile(profile_name): + """Load settings from a named profile. + + 1. Backs up current settings to 'backup' profile + 2. Loads all settings from the specified profile + 3. Sets current profile marker + """ + r = interprocess.get_redis_client() + + # First, backup current settings + save_profile('backup') + + # Load the requested profile + profile_json = r.get(get_redis_key(profile_name)) + if profile_json is None: + return None + + profile_settings = json.loads(profile_json) + + # Clear all current settings and load profile settings + settings.clear_all() + for key, value in profile_settings.items(): + settings.set(key, value) + + # Mark this as the current profile + r.set(CURRENT_PROFILE_KEY, profile_name) + + return profile_settings + + +def get_current_profile(): + """Get the name of the currently active profile.""" + r = interprocess.get_redis_client() + profile_bytes = r.get(CURRENT_PROFILE_KEY) + if profile_bytes is None: + return None + return profile_bytes.decode('utf-8') + + +def list_profiles(): + """List all saved profile names.""" + r = interprocess.get_redis_client() + profile_keys = r.keys(get_redis_key('*')) + profile_names = [] + for key in profile_keys: + key_str = key.decode('utf-8') if isinstance(key, bytes) else key + # Extract profile name from key + if key_str.startswith(f'{PROFILES_KEY}:'): + profile_name = key_str[len(f'{PROFILES_KEY}:'):] + profile_names.append(profile_name) + return sorted(profile_names) + + +def delete_profile(profile_name): + """Delete a saved profile.""" + r = interprocess.get_redis_client() + r.delete(get_redis_key(profile_name)) From 91173c4f36aec4a857e00a694cf7a16b48c394b2 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Tue, 28 Oct 2025 19:57:19 -0400 Subject: [PATCH 2/3] Make profile names and shortcuts user-configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of hardcoding profile names (roam, work, assistant, guest), profiles now store their name and shortcut as metadata. This makes the feature work for any GNG user, not just David-specific configs. Changes: - Profiles now store: {name, shortcut, settings} - Shortcuts mapped dynamically in Redis (GoNoteGo:profile_shortcuts) - New command: `profile save ` to set shortcuts - `profile list` shows shortcuts: "roam (:1)" - Numeric shortcuts (`:1`, `:2`) look up mapping dynamically - Backward compatible with old profile format Example usage: :profile save roam 1 # Save as "roam" with shortcut :1 :1 # Load roam profile :profile list # Shows: roam (:1), work (:2), backup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PROFILES.md | 84 ++++++++++++------- gonotego/command_center/profile_commands.py | 43 ++++------ gonotego/settings/profiles.py | 91 +++++++++++++++++---- 3 files changed, 146 insertions(+), 72 deletions(-) diff --git a/PROFILES.md b/PROFILES.md index 962a312..2fd2927 100644 --- a/PROFILES.md +++ b/PROFILES.md @@ -1,30 +1,27 @@ # Go Note Go Profiles -Profiles allow you to quickly switch between different Go Note Go configurations. Each profile stores a complete snapshot of all settings. +Profiles allow you to quickly switch between different Go Note Go configurations. Each profile stores a complete snapshot of all settings, plus a name and optional numeric shortcut. ## Quick Start -### Initialize Default Profiles +### Create Your First Profile + +Set up your settings the way you want them, then save as a profile with a shortcut: -First, set up your settings the way you want them, then run: ``` -:profile init +:profile save roam 1 ``` -This creates four default profiles: -- `roam` (shortcut: `:1`) -- `work` (shortcut: `:2`) -- `assistant` (shortcut: `:3`) -- `guest` (shortcut: `:4`) +This creates a profile named "roam" with shortcut `:1`. ### Switch Between Profiles -Use the numeric shortcuts: +Use the numeric shortcuts you've configured: ``` -:1 # Switch to roam profile -:2 # Switch to work profile -:3 # Switch to assistant profile -:4 # Switch to guest profile +:1 # Switch to profile with shortcut 1 +:2 # Switch to profile with shortcut 2 +:3 # Switch to profile with shortcut 3 +:4 # Switch to profile with shortcut 4 ``` Or use the full command: @@ -36,21 +33,32 @@ Or use the full command: ### Save a Profile ``` -:profile save +:profile save # Save without shortcut +:profile save # Save with numeric shortcut +``` + +Examples: +``` +:profile save roam 1 # Save as "roam" with shortcut :1 +:profile save work 2 # Save as "work" with shortcut :2 +:profile save temp # Save as "temp" with no shortcut ``` -Saves your current settings as a named profile. ### Load a Profile ``` -:profile load +:profile load # Load by name +: # Load by shortcut (if configured) ``` -Loads all settings from the specified profile. Your current settings are automatically backed up to the `backup` profile before loading. + +Your current settings are automatically backed up to the `backup` profile before loading. ### List Profiles ``` :profile list ``` -Shows all saved profiles. +Shows all saved profiles with their shortcuts (if any). + +Example output: `Profiles: backup, roam (:1), temp, work (:2)` ### Current Profile ``` @@ -62,30 +70,46 @@ Shows which profile is currently active. ``` :profile delete ``` -Deletes a saved profile. +Deletes a saved profile and removes its shortcut mapping. ## Example Use Cases ### Personal vs Work -- Profile 1 (roam): Personal Roam graph with your personal account -- Profile 2 (work): Work Roam graph or different note-taking system +``` +:profile save personal 1 # Personal Roam graph +:profile save work 2 # Work note-taking system +``` + +Then switch with `:1` or `:2` ### Different Assistants -- Profile 3 (assistant): Connected to your personal assistant -- Profile 4 (guest): Safe settings for letting others try your GNG +``` +:profile save assistant 3 # Connected to personal assistant +:profile save guest 4 # Safe settings for demos +``` ### Different Upload Destinations -Switch between different note-taking systems (Roam, RemNote, Notion, etc.) with a single command. +Switch between Roam, RemNote, Notion, etc. with a single command. ## How It Works -- Each profile is stored as a JSON blob in Redis containing all setting values -- When you load a profile, your current settings are automatically backed up -- The `backup` profile always contains your most recent settings before the last profile switch -- Settings include: uploader type, credentials, custom command paths, API keys, etc. +- Each profile stores all settings from `secure_settings.py` as JSON in Redis +- Profile metadata (name, shortcut) is stored with the settings +- Shortcuts are mapped dynamically in Redis (no hardcoded values) +- When you load a profile, current settings are backed up to `backup` +- The `backup` profile always contains your most recent settings ## Safety - Your current settings are always backed up to `backup` before loading a new profile - The secure_settings.py file is never modified - profiles only affect Redis settings -- You can always revert to your previous settings by running `:profile load backup` +- You can always revert: `:profile load backup` +- Deleting a profile also removes its shortcut mapping + +## Configuration + +Profiles are completely user-configurable: +- Choose your own profile names +- Assign any numeric shortcuts you want +- No hardcoded profile names in the codebase +- Works for any Go Note Go user diff --git a/gonotego/command_center/profile_commands.py b/gonotego/command_center/profile_commands.py index 8771926..515a34f 100644 --- a/gonotego/command_center/profile_commands.py +++ b/gonotego/command_center/profile_commands.py @@ -8,32 +8,32 @@ say = system_commands.say -# Predefined profile shortcuts -PROFILE_SHORTCUTS = { - '1': 'roam', - '2': 'work', - '3': 'assistant', - '4': 'guest', -} - - @register_command('{}') def load_profile_shortcut(shortcut): - """Load a profile using numeric shortcut (e.g., :1 for roam).""" - if shortcut not in PROFILE_SHORTCUTS: + """Load a profile using numeric shortcut (e.g., :1, :2, :3).""" + # Check if this is a numeric shortcut + if not shortcut.isdigit(): return # Not a profile shortcut, let other commands handle it - profile_name = PROFILE_SHORTCUTS[shortcut] + profile_name = profiles.get_profile_by_shortcut(shortcut) + if profile_name is None: + return # No profile mapped to this shortcut + result = profiles.load_profile(profile_name) if result is None: - say(f'Profile {profile_name} not found. Creating from current settings.') - profiles.save_profile(profile_name) - say(f'Saved current settings as {profile_name}.') + say(f'Profile {profile_name} not found.') else: say(f'Loaded profile: {profile_name}') +@register_command('profile save {} {}') +def save_profile_with_shortcut(profile_name, shortcut): + """Save current settings as a named profile with a shortcut.""" + profiles.save_profile(profile_name, shortcut=shortcut) + say(f'Saved profile: {profile_name} with shortcut :{shortcut}') + + @register_command('profile save {}') def save_profile(profile_name): """Save current settings as a named profile.""" @@ -53,7 +53,7 @@ def load_profile(profile_name): @register_command('profile list') def list_profiles(): - """List all saved profiles.""" + """List all saved profiles with their shortcuts.""" profile_names = profiles.list_profiles() if not profile_names: say('No profiles saved.') @@ -76,14 +76,3 @@ def delete_profile(profile_name): """Delete a saved profile.""" profiles.delete_profile(profile_name) say(f'Deleted profile: {profile_name}') - - -@register_command('profile init') -def init_default_profiles(): - """Initialize default profiles (roam, work, assistant, guest) from current settings.""" - current_settings = profiles.get_all_settings() - - for shortcut, profile_name in PROFILE_SHORTCUTS.items(): - profiles.save_profile(profile_name) - - say('Initialized default profiles: roam, work, assistant, guest') diff --git a/gonotego/settings/profiles.py b/gonotego/settings/profiles.py index d12fdbb..1987572 100644 --- a/gonotego/settings/profiles.py +++ b/gonotego/settings/profiles.py @@ -1,7 +1,7 @@ """Profile management for Go Note Go settings. -Profiles allow switching between different configurations (roam, work, assistant, guest). -Each profile stores a complete snapshot of all settings. +Profiles allow switching between different configurations. +Each profile stores a complete snapshot of all settings plus metadata (name, shortcut). """ import json from gonotego.settings import settings @@ -9,8 +9,8 @@ from gonotego.common import interprocess PROFILES_KEY = 'GoNoteGo:profiles' +PROFILE_SHORTCUTS_KEY = 'GoNoteGo:profile_shortcuts' CURRENT_PROFILE_KEY = 'GoNoteGo:current_profile' -BACKUP_PROFILE_KEY = 'GoNoteGo:backup_profile' def get_redis_key(profile_name): @@ -28,12 +28,33 @@ def get_all_settings(): return settings_dict -def save_profile(profile_name): - """Save current settings to a named profile.""" +def save_profile(profile_name, shortcut=None): + """Save current settings to a named profile. + + Args: + profile_name: Name of the profile + shortcut: Optional numeric shortcut (e.g., '1', '2', '3') + """ r = interprocess.get_redis_client() current_settings = get_all_settings() - settings_json = json.dumps(current_settings) - r.set(get_redis_key(profile_name), settings_json) + + # Store profile data + profile_data = { + 'name': profile_name, + 'settings': current_settings, + } + if shortcut is not None: + profile_data['shortcut'] = shortcut + + profile_json = json.dumps(profile_data) + r.set(get_redis_key(profile_name), profile_json) + + # Update shortcuts mapping if shortcut is provided + if shortcut is not None: + shortcuts = get_shortcuts_mapping() + shortcuts[shortcut] = profile_name + r.set(PROFILE_SHORTCUTS_KEY, json.dumps(shortcuts)) + return current_settings @@ -46,15 +67,16 @@ def load_profile(profile_name): """ r = interprocess.get_redis_client() - # First, backup current settings - save_profile('backup') + # First, backup current settings (without shortcut) + save_profile('backup', shortcut=None) # Load the requested profile profile_json = r.get(get_redis_key(profile_name)) if profile_json is None: return None - profile_settings = json.loads(profile_json) + profile_data = json.loads(profile_json) + profile_settings = profile_data.get('settings', profile_data) # Backward compat # Clear all current settings and load profile settings settings.clear_all() @@ -76,21 +98,60 @@ def get_current_profile(): return profile_bytes.decode('utf-8') +def get_shortcuts_mapping(): + """Get the mapping of shortcuts to profile names.""" + r = interprocess.get_redis_client() + shortcuts_json = r.get(PROFILE_SHORTCUTS_KEY) + if shortcuts_json is None: + return {} + return json.loads(shortcuts_json) + + +def get_profile_by_shortcut(shortcut): + """Get profile name for a given shortcut.""" + shortcuts = get_shortcuts_mapping() + return shortcuts.get(shortcut) + + def list_profiles(): - """List all saved profile names.""" + """List all saved profile names with their shortcuts.""" r = interprocess.get_redis_client() profile_keys = r.keys(get_redis_key('*')) - profile_names = [] + + profiles_info = [] + shortcuts = get_shortcuts_mapping() + # Reverse mapping for lookup + name_to_shortcut = {v: k for k, v in shortcuts.items()} + for key in profile_keys: key_str = key.decode('utf-8') if isinstance(key, bytes) else key # Extract profile name from key if key_str.startswith(f'{PROFILES_KEY}:'): profile_name = key_str[len(f'{PROFILES_KEY}:'):] - profile_names.append(profile_name) - return sorted(profile_names) + shortcut = name_to_shortcut.get(profile_name) + if shortcut: + profiles_info.append(f"{profile_name} (:{shortcut})") + else: + profiles_info.append(profile_name) + + return sorted(profiles_info) def delete_profile(profile_name): - """Delete a saved profile.""" + """Delete a saved profile and remove its shortcut if any.""" r = interprocess.get_redis_client() + + # Remove from shortcuts mapping + shortcuts = get_shortcuts_mapping() + shortcut_to_remove = None + for shortcut, name in shortcuts.items(): + if name == profile_name: + shortcut_to_remove = shortcut + break + + if shortcut_to_remove: + del shortcuts[shortcut_to_remove] + r.set(PROFILE_SHORTCUTS_KEY, json.dumps(shortcuts)) + + # Delete the profile r.delete(get_redis_key(profile_name)) From ed7edf59106ec8bff394030989a311a8704cb115 Mon Sep 17 00:00:00 2001 From: David Bieber Date: Wed, 29 Oct 2025 22:54:20 -0400 Subject: [PATCH 3/3] Clean up profiles code, ready to try it --- gonotego/command_center/profile_commands.py | 7 ++-- gonotego/settings-server/package-lock.json | 9 ++--- gonotego/settings/profiles.py | 45 ++++++++++++++++----- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/gonotego/command_center/profile_commands.py b/gonotego/command_center/profile_commands.py index 515a34f..2fb4ed6 100644 --- a/gonotego/command_center/profile_commands.py +++ b/gonotego/command_center/profile_commands.py @@ -8,15 +8,16 @@ say = system_commands.say -@register_command('{}') +@register_command(r'p(\d)') def load_profile_shortcut(shortcut): - """Load a profile using numeric shortcut (e.g., :1, :2, :3).""" + """Load a profile using numeric shortcut (e.g., :p1, :p2, :p3).""" # Check if this is a numeric shortcut if not shortcut.isdigit(): - return # Not a profile shortcut, let other commands handle it + return # Not a profile shortcut profile_name = profiles.get_profile_by_shortcut(shortcut) if profile_name is None: + say(f'Profile {shortcut} not found') return # No profile mapped to this shortcut result = profiles.load_profile(profile_name) diff --git a/gonotego/settings-server/package-lock.json b/gonotego/settings-server/package-lock.json index b81a6e0..2f4f435 100644 --- a/gonotego/settings-server/package-lock.json +++ b/gonotego/settings-server/package-lock.json @@ -2503,9 +2503,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001679", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001679.tgz", - "integrity": "sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==", + "version": "1.0.30001713", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", + "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", "dev": true, "funding": [ { @@ -2520,8 +2520,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/chalk": { "version": "4.1.2", diff --git a/gonotego/settings/profiles.py b/gonotego/settings/profiles.py index 1987572..a909322 100644 --- a/gonotego/settings/profiles.py +++ b/gonotego/settings/profiles.py @@ -29,20 +29,32 @@ def get_all_settings(): def save_profile(profile_name, shortcut=None): + backup_profile(profile_name) + return save_profile_raw(profile_name, shortcut=shortcut) + + +def save_profile_raw(profile_name, shortcut=None): """Save current settings to a named profile. Args: - profile_name: Name of the profile - shortcut: Optional numeric shortcut (e.g., '1', '2', '3') + profile_name: Name of the profile + shortcut: Optional numeric shortcut (e.g., '1', '2', '3') """ r = interprocess.get_redis_client() current_settings = get_all_settings() # Store profile data profile_data = { - 'name': profile_name, - 'settings': current_settings, + 'name': profile_name, + 'settings': current_settings, } + return save_profile_data(profile_name, profile_data, shortcut=shortcut) + + +def save_profile_data(profile_name, profile_data, shortcut=None): + r = interprocess.get_redis_client() + current_settings = get_all_settings() + if shortcut is not None: profile_data['shortcut'] = shortcut @@ -58,6 +70,23 @@ def save_profile(profile_name, shortcut=None): return current_settings +def backup_profile(profile_name): + profile_data = get_profile_data(profile_name) + if profile_data is not None: + save_profile_data(f'{profile_name}.backup', profile_data) + + +def get_profile_data(profile_name): + r = interprocess.get_redis_client() + + profile_json = r.get(get_redis_key(profile_name)) + if profile_json is None: + return None + + profile_data = json.loads(profile_json) + return profile_data + + def load_profile(profile_name): """Load settings from a named profile. @@ -71,11 +100,9 @@ def load_profile(profile_name): save_profile('backup', shortcut=None) # Load the requested profile - profile_json = r.get(get_redis_key(profile_name)) - if profile_json is None: + profile_data = get_profile_data(profile_name) + if profile_data is None: return None - - profile_data = json.loads(profile_json) profile_settings = profile_data.get('settings', profile_data) # Backward compat # Clear all current settings and load profile settings @@ -130,7 +157,7 @@ def list_profiles(): profile_name = key_str[len(f'{PROFILES_KEY}:'):] shortcut = name_to_shortcut.get(profile_name) if shortcut: - profiles_info.append(f"{profile_name} (:{shortcut})") + profiles_info.append(f"{profile_name} ({shortcut})") else: profiles_info.append(profile_name)