diff --git a/ProcessMaker/Http/Controllers/Api/CasesRetentionController.php b/ProcessMaker/Http/Controllers/Api/CasesRetentionController.php
new file mode 100644
index 0000000000..218b7e0439
--- /dev/null
+++ b/ProcessMaker/Http/Controllers/Api/CasesRetentionController.php
@@ -0,0 +1,76 @@
+getConnection()->getDriverName();
+
+ $query->where(function ($q) use ($like, $driver) {
+ $q->where('id', 'like', $like)
+ ->orWhere('process_id', 'like', $like)
+ ->orWhere('deleted_count', 'like', $like)
+ ->orWhere('total_time_taken', 'like', $like);
+
+ if ($driver === 'pgsql') {
+ $q->orWhereRaw('case_ids::text ILIKE ?', [$like]);
+ } else {
+ $q->orWhereRaw('CAST(case_ids AS CHAR) LIKE ?', [$like]);
+ }
+ });
+ }
+
+ public function logs(Request $request): ApiCollection
+ {
+ $query = CaseRetentionPolicyLog::query();
+
+ if ($request->filled('filter')) {
+ $this->applyLogsFilter($query, (string) $request->input('filter'));
+ }
+
+ $orderBy = $request->input('order_by');
+ if ($orderBy && in_array($orderBy, self::LOG_SORT_COLUMNS, true)) {
+ $orderBy = DB::raw(preg_replace('/\.(.+)/', "->>'\$.$1'", $orderBy, 1));
+
+ $orderDirection = strtolower((string) $request->input('order_direction', 'asc'));
+ if (!in_array($orderDirection, ['asc', 'desc'], true)) {
+ $orderDirection = 'asc';
+ }
+
+ $query->orderBy($orderBy, $orderDirection);
+ } else {
+ $query->orderByDesc('created_at');
+ }
+
+ $response = $query->paginate($request->input('per_page', 10));
+
+ return new ApiCollection($response);
+ }
+}
diff --git a/ProcessMaker/Jobs/EvaluateProcessRetentionJob.php b/ProcessMaker/Jobs/EvaluateProcessRetentionJob.php
index a04cba2800..e5b14a267d 100644
--- a/ProcessMaker/Jobs/EvaluateProcessRetentionJob.php
+++ b/ProcessMaker/Jobs/EvaluateProcessRetentionJob.php
@@ -184,7 +184,7 @@ public function handle(): void
CaseRetentionPolicyLog::create([
'process_id' => $this->processId,
- 'case_ids' => json_encode($caseIds),
+ 'case_ids' => $caseIds,
'deleted_count' => $chunkSize,
'total_time_taken' => $chunkTimeMs,
'deleted_at' => Carbon::now(),
diff --git a/ProcessMaker/Models/CaseRetentionPolicyLog.php b/ProcessMaker/Models/CaseRetentionPolicyLog.php
index 35da191f1e..a2d16c7364 100644
--- a/ProcessMaker/Models/CaseRetentionPolicyLog.php
+++ b/ProcessMaker/Models/CaseRetentionPolicyLog.php
@@ -25,4 +25,8 @@ class CaseRetentionPolicyLog extends ProcessMakerModel
'total_time_taken',
'deleted_at',
];
+
+ protected $casts = [
+ 'case_ids' => 'array',
+ ];
}
diff --git a/database/factories/ProcessMaker/Models/CaseRetentionPolicyLogFactory.php b/database/factories/ProcessMaker/Models/CaseRetentionPolicyLogFactory.php
index e38c9a3fb8..9a82e8d17d 100644
--- a/database/factories/ProcessMaker/Models/CaseRetentionPolicyLogFactory.php
+++ b/database/factories/ProcessMaker/Models/CaseRetentionPolicyLogFactory.php
@@ -22,7 +22,7 @@ public function definition()
'process_id' => function () {
return Process::factory()->create()->id;
},
- 'case_ids' => json_encode(CaseNumber::factory()->count($this->faker->numberBetween(1, 1000))->create()->pluck('id')->toArray()),
+ 'case_ids' => CaseNumber::factory()->count($this->faker->numberBetween(1, 1000))->create()->pluck('id')->toArray(),
'deleted_count' => $this->faker->numberBetween(1, 1000),
'total_time_taken' => $this->faker->numberBetween(1, 1000000),
'deleted_at' => $this->faker->dateTimeBetween('-1 year', 'now'),
diff --git a/resources/js/admin/cases-retention/components/CaseIdsTableCell.vue b/resources/js/admin/cases-retention/components/CaseIdsTableCell.vue
new file mode 100644
index 0000000000..8710bc181e
--- /dev/null
+++ b/resources/js/admin/cases-retention/components/CaseIdsTableCell.vue
@@ -0,0 +1,172 @@
+
+
+
+ —
+
+
+ {{ ids.join(", ") }}
+
+
+
+
+
+ {{ $t("Case IDs") }}
+ ({{ ids.length }})
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/admin/cases-retention/components/CasesRetentionLogs.vue b/resources/js/admin/cases-retention/components/CasesRetentionLogs.vue
index 933e99eef1..ea6f5ff671 100644
--- a/resources/js/admin/cases-retention/components/CasesRetentionLogs.vue
+++ b/resources/js/admin/cases-retention/components/CasesRetentionLogs.vue
@@ -34,7 +34,11 @@
slot="case_ids"
slot-scope="props"
>
- {{ props.rowData.case_ids.join(', ') }}
+
this.$t("Case IDs"),
name: "__slot:case_ids",
- sortField: "case_ids",
width: "16.66%",
},
{
@@ -189,32 +147,32 @@ export default {
width: "16.66%",
},
],
+ caseIdsPreviewLimit: 5,
};
},
watch: {
filter() {
- this.page = 1;
+ // this.page = 1;
this.fetch();
},
+
},
methods: {
fetch() {
- // TODO: replace with API call when retention_policy_logs table and endpoint exist
- const total = FAKE_RETENTION_LOGS.length;
- this.data = {
- data: FAKE_RETENTION_LOGS,
- meta: {
- total,
- per_page: 15,
- current_page: 1,
- last_page: 1,
- from: 1,
- to: total,
- total_pages: 1,
- count: total,
+ ProcessMaker.apiClient.get('cases-retention/logs', {
+ params: {
+ filter: this.filter,
+ order_by: this.orderBy,
+ order_direction: this.orderDirection,
+ page: this.page,
+ per_page: this.perPage,
},
- };
- this.apiDataLoading = false;
+ }).then(response => {
+ this.data = this.transform(response.data);
+ this.apiDataLoading = false;
+ }).catch(error => {
+ this.apiDataLoading = false;
+ });
},
reload() {
this.fetch();
diff --git a/routes/api.php b/routes/api.php
index 99eb8b31d7..8617b3de7e 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -4,6 +4,7 @@
use ProcessMaker\Http\Controllers\Admin\TenantQueueController;
use ProcessMaker\Http\Controllers\Api\BookmarkController;
use ProcessMaker\Http\Controllers\Api\CaseController;
+use ProcessMaker\Http\Controllers\Api\CasesRetentionController;
use ProcessMaker\Http\Controllers\Api\ChangePasswordController;
use ProcessMaker\Http\Controllers\Api\CommentController;
use ProcessMaker\Http\Controllers\Api\CssOverrideController;
@@ -450,5 +451,8 @@
// Slack Connector Validation
Route::post('connector-slack/validate-token', [ProcessMaker\Packages\Connectors\Slack\Controllers\SlackController::class, 'validateToken'])->name('connector-slack.validate-token');
+
+ // Cases Retention
+ Route::get('cases-retention/logs', [CasesRetentionController::class, 'logs'])->name('cases-retention.logs');
});
Route::post('devlink/bundle-updated/{bundle}/{token}', [DevLinkController::class, 'bundleUpdated'])->name('devlink.bundle-updated');
diff --git a/tests/unit/ProcessMaker/Models/CaseRetentionPolicyLogTest.php b/tests/unit/ProcessMaker/Models/CaseRetentionPolicyLogTest.php
index 285340552a..52c388feb2 100644
--- a/tests/unit/ProcessMaker/Models/CaseRetentionPolicyLogTest.php
+++ b/tests/unit/ProcessMaker/Models/CaseRetentionPolicyLogTest.php
@@ -57,7 +57,7 @@ public function testJobAddsLogRecordWhenCasesAreDeleted(): void
$this->assertIsNumeric($log->total_time_taken);
$this->assertNotNull($log->deleted_at);
- $loggedCaseIds = json_decode($log->case_ids, true);
+ $loggedCaseIds = $log->case_ids;
$this->assertIsArray($loggedCaseIds);
$this->assertContains((int) $caseOld->id, array_map('intval', $loggedCaseIds));