diff --git a/modules/helpdesk/i18n/default_de.json b/modules/helpdesk/i18n/default_de.json index e8e9b0f..fed4cd3 100644 --- a/modules/helpdesk/i18n/default_de.json +++ b/modules/helpdesk/i18n/default_de.json @@ -460,5 +460,25 @@ "Progress": "Fortschritt", "Created by": "Erstellt von", "Search handovers...": "Übergaben suchen...", - "ID": "ID" + "ID": "ID", + "History": "Verlauf", + "Current": "Aktuell", + "Viewing version %d": "Version %d wird angezeigt", + "compared with version %d": "verglichen mit Version %d", + "Back to current": "Zurück zur aktuellen Version", + "Restore this version": "Diese Version wiederherstellen", + "Restore this version?": "Diese Version wiederherstellen?", + "Version restored": "Version wiederhergestellt", + "Only managers can restore revisions": "Nur Manager können Versionen wiederherstellen", + "Revision not found": "Version nicht gefunden", + "Created": "Erstellt", + "Fields changed": "Felder geändert", + "Status changed": "Status geändert", + "Fields and status changed": "Felder und Status geändert", + "Restored": "Wiederhergestellt", + "was: %s": "war: %s", + "Yes": "Ja", + "No": "Nein", + "Changed": "Geändert", + "Compare with current": "Mit aktueller Version vergleichen" } diff --git a/modules/helpdesk/i18n/default_en.json b/modules/helpdesk/i18n/default_en.json index 560ee20..869c3ea 100644 --- a/modules/helpdesk/i18n/default_en.json +++ b/modules/helpdesk/i18n/default_en.json @@ -460,5 +460,25 @@ "Progress": "Progress", "Created by": "Created by", "Search handovers...": "Search handovers...", - "ID": "ID" + "ID": "ID", + "History": "History", + "Current": "Current", + "Viewing version %d": "Viewing version %d", + "compared with version %d": "compared with version %d", + "Back to current": "Back to current", + "Restore this version": "Restore this version", + "Restore this version?": "Restore this version?", + "Version restored": "Version restored", + "Only managers can restore revisions": "Only managers can restore revisions", + "Revision not found": "Revision not found", + "Created": "Created", + "Fields changed": "Fields changed", + "Status changed": "Status changed", + "Fields and status changed": "Fields and status changed", + "Restored": "Restored", + "was: %s": "was: %s", + "Yes": "Yes", + "No": "No", + "Changed": "Changed", + "Compare with current": "Compare with current" } diff --git a/modules/helpdesk/lib/Module/Helpdesk/HelpdeskContainerRegistrar.php b/modules/helpdesk/lib/Module/Helpdesk/HelpdeskContainerRegistrar.php index e95b3da..403633a 100644 --- a/modules/helpdesk/lib/Module/Helpdesk/HelpdeskContainerRegistrar.php +++ b/modules/helpdesk/lib/Module/Helpdesk/HelpdeskContainerRegistrar.php @@ -21,7 +21,9 @@ use MintyPHP\Module\Helpdesk\Service\SystemRecommendationEngine; use MintyPHP\Module\Helpdesk\Service\TicketCommunicationService; use MintyPHP\Module\Helpdesk\Handler\SoftwareProductSyncJobHandler; use MintyPHP\Module\Helpdesk\Repository\HandoverRepository; +use MintyPHP\Module\Helpdesk\Repository\HandoverRevisionRepository; use MintyPHP\Module\Helpdesk\Repository\SoftwareProductRepository; +use MintyPHP\Module\Helpdesk\Service\HandoverRevisionService; use MintyPHP\Module\Helpdesk\Service\HandoverService; use MintyPHP\Service\Access\PermissionService; use MintyPHP\Service\Settings\SettingServicesFactory; @@ -109,9 +111,17 @@ final class HelpdeskContainerRegistrar implements ContainerRegistrar $container->set(HandoverRepository::class, static fn (): HandoverRepository => new HandoverRepository()); + $container->set(HandoverRevisionRepository::class, static fn (): HandoverRevisionRepository => new HandoverRevisionRepository()); + + $container->set(HandoverRevisionService::class, static fn (AppContainer $c): HandoverRevisionService => new HandoverRevisionService( + $c->get(HandoverRevisionRepository::class), + $c->get(HandoverRepository::class) + )); + $container->set(HandoverService::class, static fn (AppContainer $c): HandoverService => new HandoverService( $c->get(HandoverRepository::class), - $c->get(SoftwareProductService::class) + $c->get(SoftwareProductService::class), + $c->get(HandoverRevisionService::class) )); } } diff --git a/modules/helpdesk/lib/Module/Helpdesk/Repository/HandoverRevisionRepository.php b/modules/helpdesk/lib/Module/Helpdesk/Repository/HandoverRevisionRepository.php new file mode 100644 index 0000000..bdacfb5 --- /dev/null +++ b/modules/helpdesk/lib/Module/Helpdesk/Repository/HandoverRevisionRepository.php @@ -0,0 +1,121 @@ + $data + * @return int|null Inserted ID or null on failure + */ + public function insert(array $data): ?int + { + $result = DB::insert( + 'INSERT INTO helpdesk_handover_revisions ' + . '(tenant_id, handover_id, revision, field_values, status, schema_version, change_type, changed_by) ' + . 'VALUES (?, ?, ?, ?, ?, ?, ?, ?)', + (string) ($data['tenant_id'] ?? 0), + (string) ($data['handover_id'] ?? 0), + (string) ($data['revision'] ?? 1), + $data['field_values'] ?? null, + (string) ($data['status'] ?? ''), + (string) ($data['schema_version'] ?? 1), + (string) ($data['change_type'] ?? 'fields'), + (string) ($data['changed_by'] ?? 0) + ); + + if ($result === false) { + return null; + } + + return (int) $result; + } + + /** + * Get the latest revision number for a handover. + */ + public function getLatestRevisionNumber(int $tenantId, int $handoverId): int + { + $value = DB::selectValue( + 'SELECT MAX(revision) FROM helpdesk_handover_revisions WHERE tenant_id = ? AND handover_id = ?', + (string) $tenantId, + (string) $handoverId + ); + + return $value !== null ? (int) $value : 0; + } + + /** + * Find a specific revision by handover ID and revision number. + * + * @return array|null + */ + public function findByRevision(int $tenantId, int $handoverId, int $revision): ?array + { + $row = DB::selectOne( + 'SELECT r.*, u.display_name AS changed_by_label, u.uuid AS changed_by_uuid' + . ' FROM helpdesk_handover_revisions r' + . ' LEFT JOIN users u ON u.id = r.changed_by' + . ' WHERE r.tenant_id = ? AND r.handover_id = ? AND r.revision = ? LIMIT 1', + (string) $tenantId, + (string) $handoverId, + (string) $revision + ); + + return $this->normalizeRow($row); + } + + /** + * List all revisions for a handover, newest first. + * + * @return list> + */ + public function listByHandover(int $tenantId, int $handoverId): array + { + $rows = DB::select( + 'SELECT r.*, u.display_name AS changed_by_label' + . ' FROM helpdesk_handover_revisions r' + . ' LEFT JOIN users u ON u.id = r.changed_by' + . ' WHERE r.tenant_id = ? AND r.handover_id = ?' + . ' ORDER BY r.revision DESC', + (string) $tenantId, + (string) $handoverId + ); + + $result = []; + if (is_array($rows)) { + foreach ($rows as $row) { + $item = $this->normalizeRow($row); + if ($item !== null) { + $result[] = $item; + } + } + } + + return $result; + } + + private function normalizeRow(mixed $row): ?array + { + if (!is_array($row)) { + return null; + } + + $item = []; + foreach ($row as $key => $value) { + if (is_array($value)) { + $item = array_merge($item, $value); + } else { + $item[$key] = $value; + } + } + + if (!isset($item['id'])) { + return null; + } + + return $item; + } +} diff --git a/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverRevisionService.php b/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverRevisionService.php new file mode 100644 index 0000000..050fb26 --- /dev/null +++ b/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverRevisionService.php @@ -0,0 +1,176 @@ + $fieldValues + */ + public function createRevision( + int $tenantId, + int $handoverId, + array $fieldValues, + string $status, + int $schemaVersion, + int $userId, + string $changeType = self::CHANGE_TYPE_FIELDS, + ): ?int { + $nextRevision = $this->revisionRepository->getLatestRevisionNumber($tenantId, $handoverId) + 1; + + $fieldValuesJson = json_encode($fieldValues, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + + return $this->revisionRepository->insert([ + 'tenant_id' => $tenantId, + 'handover_id' => $handoverId, + 'revision' => $nextRevision, + 'field_values' => $fieldValuesJson, + 'status' => $status, + 'schema_version' => $schemaVersion, + 'change_type' => $changeType, + 'changed_by' => $userId, + ]); + } + + /** + * List all revisions for a handover, newest first. + * + * @return list> + */ + public function listByHandover(int $tenantId, int $handoverId): array + { + return $this->revisionRepository->listByHandover($tenantId, $handoverId); + } + + /** + * Find a specific revision. + * + * @return array|null + */ + public function findRevision(int $tenantId, int $handoverId, int $revision): ?array + { + return $this->revisionRepository->findByRevision($tenantId, $handoverId, $revision); + } + + /** + * Compute the diff between two sets of field values. + * + * @param array $oldValues + * @param array $newValues + * @return array + */ + public function computeDiff(array $oldValues, array $newValues): array + { + $diff = []; + $allKeys = array_unique(array_merge(array_keys($oldValues), array_keys($newValues))); + + foreach ($allKeys as $key) { + $oldVal = $oldValues[$key] ?? null; + $newVal = $newValues[$key] ?? null; + + if ($oldVal === null && $newVal !== null) { + $diff[$key] = ['type' => 'added', 'old' => null, 'new' => $newVal]; + } elseif ($oldVal !== null && $newVal === null) { + $diff[$key] = ['type' => 'removed', 'old' => $oldVal, 'new' => null]; + } elseif ((string) $oldVal !== (string) $newVal) { + $diff[$key] = ['type' => 'changed', 'old' => $oldVal, 'new' => $newVal]; + } + } + + return $diff; + } + + /** + * Restore a handover to a previous revision's values. + * Creates a new revision with the restored values. + * + * @return array{ok: bool, errors: array} + */ + public function restoreRevision( + int $tenantId, + int $handoverId, + int $revisionNumber, + int $userId, + string $permissionLevel, + ): array { + if ($permissionLevel !== HandoverService::PERMISSION_MANAGE) { + return ['ok' => false, 'errors' => ['general' => t('Only managers can restore revisions')]]; + } + + $revision = $this->revisionRepository->findByRevision($tenantId, $handoverId, $revisionNumber); + if ($revision === null) { + return ['ok' => false, 'errors' => ['general' => t('Revision not found')]]; + } + + $handover = $this->handoverRepository->findById($tenantId, $handoverId); + if ($handover === null) { + return ['ok' => false, 'errors' => ['general' => t('Handover not found')]]; + } + + $restoredValues = json_decode((string) ($revision['field_values'] ?? '{}'), true); + if (!is_array($restoredValues)) { + $restoredValues = []; + } + + $restoredStatus = (string) ($revision['status'] ?? $handover['status']); + + // Update the handover with restored values + $fieldValuesJson = json_encode($restoredValues, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + $this->handoverRepository->updateFieldValues($tenantId, $handoverId, $fieldValuesJson, $userId); + + $currentStatus = (string) ($handover['status'] ?? ''); + if ($restoredStatus !== $currentStatus) { + $this->handoverRepository->updateStatus($tenantId, $handoverId, $restoredStatus, $userId); + } + + // Determine schema version from current handover + $schema = json_decode((string) ($handover['schema_snapshot'] ?? '{}'), true); + $schemaVersion = is_array($schema) ? (int) ($schema['version'] ?? 1) : 1; + + // Create a new revision marking the restore + $this->createRevision( + $tenantId, + $handoverId, + $restoredValues, + $restoredStatus, + $schemaVersion, + $userId, + self::CHANGE_TYPE_RESTORE + ); + + return ['ok' => true, 'errors' => []]; + } + + /** + * Get a human-readable label for a change type. + */ + public static function changeTypeLabel(string $changeType): string + { + return match ($changeType) { + self::CHANGE_TYPE_INITIAL => t('Created'), + self::CHANGE_TYPE_FIELDS => t('Fields changed'), + self::CHANGE_TYPE_STATUS => t('Status changed'), + self::CHANGE_TYPE_BOTH => t('Fields and status changed'), + self::CHANGE_TYPE_RESTORE => t('Restored'), + default => $changeType, + }; + } +} diff --git a/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverService.php b/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverService.php index b31e044..42fa63a 100644 --- a/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverService.php +++ b/modules/helpdesk/lib/Module/Helpdesk/Service/HandoverService.php @@ -45,6 +45,7 @@ class HandoverService public function __construct( private readonly HandoverRepository $repository, private readonly SoftwareProductService $softwareProductService, + private readonly ?HandoverRevisionService $revisionService = null, ) { } @@ -122,6 +123,17 @@ class HandoverService return ['ok' => false, 'id' => null, 'errors' => ['general' => t('Failed to create handover')]]; } + // Create initial revision (revision 1) + $this->revisionService?->createRevision( + $tenantId, + $id, + $fieldValues, + self::STATUS_DRAFT, + (int) ($schema['version'] ?? 1), + $userId, + HandoverRevisionService::CHANGE_TYPE_INITIAL + ); + return ['ok' => true, 'id' => $id, 'errors' => []]; } @@ -199,6 +211,76 @@ class HandoverService return ['ok' => true, 'errors' => []]; } + /** + * Create a revision snapshot after a combined save (fields + optional status change). + * Call this from the action after both updateFields and changeStatus have succeeded. + * + * @param array $fieldValues The final field values + */ + public function createRevisionAfterSave( + int $tenantId, + int $handoverId, + array $fieldValues, + string $status, + string $previousStatus, + int $schemaVersion, + int $userId, + ): void { + if ($this->revisionService === null) { + return; + } + + $statusChanged = $status !== $previousStatus; + $changeType = $statusChanged + ? HandoverRevisionService::CHANGE_TYPE_BOTH + : HandoverRevisionService::CHANGE_TYPE_FIELDS; + + $this->revisionService->createRevision( + $tenantId, + $handoverId, + $fieldValues, + $status, + $schemaVersion, + $userId, + $changeType + ); + } + + /** + * Create a revision for a status-only change. + */ + public function createRevisionForStatusChange( + int $tenantId, + int $handoverId, + string $newStatus, + int $schemaVersion, + int $userId, + ): void { + if ($this->revisionService === null) { + return; + } + + $handover = $this->repository->findById($tenantId, $handoverId); + if ($handover === null) { + return; + } + + $fieldValues = json_decode((string) ($handover['field_values'] ?? '{}'), true); + if (!is_array($fieldValues)) { + $fieldValues = []; + } + + $this->revisionService->createRevision( + $tenantId, + $handoverId, + $fieldValues, + $newStatus, + $schemaVersion, + $userId, + HandoverRevisionService::CHANGE_TYPE_STATUS + ); + } + /** * @return array{total: int, rows: list>} */ diff --git a/modules/helpdesk/migrations/006_create_handover_revisions.sql b/modules/helpdesk/migrations/006_create_handover_revisions.sql new file mode 100644 index 0000000..f5d0ea4 --- /dev/null +++ b/modules/helpdesk/migrations/006_create_handover_revisions.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS `helpdesk_handover_revisions` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + `tenant_id` INT UNSIGNED NOT NULL, + `handover_id` BIGINT UNSIGNED NOT NULL, + `revision` INT UNSIGNED NOT NULL, + `field_values` TEXT NULL DEFAULT NULL, + `status` VARCHAR(20) NOT NULL, + `schema_version` INT UNSIGNED NOT NULL DEFAULT 1, + `change_type` VARCHAR(20) NOT NULL DEFAULT 'fields', + `changed_by` INT UNSIGNED NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_hr_handover_revision` (`handover_id`, `revision`), + KEY `idx_hr_tenant_handover` (`tenant_id`, `handover_id`), + KEY `idx_hr_handover_created` (`handover_id`, `created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/modules/helpdesk/pages/helpdesk/handovers/_form.phtml b/modules/helpdesk/pages/helpdesk/handovers/_form.phtml index 3bb71c5..2ebf466 100644 --- a/modules/helpdesk/pages/helpdesk/handovers/_form.phtml +++ b/modules/helpdesk/pages/helpdesk/handovers/_form.phtml @@ -6,10 +6,13 @@ * $schemaFields — list of field definitions from schema_snapshot['fields'] * $fieldValues — associative array of current field values (key => value) * $readonly — bool, if true all inputs are disabled + * $fieldDiff — (optional) associative array of diffs: key => ['type' => added|removed|changed, 'old' => ..., 'new' => ...] */ $schemaFields = is_array($schemaFields ?? null) ? $schemaFields : []; $fieldValues = is_array($fieldValues ?? null) ? $fieldValues : []; +$fieldDiff = is_array($fieldDiff ?? null) ? $fieldDiff : []; $readonly = !empty($readonly); +$hasDiff = $fieldDiff !== []; ?>

@@ -21,6 +24,8 @@ $readonly = !empty($readonly); $required = !empty($field['required']); $value = $key !== '' ? (string) ($fieldValues[$key] ?? '') : ''; $inputId = 'handover-field-' . $index; + $diff = ($key !== '' && isset($fieldDiff[$key])) ? $fieldDiff[$key] : null; + $diffClass = $diff !== null ? ' handover-diff-' . ($diff['type'] ?? '') : ''; ?>

@@ -29,50 +34,69 @@ $readonly = !empty($readonly);

- +
+ + + + + + + + +
- - +
+ + + + + +
- - +
+ + + + + +
'text', }; ?> - - aria-required="true" - disabled - > +
+ + aria-required="true" + disabled + > + + + +
diff --git a/modules/helpdesk/pages/helpdesk/handovers/edit($id).php b/modules/helpdesk/pages/helpdesk/handovers/edit($id).php index 2fdce52..f8c6337 100644 --- a/modules/helpdesk/pages/helpdesk/handovers/edit($id).php +++ b/modules/helpdesk/pages/helpdesk/handovers/edit($id).php @@ -3,6 +3,7 @@ use MintyPHP\Buffer; use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy; +use MintyPHP\Module\Helpdesk\Service\HandoverRevisionService; use MintyPHP\Module\Helpdesk\Service\HandoverService; use MintyPHP\Router; use MintyPHP\Session; @@ -16,13 +17,15 @@ $request = requestInput(); $returnTarget = requestResolveReturnTarget(); $closeTarget = requestResolveReturnTarget('helpdesk/handovers'); $handoverId = (int) ($id ?? 0); -$editTarget = requestPathWithReturnTarget('helpdesk/handovers/edit/' . $handoverId, $returnTarget); +$editBasePath = 'helpdesk/handovers/edit/' . $handoverId; +$editTarget = requestPathWithReturnTarget($editBasePath, $returnTarget); $session = app(SessionStoreInterface::class)->all(); $tenantId = (int) ($session['current_tenant']['id'] ?? 0); $userId = (int) ($session['user']['id'] ?? 0); $service = app(HandoverService::class); +$revisionService = app(HandoverRevisionService::class); $handover = $service->findById($tenantId, $handoverId); if ($handover === null) { @@ -47,6 +50,7 @@ $allowedStatuses = $service->getAllowedStatuses($permissionLevel); $schemaRaw = (string) ($handover['schema_snapshot'] ?? '{}'); $schema = json_decode($schemaRaw, true); $schemaFields = is_array($schema) ? ($schema['fields'] ?? []) : []; +$schemaVersion = is_array($schema) ? (int) ($schema['version'] ?? 1) : 1; // Parse field values $fieldValuesRaw = (string) ($handover['field_values'] ?? '{}'); @@ -57,6 +61,31 @@ if (!is_array($fieldValues)) { $errorBag = formErrors(); +// Handle restore POST +if ($request->isMethod('POST') && (string) $request->body('action', '') === 'restore') { + if (!Session::checkCsrfToken()) { + Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired'); + Router::redirect($editTarget); + + return; + } + + $restoreRevision = (int) $request->body('restore_revision', 0); + $restoreResult = $revisionService->restoreRevision($tenantId, $handoverId, $restoreRevision, $userId, $permissionLevel); + + if ($restoreResult['ok']) { + Flash::success(t('Version restored'), $editTarget, 'revision_restored'); + } else { + $firstError = reset($restoreResult['errors']) ?: t('Failed to restore'); + Flash::error($firstError, $editTarget, 'revision_restore_failed'); + } + + Router::redirect($editTarget); + + return; +} + +// Handle normal save POST if ($request->isMethod('POST') && $canEdit) { if (!Session::checkCsrfToken()) { Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired'); @@ -80,17 +109,34 @@ if ($request->isMethod('POST') && $canEdit) { } } + $previousStatus = $currentStatus; $updateResult = $service->updateFields($tenantId, $handoverId, $submittedValues, $userId, $permissionLevel); $errorBag->merge($updateResult['errors'] ?? []); // Handle status change $newStatus = (string) $request->body('status', ''); + $statusChanged = false; if ($newStatus !== '' && $newStatus !== $currentStatus) { $statusResult = $service->changeStatus($tenantId, $handoverId, $newStatus, $userId, $permissionLevel); $errorBag->merge($statusResult['errors'] ?? []); + if (empty($statusResult['errors'])) { + $statusChanged = true; + } } if (!$errorBag->hasAny()) { + // Create a single revision for the combined save + $finalStatus = $statusChanged ? $newStatus : $currentStatus; + $service->createRevisionAfterSave( + $tenantId, + $handoverId, + $submittedValues, + $finalStatus, + $previousStatus, + $schemaVersion, + $userId + ); + $handover = $service->findById($tenantId, $handoverId); $fieldValues = $submittedValues; $currentStatus = (string) ($handover['status'] ?? $currentStatus); @@ -111,11 +157,61 @@ if ($request->isMethod('POST') && $canEdit) { $validationSummaryErrors = $errorBag->toArray(); $errors = $errorBag->toFlatList(); +// Load revision data +$revisions = $revisionService->listByHandover($tenantId, $handoverId); +$activeRevisionNumber = (int) $request->query('revision', 0); +$compareRevisionNumber = (int) $request->query('compare', 0); +$isViewingRevision = $activeRevisionNumber > 0; +$activeRevision = null; +$fieldDiff = []; + +if ($isViewingRevision) { + $activeRevision = $revisionService->findRevision($tenantId, $handoverId, $activeRevisionNumber); + if ($activeRevision === null) { + // Invalid revision number — fall back to current + $isViewingRevision = false; + $activeRevisionNumber = 0; + } else { + // Load this revision's field values + $revisionFieldValues = json_decode((string) ($activeRevision['field_values'] ?? '{}'), true); + if (!is_array($revisionFieldValues)) { + $revisionFieldValues = []; + } + + // Compute diff + if ($compareRevisionNumber > 0) { + // Compare against a specific revision + $compareRevision = $revisionService->findRevision($tenantId, $handoverId, $compareRevisionNumber); + if ($compareRevision !== null) { + $compareValues = json_decode((string) ($compareRevision['field_values'] ?? '{}'), true); + if (!is_array($compareValues)) { + $compareValues = []; + } + $fieldDiff = $revisionService->computeDiff($compareValues, $revisionFieldValues); + } + } elseif ($activeRevisionNumber > 1) { + // Compare against previous revision + $prevRevision = $revisionService->findRevision($tenantId, $handoverId, $activeRevisionNumber - 1); + if ($prevRevision !== null) { + $prevValues = json_decode((string) ($prevRevision['field_values'] ?? '{}'), true); + if (!is_array($prevValues)) { + $prevValues = []; + } + $fieldDiff = $revisionService->computeDiff($prevValues, $revisionFieldValues); + } + } + + $fieldValues = $revisionFieldValues; + $currentStatus = (string) ($activeRevision['status'] ?? $currentStatus); + } +} + $productCode = (string) ($handover['product_code'] ?? ''); $product = app(\MintyPHP\Module\Helpdesk\Service\SoftwareProductService::class)->findByCode($productCode); $productName = trim((string) ($product['name'] ?? '')) !== '' ? $product['name'] : (trim((string) ($product['bc_description'] ?? '')) !== '' ? $product['bc_description'] : $productCode); +$canViewSoftwareProducts = $authService->authorize(HelpdeskAuthorizationPolicy::ABILITY_SOFTWARE_PRODUCTS_MANAGE, $actorContext)->isAllowed(); $titleText = t('Handover') . ' ' . $productName; Buffer::set('title', $titleText); Buffer::set('style_groups', json_encode(['helpdesk'])); diff --git a/modules/helpdesk/pages/helpdesk/handovers/edit(default).phtml b/modules/helpdesk/pages/helpdesk/handovers/edit(default).phtml index 5cabd7a..9638ef9 100644 --- a/modules/helpdesk/pages/helpdesk/handovers/edit(default).phtml +++ b/modules/helpdesk/pages/helpdesk/handovers/edit(default).phtml @@ -1,5 +1,6 @@
@@ -24,7 +33,7 @@ $readonly = !$canEdit; 'title' => $titleText ?? t('Handover'), 'backHref' => $closeTarget, 'backTitle' => t('Back to list'), - 'actions' => $canEdit ? [ + 'actions' => ($canEdit && !$isViewingRevision) ? [ [ 'form' => $formId, 'name' => 'action', @@ -44,9 +53,22 @@ $readonly = !$canEdit; require templatePath('partials/app-details-titlebar.phtml'); ?> + +
+

+ + + 0): ?> + — + +

+ +
+ + - +
@@ -75,19 +97,30 @@ $readonly = !$canEdit;