Skip to content

Commit f60b95f

Browse files
committed
DRY up audit components, fix path on Docs, fix database for testing/pipeline
1 parent 45dbe16 commit f60b95f

9 files changed

Lines changed: 184 additions & 420 deletions

File tree

app/Console/Commands/PreCommitChecks.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ public function handle()
5353

5454
// Refresh testing database before running tests
5555
if ($check === 'tests:php') {
56-
$this->refreshTestingDatabase();
5756
$env = [
5857
'APP_ENV' => 'testing',
5958
'DB_CONNECTION' => 'sqlite',
6059
'DB_DATABASE' => ':memory:',
6160
];
61+
$this->refreshTestingDatabase();
6262
}
6363

6464
$this->info("========== Running $check ==========");
@@ -156,13 +156,13 @@ protected function refreshTestingDatabase(): void
156156
// Override the database configuration for testing
157157
config([
158158
'database.connections.sqlite.database' => ':memory:',
159-
'database.default' => 'sqlite',
159+
'database.default' => 'sqlite_testing',
160160
]);
161161

162162
$this->call('migrate:fresh', [
163163
'--env' => 'testing',
164164
'--seed' => true,
165-
'--database' => 'sqlite',
165+
'--database' => 'sqlite_testing',
166166
]);
167167
$this->info("Testing database refreshed successfully");
168168
} catch (\Exception $e) {

config/database.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
'synchronous' => null,
4343
],
4444

45+
'sqlite_testing' => [
46+
'driver' => 'sqlite',
47+
'database' => ':memory:',
48+
],
49+
4550
// connector for doing zip 3 to timezone lookups
4651
'zip3_to_timezone' => [
4752
'driver' => 'sqlite',

resources/js/Components/Audit/AuditFieldValue.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,24 @@ export default function AuditFieldValue({
3737
const [modalOpen, setModalOpen] = useState(false);
3838

3939
const formatValue = (value: unknown): string => {
40+
// Check for folder-related fields (both raw and formatted names)
41+
const isFolderField = fieldName === 'folder_name' || fieldName === 'Folder Name';
42+
const isPathField = fieldName === 'path' || fieldName === 'Path';
43+
4044
if (value === null || value === undefined) {
45+
// For path fields, only show '/' if the value was explicitly set to null/undefined
46+
// but not when there was no previous value (which should show 'No value')
4147
return 'No value';
4248
}
4349
if (typeof value === 'boolean') {
50+
// Special handling for folder fields - don't convert to Yes/No
51+
if (isFolderField) {
52+
return value ? 'true' : '/';
53+
}
54+
// Special handling for path fields - show root folder when false
55+
if (isPathField) {
56+
return value ? 'true' : '/';
57+
}
4458
return value ? 'Yes' : 'No';
4559
}
4660
if (typeof value === 'object') {
@@ -49,6 +63,11 @@ export default function AuditFieldValue({
4963

5064
const stringValue = String(value);
5165

66+
// Special handling for folder fields - show root folder when empty
67+
if (isFolderField && stringValue.trim() === '') {
68+
return '/';
69+
}
70+
5271
// Special handling for file paths
5372
if (fieldName === 'path' && stringValue) {
5473
// Extract just the filename from the path
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Card, CardContent } from '@/Components/ui/card';
2+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/Components/ui/tabs';
3+
import { Clock, Table } from 'lucide-react';
4+
import { useEffect, useState } from 'react';
5+
import AuditTable from './AuditTable';
6+
import AuditTimeline from './AuditTimeline';
7+
import { AuditEntry } from './types';
8+
9+
interface AuditHistoryProps {
10+
entityId: number;
11+
routeName: string;
12+
showTabs?: boolean;
13+
}
14+
15+
export default function AuditHistory({
16+
entityId,
17+
routeName,
18+
showTabs = true,
19+
}: AuditHistoryProps) {
20+
const [audits, setAudits] = useState<AuditEntry[]>([]);
21+
const [loading, setLoading] = useState(true);
22+
const [error, setError] = useState<string | null>(null);
23+
const [activeTab, setActiveTab] = useState('timeline');
24+
25+
useEffect(() => {
26+
const fetchAudits = async () => {
27+
try {
28+
setLoading(true);
29+
const response = await fetch(route(routeName, entityId));
30+
31+
if (!response.ok) {
32+
throw new Error('Failed to fetch audit history');
33+
}
34+
35+
const data = await response.json();
36+
setAudits(data.audits || []);
37+
} catch (err) {
38+
setError(
39+
err instanceof Error ? err.message : 'An error occurred',
40+
);
41+
} finally {
42+
setLoading(false);
43+
}
44+
};
45+
46+
if (entityId) {
47+
fetchAudits();
48+
}
49+
}, [entityId, routeName]);
50+
51+
if (error) {
52+
return (
53+
<Card>
54+
<CardContent className="p-6">
55+
<div className="py-8 text-center">
56+
<div className="mb-2 text-red-500">
57+
Error loading audit history
58+
</div>
59+
<div className="text-sm text-gray-500">{error}</div>
60+
</div>
61+
</CardContent>
62+
</Card>
63+
);
64+
}
65+
66+
if (!showTabs) {
67+
return <AuditTimeline audits={audits} loading={loading} />;
68+
}
69+
70+
return (
71+
<div className="space-y-6">
72+
<Tabs
73+
value={activeTab}
74+
onValueChange={setActiveTab}
75+
className="w-full"
76+
>
77+
<TabsList className="w-full">
78+
<TabsTrigger
79+
value="timeline"
80+
className="flex items-center gap-2"
81+
>
82+
<Clock className="h-4 w-4" />
83+
Audit Timeline
84+
</TabsTrigger>
85+
<TabsTrigger
86+
value="table"
87+
className="flex items-center gap-2"
88+
>
89+
<Table className="h-4 w-4" />
90+
Audit Table
91+
</TabsTrigger>
92+
</TabsList>
93+
94+
<TabsContent value="timeline" className="mt-6">
95+
<AuditTimeline audits={audits} loading={loading} />
96+
</TabsContent>
97+
98+
<TabsContent value="table" className="mt-6">
99+
<AuditTable audits={audits} loading={loading} />
100+
</TabsContent>
101+
</Tabs>
102+
</div>
103+
);
104+
}
Lines changed: 6 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,5 @@
1-
import { Card, CardContent } from '@/Components/ui/card';
2-
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/Components/ui/tabs';
31
import { Carrier } from '@/types';
4-
import { Clock, Table } from 'lucide-react';
5-
import { useEffect, useState } from 'react';
6-
import AuditTable from './AuditTable';
7-
import AuditTimeline from './AuditTimeline';
8-
9-
interface AuditChange {
10-
field: string;
11-
field_name: string;
12-
old_value: unknown;
13-
new_value: unknown;
14-
}
15-
16-
interface AuditEntry {
17-
id: number;
18-
event: string;
19-
user: {
20-
id: number;
21-
name: string;
22-
email: string;
23-
} | null;
24-
old_values: Record<string, unknown>;
25-
new_values: Record<string, unknown>;
26-
changes: AuditChange[];
27-
created_at: string;
28-
created_at_human: string;
29-
ip_address?: string;
30-
user_agent?: string;
31-
}
2+
import AuditHistory from './AuditHistory';
323

334
interface CarrierAuditHistoryProps {
345
carrier: Carrier;
@@ -37,86 +8,11 @@ interface CarrierAuditHistoryProps {
378
export default function CarrierAuditHistory({
389
carrier,
3910
}: CarrierAuditHistoryProps) {
40-
const [audits, setAudits] = useState<AuditEntry[]>([]);
41-
const [loading, setLoading] = useState(true);
42-
const [error, setError] = useState<string | null>(null);
43-
const [activeTab, setActiveTab] = useState('timeline');
44-
45-
useEffect(() => {
46-
const fetchAudits = async () => {
47-
try {
48-
setLoading(true);
49-
const response = await fetch(
50-
route('carriers.audit-history', carrier.id),
51-
);
52-
53-
if (!response.ok) {
54-
throw new Error('Failed to fetch audit history');
55-
}
56-
57-
const data = await response.json();
58-
setAudits(data.audits || []);
59-
} catch (err) {
60-
setError(
61-
err instanceof Error ? err.message : 'An error occurred',
62-
);
63-
} finally {
64-
setLoading(false);
65-
}
66-
};
67-
68-
if (carrier.id) {
69-
fetchAudits();
70-
}
71-
}, [carrier.id]);
72-
73-
if (error) {
74-
return (
75-
<Card>
76-
<CardContent className="p-6">
77-
<div className="py-8 text-center">
78-
<div className="mb-2 text-red-500">
79-
Error loading audit history
80-
</div>
81-
<div className="text-sm text-gray-500">{error}</div>
82-
</div>
83-
</CardContent>
84-
</Card>
85-
);
86-
}
87-
8811
return (
89-
<div className="space-y-6">
90-
<Tabs
91-
value={activeTab}
92-
onValueChange={setActiveTab}
93-
className="w-full"
94-
>
95-
<TabsList className="w-full">
96-
<TabsTrigger
97-
value="timeline"
98-
className="flex items-center gap-2"
99-
>
100-
<Clock className="h-4 w-4" />
101-
Audit Timeline
102-
</TabsTrigger>
103-
<TabsTrigger
104-
value="table"
105-
className="flex items-center gap-2"
106-
>
107-
<Table className="h-4 w-4" />
108-
Audit Table
109-
</TabsTrigger>
110-
</TabsList>
111-
112-
<TabsContent value="timeline" className="mt-6">
113-
<AuditTimeline audits={audits} loading={loading} />
114-
</TabsContent>
115-
116-
<TabsContent value="table" className="mt-6">
117-
<AuditTable audits={audits} loading={loading} />
118-
</TabsContent>
119-
</Tabs>
120-
</div>
12+
<AuditHistory
13+
entityId={carrier.id}
14+
routeName="carriers.audit-history"
15+
showTabs={true}
16+
/>
12117
);
12218
}

0 commit comments

Comments
 (0)