🔍 Code Extractor

class ControlledDocApp

Maturity: 56

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 including login/logout, UI state management, and permission-based access control. 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 instance with login panel displayed

_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 initiate login process

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 initializing document system and building main UI

Parameters:

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

Returns: None - updates authentication state and switches to main UI, or shows error on failure

_ensure_document_types_exist(self)

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

Returns: None - calls ensure_document_types function or raises exception on error

_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 permission-based access controls

Returns: None - clears and repopulates sidebar_window with navigation elements

_setup_navigation_handlers(self)

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

Returns: None - reserved for future navigation handler setup

_navigate_to_dashboard(self, event=None)

Purpose: Navigate to the document dashboard view

Parameters:

  • event: Optional Panel button click event object

Returns: None - updates current_view, main_window, and 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 UI to show creation form

_navigate_to_edit_document(self, document_id: str)

Purpose: Navigate to the document edit form for a specific document

Parameters:

  • document_id: ID of the document to edit

Returns: None - creates DocumentForm with document_id and updates UI to show edit form

_navigate_to_reviews(self, event=None)

Purpose: Navigate to the reviews dashboard showing pending document reviews

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 management

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 clearing user data and returning to login screen

Parameters:

  • event: Panel button click event object

Returns: None - resets authentication state, closes doc_system, and shows login panel

get_app(self) -> pn.template.MaterialTemplate

Purpose: Get the Panel application template for serving as a web application

Returns: Panel MaterialTemplate object that can be served with pn.serve() or made servable

Attributes

Name Type Description Scope
current_view str or None Tracks the currently active view ('dashboard', 'document_form', 'reviews', 'admin', or None) instance
current_document_id str or None Stores the ID of the document currently being edited, None for new documents instance
doc_system ControlledDocSystem or None The main document management system instance, initialized after successful login instance
user dict or 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 in login form instance
password_input pn.widgets.PasswordInput Panel password input widget for password entry in login form instance
login_message pn.pane.Alert Panel alert pane for displaying login status messages and errors instance
login_panel pn.Card Panel card containing the complete login form UI instance
main_ui Panel component The main UI component displayed after login, initially a placeholder markdown pane instance
template pn.template.MaterialTemplate The Panel MaterialTemplate that serves as the application container with header and sidebar instance
main_window pn.Column Panel column container for the main content area, appended to template.main instance
sidebar_window pn.Column Panel column container for the sidebar navigation, appended to template.sidebar 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

Usage Example

import panel as pn
from controlled_doc_system.cdoc_config import DOCUMENT_DB

# Initialize Panel
pn.extension()

# Create the application
app = ControlledDocApp()

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

# Serve the application
# pn.serve(template, port=5006, show=True)

# Or in a Jupyter notebook:
# template.servable()

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

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 doc_system is initialized only after successful login and should be accessed only when is_authenticated is True
  • Always call the close() method on doc_system during logout to properly clean up resources
  • Navigation methods update both main_window and sidebar_window - don't modify these directly
  • The current_view attribute tracks the active view and prevents redundant navigation
  • Document types must exist in the database before document system initialization
  • Permission checks are performed in _update_sidebar to show/hide navigation buttons based on user roles
  • Error handling during login will reset authentication state and display error messages
  • The template uses MaterialTemplate with a fixed sidebar width of 300px and custom header color
  • Method call order: __init__ -> user logs in -> _handle_login -> _login_success -> _ensure_document_types_exist -> _build_main_ui -> navigation methods
  • State management: current_view, current_document_id, doc_system, user, and is_authenticated track application state
  • Side effects: All navigation methods clear and repopulate main_window and update sidebar_window

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class CDocsApp 89.1% similar

    Panel-based web application class for the CDocs Controlled Document System that provides a complete UI with navigation, authentication, and document management features.

    From: /tf/active/vicechatdev/cdocs_panel_app.py
  • class ControlledDocumentApp 80.3% similar

    Main application class for the Controlled Document Management System. This class initializes all components and provides the main Panel interface for the application. It is designed to be served via `panel serve` command and integrates with the existing datacapture application.

    From: /tf/active/vicechatdev/CDocs/main.py
  • class ControlledDocumentFlaskApp 69.0% similar

    Main Flask application class for Controlled Document Management System.

    From: /tf/active/vicechatdev/CDocs/main_flask.py
  • class DocumentAccessControls 66.3% similar

    A Panel-based UI component that manages document access controls, providing view and edit buttons with role-based permissions and status indicators.

    From: /tf/active/vicechatdev/CDocs/ui/components/document_access_controls.py
  • class DocumentDashboard 64.8% similar

    Dashboard for viewing and managing controlled documents.

    From: /tf/active/vicechatdev/CDocs/ui/document_dashboard.py
← Back to Browse