From 775fb4cae8ce460a96746b1ed440f0f71c0b42a6 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Mon, 29 Jun 2026 16:34:21 +0000
Subject: [PATCH] feat: my-apis empty state
Co-authored-by: gloskull <189399494+gloskull@users.noreply.github.com>
---
src/App.tsx | 22 ++++++++++--
src/components/CommandPalette.tsx | 7 ++++
src/components/EmptyState.tsx | 19 ++++++++++
src/pages/MyApis.test.tsx | 58 +++++++++++++++++++++++++++++++
src/pages/MyApis.tsx | 54 ++++++++++++++++++++++++++++
5 files changed, 158 insertions(+), 2 deletions(-)
create mode 100644 src/pages/MyApis.test.tsx
create mode 100644 src/pages/MyApis.tsx
diff --git a/src/App.tsx b/src/App.tsx
index f53678f..be0c1fe 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,12 +3,12 @@ import { Routes, Route, NavLink, useNavigate, useLocation } from 'react-router-d
import { ThemeToggle } from './ThemeToggle';
import ApiUsage from './ApiUsage';
import Dashboard from './components/Dashboard';
+import MyApis from './pages/MyApis';
import RouteProgressBar from './components/RouteProgressBar';
import ServerError from './components/ServerError';
import useDocumentTitle from "./hooks/useDocumentTitle";
import NotFound from './components/NotFound';
import { startRouteLoading, stopRouteLoading } from './hooks/useRouteLoading';
-import useDocumentTitle from './hooks/useDocumentTitle';
import { formatUsdc, formatUsdShortcut } from './utils/format';
import {
EXPLORER_BASE_URL,
@@ -104,6 +104,7 @@ const APP_ROUTES = {
dashboard: "/dashboard",
marketplace: "/marketplace",
publish: "/publish",
+ myApis: "/apis/my-apis",
apiUsage: "/api-usage",
billing: "/billing",
documentation: "/documentation",
@@ -273,10 +274,10 @@ function createMockHash() {
function App() {
const navigate = useNavigate();
const location = useLocation();
- const navigate = useNavigate();
const routeTitleMap: Record = {
[APP_ROUTES.marketplace]: "Marketplace – Callora",
[APP_ROUTES.dashboard]: "Dashboard – Callora",
+ [APP_ROUTES.myApis]: "My APIs – Callora",
[APP_ROUTES.billing]: "Billing – Callora",
"/api-usage": "API Usage – Callora",
[APP_ROUTES.landing]: "Callora",
@@ -305,6 +306,16 @@ function App() {
// Handle global shortcuts
const handleGlobalKeyDown = useCallback((event: KeyboardEvent) => {
+ // Navigation to My APIs (e.g. g then a)
+ if (event.key === 'g') {
+ const handleNextKey = (e: KeyboardEvent) => {
+ if (e.key === 'a') {
+ navigate(APP_ROUTES.myApis);
+ }
+ };
+ window.addEventListener('keydown', handleNextKey, { once: true });
+ }
+
// Open shortcuts modal with ?
if (event.key === '?' || (event.shiftKey && event.key === '/')) {
event.preventDefault();
@@ -548,6 +559,7 @@ function App() {
@@ -570,6 +582,11 @@ function App() {
}
/>
+ }
+ />
+
isActive ? "link-nav active" : "link-nav"}>Dashboard
isActive ? "link-nav active" : "link-nav"}>Marketplace
+ isActive ? "link-nav active" : "link-nav"}>My APIs
isActive ? "link-nav active" : "link-nav"}>Billing
isActive ? "link-nav active" : "link-nav"}>Theme Playground
isActive ? "link-nav active" : "link-nav"}>Status
diff --git a/src/components/CommandPalette.tsx b/src/components/CommandPalette.tsx
index ef34cb6..9ac7942 100644
--- a/src/components/CommandPalette.tsx
+++ b/src/components/CommandPalette.tsx
@@ -47,6 +47,13 @@ export default function CommandPalette() {
action: () => navigateTo('/marketplace'),
icon: '🛍️'
},
+ {
+ id: 'my-apis',
+ name: 'Go to My APIs',
+ category: 'Navigation',
+ action: () => navigateTo('/apis/my-apis'),
+ icon: '🔌'
+ },
{
id: 'billing',
name: 'Go to Billing',
diff --git a/src/components/EmptyState.tsx b/src/components/EmptyState.tsx
index 429b615..03564f4 100644
--- a/src/components/EmptyState.tsx
+++ b/src/components/EmptyState.tsx
@@ -6,6 +6,10 @@ export interface EmptyStateProps {
message?: string;
onClearFilters?: () => void;
onRetry?: () => void | Promise;
+ action?: {
+ label: string;
+ onClick: () => void;
+ };
}
/**
@@ -23,6 +27,7 @@ export default function EmptyState({
message,
onClearFilters,
onRetry,
+ action,
}: EmptyStateProps) {
// Default copy based on variant
const defaults = {
@@ -153,6 +158,20 @@ export default function EmptyState({
{/* Primary action */}
+ {action && (
+
+ )}
+
{variant === "filtered" && onClearFilters && (