Skip to content

Commit 622ade0

Browse files
committed
fix: add error logging in catch blocks and improve history pane UI consistency
- Add console.warn in empty catch blocks for history logging failures - Restyle history pane to match Read/Write panel (purple border card, tabs-box header) - Use consistent rounded-[5px] borders, bg-component, and border-[#8A45FC] - Improve search bar, filter chips, and toolbar styling for dark/light themes - Extract StatusIcon outside component body to avoid re-renders - Clean up modal layout with meta info row and consistent section styling
1 parent bc742b2 commit 622ade0

4 files changed

Lines changed: 154 additions & 117 deletions

File tree

packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ export const ReadOnlyFunctionForm = ({
139139
duration,
140140
});
141141
}
142-
} catch {}
142+
} catch (e) {
143+
console.warn("Failed to log read history:", e);
144+
}
143145
};
144146

145147
return (

packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ export const WriteOnlyFunctionForm = ({
102102
input: inputStr,
103103
duration: Date.now() - startTime,
104104
});
105-
} catch {}
105+
} catch (histErr) {
106+
console.warn("Failed to log write history:", histErr);
107+
}
106108
} catch (e: any) {
107109
const errorPattern = /Contract (.*?)"}/;
108110
const match = errorPattern.exec(e.message);
@@ -126,7 +128,9 @@ export const WriteOnlyFunctionForm = ({
126128
duration: Date.now() - startTime,
127129
errorDetails: e.stack || e.message,
128130
});
129-
} catch {}
131+
} catch (histErr) {
132+
console.warn("Failed to log write history:", histErr);
133+
}
130134
}
131135
};
132136

packages/nextjs/app/debug/_components/contract/history/DebugHistory.tsx

Lines changed: 100 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ function entriesToCSV(entries: HistoryEntry[]): string {
5050
return [headers, ...rows].join("\n");
5151
}
5252

53+
const StatusIcon = ({ status }: { status: HistoryEntry["status"] }) => (
54+
<Image
55+
src={status === "success" ? "/success-icon.svg" : "/fail-icon.svg"}
56+
alt={status}
57+
width={16}
58+
height={16}
59+
/>
60+
);
61+
5362
export default function DebugHistory() {
5463
const [selectedContract] = useLocalStorage<ContractName>(
5564
"scaffoldStark2.selectedContract",
@@ -58,7 +67,9 @@ export default function DebugHistory() {
5867
);
5968
const historyByContract = useHistoryStore((s) => s.historyByContract);
6069
const clearHistory = useHistoryStore((s) => s.clearHistory);
61-
const selectedAddress = (contractsData as Record<string, { address: string }>)[selectedContract as string]?.address as string;
70+
const selectedAddress = (
71+
contractsData as Record<string, { address: string }>
72+
)[selectedContract as string]?.address as string;
6273
const entries = useMemo(
6374
() => historyByContract[selectedAddress] || [],
6475
[historyByContract, selectedAddress],
@@ -107,15 +118,6 @@ export default function DebugHistory() {
107118

108119
const formatDate = (ts: number) => formatTimestamp(ts);
109120

110-
const StatusIcon = ({ status }: { status: HistoryEntry["status"] }) => (
111-
<Image
112-
src={status === "success" ? "/success-icon.svg" : "/fail-icon.svg"}
113-
alt={status}
114-
width={20}
115-
height={20}
116-
/>
117-
);
118-
119121
const chips: FilterChip[] = ["All", "Read", "Write", "Success", "Error"];
120122

121123
const handleExportJSON = () => {
@@ -137,99 +139,122 @@ export default function DebugHistory() {
137139
};
138140

139141
return (
140-
<div className="h-full max-h-[650px] w-full xl:w-[400px] space-y-4">
141-
<div className="tab h-10 w-full xl:w-1/3 tab-active bg-[#8A45FC]! rounded-[5px] text-white!">
142-
History
142+
<div className="w-full xl:w-[400px] flex flex-col gap-6">
143+
{/* Tab header — matches Read/Write tab bar */}
144+
<div className="tabs tabs-box border border-[#8A45FC] rounded-[5px] bg-transparent">
145+
<a className="tab h-10 w-full tab-active bg-[#8A45FC]! rounded-[5px]! text-white!">
146+
History
147+
</a>
143148
</div>
144149

145-
{/* Search bar */}
146-
<input
147-
type="text"
148-
className="w-full bg-input text-sm rounded-[5px] px-3 py-1.5 outline-none border border-transparent focus:border-[#8A45FC] placeholder:text-neutral"
149-
placeholder="Search by function name..."
150-
value={searchTerm}
151-
onChange={(e) => setSearchTerm(e.target.value)}
152-
/>
153-
154-
{/* Filter chips */}
155-
<div className="flex flex-wrap gap-1.5">
156-
{chips.map((chip) => {
157-
const isActive =
158-
chip === "All" ? activeFilters.length === 0 : activeFilters.includes(chip);
159-
return (
150+
{/* Content card — matches the contract methods card */}
151+
<div className="rounded-[5px] border border-[#8A45FC] bg-component flex flex-col max-h-[600px]">
152+
{/* Search bar */}
153+
<div className="p-3 pb-0">
154+
<input
155+
type="text"
156+
className={`w-full text-sm rounded-[5px] px-3 py-2 outline-none border transition-colors ${
157+
isDarkMode
158+
? "bg-[#0C1023] border-[#ffffff1a] focus:border-[#8A45FC] placeholder:text-neutral"
159+
: "bg-base-200 border-transparent focus:border-[#8A45FC] placeholder:text-neutral"
160+
}`}
161+
placeholder="Search by function name..."
162+
value={searchTerm}
163+
onChange={(e) => setSearchTerm(e.target.value)}
164+
/>
165+
</div>
166+
167+
{/* Filter chips + toolbar */}
168+
<div className="px-3 pt-3 space-y-2">
169+
<div className="flex flex-wrap gap-1.5">
170+
{chips.map((chip) => {
171+
const isActive =
172+
chip === "All"
173+
? activeFilters.length === 0
174+
: activeFilters.includes(chip);
175+
return (
176+
<button
177+
key={chip}
178+
onClick={() => toggleFilter(chip)}
179+
className={`px-2.5 py-1 rounded-[5px] text-xs font-medium transition-colors border ${
180+
isActive
181+
? "bg-[#8A45FC] text-white border-[#8A45FC]"
182+
: isDarkMode
183+
? "bg-transparent text-neutral border-[#ffffff1a] hover:border-[#8A45FC]/50"
184+
: "bg-transparent text-neutral border-black/10 hover:border-[#8A45FC]/50"
185+
}`}
186+
>
187+
{chip}
188+
</button>
189+
);
190+
})}
191+
</div>
192+
193+
{/* Export / Clear toolbar */}
194+
<div className="flex items-center gap-1 border-b border-secondary pb-2">
160195
<button
161-
key={chip}
162-
onClick={() => toggleFilter(chip)}
163-
className={`px-2.5 py-0.5 rounded-full text-xs font-medium transition-colors ${
164-
isActive
165-
? "bg-[#8A45FC] text-white"
166-
: "bg-base-200 text-neutral hover:bg-base-300"
167-
}`}
196+
className="text-xs text-[#8A45FC] hover:text-[#a06aff] transition-colors disabled:opacity-40 disabled:hover:text-[#8A45FC] px-1.5 py-0.5"
197+
onClick={handleExportJSON}
198+
disabled={formatted.length === 0}
168199
>
169-
{chip}
200+
Export JSON
170201
</button>
171-
);
172-
})}
173-
</div>
174-
175-
{/* Toolbar: export + clear */}
176-
<div className="flex items-center gap-2">
177-
<button
178-
className="btn btn-ghost btn-xs"
179-
onClick={handleExportJSON}
180-
disabled={formatted.length === 0}
181-
>
182-
Export JSON
183-
</button>
184-
<button
185-
className="btn btn-ghost btn-xs"
186-
onClick={handleExportCSV}
187-
disabled={formatted.length === 0}
188-
>
189-
Export CSV
190-
</button>
191-
<button
192-
className="btn btn-ghost btn-xs text-error ml-auto"
193-
onClick={handleClear}
194-
disabled={entries.length === 0}
195-
>
196-
Clear
197-
</button>
198-
</div>
202+
<span className="text-neutral/30">|</span>
203+
<button
204+
className="text-xs text-[#8A45FC] hover:text-[#a06aff] transition-colors disabled:opacity-40 disabled:hover:text-[#8A45FC] px-1.5 py-0.5"
205+
onClick={handleExportCSV}
206+
disabled={formatted.length === 0}
207+
>
208+
Export CSV
209+
</button>
210+
<button
211+
className="text-xs text-red-400 hover:text-red-300 transition-colors disabled:opacity-40 ml-auto px-1.5 py-0.5"
212+
onClick={handleClear}
213+
disabled={entries.length === 0}
214+
>
215+
Clear
216+
</button>
217+
</div>
218+
</div>
199219

200-
<div className="border-gradient rounded-[5px] h-full w-full overflow-y-auto">
201-
<div className="flex flex-col">
220+
{/* History entries list */}
221+
<div className="flex-1 overflow-y-auto">
202222
{formatted.length === 0 ? (
203-
<div className="p-4 text-sm text-neutral">No history yet.</div>
223+
<div className="p-4 text-sm text-neutral text-center">
224+
No history yet.
225+
</div>
204226
) : (
205227
formatted.map((e) => (
206228
<button
207229
key={e.txHash ?? `${e.functionName}-${e.timestamp}`}
208-
className={`w-full flex items-center justify-between py-3 px-3 text-left border-b ${isDarkMode ? "bg-[#0000002E] border-b-[#ffffff4f]" : "bg-[#ffffff0f] border-b-black/40"}`}
230+
className={`w-full flex items-center justify-between py-3 px-3 text-left border-b transition-colors ${
231+
isDarkMode
232+
? "border-b-[#ffffff12] hover:bg-[#ffffff08]"
233+
: "border-b-black/10 hover:bg-black/5"
234+
}`}
209235
onClick={() => setOpenEntry(e)}
210236
>
211-
<div className="flex items-center gap-1.5 min-w-0">
212-
{/* callType badge */}
237+
<div className="flex items-center gap-2 min-w-0">
213238
<span
214-
className={`flex-shrink-0 inline-flex items-center justify-center w-4 h-4 rounded text-[10px] font-bold leading-none ${
239+
className={`flex-shrink-0 inline-flex items-center justify-center w-5 h-5 rounded-[3px] text-[10px] font-bold leading-none ${
215240
e.callType === "read"
216241
? "bg-blue-500/20 text-blue-400"
217242
: "bg-amber-500/20 text-amber-400"
218243
}`}
219244
>
220245
{e.callType === "read" ? "R" : "W"}
221246
</span>
222-
<span className="truncate text-[#4DB4FF]">
247+
<span className="truncate text-sm text-[#4DB4FF]">
223248
{e.functionName}
224249
</span>
225250
</div>
226-
<div className="flex items-center gap-3 flex-shrink-0">
251+
<div className="flex items-center gap-2 flex-shrink-0 ml-2">
227252
<div className="flex flex-col items-end">
228-
<span className="text-xs text-neutral">
253+
<span className="text-[11px] text-neutral">
229254
{formatDate(e.timestamp)}
230255
</span>
231256
{e.duration !== undefined && (
232-
<span className="text-[10px] text-neutral/60">
257+
<span className="text-[10px] text-neutral/50">
233258
{e.duration}ms
234259
</span>
235260
)}

0 commit comments

Comments
 (0)