class DocumentShareManager
A Panel-based UI component for managing document sharing permissions, displaying share URLs, and viewing user access information for controlled documents.
/tf/active/vicechatdev/CDocs/ui/components/share_manager.py
115 - 311
moderate
Purpose
DocumentShareManager provides a comprehensive user interface for document sharing management in a document control system. It displays document information, generates and displays shareable URLs, shows current user permissions in a table format, and allows refreshing of permission data. The component integrates with a document control backend to fetch and display real-time sharing information, making it easy for users to manage who has access to specific document versions.
Source Code
class DocumentShareManager(param.Parameterized):
"""
UI Component for managing document sharing.
This component provides a UI for viewing and managing document
sharing permissions, including:
- Viewing current share URL
- Viewing current users with access
- Granting/revoking access
"""
document_uid = param.String(default="")
user_uid = param.String(default="")
def __init__(self, **params):
super().__init__(**params)
# Create UI components
self.title = pn.pane.Markdown("## Document Sharing")
self.document_info = pn.pane.Markdown("Loading document information...")
self.access_url_input = pn.widgets.TextInput(
name="Document Access URL",
value="",
disabled=True,
width=400
)
self.copy_url_button = pn.widgets.Button(
name="Copy URL",
button_type="primary",
width=100,
disabled=True
)
self.copy_url_button.on_click(self._copy_url_to_clipboard)
self.update_button = pn.widgets.Button(
name="Refresh Permissions",
button_type="default",
width=150
)
self.update_button.on_click(self._refresh_permissions)
self.message_area = pn.pane.Markdown("")
# Current access table
self.access_table = pn.widgets.Tabulator(
pd.DataFrame(columns=["User", "Role", "Access Type", "Last Updated"]),
height=300,
width=500
)
# Layout
self.layout = pn.Column(
self.title,
self.document_info,
pn.Row(
self.access_url_input,
self.copy_url_button
),
pn.layout.Divider(),
pn.pane.Markdown("### Current Access"),
self.access_table,
pn.Row(
self.update_button,
pn.layout.HSpacer(),
self.message_area
)
)
# Initialize
self._update_display()
def _update_display(self):
"""Update the display with current document sharing information."""
if not self.document_uid:
self.document_info.object = "No document selected."
return
try:
# Get document and version
document = ControlledDocument(uid=self.document_uid)
if not document:
self.document_info.object = "Document not found."
return
# Update document info
self.document_info.object = f"""
**Document**: {document.title}
**Document Number**: {document.doc_number}
**Status**: {document.get_status_name()}
"""
# Get current version
version = document.current_version
if not version:
self.access_url_input.value = "No current version available"
self.copy_url_button.disabled = True
return
# Get access URL
if self.user_uid:
result = get_user_access_url(version, self.user_uid)
if result.get('success', False) and result.get('share_url'):
self.access_url_input.value = result.get('share_url')
self.copy_url_button.disabled = False
else:
self.access_url_input.value = f"Error: {result.get('message', 'Unable to get access URL')}"
self.copy_url_button.disabled = True
else:
# Just get a general share URL
share_url = get_document_share_url(version)
if share_url:
self.access_url_input.value = share_url
self.copy_url_button.disabled = False
else:
self.access_url_input.value = "Unable to get access URL"
self.copy_url_button.disabled = True
# Update access table
# This would require fetching permission information from the share API
# For the demo, we'll just show static data
perm_result = manage_document_permissions(document)
if perm_result.get('success', False) and 'details' in perm_result:
access_data = []
for user_perm in perm_result.get('details', []):
access_data.append({
"User": user_perm.get('user', 'Unknown'),
"Role": user_perm.get('role', 'User'),
"Access Type": "Edit" if user_perm.get('write_access', False) else "Read Only",
"Last Updated": datetime.now().strftime("%Y-%m-%d %H:%M")
})
self.access_table.value = pd.DataFrame(access_data)
else:
self.access_table.value = pd.DataFrame([{
"User": "Error fetching permissions",
"Role": "",
"Access Type": "",
"Last Updated": ""
}])
except Exception as e:
logger.error(f"Error updating share display: {e}")
self.document_info.object = f"Error: {str(e)}"
def _copy_url_to_clipboard(self, event):
"""Copy the access URL to clipboard."""
if not self.access_url_input.value:
return
try:
import pyperclip
pyperclip.copy(self.access_url_input.value)
self.message_area.object = "✅ URL copied to clipboard"
self.message_area.style = {'color': 'green'}
except ImportError:
# If pyperclip is not available, show the message to manually copy
self.message_area.object = "Please manually copy the URL"
self.message_area.style = {'color': 'orange'}
def _refresh_permissions(self, event):
"""Refresh document permissions."""
if not self.document_uid:
return
try:
document = ControlledDocument(uid=self.document_uid)
if not document:
self.message_area.object = "Document not found"
self.message_area.style = {'color': 'red'}
return
result = manage_document_permissions(document)
if result.get('success', False):
self.message_area.object = "✅ Permissions updated successfully"
self.message_area.style = {'color': 'green'}
# Update the display
self._update_display()
else:
self.message_area.object = f"❌ Error: {result.get('message', 'Unknown error')}"
self.message_area.style = {'color': 'red'}
except Exception as e:
logger.error(f"Error refreshing permissions: {e}")
self.message_area.object = f"❌ Error: {str(e)}"
self.message_area.style = {'color': 'red'}
def view(self):
"""Return the layout for display."""
return self.layout
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
param.Parameterized | - |
Parameter Details
document_uid: String parameter representing the unique identifier of the document to manage. Must be a valid UID from the ControlledDocument system. When empty, the component displays a 'No document selected' message.
user_uid: String parameter representing the unique identifier of the user for whom to generate a personalized access URL. When provided, generates a user-specific share URL; when empty, generates a general document share URL.
Return Value
The class constructor returns a DocumentShareManager instance with initialized UI components and layout. The view() method returns a Panel Column layout object containing all UI elements (title, document info, URL input, buttons, access table) ready for display in a Panel application. Internal methods return None (event handlers) or update component state.
Class Interface
Methods
__init__(self, **params) -> None
Purpose: Initialize the DocumentShareManager with UI components, layout, and event handlers
Parameters:
params: Keyword arguments passed to param.Parameterized parent class, typically document_uid and user_uid
Returns: None - initializes instance with all UI components and triggers initial display update
_update_display(self) -> None
Purpose: Update all UI components with current document sharing information, including document details, share URL, and permissions table
Returns: None - updates instance attributes (document_info, access_url_input, access_table) with current data
_copy_url_to_clipboard(self, event) -> None
Purpose: Event handler to copy the document access URL to the system clipboard using pyperclip
Parameters:
event: Panel button click event object (automatically passed by Panel framework)
Returns: None - copies URL to clipboard and updates message_area with success/error message
_refresh_permissions(self, event) -> None
Purpose: Event handler to refresh document permissions from the backend and update the display
Parameters:
event: Panel button click event object (automatically passed by Panel framework)
Returns: None - fetches fresh permission data and updates UI components with results
view(self) -> pn.Column
Purpose: Return the complete Panel layout for rendering in a Panel application
Returns: Panel Column object containing all UI components arranged in the defined layout structure
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
document_uid |
param.String | Parameter storing the unique identifier of the document being managed, defaults to empty string | instance |
user_uid |
param.String | Parameter storing the unique identifier of the user for personalized access URLs, defaults to empty string | instance |
title |
pn.pane.Markdown | Markdown pane displaying the component title '## Document Sharing' | instance |
document_info |
pn.pane.Markdown | Markdown pane displaying document details (title, number, status) or loading/error messages | instance |
access_url_input |
pn.widgets.TextInput | Disabled text input widget displaying the generated document access URL (400px wide) | instance |
copy_url_button |
pn.widgets.Button | Primary button to copy the access URL to clipboard, disabled when no valid URL is available (100px wide) | instance |
update_button |
pn.widgets.Button | Default button to manually refresh permissions data from the backend (150px wide) | instance |
message_area |
pn.pane.Markdown | Markdown pane for displaying status messages with color-coded styling (success, error, warning) | instance |
access_table |
pn.widgets.Tabulator | Tabulator widget displaying current user permissions with columns: User, Role, Access Type, Last Updated (300px height, 500px width) | instance |
layout |
pn.Column | Main Panel Column layout containing all UI components arranged vertically with rows and dividers | instance |
Dependencies
panelparampandasloggingdatetimepyperclipCDocs.models.documentCDocs.models.user_extensionsCDocs.controllers.share_controller
Required Imports
import panel as pn
import param
import pandas as pd
from typing import Dict, List, Any, Optional, Callable
import logging
from datetime import datetime
from CDocs.models.document import ControlledDocument, DocumentVersion
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.share_controller import get_document_share_url, get_user_access_url, manage_document_permissions
Conditional/Optional Imports
These imports are only needed under specific conditions:
import pyperclip
Condition: only needed when copying URL to clipboard via the Copy URL button; gracefully degrades if not available
OptionalUsage Example
import panel as pn
from document_share_manager import DocumentShareManager
# Initialize Panel extension
pn.extension('tabulator')
# Create manager instance with document and user UIDs
share_manager = DocumentShareManager(
document_uid='doc-12345-abcde',
user_uid='user-67890-fghij'
)
# Display the UI in a Panel application
share_manager.view().servable()
# Or update document dynamically
share_manager.document_uid = 'doc-new-uid'
share_manager._update_display()
# Access UI components directly if needed
share_manager.message_area.object = 'Custom message'
# Serve in a Panel app
app = pn.template.FastListTemplate(
title='Document Sharing',
main=[share_manager.view()]
)
app.servable()
Best Practices
- Always set document_uid before displaying the component to avoid 'No document selected' state
- Call _update_display() after changing document_uid or user_uid to refresh the UI with new data
- Handle the optional pyperclip dependency gracefully - the component will show a manual copy message if unavailable
- The component automatically initializes and updates on instantiation, no manual initialization needed
- Use the view() method to get the renderable layout for Panel applications
- The access_table uses Tabulator widget which requires Panel's tabulator extension to be loaded
- Error messages are displayed in the message_area with color-coded styling (green for success, red for errors, orange for warnings)
- The component maintains its own state through Panel widgets - avoid directly modifying widget values outside the class methods
- Refresh permissions periodically using the Refresh Permissions button or programmatically calling _refresh_permissions()
- The component expects a logger instance to be available in the module scope for error logging
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class SharePermissionIndicator 75.4% similar
-
class DocumentAccessControls 71.0% similar
-
class ControlledDocApp 61.6% similar
-
class CDocsApp 59.1% similar
-
function manage_document_permissions 58.6% similar