Multi-instance Silo configuration UI #15

Closed
opened 2026-02-05 18:29:20 +00:00 by forbes · 1 comment
Owner

Overview

Create a configuration UI for managing multiple Silo instances. Users should be able to add, edit, remove, and nickname Silo connections, with each instance appearing as a separate origin in the origin selector.

Parent Issue

Epic: #8 Unified File Origin System

Goals

  1. Allow users to configure multiple Silo instances
  2. Provide nicknames for quick identification (e.g., "Work", "Prod")
  3. Manage connection settings (URL, auth, SSL)
  4. Test connections before saving
  5. Integrate with Preferences dialog

Detailed Design

Origins Management Dialog

Accessible from "Manage Origins..." in origin selector dropdown:

┌─────────────────────────────────────────────────────────────────────┐
│ Manage File Origins                                           [X]  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Origins                                                            │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 📁 Local Files                              [Default]       │   │
│  │ ☁️ Work          https://silo.work.com      [Connected]     │   │
│  │ ☁️ Production    https://silo.prod.com      [Disconnected]  │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  [+ Add Silo]  [Edit]  [Remove]  [Set Default]                     │
│                                                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                          [Cancel]  [Apply]  [OK]   │
└─────────────────────────────────────────────────────────────────────┘

Add/Edit Silo Dialog

┌─────────────────────────────────────────────────────────────────────┐
│ Add Silo Instance                                             [X]  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Display Name:    [Work                              ]              │
│  Nickname:        [Work        ]  (shown in toolbar)               │
│                                                                     │
│  ── Connection ──────────────────────────────────────────────────  │
│                                                                     │
│  API URL:         [https://silo.work.example.com     ]              │
│                                                                     │
│  ── Authentication ──────���───────────────────────────────────────  │
│                                                                     │
│  API Token:       [********************************** ]  [Show]    │
│                   [Get token from Silo web interface]              │
│                                                                     │
│  ── SSL/TLS ─────────────────────────────────────────────────────  │
│                                                                     │
│  [✓] Verify SSL certificates                                       │
│  CA Certificate:  [                                  ]  [Browse]   │
│                   (Optional: custom CA for self-signed certs)      │
│                                                                     │
│  ────────────────────────────────────────────────────────────────  │
│                                                                     │
│  [Test Connection]     Status: ✓ Connected as "admin"              │
│                                                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                              [Cancel]     [Save]   │
└─────────────────────────────────────────────────────────────────────┘

Dialog Implementation

// src/Gui/OriginManagerDialog.h

class OriginManagerDialog : public QDialog {
    Q_OBJECT
public:
    explicit OriginManagerDialog(QWidget* parent = nullptr);
    
private Q_SLOTS:
    void onAddSilo();
    void onEditOrigin();
    void onRemoveOrigin();
    void onSetDefault();
    void onOriginSelectionChanged();
    
private:
    void populateOriginList();
    void updateButtonStates();
    
    QListWidget* m_originList;
    QPushButton* m_addButton;
    QPushButton* m_editButton;
    QPushButton* m_removeButton;
    QPushButton* m_defaultButton;
};

// src/Gui/SiloConfigDialog.h

class SiloConfigDialog : public QDialog {
    Q_OBJECT
public:
    explicit SiloConfigDialog(QWidget* parent = nullptr);
    SiloConfigDialog(const SiloConfig& existing, QWidget* parent = nullptr);
    
    SiloConfig getConfig() const;
    
private Q_SLOTS:
    void onTestConnection();
    void onBrowseCertificate();
    void onShowToken();
    void validateInput();
    
private:
    QLineEdit* m_nameEdit;
    QLineEdit* m_nicknameEdit;
    QLineEdit* m_urlEdit;
    QLineEdit* m_tokenEdit;
    QCheckBox* m_sslVerifyCheck;
    QLineEdit* m_certPathEdit;
    QLabel* m_statusLabel;
    QPushButton* m_testButton;
    QPushButton* m_saveButton;
};

Configuration Storage

struct SiloConfig {
    QString id;           // Unique ID: "silo-{uuid}"
    QString name;         // Display name: "Work Silo"
    QString nickname;     // Short name: "Work"
    QString apiUrl;       // "https://silo.example.com"
    QString apiToken;     // Auth token
    bool sslVerify;       // Verify SSL certs
    QString sslCertPath;  // Custom CA cert path
};

// Storage path:
// User parameter:BaseApp/Preferences/Origins/Silo/{id}/

Preferences Integration

Add "Origins" page to Preferences dialog:

// In preferences dialog setup
void PreferencesDialog::setupPages() {
    // ...existing pages...
    
    addPage(new OriginsPreferencePage(this), 
            tr("Origins"), 
            QIcon(":/icons/folder.svg"));
}

Migration from Old Config

Migrate existing single-instance Silo config:

void migrateOldSiloConfig() {
    auto oldParam = FreeCAD::ParamGet(
        "User parameter:BaseApp/Preferences/Mod/KindredSilo");
    
    QString oldUrl = oldParam.GetString("ApiUrl", "");
    if (oldUrl.isEmpty()) return;  // No old config
    
    auto newParam = FreeCAD::ParamGet(
        "User parameter:BaseApp/Preferences/Origins/Silo/default");
    
    // Migrate settings
    newParam.SetString("Id", "silo-default");
    newParam.SetString("Name", "Silo");
    newParam.SetString("Nickname", "Silo");
    newParam.SetString("ApiUrl", oldParam.GetString("ApiUrl", ""));
    newParam.SetString("ApiToken", oldParam.GetString("ApiToken", ""));
    newParam.SetBool("SslVerify", oldParam.GetBool("SslVerify", true));
    newParam.SetString("SslCertPath", oldParam.GetString("SslCertPath", ""));
    
    // Mark migration complete
    oldParam.SetBool("MigratedToOrigins", true);
}

Implementation Tasks

  • Create OriginManagerDialog class
  • Create SiloConfigDialog class
  • Implement origin list with status display
  • Implement Add/Edit/Remove functionality
  • Implement "Test Connection" feature
  • Add SSL certificate browsing
  • Create OriginsPreferencePage
  • Implement config migration from old format
  • Validate nickname uniqueness
  • Handle token security (mask display)
  • Add confirmation for remove action

Files to Create/Modify

  • src/Gui/OriginManagerDialog.h (new)
  • src/Gui/OriginManagerDialog.cpp (new)
  • src/Gui/SiloConfigDialog.h (new)
  • src/Gui/SiloConfigDialog.cpp (new)
  • src/Gui/OriginsPreferencePage.h (new)
  • src/Gui/OriginsPreferencePage.cpp (new)
  • src/Gui/DlgPreferences.cpp (add page)

Acceptance Criteria

  • Can add new Silo instances
  • Can edit existing Silo instances
  • Can remove Silo instances (with confirmation)
  • Can set default origin
  • Test connection works and shows status
  • Nicknames are validated for uniqueness
  • Token is masked by default
  • SSL certificate browsing works
  • Old config is migrated automatically
  • Origins appear in selector after adding

Dependencies

  • #9 Origin abstraction layer
  • #11 Silo origin adapter
  • #13 Origin selector widget

Blocking

None

## Overview Create a configuration UI for managing multiple Silo instances. Users should be able to add, edit, remove, and nickname Silo connections, with each instance appearing as a separate origin in the origin selector. ## Parent Issue Epic: #8 Unified File Origin System ## Goals 1. Allow users to configure multiple Silo instances 2. Provide nicknames for quick identification (e.g., "Work", "Prod") 3. Manage connection settings (URL, auth, SSL) 4. Test connections before saving 5. Integrate with Preferences dialog ## Detailed Design ### Origins Management Dialog Accessible from "Manage Origins..." in origin selector dropdown: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Manage File Origins [X] │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Origins │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 📁 Local Files [Default] │ │ │ │ ☁️ Work https://silo.work.com [Connected] │ │ │ │ ☁️ Production https://silo.prod.com [Disconnected] │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ [+ Add Silo] [Edit] [Remove] [Set Default] │ │ │ ├─────────────────────────────────────────────────────────────────────┤ │ [Cancel] [Apply] [OK] │ └─────────────────────────────────────────────────────────────────────┘ ``` ### Add/Edit Silo Dialog ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Add Silo Instance [X] │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Display Name: [Work ] │ │ Nickname: [Work ] (shown in toolbar) │ │ │ │ ── Connection ────────────────────────────────────────────────── │ │ │ │ API URL: [https://silo.work.example.com ] │ │ │ │ ── Authentication ──────���─────────────────────────────────────── │ │ │ │ API Token: [********************************** ] [Show] │ │ [Get token from Silo web interface] │ │ │ │ ── SSL/TLS ───────────────────────────────────────────────────── │ │ │ │ [✓] Verify SSL certificates │ │ CA Certificate: [ ] [Browse] │ │ (Optional: custom CA for self-signed certs) │ │ │ │ ──────────────────────────────────────────────────────────────── │ │ │ │ [Test Connection] Status: ✓ Connected as "admin" │ │ │ ├─────────────────────────────────────────────────────────────────────┤ │ [Cancel] [Save] │ └─────────────────────────────────────────────────────────────────────┘ ``` ### Dialog Implementation ```cpp // src/Gui/OriginManagerDialog.h class OriginManagerDialog : public QDialog { Q_OBJECT public: explicit OriginManagerDialog(QWidget* parent = nullptr); private Q_SLOTS: void onAddSilo(); void onEditOrigin(); void onRemoveOrigin(); void onSetDefault(); void onOriginSelectionChanged(); private: void populateOriginList(); void updateButtonStates(); QListWidget* m_originList; QPushButton* m_addButton; QPushButton* m_editButton; QPushButton* m_removeButton; QPushButton* m_defaultButton; }; // src/Gui/SiloConfigDialog.h class SiloConfigDialog : public QDialog { Q_OBJECT public: explicit SiloConfigDialog(QWidget* parent = nullptr); SiloConfigDialog(const SiloConfig& existing, QWidget* parent = nullptr); SiloConfig getConfig() const; private Q_SLOTS: void onTestConnection(); void onBrowseCertificate(); void onShowToken(); void validateInput(); private: QLineEdit* m_nameEdit; QLineEdit* m_nicknameEdit; QLineEdit* m_urlEdit; QLineEdit* m_tokenEdit; QCheckBox* m_sslVerifyCheck; QLineEdit* m_certPathEdit; QLabel* m_statusLabel; QPushButton* m_testButton; QPushButton* m_saveButton; }; ``` ### Configuration Storage ```cpp struct SiloConfig { QString id; // Unique ID: "silo-{uuid}" QString name; // Display name: "Work Silo" QString nickname; // Short name: "Work" QString apiUrl; // "https://silo.example.com" QString apiToken; // Auth token bool sslVerify; // Verify SSL certs QString sslCertPath; // Custom CA cert path }; // Storage path: // User parameter:BaseApp/Preferences/Origins/Silo/{id}/ ``` ### Preferences Integration Add "Origins" page to Preferences dialog: ```cpp // In preferences dialog setup void PreferencesDialog::setupPages() { // ...existing pages... addPage(new OriginsPreferencePage(this), tr("Origins"), QIcon(":/icons/folder.svg")); } ``` ### Migration from Old Config Migrate existing single-instance Silo config: ```cpp void migrateOldSiloConfig() { auto oldParam = FreeCAD::ParamGet( "User parameter:BaseApp/Preferences/Mod/KindredSilo"); QString oldUrl = oldParam.GetString("ApiUrl", ""); if (oldUrl.isEmpty()) return; // No old config auto newParam = FreeCAD::ParamGet( "User parameter:BaseApp/Preferences/Origins/Silo/default"); // Migrate settings newParam.SetString("Id", "silo-default"); newParam.SetString("Name", "Silo"); newParam.SetString("Nickname", "Silo"); newParam.SetString("ApiUrl", oldParam.GetString("ApiUrl", "")); newParam.SetString("ApiToken", oldParam.GetString("ApiToken", "")); newParam.SetBool("SslVerify", oldParam.GetBool("SslVerify", true)); newParam.SetString("SslCertPath", oldParam.GetString("SslCertPath", "")); // Mark migration complete oldParam.SetBool("MigratedToOrigins", true); } ``` ## Implementation Tasks - [ ] Create `OriginManagerDialog` class - [ ] Create `SiloConfigDialog` class - [ ] Implement origin list with status display - [ ] Implement Add/Edit/Remove functionality - [ ] Implement "Test Connection" feature - [ ] Add SSL certificate browsing - [ ] Create `OriginsPreferencePage` - [ ] Implement config migration from old format - [ ] Validate nickname uniqueness - [ ] Handle token security (mask display) - [ ] Add confirmation for remove action ## Files to Create/Modify - `src/Gui/OriginManagerDialog.h` (new) - `src/Gui/OriginManagerDialog.cpp` (new) - `src/Gui/SiloConfigDialog.h` (new) - `src/Gui/SiloConfigDialog.cpp` (new) - `src/Gui/OriginsPreferencePage.h` (new) - `src/Gui/OriginsPreferencePage.cpp` (new) - `src/Gui/DlgPreferences.cpp` (add page) ## Acceptance Criteria - [ ] Can add new Silo instances - [ ] Can edit existing Silo instances - [ ] Can remove Silo instances (with confirmation) - [ ] Can set default origin - [ ] Test connection works and shows status - [ ] Nicknames are validated for uniqueness - [ ] Token is masked by default - [ ] SSL certificate browsing works - [ ] Old config is migrated automatically - [ ] Origins appear in selector after adding ## Dependencies - #9 Origin abstraction layer - #11 Silo origin adapter - #13 Origin selector widget ## Blocking None
Author
Owner

Complete. Closing with code references:

  • src/Gui/OriginManagerDialog.h / .cpp (251 lines) — List view with Add/Edit/Remove/Set Default
  • src/Gui/OriginManager.cpp — Multi-origin registration, preference persistence, default origin selection
  • src/Gui/FileOriginPython.cpp — Python wrapper enables Silo addon to register multiple instances
  • src/Mod/Create/InitGui.py:60-75 — Silo first-start check and settings integration

Note: Silo instance configuration (API URL, token, SSL) is handled by the Silo Python addon, keeping the C++ layer origin-agnostic by design.

Complete. Closing with code references: - `src/Gui/OriginManagerDialog.h` / `.cpp` (251 lines) — List view with Add/Edit/Remove/Set Default - `src/Gui/OriginManager.cpp` — Multi-origin registration, preference persistence, default origin selection - `src/Gui/FileOriginPython.cpp` — Python wrapper enables Silo addon to register multiple instances - `src/Mod/Create/InitGui.py:60-75` — Silo first-start check and settings integration Note: Silo instance configuration (API URL, token, SSL) is handled by the Silo Python addon, keeping the C++ layer origin-agnostic by design.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kindred/create#15