Enhance loading state and UI for provider selection in dashboard components

- Added loading indicators using the Loader2 icon to improve user experience while fetching provider data in both ShowProviderForm and ShowProviderFormCompose components.
- Updated the minimum height of the provider selection messages to enhance visual consistency and user guidance during loading states.
- Refactored data fetching logic to include loading states for GitHub, GitLab, Bitbucket, and Gitea providers, ensuring a smoother user interface.
This commit is contained in:
Mauricio Siu 2025-05-04 12:29:37 -06:00
parent 4bec311ad0
commit 27521decbd
2 changed files with 87 additions and 18 deletions

View File

@ -13,7 +13,7 @@ import {
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { GitBranch, UploadCloud } from "lucide-react"; import { GitBranch, Loader2, UploadCloud } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useState } from "react"; import { useState } from "react";
import { SaveBitbucketProvider } from "./save-bitbucket-provider"; import { SaveBitbucketProvider } from "./save-bitbucket-provider";
@ -34,14 +34,49 @@ interface Props {
} }
export const ShowProviderForm = ({ applicationId }: Props) => { export const ShowProviderForm = ({ applicationId }: Props) => {
const { data: githubProviders } = api.github.githubProviders.useQuery(); const { data: githubProviders, isLoading: isLoadingGithub } =
const { data: gitlabProviders } = api.gitlab.gitlabProviders.useQuery(); api.github.githubProviders.useQuery();
const { data: bitbucketProviders } = const { data: gitlabProviders, isLoading: isLoadingGitlab } =
api.gitlab.gitlabProviders.useQuery();
const { data: bitbucketProviders, isLoading: isLoadingBitbucket } =
api.bitbucket.bitbucketProviders.useQuery(); api.bitbucket.bitbucketProviders.useQuery();
const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); const { data: giteaProviders, isLoading: isLoadingGitea } =
api.gitea.giteaProviders.useQuery();
const { data: application } = api.application.one.useQuery({ applicationId }); const { data: application } = api.application.one.useQuery({ applicationId });
const [tab, setSab] = useState<TabState>(application?.sourceType || "github"); const [tab, setSab] = useState<TabState>(application?.sourceType || "github");
const isLoading =
isLoadingGithub || isLoadingGitlab || isLoadingBitbucket || isLoadingGitea;
if (isLoading) {
return (
<Card className="group relative w-full bg-transparent">
<CardHeader>
<CardTitle className="flex items-start justify-between">
<div className="flex flex-col gap-2">
<span className="flex flex-col space-y-0.5">Provider</span>
<p className="flex items-center text-sm font-normal text-muted-foreground">
Select the source of your code
</p>
</div>
<div className="hidden space-y-1 text-sm font-normal md:block">
<GitBranch className="size-6 text-muted-foreground" />
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex min-h-[25vh] items-center justify-center">
<div className="flex items-center gap-2 text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
<span>Loading providers...</span>
</div>
</div>
</CardContent>
</Card>
);
}
return ( return (
<Card className="group relative w-full bg-transparent"> <Card className="group relative w-full bg-transparent">
<CardHeader> <CardHeader>
@ -123,7 +158,7 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
{githubProviders && githubProviders?.length > 0 ? ( {githubProviders && githubProviders?.length > 0 ? (
<SaveGithubProvider applicationId={applicationId} /> <SaveGithubProvider applicationId={applicationId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GithubIcon className="size-8 text-muted-foreground" /> <GithubIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using GitHub, you need to configure your account To deploy using GitHub, you need to configure your account
@ -143,7 +178,7 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
{gitlabProviders && gitlabProviders?.length > 0 ? ( {gitlabProviders && gitlabProviders?.length > 0 ? (
<SaveGitlabProvider applicationId={applicationId} /> <SaveGitlabProvider applicationId={applicationId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GitlabIcon className="size-8 text-muted-foreground" /> <GitlabIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using GitLab, you need to configure your account To deploy using GitLab, you need to configure your account
@ -163,7 +198,7 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
{bitbucketProviders && bitbucketProviders?.length > 0 ? ( {bitbucketProviders && bitbucketProviders?.length > 0 ? (
<SaveBitbucketProvider applicationId={applicationId} /> <SaveBitbucketProvider applicationId={applicationId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<BitbucketIcon className="size-8 text-muted-foreground" /> <BitbucketIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using Bitbucket, you need to configure your account To deploy using Bitbucket, you need to configure your account
@ -183,7 +218,7 @@ export const ShowProviderForm = ({ applicationId }: Props) => {
{giteaProviders && giteaProviders?.length > 0 ? ( {giteaProviders && giteaProviders?.length > 0 ? (
<SaveGiteaProvider applicationId={applicationId} /> <SaveGiteaProvider applicationId={applicationId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GiteaIcon className="size-8 text-muted-foreground" /> <GiteaIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using Gitea, you need to configure your account To deploy using Gitea, you need to configure your account

View File

@ -8,7 +8,7 @@ import {
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { CodeIcon, GitBranch } from "lucide-react"; import { CodeIcon, GitBranch, Loader2 } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useState } from "react"; import { useState } from "react";
import { ComposeFileEditor } from "../compose-file-editor"; import { ComposeFileEditor } from "../compose-file-editor";
@ -25,15 +25,49 @@ interface Props {
} }
export const ShowProviderFormCompose = ({ composeId }: Props) => { export const ShowProviderFormCompose = ({ composeId }: Props) => {
const { data: githubProviders } = api.github.githubProviders.useQuery(); const { data: githubProviders, isLoading: isLoadingGithub } =
const { data: gitlabProviders } = api.gitlab.gitlabProviders.useQuery(); api.github.githubProviders.useQuery();
const { data: bitbucketProviders } = const { data: gitlabProviders, isLoading: isLoadingGitlab } =
api.gitlab.gitlabProviders.useQuery();
const { data: bitbucketProviders, isLoading: isLoadingBitbucket } =
api.bitbucket.bitbucketProviders.useQuery(); api.bitbucket.bitbucketProviders.useQuery();
const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); const { data: giteaProviders, isLoading: isLoadingGitea } =
api.gitea.giteaProviders.useQuery();
const { data: compose } = api.compose.one.useQuery({ composeId }); const { data: compose } = api.compose.one.useQuery({ composeId });
const [tab, setSab] = useState<TabState>(compose?.sourceType || "github"); const [tab, setSab] = useState<TabState>(compose?.sourceType || "github");
const isLoading =
isLoadingGithub || isLoadingGitlab || isLoadingBitbucket || isLoadingGitea;
if (isLoading) {
return (
<Card className="group relative w-full bg-transparent">
<CardHeader>
<CardTitle className="flex items-start justify-between">
<div className="flex flex-col gap-2">
<span className="flex flex-col space-y-0.5">Provider</span>
<p className="flex items-center text-sm font-normal text-muted-foreground">
Select the source of your code
</p>
</div>
<div className="hidden space-y-1 text-sm font-normal md:block">
<GitBranch className="size-6 text-muted-foreground" />
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex min-h-[25vh] items-center justify-center">
<div className="flex items-center gap-2 text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
<span>Loading providers...</span>
</div>
</div>
</CardContent>
</Card>
);
}
return ( return (
<Card className="group relative w-full bg-transparent"> <Card className="group relative w-full bg-transparent">
<CardHeader> <CardHeader>
@ -108,7 +142,7 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
{githubProviders && githubProviders?.length > 0 ? ( {githubProviders && githubProviders?.length > 0 ? (
<SaveGithubProviderCompose composeId={composeId} /> <SaveGithubProviderCompose composeId={composeId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GithubIcon className="size-8 text-muted-foreground" /> <GithubIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using GitHub, you need to configure your account To deploy using GitHub, you need to configure your account
@ -128,7 +162,7 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
{gitlabProviders && gitlabProviders?.length > 0 ? ( {gitlabProviders && gitlabProviders?.length > 0 ? (
<SaveGitlabProviderCompose composeId={composeId} /> <SaveGitlabProviderCompose composeId={composeId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GitlabIcon className="size-8 text-muted-foreground" /> <GitlabIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using GitLab, you need to configure your account To deploy using GitLab, you need to configure your account
@ -148,7 +182,7 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
{bitbucketProviders && bitbucketProviders?.length > 0 ? ( {bitbucketProviders && bitbucketProviders?.length > 0 ? (
<SaveBitbucketProviderCompose composeId={composeId} /> <SaveBitbucketProviderCompose composeId={composeId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<BitbucketIcon className="size-8 text-muted-foreground" /> <BitbucketIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using Bitbucket, you need to configure your account To deploy using Bitbucket, you need to configure your account
@ -168,7 +202,7 @@ export const ShowProviderFormCompose = ({ composeId }: Props) => {
{giteaProviders && giteaProviders?.length > 0 ? ( {giteaProviders && giteaProviders?.length > 0 ? (
<SaveGiteaProviderCompose composeId={composeId} /> <SaveGiteaProviderCompose composeId={composeId} />
) : ( ) : (
<div className="flex flex-col items-center gap-3 min-h-[15vh] justify-center"> <div className="flex flex-col items-center gap-3 min-h-[25vh] justify-center">
<GiteaIcon className="size-8 text-muted-foreground" /> <GiteaIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
To deploy using Gitea, you need to configure your account To deploy using Gitea, you need to configure your account