diff --git a/README.md b/README.md index 01445997..c9dce2c1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Dashboard SPA tracking GitHub issues, PRs, and GHA workflow runs across multiple ## Features -- **Issues Tab** — Open issues where you're the creator, assignee, or mentioned. Sortable, filterable, paginated. +- **Issues Tab** — Open issues where you're the creator, assignee, or mentioned. Sortable, filterable, paginated. Dependency Dashboard issues hidden by default (toggleable). - **Pull Requests Tab** — Open PRs with CI check status indicators (green/yellow/red dots). Draft badges, reviewer names. - **Actions Tab** — GHA workflow runs grouped by repo and workflow. Accordion collapse, PR run toggle. - **Onboarding Wizard** — Two-step org/repo selection with search filtering and bulk select. diff --git a/src/app/components/dashboard/ActionsTab.tsx b/src/app/components/dashboard/ActionsTab.tsx index ab94ab1a..c20267fb 100644 --- a/src/app/components/dashboard/ActionsTab.tsx +++ b/src/app/components/dashboard/ActionsTab.tsx @@ -11,6 +11,7 @@ import type { FilterChipGroupDef } from "../shared/FilterChips"; import ChevronIcon from "../shared/ChevronIcon"; import ExpandCollapseButtons from "../shared/ExpandCollapseButtons"; import RepoLockControls from "../shared/RepoLockControls"; +import RepoGitHubLink from "../shared/RepoGitHubLink"; import { orderRepoGroups } from "../../lib/grouping"; import { createReorderHighlight } from "../../lib/reorderHighlight"; import { createFlashDetection } from "../../lib/flashDetection"; @@ -19,6 +20,7 @@ interface ActionsTabProps { workflowRuns: WorkflowRun[]; loading?: boolean; hasUpstreamRepos?: boolean; + refreshTick?: number; hotPollingRunIds?: ReadonlySet; } @@ -318,6 +320,7 @@ export default function ActionsTab(props: ActionsTabProps) { + @@ -347,6 +350,7 @@ export default function ActionsTab(props: ActionsTabProps) { onToggle={() => toggleWorkflow(wfKey)} onIgnoreRun={handleIgnore} density={config.viewDensity} + refreshTick={props.refreshTick} hotPollingRunIds={props.hotPollingRunIds} flashingRunIds={flashingRunIds()} /> diff --git a/src/app/components/dashboard/DashboardPage.tsx b/src/app/components/dashboard/DashboardPage.tsx index 393ec83c..a5ff0885 100644 --- a/src/app/components/dashboard/DashboardPage.tsx +++ b/src/app/components/dashboard/DashboardPage.tsx @@ -240,6 +240,8 @@ export default function DashboardPage() { updateViewState({ lastActiveTab: tab }); } + const [clockTick, setClockTick] = createSignal(0); + onMount(() => { if (!_coordinator()) { _setCoordinator(createPollCoordinator(() => config.refreshInterval, pollFetch)); @@ -306,15 +308,21 @@ export default function DashboardPage() { }); } + // Wall-clock tick keeps relative time displays fresh between full poll cycles. + const clockInterval = setInterval(() => setClockTick((t) => t + 1), 60_000); + onCleanup(() => { _coordinator()?.destroy(); _setCoordinator(null); _hotCoordinator()?.destroy(); _setHotCoordinator(null); clearHotSets(); + clearInterval(clockInterval); }); }); + const refreshTick = createMemo(() => (dashboardData.lastRefreshedAt?.getTime() ?? 0) + clockTick()); + const tabCounts = createMemo(() => ({ issues: dashboardData.issues.length, pullRequests: dashboardData.pullRequests.length, @@ -336,22 +344,23 @@ export default function DashboardPage() {
{/* Offset for fixed header */} -
- {/* Single constrained panel: tabs + filters + content */} -
- - - _coordinator()?.manualRefresh()} - /> - -
+
+
+
+ + + _coordinator()?.manualRefresh()} + /> +
+ +
@@ -372,6 +382,7 @@ export default function DashboardPage() { trackedUsers={config.trackedUsers} hotPollingPRIds={hotPollingPRIds()} monitoredRepos={config.monitoredRepos} + refreshTick={refreshTick()} /> @@ -379,6 +390,7 @@ export default function DashboardPage() { workflowRuns={dashboardData.workflowRuns} loading={dashboardData.loading} hasUpstreamRepos={config.upstreamRepos.length > 0} + refreshTick={refreshTick()} hotPollingRunIds={hotPollingRunIds()} /> @@ -386,7 +398,7 @@ export default function DashboardPage() {
-