BranchSelector.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { Check, GitMerge, Shield } from 'lucide-react'
  2. import { useState } from 'react'
  3. import {
  4. Command,
  5. CommandEmpty,
  6. CommandGroup,
  7. CommandInput,
  8. CommandItem,
  9. CommandList,
  10. Popover,
  11. PopoverContent,
  12. PopoverTrigger,
  13. ScrollArea,
  14. } from 'ui'
  15. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  16. import { Branch } from '@/data/branches/branches-query'
  17. interface BranchSelectorProps {
  18. branches: Branch[]
  19. onBranchSelected?: (branch: Branch) => void
  20. disabled?: boolean
  21. isUpdating?: boolean
  22. type?: 'primary' | 'outline'
  23. align?: 'end' | 'center'
  24. }
  25. export const BranchSelector = ({
  26. branches,
  27. onBranchSelected,
  28. disabled = false,
  29. isUpdating = false,
  30. type = 'primary',
  31. align = 'end',
  32. }: BranchSelectorProps) => {
  33. const [open, setOpen] = useState(false)
  34. const [selectedBranch, setSelectedBranch] = useState<Branch | null>(null)
  35. const availableBranches = branches.filter((branch) => !branch.is_default)
  36. const handleBranchSelect = (branch: Branch) => {
  37. setSelectedBranch(branch)
  38. setOpen(false)
  39. onBranchSelected?.(branch)
  40. }
  41. return (
  42. <Popover open={open} onOpenChange={setOpen} modal={false}>
  43. <PopoverTrigger asChild>
  44. <ButtonTooltip
  45. icon={<GitMerge size={14} strokeWidth={1.5} />}
  46. type={type}
  47. disabled={
  48. disabled || isUpdating || branches.length === 0 || availableBranches.length === 0
  49. }
  50. tooltip={{
  51. content: {
  52. side: 'bottom',
  53. align,
  54. text:
  55. branches.length === 0 || availableBranches.length === 0
  56. ? 'Create a branch first to start a merge request'
  57. : undefined,
  58. },
  59. }}
  60. >
  61. {isUpdating ? 'Creating...' : 'New merge request'}
  62. </ButtonTooltip>
  63. </PopoverTrigger>
  64. <PopoverContent className="p-0 w-80" side="bottom" align="end">
  65. <Command>
  66. <CommandInput placeholder="Find branch to review..." />
  67. <CommandList>
  68. <CommandEmpty>No available branches found</CommandEmpty>
  69. <CommandGroup>
  70. <ScrollArea className="max-h-[210px] overflow-y-auto">
  71. {availableBranches.map((branch) => (
  72. <CommandItem
  73. key={branch.id}
  74. value={branch.name.replaceAll('"', '')}
  75. className="cursor-pointer w-full flex items-center justify-between"
  76. onSelect={() => handleBranchSelect(branch)}
  77. disabled={isUpdating || !!branch.git_branch || !!branch.review_requested_at}
  78. >
  79. <div className="flex items-center gap-2">
  80. {branch.is_default && <Shield size={14} className="text-amber-900" />}
  81. <span className="truncate" title={branch.name}>
  82. {branch.name}
  83. </span>
  84. </div>
  85. {selectedBranch?.id === branch.id && (
  86. <Check size={14} strokeWidth={1.5} className="text-brand" />
  87. )}
  88. {branch.git_branch && <span>Synced to a Git branch</span>}
  89. {branch.review_requested_at && <span>Merge request opened</span>}
  90. </CommandItem>
  91. ))}
  92. </ScrollArea>
  93. </CommandGroup>
  94. </CommandList>
  95. </Command>
  96. </PopoverContent>
  97. </Popover>
  98. )
  99. }