feat(ui): add repository link buttons for git providers

- Implement "View Repository" links for GitHub, GitLab, Bitbucket, and Git providers
- Add repository icons and direct links to source repositories
- Support links for both application and compose service git provider forms
- Enhance user experience with quick access to repository pages
This commit is contained in:
Mauricio Siu 2025-03-08 23:45:21 -06:00
parent 9d50f384d1
commit 467bca3efb
8 changed files with 129 additions and 14 deletions

View File

@ -44,6 +44,8 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
import Link from "next/link";
const BitbucketProviderSchema = z.object({ const BitbucketProviderSchema = z.object({
buildPath: z.string().min(1, "Path is required").default("/"), buildPath: z.string().min(1, "Path is required").default("/"),
@ -206,7 +208,20 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://bitbucket.org/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<BitbucketIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>

View File

@ -27,12 +27,14 @@ import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { KeyRoundIcon, LockIcon, X } from "lucide-react"; import { KeyRoundIcon, LockIcon, X } from "lucide-react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Link from "next/link";
import { useEffect } from "react"; import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { GitIcon } from "@/components/icons/data-tools-icons";
const GitProviderSchema = z.object({ const GitProviderSchema = z.object({
buildPath: z.string().min(1, "Path is required").default("/"), buildPath: z.string().min(1, "Path is required").default("/"),
@ -113,11 +115,22 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
name="repositoryURL" name="repositoryURL"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel className="flex flex-row justify-between"> <div className="flex items-center justify-between">
Repository URL <FormLabel>Repository URL</FormLabel>
</FormLabel> {field.value?.startsWith("https://") && (
<Link
href={field.value}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GitIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<FormControl> <FormControl>
<Input placeholder="git@bitbucket.org" {...field} /> <Input placeholder="Repository URL" {...field} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@ -44,6 +44,7 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import Link from "next/link"; import Link from "next/link";
import { GithubIcon } from "@/components/icons/data-tools-icons";
const GithubProviderSchema = z.object({ const GithubProviderSchema = z.object({
buildPath: z.string().min(1, "Path is required").default("/"), buildPath: z.string().min(1, "Path is required").default("/"),
@ -198,7 +199,20 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://github.com/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GithubIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>

View File

@ -44,6 +44,8 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import Link from "next/link";
import { GitlabIcon } from "@/components/icons/data-tools-icons";
const GitlabProviderSchema = z.object({ const GitlabProviderSchema = z.object({
buildPath: z.string().min(1, "Path is required").default("/"), buildPath: z.string().min(1, "Path is required").default("/"),
@ -213,7 +215,20 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://gitlab.com/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GitlabIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>

View File

@ -44,6 +44,8 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
import Link from "next/link";
const BitbucketProviderSchema = z.object({ const BitbucketProviderSchema = z.object({
composePath: z.string().min(1), composePath: z.string().min(1),
@ -208,7 +210,20 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://bitbucket.org/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<BitbucketIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>

View File

@ -32,6 +32,8 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { GitIcon } from "@/components/icons/data-tools-icons";
import Link from "next/link";
const GitProviderSchema = z.object({ const GitProviderSchema = z.object({
composePath: z.string().min(1), composePath: z.string().min(1),
@ -113,11 +115,22 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
name="repositoryURL" name="repositoryURL"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel className="flex flex-row justify-between"> <div className="flex items-center justify-between">
Repository URL <FormLabel>Repository URL</FormLabel>
</FormLabel> {field.value?.startsWith("https://") && (
<Link
href={field.value}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GitIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<FormControl> <FormControl>
<Input placeholder="git@bitbucket.org" {...field} /> <Input placeholder="Repository URL" {...field} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@ -43,6 +43,8 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { GithubIcon } from "@/components/icons/data-tools-icons";
import Link from "next/link";
const GithubProviderSchema = z.object({ const GithubProviderSchema = z.object({
composePath: z.string().min(1), composePath: z.string().min(1),
@ -199,7 +201,20 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://github.com/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GithubIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>

View File

@ -44,6 +44,8 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { GitlabIcon } from "@/components/icons/data-tools-icons";
import Link from "next/link";
const GitlabProviderSchema = z.object({ const GitlabProviderSchema = z.object({
composePath: z.string().min(1), composePath: z.string().min(1),
@ -215,7 +217,20 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
name="repository" name="repository"
render={({ field }) => ( render={({ field }) => (
<FormItem className="md:col-span-2 flex flex-col"> <FormItem className="md:col-span-2 flex flex-col">
<FormLabel>Repository</FormLabel> <div className="flex items-center justify-between">
<FormLabel>Repository</FormLabel>
{field.value.owner && field.value.repo && (
<Link
href={`https://gitlab.com/${field.value.owner}/${field.value.repo}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-sm text-muted-foreground hover:text-primary"
>
<GitlabIcon className="h-4 w-4" />
<span>View Repository</span>
</Link>
)}
</div>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<FormControl> <FormControl>