feat(forgejo): add create issue dialog and integrate with metric cards
This commit is contained in:
parent
463a75fdb7
commit
1076ca27bb
|
|
@ -19,6 +19,7 @@ import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
|
||||||
import { DashboardShell } from "@/components/templates/DashboardShell";
|
import { DashboardShell } from "@/components/templates/DashboardShell";
|
||||||
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
|
||||||
import { ForgejoIssueMetricCards } from "@/components/git/ForgejoIssueMetricCards";
|
import { ForgejoIssueMetricCards } from "@/components/git/ForgejoIssueMetricCards";
|
||||||
|
import { CreateForgejoIssueDialog } from "@/components/git/CreateForgejoIssueDialog";
|
||||||
import { ForgejoHeatmap } from "@/components/git/ForgejoHeatmap";
|
import { ForgejoHeatmap } from "@/components/git/ForgejoHeatmap";
|
||||||
import {
|
import {
|
||||||
DashboardMetricCard,
|
DashboardMetricCard,
|
||||||
|
|
@ -440,6 +441,7 @@ export default function DashboardPage() {
|
||||||
const [selectedForgejoRepositoryId, setSelectedForgejoRepositoryId] =
|
const [selectedForgejoRepositoryId, setSelectedForgejoRepositoryId] =
|
||||||
useState(ALL_FORGEJO_REPOSITORIES);
|
useState(ALL_FORGEJO_REPOSITORIES);
|
||||||
const [isRefreshingForgejoSync, setIsRefreshingForgejoSync] = useState(false);
|
const [isRefreshingForgejoSync, setIsRefreshingForgejoSync] = useState(false);
|
||||||
|
const [createForgejoIssueOpen, setCreateForgejoIssueOpen] = useState(false);
|
||||||
|
|
||||||
const boardsQuery = useListBoardsApiV1BoardsGet<
|
const boardsQuery = useListBoardsApiV1BoardsGet<
|
||||||
listBoardsApiV1BoardsGetResponse,
|
listBoardsApiV1BoardsGetResponse,
|
||||||
|
|
@ -1325,10 +1327,30 @@ export default function DashboardPage() {
|
||||||
selectedRepositoryId={selectedForgejoRepositoryId}
|
selectedRepositoryId={selectedForgejoRepositoryId}
|
||||||
onSelectedRepositoryChange={setSelectedForgejoRepositoryId}
|
onSelectedRepositoryChange={setSelectedForgejoRepositoryId}
|
||||||
onRefreshLastSync={handleRefreshForgejoLastSync}
|
onRefreshLastSync={handleRefreshForgejoLastSync}
|
||||||
|
onCreateIssue={() => setCreateForgejoIssueOpen(true)}
|
||||||
isRefreshingLastSync={isRefreshingForgejoSync}
|
isRefreshingLastSync={isRefreshingForgejoSync}
|
||||||
isLoading={forgejoIssueMetricsLoading}
|
isLoading={forgejoIssueMetricsLoading}
|
||||||
error={forgejoIssueMetricsError}
|
error={forgejoIssueMetricsError}
|
||||||
/>
|
/>
|
||||||
|
<CreateForgejoIssueDialog
|
||||||
|
repositories={forgejoRepositories}
|
||||||
|
open={createForgejoIssueOpen}
|
||||||
|
onOpenChange={setCreateForgejoIssueOpen}
|
||||||
|
defaultRepositoryId={
|
||||||
|
selectedForgejoRepositoryId === ALL_FORGEJO_REPOSITORIES
|
||||||
|
? undefined
|
||||||
|
: selectedForgejoRepositoryId
|
||||||
|
}
|
||||||
|
onSuccess={() => {
|
||||||
|
setCreateForgejoIssueOpen(false);
|
||||||
|
void Promise.all([
|
||||||
|
forgejoRepositoriesQuery.refetch(),
|
||||||
|
forgejoMetricsQuery.refetch(),
|
||||||
|
forgejoHeatmapQuery.refetch(),
|
||||||
|
forgejoLastPushQuery.refetch(),
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
|
@ -43,6 +43,12 @@ export function CreateForgejoIssueDialog({
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (open && !isSubmitting) {
|
||||||
|
setRepositoryId(defaultRepositoryId ?? repositories[0]?.id ?? "");
|
||||||
|
}
|
||||||
|
}, [defaultRepositoryId, isSubmitting, open, repositories]);
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setTitle("");
|
setTitle("");
|
||||||
setBody(ISSUE_TEMPLATE);
|
setBody(ISSUE_TEMPLATE);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
ArrowUpRight,
|
ArrowUpRight,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
Clock3,
|
Clock3,
|
||||||
|
PlusCircle,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
ShieldAlert,
|
ShieldAlert,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
|
|
@ -30,6 +31,7 @@ type ForgejoIssueMetricCardsProps = {
|
||||||
selectedRepositoryId: string;
|
selectedRepositoryId: string;
|
||||||
onSelectedRepositoryChange: (repositoryId: string) => void;
|
onSelectedRepositoryChange: (repositoryId: string) => void;
|
||||||
onRefreshLastSync: () => void;
|
onRefreshLastSync: () => void;
|
||||||
|
onCreateIssue: () => void;
|
||||||
isRefreshingLastSync?: boolean;
|
isRefreshingLastSync?: boolean;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
error?: string | null;
|
error?: string | null;
|
||||||
|
|
@ -309,6 +311,7 @@ export function ForgejoIssueMetricCards({
|
||||||
selectedRepositoryId,
|
selectedRepositoryId,
|
||||||
onSelectedRepositoryChange,
|
onSelectedRepositoryChange,
|
||||||
onRefreshLastSync,
|
onRefreshLastSync,
|
||||||
|
onCreateIssue,
|
||||||
isRefreshingLastSync = false,
|
isRefreshingLastSync = false,
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
error,
|
error,
|
||||||
|
|
@ -412,17 +415,15 @@ export function ForgejoIssueMetricCards({
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Link
|
<button
|
||||||
href={
|
type="button"
|
||||||
selectedRepositoryId === ALL_REPOSITORIES_VALUE
|
onClick={onCreateIssue}
|
||||||
? "/git-projects/issues"
|
disabled={repositories.length === 0}
|
||||||
: `/git-projects/issues?repository_id=${encodeURIComponent(selectedRepositoryId)}`
|
className="inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--accent)] transition hover:text-[color:var(--accent-strong)] disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
}
|
|
||||||
className="inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--accent)] transition hover:text-[color:var(--accent-strong)]"
|
|
||||||
>
|
>
|
||||||
Open issues
|
Create issue
|
||||||
<ArrowUpRight className="h-4 w-4" />
|
<PlusCircle className="h-4 w-4" />
|
||||||
</Link>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue