ViewAppSheetInfo.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { formatDistanceToNow } from 'date-fns'
  2. import { Check, Copy } from 'lucide-react'
  3. import { useState } from 'react'
  4. import { toast } from 'sonner'
  5. import {
  6. Badge,
  7. Card,
  8. CardContent,
  9. copyToClipboard,
  10. Table,
  11. TableBody,
  12. TableCell,
  13. TableHead,
  14. TableHeader,
  15. TableRow,
  16. } from 'ui'
  17. import type { Installation, PrivateApp } from '../../PrivateAppsContext'
  18. interface ViewAppSheetInfoProps {
  19. app: PrivateApp
  20. isInstalled: boolean
  21. installation: Installation | undefined
  22. }
  23. function CopyableId({ id, label }: { id: string; label: string }) {
  24. const [isCopied, setIsCopied] = useState(false)
  25. function handleCopy(e: React.MouseEvent) {
  26. e.stopPropagation()
  27. copyToClipboard(id, () => {
  28. setIsCopied(true)
  29. toast.success(`Copied ${label} to clipboard`)
  30. setTimeout(() => setIsCopied(false), 2000)
  31. })
  32. }
  33. return (
  34. <button
  35. onClick={handleCopy}
  36. className="inline-flex items-center gap-x-1 cursor-pointer border border-transparent border-dashed rounded-sm transition-colors hover:bg-surface-100 hover:border hover:border-strong group font-mono text-xs text-foreground-light px-1 -ml-1"
  37. >
  38. <span className="truncate">{id}</span>
  39. {isCopied ? (
  40. <Check size={12} strokeWidth={1.25} className="text-brand shrink-0" />
  41. ) : (
  42. <Copy
  43. size={12}
  44. strokeWidth={1.25}
  45. className="opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
  46. />
  47. )}
  48. </button>
  49. )
  50. }
  51. export function ViewAppSheetInfo({ app, isInstalled, installation }: ViewAppSheetInfoProps) {
  52. return (
  53. <div className="px-5 sm:px-6 py-6 space-y-3">
  54. <h3 className="text-sm font-medium text-foreground">Metadata</h3>
  55. <Card className="w-full overflow-hidden bg-surface-100">
  56. <CardContent className="p-0">
  57. <Table className="table-fixed w-full">
  58. <TableHeader>
  59. <TableRow>
  60. <TableHead className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 w-[40%]">
  61. Field
  62. </TableHead>
  63. <TableHead className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 w-[60%]">
  64. Value
  65. </TableHead>
  66. </TableRow>
  67. </TableHeader>
  68. <TableBody>
  69. <TableRow>
  70. <TableCell>
  71. <p className="text-foreground-light truncate">Name</p>
  72. </TableCell>
  73. <TableCell>
  74. <p className="font-medium truncate">{app.name}</p>
  75. </TableCell>
  76. </TableRow>
  77. <TableRow>
  78. <TableCell>
  79. <p className="text-foreground-light truncate">Created</p>
  80. </TableCell>
  81. <TableCell>
  82. <p className="truncate">
  83. {formatDistanceToNow(new Date(app.created_at), { addSuffix: true })}
  84. </p>
  85. </TableCell>
  86. </TableRow>
  87. <TableRow>
  88. <TableCell>
  89. <p className="text-foreground-light truncate">Status</p>
  90. </TableCell>
  91. <TableCell>
  92. {isInstalled ? (
  93. <Badge variant="success" className="uppercase">
  94. Installed
  95. </Badge>
  96. ) : (
  97. <Badge variant="default" className="uppercase">
  98. Uninstalled
  99. </Badge>
  100. )}
  101. </TableCell>
  102. </TableRow>
  103. <TableRow>
  104. <TableCell>
  105. <p className="text-foreground-light truncate">App ID</p>
  106. </TableCell>
  107. <TableCell>
  108. <CopyableId id={app.id} label="App ID" />
  109. </TableCell>
  110. </TableRow>
  111. <TableRow>
  112. <TableCell>
  113. <p className="text-foreground-light truncate">Installation ID</p>
  114. </TableCell>
  115. <TableCell>
  116. {installation ? (
  117. <CopyableId id={installation.id} label="Installation ID" />
  118. ) : (
  119. <p className="font-mono text-xs text-foreground-light">—</p>
  120. )}
  121. </TableCell>
  122. </TableRow>
  123. </TableBody>
  124. </Table>
  125. </CardContent>
  126. </Card>
  127. </div>
  128. )
  129. }