🔍 Code Extractor

class ControlledDocumentApp_v1

Maturity: 32

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.

File:
/tf/active/vicechatdev/CDocs single class/main.py
Lines:
112 - 2509
Complexity:
moderate

Purpose

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.

Source Code

class ControlledDocumentApp(param.Parameterized):
    """
    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.
    """
    
    current_user = param.Parameter(default=None)
    current_view = param.String(default='dashboard')
    sidebar_collapsed = param.Boolean(default=False)
    
    # Add dialog initialization in the __init__ method
    def __init__(self, config_path=None, **params):
        """
        Initialize the application with optional configuration path.
        
        Parameters
        ----------
        config_path : str, optional
            Path to configuration file. If not provided, default configuration is used.
        """
        super().__init__(**params)
        self.app_name = "Controlled Document Management System"
        
        # Get version from settings or use default
        self.version = getattr(settings, 'VERSION', "1.0.0")
        self.debug = getattr(settings, 'DEBUG_MODE', False)
        
        # Add environment attribute to prevent errors
        self.environment = getattr(settings, 'ENVIRONMENT', 'Development')
        
        # Initialize logging
        self._setup_logging()
        logger.info(f"Initializing {self.app_name} v{self.version}")
        
        # Initialize notification area
        self.notification_area = pn.pane.HTML("")
        
        # Initialize database
        self._init_database()
        
        # Initialize Panel template and UI
        self.template = self._create_panel_template()
        self.notification_area = pn.pane.Markdown("", width=600)
        
        # Main content area
        #self.main_content = pn.Column(sizing_mode='stretch_width')
        
        # Notification manager
        self.notification_manager = NotificationManager()
        
        # UI components
        self.document_dashboard = None
        self.document_detail = None
        self.review_panel = None
        self.approval_panel = None
        self.admin_panel = None
        
        # Set up application layout
        self._setup_layout()
        
        # Initialize UI components
        self._init_ui_components()
        
        # Default to dashboard view
        self.load_dashboard()
        
        logger.info(f"Application initialized: {self.app_name} v{self.version}")
        
        # Initialize dialog component early
        self.dialog = None  # Will be initialized properly after UI setup
    
    def _setup_logging(self):
        """Configure logging for the application."""
        log_level = logging.DEBUG if self.debug else logging.INFO
        log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        
        # Create handlers
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(logging.Formatter(log_format))
        
        # Configure file logging if enabled
        if settings.ENABLE_FILE_LOGGING:
            os.makedirs(settings.LOG_DIRECTORY, exist_ok=True)
            log_filename = os.path.join(
                settings.LOG_DIRECTORY, 
                f"cdocs_{datetime.now().strftime('%Y%m%d')}.log"
            )
            file_handler = logging.FileHandler(log_filename)
            file_handler.setFormatter(logging.Formatter(log_format))
            root_logger = logging.getLogger('CDocs')
            root_logger.addHandler(file_handler)
        
        # Set up root logger
        root_logger = logging.getLogger('CDocs')
        root_logger.setLevel(log_level)
        root_logger.addHandler(console_handler)
        
        # Set log levels for dependencies
        logging.getLogger('urllib3').setLevel(logging.WARNING)
        logging.getLogger('neo4j').setLevel(logging.WARNING)
        logging.getLogger('panel').setLevel(logging.WARNING)
    
    def _load_configuration(self, config_path: str):
        """
        Load configuration from file.
        
        Parameters
        ----------
        config_path : str
            Path to configuration file
        """
        try:
            with open(config_path, 'r') as f:
                config_data = json.load(f)
            
            # Update settings based on loaded configuration
            for key, value in config_data.items():
                if hasattr(settings, key):
                    setattr(settings, key, value)
            
            logger.info(f"Configuration loaded from {config_path}")
        except Exception as e:
            logger.error(f"Failed to load configuration from {config_path}: {e}")
            self.show_notification(f"Failed to load configuration: {str(e)}", level="error")
    
    def _init_database(self):
        """Initialize database connection and schema."""
        try:
            # Use the correct imports
            from CDocs.db import get_driver, init_database
            
            # Initialize Neo4j schema
            success = init_database()
            
            if success:
                logger.info("Database schema initialized successfully")
            else:
                logger.error("Database schema initialization failed")
                
            # Create admin user if it doesn't exist
            self._ensure_admin_user()
            
            # Load initial data if needed
            #self._load_initial_data()
        except Exception as e:
            logger.error(f"Database initialization failed: {e}")
            if hasattr(self, 'notification_area'):
                self.show_notification(f"Database initialization failed: {str(e)}", level="error")
    
    def _ensure_admin_user(self):
        """Ensure admin user exists in the database."""
        # Check if admin user exists
        admin_exists = db_operations.check_node_exists('User', {'username': 'admin'})
        
        if not admin_exists:
            # Get department code for Administration
            from CDocs.config import settings
            admin_dept_code = settings.get_department_code('Administration')
            
            # Create admin user
            DocUser.create(
                username='admin',
                password=settings.DEFAULT_ADMIN_PASSWORD,
                name='Administrator',
                email=settings.ADMIN_EMAIL,
                department=admin_dept_code,  # Use the code, not the full name
                role='ADMIN'
            )
            logger.info("Admin user created")
    
    def _load_initial_data(self):
        """Load initial data into the database."""
        # Load document types
        self._ensure_document_types_exist()
        
        # Load departments
        self._ensure_departments_exist()
    
    def _ensure_document_types_exist(self):
        """Ensure document types exist in the database."""
        for doc_type in settings.DOCUMENT_TYPES:
            exists = db_operations.check_node_exists('DocumentType', {'name': doc_type})
            if not exists:
                db_operations.create_node('DocumentType', {
                    'name': doc_type,
                    'description': f'{doc_type} document type',
                    'active': True
                })
                logger.info(f"Created document type: {doc_type}")
    
    def _ensure_departments_exist(self):
        """Ensure departments exist in the database."""
        for dept in settings.DEFAULT_DEPARTMENTS:
            exists = db_operations.check_node_exists('Department', {'name': dept})
            if not exists:
                db_operations.create_node('Department', {
                    'name': dept,
                    'description': f'{dept} department',
                    'active': True
                })
                logger.info(f"Created department: {dept}")
    
    def _create_panel_template(self) -> pn.Template:
        """
        Create and configure the Panel template.
        
        Returns
        -------
        pn.Template
            Configured Panel template
        """
        # Set up Panel extensions without setting a global template
        pn.extension('tabulator', 'ace', 'katex')  # Remove template='bootstrap' here
        
        # Create template
        template = BootstrapTemplate(
            title=self.app_name,
            theme=getattr(settings, 'UI_THEME', 'default'),
            sidebar_width=300
        )
        
        # Configure global Panel settings
        pn.config.sizing_mode = 'stretch_width'
        
        # Add custom CSS files if specified in settings
        css_files = getattr(settings, 'CSS_FILES', [])
        if (css_files):
            pn.config.css_files = css_files
        
        return template
    
    def _setup_layout(self):
        """Set up the main application layout with dynamic containers."""
        # Create dynamic containers for each template section
        self.header_container = pn.Column(sizing_mode='stretch_width', margin=0)
        self.sidebar_container = pn.Column(sizing_mode='stretch_width', margin=0)
        self.main_container = pn.Column(sizing_mode='stretch_width', margin=0)
        
        # Add these containers to the template sections (these operations happen only once)
        self.template.header.append(self.header_container)
        self.template.sidebar.append(self.sidebar_container)
        self.template.main.append(self.main_container)
        
        # Initialize notification area
        self.notification_area = pn.pane.Markdown("", sizing_mode="stretch_width")
        
        # Add notification area to main container
        self.main_container.append(self.notification_area)
        
        # Add main content area (will be populated later)
        self.main_content = pn.Column(sizing_mode='stretch_width')
        self.main_container.append(self.main_content)
    
    def _setup_header(self):
        """Set up the application header."""
        # Clear existing content
        self.header_container.clear()
        
        # Create user info and logout button if user is logged in
        if self.current_user:
            user_info = pn.pane.HTML(f"""
                <div class="d-flex align-items-center">
                    <span class="mr-2">Logged in as: <strong>{getattr(self.current_user, 'name', 'User')}</strong></span>
                </div>
            """)
            
            logout_btn = pn.widgets.Button(
                name="Logout",
                button_type="default",
                width=80
            )
            logout_btn.on_click(self.logout)
            
            # Add header elements to header container
            self.header_container.append(
                pn.Row(
                    user_info,
                    logout_btn,
                    sizing_mode='stretch_width',
                    align='end'
                )
            )
        else:
            # If not logged in, show login button
            login_btn = pn.widgets.Button(
                name="Login",
                button_type="primary",
                width=80
            )
            login_btn.on_click(self.show_login)
            
            self.header_container.append(
                pn.Row(
                    login_btn,
                    sizing_mode='stretch_width',
                    align='end'
                )
            )
    
    def _setup_sidebar(self, integrated=False):
        """Set up the sidebar with filters and actions."""
        try:
            # Clear existing content
            self.sidebar_container.clear()
            
            # Get environment safely
            env_text = getattr(self, 'environment', 'Development')
            
            # For integrated mode, use a more compact sidebar
            if integrated:
                # Add a minimal system info section
                system_info = pn.Column(
                    pn.pane.Markdown(f"**Version:** {self.version}"),
                    sizing_mode='stretch_width',
                    margin=(10, 0, 0, 0)
                )
            else:
                # Add more detailed system info for standalone mode
                system_info = pn.Column(
                    pn.pane.Markdown(f"**Version:** {self.version}"),
                    pn.pane.Markdown(f"**Environment:** {env_text}"),
                    sizing_mode='stretch_width',
                    margin=(20, 0, 0, 0)
                )
            
            # Add navigation buttons if user is logged in
            if self.current_user:
                # Enhanced debugging of user information
                logger.debug(f"User in _setup_sidebar: {self.current_user.username if hasattr(self.current_user, 'username') else 'Unknown'}")
                logger.debug(f"User role attributes: roles={getattr(self.current_user, 'roles', 'Not present')}, role={getattr(self.current_user, 'role', 'Not present')}")
                logger.debug(f"User permissions: {permissions.get_user_permissions(self.current_user)}")
                
                # Debug user permissions
                has_admin = permissions.user_has_permission(self.current_user, "ADMIN")
                logger.debug(f"User {self.current_user.username} has ADMIN permission: {has_admin}")
                
                # Create navigation buttons
                dashboard_btn = pn.widgets.Button(
                    name="Documents Dashboard",
                    button_type="primary",
                    width=200
                )
                dashboard_btn.on_click(self.load_dashboard)
                
                # Add navigation links
                nav_links = pn.Column(
                    pn.pane.Markdown("### Navigation"),
                    dashboard_btn,
                    sizing_mode='stretch_width'
                )
                
                # Add create document button if user has permission
                can_create = permissions.user_has_permission(self.current_user, "CREATE_DOCUMENT")
                logger.debug(f"User {self.current_user.username} has CREATE_DOCUMENT permission: {can_create}")
                if can_create:
                    create_btn = pn.widgets.Button(
                        name="Create Document",
                        button_type="success", 
                        width=200
                    )
                    create_btn.on_click(self.create_document)
                    nav_links.append(create_btn)
                
                # Add reviews button
                reviews_btn = pn.widgets.Button(
                    name="My Reviews",
                    button_type="default",
                    width=200
                )
                reviews_btn.on_click(self.load_reviews)
                nav_links.append(reviews_btn)
                
                # Add approvals button
                approvals_btn = pn.widgets.Button(
                    name="My Approvals", 
                    button_type="default",
                    width=200
                )
                approvals_btn.on_click(self.load_approvals)
                nav_links.append(approvals_btn)
                
                # Add admin button if user has admin permission
                # Try multiple approaches to check for admin permissions
                admin_permission = permissions.user_has_permission(self.current_user, "ADMIN")
                admin_role = hasattr(self.current_user, 'roles') and 'ADMIN' in self.current_user.roles
                
                logger.debug(f"Admin permission check: {admin_permission}")
                logger.debug(f"Admin role check: {admin_role}")
                
                if admin_permission or admin_role:
                    logger.debug(f"Adding admin button for user {self.current_user.username}")
                    admin_btn = pn.widgets.Button(
                        name="Admin Panel",
                        button_type="warning",
                        width=200
                    )
                    admin_btn.on_click(self.load_admin)
                    nav_links.append(admin_btn)
                else:
                    logger.warning(f"Not adding admin button for user {self.current_user.username} - lacks admin permission")
                
                # Add navigation links to sidebar
                self.sidebar_container.append(nav_links)
                
                # Add system info at the bottom of sidebar
                self.sidebar_container.append(system_info)
                
                return True
                    
        except Exception as e:
            logger.error(f"Error setting up sidebar: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return False
    
    def _init_ui_components(self):
        """Initialize UI components for the application."""
        try:
            # Initialize the document dashboard
            from CDocs.ui.document_dashboard import DocumentDashboard
            self.document_dashboard = DocumentDashboard(self)
            
            # Initialize the document detail view (lazily loaded)
            self.document_detail = None
            
            # Initialize review panel (lazily loaded)
            self.review_panel = None
            
            # Initialize approval panel (lazily loaded)
            self.approval_panel = None
            
            # Initialize admin panel (lazily loaded)
            self.admin_panel = None
                
            logger.info("UI components initialized")
        except Exception as e:
            logger.error(f"Error initializing UI components: {str(e)}")
    
    def show_notification(self, message: str, level: str = "info", duration: int = 5000):
        """
        Show a notification message.
        
        Parameters
        ----------
        message : str
            The message to display
        level : str, optional
            The notification level (info, warning, error, success)
        duration : int, optional
            How long to display the message (in milliseconds)
        """
        # Set appropriate styling based on level
        if level == "error":
            style = "color: #dc3545; font-weight: bold;"
        elif level == "warning":
            style = "color: #ffc107; font-weight: bold;"
        elif level == "success":
            style = "color: #28a745; font-weight: bold;"
        else:  # info
            style = "color: #17a2b8; font-weight: bold;"
        
        # Update notification area
        self.notification_area.object = f"<div style='{style}'>{message}</div>"
        
        # Clear notification after duration if not error
        if level != "error" and duration > 0:
            pn.state.onload(lambda: pn.state.add_timeout(duration, self.clear_notification))
    
    def clear_notification(self):
        """Clear the notification area."""
        self.notification_area.object = ""
    
    def login(self, username: str, password: str) -> bool:
        """
        Authenticate a user.
        
        Parameters
        ----------
        username : str
            Username
        password : str
            Password
            
        Returns
        -------
        bool
            True if authentication successful, False otherwise
        """
        try:
            # Try to authenticate user
            user = DocUser.authenticate(username, password)
            
            if user:
                # Set current user
                self.current_user = user
                logger.info(f"User {username} logged in")
                
                # Refresh layout with logged-in user
                self._setup_header()
                self._setup_sidebar()
                
                # Reload dashboard
                self.load_dashboard()
                
                return True
            else:
                logger.warning(f"Failed login attempt for user {username}")
                self.show_notification("Invalid username or password", level="error")
                return False
                
        except Exception as e:
            logger.error(f"Login error: {str(e)}")
            self.show_notification(f"Login error: {str(e)}", level="error")
            return False
    
    def logout(self, event=None):
        """Log out the current user."""
        if self.current_user:
            username = self.current_user.username
            self.current_user = None
            logger.info(f"User {username} logged out")
            
            # Refresh layout
            self._setup_header()
            self._setup_sidebar()
            
            # Show login form
            self.show_login()
    
    def show_login(self, event=None):
        """Show the login form."""
        # Clear main content
        self.main_content.clear()
        
        # Create login form
        username_input = pn.widgets.TextInput(
            name="Username or Email",
            placeholder="Enter username or email",
            width=300
        )
        
        password_input = pn.widgets.PasswordInput(
            name="Password",
            placeholder="Enter password",
            width=300
        )
        
        login_btn = pn.widgets.Button(
            name="Login",
            button_type="primary",
            width=100
        )
        
        # Login message area
        login_message = pn.pane.Markdown("", width=300)
        
        # Create login form container
        login_form = pn.Column(
            pn.pane.Markdown("## Login"),
            pn.pane.Markdown("Please enter your credentials to log in."),
            username_input,
            password_input,
            pn.Row(login_btn),
            login_message,
            width=400,
            styles={'background':'#f8f9fa'},
            css_classes=['p-4', 'border', 'rounded']
        )
        
        # Add login handler
        def handle_login(event):
            if not username_input.value:
                login_message.object = "**Error:** Username or email is required"
                return
                
            if not password_input.value:
                login_message.object = "**Error:** Password is required"
                return
                
            # Show processing message
            login_message.object = "Logging in..."
            
            # Call login method
            success = self.login(username_input.value, password_input.value)
            
            if not success:
                login_message.object = "**Error:** Invalid login credentials"
        
        # Add handler to login button
        login_btn.on_click(handle_login)
        
        # Add login form to center of main content
        container = pn.Column(
            pn.Row(login_form, align='center'),
            sizing_mode='stretch_both'
        )
        self.main_content.append(container)

    def load_dashboard(self, event=None):
        """Load the document dashboard view."""
        # Update current view
        self.current_view = 'dashboard'
        logger.info("Loading document dashboard view")
        
        # Add debugging for user information
        if self.current_user:
            logger.debug(f"Current user: {self.current_user.username}, Role: {getattr(self.current_user, 'role', 'Unknown')}")
            logger.debug(f"User permissions: {permissions.get_user_permissions(self.current_user)}")
        else:
            logger.debug("No user currently logged in")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Update sidebar buttons for main dashboard
        self._setup_sidebar()
        
        # Check if user is authenticated, but skip login screen in integration mode
        if not self.current_user and not getattr(self, 'integration_mode', False):
            self.show_login()
            return
        
        try:
            # Initialize document dashboard if needed
            if not self.document_dashboard:
                logger.debug("Creating new DocumentDashboard instance")
                self.document_dashboard = document_dashboard.DocumentDashboard(self)
            
            # Set the current user
            if self.current_user:
                logger.debug(f"Setting user {self.current_user.username} in document dashboard")
                self.document_dashboard.set_user(self.current_user)
            
            # Load dashboard content
            dashboard_view = self.document_dashboard.get_dashboard_view()
            #self.main_content.append(pn.pane.Markdown("# system dashboard"))
            #logger.info(f'Document dashboard loaded successfully {dashboard_view}')
            self.main_content.append(dashboard_view)
            
        except Exception as e:
            logger.error(f"Error loading dashboard: {str(e)}")
            import traceback
            logger.error(f"Traceback: {traceback.format_exc()}")
            self.show_notification(f"Error loading dashboard: {str(e)}", level="error")
            # Add basic error view
            self.main_content.append(pn.pane.Markdown("# Document Dashboard"))
            self.main_content.append(pn.pane.Markdown(f"**Error loading dashboard: {str(e)}**"))

# This continues the implementation of /CDocs/main.py

    def load_document(self, document_uid: str, event=None):
        """Load a specific document."""
        # Update current view
        self.current_view = 'document'
        logger.info(f"Loading document view for {document_uid}")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Check if user is authenticated
        if not self.current_user:
            logger.warning("Attempted to view document without logged-in user")
            self.show_login()
            return
        
        try:
            # Get document data
            from CDocs.controllers.document_controller import get_document
            document_data = get_document(document_uid=document_uid)
            
            if not document_data:
                logger.error(f"Document {document_uid} not found")
                self.show_notification(f"Document not found", level="error")
                self.load_dashboard()
                return
                
            # Create document detail view
            self.document_detail = document_detail.DocumentDetail(parent_app=self)
            
            # Set user
            self.document_detail.set_user(self.current_user)
            
            # Use document_uid and let the detail view fetch the data
            self.document_detail.document_uid = document_uid
            
            # Load document
            loaded = self.document_detail._load_document()
            if not loaded:
                logger.error(f"Failed to load document {document_uid}")
                self.show_notification("Failed to load document", level="error")
                self.load_dashboard()
                return
            
            # Get document view
            document_view = self.document_detail.get_document_view()
            
            # Add to main content
            self.main_content.append(document_view)
            
        except Exception as e:
            logger.error(f"Error loading document {document_uid}: {str(e)}")
            import traceback
            logger.error(f"Traceback: {traceback.format_exc()}")
            self.show_notification(f"Error loading document: {str(e)}", level="error")
    

    def load_reviews(self, event=None):
        """Load the reviews view."""
        # Update current view
        self.current_view = 'reviews'
        logger.info("Loading reviews panel")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Setup review-specific sidebar
        self._setup_review_sidebar()
        
        # Check if user is authenticated
        if not self.current_user:
            self.show_login()
            return
        
        try:
            # Initialize review panel if needed
            if not self.review_panel:
                from CDocs.ui.review_panel import create_review_panel
                self.review_panel = create_review_panel(parent_app=self)
            else:
                # Set the current user
                self.review_panel.set_user(self.current_user)
                self._load_reviews_by_mode('pending')
            # Create a header for the reviews section
            self.main_content.append(pn.pane.Markdown("# Review Management"))
            
            # Load pending reviews
            
            review_view = self.review_panel.get_main_content()
            self.main_content.append(review_view)
            
        except Exception as e:
            logger.error(f"Error loading reviews panel: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            
            self.show_notification(f"Error loading reviews: {str(e)}", level="error")
            # Add basic error view
            self.main_content.append(Markdown("# Reviews"))
            self.main_content.append(Markdown(f"**Error loading reviews: {str(e)}**"))
            
            # Add back button
            back_btn = pn.widgets.Button(
                name="Back to Dashboard",
                button_type="primary",
                width=150
            )
            back_btn.on_click(self.load_dashboard)
            self.main_content.append(back_btn)
    
    def load_review(self, review_uid: str, event=None):
        """
        Load a specific review.
        
        Parameters
        ----------
        review_uid : str
            UID of the review to load
        event : event, optional
            Event that triggered this action
        """
        # Update current view
        self.current_view = 'review_detail'
        logger.info(f"Loading review {review_uid}")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Setup review-specific sidebar
        self._setup_review_sidebar()
        
        # Check if user is authenticated
        if not self.current_user:
            self.show_login()
            return
        
        try:
            # Initialize review panel if needed
            if not self.review_panel:
                from CDocs.ui.review_panel import create_review_panel
                self.review_panel = create_review_panel(parent_app=self)
            
            # Set the current user
            self.review_panel.set_user(self.current_user)
            
            # Load review
            self.review_panel._load_review(review_uid)
            review_view = self.review_panel.get_main_content()
            self.main_content.append(review_view)
            
        except Exception as e:
            logger.error(f"Error loading review {review_uid}: {str(e)}")
            self.show_notification(f"Error loading review: {str(e)}", level="error")
            # Add basic error view
            self.main_content.append(Markdown("# Review Details"))
            self.main_content.append(Markdown(f"**Error loading review: {str(e)}**"))
            
            # Add back button
            back_btn = Button(name="Back to Reviews", button_type="primary", width=150)
            back_btn.on_click(self.load_reviews)
            self.main_content.append(Row(back_btn))
    
    def load_approvals(self, event=None):
        """Load the approvals panel."""
        # Update current view
        self.current_view = 'approvals'
        logger.info("Loading approvals panel")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Setup approval-specific sidebar
        self._setup_approval_sidebar()
        
        # Check if user is authenticated
        if not self.current_user:
            self.show_login()
            return
        
        try:
            # Initialize approval panel if needed
            if not self.approval_panel:
                # Use absolute import instead of relative import
                from CDocs.ui.approval_panel import create_approval_panel
                self.approval_panel = create_approval_panel(parent_app=self)
            
            # Set the current user
            self.approval_panel.set_user(self.current_user)
            
            # Create a header for the approvals section
            self.main_content.append(pn.pane.Markdown("# Approval Management"))
            
            # Load approvals with default mode (pending)
            self._load_approvals_by_mode('pending')
            
            # Get the main panel content
            approval_view = self.approval_panel.get_main_content()
            self.main_content.append(approval_view)
            
        except Exception as e:
            logger.error(f"Error loading approvals panel: {e}")
            logger.error(traceback.format_exc())
            
            self.show_notification(f"Error loading approvals: {e}", level="error")
            # Add basic error view
            self.main_content.append(Markdown("# Approvals"))
            self.main_content.append(Markdown(f"**Error loading approvals: {e}**"))
            
            # Add back button
            back_btn = pn.widgets.Button(
                name="Back to Dashboard",
                button_type="primary",
                width=150
            )
            back_btn.on_click(self.load_dashboard)
            self.main_content.append(back_btn)

    def _load_approvals_by_mode(self, mode='pending'):
        """
        Load approvals based on selected mode.
        
        Args:
            mode: The approval mode ('pending', 'completed', or 'all')
        """
        try:
            logger.info(f"Loading approvals in '{mode}' mode")
            
            # Update current view
            self.current_view = 'approvals'
            self.current_approval_mode = mode
            
            # Clear main content
            self.main_content.clear()
            self.notification_area.object = ""
            
            # Update sidebar
            self._setup_approval_sidebar()
            
            # Show header
            header_text = {
                'pending': "# My Pending Approvals",
                'completed': "# My Completed Approvals",
                'all': "# All Approvals"
            }.get(mode, "# Approvals")
            
            self.main_content.append(pn.pane.Markdown(header_text))
            self.main_content.append(self.notification_area)
            
            # If no approval panel exists, create it
            if not self.approval_panel:
                from CDocs.ui.approval_panel import create_approval_panel
                self.approval_panel = create_approval_panel(parent_app=self)
            
            # Set the current user
            if self.current_user:
                self.approval_panel.set_user(self.current_user)
            else:
                self.notification_area.object = "Please log in to view approvals"
                return
            
            # Load appropriate approvals based on mode
            try:
                from CDocs.controllers.approval_controller import get_user_assigned_approvals, _controller
                
                if mode == 'pending':
                    result = get_user_pending_approvals(self.current_user, include_completed=False)
                    approvals = result.get('approvals', [])
                elif mode == 'completed':
                    # Get completed approvals
                    result = get_user_assigned_approvals(
                        self.current_user, 
                        status_filter=["COMPLETED", "REJECTED"], 
                        include_completed=True
                    )
                    approvals = result.get('assignments', [])
                elif mode == 'all' and permissions.user_has_permission(self.current_user, "MANAGE_APPROVALS"):
                    # For all approvals, query directly using controller
                    approvals, total = _controller.search_cycles({}, limit=100, offset=0)
                else:
                    approvals = []
                
                # Create approval table if we have approvals
                if approvals:
                    self._display_approvals_table(approvals)
                else:
                    self.main_content.append(pn.pane.Markdown("No approvals found for the selected filter."))
            
            except Exception as e:
                logger.error(f"Error loading approvals: {e}")
                logger.error(traceback.format_exc())
                self.notification_area.object = f"Error loading approvals: {str(e)}"
                
        except Exception as e:
            logger.error(f"Error in _load_approvals_by_mode: {e}")
            self.notification_area.object = f"Error: {str(e)}"
    
    # Update load_approval method to properly initialize approval panel with the refactored code
    def load_approval(self, approval_uid: str, event=None):
        """
        Load a specific approval.
        
        Parameters
        ----------
        approval_uid : str
            UID of the approval to load
        event : event, optional
            Event that triggered this action
        """
        # Update current view
        self.current_view = 'approval_detail'
        logger.info(f"Loading approval {approval_uid}")
        
        # Clear main content
        self.main_content.clear()
        self.notification_area.object = ""
        
        # Setup approval-specific sidebar
        self._setup_approval_sidebar()
        
        # Check if user is authenticated
        if not self.current_user:
            self.show_login()
            return
        
        try:
            # Initialize approval panel if needed
            if not self.approval_panel:
                from CDocs.ui.approval_panel import create_approval_panel
                self.approval_panel = create_approval_panel(parent_app=self)
            
            # Set the current user
            self.approval_panel.set_user(self.current_user)
            
            # Load approval using the workflow_panel_base method
            self.approval_panel._load_cycle(approval_uid)
            approval_view = self.approval_panel.get_main_content()
            self.main_content.append(approval_view)
            
        except Exception as e:
            logger.error(f"Error loading approval {approval_uid}: {str(e)}")
            logger.error(traceback.format_exc())
            self.show_notification(f"Error loading approval: {str(e)}", level="error")
            # Add basic error view
            self.main_content.append(Markdown("# Approval Details"))
            self.main_content.append(Markdown(f"**Error loading approval: {str(e)}**"))
            
            # Add back button
            back_btn = Button(name="Back to Approvals", button_type="primary", width=150)
            back_btn.on_click(self.load_approvals)
            self.main_content.append(Row(back_btn))
    
    def load_admin(self, event=None):
        """Load the admin panel."""
        try:
            # Update current view
            self.current_view = 'admin'
            logger.info("Loading admin panel")
            
            # Clear main content
            self.main_content.clear()
            self.notification_area.object = ""
            
            # Check if user is authenticated
            if not self.current_user:
                self.show_login()
                return
                
            # Use multiple methods to check admin access
            has_admin_permission = permissions.user_has_permission(self.current_user, "ADMIN")
            has_admin_role = False
            if hasattr(self.current_user, 'roles') and isinstance(self.current_user.roles, (list, tuple, set)):
                has_admin_role = 'ADMIN' in self.current_user.roles
            
            logger.debug(f"User {self.current_user.username if hasattr(self.current_user, 'username') else 'Unknown'} - Admin permission: {has_admin_permission}, Admin role: {has_admin_role}")
            
            if not (has_admin_permission or has_admin_role):
                logger.warning(f"User {self.current_user.username if hasattr(self.current_user, 'username') else 'Unknown'} attempted to access admin panel without permission")
                self.show_notification("You do not have permission to access the admin panel", level="error")
                self.load_dashboard()
                return
            
            try:
                # Initialize admin panel if needed
                if not self.admin_panel:
                    from CDocs.ui.admin_panel import create_admin_panel
                    self.admin_panel = create_admin_panel(
                        parent_app=self,  # Just pass self as parent_app
                        embedded=True
                    )
                
                # Set up admin sidebar AFTER creating admin panel but BEFORE setting user
                # so that the sidebar uses the admin panel's current tab
                self._setup_admin_sidebar()
                
                # Set the current user if needed
                if self.admin_panel and hasattr(self.admin_panel, 'set_user'):
                    self.admin_panel.set_user(self.current_user)
                
                # Get admin view
                if self.admin_panel and hasattr(self.admin_panel, 'get_admin_view'):
                    admin_view = self.admin_panel.get_admin_view()
                    self.main_content.append(admin_view)
                else:
                    raise AttributeError("Admin panel does not have get_admin_view method")
                
            except Exception as e:
                logger.error(f"Error loading admin panel: {e}")
                import traceback
                logger.error(f"Traceback: {traceback.format_exc()}")
                self.show_notification(f"Error loading admin panel: {e}", level="error")
                # Add basic error view
                from panel.pane import Markdown
                self.main_content.append(Markdown("# Admin Panel"))
                self.main_content.append(Markdown(f"**Error loading admin panel: {str(e)}**"))
        except Exception as e:
            logger.error(f"Error in load_admin: {e}")
            import traceback
            logger.error(f"Traceback: {traceback.format_exc()}")
            self.show_notification(f"Error: {e}", level="error")
    
    def _update_sidebar_buttons(self):
        """Update sidebar button states based on current view."""
        # Clear sidebar and rebuild based on current view
        if self.current_view == 'dashboard':
            self._setup_sidebar()
        elif self.current_view == 'reviews':
            self._setup_review_sidebar()
        elif self.current_view == 'approvals':
            self._setup_approval_sidebar()
        elif self.current_view == 'admin':
            self._setup_admin_sidebar()
        else:
            # Default to standard sidebar
            self._setup_sidebar()
    
    def create_document(self, event=None):
        """Create a new document from the navigation menu."""
        try:
            # Use a Modal instead of Dialog for Panel 1.6.1
            # Navigate directly to document dashboard and use its form instead
            
            # If we have a document dashboard, use it to create a document
            if hasattr(self, 'document_dashboard') and self.document_dashboard:
                # Navigate to documents page
                self.navigate_to('documents')
                # Call the create document method on the dashboard
                self.document_dashboard.show_create_document_form()
                return
                
            # If we don't have a document dashboard yet, create a simple modal
            # using what's available in Panel 1.6.1
            from CDocs.config import settings
            
            # Use DEPARTMENTS dictionary keys for department options
            departments = list(settings.DEPARTMENTS.keys())
            
            # Create form widgets
            title_input = pn.widgets.TextInput(name="Title", placeholder="Enter document title")
            doc_type_select = pn.widgets.Select(name="Document Type", options=list(settings.DOCUMENT_TYPES.keys()))
            department_select = pn.widgets.Select(name="Department", options=departments)
            content_area = pn.widgets.TextAreaInput(name="Content", placeholder="Enter document content", rows=5)
            
            # Buttons
            create_btn = pn.widgets.Button(name="Create", button_type="primary")
            cancel_btn = pn.widgets.Button(name="Cancel", button_type="default")
            
            # Handler for create button
            def handle_create(event):
                try:
                    # Validate inputs
                    if not title_input.value:
                        self.show_notification("Document title is required", level="error")
                        return
                    
                    if not doc_type_select.value:
                        self.show_notification("Document type is required", level="error")
                        return
                        
                    # Get values from form
                    title = title_input.value
                    doc_type = settings.get_document_type_code(doc_type_select.value)
                    department = settings.get_department_code(department_select.value)
                    content = content_area.value or ""
                    
                    # Create document using document controller
                    from CDocs.controllers.document_controller import create_document
                    
                    result = create_document(
                        user=self.current_user,
                        title=title,
                        doc_text=content,
                        doc_type=doc_type,
                        department=department,
                        status='DRAFT'
                    )
                    
                    # Check result
                    if result and isinstance(result, dict) and result.get('status') == 'success':
                        doc_number = result.get('document', {}).get('doc_number', 'Unknown')
                        self.show_notification(f"Document {doc_number} created successfully", level="success")
                        
                        # Load document dashboard
                        self.load_dashboard()
                    else:
                        error_msg = result.get('message') if isinstance(result, dict) else "Unknown error"
                        self.show_notification(f"Error creating document: {error_msg}", level="error")
                    
                except Exception as e:
                    logger.error(f"Error creating document: {e}")
                    import traceback
                    logger.error(traceback.format_exc())
                    self.show_notification(f"Error creating document: {str(e)}", level="error")
            
            # Handler for cancel button
            def handle_cancel(event):
                # Clear main content and return to dashboard
                self.load_dashboard()
            
            # Bind handlers
            create_btn.on_click(handle_create)
            cancel_btn.on_click(handle_cancel)
            
            # Create form
            form = pn.Column(
                pn.pane.Markdown("# Create New Document"),
                title_input,
                pn.Row(doc_type_select, department_select),
                content_area,
                pn.Row(
                    pn.layout.HSpacer(),
                    cancel_btn,
                    create_btn,
                ),
                styles={'background': '#f8f9fa'},
                css_classes=['p-4', 'border', 'rounded'],
                width=700
            )
            
            # Show form in main content area
            self.main_content.clear()
            self.main_content.append(form)
            
        except Exception as e:
            logger.error(f"Error creating document: {e}")
            import traceback
            logger.error(f"Traceback: {traceback.format_exc()}")
            self.show_notification(f"Error creating document: {str(e)}", level="error")
    
    def get_server_info(self) -> Dict[str, Any]:
        """
        Get server information for health checks.
        
        Returns
        -------
        Dict[str, Any]
            Server information
        """
        return {
            'app_name': self.app_name,
            'version': self.version,
            'debug': self.debug,
            'uptime': self._get_uptime(),
            'database_status': self._check_database_status()
        }
    
    def _get_uptime(self) -> int:
        """
        Get application uptime in seconds.
        
        Returns
        -------
        int
            Uptime in seconds
        """
        # In a real implementation, this would track the actual start time
        # For now, we'll just return a placeholder
        return 0
    
    def _check_database_status(self) -> str:
        """
        Check database connection status.
        
        Returns
        -------
        str
            Database status ('connected', 'disconnected', or error message)
        """
        try:
            # Check database connection
            if db_operations.test_connection():
                return 'connected'
            else:
                return 'disconnected'
        except Exception as e:
            return f'error: {str(e)}'
    
    def health_check(self) -> Dict[str, Any]:
        """
        Perform a health check on the application.
        
        Returns
        -------
        Dict[str, Any]
            Health check results
        """
        # Get server info
        server_info = self.get_server_info()
        
        # Check database status
        db_status = self._check_database_status()
        
        # Check if all components are loaded
        components_status = {
            'document_dashboard': self.document_dashboard is not None,
            'review_panel': self.review_panel is not None,
            'approval_panel': self.approval_panel is not None
        }
        
        # Determine overall status
        status = 'healthy'
        if db_status != 'connected':
            status = 'degraded'
        
        if not all(components_status.values()):
            status = 'degraded'
        
        return {
            'status': status,
            'timestamp': datetime.now().isoformat(),
            'server': server_info,
            'database': db_status,
            'components': components_status
        }
    
    def initialize_integration(self, datacapture_app=None):
        """Initialize integration with DataCapture application."""
        try:
            logger.info("Initializing integration with datacapture application")
            
            # Store reference to DataCapture app if provided
            if (datacapture_app is not None):
                self.datacapture_app = datacapture_app
            
            # Set integration mode flag
            self.integration_mode = True
            
            # Ensure environment attribute exists
            if not hasattr(self, 'environment'):
                self.environment = "Integrated"
            
            logger.info("Integration with datacapture application initialized")
            return True
            
        except Exception as e:
            logger.error(f"Failed to initialize integration: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return False

    def import_user_from_datacapture(self, dc_user):
        """Import user from DataCapture application."""
        try:
            if not dc_user:
                logger.warning("No user provided from DataCapture")
                return False

            # Get user attributes for logging
            user_name = getattr(dc_user, 'user', '')
            user_mail = getattr(dc_user, 'mail', '')
            logger.info(f"Importing user from DataCapture: {user_name} ({user_mail})")
            
            # Check if this is a Neo4j user with proper UID
            if hasattr(dc_user, 'UID') and dc_user.UID:
                # Create DocUser from datacapture user or get existing user
                from .models.user_extensions import DocUser
                
                # First try to get user directly from database
                doc_user = DocUser.get_by_uid(dc_user.UID)
                
                # If not found, create a new DocUser from the datacapture user
                if not doc_user:
                    doc_user = DocUser.from_datacapture_user(dc_user)
                    
                if not doc_user:
                    logger.error("Failed to create or retrieve DocUser")
                    return False
                
                # Set current user
                self.current_user = doc_user
                
                # Load the dashboard
                self.load_dashboard()
                
                return True
            else:
                logger.error("User has no UID attribute - cannot import")
                return False
            
        except Exception as e:
            logger.error(f"Error importing user from datacapture: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return False

    def get_integrated_view(self):
        """
        Get a view optimized for integration with datacapture.
        
        Returns
        -------
        pn.viewable.Viewable
            Panel viewable for integration
        """
        try:
            return self.main_content
        except Exception as e:
            logger.error(f"Error creating integrated view: {e}")
            # Return a simple error message
            import panel as pn
            return pn.Column(
                pn.pane.Markdown("## Error Loading Controlled Documents"),
                pn.pane.Markdown(f"**Error:** {str(e)}")
            )

    def is_standalone_mode(self):
        """Determine if CDocs is running in standalone mode (not embedded in datacapture).
        
        Returns
        -------
        bool
            True if running standalone, False if embedded
        """
        # Check if integration_mode attribute has been set, which indicates embedding
        return not hasattr(self, 'integration_mode') or not self.integration_mode

    def _setup_navigation(self, integrated=False):
        """Set up navigation buttons for the application."""
        try:
            # Clear existing navigation
            if hasattr(self, 'nav_container'):
                self.nav_container.clear()
            else:
                self.nav_container = pn.Row(sizing_mode='stretch_width')
                self.header_container.append(self.nav_container)
            
            # Create navigation buttons
            dashboard_btn = pn.widgets.Button(
                name="Documents", 
                button_type="primary",
                width=150
            )
            dashboard_btn.on_click(self.load_dashboard)
            
            # Create more compact set of buttons for integrated mode
            if integrated:
                self.nav_container.append(dashboard_btn)
            else:
                # Create full navigation for standalone mode
                create_doc_btn = pn.widgets.Button(
                    name="Create Document", 
                    button_type="success",
                    width=150
                )
                create_doc_btn.on_click(self.create_document)
                
                reviews_btn = pn.widgets.Button(
                    name="Reviews", 
                    button_type="default",
                    width=150
                )
                reviews_btn.on_click(self.load_reviews)
                
                approvals_btn = pn.widgets.Button(
                    name="Approvals", 
                    button_type="default",
                    width=150
                )
                approvals_btn.on_click(self.load_approvals)
                
                admin_btn = pn.widgets.Button(
                    name="Admin", 
                    button_type="warning",
                    width=150
                )
                admin_btn.on_click(self.load_admin)
                
                self.nav_container.extend([
                    dashboard_btn,
                    create_doc_btn,
                    reviews_btn,
                    approvals_btn,
                    admin_btn
                ])
        except Exception as e:
            logger.error(f"Error setting up navigation: {e}")
            import traceback
            logger.error(traceback.format_exc())

    def handle_datacapture_document(self, document_data, event=None):
        """
        Handle a document submitted from datacapture application.
        
        Parameters
        ----------
        document_data : Dict[str, Any]
            Document data from datacapture
        event : event, optional
            Event that triggered this action
        
        Returns
        -------
        Dict[str, Any]
            Result of document processing
        """
        try:
            logger.info(f"Processing document from datacapture: {document_data.get('title', 'Untitled')}")
            
            # Extract document metadata
            doc_title = document_data.get('title', 'Untitled Document')
            doc_content = document_data.get('content', '')
            doc_type = document_data.get('doc_type', 'GENERAL')
            department = document_data.get('department', 'General')
            
            # Set creator to current user or admin if no user is logged in
            creator = self.current_user
            if not creator:
                # Handle case where no user is logged in
                logger.warning("No user logged in for document creation - using admin")
                from CDocs.models.user_extensions import DocUser
                creator = DocUser.get_admin_user()
            
            # Create document in the controlled document system
            # Note the parameter name doc_text used correctly here
            result = document_controller.create_document(
                user=creator,
                title=doc_title,
                doc_text=doc_content,  # Changed from content to doc_text
                doc_type=doc_type,
                department=department,
                status='DRAFT'
            )
            
            # Validate result before accessing
            if not result or not isinstance(result, dict):
                logger.error(f"Invalid result from create_document: {result}")
                self.show_notification("Error creating document: Invalid result from server", level="error")
                return {'error': 'Invalid result from server'}
                
            # Check for document data in the result
            if 'document' not in result:
                logger.error(f"Missing document data in result: {result}")
                self.show_notification("Error creating document: Missing document data", level="error")
                return {'error': 'Missing document data in result'}
            
            # Show success notification
            document_uid = result.get('document', {}).get('uid')
            doc_number = result.get('document', {}).get('doc_number')
            
            if document_uid:
                success_message = f"Document {doc_number} created successfully" if doc_number else "Document created successfully"
                self.show_notification(success_message, level="success")
                
                # Optionally load the document detail view
                self.load_document(document_uid)
            
            return result
            
        except Exception as e:
            logger.error(f"Error processing document from datacapture: {str(e)}")
            logger.error(traceback.format_exc())
            self.show_notification(f"Error processing document: {str(e)}", level="error")
            return {'error': str(e)}

    def login_user(self, user):
        """
        Set the current user and update UI accordingly.
        
        Parameters
        ----------
        user : DocUser
            The user to log in
        """
        try:
            # Set current user
            self.current_user = user
            logger.info(f"User {user.username} logged in")
            
            # Refresh layout with logged-in user
            self._setup_header()
            self._setup_sidebar()
            
            # Initialize UI components that depend on user
            self._init_ui_components()
            
            # Reload dashboard
            if hasattr(self, 'document_dashboard') and self.document_dashboard:
                self.document_dashboard.set_user(user)
            
            self.load_dashboard()
            
            return True
        except Exception as e:
            logger.error(f"Error logging in user: {e}")
            return False

    def servable(self, title="Controlled Documents"):
        """
        Make the application servable in standalone mode.
        
        Parameters
        ----------
        title : str
            The title for the application
        
        Returns
        -------
        panel.viewable.Viewable
            The servable application
        """
        import panel as pn
        if self.is_standalone_mode():
            logger.info("Starting CDocs in standalone mode")
            return self.template.servable(title)
        else:
            logger.info("CDocs is running in embedded mode")
            return self.main_content.servable()

    def _init_review_panel(self):
        """Initialize the review panel."""
        from .ui.review_panel import create_review_panel
        self.review_panel = create_review_panel(parent_app=self)

    def _setup_review_sidebar(self):
        """Set up sidebar for review context."""
        try:
            # Clear the sidebar
            self.sidebar_container.clear()
            
            # Add navigation buttons
            dashboard_btn = Button(name="Back to Dashboard", button_type="primary", width=200)
            dashboard_btn.on_click(self.load_dashboard)
            self.sidebar_container.append(dashboard_btn)
            
            # Add a divider
            self.sidebar_container.append(pn.layout.Divider())
            
            # Add review mode selection section
            self.sidebar_container.append(pn.pane.Markdown("## Review Views"))
            
            # Mode selection buttons
            pending_btn = Button(name="My Pending Reviews", button_type="success", width=200)
            completed_btn = Button(name="My Completed Reviews", button_type="default", width=200)
            all_reviews_btn = Button(name="All Reviews", button_type="default", width=200)
            
            # Add click handlers
            pending_btn.on_click(lambda event: self._load_reviews_by_mode('pending'))
            completed_btn.on_click(lambda event: self._load_reviews_by_mode('completed'))
            all_reviews_btn.on_click(lambda event: self._load_reviews_by_mode('all'))
            
            # Add buttons to sidebar
            self.sidebar_container.append(pending_btn)
            self.sidebar_container.append(completed_btn)
            
            # Only show "All Reviews" button if user has permission
            if self.current_user and permissions.user_has_permission(self.current_user, "MANAGE_REVIEWS"):
                self.sidebar_container.append(all_reviews_btn)
            
            # Add a divider
            self.sidebar_container.append(pn.layout.Divider())
            
            # Show pending reviews
            self.sidebar_container.append(pn.pane.Markdown("## My Pending Reviews"))
            
            # Get pending reviews for current user
            if self.current_user:
                from CDocs.controllers.review_controller import get_user_pending_reviews
                result = get_user_pending_reviews(self.current_user)
                
                if result and result.get('success') and result.get('reviews'):
                    reviews = result.get('reviews')
                    for review in reviews[:5]:  # Show top 5
                        doc_title = review.get('document', {}).get('title', 'Untitled Document')
                        review_uid = review.get('UID')
                        
                        review_btn = Button(name=f"{doc_title[:30]}...", button_type="default", width=200)
                        review_btn.on_click(lambda e, uid=review_uid: self.load_review(uid))
                        self.sidebar_container.append(review_btn)
                else:
                    self.sidebar_container.append(pn.pane.Markdown("No pending reviews"))
                    
        except Exception as e:
            logger.error(f"Error setting up review sidebar: {e}")
    
    def _load_reviews_by_mode(self, mode='pending'):
        """
        Load reviews based on selected mode.
        
        Args:
            mode: The review mode ('pending', 'completed', or 'all')
        """
        try:
            logger.info(f"Loading reviews in '{mode}' mode")
            
            # Update current view
            self.current_view = 'reviews'
            self.current_review_mode = mode
            
            # Clear main content
            self.main_content.clear()
            self.notification_area.object = ""
            
            # Update sidebar
            self._setup_review_sidebar()
            
            # Show header
            header_text = {
                'pending': "# My Pending Reviews",
                'completed': "# My Completed Reviews",
                'all': "# All Reviews"
            }.get(mode, "# Reviews")
            
            self.main_content.append(pn.pane.Markdown(header_text))
            self.main_content.append(self.notification_area)
            
            # Load appropriate reviews
            if not self.current_user:
                self.notification_area.object = "Please log in to view reviews"
                return
            
            try:
                from CDocs.controllers.review_controller import get_user_assigned_reviews, _controller, get_user_pending_reviews
                
                if mode == 'pending':
                    result = get_user_pending_reviews(self.current_user, include_completed=False)
                    reviews = result.get('reviews', [])
                elif mode == 'completed':
                    # Get completed reviews
                    result = get_user_assigned_reviews(
                        self.current_user, 
                        status_filter=["COMPLETED", "REJECTED"], 
                        include_completed=True
                    )
                    reviews = result.get('assignments', [])
                elif mode == 'all' and permissions.user_has_permission(self.current_user, "MANAGE_REVIEWS"):
                    # For all reviews, query directly using controller
                    reviews, total = _controller.search_cycles({}, limit=100, offset=0)
                else:
                    reviews = []
                
                # Create review table if we have reviews
                if reviews:
                    self._display_reviews_table(reviews)
                else:
                    self.main_content.append(pn.pane.Markdown("No reviews found for the selected filter."))
            
            except Exception as e:
                logger.error(f"Error loading reviews: {e}")
                logger.error(traceback.format_exc())
                self.notification_area.object = f"Error loading reviews: {str(e)}"
                
        except Exception as e:
            logger.error(f"Error in _load_reviews_by_mode: {e}")
            self.notification_area.object = f"Error: {str(e)}"

    def _display_reviews_table(self, reviews):
        """
        Display a table of reviews.
        
        Args:
            reviews: List of review data
        """
        try:
            # Format data for table
            table_data = []
            
            for review in reviews:
                # Check if review is None or empty
                if not review:
                    logger.warning("Skipping empty review record")
                    continue
                    
                # Extract document info with safety check for None
                doc_info = review.get('document') or {}
                doc_title = doc_info.get('title', 'Unknown Document')
                doc_number = doc_info.get('doc_number', doc_info.get('docNumber', 'N/A'))
                
                # Extract review info with safety checks
                review_uid = review.get('UID', '')
                if not review_uid:
                    logger.warning(f"Skipping review record with missing UID: {review}")
                    continue
                    
                status = review.get('status', 'PENDING')
                
                # Handle date fields with proper conversion from Neo4j DateTime objects
                start_date = review.get('startDate', review.get('start_date', ''))
                due_date = review.get('dueDate', review.get('due_date', ''))
                
                # Convert Neo4j DateTime objects to string format
                if hasattr(start_date, 'to_native'):
                    # This is a Neo4j DateTime object
                    start_date = start_date.to_native().strftime('%Y-%m-%d')
                elif isinstance(start_date, str) and 'T' in start_date:
                    start_date = start_date.split('T')[0]
                    
                if hasattr(due_date, 'to_native'):
                    # This is a Neo4j DateTime object
                    due_date = due_date.to_native().strftime('%Y-%m-%d')
                elif isinstance(due_date, str) and 'T' in due_date:
                    due_date = due_date.split('T')[0]
                
                # Create view button
                view_button = f'<button class="view-review-btn" data-uid="{review_uid}">View</button>'
                
                # Add to table data
                table_data.append({
                    'Document': f"{doc_title} ({doc_number})",
                    'Status': status,
                    'Started': start_date,
                    'Due': due_date,
                    'Action': view_button,
                    'UID': review_uid
                })
            
            # Check if we have any data to display
            if not table_data:
                self.main_content.append(pn.pane.Markdown("No valid review data to display."))
                return
                
            # Create dataframe
            import pandas as pd
            df = pd.DataFrame(table_data)
            
            # Create tabulator
            table = pn.widgets.Tabulator(
                df,
                formatters={'Action': {'type': 'html'}},
                selectable=True,
                pagination='local',
                page_size=10,
                sizing_mode='stretch_width',
                hidden_columns=['UID']
            )
            
            # Add click handler with data-* attribute support
            js_code = """
            function setupViewButtons() {
                // Set timeout to ensure DOM is ready
                setTimeout(function() {
                    const buttons = document.querySelectorAll('.view-review-btn');
                    buttons.forEach(button => {
                        button.addEventListener('click', function(e) {
                            const uid = e.target.getAttribute('data-uid');
                            // Send message to Python
                            if (uid) {
                                console.log('View review clicked:', uid);
                                comm.send({event_type: 'view_review', uid: uid});
                            }
                        });
                    });
                }, 500);
            }
            
            // Initial setup
            setupViewButtons();
            
            // Setup observer for pagination changes
            const observer = new MutationObserver(function(mutations) {
                setupViewButtons();
            });
            
            // Start observing
            const tabulator = document.querySelector('.tabulator');
            if (tabulator) {
                observer.observe(tabulator, { childList: true, subtree: true });
            }
            """
            
            # Add JavaScript callback
            table.on_click(self._handle_review_table_click)
            
            # Add custom JS for button handling
            custom_js = pn.pane.HTML(f"<script>{js_code}</script>", width=0, height=0)
            
            # Add to main content
            self.main_content.append(table)
            self.main_content.append(custom_js)
            
            # Add message handler for view buttons
            def handle_custom_js_message(event):
                if event.get('event_type') == 'view_review':
                    review_uid = event.get('uid')
                    if review_uid:
                        self.load_review(review_uid)
            
            # Register message handler
            pn.state.curdoc.on_message(handle_custom_js_message)
            
        except Exception as e:
            logger.error(f"Error displaying reviews table: {e}")
            logger.error(traceback.format_exc())
            self.notification_area.object = f"Error displaying reviews: {str(e)}"

    def _handle_review_table_click(self, event):
        """
        Handle clicks in the review table.
        
        Args:
            event: The click event
        """
        try:
            # Skip if clicking on action column (handled by custom JS)
            if hasattr(event, 'column') and event.column == 'Action':
                return
            
            # Get the review UID from the clicked row
            if hasattr(event, 'row'):
                # Check row type
                if isinstance(event.row, dict) and 'UID' in event.row:
                    # Dictionary case - direct access to row data
                    review_uid = event.row['UID']
                    self.load_review(review_uid)
                elif isinstance(event.row, int):
                    # Integer case - row index, need to look up data from table
                    try:
                        # Find the Tabulator widget in main_content
                        row_index = event.row
                        if hasattr(self, 'main_content'):
                            for item in self.main_content:
                                if isinstance(item, pn.widgets.Tabulator):
                                    df = item.value
                                    if row_index < len(df) and 'UID' in df.columns:
                                        review_uid = df.iloc[row_index]['UID']
                                        self.load_review(review_uid)
                                    break
                    except Exception as e:
                        logger.warning(f"Error handling row index click: {e}")
                else:
                    logger.warning(f"Unexpected row format in review table click: {type(event.row)}")
        except Exception as e:
            logger.error(f"Error in review table click handler: {e}")
            logger.error(traceback.format_exc())
    
    
    def _setup_approval_sidebar(self):
        """Set up sidebar for approval context."""
        try:
            # Clear the sidebar
            self.sidebar_container.clear()
            
            # Add navigation buttons
            dashboard_btn = Button(name="Back to Dashboard", button_type="primary", width=200)
            dashboard_btn.on_click(self.load_dashboard)
            self.sidebar_container.append(dashboard_btn)
            
            # Add a divider
            self.sidebar_container.append(pn.layout.Divider())
            
            # Add approval mode selection section
            self.sidebar_container.append(pn.pane.Markdown("## Approval Views"))
            
            # Mode selection buttons
            pending_btn = Button(name="My Pending Approvals", button_type="success", width=200)
            completed_btn = Button(name="My Completed Approvals", button_type="default", width=200)
            all_approvals_btn = Button(name="All Approvals", button_type="default", width=200)
            
            # Add click handlers
            pending_btn.on_click(lambda event: self._load_approvals_by_mode('pending'))
            completed_btn.on_click(lambda event: self._load_approvals_by_mode('completed'))
            all_approvals_btn.on_click(lambda event: self._load_approvals_by_mode('all'))
            
            # Add buttons to sidebar
            self.sidebar_container.append(pending_btn)
            self.sidebar_container.append(completed_btn)
            
            # Only show "All Approvals" button if user has permission
            if self.current_user and permissions.user_has_permission(self.current_user, "MANAGE_APPROVALS"):
                self.sidebar_container.append(all_approvals_btn)
            
            # Add a divider
            self.sidebar_container.append(pn.layout.Divider())
            
            # Show pending approvals
            self.sidebar_container.append(pn.pane.Markdown("## My Pending Approvals"))
            
            # Get pending approvals for current user
            if self.current_user:
                from CDocs.controllers.approval_controller import get_user_pending_approvals
                result = get_user_pending_approvals(self.current_user)
                
                if result and result.get('success') and result.get('approvals'):
                    approvals = result.get('approvals')
                    for approval in approvals[:5]:  # Show top 5
                        doc_title = approval.get('document', {}).get('title', 'Untitled Document')
                        approval_uid = approval.get('UID')
                        
                        approval_btn = Button(name=f"{doc_title[:30]}...", button_type="default", width=200)
                        approval_btn.on_click(lambda e, uid=approval_uid: self.load_approval(uid))
                        self.sidebar_container.append(approval_btn)
                else:
                    self.sidebar_container.append(pn.pane.Markdown("No pending approvals"))
                    
        except Exception as e:
            logger.error(f"Error setting up approval sidebar: {e}")

    def _load_approvals_by_mode(self, mode='pending'):
        """
        Load approvals based on selected mode.
        
        Args:
            mode: The approval mode ('pending', 'completed', or 'all')
        """
        try:
            logger.info(f"Loading approvals in '{mode}' mode")
            
            # Update current view
            self.current_view = 'approvals'
            self.current_approval_mode = mode
            
            # Clear main content
            self.main_content.clear()
            self.notification_area.object = ""
            
            # Update sidebar
            self._setup_approval_sidebar()
            
            # Show header
            header_text = {
                'pending': "# My Pending Approvals",
                'completed': "# My Completed Approvals",
                'all': "# All Approvals"
            }.get(mode, "# Approvals")
            
            self.main_content.append(pn.pane.Markdown(header_text))
            self.main_content.append(self.notification_area)
            
            # Load appropriate approvals
            if not self.current_user:
                self.notification_area.object = "Please log in to view approvals"
                return
            
            try:
                from CDocs.controllers.approval_controller import get_user_pending_approvals, _controller
                
                if mode == 'pending':
                    result = get_user_pending_approvals(self.current_user, include_completed=False)
                    approvals = result.get('approvals', [])
                elif mode == 'completed':
                    # Get completed approvals
                    from CDocs.controllers.approval_controller import get_user_assigned_approvals
                    result = get_user_assigned_approvals(
                        self.current_user, 
                        status_filter=["COMPLETED", "REJECTED"], 
                        include_completed=True
                    )
                    approvals = result.get('assignments', [])
                elif mode == 'all' and permissions.user_has_permission(self.current_user, "MANAGE_APPROVALS"):
                    # For all approvals, query directly using controller
                    approvals, total = _controller.search_cycles({}, limit=100, offset=0)
                else:
                    approvals = []
                
                # Create approvals table if we have approvals
                if approvals:
                    self._display_approvals_table(approvals)
                else:
                    self.main_content.append(pn.pane.Markdown("No approvals found for the selected filter."))
            
            except Exception as e:
                logger.error(f"Error loading approvals: {e}")
                logger.error(traceback.format_exc())
                self.notification_area.object = f"Error loading approvals: {str(e)}"
                
        except Exception as e:
            logger.error(f"Error in _load_approvals_by_mode: {e}")
            self.notification_area.object = f"Error: {str(e)}"

    def _display_approvals_table(self, approvals):
        """
        Display a table of approvals.
        
        Args:
            approvals: List of approval data
        """
        try:
            # Format data for table
            table_data = []
            
            for approval in approvals:
                # Check if approval is None or empty
                if not approval:
                    logger.warning("Skipping empty approval record")
                    continue
                    
                # Extract document info with safety check for None
                doc_info = approval.get('document') or {}
                doc_title = doc_info.get('title', 'Unknown Document')
                doc_number = doc_info.get('doc_number', doc_info.get('docNumber', 'N/A'))
                
                # Extract approval info with safety checks
                approval_uid = approval.get('UID', '')
                if not approval_uid:
                    logger.warning(f"Skipping approval record with missing UID: {approval}")
                    continue
                    
                status = approval.get('status', 'PENDING')
                
                # Handle date fields with proper conversion from Neo4j DateTime objects
                start_date = approval.get('startDate', approval.get('start_date', ''))
                due_date = approval.get('dueDate', approval.get('due_date', ''))
                
                # Convert Neo4j DateTime objects to string format
                if hasattr(start_date, 'to_native'):
                    # This is a Neo4j DateTime object
                    start_date = start_date.to_native().strftime('%Y-%m-%d')
                elif isinstance(start_date, str) and 'T' in start_date:
                    start_date = start_date.split('T')[0]
                    
                if hasattr(due_date, 'to_native'):
                    # This is a Neo4j DateTime object
                    due_date = due_date.to_native().strftime('%Y-%m-%d')
                elif isinstance(due_date, str) and 'T' in due_date:
                    due_date = due_date.split('T')[0]
                
                # Create view button
                view_button = f'<button class="view-approval-btn" data-uid="{approval_uid}">View</button>'
                
                # Add to table data
                table_data.append({
                    'Document': f"{doc_title} ({doc_number})",
                    'Status': status,
                    'Started': start_date,
                    'Due': due_date,
                    'Action': view_button,
                    'UID': approval_uid
                })
            
            # Check if we have any data to display
            if not table_data:
                self.main_content.append(pn.pane.Markdown("No valid approval data to display."))
                return
                
            # Create dataframe
            import pandas as pd
            df = pd.DataFrame(table_data)
            
            # Create tabulator
            table = pn.widgets.Tabulator(
                df,
                formatters={'Action': {'type': 'html'}},
                selectable=True,
                pagination='local',
                page_size=10,
                sizing_mode='stretch_width',
                hidden_columns=['UID']
            )
            
            # Add click handler with data-* attribute support
            js_code = """
            function setupViewButtons() {
                // Set timeout to ensure DOM is ready
                setTimeout(function() {
                    const buttons = document.querySelectorAll('.view-approval-btn');
                    buttons.forEach(button => {
                        button.addEventListener('click', function(e) {
                            const uid = e.target.getAttribute('data-uid');
                            // Send message to Python
                            if (uid) {
                                console.log('View approval clicked:', uid);
                                comm.send({event_type: 'view_approval', uid: uid});
                            }
                        });
                    });
                }, 500);
            }
            
            // Initial setup
            setupViewButtons();
            
            // Setup observer for pagination changes
            const observer = new MutationObserver(function(mutations) {
                setupViewButtons();
            });
            
            // Start observing
            const tabulator = document.querySelector('.tabulator');
            if (tabulator) {
                observer.observe(tabulator, { childList: true, subtree: true });
            }
            """
            
            # Add JavaScript callback
            table.on_click(self._handle_approval_table_click)
            
            # Add custom JS for button handling
            custom_js = pn.pane.HTML(f"<script>{js_code}</script>", width=0, height=0)
            
            # Add to main content
            self.main_content.append(table)
            self.main_content.append(custom_js)
            
            # Add message handler for view buttons
            def handle_custom_js_message(event):
                if event.get('event_type') == 'view_approval':
                    approval_uid = event.get('uid')
                    if approval_uid:
                        self.load_approval(approval_uid)
            
            # Register message handler
            pn.state.curdoc.on_message(handle_custom_js_message)
            
        except Exception as e:
            logger.error(f"Error displaying approvals table: {e}")
            logger.error(traceback.format_exc())
            self.notification_area.object = f"Error displaying approvals: {str(e)}"

    def _handle_approval_table_click(self, event):
        """
        Handle clicks in the approval table.
        
        Args:
            event: The click event
        """
        try:
            # Skip if clicking on action column (handled by custom JS)
            if hasattr(event, 'column') and event.column == 'Action':
                return
            
            # Get the approval UID from the clicked row
            if hasattr(event, 'row'):
                # Check row type
                if isinstance(event.row, dict) and 'UID' in event.row:
                    # Dictionary case - direct access to row data
                    approval_uid = event.row['UID']
                    self.load_approval(approval_uid)
                elif isinstance(event.row, int):
                    # Integer case - row index, need to look up data from table
                    try:
                        # Find the Tabulator widget in main_content
                        row_index = event.row
                        if hasattr(self, 'main_content'):
                            for item in self.main_content:
                                if isinstance(item, pn.widgets.Tabulator):
                                    df = item.value
                                    if row_index < len(df) and 'UID' in df.columns:
                                        approval_uid = df.iloc[row_index]['UID']
                                        self.load_approval(approval_uid)
                                    break
                    except Exception as e:
                        logger.warning(f"Error handling row index click: {e}")
                else:
                    logger.warning(f"Unexpected row format in approval table click: {type(event.row)}")
        except Exception as e:
            logger.error(f"Error in approval table click handler: {e}")
            logger.error(traceback.format_exc())

    def _init_approval_panel(self):
        """Initialize the approval panel."""
        # Use absolute import instead of relative import
        from CDocs.ui.approval_panel import create_approval_panel
        self.approval_panel = create_approval_panel(parent_app=self)

    def _setup_admin_sidebar(self):
        """Set up the sidebar specifically for the admin panel."""
        try:
            # Clear the sidebar container
            self.sidebar_container.clear()
            
            # Create navigation buttons for admin
            dashboard_btn = pn.widgets.Button(
                name='System Dashboard',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'dashboard' else 'default',
                width=200
            )
            
            users_btn = pn.widgets.Button(
                name='User Management',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'users' else 'default',
                width=200
            )
            
            departments_btn = pn.widgets.Button(
                name='Departments',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'departments' else 'default',
                width=200
            )
            
            doc_types_btn = pn.widgets.Button(
                name='Document Types',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'doc_types' else 'default',
                width=200
            )
            
            settings_btn = pn.widgets.Button(
                name='System Settings',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'settings' else 'default',
                width=200
            )
            
            backup_btn = pn.widgets.Button(
                name='Backup & Restore',
                button_type='primary' if self.admin_panel and getattr(self.admin_panel, 'current_tab', '') == 'backup' else 'default',
                width=200
            )
            
            # Define click handlers
            def load_dashboard(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_admin_dashboard'):
                    self.admin_panel._load_admin_dashboard()
                    self._setup_admin_sidebar()  # Update sidebar buttons
                    
            def load_users(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_user_management'):
                    self.admin_panel._load_user_management()
                    self._setup_admin_sidebar()  # Update sidebar buttons
                    
            def load_departments(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_department_management'):
                    self.admin_panel._load_department_management()
                    self._setup_admin_sidebar()  # Update sidebar buttons
                    
            def load_doc_types(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_document_type_management'):
                    self.admin_panel._load_document_type_management()
                    self._setup_admin_sidebar()  # Update sidebar buttons
                    
            def load_settings(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_system_settings'):
                    self.admin_panel._load_system_settings()
                    self._setup_admin_sidebar()  # Update sidebar buttons
                    
            def load_backup(event):
                if self.admin_panel and hasattr(self.admin_panel, '_load_backup_restore'):
                    self.admin_panel._load_backup_restore()
                    self._setup_admin_sidebar()  # Update sidebar buttons
            
            # Attach handlers
            dashboard_btn.on_click(load_dashboard)
            users_btn.on_click(load_users)
            departments_btn.on_click(load_departments)
            doc_types_btn.on_click(load_doc_types)
            settings_btn.on_click(load_settings)
            backup_btn.on_click(load_backup)
            
            # Add to navigation area
            navigation = pn.Column(
                pn.pane.Markdown("## Admin Navigation"),
                dashboard_btn,
                users_btn,
                departments_btn,
                doc_types_btn,
                settings_btn,
                backup_btn,
                sizing_mode='stretch_width'
            )
            
            # Add navigation to sidebar
            self.sidebar_container.append(navigation)
            
            # Add back to dashboard button
            back_btn = pn.widgets.Button(
                name="← Back to Dashboard",
                button_type="primary",
                width=200
            )
            back_btn.on_click(self.load_dashboard)
            self.sidebar_container.append(pn.layout.Spacer(height=20))
            self.sidebar_container.append(back_btn)
            
            # Add system status if available
            if self.admin_panel and hasattr(self.admin_panel, 'status_area'):
                # Clone the status area from admin panel
                status_container = pn.Column(
                    pn.pane.Markdown("## System Status"),
                    sizing_mode='stretch_width',
                    styles={'background': '#f8f9fa'},
                    css_classes=['p-3', 'border', 'rounded']
                )
                
                try:
                    # Get statistics from admin controller
                    from CDocs.controllers.admin_controller import get_system_stats
                    stats = get_system_stats()
                    
                    # Format uptime
                    uptime_seconds = stats.get('uptime', 0)
                    days, remainder = divmod(uptime_seconds, 86400)
                    hours, remainder = divmod(remainder, 3600)
                    minutes, seconds = divmod(remainder, 60)
                    uptime_str = f"{days}d {hours}h {minutes}m"
                    
                    # Display key statistics
                    active_users = stats.get('active_users', 0)
                    total_users = stats.get('total_users', 0)
                    active_docs = stats.get('active_documents', 0)
                    total_docs = stats.get('total_documents', 0)
                    
                    status_container.append(pn.pane.Markdown(f"**Users:** {active_users}/{total_users} active"))
                    status_container.append(pn.pane.Markdown(f"**Documents:** {active_docs}/{total_docs} active"))
                    status_container.append(pn.pane.Markdown(f"**Reviews:** {stats.get('pending_reviews', 0)} pending"))
                    status_container.append(pn.pane.Markdown(f"**Approvals:** {stats.get('pending_approvals', 0)} pending"))
                    status_container.append(pn.pane.Markdown(f"**Uptime:** {uptime_str}"))
                    
                    self.sidebar_container.append(status_container)
                    
                except Exception as e:
                    logger.warning(f"Error getting system statistics: {e}")
                    status_container.append(pn.pane.Markdown("*Statistics unavailable*"))
                    self.sidebar_container.append(status_container)
            
            return True
        
        except Exception as e:
            logger.error(f"Error setting up admin sidebar: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return False

    def navigate_to(self, view_name):
        """Navigate to a specific view.
        
        Args:
            view_name: Name of the view to navigate to
        """
        try:
            if view_name == 'dashboard':
                self.load_dashboard()
            elif view_name == 'documents':
                self.load_dashboard()
            elif view_name == 'reviews':
                self.load_reviews()
            elif view_name == 'approvals':
                self.load_approvals()
            elif view_name == 'admin':
                self.load_admin()
            else:
                logger.warning(f"Unknown view name: {view_name}")
                self.load_dashboard()
        except Exception as e:
            logger.error(f"Error navigating to {view_name}: {e}")
            self.show_notification(f"Error navigating to {view_name}: {str(e)}", level="error")

Parameters

Name Type Default Kind
bases param.Parameterized -

Parameter Details

bases: Parameter of type param.Parameterized

Return Value

Returns unspecified type

Class Interface

Methods

__init__(self, config_path)

Purpose: Initialize the application with optional configuration path. Parameters ---------- config_path : str, optional Path to configuration file. If not provided, default configuration is used.

Parameters:

  • config_path: Parameter

Returns: None

_setup_logging(self)

Purpose: Configure logging for the application.

Returns: None

_load_configuration(self, config_path)

Purpose: Load configuration from file. Parameters ---------- config_path : str Path to configuration file

Parameters:

  • config_path: Type: str

Returns: None

_init_database(self)

Purpose: Initialize database connection and schema.

Returns: None

_ensure_admin_user(self)

Purpose: Ensure admin user exists in the database.

Returns: None

_load_initial_data(self)

Purpose: Load initial data into the database.

Returns: None

_ensure_document_types_exist(self)

Purpose: Ensure document types exist in the database.

Returns: None

_ensure_departments_exist(self)

Purpose: Ensure departments exist in the database.

Returns: None

_create_panel_template(self) -> pn.Template

Purpose: Create and configure the Panel template. Returns ------- pn.Template Configured Panel template

Returns: Returns pn.Template

_setup_layout(self)

Purpose: Set up the main application layout with dynamic containers.

Returns: None

_setup_header(self)

Purpose: Set up the application header.

Returns: None

_setup_sidebar(self, integrated)

Purpose: Set up the sidebar with filters and actions.

Parameters:

  • integrated: Parameter

Returns: None

_init_ui_components(self)

Purpose: Initialize UI components for the application.

Returns: None

show_notification(self, message, level, duration)

Purpose: Show a notification message. Parameters ---------- message : str The message to display level : str, optional The notification level (info, warning, error, success) duration : int, optional How long to display the message (in milliseconds)

Parameters:

  • message: Type: str
  • level: Type: str
  • duration: Type: int

Returns: None

clear_notification(self)

Purpose: Clear the notification area.

Returns: None

login(self, username, password) -> bool

Purpose: Authenticate a user. Parameters ---------- username : str Username password : str Password Returns ------- bool True if authentication successful, False otherwise

Parameters:

  • username: Type: str
  • password: Type: str

Returns: Returns bool

logout(self, event)

Purpose: Log out the current user.

Parameters:

  • event: Parameter

Returns: None

show_login(self, event)

Purpose: Show the login form.

Parameters:

  • event: Parameter

Returns: None

load_dashboard(self, event)

Purpose: Load the document dashboard view.

Parameters:

  • event: Parameter

Returns: None

load_document(self, document_uid, event)

Purpose: Load a specific document.

Parameters:

  • document_uid: Type: str
  • event: Parameter

Returns: None

load_reviews(self, event)

Purpose: Load the reviews view.

Parameters:

  • event: Parameter

Returns: None

load_review(self, review_uid, event)

Purpose: Load a specific review. Parameters ---------- review_uid : str UID of the review to load event : event, optional Event that triggered this action

Parameters:

  • review_uid: Type: str
  • event: Parameter

Returns: None

load_approvals(self, event)

Purpose: Load the approvals panel.

Parameters:

  • event: Parameter

Returns: None

_load_approvals_by_mode(self, mode)

Purpose: Load approvals based on selected mode. Args: mode: The approval mode ('pending', 'completed', or 'all')

Parameters:

  • mode: Parameter

Returns: None

load_approval(self, approval_uid, event)

Purpose: Load a specific approval. Parameters ---------- approval_uid : str UID of the approval to load event : event, optional Event that triggered this action

Parameters:

  • approval_uid: Type: str
  • event: Parameter

Returns: None

load_admin(self, event)

Purpose: Load the admin panel.

Parameters:

  • event: Parameter

Returns: None

_update_sidebar_buttons(self)

Purpose: Update sidebar button states based on current view.

Returns: None

create_document(self, event)

Purpose: Create a new document from the navigation menu.

Parameters:

  • event: Parameter

Returns: None

get_server_info(self) -> Dict[str, Any]

Purpose: Get server information for health checks. Returns ------- Dict[str, Any] Server information

Returns: Returns Dict[str, Any]

_get_uptime(self) -> int

Purpose: Get application uptime in seconds. Returns ------- int Uptime in seconds

Returns: Returns int

_check_database_status(self) -> str

Purpose: Check database connection status. Returns ------- str Database status ('connected', 'disconnected', or error message)

Returns: Returns str

health_check(self) -> Dict[str, Any]

Purpose: Perform a health check on the application. Returns ------- Dict[str, Any] Health check results

Returns: Returns Dict[str, Any]

initialize_integration(self, datacapture_app)

Purpose: Initialize integration with DataCapture application.

Parameters:

  • datacapture_app: Parameter

Returns: None

import_user_from_datacapture(self, dc_user)

Purpose: Import user from DataCapture application.

Parameters:

  • dc_user: Parameter

Returns: None

get_integrated_view(self)

Purpose: Get a view optimized for integration with datacapture. Returns ------- pn.viewable.Viewable Panel viewable for integration

Returns: See docstring for return details

is_standalone_mode(self)

Purpose: Determine if CDocs is running in standalone mode (not embedded in datacapture). Returns ------- bool True if running standalone, False if embedded

Returns: See docstring for return details

_setup_navigation(self, integrated)

Purpose: Set up navigation buttons for the application.

Parameters:

  • integrated: Parameter

Returns: None

handle_datacapture_document(self, document_data, event)

Purpose: Handle a document submitted from datacapture application. Parameters ---------- document_data : Dict[str, Any] Document data from datacapture event : event, optional Event that triggered this action Returns ------- Dict[str, Any] Result of document processing

Parameters:

  • document_data: Parameter
  • event: Parameter

Returns: See docstring for return details

login_user(self, user)

Purpose: Set the current user and update UI accordingly. Parameters ---------- user : DocUser The user to log in

Parameters:

  • user: Parameter

Returns: None

servable(self, title)

Purpose: Make the application servable in standalone mode. Parameters ---------- title : str The title for the application Returns ------- panel.viewable.Viewable The servable application

Parameters:

  • title: Parameter

Returns: See docstring for return details

_init_review_panel(self)

Purpose: Initialize the review panel.

Returns: None

_setup_review_sidebar(self)

Purpose: Set up sidebar for review context.

Returns: None

_load_reviews_by_mode(self, mode)

Purpose: Load reviews based on selected mode. Args: mode: The review mode ('pending', 'completed', or 'all')

Parameters:

  • mode: Parameter

Returns: None

_display_reviews_table(self, reviews)

Purpose: Display a table of reviews. Args: reviews: List of review data

Parameters:

  • reviews: Parameter

Returns: None

_handle_review_table_click(self, event)

Purpose: Handle clicks in the review table. Args: event: The click event

Parameters:

  • event: Parameter

Returns: None

_setup_approval_sidebar(self)

Purpose: Set up sidebar for approval context.

Returns: None

_load_approvals_by_mode(self, mode)

Purpose: Load approvals based on selected mode. Args: mode: The approval mode ('pending', 'completed', or 'all')

Parameters:

  • mode: Parameter

Returns: None

_display_approvals_table(self, approvals)

Purpose: Display a table of approvals. Args: approvals: List of approval data

Parameters:

  • approvals: Parameter

Returns: None

_handle_approval_table_click(self, event)

Purpose: Handle clicks in the approval table. Args: event: The click event

Parameters:

  • event: Parameter

Returns: None

_init_approval_panel(self)

Purpose: Initialize the approval panel.

Returns: None

_setup_admin_sidebar(self)

Purpose: Set up the sidebar specifically for the admin panel.

Returns: None

navigate_to(self, view_name)

Purpose: Navigate to a specific view. Args: view_name: Name of the view to navigate to

Parameters:

  • view_name: Parameter

Returns: None

Required Imports

import os
import sys
import logging
from datetime import datetime
import json

Usage Example

# Example usage:
# result = ControlledDocumentApp(bases)

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class ControlledDocumentApp 99.1% 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 ControlledDocApp 80.1% similar

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

    From: /tf/active/vicechatdev/panel_app.py
  • class CDocsApp 75.3% 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 ControlledDocumentFlaskApp 71.8% similar

    Main Flask application class for Controlled Document Management System.

    From: /tf/active/vicechatdev/CDocs/main_flask.py
  • function main_v21 66.7% 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
← Back to Browse