Skip to content

Commit 1567519

Browse files
Merge pull request #282 from SheetMetalConnect/claude/find-perf-issues-mjidyjjjgoewtkst-TJrJ3
Find performance issues
2 parents 67915ee + e9efd46 commit 1567519

File tree

7 files changed

+58
-35
lines changed

7 files changed

+58
-35
lines changed

src/hooks/useJobIssues.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,17 @@ export function useJobIssues(jobId: string | undefined) {
5858

5959
fetchIssueSummary();
6060

61-
// Subscribe to changes in issues
62-
const subscription = supabase
61+
// Subscribe to changes in issues - filter by status to reduce callback frequency
62+
// Note: Can't filter by job_id directly since issues link through operations
63+
const channel = supabase
6364
.channel(`job-issues-${jobId}`)
6465
.on(
6566
'postgres_changes',
6667
{
6768
event: '*',
6869
schema: 'public',
6970
table: 'issues',
71+
filter: 'status=eq.pending',
7072
},
7173
() => {
7274
fetchIssueSummary();
@@ -75,7 +77,7 @@ export function useJobIssues(jobId: string | undefined) {
7577
.subscribe();
7678

7779
return () => {
78-
subscription.unsubscribe();
80+
supabase.removeChannel(channel);
7981
};
8082
}, [jobId]);
8183

src/hooks/useOEEMetrics.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function useOEEMetrics(dateRange: number = 30) {
4949
const startDate = subDays(new Date(), dateRange).toISOString();
5050
const now = new Date();
5151

52-
// Fetch operations with cell info
52+
// Fetch operations with cell info - removed unused capacity_hours_per_day
5353
const { data: operations, error: opsError } = await supabase
5454
.from("operations")
5555
.select(`
@@ -61,7 +61,7 @@ export function useOEEMetrics(dateRange: number = 30) {
6161
status,
6262
completed_at,
6363
cell_id,
64-
cells(name, capacity_hours_per_day)
64+
cells(name)
6565
`)
6666
.eq("tenant_id", profile.tenant_id)
6767
.gte("updated_at", startDate);
@@ -184,9 +184,10 @@ export function useOEEMetrics(dateRange: number = 30) {
184184
}
185185
});
186186

187-
// Add quality data to cells
187+
// Add quality data to cells - use Map for O(1) lookups instead of O(n) find
188+
const operationMap = new Map(operations?.map(o => [o.id, o]) || []);
188189
quantities?.forEach(q => {
189-
const op = operations?.find(o => o.id === q.operation_id);
190+
const op = operationMap.get(q.operation_id);
190191
if (op?.cells?.name) {
191192
const current = cellMap.get(op.cells.name);
192193
if (current) {

src/hooks/usePartIssues.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,17 @@ export function usePartIssues(partId: string | undefined) {
5858

5959
fetchIssueSummary();
6060

61-
// Subscribe to changes in issues
62-
const subscription = supabase
61+
// Subscribe to changes in issues - filter by status to reduce callback frequency
62+
// Note: Can't filter by part_id directly since issues link through operations
63+
const channel = supabase
6364
.channel(`part-issues-${partId}`)
6465
.on(
6566
'postgres_changes',
6667
{
6768
event: '*',
6869
schema: 'public',
6970
table: 'issues',
71+
filter: 'status=eq.pending',
7072
},
7173
() => {
7274
fetchIssueSummary();
@@ -75,7 +77,7 @@ export function usePartIssues(partId: string | undefined) {
7577
.subscribe();
7678

7779
return () => {
78-
subscription.unsubscribe();
80+
supabase.removeChannel(channel);
7981
};
8082
}, [partId]);
8183

src/hooks/usePendingIssuesCount.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function usePendingIssuesCount() {
1010
queryFn: async () => {
1111
const { count, error } = await supabase
1212
.from('issues')
13-
.select('*', { count: 'exact', head: true })
13+
.select('id', { count: 'exact', head: true })
1414
.eq('status', 'pending');
1515

1616
if (error) throw error;

src/hooks/useQualityMetrics.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,17 @@ export function useQualityMetrics() {
9191

9292
if (issuesError) throw issuesError;
9393

94-
// Calculate production totals
95-
const totalProduced = quantities?.reduce((sum, q) => sum + (q.quantity_produced || 0), 0) || 0;
96-
const totalGood = quantities?.reduce((sum, q) => sum + (q.quantity_good || 0), 0) || 0;
97-
const totalScrap = quantities?.reduce((sum, q) => sum + (q.quantity_scrap || 0), 0) || 0;
98-
const totalRework = quantities?.reduce((sum, q) => sum + (q.quantity_rework || 0), 0) || 0;
94+
// Calculate production totals in single pass instead of 4 separate reduces
95+
const totals = quantities?.reduce(
96+
(acc, q) => ({
97+
produced: acc.produced + (q.quantity_produced || 0),
98+
good: acc.good + (q.quantity_good || 0),
99+
scrap: acc.scrap + (q.quantity_scrap || 0),
100+
rework: acc.rework + (q.quantity_rework || 0),
101+
}),
102+
{ produced: 0, good: 0, scrap: 0, rework: 0 }
103+
) || { produced: 0, good: 0, scrap: 0, rework: 0 };
104+
const { produced: totalProduced, good: totalGood, scrap: totalScrap, rework: totalRework } = totals;
99105

100106
// Calculate yield metrics
101107
const overallYield = totalProduced > 0 ? (totalGood / totalProduced) * 100 : 100;
@@ -142,18 +148,35 @@ export function useQualityMetrics() {
142148
.sort((a, b) => b.quantity - a.quantity)
143149
.slice(0, 10);
144150

145-
// Calculate issue metrics
151+
// Calculate issue metrics in single pass instead of 9 separate filters
152+
const issueCounts = issues?.reduce(
153+
(acc, i) => {
154+
// Count by status
155+
if (i.status === "pending") acc.pending++;
156+
else if (i.status === "approved") acc.approved++;
157+
else if (i.status === "rejected") acc.rejected++;
158+
else if (i.status === "closed") acc.closed++;
159+
// Count by severity
160+
if (i.severity === "critical") acc.critical++;
161+
else if (i.severity === "high") acc.high++;
162+
else if (i.severity === "medium") acc.medium++;
163+
else if (i.severity === "low") acc.low++;
164+
return acc;
165+
},
166+
{ pending: 0, approved: 0, rejected: 0, closed: 0, critical: 0, high: 0, medium: 0, low: 0 }
167+
) || { pending: 0, approved: 0, rejected: 0, closed: 0, critical: 0, high: 0, medium: 0, low: 0 };
168+
146169
const issueMetrics = {
147170
total: issues?.length || 0,
148-
pending: issues?.filter((i) => i.status === "pending").length || 0,
149-
approved: issues?.filter((i) => i.status === "approved").length || 0,
150-
rejected: issues?.filter((i) => i.status === "rejected").length || 0,
151-
closed: issues?.filter((i) => i.status === "closed").length || 0,
171+
pending: issueCounts.pending,
172+
approved: issueCounts.approved,
173+
rejected: issueCounts.rejected,
174+
closed: issueCounts.closed,
152175
bySeverity: {
153-
critical: issues?.filter((i) => i.severity === "critical").length || 0,
154-
high: issues?.filter((i) => i.severity === "high").length || 0,
155-
medium: issues?.filter((i) => i.severity === "medium").length || 0,
156-
low: issues?.filter((i) => i.severity === "low").length || 0,
176+
critical: issueCounts.critical,
177+
high: issueCounts.high,
178+
medium: issueCounts.medium,
179+
low: issueCounts.low,
157180
},
158181
};
159182

@@ -186,10 +209,10 @@ export function useScrapReasonUsage() {
186209
throw new Error("No tenant ID");
187210
}
188211

189-
// Fetch all scrap reasons
212+
// Fetch all scrap reasons - only fields we need
190213
const { data: reasons, error: reasonsError } = await supabase
191214
.from("scrap_reasons")
192-
.select("*")
215+
.select("id, code, description, category, active")
193216
.eq("tenant_id", profile.tenant_id)
194217
.order("code");
195218

src/hooks/useRealtimeSubscription.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export function useRealtimeSubscription(options: RealtimeSubscriptionOptions): v
186186
operation: 'useRealtimeSubscription',
187187
channelName,
188188
});
189-
channel.unsubscribe();
189+
supabase.removeChannel(channel);
190190
};
191191
}, [channelName, tables, enabled, debounceMs, includePayload, debouncedCallback]);
192192
}

src/pages/admin/Parts.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,9 @@ export default function Parts() {
104104
const { data, error } = await query;
105105
if (error) throw error;
106106

107-
// Check which parts have children
108-
const { data: allChildRelations } = await supabase
109-
.from("parts")
110-
.select("parent_part_id")
111-
.not("parent_part_id", "is", null);
112-
107+
// Build children set from already-fetched data (no second query needed)
113108
const partsWithChildren = new Set(
114-
allChildRelations?.map((p) => p.parent_part_id) || [],
109+
data?.filter((p: any) => p.parent_part_id).map((p: any) => p.parent_part_id) || [],
115110
);
116111

117112
return data.map((part: any) => {

0 commit comments

Comments
 (0)