diff --git a/apps/web/.env.example b/apps/web/.env.example index fe475a7aca..34d97bc736 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -136,3 +136,8 @@ LOOPS_API_SECRET= # Sanity config for blog. (Not needed. Only for blog): # NEXT_PUBLIC_SANITY_PROJECT_ID= # NEXT_PUBLIC_SANITY_DATASET="production" + +# Feature flags +# NEXT_PUBLIC_DIGEST_ENABLED=true +# NEXT_PUBLIC_MEETING_BRIEFS_ENABLED=true +# NEXT_PUBLIC_INTEGRATIONS_ENABLED=true \ No newline at end of file diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx index 9cc15d3825..09d1bdcc29 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx @@ -52,6 +52,7 @@ import { getRuleConfig } from "@/utils/rule/consts"; import { RuleSectionCard } from "@/app/(app)/[emailAccountId]/assistant/RuleSectionCard"; import { ConditionSteps } from "@/app/(app)/[emailAccountId]/assistant/ConditionSteps"; import { ActionSteps } from "@/app/(app)/[emailAccountId]/assistant/ActionSteps"; +import { env } from "@/env"; export function Rule({ ruleId, @@ -493,22 +494,24 @@ export function RuleForm({ -
- { - setValue("digest", enabled); - }} - /> + {env.NEXT_PUBLIC_DIGEST_ENABLED && ( +
+ { + setValue("digest", enabled); + }} + /> - -
+ +
+ )} {!!rule.id && (
diff --git a/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx b/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx index 759a3d4efa..dd5e0e1789 100644 --- a/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx +++ b/apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx @@ -7,6 +7,7 @@ import { LearnedPatternsSetting } from "@/app/(app)/[emailAccountId]/assistant/s import { PersonalSignatureSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/PersonalSignatureSetting"; import { MultiRuleSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/MultiRuleSetting"; import { WritingStyleSetting } from "@/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting"; +import { env } from "@/env"; export function SettingsTab() { return ( @@ -16,7 +17,7 @@ export function SettingsTab() { - + {env.NEXT_PUBLIC_DIGEST_ENABLED && } diff --git a/apps/web/components/SideNav.tsx b/apps/web/components/SideNav.tsx index a3ae2749bf..ff7fee8e1b 100644 --- a/apps/web/components/SideNav.tsx +++ b/apps/web/components/SideNav.tsx @@ -15,7 +15,6 @@ import { ChevronDownIcon, ChevronRightIcon, FileIcon, - HomeIcon, FileTextIcon, InboxIcon, type LucideIcon, @@ -29,6 +28,7 @@ import { SparklesIcon, TagIcon, Users2Icon, + ZapIcon, } from "lucide-react"; import { Logo } from "@/components/Logo"; import { useComposeModal } from "@/providers/ComposeModalProvider"; @@ -53,6 +53,7 @@ import { useSplitLabels } from "@/hooks/useLabels"; import { LoadingContent } from "@/components/LoadingContent"; import { useCleanerEnabled, + useIntegrationsEnabled, useMeetingBriefsEnabled, } from "@/hooks/useFeatureFlags"; import { ClientOnly } from "@/components/ClientOnly"; @@ -72,22 +73,19 @@ type NavItem = { target?: "_blank"; count?: number; hideInMail?: boolean; + beta?: boolean; }; export const useNavigation = () => { const showCleaner = useCleanerEnabled(); const showMeetingBriefs = useMeetingBriefsEnabled(); + const showIntegrations = useIntegrationsEnabled(); const { emailAccountId, emailAccount, provider } = useAccount(); const currentEmailAccountId = emailAccount?.id || emailAccountId; const navItems: NavItem[] = useMemo( () => [ - // { - // name: "Dashboard", - // href: prefixPath(currentEmailAccountId, "/setup"), - // icon: HomeIcon, - // }, { name: "Assistant", href: prefixPath(currentEmailAccountId, "/automation"), @@ -117,17 +115,28 @@ export const useNavigation = () => { href: prefixPath(currentEmailAccountId, "/calendars"), icon: CalendarIcon, }, + ...(showIntegrations + ? [ + { + name: "Integrations", + href: prefixPath(currentEmailAccountId, "/integrations"), + icon: ZapIcon, + beta: true, + }, + ] + : []), ...(showMeetingBriefs ? [ { name: "Meeting Briefs", href: prefixPath(currentEmailAccountId, "/briefs"), icon: FileTextIcon, + beta: true, }, ] : []), ], - [currentEmailAccountId, provider, showMeetingBriefs], + [currentEmailAccountId, provider, showMeetingBriefs, showIntegrations], ); const navItemsFiltered = useMemo( diff --git a/apps/web/components/SideNavMenu.tsx b/apps/web/components/SideNavMenu.tsx index 77004e6be8..91fe360d59 100644 --- a/apps/web/components/SideNavMenu.tsx +++ b/apps/web/components/SideNavMenu.tsx @@ -7,6 +7,7 @@ import { SidebarMenuButton, SidebarMenuItem, } from "@/components/ui/sidebar"; +import { Badge } from "@/components/ui/badge"; type NavItem = { name: string; @@ -16,6 +17,7 @@ type NavItem = { count?: number; hideInMail?: boolean; active?: boolean; + beta?: boolean; }; export function SideNavMenu({ @@ -39,6 +41,11 @@ export function SideNavMenu({ {item.name} + {item.beta && ( + + Beta + + )} diff --git a/apps/web/env.ts b/apps/web/env.ts index 1e9017da1d..4655e252a6 100644 --- a/apps/web/env.ts +++ b/apps/web/env.ts @@ -187,6 +187,9 @@ export const env = createEnv({ .default(false), NEXT_PUBLIC_USE_AEONIK_FONT: z.coerce.boolean().optional().default(false), NEXT_PUBLIC_BYPASS_PREMIUM_CHECKS: z.coerce.boolean().optional(), + NEXT_PUBLIC_DIGEST_ENABLED: z.coerce.boolean().optional(), + NEXT_PUBLIC_MEETING_BRIEFS_ENABLED: z.coerce.boolean().optional(), + NEXT_PUBLIC_INTEGRATIONS_ENABLED: z.coerce.boolean().optional(), }, // For Next.js >= 13.4.4, you only need to destructure client variables: experimental__runtimeEnv: { @@ -243,5 +246,10 @@ export const env = createEnv({ NEXT_PUBLIC_USE_AEONIK_FONT: process.env.NEXT_PUBLIC_USE_AEONIK_FONT, NEXT_PUBLIC_BYPASS_PREMIUM_CHECKS: process.env.NEXT_PUBLIC_BYPASS_PREMIUM_CHECKS, + NEXT_PUBLIC_DIGEST_ENABLED: process.env.NEXT_PUBLIC_DIGEST_ENABLED, + NEXT_PUBLIC_MEETING_BRIEFS_ENABLED: + process.env.NEXT_PUBLIC_MEETING_BRIEFS_ENABLED, + NEXT_PUBLIC_INTEGRATIONS_ENABLED: + process.env.NEXT_PUBLIC_INTEGRATIONS_ENABLED, }, }); diff --git a/apps/web/hooks/useFeatureFlags.ts b/apps/web/hooks/useFeatureFlags.ts index 4abc2c9415..0434bbf34f 100644 --- a/apps/web/hooks/useFeatureFlags.ts +++ b/apps/web/hooks/useFeatureFlags.ts @@ -2,13 +2,18 @@ import { useFeatureFlagEnabled, useFeatureFlagVariantKey, } from "posthog-js/react"; +import { env } from "@/env"; export function useCleanerEnabled() { return useFeatureFlagEnabled("inbox-cleaner"); } export function useMeetingBriefsEnabled() { - return useFeatureFlagEnabled("meeting-briefs"); + return env.NEXT_PUBLIC_MEETING_BRIEFS_ENABLED; +} + +export function useIntegrationsEnabled() { + return env.NEXT_PUBLIC_INTEGRATIONS_ENABLED; } const HERO_FLAG_NAME = "hero-copy-7"; diff --git a/apps/web/utils/action-item.ts b/apps/web/utils/action-item.ts index dd0bc06e0c..09205194d4 100644 --- a/apps/web/utils/action-item.ts +++ b/apps/web/utils/action-item.ts @@ -109,15 +109,15 @@ export const actionInputs: Record< }, [ActionType.FORWARD]: { fields: [ + { + name: "to", + label: "To", + }, { name: "content", label: "Extra Content", textArea: true, }, - { - name: "to", - label: "To", - }, { name: "cc", label: "CC", diff --git a/docs/hosting/environment-variables.md b/docs/hosting/environment-variables.md index 40c33aed19..d090f1f12c 100644 --- a/docs/hosting/environment-variables.md +++ b/docs/hosting/environment-variables.md @@ -85,6 +85,9 @@ cp apps/web/.env.example apps/web/.env | `NEXT_PUBLIC_CONTACTS_ENABLED` | No | Enable contacts feature | `false` | | `NEXT_PUBLIC_EMAIL_SEND_ENABLED` | No | Enable email sending | `true` | | `NEXT_PUBLIC_BYPASS_PREMIUM_CHECKS` | No | Bypass premium checks (recommended for self-hosting) | `true` | +| `NEXT_PUBLIC_DIGEST_ENABLED` | No | Enable email digest feature, which sends periodic summaries of emails. Requires QStash to be configured. | `false` | +| `NEXT_PUBLIC_MEETING_BRIEFS_ENABLED` | No | Enable meeting briefs, which automatically sends pre-meeting briefings to users. Requires the meeting briefs cron job to be running. | `false` | +| `NEXT_PUBLIC_INTEGRATIONS_ENABLED` | No | Enable the integrations feature, allowing users to connect external services. | `false` | | **Debugging** |||| | `LOG_ZOD_ERRORS` | No | Log Zod validation errors | — | | `ENABLE_DEBUG_LOGS` | No | Enable debug logging | `false` | diff --git a/turbo.json b/turbo.json index 989333442e..9ecaf4d4a3 100644 --- a/turbo.json +++ b/turbo.json @@ -128,7 +128,11 @@ "NEXT_PUBLIC_AXIOM_DATASET", "NEXT_PUBLIC_AXIOM_TOKEN", "NEXT_PUBLIC_DUB_REFER_DOMAIN", - "NEXT_PUBLIC_USE_AEONIK_FONT" + "NEXT_PUBLIC_USE_AEONIK_FONT", + "NEXT_PUBLIC_BYPASS_PREMIUM_CHECKS", + "NEXT_PUBLIC_DIGEST_ENABLED", + "NEXT_PUBLIC_MEETING_BRIEFS_ENABLED", + "NEXT_PUBLIC_INTEGRATIONS_ENABLED" ], "outputs": [".next/**", "!.next/cache/**"] }, diff --git a/version.txt b/version.txt index e74893adad..aaccdefabd 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v2.23.0 +v2.23.1