From 0f00ea6434d9bcfac4a9492a8749bd7e4be1cb6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:30:34 +0000 Subject: [PATCH 1/2] Initial plan From a8d4827dbd87bd4629a9f9612648c62720a986c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:46:30 +0000 Subject: [PATCH 2/2] Complete collaborative editing documentation implementation Co-authored-by: mnocon <10993858+mnocon@users.noreply.github.com> --- .../collaboration_event_listener.php | 110 ++++++++ .../create_invitation.php | 60 +++++ .../session_management.php | 98 +++++++ .../collaborative_editing_events.md | 230 ++++++++++++++++ .../collaborative_editing_guide.md | 251 ++++++++++++++++++ mkdocs.yml | 1 + 6 files changed, 750 insertions(+) create mode 100644 code_samples/collaborative_editing/collaboration_event_listener.php create mode 100644 code_samples/collaborative_editing/create_invitation.php create mode 100644 code_samples/collaborative_editing/session_management.php create mode 100644 docs/content_management/collaborative_editing/collaborative_editing_events.md create mode 100644 docs/content_management/collaborative_editing/collaborative_editing_guide.md diff --git a/code_samples/collaborative_editing/collaboration_event_listener.php b/code_samples/collaborative_editing/collaboration_event_listener.php new file mode 100644 index 0000000000..dc5f892597 --- /dev/null +++ b/code_samples/collaborative_editing/collaboration_event_listener.php @@ -0,0 +1,110 @@ + 'onJoinSession', + SessionPublicPreviewEvent::class => 'onSessionPublicPreview', + ]; + } + + /** + * Handle user joining a collaboration session + */ + public function onJoinSession(JoinSessionEvent $event): void + { + $session = $event->getSession(); + $user = $event->getUser(); + + $this->logger->info('User joined collaboration session', [ + 'user_id' => $user->getId(), + 'user_name' => $user->getName(), + 'session_id' => $session->getId(), + 'content_id' => $session->getContentId(), + ]); + + // Custom logic: Send notification to other participants + $this->notifyOtherParticipants($session, $user); + + // Custom logic: Update user activity metrics + $this->updateUserActivityMetrics($user->getId(), 'session_join'); + } + + /** + * Handle public preview access for collaboration session + */ + public function onSessionPublicPreview(SessionPublicPreviewEvent $event): void + { + $session = $event->getSession(); + $content = $this->contentService->loadContent($session->getContentId()); + + $this->logger->info('Public preview accessed for collaboration session', [ + 'session_id' => $session->getId(), + 'content_id' => $session->getContentId(), + 'content_name' => $content->getName(), + 'preview_url' => $event->getPreviewUrl(), + ]); + + // Custom logic: Track public preview usage + $this->trackPublicPreviewAccess($session, $event->getPreviewUrl()); + } + + /** + * Notify other participants when someone joins the session + */ + private function notifyOtherParticipants($session, $user): void + { + // Implementation would send real-time notifications + // to other active participants in the session + $this->logger->debug('Notifying other participants of new joiner', [ + 'session_id' => $session->getId(), + 'new_participant' => $user->getName(), + ]); + } + + /** + * Update user activity metrics for analytics + */ + private function updateUserActivityMetrics(int $userId, string $action): void + { + // Implementation would update user activity statistics + // for collaboration analytics and reporting + $this->logger->debug('Updated user activity metrics', [ + 'user_id' => $userId, + 'action' => $action, + 'timestamp' => new \DateTime(), + ]); + } + + /** + * Track public preview access for analytics + */ + private function trackPublicPreviewAccess($session, string $previewUrl): void + { + // Implementation would track public preview usage + // for collaboration session analytics + $this->logger->debug('Tracked public preview access', [ + 'session_id' => $session->getId(), + 'preview_url' => $previewUrl, + 'access_time' => new \DateTime(), + ]); + } +} \ No newline at end of file diff --git a/code_samples/collaborative_editing/create_invitation.php b/code_samples/collaborative_editing/create_invitation.php new file mode 100644 index 0000000000..8d47d3038f --- /dev/null +++ b/code_samples/collaborative_editing/create_invitation.php @@ -0,0 +1,60 @@ +contentService->loadContent($contentId); + $user = $this->userService->loadUser($userId); + + $invitationCreateStruct = new InvitationCreateStruct(); + $invitationCreateStruct->contentId = $contentId; + $invitationCreateStruct->userId = $userId; + $invitationCreateStruct->message = $message; + $invitationCreateStruct->permissions = ['edit', 'comment']; + + $invitation = $this->invitationService->createInvitation($invitationCreateStruct); + + // Send notification to invited user + // This would typically trigger email notifications + echo "Invitation created for user {$user->getName()} to collaborate on '{$content->getName()}'"; + } + + /** + * Create invitation for external user by email + */ + public function createExternalInvitation(int $contentId, string $email, string $message = ''): void + { + $content = $this->contentService->loadContent($contentId); + + $invitationCreateStruct = new InvitationCreateStruct(); + $invitationCreateStruct->contentId = $contentId; + $invitationCreateStruct->email = $email; + $invitationCreateStruct->message = $message; + $invitationCreateStruct->permissions = ['comment']; // Limited permissions for external users + $invitationCreateStruct->expirationDate = new \DateTime('+7 days'); // Expires in 7 days + + $invitation = $this->invitationService->createInvitation($invitationCreateStruct); + + echo "External invitation created for {$email} to collaborate on '{$content->getName()}'"; + } +} \ No newline at end of file diff --git a/code_samples/collaborative_editing/session_management.php b/code_samples/collaborative_editing/session_management.php new file mode 100644 index 0000000000..be1bbb86f0 --- /dev/null +++ b/code_samples/collaborative_editing/session_management.php @@ -0,0 +1,98 @@ +contentId = $contentId; + $sessionCreateStruct->participants = $participants; + $sessionCreateStruct->settings = [ + 'realTimeEnabled' => true, + 'allowExternalUsers' => false, + 'maxParticipants' => 10, + 'autoSave' => true, + ]; + + $session = $this->sessionService->createSession($sessionCreateStruct); + + echo "Collaboration session created with ID: {$session->getId()}"; + } + + /** + * Find active collaboration sessions for a user + */ + public function findUserSessions(int $userId): array + { + $query = new SessionQuery(); + $query->filter = new Criterion\ParticipantId($userId); + $query->sortClauses = [ + new SortClause\UpdatedAt('DESC'), + ]; + $query->limit = 50; + + $searchResult = $this->sessionService->findSessions($query); + + return $searchResult->sessions; + } + + /** + * Join an existing collaboration session + */ + public function joinSession(int $sessionId, int $userId): void + { + $session = $this->sessionService->loadSession($sessionId); + + // Add user as participant + $this->sessionService->addParticipant($sessionId, $userId); + + echo "User {$userId} joined collaboration session {$sessionId}"; + } + + /** + * Leave a collaboration session + */ + public function leaveSession(int $sessionId, int $userId): void + { + $this->sessionService->removeParticipant($sessionId, $userId); + + echo "User {$userId} left collaboration session {$sessionId}"; + } + + /** + * Get session statistics + */ + public function getSessionStats(int $sessionId): array + { + $session = $this->sessionService->loadSession($sessionId); + $participants = $this->sessionService->getSessionParticipants($sessionId); + + return [ + 'session_id' => $session->getId(), + 'content_id' => $session->getContentId(), + 'created_at' => $session->getCreatedAt(), + 'updated_at' => $session->getUpdatedAt(), + 'participant_count' => count($participants), + 'active_participants' => array_filter($participants, fn($p) => $p->isActive()), + 'real_time_enabled' => $session->getSetting('realTimeEnabled', false), + ]; + } +} \ No newline at end of file diff --git a/docs/content_management/collaborative_editing/collaborative_editing_events.md b/docs/content_management/collaborative_editing/collaborative_editing_events.md new file mode 100644 index 0000000000..473158aa6d --- /dev/null +++ b/docs/content_management/collaborative_editing/collaborative_editing_events.md @@ -0,0 +1,230 @@ +--- +description: Learn about events triggered during collaborative editing sessions in Ibexa DXP. +--- + +# Collaborative editing events + +The collaborative editing feature in Ibexa DXP provides a comprehensive event system that allows developers to hook into various collaboration lifecycle stages and customize the behavior according to their needs. + +## Available events + +### Session events + +#### JoinSessionEvent + +The `JoinSessionEvent` is triggered when a user joins a collaboration session. + +**Event class:** `Ibexa\Contracts\Collaboration\Session\Event\JoinSessionEvent` + +**Properties:** +- `getSession()` - Returns the collaboration session +- `getUser()` - Returns the user joining the session +- `getTimestamp()` - Returns when the join occurred + +**Use cases:** +- Send notifications to other participants +- Log user activity for analytics +- Apply custom permissions or restrictions +- Initialize user-specific collaboration settings + +#### SessionPublicPreviewEvent + +The `SessionPublicPreviewEvent` is triggered when public preview access is requested for a collaboration session. + +**Event class:** `Ibexa\Contracts\Collaboration\Session\Event\SessionPublicPreviewEvent` + +**Properties:** +- `getSession()` - Returns the collaboration session +- `getPreviewUrl()` - Returns the public preview URL +- `getAccessTime()` - Returns when preview was accessed + +**Use cases:** +- Track public preview usage +- Apply access restrictions +- Log preview activity +- Generate analytics reports + +### Invitation events + +Invitation events are triggered during the invitation lifecycle management. + +**Available invitation events:** +- `BeforeCreateInvitationEvent` - Before creating an invitation +- `AfterCreateInvitationEvent` - After invitation is created +- `BeforeAcceptInvitationEvent` - Before invitation is accepted +- `AfterAcceptInvitationEvent` - After invitation is accepted +- `BeforeDeclineInvitationEvent` - Before invitation is declined +- `AfterDeclineInvitationEvent` - After invitation is declined + +### Participant events + +Participant events handle user participation in collaboration sessions. + +**Available participant events:** +- `BeforeAddParticipantEvent` - Before adding a participant to session +- `AfterAddParticipantEvent` - After participant is added +- `BeforeRemoveParticipantEvent` - Before removing a participant +- `AfterRemoveParticipantEvent` - After participant is removed + +## Event listener examples + +### Basic event listener + +```php + 'onJoinSession', + ]; + } + + public function onJoinSession(JoinSessionEvent $event): void + { + $session = $event->getSession(); + $user = $event->getUser(); + + // Custom logic here + error_log("User {$user->getName()} joined session {$session->getId()}"); + } +} +``` + +### Advanced event handling + +For more complex event handling scenarios, see the [collaboration event listener example](../../code_samples/collaborative_editing/collaboration_event_listener.php). + +## Event configuration + +### Registering event listeners + +Register your event listeners in your bundle's service configuration: + +```yaml +# config/services.yaml +services: + App\EventListener\CollaborationEventListener: + tags: + - { name: kernel.event_subscriber } +``` + +### Event priorities + +You can set event listener priorities to control execution order: + +```yaml +services: + App\EventListener\CollaborationEventListener: + tags: + - { name: kernel.event_listener, event: Ibexa\Contracts\Collaboration\Session\Event\JoinSessionEvent, priority: 100 } +``` + +## Best practices + +### Performance considerations + +- **Keep event listeners lightweight** - Avoid heavy processing in event listeners +- **Use queued processing** for time-consuming tasks triggered by events +- **Cache frequently accessed data** to avoid repeated database queries +- **Log appropriately** - Balance debugging needs with performance + +### Error handling + +- **Handle exceptions gracefully** in event listeners to avoid breaking the collaboration flow +- **Log errors appropriately** for debugging and monitoring +- **Provide fallback behavior** when possible +- **Test event listeners thoroughly** including error scenarios + +### Security considerations + +- **Validate user permissions** in event listeners +- **Sanitize user input** from event data +- **Audit sensitive operations** triggered by events +- **Implement rate limiting** for resource-intensive event handlers + +## Integration patterns + +### Notification systems + +Use collaboration events to integrate with notification systems: + +```php +public function onJoinSession(JoinSessionEvent $event): void +{ + $this->notificationService->sendRealTimeNotification( + $event->getSession()->getParticipants(), + 'user_joined_session', + ['user' => $event->getUser()->getName()] + ); +} +``` + +### Analytics and reporting + +Collect collaboration metrics using events: + +```php +public function onJoinSession(JoinSessionEvent $event): void +{ + $this->analyticsService->trackEvent('collaboration_session_join', [ + 'session_id' => $event->getSession()->getId(), + 'user_id' => $event->getUser()->getId(), + 'timestamp' => $event->getTimestamp(), + ]); +} +``` + +### Workflow integration + +Integrate with content workflows: + +```php +public function onSessionComplete(SessionCompleteEvent $event): void +{ + $content = $this->contentService->loadContent($event->getSession()->getContentId()); + + // Trigger workflow transition + $this->workflowService->apply($content, 'review_completed'); +} +``` + +## Troubleshooting + +### Common issues + +- **Event not triggered** - Check event listener registration and service configuration +- **Performance degradation** - Profile event listeners and optimize heavy operations +- **Circular dependencies** - Avoid triggering events from within event listeners that could cause loops +- **Permission errors** - Ensure proper user context and permissions in event handlers + +### Debugging events + +Enable detailed logging for collaboration events: + +```yaml +# config/packages/dev/monolog.yaml +monolog: + handlers: + collaboration: + type: stream + path: '%kernel.logs_dir%/collaboration.log' + level: debug + channels: ['collaboration'] +``` + +Then use the collaboration channel in your event listeners: + +```php +$this->logger->debug('Collaboration event triggered', [ + 'event' => get_class($event), + 'session_id' => $event->getSession()->getId(), +]); +``` \ No newline at end of file diff --git a/docs/content_management/collaborative_editing/collaborative_editing_guide.md b/docs/content_management/collaborative_editing/collaborative_editing_guide.md new file mode 100644 index 0000000000..ff99a05283 --- /dev/null +++ b/docs/content_management/collaborative_editing/collaborative_editing_guide.md @@ -0,0 +1,251 @@ +--- +description: Learn about Ibexa DXP's Collaborative Editing feature that enables multiple users to work together on content creation and editing. +page_type: landing_page +month_change: true +editions: [headless, experience, commerce] +--- + +# Collaborative editing product guide + +**Collaborative editing** is a powerful feature in Ibexa DXP that allows multiple users to work together on content creation and editing in real-time or asynchronously. This feature enhances teamwork, streamlines the review process, and improves overall content management efficiency. + +## Capabilities and benefits + +### Real-time collaboration + +With collaborative editing, multiple users can: + +- **Preview, review, and edit** the same content simultaneously +- **See changes in real-time** as other users make modifications +- **Work asynchronously** on content when real-time collaboration isn't needed +- **Invite internal and external users** to collaboration sessions + +### Enhanced workflow management + +The collaborative editing feature provides: + +- **Multiple sharing options** for inviting collaborators +- **Dashboard integration** with dedicated tabs for managing shared content: + - **My shared drafts** - Content you've shared with others + - **Drafts shared with me** - Content others have shared with you +- **Organized collaboration** helping users stay on top of their collaborative work + +### User management and security + +Collaborative editing supports: + +- **Internal user collaboration** - Work with team members within your organization +- **External user sharing** - Invite external contributors and reviewers +- **Secure invitation system** - Control who can access and edit your content +- **Permission-based access** - Maintain control over editing capabilities + +## How it works + +### Starting a collaboration session + +1. **Open content** you want to collaborate on in the Ibexa DXP back office +2. **Use the sharing options** to invite collaborators +3. **Send invitations** to internal or external users +4. **Begin collaborative editing** once users join the session + +### Managing shared content + +Use the dedicated dashboard tabs to: + +- **Monitor active collaborations** in "My shared drafts" +- **Access content shared with you** in "Drafts shared with me" +- **Track collaboration status** and participant activity +- **Manage permissions** and session settings + +### Real-time editing features + +When multiple users are editing simultaneously: + +- **Live cursor tracking** shows where other users are working +- **Real-time content updates** display changes as they happen +- **Conflict resolution** helps manage concurrent edits +- **Version management** maintains content integrity + +## Getting started + +### Prerequisites + +Collaborative editing is available in: + +- [[= product_name_headless =]] +- [[= product_name_exp =]] +- [[= product_name_com =]] + +### Installation and configuration + +Collaborative editing is part of the core Ibexa DXP functionality. To enable the feature: + +1. **Ensure you have the collaboration package** installed: + ```bash + composer require ibexa/collaboration + ``` + +2. **Configure user permissions** for collaborative editing +3. **Set up notification preferences** for collaboration invitations +4. **Configure sharing options** based on your organization's needs + +### User interface + +The collaborative editing interface includes: + +- **Collaboration controls** in the content editing interface +- **User presence indicators** showing active collaborators +- **Real-time change notifications** and visual cues +- **Dashboard tabs** for managing collaborative content + +## Technical implementation + +### PHP API + +Collaborative editing provides extensive PHP API coverage through the `Ibexa\Contracts\Collaboration` namespace, including: + +- **Invitation management** - Create and manage collaboration invitations +- **Session handling** - Control collaboration sessions and participants +- **Participant management** - Add, remove, and manage session participants +- **Configuration options** - Customize collaborative editing behavior + +#### Code examples + +The following code examples demonstrate key collaborative editing functionality: + +- **[Creating invitations](../../code_samples/collaborative_editing/create_invitation.php)** - Shows how to invite internal and external users to collaborate +- **[Session management](../../code_samples/collaborative_editing/session_management.php)** - Demonstrates session creation, joining, and management +- **[Event handling](../../code_samples/collaborative_editing/collaboration_event_listener.php)** - Example event listener for collaboration events + +For detailed API documentation, see: +- [Collaboration PHP API](https://doc.ibexa.co/en/5.0/api/php_api/php_api_reference/namespaces/ibexa-contracts-collaboration.html) +- [Share PHP API](https://doc.ibexa.co/en/5.0/api/php_api/php_api_reference/namespaces/ibexa-contracts-share.html) + +### REST API + +The collaborative editing feature includes REST API endpoints for: + +- **Invitation** - Manage collaboration invitations via API +- **CollaborationSession** - Control session lifecycle and settings +- **Participant** - Handle participant management +- **ParticipantList** - Retrieve and manage participant lists + +### Events and integration + +The feature provides comprehensive event coverage for custom integrations: + +- **JoinSessionEvent** - Triggered when users join collaboration sessions +- **SessionPublicPreviewEvent** - Handles public preview access +- **Invitation events** - Manage invitation lifecycle events +- **Participant events** - Track participant activity and changes + +For detailed information on available events and how to use them, see [Collaborative editing events](collaborative_editing_events.md). + +### Search and queries + +Collaborative editing includes advanced query capabilities: + +- **Sort clauses** for organizing collaboration data: + - CreatedAt, UpdatedAt sorting for invitations and sessions + - Status-based sorting for invitation management + - ID-based sorting for consistent ordering + +- **Criteria system** for filtering collaborative content +- **Real-time search** integration for finding shared content + +## Use cases + +### Content team collaboration + +- **Editorial teams** working together on articles and blog posts +- **Marketing teams** collaborating on campaign content +- **Product teams** developing documentation and specifications + +### Review and approval workflows + +- **Content review processes** with multiple stakeholders +- **Approval workflows** involving managers and subject matter experts +- **Quality assurance** processes with dedicated reviewers + +### External collaboration + +- **Client collaboration** on project content and deliverables +- **Freelancer integration** for content creation and editing +- **Partner collaboration** on joint content initiatives + +### Educational and training content + +- **Course development** with multiple instructors +- **Training material creation** with subject matter experts +- **Collaborative knowledge base** development + +## Best practices + +### Organizing collaborative content + +- **Use clear naming conventions** for shared drafts +- **Set appropriate permissions** for different types of collaborators +- **Regularly review** shared content in dashboard tabs +- **Establish clear workflows** for collaborative editing processes + +### Managing real-time collaboration + +- **Communicate changes** effectively during real-time sessions +- **Avoid conflicting edits** by coordinating with other users +- **Use version control** features to track significant changes +- **Save work frequently** to prevent data loss + +### Security and access control + +- **Review external user access** regularly +- **Use time-limited sharing** when appropriate +- **Monitor collaboration activity** through dashboard tools +- **Implement proper user permission policies** + +## Integration with other features + +### Workflow integration + +Collaborative editing works seamlessly with: + +- **Content workflow systems** for approval processes +- **Version management** for tracking collaborative changes +- **Notification systems** for collaboration alerts + +### Dashboard integration + +The feature integrates with: + +- **User dashboards** with dedicated collaboration tabs +- **Activity feeds** showing collaboration updates +- **Task management** for collaborative content projects + +### Search and content discovery + +Collaborative editing enhances: + +- **Content search** with collaboration-aware filtering +- **Content organization** through shared content categorization +- **Content recommendations** based on collaboration patterns + +## Troubleshooting + +### Common issues + +- **Permission problems** - Check user roles and collaboration permissions +- **Real-time sync issues** - Verify network connectivity and browser settings +- **Invitation delivery** - Check email settings and spam filters +- **Performance optimization** - Monitor concurrent user limits and system resources + +### Support resources + +For additional help with collaborative editing: + +- Check the [PHP API documentation](https://doc.ibexa.co/en/5.0/api/php_api/php_api_reference/namespaces/ibexa-contracts-collaboration.html) +- Review [event reference documentation](../../api/event_reference/) +- Consult the [user guide](https://doc.ibexa.co/projects/userguide/en/master/) for end-user instructions +- Contact Ibexa support for advanced configuration assistance + +--- + +*Collaborative editing is a game-changing feature that transforms how teams work together on content. By enabling real-time collaboration and providing comprehensive management tools, it streamlines content creation processes and improves team productivity.* \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ca209a9202..f826482664 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -281,6 +281,7 @@ nav: - User field type: content_management/field_types/field_type_reference/userfield.md - Collaborative editing: - Collaborative editing product guide: content_management/collaborative_editing/collaborative_editing_guide.md + - Collaborative editing events: content_management/collaborative_editing/collaborative_editing_events.md - Templating: - Templating: templating/templating.md - Render content: