diff --git a/package.json b/package.json
index 62bb264..2734074 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "orgexplorer",
- "version": "2.0.0",
+ "version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
diff --git a/src/components/EmptyStateCard.jsx b/src/components/EmptyStateCard.jsx
new file mode 100644
index 0000000..61f9b66
--- /dev/null
+++ b/src/components/EmptyStateCard.jsx
@@ -0,0 +1,103 @@
+
+export default function EmptyStateCard({
+ SvgIcon,
+ title = "No results found",
+ description = "We couldn't find anything for this organization right now.",
+ buttonText = "Explore Organizations",
+ onButtonClick,
+}) {
+ return (
+
+
+ {/* Top Icon */}
+
+ {SvgIcon}
+
+
+ {/* Title */}
+
+ {title}
+
+
+ {/* Description */}
+
+ {description}
+
+
+ {/* CTA Button */}
+
+
+
+ );
+}
diff --git a/src/pages/ContributorsPage.jsx b/src/pages/ContributorsPage.jsx
index 82c347a..d0f6370 100644
--- a/src/pages/ContributorsPage.jsx
+++ b/src/pages/ContributorsPage.jsx
@@ -1,9 +1,11 @@
import React, { useState, useMemo } from 'react'
-import { FiDownload } from 'react-icons/fi'
+import { FiDatabase, FiDownload } from 'react-icons/fi'
import { useApp } from '../context/AppContext'
import { C, SortTh, PageTitle, LoadMore } from '../components/UI'
import { useSortedData } from '../hooks/useSortedData'
import { computeBusFactor, exportContributorsCSV } from '../services/analytics'
+import { useNavigate } from 'react-router-dom'
+import EmptyStateCard from '../components/EmptyStateCard'
export default function ContributorsPage() {
const { model } = useApp()
@@ -12,6 +14,7 @@ export default function ContributorsPage() {
if (!model) return null
const { contributors } = model
+ const navigate = useNavigate()
const busFactor = useMemo(() => computeBusFactor(contributors), [contributors])
const topActive = contributors.slice(0, 10).filter(c => c.freshness > 50).length
@@ -122,51 +125,69 @@ export default function ContributorsPage() {
{filtered.length} contributors — no rank column by design
-
-
-
-
-
-
-
-
- |
- SIGNALS
- |
-
-
-
- {visible.map((c, i) => (
-
-
-
- 
- {c.login}
-
- |
-
-
-
- {c.totalContribs.toLocaleString()}
-
- |
- {c.repos.length} |
- {c.orgs.length} |
- {c.lastActive?.slice(0, 10) || '—'} |
-
-
- {c.isConnector && CONNECTOR}
- {c.isCrossOrg && CROSS-ORG}
- {c.freshness > 70 && ACTIVE}
-
- |
-
- ))}
-
-
- setShown(s => s + 20)} />
+ {contributors?.length ?
+ (<>
+
+
+
+
+
+
+
+
+ |
+ SIGNALS
+ |
+
+
+
+ {visible.map((c, i) => (
+
+
+
+ 
+ {c.login}
+
+ |
+
+
+
+ {c.totalContribs.toLocaleString()}
+
+ |
+ {c.repos.length} |
+ {c.orgs.length} |
+ {c.lastActive?.slice(0, 10) || '—'} |
+
+
+ {c.isConnector && CONNECTOR}
+ {c.isCrossOrg && CROSS-ORG}
+ {c.freshness > 70 && ACTIVE}
+
+ |
+
+ ))}
+
+
+ setShown(s => s + 20)} />>) :
+ (<>
+
+ }
+ title="No contributors found"
+ description="We couldn't find any contributor data for this organization. "
+ buttonText="Go to Home"
+ onButtonClick={() => navigate('/')}/>
+
+ >)}
)
diff --git a/src/pages/NetworkPage.jsx b/src/pages/NetworkPage.jsx
index 14549eb..22ff154 100644
--- a/src/pages/NetworkPage.jsx
+++ b/src/pages/NetworkPage.jsx
@@ -2,6 +2,9 @@ import React, { useEffect, useRef, useState } from 'react'
import * as d3 from 'd3'
import { useApp } from '../context/AppContext'
import { C, PageTitle } from '../components/UI'
+import EmptyStateCard from '../components/EmptyStateCard'
+import { FiDatabase } from 'react-icons/fi'
+import { useNavigate } from 'react-router-dom'
export default function NetworkPage() {
const { model } = useApp()
@@ -126,7 +129,7 @@ export default function NetworkPage() {
return () => sim.stop()
}, [model, showRepos, showContribs])
- if (!model) return null
+ const navigate = useNavigate()
return (
@@ -154,7 +157,9 @@ export default function NetworkPage() {
{/* Canvas */}
-
+ {model.allRepos?.length ? (
+ <>
+
{/* Tooltip */}
@@ -195,6 +200,26 @@ export default function NetworkPage() {
Drag nodes to reposition — scroll to zoom
+ >) :
+ (
+ <>
+
+ }
+ title="No repositories found"
+ description="We couldn't find any repositories in this organization."
+ buttonText="Go to Home"
+ onButtonClick={() => navigate('/')}
+ />
+
+ >
+ )}
)
}
diff --git a/src/pages/RepositoriesPage.jsx b/src/pages/RepositoriesPage.jsx
index c124fef..3f87597 100644
--- a/src/pages/RepositoriesPage.jsx
+++ b/src/pages/RepositoriesPage.jsx
@@ -1,9 +1,11 @@
import React, { useState, useMemo } from 'react'
-import { FiDownload, FiGrid, FiList } from 'react-icons/fi'
+import { FiDatabase, FiDownload, FiGrid, FiList } from 'react-icons/fi'
import { useApp } from '../context/AppContext'
import { C, Badge, HealthBar, SortTh, PageTitle, LoadMore } from '../components/UI'
import { useSortedData } from '../hooks/useSortedData'
import { exportReposCSV } from '../services/analytics'
+import EmptyStateCard from '../components/EmptyStateCard'
+import { useNavigate } from 'react-router-dom'
const LIFECYCLES = ['All','Thriving','Stable','Dormant','Abandoned']
const LC_ACTIVE = { Thriving:'var(--green)', Stable:'var(--blue)', Dormant:'var(--amber)', Abandoned:'var(--red)' }
@@ -16,6 +18,7 @@ export default function RepositoriesPage() {
const [view, setView] = useState('grid')
const [shown, setShown] = useState(20)
+ const navigate = useNavigate()
if (!model) return null
const { allRepos } = model
@@ -95,7 +98,8 @@ export default function RepositoriesPage() {
))}
-
+{allRepos?.length ? (
+ <>
{/* Table view */}
{view === 'list' && (
@@ -182,7 +186,25 @@ export default function RepositoriesPage() {
setShown(s => s + 20)} />
>
- )}
+ )}
+ >)
+ : (
+
+ }
+ title="No repositories available"
+ description="We couldn't find any repositories for this organization yet."
+ buttonText="Go to Home"
+ onButtonClick={() => navigate('/')}
+ />
+
+ )}
)
}