refactor: consolidate loading/error states and extract instance actions hook

Frontend:
- Create reusable DataStates components (LoadingState, ErrorState, EmptyState)
- Refactor 12 pages to use shared state components instead of inline JSX
- Extract useInstanceActions hook to eliminate session action duplication
- Update dashboard and sessions pages to use shared hook

OpenSpec:
- Archive completed mobile-app-usability change (44/44 tasks)
- Archive completed add-config-profiles change (15/15 tasks)

Quality: TypeScript check passes, production build succeeds
This commit is contained in:
Alex Blank
2026-05-25 22:50:18 +02:00
parent 4c216dd1ca
commit ab79080f0b
31 changed files with 258 additions and 266 deletions
+5 -14
View File
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { EmptyState, ErrorState, LoadingState } from "../components/data-states";
import { Icon } from "../components/icon";
import { useMobileViewport } from "../hooks/use-mobile-viewport";
@@ -164,26 +165,16 @@ export const RepoWorkspace = () => {
)}
{status === "loading" && (
<p className="muted">Loading repositories...</p>
<LoadingState message="Loading repositories..." />
)}
{status === "error" && (
<div className="card stack">
<p>Failed to load repositories</p>
<button
className="secondary-button"
onClick={() => void loadRepositories()}
type="button"
>
<Icon name="refresh" size="sm" />
Retry
</button>
</div>
<ErrorState message="Failed to load repositories" onRetry={() => void loadRepositories()} />
)}
{status === "empty" && (
<div className="card stack">
<p>No repositories in this project yet.</p>
<EmptyState message="No repositories in this project yet." />
<Link
className="primary-button"
to={`/projects/${projectId}/settings/repositories`}
@@ -486,7 +477,7 @@ const FileBrowser = ({
</button>
)}
{entries.length === 0 && (
<p className="muted">No files in this repository yet.</p>
<EmptyState message="No files in this repository yet." />
)}
{entries.map((entry) => {
const fileStatus = entry.type === "file" ? getFileStatus(entry.path) : null;