scoped.tsx 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { ExternalLink, Search } from 'lucide-react'
  2. import { useState } from 'react'
  3. import { Button } from 'ui'
  4. import { Input } from 'ui-patterns/DataInputs/Input'
  5. import { AccessTokenNewBanner } from '@/components/interfaces/Account/AccessTokens/AccessTokenNewBanner/AccessTokenNewBanner'
  6. import { NewScopedTokenButton } from '@/components/interfaces/Account/AccessTokens/Scoped/NewScopedTokenButton'
  7. import { ScopedTokenList } from '@/components/interfaces/Account/AccessTokens/Scoped/ScopedTokenList'
  8. import { AccessTokensLayout } from '@/components/layouts/AccessTokens/AccessTokensLayout'
  9. import AccountLayout from '@/components/layouts/AccountLayout/AccountLayout'
  10. import { AppLayout } from '@/components/layouts/AppLayout/AppLayout'
  11. import { DefaultLayout } from '@/components/layouts/DefaultLayout'
  12. import { NewScopedAccessToken } from '@/data/scoped-access-tokens/scoped-access-token-create-mutation'
  13. import type { NextPageWithLayout } from '@/types'
  14. const ScopedTokens: NextPageWithLayout = () => {
  15. const [searchString, setSearchString] = useState('')
  16. const [newToken, setNewToken] = useState<NewScopedAccessToken | undefined>()
  17. return (
  18. <AccessTokensLayout>
  19. <div className="space-y-4">
  20. {newToken && (
  21. <AccessTokenNewBanner
  22. token={newToken}
  23. onClose={() => setNewToken(undefined)}
  24. getTokenValue={(token) => token.token}
  25. getTokenPermissions={(token) => token.permissions}
  26. />
  27. )}
  28. <div className="flex items-center justify-between gap-x-2 mb-3">
  29. <Input
  30. size="tiny"
  31. autoComplete="off"
  32. icon={<Search size={12} />}
  33. value={searchString}
  34. onChange={(e) => setSearchString(e.target.value)}
  35. name="search"
  36. id="search"
  37. placeholder="Filter by name"
  38. />
  39. <div className="flex items-center gap-x-2">
  40. <Button asChild type="default" icon={<ExternalLink />}>
  41. <a
  42. href="https://supabase.com/docs/reference/api/introduction"
  43. target="_blank"
  44. rel="noreferrer"
  45. >
  46. API Docs
  47. </a>
  48. </Button>
  49. <Button asChild type="default" icon={<ExternalLink />}>
  50. <a
  51. href="https://supabase.com/docs/reference/cli/start"
  52. target="_blank"
  53. rel="noreferrer"
  54. >
  55. CLI docs
  56. </a>
  57. </Button>
  58. <NewScopedTokenButton onCreateToken={setNewToken} />
  59. </div>
  60. </div>
  61. <ScopedTokenList
  62. searchString={searchString}
  63. onDeleteSuccess={(id) => {
  64. if (id === newToken?.id) setNewToken(undefined)
  65. }}
  66. />
  67. <p className="text-sm text-foreground-muted text-center mt-6">
  68. Looking for Private Apps?{' '}
  69. <a
  70. href="/org"
  71. className="text-foreground-light underline hover:text-foreground transition-colors"
  72. >
  73. Go to Organization Settings → Connections → Private Apps
  74. </a>
  75. </p>
  76. </div>
  77. </AccessTokensLayout>
  78. )
  79. }
  80. ScopedTokens.getLayout = (page) => (
  81. <AppLayout>
  82. <DefaultLayout headerTitle="Account">
  83. <AccountLayout title="Access Tokens">{page}</AccountLayout>
  84. </DefaultLayout>
  85. </AppLayout>
  86. )
  87. export default ScopedTokens