Skip to content

Commit 7b3f532

Browse files
feat(ui): interface for the experiment flags (TabbyML#1724)
* feat(ui): experimental ai ui interface * fix warning; * [autofix.ci] apply automated fixes * integrate with local storage * [autofix.ci] apply automated fixes * rename * update * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 8dc0548 commit 7b3f532

4 files changed

Lines changed: 95 additions & 10 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use client'
2+
3+
import { useEnableCodeBrowserQuickActionBar } from '@/lib/experiment-flags'
4+
import { Switch } from '@/components/ui/switch'
5+
6+
export default function FeatureList() {
7+
const [quickActionBar, toggleQuickActionBar] =
8+
useEnableCodeBrowserQuickActionBar()
9+
return (
10+
<>
11+
{!quickActionBar.loading && (
12+
<div className="flex items-center space-x-4 rounded-md border p-4">
13+
<div className="flex-1 space-y-1">
14+
<p className="text-sm font-medium leading-none">
15+
{quickActionBar.title}
16+
</p>
17+
<p className="text-sm text-muted-foreground">
18+
{quickActionBar.description}
19+
</p>
20+
</div>
21+
<Switch
22+
checked={quickActionBar.value}
23+
onCheckedChange={toggleQuickActionBar}
24+
/>
25+
</div>
26+
)}
27+
</>
28+
)
29+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Metadata } from 'next'
2+
3+
import FeatureList from './components/feature-list'
4+
5+
export const metadata: Metadata = {
6+
title: 'Experiment Flags'
7+
}
8+
9+
export default function IndexPage() {
10+
return (
11+
<div className="mx-auto flex max-w-xl flex-col gap-3">
12+
<h3 className="scroll-m-20 text-2xl font-semibold tracking-tight">
13+
Experiment Flags
14+
</h3>
15+
<FeatureList />
16+
</div>
17+
)
18+
}

ee/tabby-ui/components/ui/switch.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const Switch = React.forwardRef<
1111
>(({ className, ...props }, ref) => (
1212
<SwitchPrimitives.Root
1313
className={cn(
14-
'peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
14+
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
1515
className
1616
)}
1717
{...props}

ee/tabby-ui/lib/experiment-flags.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
1-
import useLocalStorage from 'use-local-storage'
1+
import { useEffect, useState } from 'react'
2+
3+
const useLocalStorageForExperimentFlag = (
4+
storageKey: string,
5+
defaultValue: boolean
6+
): [boolean, (value: boolean) => void, boolean] => {
7+
const [storageValue, setStorageValue] = useState(defaultValue)
8+
const [loading, setLoading] = useState(true)
9+
10+
useEffect(() => {
11+
const value = localStorage.getItem(storageKey)
12+
if (value) {
13+
setStorageValue(JSON.parse(value))
14+
}
15+
setLoading(false)
16+
}, [])
17+
18+
const upateStorageValue = (newValue: boolean) => {
19+
setStorageValue(newValue)
20+
localStorage.setItem(storageKey, JSON.stringify(newValue))
21+
}
22+
23+
return [storageValue, upateStorageValue, loading]
24+
}
225

326
class ExperimentFlag {
427
constructor(
528
private storageKey: string,
29+
readonly title: string,
630
readonly description: string,
731
readonly defaultValue: boolean
832
) {}
@@ -21,36 +45,49 @@ class ExperimentFlag {
2145

2246
class ExperimentFlagFactory {
2347
private storageKey: string
48+
private title: string
2449
private description: string
2550
private defaultValue: boolean
2651

27-
constructor(storageKey: string, description: string, defaultValue?: boolean) {
52+
constructor(
53+
storageKey: string,
54+
title: string,
55+
description: string,
56+
defaultValue?: boolean
57+
) {
2858
this.storageKey = `EXP_${storageKey}`
59+
this.title = title
2960
this.description = description
3061
this.defaultValue = defaultValue ?? false
3162
}
3263

3364
defineGlobalVar() {
3465
return new ExperimentFlag(
3566
this.storageKey,
67+
this.title,
3668
this.description,
3769
this.defaultValue
3870
)
3971
}
4072

4173
defineHook() {
42-
return (): [{ value: boolean; description: string }, () => void] => {
43-
const [storageValue, setStorageValue] = useLocalStorage(
44-
this.storageKey,
45-
this.defaultValue
46-
)
74+
return (): [
75+
{ value: boolean; title: string; description: string; loading: boolean },
76+
() => void
77+
] => {
78+
const [storageValue, setStorageValue, loading] =
79+
useLocalStorageForExperimentFlag(this.storageKey, this.defaultValue)
80+
4781
const toggleFlag = () => {
4882
setStorageValue(!storageValue)
4983
}
84+
5085
return [
5186
{
5287
value: storageValue,
53-
description: this.description
88+
title: this.title,
89+
description: this.description,
90+
loading
5491
},
5592
toggleFlag
5693
]
@@ -60,7 +97,8 @@ class ExperimentFlagFactory {
6097

6198
const enableCodeBrowserQuickActionBarFactory = new ExperimentFlagFactory(
6299
'enable_code_browser_quick_action_bar',
63-
'Show a quick action popup upon selecting code snippets',
100+
'Quick Action Bar',
101+
'Enable Quick Action Bar to display a convenient toolbar when you select code, offering options to explain the code, add unit tests, and more.',
64102
false
65103
)
66104

0 commit comments

Comments
 (0)