add tooltip

This commit is contained in:
Owen
2025-12-20 15:42:10 -05:00
committed by Owen Schwartz
parent d82535d3e1
commit 662e63317b
2 changed files with 104 additions and 66 deletions

View File

@@ -2386,5 +2386,7 @@
"maintenanceTime": "e.g., 2 hours, Nov 1 at 5:00 PM", "maintenanceTime": "e.g., 2 hours, Nov 1 at 5:00 PM",
"maintenanceEstimatedTimeDescription": "When you expect maintenance to be completed", "maintenanceEstimatedTimeDescription": "When you expect maintenance to be completed",
"editDomain": "Edit Domain", "editDomain": "Edit Domain",
"editDomainDescription": "Select a domain for your resource" "editDomainDescription": "Select a domain for your resource",
"maintenanceModeDisabledTooltip": "This feature requires a valid license to enable."
} }

View File

@@ -51,7 +51,7 @@ import {
CredenzaTitle CredenzaTitle
} from "@app/components/Credenza"; } from "@app/components/Credenza";
import DomainPicker from "@app/components/DomainPicker"; import DomainPicker from "@app/components/DomainPicker";
import { AlertCircle, Globe } from "lucide-react"; import { AlertCircle, Globe, Info } from "lucide-react";
import { build } from "@server/build"; import { build } from "@server/build";
import { finalizeSubdomainSanitize } from "@app/lib/subdomain-utils"; import { finalizeSubdomainSanitize } from "@app/lib/subdomain-utils";
import { DomainRow } from "../../../../../../components/DomainsTable"; import { DomainRow } from "../../../../../../components/DomainsTable";
@@ -61,6 +61,7 @@ import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusCo
import { useUserContext } from "@app/hooks/useUserContext"; import { useUserContext } from "@app/hooks/useUserContext";
import { Alert, AlertDescription } from "@app/components/ui/alert"; import { Alert, AlertDescription } from "@app/components/ui/alert";
import { RadioGroup, RadioGroupItem } from "@app/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@app/components/ui/radio-group";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@app/components/ui/tooltip";
export default function GeneralForm() { export default function GeneralForm() {
const [formKey, setFormKey] = useState(0); const [formKey, setFormKey] = useState(0);
@@ -70,8 +71,9 @@ export default function GeneralForm() {
const router = useRouter(); const router = useRouter();
const t = useTranslations(); const t = useTranslations();
const [editDomainOpen, setEditDomainOpen] = useState(false); const [editDomainOpen, setEditDomainOpen] = useState(false);
const { licenseStatus } = useLicenseStatusContext();
const subscriptionStatus = useSubscriptionStatusContext(); const subscriptionStatus = useSubscriptionStatusContext();
const { licenseStatus, isUnlocked } = useLicenseStatusContext();
const subscription = useSubscriptionStatusContext();
const { user } = useUserContext(); const { user } = useUserContext();
const { env } = useEnvContext(); const { env } = useEnvContext();
@@ -99,6 +101,14 @@ export default function GeneralForm() {
baseDomain: string; baseDomain: string;
} | null>(null); } | null>(null);
// Check if security features are disabled due to licensing/subscription
const isSecurityFeatureDisabled = () => {
const isEnterpriseNotLicensed = build === "enterprise" && !isUnlocked();
const isSaasNotSubscribed =
build === "saas" && !subscription?.isSubscribed();
return isEnterpriseNotLicensed || isSaasNotSubscribed;
};
const GeneralFormSchema = z const GeneralFormSchema = z
.object({ .object({
enabled: z.boolean(), enabled: z.boolean(),
@@ -360,19 +370,19 @@ export default function GeneralForm() {
{!resource.http && ( {!resource.http && (
<> <>
<FormField <FormField
control={form.control} control={form.control}
name="proxyPort" name="proxyPort"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t( {t(
"resourcePortNumber" "resourcePortNumber"
)} )}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
type="number" type="number"
value={ value={
field.value ?? field.value ??
"" ""
@@ -380,7 +390,7 @@ export default function GeneralForm() {
onChange={( onChange={(
e e
) => ) =>
field.onChange( field.onChange(
e e
.target .target
.value .value
@@ -389,20 +399,20 @@ export default function GeneralForm() {
.target .target
.value .value
) )
: undefined : undefined
) )
} }
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
<FormDescription> <FormDescription>
{t( {t(
"resourcePortNumberDescription" "resourcePortNumberDescription"
)} )}
</FormDescription> </FormDescription>
</FormItem> </FormItem>
)} )}
/> />
{/* {build == "oss" && ( {/* {build == "oss" && (
<FormField <FormField
@@ -445,9 +455,9 @@ export default function GeneralForm() {
{resource.http && ( {resource.http && (
<> <>
<div className="space-y-2"> <div className="space-y-2">
<Label> <Label>
{t("resourceDomain")} {t("resourceDomain")}
</Label> </Label>
<div className="border p-2 rounded-md flex items-center justify-between"> <div className="border p-2 rounded-md flex items-center justify-between">
<span className="text-sm text-muted-foreground flex items-center gap-2"> <span className="text-sm text-muted-foreground flex items-center gap-2">
<Globe size="14" /> <Globe size="14" />
@@ -458,15 +468,15 @@ export default function GeneralForm() {
type="button" type="button"
size="sm" size="sm"
onClick={() => onClick={() =>
setEditDomainOpen( setEditDomainOpen(
true true
) )
} }
> >
{t( {t(
"resourceEditDomain" "resourceEditDomain"
)} )}
</Button> </Button>
</div> </div>
</div> </div>
</> </>
@@ -511,29 +521,55 @@ export default function GeneralForm() {
<FormField <FormField
control={form.control} control={form.control}
name="maintenanceModeEnabled" name="maintenanceModeEnabled"
render={({ field }) => ( render={({ field }) => {
<FormItem> const isDisabled =
<div className="flex items-center space-x-2"> isSecurityFeatureDisabled();
<FormControl>
<SwitchInput return (
id="enable-maintenance"
checked={field.value} <FormItem>
label={t("enableMaintenanceMode")} <div className="flex items-center space-x-2">
onCheckedChange={(val) => <FormControl>
form.setValue( <TooltipProvider>
"maintenanceModeEnabled", <Tooltip>
val <TooltipTrigger asChild>
) <div className="flex items-center gap-2">
} <span
/> className={isDisabled ? "pointer-events-auto" : ""}
</FormControl> >
</div> <SwitchInput
<FormDescription> id="enable-maintenance"
{t("showMaintenancePage")} checked={field.value}
</FormDescription> label={t("enableMaintenanceMode")}
<FormMessage /> disabled={isDisabled}
</FormItem> onCheckedChange={(val) => {
)} if (!isDisabled) {
form.setValue("maintenanceModeEnabled", val);
}
}}
/>
</span>
</div>
</TooltipTrigger>
{isDisabled && (
<TooltipContent className="max-w-xs">
<p>{t("maintenanceModeDisabledTooltip")}</p>
</TooltipContent>
)}
</Tooltip>
</TooltipProvider>
</FormControl>
</div>
<FormDescription>
{t("showMaintenancePage")}
</FormDescription>
<FormMessage />
</FormItem>
);
}}
/> />
{isMaintenanceEnabled && ( {isMaintenanceEnabled && (
@@ -601,7 +637,7 @@ export default function GeneralForm() {
<FormItem> <FormItem>
<FormLabel>{t("pageTitle")}</FormLabel> <FormLabel>{t("pageTitle")}</FormLabel>
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
placeholder="We'll be back soon!" placeholder="We'll be back soon!"
/> />
@@ -621,7 +657,7 @@ export default function GeneralForm() {
<FormItem> <FormItem>
<FormLabel>{t("maintenancePageMessage")}</FormLabel> <FormLabel>{t("maintenancePageMessage")}</FormLabel>
<FormControl> <FormControl>
<Textarea <Textarea
{...field} {...field}
rows={4} rows={4}
placeholder={t("maintenancePageMessagePlaceholder")} placeholder={t("maintenancePageMessagePlaceholder")}
@@ -644,7 +680,7 @@ export default function GeneralForm() {
{t("maintenancePageTimeTitle")} {t("maintenancePageTimeTitle")}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
placeholder={t("maintenanceTime")} placeholder={t("maintenanceTime")}
/> />
@@ -666,9 +702,9 @@ export default function GeneralForm() {
<SettingsSectionFooter> <SettingsSectionFooter>
<Button <Button
type="submit" type="submit"
onClick={() => { onClick={() => {
console.log(form.getValues()); console.log(form.getValues());
}} }}
loading={saveLoading} loading={saveLoading}
disabled={saveLoading} disabled={saveLoading}
form="general-settings-form" form="general-settings-form"