Skip to content

Commit

Permalink
feat(ui): add license guard at proper locations (TabbyML#1549)
Browse files Browse the repository at this point in the history
* ui: add license guard at proper locations

* fix

* [autofix.ci] apply automated fixes

* fix preventDefault

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: liangfung <[email protected]>
  • Loading branch information
3 people authored Feb 26, 2024
1 parent a4a3640 commit a84e441
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useClient, useQuery } from 'urql'
import * as z from 'zod'

import { graphql } from '@/lib/gql/generates'
import { OAuthProvider } from '@/lib/gql/generates/graphql'
import { LicenseType, OAuthProvider } from '@/lib/gql/generates/graphql'
import { useMutation } from '@/lib/tabby/gql'
import { cn } from '@/lib/utils'
import {
Expand Down Expand Up @@ -39,6 +39,7 @@ import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import { CopyButton } from '@/components/copy-button'
import { LicenseGuard } from '@/components/license-guard'

import { oauthCredential } from './oauth-credential-list'

Expand Down Expand Up @@ -324,15 +325,21 @@ export default function OAuthCredentialForm({
</AlertDialogContent>
</AlertDialog>
)}
<Button
type="submit"
disabled={isSubmitting || (!isNew && !isDirty)}
>
{isSubmitting && (
<IconSpinner className="mr-2 h-4 w-4 animate-spin" />
<LicenseGuard licenses={[LicenseType.Enterprise]}>
{({ hasValidLicense }) => (
<Button
type="submit"
disabled={
!hasValidLicense || isSubmitting || (!isNew && !isDirty)
}
>
{isSubmitting && (
<IconSpinner className="mr-2 h-4 w-4 animate-spin" />
)}
{isNew ? 'Create' : 'Update'}
</Button>
)}
{isNew ? 'Create' : 'Update'}
</Button>
</LicenseGuard>
</div>
</form>
<FormMessage className="text-center" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { compact, find } from 'lodash-es'
import { useQuery } from 'urql'

import { graphql } from '@/lib/gql/generates'
import {
LicenseType,
OAuthCredentialQuery,
OAuthProvider
} from '@/lib/gql/generates/graphql'
import { buttonVariants } from '@/components/ui/button'
import { Button, buttonVariants } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Skeleton } from '@/components/ui/skeleton'
import { LicenseGuard } from '@/components/license-guard'

import { PROVIDER_METAS } from './constant'
import { SSOHeader } from './sso-header'
Expand Down Expand Up @@ -43,6 +46,20 @@ const OAuthCredentialList = () => {
return compact([githubData?.oauthCredential, googleData?.oauthCredential])
}, [githubData, googleData])

const router = useRouter()
const createButton = (
<LicenseGuard licenses={[LicenseType.Enterprise]}>
{({ hasValidLicense }) => (
<Button
disabled={!hasValidLicense}
onClick={() => router.push('/settings/sso/new')}
>
Create
</Button>
)}
</LicenseGuard>
)

if (!credentialList?.length) {
return (
<div>
Expand Down Expand Up @@ -80,14 +97,7 @@ const OAuthCredentialList = () => {
})}
</div>
{credentialList.length < 2 && (
<div className="mt-4 flex justify-end">
<Link
href="/settings/sso/new"
className={buttonVariants({ variant: 'default' })}
>
Create
</Link>
</div>
<div className="mt-4 flex justify-end">{createButton}</div>
)}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react'
import { toast } from 'sonner'

import { graphql } from '@/lib/gql/generates/gql'
import { LicenseType } from '@/lib/gql/generates/graphql'
import { useMutation } from '@/lib/tabby/gql'
import {
AlertDialog,
Expand All @@ -17,6 +18,7 @@ import {
} from '@/components/ui/alert-dialog'
import { buttonVariants } from '@/components/ui/button'
import { IconSpinner } from '@/components/ui/icons'
import { LicenseGuard } from '@/components/license-guard'

const updateUserRoleMutation = graphql(/* GraphQL */ `
mutation updateUserRole($id: ID!, $isAdmin: Boolean!) {
Expand Down Expand Up @@ -81,16 +83,20 @@ export const UpdateUserRoleDialog: React.FC<UpdateUserRoleDialogProps> = ({
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
className={buttonVariants()}
onClick={onSubmit}
disabled={isSubmitting}
>
{isSubmitting && (
<IconSpinner className="mr-2 h-4 w-4 animate-spin" />
<LicenseGuard licenses={[LicenseType.Team, LicenseType.Enterprise]}>
{({ hasValidLicense }) => (
<AlertDialogAction
className={buttonVariants()}
onClick={onSubmit}
disabled={!hasValidLicense || isSubmitting}
>
{isSubmitting && (
<IconSpinner className="mr-2 h-4 w-4 animate-spin" />
)}
Confirm
</AlertDialogAction>
)}
Confirm
</AlertDialogAction>
</LicenseGuard>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
Expand Down
14 changes: 8 additions & 6 deletions ee/tabby-ui/components/license-guard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,31 @@ const LicenseGuard: React.FC<LicenseGuardProps> = ({ licenses, children }) => {

let licenseString = capitalize(licenses[0])
let licenseText = licenseString
if (licenses.length > 1) {
licenseText = `${licenseString} or higher`
if (licenses.length == 2) {
licenseText = `${capitalize(licenses[0])} or ${capitalize(licenses[1])}`
}

return (
<HoverCard open={open} onOpenChange={onOpenChange} openDelay={100}>
<HoverCardContent side="top" collisionPadding={16} className="w-[400px]">
<div>
This feature is only available on Tabbys{' '}
This feature is only available on Tabby&apos;s{' '}
<span className="font-semibold">{licenseText}</span> plan. Upgrade to
use this feature.
</div>
<div className="mt-4 text-center">
<Link className={buttonVariants()} href="/settings/subscription">
Upgrade to {licenseText}
Upgrade to {licenseString}
</Link>
</div>
</HoverCardContent>
<HoverCardTrigger
asChild
onClick={e => {
e.preventDefault()
onOpenChange(true)
if (!hasValidLicense) {
e.preventDefault()
onOpenChange(true)
}
}}
>
<div className={cn(!hasValidLicense ? 'cursor-not-allowed' : '')}>
Expand Down
4 changes: 2 additions & 2 deletions ee/tabby-webserver/src/schema/license.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ impl LicenseInfo {
let seats = self.seats as usize;
self.seats = match self.r#type {
LicenseType::Community => {
std::cmp::max(seats, Self::seat_limits_for_community_license())
std::cmp::min(seats, Self::seat_limits_for_community_license())
}
LicenseType::Team => std::cmp::max(seats, Self::seat_limits_for_team_license()),
LicenseType::Team => std::cmp::min(seats, Self::seat_limits_for_team_license()),
LicenseType::Enterprise => seats,
} as i32;

Expand Down

0 comments on commit a84e441

Please sign in to comment.