55 ImportIcon ,
66 Loader2 ,
77 Trash2 ,
8+ Users ,
89} from "lucide-react" ;
910import Link from "next/link" ;
1011import { toast } from "sonner" ;
@@ -24,6 +25,13 @@ import {
2425 CardHeader ,
2526 CardTitle ,
2627} from "@/components/ui/card" ;
28+ import { Switch } from "@/components/ui/switch" ;
29+ import {
30+ Tooltip ,
31+ TooltipContent ,
32+ TooltipProvider ,
33+ TooltipTrigger ,
34+ } from "@/components/ui/tooltip" ;
2735import { api } from "@/utils/api" ;
2836import { useUrl } from "@/utils/hooks/use-url" ;
2937import { AddBitbucketProvider } from "./bitbucket/add-bitbucket-provider" ;
@@ -39,6 +47,8 @@ export const ShowGitProviders = () => {
3947 const { data, isPending, refetch } = api . gitProvider . getAll . useQuery ( ) ;
4048 const { mutateAsync, isPending : isRemoving } =
4149 api . gitProvider . remove . useMutation ( ) ;
50+ const { mutateAsync : toggleShare , isPending : isToggling } =
51+ api . gitProvider . toggleShare . useMutation ( ) ;
4252 const url = useUrl ( ) ;
4353
4454 const getGitlabUrl = (
@@ -154,10 +164,62 @@ export const ShowGitProviders = () => {
154164 ) }
155165 </ span >
156166 </ div >
167+ { ! gitProvider . isOwner && (
168+ < Badge
169+ variant = "secondary"
170+ className = "text-xs"
171+ >
172+ < Users className = "size-3 mr-1" />
173+ Shared
174+ </ Badge >
175+ ) }
157176 </ div >
158177 </ div >
159178
160179 < div className = "flex flex-row gap-1 items-center" >
180+ { gitProvider . isOwner && (
181+ < TooltipProvider delayDuration = { 0 } >
182+ < Tooltip >
183+ < TooltipTrigger asChild >
184+ < div className = "flex items-center gap-1.5 mr-2" >
185+ < Users className = "size-4 text-muted-foreground" />
186+ < Switch
187+ disabled = { isToggling }
188+ checked = {
189+ gitProvider . sharedWithOrganization
190+ }
191+ onCheckedChange = { async (
192+ checked ,
193+ ) => {
194+ await toggleShare ( {
195+ gitProviderId :
196+ gitProvider . gitProviderId ,
197+ sharedWithOrganization : checked ,
198+ } )
199+ . then ( ( ) => {
200+ toast . success (
201+ checked
202+ ? "Provider shared with organization"
203+ : "Provider unshared" ,
204+ ) ;
205+ refetch ( ) ;
206+ } )
207+ . catch ( ( ) => {
208+ toast . error (
209+ "Error updating sharing" ,
210+ ) ;
211+ } ) ;
212+ } }
213+ />
214+ </ div >
215+ </ TooltipTrigger >
216+ < TooltipContent >
217+ Share with entire organization
218+ </ TooltipContent >
219+ </ Tooltip >
220+ </ TooltipProvider >
221+ ) }
222+
161223 { isBitbucket &&
162224 gitProvider . bitbucket ?. appPassword &&
163225 ! gitProvider . bitbucket ?. apiToken ? (
@@ -222,62 +284,71 @@ export const ShowGitProviders = () => {
222284 </ div >
223285 ) }
224286
225- { isGithub && haveGithubRequirements && (
226- < EditGithubProvider
227- githubId = { gitProvider . github ?. githubId }
228- />
229- ) }
287+ { gitProvider . isOwner && (
288+ < >
289+ { isGithub && haveGithubRequirements && (
290+ < EditGithubProvider
291+ githubId = { gitProvider . github ?. githubId }
292+ />
293+ ) }
230294
231- { isGitlab && (
232- < EditGitlabProvider
233- gitlabId = { gitProvider . gitlab ?. gitlabId }
234- />
235- ) }
295+ { isGitlab && (
296+ < EditGitlabProvider
297+ gitlabId = { gitProvider . gitlab ?. gitlabId }
298+ />
299+ ) }
236300
237- { isBitbucket && (
238- < EditBitbucketProvider
239- bitbucketId = {
240- gitProvider . bitbucket ?. bitbucketId
241- }
242- />
243- ) }
301+ { isBitbucket && (
302+ < EditBitbucketProvider
303+ bitbucketId = {
304+ gitProvider . bitbucket ?. bitbucketId
305+ }
306+ />
307+ ) }
244308
245- { isGitea && (
246- < EditGiteaProvider
247- giteaId = { gitProvider . gitea ?. giteaId }
248- />
249- ) }
309+ { isGitea && (
310+ < EditGiteaProvider
311+ giteaId = { gitProvider . gitea ?. giteaId }
312+ />
313+ ) }
250314
251- < DialogAction
252- title = "Delete Git Provider"
253- description = "Are you sure you want to delete this Git Provider?"
254- type = "destructive"
255- onClick = { async ( ) => {
256- await mutateAsync ( {
257- gitProviderId : gitProvider . gitProviderId ,
258- } )
259- . then ( ( ) => {
260- toast . success (
261- "Git Provider deleted successfully" ,
262- ) ;
263- refetch ( ) ;
264- } )
265- . catch ( ( ) => {
266- toast . error (
267- "Error deleting Git Provider" ,
268- ) ;
269- } ) ;
270- } }
271- >
272- < Button
273- variant = "ghost"
274- size = "icon"
275- className = "group hover:bg-red-500/10"
276- isLoading = { isRemoving }
277- >
278- < Trash2 className = "size-4 text-primary group-hover:text-red-500" />
279- </ Button >
280- </ DialogAction >
315+ < DialogAction
316+ title = "Delete Git Provider"
317+ description = {
318+ gitProvider . sharedWithOrganization
319+ ? "This provider is shared with the organization. Deleting it will remove access for all members. Are you sure?"
320+ : "Are you sure you want to delete this Git Provider?"
321+ }
322+ type = "destructive"
323+ onClick = { async ( ) => {
324+ await mutateAsync ( {
325+ gitProviderId :
326+ gitProvider . gitProviderId ,
327+ } )
328+ . then ( ( ) => {
329+ toast . success (
330+ "Git Provider deleted successfully" ,
331+ ) ;
332+ refetch ( ) ;
333+ } )
334+ . catch ( ( ) => {
335+ toast . error (
336+ "Error deleting Git Provider" ,
337+ ) ;
338+ } ) ;
339+ } }
340+ >
341+ < Button
342+ variant = "ghost"
343+ size = "icon"
344+ className = "group hover:bg-red-500/10"
345+ isLoading = { isRemoving }
346+ >
347+ < Trash2 className = "size-4 text-primary group-hover:text-red-500" />
348+ </ Button >
349+ </ DialogAction >
350+ </ >
351+ ) }
281352 </ div >
282353 </ div >
283354 </ div >
0 commit comments