MetaList 0.3.4__tar.gz → 0.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metalist-0.3.4 → metalist-0.3.7}/MANIFEST.in +1 -0
- {metalist-0.3.4/metalist.egg-info → metalist-0.3.7}/PKG-INFO +5 -5
- {metalist-0.3.4 → metalist-0.3.7}/README.md +4 -4
- {metalist-0.3.4 → metalist-0.3.7}/app/api/middleware/auth.py +2 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/auth.py +99 -2
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/backups.py +135 -26
- {metalist-0.3.4 → metalist-0.3.7}/app/main.py +88 -32
- {metalist-0.3.4 → metalist-0.3.7}/app/server_runtime.py +5 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/namespace_deletion_worker.py +32 -3
- metalist-0.3.7/app/services/namespace_rename_jobs.py +115 -0
- metalist-0.3.7/app/services/namespace_rename_worker.py +160 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/namespace_switcher.py +247 -23
- {metalist-0.3.4 → metalist-0.3.7}/app/static/config/command_palette_tags.json +4 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/css/main.css +0 -13
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/auth.js +23 -3
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/command-palette-controller.js +15 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/endpoint-registry.js +7 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/config.js +2 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/backup-restore-modal.js +151 -83
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/delete-namespace-modal.js +53 -4
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/delete-namespace-validation.js +10 -3
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/namespace-modals.js +167 -1
- metalist-0.3.7/app/static/js/modules/modals/namespace-ports-profile.js +17 -0
- metalist-0.3.7/app/static/js/modules/modals/namespace-rename-validation.js +32 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/namespace-deleted.js +29 -3
- metalist-0.3.7/app/static/js/namespace-renamed.js +116 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/namespace_deleted.html +1 -1
- metalist-0.3.7/app/templates/namespace_renamed.html +67 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/version.py +1 -1
- {metalist-0.3.4 → metalist-0.3.7}/convert-from-legacy.py +91 -11
- {metalist-0.3.4 → metalist-0.3.7}/main.py +23 -21
- {metalist-0.3.4 → metalist-0.3.7/metalist.egg-info}/PKG-INFO +5 -5
- {metalist-0.3.4 → metalist-0.3.7}/metalist.egg-info/SOURCES.txt +6 -0
- {metalist-0.3.4 → metalist-0.3.7}/pyproject.toml +2 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/deps.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/dev.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/request_auth.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/files.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/mcp.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/memory.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/notes.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/ontology.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/reminders.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/sounds.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/routes/test.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/api/transactions.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/config.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/engine.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/file_schema.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/file_session.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/files_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/link_titles_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/migrations.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/notes_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/reminders_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/schema.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/search_history_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/session.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/settings_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/sounds_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/db/tab_state_sql.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/encryption_audit.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/__main__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/errors.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/policy.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/read_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/server.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/mcp/tools.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/commands.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/database.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/entities.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/enums.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/linked_list.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/list_operations.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/list_traversal.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/note_crud.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/models/utils.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/presentation/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/presentation/render/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/presentation/templates.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/security/encryption.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/auth.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/auth_cache_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/auth_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/backlinks.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/backup_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/backup_settings_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/base_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/client_state_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/content_cache.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/content_formatting.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/date_filtering.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/dependencies.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/diagnostics.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/embedded_references.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/encryption.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/exception_capture.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/file_registry.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/file_storage.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/html_export.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/html_unformatting.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/hydration_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/integrity.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/latex_rendering.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/link_titles.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/login_rate_limit.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/maintenance_mode.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/markdown_rendering.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/memory.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/memory_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/note_image_tags.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/note_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/note_store.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/query_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/reminders.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/root_sorting.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/runtime_hardening.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/search_history.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/search_index.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/search_query.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/search_text.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/session_timeout_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/shell_session_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/snapshot.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/sound_storage.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/store.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/sync.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/sync_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tab_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tag_case.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tag_ontology.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tag_rename.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tag_suggestions.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tag_term_matching.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/test_reset.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/tokens.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/transaction_manager.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/undo_service.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/undo_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/view_cache.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/view_diff.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/view_state.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/services/windows_process_control.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/startup_js_sanity.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/startup_sanity.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/startup_sanity_config.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/css/forms.css +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/img/favicon.ico +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/locked.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/main.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/api-client.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/memory-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/ontology-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/sound-manager-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/date-filter-indicator-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/date-filter-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/rhs-panel-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/sound-service.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/js/vendor/markdown-it.min.js +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/static/video/login-startup.mp4 +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/base.html +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/index.html +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/locked.html +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/maintenance.html +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/templates/notes_list.html +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/base.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/collapse.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/copy_note.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/create_child.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/create_note.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/create_sibling.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/expand.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/indent.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/lock.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/move.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/move_to_top.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/outdent.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/paste_child.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/prioritize.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/record_edit_mode.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/redo.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/rename_tag.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/run_shell.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/split_note.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/undo.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/unformat_content.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/update_content.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/usecases/view.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/utils/__init__.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/utils/encryption.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/app/utils/text_utils.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/mcp_client.py +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/metalist.egg-info/requires.txt +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.3.4 → metalist-0.3.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
|
|
5
5
|
Project-URL: Homepage, https://github.com/evolvingstuff/metalist
|
|
6
6
|
Project-URL: Repository, https://github.com/evolvingstuff/metalist
|
|
@@ -234,9 +234,9 @@ Tool catalog and schemas:
|
|
|
234
234
|
- `docs/mcp_tools.md`
|
|
235
235
|
|
|
236
236
|
### Legacy Import
|
|
237
|
-
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL
|
|
237
|
+
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
|
|
238
238
|
|
|
239
|
-
This is destructive. It deletes the existing DB
|
|
239
|
+
This is destructive. It deletes the existing notes DB and related files/sounds DB before rebuilding the namespace.
|
|
240
240
|
|
|
241
241
|
Example usage:
|
|
242
242
|
```bash
|
|
@@ -263,11 +263,11 @@ This repo now packages itself under the PyPI distribution name `metalist`. Curre
|
|
|
263
263
|
|
|
264
264
|
Recommended release path:
|
|
265
265
|
1. In the existing PyPI project `metalist`, configure GitHub Trusted Publishing for `evolvingstuff/metalist` and the workflow file `.github/workflows/publish-pypi.yml`.
|
|
266
|
-
2. Push a tag such as `v0.3.
|
|
266
|
+
2. Push a tag such as `v0.3.5`.
|
|
267
267
|
3. After the GitHub Actions workflow completes, users can run it with `uvx metalist`, install it persistently with `uv tool install metalist`, or install it with `pip install metalist`.
|
|
268
268
|
|
|
269
269
|
If `--input` is omitted, a file picker opens (when `tkinter` is available).
|
|
270
|
-
Notes tagged with `@implies` are converted into ontology rules and are not imported as notes.
|
|
270
|
+
Notes tagged with `@implies` are converted into ontology rules and are not imported as notes. Legacy rules that are invalid under the current ontology grammar are reported and skipped while valid rules continue importing.
|
|
271
271
|
|
|
272
272
|
### Run Tests
|
|
273
273
|
|
|
@@ -205,9 +205,9 @@ Tool catalog and schemas:
|
|
|
205
205
|
- `docs/mcp_tools.md`
|
|
206
206
|
|
|
207
207
|
### Legacy Import
|
|
208
|
-
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL
|
|
208
|
+
`convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
|
|
209
209
|
|
|
210
|
-
This is destructive. It deletes the existing DB
|
|
210
|
+
This is destructive. It deletes the existing notes DB and related files/sounds DB before rebuilding the namespace.
|
|
211
211
|
|
|
212
212
|
Example usage:
|
|
213
213
|
```bash
|
|
@@ -234,11 +234,11 @@ This repo now packages itself under the PyPI distribution name `metalist`. Curre
|
|
|
234
234
|
|
|
235
235
|
Recommended release path:
|
|
236
236
|
1. In the existing PyPI project `metalist`, configure GitHub Trusted Publishing for `evolvingstuff/metalist` and the workflow file `.github/workflows/publish-pypi.yml`.
|
|
237
|
-
2. Push a tag such as `v0.3.
|
|
237
|
+
2. Push a tag such as `v0.3.5`.
|
|
238
238
|
3. After the GitHub Actions workflow completes, users can run it with `uvx metalist`, install it persistently with `uv tool install metalist`, or install it with `pip install metalist`.
|
|
239
239
|
|
|
240
240
|
If `--input` is omitted, a file picker opens (when `tkinter` is available).
|
|
241
|
-
Notes tagged with `@implies` are converted into ontology rules and are not imported as notes.
|
|
241
|
+
Notes tagged with `@implies` are converted into ontology rules and are not imported as notes. Legacy rules that are invalid under the current ontology grammar are reported and skipped while valid rules continue importing.
|
|
242
242
|
|
|
243
243
|
### Run Tests
|
|
244
244
|
|
|
@@ -20,10 +20,12 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
20
20
|
f"{API_PREFIX}/auth/status",
|
|
21
21
|
f"{API_PREFIX}/auth/session",
|
|
22
22
|
f"{API_PREFIX}/auth/namespaces/delete-jobs/",
|
|
23
|
+
f"{API_PREFIX}/auth/namespaces/rename-jobs/",
|
|
23
24
|
f"{API_PREFIX}/mcp",
|
|
24
25
|
"/mcp-client-v2",
|
|
25
26
|
"/mcp-client",
|
|
26
27
|
"/namespace-deleted",
|
|
28
|
+
"/namespace-renamed",
|
|
27
29
|
"/static/", # CSS/JS files needed for login page
|
|
28
30
|
"/favicon.ico",
|
|
29
31
|
"/locked",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import secrets
|
|
4
5
|
import sqlite3
|
|
5
6
|
from fastapi import APIRouter, Depends, Header, HTTPException, Request, Response
|
|
@@ -46,8 +47,10 @@ from app.services.namespace_switcher import delete_current_namespace
|
|
|
46
47
|
from app.services.namespace_switcher import delete_namespace
|
|
47
48
|
from app.services.namespace_switcher import open_login_namespace
|
|
48
49
|
from app.services.namespace_switcher import open_or_launch_namespace
|
|
50
|
+
from app.services.namespace_switcher import rename_current_namespace
|
|
49
51
|
from app.services.namespace_switcher import save_namespace_port_profiles
|
|
50
52
|
from app.services.namespace_deletion_jobs import load_namespace_deletion_job
|
|
53
|
+
from app.services.namespace_rename_jobs import load_namespace_rename_job
|
|
51
54
|
from app.server_runtime import NamespaceLaunchProfile
|
|
52
55
|
from app.server_runtime import resolve_namespace_directory
|
|
53
56
|
from app.server_runtime import resolve_namespaced_database_path
|
|
@@ -88,6 +91,7 @@ from app.services.client_state_service import save_command_palette_usage
|
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
router = APIRouter(prefix="/auth", tags=["auth2"])
|
|
94
|
+
logger = logging.getLogger(__name__)
|
|
91
95
|
|
|
92
96
|
|
|
93
97
|
class LoginRequest(BaseModel):
|
|
@@ -437,7 +441,13 @@ def _on_hydration_done(future: Future) -> None:
|
|
|
437
441
|
return
|
|
438
442
|
error = future.exception()
|
|
439
443
|
if error is not None:
|
|
440
|
-
|
|
444
|
+
error_message = f"{type(error).__name__}: {error}"
|
|
445
|
+
logger.error(
|
|
446
|
+
"Hydration worker failed: %s",
|
|
447
|
+
error_message,
|
|
448
|
+
exc_info=(type(error), error, error.__traceback__),
|
|
449
|
+
)
|
|
450
|
+
hydration_state.fail(error_message)
|
|
441
451
|
|
|
442
452
|
|
|
443
453
|
def _start_hydration(*, first_load: bool, rebuild_required: bool) -> None:
|
|
@@ -582,6 +592,15 @@ def _require_string_field(payload: dict[str, object], field_name: str) -> str:
|
|
|
582
592
|
return value
|
|
583
593
|
|
|
584
594
|
|
|
595
|
+
def _require_string_field_allow_empty(payload: dict[str, object], field_name: str) -> str:
|
|
596
|
+
if field_name not in payload:
|
|
597
|
+
raise HTTPException(status_code=400, detail=f"{field_name} is required")
|
|
598
|
+
value = payload[field_name]
|
|
599
|
+
if not isinstance(value, str):
|
|
600
|
+
raise HTTPException(status_code=400, detail=f"{field_name} must be a string")
|
|
601
|
+
return value
|
|
602
|
+
|
|
603
|
+
|
|
585
604
|
def _require_int_field(payload: dict[str, object], field_name: str) -> int:
|
|
586
605
|
if field_name not in payload:
|
|
587
606
|
raise HTTPException(status_code=400, detail=f"{field_name} is required")
|
|
@@ -960,7 +979,8 @@ def save_namespace_ports(
|
|
|
960
979
|
def _delete_namespace_from_body(*, body: dict[str, object], target_namespace: str) -> dict[str, object]:
|
|
961
980
|
normalized_target_namespace = validate_namespace(namespace=target_namespace)
|
|
962
981
|
confirmed_namespace = _require_string_field(body, "confirmed_namespace")
|
|
963
|
-
current_password =
|
|
982
|
+
current_password = _require_string_field_allow_empty(body, "current_password")
|
|
983
|
+
redirect_namespace = _require_string_field(body, "redirect_namespace")
|
|
964
984
|
|
|
965
985
|
if _namespace_requires_password(namespace=normalized_target_namespace):
|
|
966
986
|
_verify_namespace_password(
|
|
@@ -981,6 +1001,7 @@ def _delete_namespace_from_body(*, body: dict[str, object], target_namespace: st
|
|
|
981
1001
|
current_namespace=ACTIVE_NAMESPACE,
|
|
982
1002
|
target_namespace=normalized_target_namespace,
|
|
983
1003
|
confirmed_namespace=confirmed_namespace,
|
|
1004
|
+
redirect_namespace=redirect_namespace,
|
|
984
1005
|
)
|
|
985
1006
|
if delete_capture.captured_exception is not None:
|
|
986
1007
|
exc = delete_capture.captured_exception
|
|
@@ -1011,11 +1032,33 @@ def namespace_delete_preflight(
|
|
|
1011
1032
|
target_requires_password = False
|
|
1012
1033
|
if target_exists:
|
|
1013
1034
|
target_requires_password = _namespace_requires_password(namespace=target_namespace)
|
|
1035
|
+
catalog = build_namespace_catalog(
|
|
1036
|
+
environ=os.environ,
|
|
1037
|
+
current_namespace=ACTIVE_NAMESPACE,
|
|
1038
|
+
)
|
|
1039
|
+
raw_namespaces = catalog["namespaces"]
|
|
1040
|
+
if not isinstance(raw_namespaces, list):
|
|
1041
|
+
raise RuntimeError("Namespace catalog missing namespaces")
|
|
1042
|
+
redirect_namespaces: list[str] = []
|
|
1043
|
+
for raw_entry in raw_namespaces:
|
|
1044
|
+
if not isinstance(raw_entry, dict):
|
|
1045
|
+
raise RuntimeError("Namespace catalog entry must be an object")
|
|
1046
|
+
namespace = raw_entry["namespace"]
|
|
1047
|
+
if not isinstance(namespace, str) or namespace == "":
|
|
1048
|
+
raise RuntimeError("Namespace catalog entry missing namespace")
|
|
1049
|
+
if namespace != target_namespace:
|
|
1050
|
+
redirect_namespaces.append(namespace)
|
|
1051
|
+
redirect_namespaces.sort()
|
|
1052
|
+
recreates_default = target_namespace == ACTIVE_NAMESPACE and len(redirect_namespaces) == 0
|
|
1053
|
+
if recreates_default:
|
|
1054
|
+
redirect_namespaces.append("default")
|
|
1014
1055
|
return {
|
|
1015
1056
|
"target_namespace": target_namespace,
|
|
1016
1057
|
"target_exists": target_exists,
|
|
1017
1058
|
"target_requires_password": target_requires_password,
|
|
1018
1059
|
"is_current_namespace": target_namespace == ACTIVE_NAMESPACE,
|
|
1060
|
+
"redirect_namespaces": redirect_namespaces,
|
|
1061
|
+
"recreates_default": recreates_default,
|
|
1019
1062
|
}
|
|
1020
1063
|
|
|
1021
1064
|
|
|
@@ -1046,6 +1089,41 @@ def delete_active_namespace(
|
|
|
1046
1089
|
)
|
|
1047
1090
|
|
|
1048
1091
|
|
|
1092
|
+
@router.post("/namespaces/rename-current")
|
|
1093
|
+
@transactional_route
|
|
1094
|
+
def rename_active_namespace(
|
|
1095
|
+
payload: dict[str, object],
|
|
1096
|
+
token: Annotated[str, Depends(_require_auth)],
|
|
1097
|
+
):
|
|
1098
|
+
body = _require_body_object(payload)
|
|
1099
|
+
target_namespace = _require_string_field(body, "target_namespace")
|
|
1100
|
+
rename_capture = CapturedExceptionContext(
|
|
1101
|
+
RuntimeError,
|
|
1102
|
+
ValueError,
|
|
1103
|
+
TypeError,
|
|
1104
|
+
FileNotFoundError,
|
|
1105
|
+
)
|
|
1106
|
+
result = None
|
|
1107
|
+
with rename_capture:
|
|
1108
|
+
result = rename_current_namespace(
|
|
1109
|
+
environ=os.environ,
|
|
1110
|
+
current_namespace=ACTIVE_NAMESPACE,
|
|
1111
|
+
target_namespace=target_namespace,
|
|
1112
|
+
)
|
|
1113
|
+
if rename_capture.captured_exception is not None:
|
|
1114
|
+
exc = rename_capture.captured_exception
|
|
1115
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
1116
|
+
if result is None:
|
|
1117
|
+
raise RuntimeError("Namespace rename did not return a result")
|
|
1118
|
+
return {
|
|
1119
|
+
"source_namespace": result.source_namespace,
|
|
1120
|
+
"target_namespace": result.target_namespace,
|
|
1121
|
+
"redirect_url": result.redirect_url,
|
|
1122
|
+
"rename_job_id": result.rename_job_id,
|
|
1123
|
+
"message": result.message,
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
|
|
1049
1127
|
@router.get("/namespaces/delete-jobs/{job_id}")
|
|
1050
1128
|
def namespace_delete_job_status(
|
|
1051
1129
|
job_id: str,
|
|
@@ -1067,6 +1145,25 @@ def namespace_delete_job_status(
|
|
|
1067
1145
|
return job_record
|
|
1068
1146
|
|
|
1069
1147
|
|
|
1148
|
+
@router.get("/namespaces/rename-jobs/{job_id}")
|
|
1149
|
+
def namespace_rename_job_status(job_id: str):
|
|
1150
|
+
job_record_capture = CapturedExceptionContext(
|
|
1151
|
+
RuntimeError,
|
|
1152
|
+
TypeError,
|
|
1153
|
+
ValueError,
|
|
1154
|
+
FileNotFoundError,
|
|
1155
|
+
)
|
|
1156
|
+
job_record: dict[str, object] | None = None
|
|
1157
|
+
with job_record_capture:
|
|
1158
|
+
job_record = load_namespace_rename_job(job_id=job_id)
|
|
1159
|
+
if job_record_capture.captured_exception is not None:
|
|
1160
|
+
exc = job_record_capture.captured_exception
|
|
1161
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
1162
|
+
if job_record is None:
|
|
1163
|
+
raise HTTPException(status_code=404, detail=f"Namespace rename job not found: {job_id}")
|
|
1164
|
+
return job_record
|
|
1165
|
+
|
|
1166
|
+
|
|
1070
1167
|
@router.post("/hydrate", response_model=HydrationStatusResponse)
|
|
1071
1168
|
@transactional_route
|
|
1072
1169
|
def hydrate_cache(
|
|
@@ -35,6 +35,7 @@ from app.server_runtime import NamespaceLaunchProfile
|
|
|
35
35
|
from app.server_runtime import _DEFAULT_HTTP_PORT
|
|
36
36
|
from app.server_runtime import _DEFAULT_MCP_AGENT_WEB_PORT
|
|
37
37
|
from app.server_runtime import load_all_namespace_launch_profiles
|
|
38
|
+
from app.server_runtime import load_namespace_launch_profile
|
|
38
39
|
from app.server_runtime import resolve_namespace_directory
|
|
39
40
|
from app.server_runtime import resolve_namespaced_database_path
|
|
40
41
|
from app.server_runtime import resolve_namespaces_directory
|
|
@@ -125,6 +126,7 @@ class BackupRestorePreflightResponse(BaseModel):
|
|
|
125
126
|
backup_namespace: str
|
|
126
127
|
target_namespace: str
|
|
127
128
|
same_namespace: bool
|
|
129
|
+
target_is_active: bool
|
|
128
130
|
target_exists: bool
|
|
129
131
|
target_requires_password: bool
|
|
130
132
|
restored_profile: BackupRestoreLaunchProfileResponse | None
|
|
@@ -699,6 +701,48 @@ def _response_profile_from_backup_profile(
|
|
|
699
701
|
)
|
|
700
702
|
|
|
701
703
|
|
|
704
|
+
def _required_existing_target_launch_profile(*, target_namespace: str) -> BackupLaunchProfile:
|
|
705
|
+
profile = load_namespace_launch_profile(namespace=target_namespace)
|
|
706
|
+
if profile is None:
|
|
707
|
+
raise RuntimeError(f"Existing target namespace has no saved launch profile: {target_namespace}")
|
|
708
|
+
if profile.port is None:
|
|
709
|
+
raise RuntimeError(f"Existing target namespace has no saved HTTP port: {target_namespace}")
|
|
710
|
+
if profile.mcp_port is None:
|
|
711
|
+
raise RuntimeError(f"Existing target namespace has no saved MCP port: {target_namespace}")
|
|
712
|
+
return BackupLaunchProfile(
|
|
713
|
+
namespace=target_namespace,
|
|
714
|
+
port=profile.port,
|
|
715
|
+
https_port=profile.https_port,
|
|
716
|
+
mcp_port=profile.mcp_port,
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
def _resolve_same_name_restore_launch_profile(
|
|
721
|
+
*,
|
|
722
|
+
backup_path: Path,
|
|
723
|
+
target_namespace: str,
|
|
724
|
+
target_exists: bool,
|
|
725
|
+
) -> BackupLaunchProfile:
|
|
726
|
+
if target_exists:
|
|
727
|
+
return _required_existing_target_launch_profile(
|
|
728
|
+
target_namespace=target_namespace,
|
|
729
|
+
)
|
|
730
|
+
restored_profile = read_backup_launch_profile(
|
|
731
|
+
backup_path,
|
|
732
|
+
expected_namespace=target_namespace,
|
|
733
|
+
)
|
|
734
|
+
suggested_profile = _suggest_import_launch_profile(
|
|
735
|
+
target_namespace=target_namespace,
|
|
736
|
+
restored_profile=restored_profile,
|
|
737
|
+
)
|
|
738
|
+
return BackupLaunchProfile(
|
|
739
|
+
namespace=target_namespace,
|
|
740
|
+
port=suggested_profile.port,
|
|
741
|
+
https_port=suggested_profile.https_port,
|
|
742
|
+
mcp_port=suggested_profile.mcp_port,
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
|
|
702
746
|
def _backup_profile_from_request(
|
|
703
747
|
*,
|
|
704
748
|
namespace: str,
|
|
@@ -725,6 +769,27 @@ def _assert_import_profile_has_no_internal_overlap(*, profile: BackupLaunchProfi
|
|
|
725
769
|
)
|
|
726
770
|
|
|
727
771
|
|
|
772
|
+
def _restore_import_to_target(
|
|
773
|
+
*,
|
|
774
|
+
backup_path: Path,
|
|
775
|
+
target_database_path: Path,
|
|
776
|
+
backup_namespace: str,
|
|
777
|
+
target_namespace: str,
|
|
778
|
+
launch_profile: BackupLaunchProfile,
|
|
779
|
+
) -> None:
|
|
780
|
+
restore_backup_to_paths_from_namespace(
|
|
781
|
+
backup_path,
|
|
782
|
+
target_database_path,
|
|
783
|
+
source_namespace=backup_namespace,
|
|
784
|
+
)
|
|
785
|
+
save_namespace_launch_profile(
|
|
786
|
+
namespace=target_namespace,
|
|
787
|
+
port=launch_profile.port,
|
|
788
|
+
https_port=launch_profile.https_port,
|
|
789
|
+
mcp_port=launch_profile.mcp_port,
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
|
|
728
793
|
@router.get("/settings", response_model=BackupSettingsResponse)
|
|
729
794
|
def get_backup_settings(token: Annotated[str, Depends(_require_auth)]):
|
|
730
795
|
settings = load_backup_settings(token=token)
|
|
@@ -878,13 +943,21 @@ def restore_backup_preflight(
|
|
|
878
943
|
backup_path,
|
|
879
944
|
expected_namespace=backup_namespace,
|
|
880
945
|
)
|
|
946
|
+
target_exists = _restore_target_exists(target_namespace=target_namespace)
|
|
881
947
|
suggested_profile = None
|
|
882
948
|
port_conflicts: list[str] = []
|
|
883
|
-
if
|
|
884
|
-
|
|
949
|
+
if target_exists:
|
|
950
|
+
target_profile = _required_existing_target_launch_profile(
|
|
885
951
|
target_namespace=target_namespace,
|
|
886
|
-
launch_profile=restored_profile,
|
|
887
952
|
)
|
|
953
|
+
suggested_profile = _response_profile_from_backup_profile(profile=target_profile)
|
|
954
|
+
assert suggested_profile is not None
|
|
955
|
+
else:
|
|
956
|
+
if restored_profile is not None:
|
|
957
|
+
port_conflicts = _collect_import_profile_port_conflicts(
|
|
958
|
+
target_namespace=target_namespace,
|
|
959
|
+
launch_profile=restored_profile,
|
|
960
|
+
)
|
|
888
961
|
suggested_profile = _suggest_import_launch_profile(
|
|
889
962
|
target_namespace=target_namespace,
|
|
890
963
|
restored_profile=restored_profile,
|
|
@@ -894,7 +967,8 @@ def restore_backup_preflight(
|
|
|
894
967
|
backup_namespace=backup_namespace,
|
|
895
968
|
target_namespace=target_namespace,
|
|
896
969
|
same_namespace=target_namespace == backup_namespace,
|
|
897
|
-
|
|
970
|
+
target_is_active=target_namespace == ACTIVE_NAMESPACE,
|
|
971
|
+
target_exists=target_exists,
|
|
898
972
|
target_requires_password=_target_namespace_requires_password(target_namespace=target_namespace),
|
|
899
973
|
restored_profile=_response_profile_from_backup_profile(profile=restored_profile),
|
|
900
974
|
suggested_profile=suggested_profile,
|
|
@@ -935,10 +1009,22 @@ def restore_backup(
|
|
|
935
1009
|
backup_path = folder_directory / folder_filename
|
|
936
1010
|
if not backup_path.exists():
|
|
937
1011
|
raise HTTPException(status_code=404, detail=f"Backup not found: {folder_filename}")
|
|
1012
|
+
target_exists = _restore_target_exists(target_namespace=target_namespace)
|
|
1013
|
+
launch_profile = _resolve_same_name_restore_launch_profile(
|
|
1014
|
+
backup_path=backup_path,
|
|
1015
|
+
target_namespace=target_namespace,
|
|
1016
|
+
target_exists=target_exists,
|
|
1017
|
+
)
|
|
938
1018
|
if target_namespace == ACTIVE_NAMESPACE:
|
|
939
1019
|
maintenance_service.enter_maintenance("Restoring backup")
|
|
940
1020
|
try:
|
|
941
1021
|
restore_backup_to_paths(backup_path, target_database_path)
|
|
1022
|
+
save_namespace_launch_profile(
|
|
1023
|
+
namespace=target_namespace,
|
|
1024
|
+
port=launch_profile.port,
|
|
1025
|
+
https_port=launch_profile.https_port,
|
|
1026
|
+
mcp_port=launch_profile.mcp_port,
|
|
1027
|
+
)
|
|
942
1028
|
_reset_runtime_state_after_restore()
|
|
943
1029
|
finally:
|
|
944
1030
|
maintenance_service.exit_maintenance()
|
|
@@ -947,6 +1033,12 @@ def restore_backup(
|
|
|
947
1033
|
open_namespace_suggested = False
|
|
948
1034
|
else:
|
|
949
1035
|
restore_backup_to_paths(backup_path, target_database_path)
|
|
1036
|
+
save_namespace_launch_profile(
|
|
1037
|
+
namespace=target_namespace,
|
|
1038
|
+
port=launch_profile.port,
|
|
1039
|
+
https_port=launch_profile.https_port,
|
|
1040
|
+
mcp_port=launch_profile.mcp_port,
|
|
1041
|
+
)
|
|
950
1042
|
return BackupRestoreResponse(
|
|
951
1043
|
backup_id=payload.backup_id,
|
|
952
1044
|
source=payload.source,
|
|
@@ -999,27 +1091,44 @@ def import_backup(
|
|
|
999
1091
|
if not backup_path.exists():
|
|
1000
1092
|
raise HTTPException(status_code=404, detail=f"Backup not found: {folder_filename}")
|
|
1001
1093
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1094
|
+
if target_exists:
|
|
1095
|
+
launch_profile = _required_existing_target_launch_profile(
|
|
1096
|
+
target_namespace=target_namespace,
|
|
1097
|
+
)
|
|
1098
|
+
else:
|
|
1099
|
+
launch_profile = _backup_profile_from_request(
|
|
1100
|
+
namespace=target_namespace,
|
|
1101
|
+
profile=payload.launch_profile,
|
|
1102
|
+
)
|
|
1103
|
+
_assert_import_profile_has_no_internal_overlap(profile=launch_profile)
|
|
1104
|
+
_assert_import_profile_ports_do_not_conflict(
|
|
1105
|
+
target_namespace=target_namespace,
|
|
1106
|
+
launch_profile=launch_profile,
|
|
1107
|
+
)
|
|
1011
1108
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1109
|
+
target_is_active = target_namespace == ACTIVE_NAMESPACE
|
|
1110
|
+
if target_is_active:
|
|
1111
|
+
maintenance_service.enter_maintenance("Importing backup")
|
|
1112
|
+
try:
|
|
1113
|
+
_restore_import_to_target(
|
|
1114
|
+
backup_path=backup_path,
|
|
1115
|
+
target_database_path=target_database_path,
|
|
1116
|
+
backup_namespace=backup_namespace,
|
|
1117
|
+
target_namespace=target_namespace,
|
|
1118
|
+
launch_profile=launch_profile,
|
|
1119
|
+
)
|
|
1120
|
+
_reset_runtime_state_after_restore()
|
|
1121
|
+
finally:
|
|
1122
|
+
maintenance_service.exit_maintenance()
|
|
1123
|
+
_schedule_server_restart_after_restore(delay_seconds=0.5)
|
|
1124
|
+
else:
|
|
1125
|
+
_restore_import_to_target(
|
|
1126
|
+
backup_path=backup_path,
|
|
1127
|
+
target_database_path=target_database_path,
|
|
1128
|
+
backup_namespace=backup_namespace,
|
|
1129
|
+
target_namespace=target_namespace,
|
|
1130
|
+
launch_profile=launch_profile,
|
|
1131
|
+
)
|
|
1023
1132
|
|
|
1024
1133
|
return BackupRestoreResponse(
|
|
1025
1134
|
backup_id=payload.backup_id,
|
|
@@ -1027,7 +1136,7 @@ def import_backup(
|
|
|
1027
1136
|
backup_filename=payload.backup_filename,
|
|
1028
1137
|
backup_namespace=backup_namespace,
|
|
1029
1138
|
target_namespace=target_namespace,
|
|
1030
|
-
active_namespace_restarted=
|
|
1031
|
-
open_namespace_suggested=
|
|
1139
|
+
active_namespace_restarted=target_is_active,
|
|
1140
|
+
open_namespace_suggested=not target_is_active,
|
|
1032
1141
|
message="Backup imported successfully",
|
|
1033
1142
|
)
|
|
@@ -34,8 +34,10 @@ from app.security.encryption import set_encryption_required
|
|
|
34
34
|
from app.server_runtime import resolve_mcp_agent_public_origin
|
|
35
35
|
from app.server_runtime import resolve_https_redirect_url
|
|
36
36
|
from app.server_runtime import resolve_request_host_for_https_redirect
|
|
37
|
+
from app.server_runtime import validate_namespace
|
|
37
38
|
from app.services.exception_capture import CapturedExceptionContext
|
|
38
39
|
from app.services.namespace_deletion_jobs import load_namespace_deletion_job
|
|
40
|
+
from app.services.namespace_rename_jobs import load_namespace_rename_job
|
|
39
41
|
from app.services.namespace_switcher import build_namespace_catalog
|
|
40
42
|
from app.services.namespace_switcher import open_or_launch_namespace
|
|
41
43
|
from app.services.diagnostics import configure_process_diagnostics
|
|
@@ -435,36 +437,17 @@ async def maintenance_page(request: Request):
|
|
|
435
437
|
)
|
|
436
438
|
|
|
437
439
|
|
|
438
|
-
def _build_namespace_deleted_links(*, job_id: str,
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
raise RuntimeError("Namespace catalog entry must be an object")
|
|
450
|
-
namespace = entry["namespace"]
|
|
451
|
-
if not isinstance(namespace, str) or namespace == "":
|
|
452
|
-
raise RuntimeError("Namespace catalog entry missing namespace")
|
|
453
|
-
if namespace == deleted_namespace:
|
|
454
|
-
continue
|
|
455
|
-
query = urlencode({"job": job_id, "namespace": namespace})
|
|
456
|
-
link_meta = "Open namespace"
|
|
457
|
-
if namespace == ACTIVE_NAMESPACE:
|
|
458
|
-
link_meta = "Already running"
|
|
459
|
-
links.append(
|
|
460
|
-
{
|
|
461
|
-
"namespace": namespace,
|
|
462
|
-
"label": namespace,
|
|
463
|
-
"meta": link_meta,
|
|
464
|
-
"href": f"/namespace-deleted/open?{query}",
|
|
465
|
-
}
|
|
466
|
-
)
|
|
467
|
-
return links
|
|
440
|
+
def _build_namespace_deleted_links(*, job_id: str, redirect_namespace: str) -> list[dict[str, str]]:
|
|
441
|
+
normalized_redirect_namespace = validate_namespace(namespace=redirect_namespace)
|
|
442
|
+
query = urlencode({"job": job_id, "namespace": normalized_redirect_namespace})
|
|
443
|
+
return [
|
|
444
|
+
{
|
|
445
|
+
"namespace": normalized_redirect_namespace,
|
|
446
|
+
"label": normalized_redirect_namespace,
|
|
447
|
+
"meta": "Selected destination",
|
|
448
|
+
"href": f"/namespace-deleted/open?{query}",
|
|
449
|
+
}
|
|
450
|
+
]
|
|
468
451
|
|
|
469
452
|
|
|
470
453
|
def _resolve_catalog_profile(*, namespace: str) -> tuple[int, int | None, int]:
|
|
@@ -543,7 +526,7 @@ async def namespace_deleted_page(request: Request):
|
|
|
543
526
|
template = templates.get_template("namespace_deleted.html")
|
|
544
527
|
namespace_links = _build_namespace_deleted_links(
|
|
545
528
|
job_id=job_record["job_id"],
|
|
546
|
-
|
|
529
|
+
redirect_namespace=job_record["redirect_namespace"],
|
|
547
530
|
)
|
|
548
531
|
page_state = json.dumps(
|
|
549
532
|
{
|
|
@@ -551,6 +534,7 @@ async def namespace_deleted_page(request: Request):
|
|
|
551
534
|
"deletedNamespace": job_record["deleted_namespace"],
|
|
552
535
|
"initialStatus": job_record["status"],
|
|
553
536
|
"initialError": job_record["error"],
|
|
537
|
+
"redirectNamespace": job_record["redirect_namespace"],
|
|
554
538
|
}
|
|
555
539
|
)
|
|
556
540
|
return template.render(
|
|
@@ -588,7 +572,10 @@ async def namespace_deleted_open_page(request: Request):
|
|
|
588
572
|
return HTMLResponse(f"Namespace deletion job not found: {job_id}", status_code=404)
|
|
589
573
|
if job_record["status"] == "pending":
|
|
590
574
|
return HTMLResponse("Namespace deletion is still in progress", status_code=409)
|
|
591
|
-
if
|
|
575
|
+
if (
|
|
576
|
+
namespace == job_record["deleted_namespace"]
|
|
577
|
+
and namespace != job_record["redirect_namespace"]
|
|
578
|
+
):
|
|
592
579
|
return HTMLResponse("Deleted namespace is unavailable", status_code=400)
|
|
593
580
|
|
|
594
581
|
launch_capture = CapturedExceptionContext(
|
|
@@ -618,6 +605,75 @@ async def namespace_deleted_open_page(request: Request):
|
|
|
618
605
|
return response
|
|
619
606
|
|
|
620
607
|
|
|
608
|
+
@app.get("/namespace-renamed", response_class=HTMLResponse)
|
|
609
|
+
async def namespace_renamed_page(request: Request):
|
|
610
|
+
job_id = request.query_params.get("job")
|
|
611
|
+
if not isinstance(job_id, str) or job_id.strip() == "":
|
|
612
|
+
return HTMLResponse("Missing namespace rename job", status_code=400)
|
|
613
|
+
job_record_capture = CapturedExceptionContext(
|
|
614
|
+
RuntimeError,
|
|
615
|
+
TypeError,
|
|
616
|
+
ValueError,
|
|
617
|
+
FileNotFoundError,
|
|
618
|
+
)
|
|
619
|
+
job_record: dict[str, object] | None = None
|
|
620
|
+
with job_record_capture:
|
|
621
|
+
job_record = load_namespace_rename_job(job_id=job_id)
|
|
622
|
+
if job_record_capture.captured_exception is not None:
|
|
623
|
+
exc = job_record_capture.captured_exception
|
|
624
|
+
return HTMLResponse(str(exc), status_code=400)
|
|
625
|
+
if job_record is None:
|
|
626
|
+
return HTMLResponse(f"Namespace rename job not found: {job_id}", status_code=404)
|
|
627
|
+
|
|
628
|
+
page_state = json.dumps(
|
|
629
|
+
{
|
|
630
|
+
"jobId": job_record["job_id"],
|
|
631
|
+
"sourceNamespace": job_record["source_namespace"],
|
|
632
|
+
"targetNamespace": job_record["target_namespace"],
|
|
633
|
+
"initialStatus": job_record["status"],
|
|
634
|
+
"initialError": job_record["error"],
|
|
635
|
+
}
|
|
636
|
+
)
|
|
637
|
+
template = templates.get_template("namespace_renamed.html")
|
|
638
|
+
return template.render(
|
|
639
|
+
request=request,
|
|
640
|
+
version=VERSION,
|
|
641
|
+
asset_version=ASSET_VERSION,
|
|
642
|
+
page_title="MetaList - Namespace Renamed",
|
|
643
|
+
source_namespace=job_record["source_namespace"],
|
|
644
|
+
target_namespace=job_record["target_namespace"],
|
|
645
|
+
page_state_json=page_state,
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
@app.get("/namespace-renamed/open")
|
|
650
|
+
async def namespace_renamed_open_page(request: Request):
|
|
651
|
+
job_id = request.query_params.get("job")
|
|
652
|
+
if not isinstance(job_id, str) or job_id.strip() == "":
|
|
653
|
+
return HTMLResponse("Missing namespace rename job", status_code=400)
|
|
654
|
+
job_record_capture = CapturedExceptionContext(
|
|
655
|
+
RuntimeError,
|
|
656
|
+
TypeError,
|
|
657
|
+
ValueError,
|
|
658
|
+
FileNotFoundError,
|
|
659
|
+
)
|
|
660
|
+
job_record: dict[str, object] | None = None
|
|
661
|
+
with job_record_capture:
|
|
662
|
+
job_record = load_namespace_rename_job(job_id=job_id)
|
|
663
|
+
if job_record_capture.captured_exception is not None:
|
|
664
|
+
exc = job_record_capture.captured_exception
|
|
665
|
+
return HTMLResponse(str(exc), status_code=400)
|
|
666
|
+
if job_record is None:
|
|
667
|
+
return HTMLResponse(f"Namespace rename job not found: {job_id}", status_code=404)
|
|
668
|
+
if job_record["status"] != "succeeded":
|
|
669
|
+
return HTMLResponse("Namespace rename is not complete", status_code=409)
|
|
670
|
+
if ACTIVE_NAMESPACE != job_record["target_namespace"]:
|
|
671
|
+
return HTMLResponse("Renamed namespace is not running here", status_code=409)
|
|
672
|
+
response = RedirectResponse(url="/?force_reauth=1", status_code=307)
|
|
673
|
+
clear_auth_cookie(response=response)
|
|
674
|
+
return response
|
|
675
|
+
|
|
676
|
+
|
|
621
677
|
@app.get("/locked", response_class=HTMLResponse)
|
|
622
678
|
async def locked_page(request: Request, db: Annotated[SafeSession, Depends(get_db)]):
|
|
623
679
|
"""Render a dedicated locked screen when a session is invalidated."""
|
|
@@ -32,6 +32,7 @@ _DEFAULT_KEY_PATH = _DEFAULT_DATABASE_DIRECTORY / "certs" / "metalist-key.pem"
|
|
|
32
32
|
_DEFAULT_RUNTIME_DIRECTORY = Path(tempfile.gettempdir()) / "metalist-runtime"
|
|
33
33
|
_DEFAULT_NAMESPACES_DIRECTORY_NAME = "namespaces"
|
|
34
34
|
_DEFAULT_NAMESPACE_DELETE_JOBS_DIRECTORY_NAME = "namespace-delete-jobs"
|
|
35
|
+
_DEFAULT_NAMESPACE_RENAME_JOBS_DIRECTORY_NAME = "namespace-rename-jobs"
|
|
35
36
|
_DEFAULT_LOGS_DIRECTORY_NAME = "logs"
|
|
36
37
|
_DEFAULT_NAMESPACE = "default"
|
|
37
38
|
_DEFAULT_HTTP_PORT = 8000
|
|
@@ -126,6 +127,10 @@ def resolve_namespace_delete_jobs_directory() -> Path:
|
|
|
126
127
|
return _DEFAULT_RUNTIME_DIRECTORY / _DEFAULT_NAMESPACE_DELETE_JOBS_DIRECTORY_NAME
|
|
127
128
|
|
|
128
129
|
|
|
130
|
+
def resolve_namespace_rename_jobs_directory() -> Path:
|
|
131
|
+
return _DEFAULT_RUNTIME_DIRECTORY / _DEFAULT_NAMESPACE_RENAME_JOBS_DIRECTORY_NAME
|
|
132
|
+
|
|
133
|
+
|
|
129
134
|
def resolve_runtime_logs_directory() -> Path:
|
|
130
135
|
return _DEFAULT_DATABASE_DIRECTORY / _DEFAULT_LOGS_DIRECTORY_NAME
|
|
131
136
|
|