🔍 Code Extractor

class ControlledDocApp

Maturity: 52

A standalone Panel web application class that provides a complete controlled document management system with user authentication, navigation, and document lifecycle management features.

File:
/tf/active/vicechatdev/panel_app.py
Lines:
45 - 390
Complexity:
complex

Purpose

ControlledDocApp serves as the main application container for a controlled document management system. It manages user authentication, navigation between different views (dashboard, document creation/editing, reviews, administration), and integrates with the underlying ControlledDocSystem. The class handles the complete application lifecycle from login to logout, manages UI state, and provides role-based access control for different features. It uses Panel's MaterialTemplate for a modern web interface with sidebar navigation.

Source Code

class ControlledDocApp:
    """
    Standalone Panel application for the Controlled Document System.
    
    This class provides a complete Panel application with navigation,
    user authentication, and all document management features.
    """
    
    def __init__(self):
        """Initialize the controlled document application."""
        # State variables
        self.current_view = None
        self.current_document_id = None
        self.doc_system = None
        self.user = None
        self.is_authenticated = False
        
        # Build login UI first
        self._build_login_ui()
        
        # Create placeholder for main UI (will be built after login)
        self.main_ui = pn.pane.Markdown("Please log in to access the system")
        
        # Create application layout with template
        self.template = pn.template.MaterialTemplate(
            title="Controlled Document Management System",
            header_background="#0072B5",
            sidebar_width=300
        )
        
        # Add login panel to template
        self.main_window  = pn.Column()
        self.sidebar_window = pn.Column()
        self.template.main.append(self.main_window)
        self.template.sidebar.append(self.sidebar_window)
        self.main_window.append(self.login_panel)
        
        # Setup event handlers for navigation
        self._setup_navigation_handlers()
    
    def _build_login_ui(self):
        """Build the login user interface."""
        # Create login form
        self.username_input = pn.widgets.TextInput(
            name="Username",
            placeholder="Enter your username"
        )
        
        self.password_input = pn.widgets.PasswordInput(
            name="Password",
            placeholder="Enter your password"
        )
        
        login_button = pn.widgets.Button(
            name="Login",
            button_type="primary"
        )
        login_button.on_click(self._handle_login)
        
        self.login_message = pn.pane.Alert(
            "Please log in with your credentials",
            alert_type="info"
        )
        
        # Assemble login panel
        self.login_panel = pn.Card(
            pn.Column(
                pn.pane.Markdown("## Login"),
                self.login_message,
                self.username_input,
                self.password_input,
                login_button,
                width=400
            ),
            title="Controlled Document System",
            width=500
        )
    
    def _handle_login(self, event):
        """Handle login button click."""
        username = self.username_input.value
        password = self.password_input.value
        
        if not username or not password:
            self.login_message.object = "Please enter both username and password"
            self.login_message.alert_type = "danger"
            return
        
        # For demo purposes, accept any login
        # In a real app, this would verify credentials against a database
        self._login_success({
            "id": username,
            "name": f"Demo User ({username})",
            "email": f"{username}@example.com",
            "department": "QA",
            "roles": ["admin", "Quality Manager"]  # Use Role enum names for full access
        })
    
    def _login_success(self, user_data):
        """Handle successful login."""
        # Store user data
        self.user = user_data
        self.is_authenticated = True
        
        try:
            # Ensure document types are created in the database before initializing the document system
            self._ensure_document_types_exist()
            
            # Initialize the document system with the authenticated user
            # Force schema initialization to ensure database is properly set up
            self.doc_system = ControlledDocSystem(
                user=self.user,
                initialize_schema=True,
                force_schema_init=True
            )
            
            # Build the main UI
            self._build_main_ui()
            
            # Switch to main UI
            self.main_window.clear()
            self.main_window.append(self.main_ui)
            
            # Update sidebar
            self._update_sidebar()
            
            print(f"User {self.user['name']} logged in successfully")
        except Exception as e:
            # If document system initialization fails, show error message
            self.login_message.object = f"Error initializing document system: {str(e)}"
            self.login_message.alert_type = "danger"
            logger.error(f"Login error: {str(e)}")
            
            # Reset user state
            self.user = None
            self.is_authenticated = False
    
    def _ensure_document_types_exist(self):
        """Ensure document types from configuration exist in the database."""
        try:
            # Call the new function to ensure document types exist
            ensure_document_types(
                DOCUMENT_DB["uri"],
                DOCUMENT_DB["user"],
                DOCUMENT_DB["password"]
            )
            logger.info("Document types updated successfully")
        except Exception as e:
            logger.error(f"Error ensuring document types: {str(e)}")
            raise
    
    def _build_main_ui(self):
        """Build the main UI after successful login."""
        # Get the UI from the document system
        #print(f"getting main UI")
        self.main_ui = self.doc_system.get_ui()
        
        # Set current view to the document dashboard
        self.current_view = "dashboard"
    def _update_sidebar(self):
        """Update the sidebar with user information and navigation."""
        # Clear existing sidebar
        self.sidebar_window.clear()
        
        # Add user information
        self.sidebar_window.append(pn.pane.Markdown(f"## Welcome, {self.user['name']}"))
        self.sidebar_window.append(pn.pane.Markdown(f"Department: {self.user['department']}"))
        self.sidebar_window.append(pn.layout.Divider())
        
        # Add navigation
        self.sidebar_window.append(pn.pane.Markdown("### Navigation"))
        
        # Dashboard button
        dashboard_btn = pn.widgets.Button(
            name="Document Dashboard",
            button_type="primary" if self.current_view == "dashboard" else "default",
            width=250
        )
        dashboard_btn.on_click(self._navigate_to_dashboard)
        self.sidebar_window.append(dashboard_btn)
        
        # Import permission classes
        from controlled_doc_system.utils.permissions import Permission, check_permission, check_any_permission
        
        # New document button
        new_doc_btn = pn.widgets.Button(
            name="Create New Document",
            button_type="success",
            width=250,
            disabled=not check_permission(self.user.get('id'), Permission.CREATE_DOCUMENT)
        )
        new_doc_btn.on_click(self._navigate_to_new_document)
        self.sidebar_window.append(new_doc_btn)
        
        # Reviews button
        reviews_btn = pn.widgets.Button(
            name="My Reviews",
            button_type="primary" if self.current_view == "reviews" else "default",
            width=250
        )
        reviews_btn.on_click(self._navigate_to_reviews)
        self.sidebar_window.append(reviews_btn)
        
        # Admin button (only for admin users)
        # Check for any admin permissions
        admin_permissions = [
            Permission.MANAGE_USERS,
            Permission.CONFIGURE_SYSTEM,
            Permission.CREATE_TEMPLATE,
            Permission.EDIT_TEMPLATE,
            Permission.DELETE_TEMPLATE
        ]
        
        if check_any_permission(self.user.get('id'), admin_permissions):
            admin_btn = pn.widgets.Button(
                name="Administration",
                button_type="primary" if self.current_view == "admin" else "default",
                width=250
            )
            admin_btn.on_click(self._navigate_to_admin)
            self.sidebar_window.append(admin_btn)
        
        self.sidebar_window.append(pn.layout.Divider())
        
        # Logout button
        logout_btn = pn.widgets.Button(
            name="Logout",
            button_type="danger",
            width=250
        )
        logout_btn.on_click(self._handle_logout)
        self.sidebar_window.append(logout_btn)
    
    def _setup_navigation_handlers(self):
        """Set up handlers for navigation buttons."""
        # These handlers will be assigned to buttons in the sidebar
        pass
    
    def _navigate_to_dashboard(self, event=None):
        """Navigate to the document dashboard."""
        if self.current_view == "dashboard":
            return
            
        self.current_view = "dashboard"
        
        # Update UI
        self.main_window.clear()
        self.main_window.append(self.doc_system.get_ui())
        
        # Update sidebar
        self._update_sidebar()
    
    def _navigate_to_new_document(self, event=None):
        """Navigate to the new document form."""
        self.current_view = "document_form"
        self.current_document_id = None
        
        # Create document form
        doc_form = DocumentForm(self.doc_system)
        
        # Update UI
        self.main_window.clear()
        self.main_window.append(doc_form.get_panel())
        
        # Update sidebar
        self._update_sidebar()
    
    def _navigate_to_edit_document(self, document_id):
        """
        Navigate to the document edit form.
        
        Args:
            document_id: ID of the document to edit
        """
        self.current_view = "document_form"
        self.current_document_id = document_id
        
        # Create document form for existing document
        doc_form = DocumentForm(self.doc_system, document_id=document_id)
        
        # Update UI
        self.main_window.clear()
        self.main_window.append(doc_form.get_panel())
        
        # Update sidebar
        self._update_sidebar()
    
    def _navigate_to_reviews(self, event=None):
        """Navigate to the reviews dashboard."""
        if self.current_view == "reviews":
            return
            
        self.current_view = "reviews"
        
        # Update UI - show the reviews tab
        self.main_window.clear()
        self.doc_system.main_tabs.active = 1  # Select the Reviews tab
        self.main_window.append(self.doc_system.get_ui())
        
        # Update sidebar
        self._update_sidebar()
    
    def _navigate_to_admin(self, event=None):
        """Navigate to the admin dashboard."""
        if self.current_view == "admin":
            return
            
        self.current_view = "admin"
        
        # Update UI - show the admin tab
        self.main_window.clear()
        self.doc_system.main_tabs.active = 2  # Select the Admin tab
        self.main_window.append(self.doc_system.get_ui())
        
        # Update sidebar
        self._update_sidebar()
    
    def _handle_logout(self, event):
        """Handle logout button click."""
        # Clear user data
        self.user = None
        self.is_authenticated = False
        
        # Clean up document system
        if self.doc_system:
            self.doc_system.close()
            self.doc_system = None
        
        # Reset UI to login screen
        self.main_window.clear()
        self.main_window.append(self.login_panel)
        
        # Clear sidebar
        self.sidebar_window.clear()
        
        # Reset login form
        self.username_input.value = ""
        self.password_input.value = ""
        self.login_message.object = "You have been logged out successfully"
        self.login_message.alert_type = "success"
        
        logger.info("User logged out")
    
    def get_app(self):
        """Get the Panel application for serving."""
        return self.template

Parameters

Name Type Default Kind
bases - -

Parameter Details

__init__: No parameters required. The constructor initializes all state variables, builds the login UI, creates the Panel template with sidebar, and sets up navigation handlers. The application starts in an unauthenticated state showing the login panel.

Return Value

The class constructor returns a ControlledDocApp instance. The get_app() method returns a Panel MaterialTemplate object that can be served as a web application. Navigation methods return None but update the UI state as side effects. The _handle_login method processes authentication and initializes the document system on success.

Class Interface

Methods

__init__(self)

Purpose: Initialize the controlled document application with login UI, template, and state variables

Returns: None - initializes the ControlledDocApp instance

_build_login_ui(self)

Purpose: Build the login user interface with username, password inputs and login button

Returns: None - creates and stores login_panel as instance attribute

_handle_login(self, event)

Purpose: Handle login button click event, validate credentials, and initialize the document system

Parameters:

  • event: Panel button click event object

Returns: None - calls _login_success on valid credentials or updates login_message on error

_login_success(self, user_data: dict)

Purpose: Handle successful login by storing user data, initializing document system, and building main UI

Parameters:

  • user_data: Dictionary containing user information with keys: id, name, email, department, roles

Returns: None - updates application state and UI on success, shows error message on failure

_ensure_document_types_exist(self)

Purpose: Ensure document types from configuration exist in the database before system initialization

Returns: None - raises exception if document types cannot be created

_build_main_ui(self)

Purpose: Build the main UI after successful login by getting UI from document system

Returns: None - updates main_ui attribute and sets current_view to 'dashboard'

_update_sidebar(self)

Purpose: Update the sidebar with user information, navigation buttons, and logout option based on permissions

Returns: None - rebuilds sidebar_window with current user context and navigation state

_setup_navigation_handlers(self)

Purpose: Set up handlers for navigation buttons (currently a placeholder method)

Returns: None - navigation handlers are assigned directly to buttons in _update_sidebar

_navigate_to_dashboard(self, event=None)

Purpose: Navigate to the document dashboard view

Parameters:

  • event: Optional Panel button click event object

Returns: None - updates main_window with dashboard UI and refreshes sidebar

_navigate_to_new_document(self, event=None)

Purpose: Navigate to the new document creation form

Parameters:

  • event: Optional Panel button click event object

Returns: None - creates DocumentForm and updates main_window with form UI

_navigate_to_edit_document(self, document_id: str)

Purpose: Navigate to the document edit form for an existing document

Parameters:

  • document_id: ID of the document to edit

Returns: None - creates DocumentForm with document_id and updates main_window

_navigate_to_reviews(self, event=None)

Purpose: Navigate to the reviews dashboard showing documents pending review

Parameters:

  • event: Optional Panel button click event object

Returns: None - switches to reviews tab and updates UI

_navigate_to_admin(self, event=None)

Purpose: Navigate to the administration dashboard for system configuration

Parameters:

  • event: Optional Panel button click event object

Returns: None - switches to admin tab and updates UI

_handle_logout(self, event)

Purpose: Handle logout button click by cleaning up resources and returning to login screen

Parameters:

  • event: Panel button click event object

Returns: None - clears user data, closes document system, and resets UI to login panel

get_app(self) -> pn.template.MaterialTemplate

Purpose: Get the Panel application template for serving

Returns: Panel MaterialTemplate object that can be served as a web application

Attributes

Name Type Description Scope
current_view str | None Tracks the currently active view ('dashboard', 'document_form', 'reviews', 'admin', or None) instance
current_document_id str | None ID of the document currently being edited, or None if creating new document instance
doc_system ControlledDocSystem | None Instance of the document management system, initialized after successful login instance
user dict | None Dictionary containing authenticated user data (id, name, email, department, roles) instance
is_authenticated bool Flag indicating whether a user is currently authenticated instance
username_input pn.widgets.TextInput Panel text input widget for username entry instance
password_input pn.widgets.PasswordInput Panel password input widget for password entry instance
login_message pn.pane.Alert Panel alert widget for displaying login status messages instance
login_panel pn.Card Panel card containing the complete login form UI instance
main_ui pn.pane.Markdown | Panel component The main UI component displayed after login, initially a placeholder instance
template pn.template.MaterialTemplate Panel MaterialTemplate providing the overall application layout with header and sidebar instance
main_window pn.Column Panel column container for the main content area instance
sidebar_window pn.Column Panel column container for the sidebar navigation area instance

Dependencies

  • panel
  • param
  • pandas
  • logging
  • pathlib
  • argparse
  • warnings
  • controlled_doc_system.panel_integration
  • controlled_doc_system.panel_ui.document_form
  • controlled_doc_system.utils.permissions
  • controlled_doc_system.core.db_schema_init
  • controlled_doc_system.cdoc_config
  • CDocs.utils.sharing_validator

Required Imports

import panel as pn
import param
import pandas as pd
import os
import sys
import logging
from pathlib import Path
import argparse
import warnings
from controlled_doc_system.panel_integration import ControlledDocSystem
from controlled_doc_system.panel_ui.document_form import DocumentForm
from controlled_doc_system.utils.permissions import Permission, Role, check_permission, check_any_permission
from controlled_doc_system.core.db_schema_init import initialize_db_schema, ensure_document_types
from controlled_doc_system.cdoc_config import DOCUMENT_DB
from CDocs.utils.sharing_validator import check_document_permissions_on_startup

Conditional/Optional Imports

These imports are only needed under specific conditions:

from controlled_doc_system.utils.permissions import Permission, check_permission, check_any_permission

Condition: imported within _update_sidebar method for permission checking

Required (conditional)

Usage Example

# Create and serve the application
import panel as pn
from controlled_doc_app import ControlledDocApp

# Initialize Panel extension
pn.extension('tabulator', notifications=True)

# Create the application
app = ControlledDocApp()

# Get the Panel template for serving
template = app.get_app()

# Serve the application
# Option 1: In a script
template.servable()

# Option 2: Programmatically
pn.serve(template, port=5006, show=True)

# The application will show a login screen
# After login with any username/password (demo mode),
# users can navigate between:
# - Document Dashboard (view and manage documents)
# - Create New Document (if user has CREATE_DOCUMENT permission)
# - My Reviews (review assigned documents)
# - Administration (if user has admin permissions)
# - Logout (return to login screen)

Best Practices

  • Always call get_app() to retrieve the Panel template for serving, not the class instance directly
  • The application manages its own state through instance variables - avoid external state manipulation
  • Login is currently in demo mode (accepts any credentials) - implement proper authentication for production
  • The document system is initialized only after successful login to ensure proper user context
  • Always handle logout properly to clean up resources (doc_system.close() is called automatically)
  • Navigation methods update both main_window and sidebar_window - don't modify these directly
  • The current_view attribute tracks the active view - use navigation methods to change views
  • Permission checks are performed when building the sidebar - ensure user object has 'id' and 'roles' fields
  • Database connection errors during login are caught and displayed to the user
  • The template uses MaterialTemplate with a fixed sidebar width of 300px
  • Document types must exist in the database before the system can be used - _ensure_document_types_exist() handles this
  • The application maintains a single ControlledDocSystem instance per session - it's recreated on each login

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class CDocsApp 85.2% similar

    Panel application for the CDocs Controlled Document System. This class provides a complete Panel application with navigation, user authentication, and all document management features.

    From: /tf/active/vicechatdev/cdocs_panel_app.py
  • function main_v10 60.2% similar

    Entry point function that initializes and serves the CDocs Panel web application with configurable port and debug mode options.

    From: /tf/active/vicechatdev/cdocs_panel_app.py
  • function controlled_docs_navigation 60.1% similar

    Navigation controller for a Streamlit-based controlled documents module that manages document and review dashboards with URL parameter-based routing.

    From: /tf/active/vicechatdev/datacapture_integrated.py
  • function create_document 59.1% similar

    Creates a new controlled document in a document management system with versioning, audit trails, and optional initial content.

    From: /tf/active/vicechatdev/document_controller_backup.py
  • class User 56.9% similar

    A user management class that handles authentication, authorization, user profiles, preferences, file management, and logging for a Panel-based web application with Neo4j backend.

    From: /tf/active/vicechatdev/userclass.py
← Back to Browse