Skip to content

Commit 67e29a8

Browse files
committed
Fix loading issues
1 parent 9d78760 commit 67e29a8

4 files changed

Lines changed: 46 additions & 64 deletions

File tree

src/App.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function App() {
162162
const { state, dispatch, setToken, setEnterpriseUrl, setSelectedOrg, setInactiveDays } = useAppState();
163163
const {
164164
token, enterpriseUrl, isConnected, selectedOrg, inactiveDays,
165-
isFirstLoad, usageLoadingStarted, smoothedAuditProgress,
165+
smoothedAuditProgress,
166166
} = state;
167167

168168
const {
@@ -185,9 +185,7 @@ function App() {
185185
} = dashboardData;
186186

187187
const {
188-
loading: usageLoading,
189188
getUsageForApp,
190-
progress: usageProgress,
191189
} = appUsage;
192190

193191
const {
@@ -303,12 +301,7 @@ function App() {
303301
loadedAppsPages={loadedAppsPages}
304302
appsPerPage={APPS_PER_PAGE}
305303
backgroundProgress={backgroundProgress}
306-
isFirstLoad={isFirstLoad}
307304
smoothedAuditProgress={smoothedAuditProgress}
308-
usageLoading={usageLoading}
309-
usageLoadingStarted={usageLoadingStarted}
310-
usageProgress={usageProgress}
311-
organizations={organizations}
312305
token={token}
313306
enterpriseUrl={enterpriseUrl}
314307
getUsageForApp={getUsageForApp}

src/components/AppsView.tsx

Lines changed: 26 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import styled from 'styled-components';
22
import { ProgressBar } from '@primer/react';
3-
import { Virtuoso } from 'react-virtuoso';
43
import { AppCard } from './AppCard';
54
import { Pagination } from './Pagination';
6-
import { AuditLogProgress } from './AuditLogProgress';
75
import { SectionTitle, EmptyState, MutedText } from './shared/styles';
8-
import type { AppInstallation, GitHubApp, Organization } from '../types';
6+
import type { AppInstallation, GitHubApp } from '../types';
97
import type { BackgroundProgress } from '../hooks/useDashboardData';
10-
import type { UsageProgress } from '../hooks/useAppUsage';
118
import type { AppUsageInfo } from '../types';
129

1310
const ContentHeader = styled.div`
@@ -71,12 +68,7 @@ interface AppsViewProps {
7168
loadedAppsPages: number;
7269
appsPerPage: number;
7370
backgroundProgress: BackgroundProgress | null;
74-
isFirstLoad: boolean;
7571
smoothedAuditProgress: { checked: number; total: number; found: number };
76-
usageLoading: boolean;
77-
usageLoadingStarted: boolean;
78-
usageProgress: UsageProgress | null;
79-
organizations: Organization[];
8072
token: string;
8173
enterpriseUrl: string;
8274
getUsageForApp: (slug: string) => AppUsageInfo | undefined;
@@ -93,16 +85,17 @@ export function AppsView({
9385
loadedAppsPages,
9486
appsPerPage,
9587
backgroundProgress,
96-
isFirstLoad,
9788
smoothedAuditProgress,
98-
usageLoading,
99-
usageLoadingStarted,
100-
usageProgress,
101-
organizations,
10289
token,
10390
enterpriseUrl,
10491
getUsageForApp,
10592
}: AppsViewProps) {
93+
// Use expectedTotalApps as the denominator while Phase 2 is still loading
94+
const activityTotal = backgroundProgress?.isLoading
95+
? Math.max(smoothedAuditProgress.total, expectedTotalApps)
96+
: smoothedAuditProgress.total;
97+
const activityProgress = activityTotal > 0 ? Math.min((smoothedAuditProgress.checked / activityTotal) * 100, 100) : 0;
98+
10699
return (
107100
<div>
108101
<ContentHeader>
@@ -135,56 +128,39 @@ export function AppsView({
135128
</BackgroundLoadingText>
136129
</BackgroundLoadingBar>
137130
)}
138-
{!isFirstLoad && smoothedAuditProgress.total > 0 && smoothedAuditProgress.checked < smoothedAuditProgress.total && (
131+
{activityTotal > 0 && smoothedAuditProgress.checked < activityTotal && (
139132
<AuditLogLoadingBar>
140133
<AuditLogLoadingText>
141-
Checking activity... ({smoothedAuditProgress.checked}/{smoothedAuditProgress.total} apps, {smoothedAuditProgress.found} active)
134+
Checking activity... ({smoothedAuditProgress.checked}/{activityTotal} apps, {smoothedAuditProgress.found} active)
142135
</AuditLogLoadingText>
143136
<BackgroundProgressWrapper>
144137
<ProgressBar
145-
progress={smoothedAuditProgress.total > 0 ? Math.min((smoothedAuditProgress.checked / smoothedAuditProgress.total) * 100, 100) : 0}
138+
progress={activityProgress}
146139
barSize="small"
147140
aria-label="Audit log loading progress"
148141
/>
149142
</BackgroundProgressWrapper>
150143
<AuditLogLoadingText>
151-
{smoothedAuditProgress.total > 0 ? Math.min(Math.round((smoothedAuditProgress.checked / smoothedAuditProgress.total) * 100), 100) : 0}%
144+
{Math.round(activityProgress)}%
152145
</AuditLogLoadingText>
153146
</AuditLogLoadingBar>
154147
)}
155-
{isFirstLoad && (usageLoading || usageLoadingStarted) && (
156-
<AuditLogProgress
157-
progress={usageProgress || {
158-
org: organizations[0]?.login || '',
159-
appsChecked: 0,
160-
totalApps: apps.size,
161-
appsFound: 0,
162-
currentPhase: 'fetching' as const,
163-
message: 'Preparing to scan audit logs...',
164-
}}
165-
totalOrgs={organizations.length}
166-
/>
167-
)}
168148
{paginatedApps.length > 0 ? (
169-
<Virtuoso
170-
useWindowScroll
171-
data={paginatedApps}
172-
computeItemKey={(_, [slug]) => slug}
173-
itemContent={(_, [slug, insts]) => {
174-
const app = apps.get(slug);
175-
if (!app) return <div />;
176-
const usageInfo = getUsageForApp(slug);
177-
return (
178-
<AppCard
179-
app={app}
180-
installations={insts}
181-
token={token}
182-
enterpriseUrl={enterpriseUrl}
183-
usageInfo={usageInfo}
184-
/>
185-
);
186-
}}
187-
/>
149+
paginatedApps.map(([slug, insts]) => {
150+
const app = apps.get(slug);
151+
if (!app) return null;
152+
const usageInfo = getUsageForApp(slug);
153+
return (
154+
<AppCard
155+
key={slug}
156+
app={app}
157+
installations={insts}
158+
token={token}
159+
enterpriseUrl={enterpriseUrl}
160+
usageInfo={usageInfo}
161+
/>
162+
);
163+
})
188164
) : (
189165
<EmptyState>
190166
<MutedText>No apps found matching your filters.</MutedText>

src/hooks/useAppState.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function appReducer(state: AppState, action: AppAction): AppState {
6262
usageLoadingStarted: false,
6363
};
6464
case 'FIRST_LOAD_COMPLETE':
65-
return { ...state, isFirstLoad: false, usageLoadingStarted: false };
65+
return { ...state, isFirstLoad: false };
6666
case 'USAGE_LOADING_STARTED':
6767
return { ...state, usageLoadingStarted: true };
6868
case 'UPDATE_AUDIT_PROGRESS':

src/hooks/useDashboardOrchestration.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,39 @@ export function useDashboardOrchestration({
5858
}
5959
}, [usageProgress, dispatch]);
6060

61-
// Reset smoothed progress when audit log checking is complete
61+
// Re-scan activity after Phase 2 background loading completes to cover all apps
62+
const { backgroundProgress } = dashboardData;
63+
64+
// Reset smoothed progress when audit log checking is complete (and no background loading pending)
6265
useEffect(() => {
63-
if (!isFirstLoad && smoothedAuditProgress.total > 0 && smoothedAuditProgress.checked >= smoothedAuditProgress.total) {
66+
if (!isFirstLoad && smoothedAuditProgress.total > 0 && smoothedAuditProgress.checked >= smoothedAuditProgress.total && !backgroundProgress?.isLoading) {
6467
const timer = setTimeout(() => {
6568
dispatch({ type: 'RESET_AUDIT_PROGRESS' });
6669
}, 1000);
6770
return () => clearTimeout(timer);
6871
}
69-
}, [isFirstLoad, smoothedAuditProgress.checked, smoothedAuditProgress.total, dispatch]);
72+
}, [isFirstLoad, smoothedAuditProgress.checked, smoothedAuditProgress.total, backgroundProgress?.isLoading, dispatch]);
7073

7174
// Load app usage when apps are loaded and config is ready
7275
useEffect(() => {
73-
if (apps.size > 0 && organizations.length > 0 && configLoaded) {
76+
if (apps.size > 0 && organizations.length > 0 && configLoaded && !usageLoadingStarted) {
7477
dispatch({ type: 'USAGE_LOADING_STARTED' });
7578
const slugs = Array.from(apps.keys());
7679
const orgLogins = organizations.map(o => o.login);
7780
loadUsage(orgLogins, slugs);
7881
}
7982
// eslint-disable-next-line react-hooks/exhaustive-deps
80-
}, [apps, organizations, configLoaded, usageRefreshKey]);
83+
}, [apps, organizations, configLoaded, usageRefreshKey, usageLoadingStarted]);
84+
85+
// Re-scan activity after Phase 2 background loading completes to cover all apps
86+
useEffect(() => {
87+
if (backgroundProgress && !backgroundProgress.isLoading && apps.size > 0 && organizations.length > 0) {
88+
const slugs = Array.from(apps.keys());
89+
const orgLogins = organizations.map(o => o.login);
90+
loadUsage(orgLogins, slugs);
91+
}
92+
// eslint-disable-next-line react-hooks/exhaustive-deps
93+
}, [backgroundProgress?.isLoading]);
8194

8295
const handleConnect = useCallback(() => {
8396
if (isConnected) {

0 commit comments

Comments
 (0)