mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-16 07:28:06 +02:00
add admin/license i18n
This commit is contained in:
parent
4dd9f4736d
commit
1e72b0f854
4 changed files with 124 additions and 98 deletions
|
@ -297,5 +297,58 @@
|
||||||
"userDeleteServer": "Delete User from Server",
|
"userDeleteServer": "Delete User from Server",
|
||||||
"userMessageRemove": "The user will be removed from all organizations and be completely removed from the server.",
|
"userMessageRemove": "The user will be removed from all organizations and be completely removed from the server.",
|
||||||
"userMessageConfirm": "To confirm, please type the name of the user below.",
|
"userMessageConfirm": "To confirm, please type the name of the user below.",
|
||||||
"userQuestionRemove": "Are you sure you want to permanently delete {selectedUser} from the server?"
|
"userQuestionRemove": "Are you sure you want to permanently delete {selectedUser} from the server?",
|
||||||
|
"licenseKey": "License Key",
|
||||||
|
"valid": "Valid",
|
||||||
|
"numberOfSites": "Number of Sites",
|
||||||
|
"licenseKeySearch": "Search license keys...",
|
||||||
|
"licenseKeyAdd": "Add License Key",
|
||||||
|
"type": "Type",
|
||||||
|
"licenseKeyRequired": "License key is required",
|
||||||
|
"licenseTermsAgree": "You must agree to the license terms",
|
||||||
|
"licenseErrorKeyLoad": "Failed to load license keys",
|
||||||
|
"licenseErrorKeyLoadDescription": "An error occurred loading license keys.",
|
||||||
|
"licenseErrorKeyDelete": "Failed to delete license key",
|
||||||
|
"licenseErrorKeyDeleteDescription": "An error occurred deleting license key.",
|
||||||
|
"licenseKeyDeleted": "License key deleted",
|
||||||
|
"licenseKeyDeletedDescription": "The license key has been deleted.",
|
||||||
|
"licenseErrorKeyActivate": "Failed to activate license key",
|
||||||
|
"licenseErrorKeyActivateDescription": "An error occurred while activating the license key.",
|
||||||
|
"licenseKeyActivated": "License key activated",
|
||||||
|
"licenseKeyActivatedDescription": "The license key has been successfully activated.",
|
||||||
|
"licenseErrorKeyRecheck": "Failed to recheck license keys",
|
||||||
|
"licenseErrorKeyRecheckDescription": "An error occurred rechecking license keys.",
|
||||||
|
"licenseErrorKeyRechecked": "License keys rechecked",
|
||||||
|
"licenseErrorKeyRecheckedDescription": "All license keys have been rechecked",
|
||||||
|
"licenseActivateKey": "Activate License Key",
|
||||||
|
"licenseActivateKeyDescription": "Enter a license key to activate it.",
|
||||||
|
"licenseActivate": "Activate License",
|
||||||
|
"licenseAgreement": "By checking this box, you confirm that you have read and agree to the license terms corresponding to the tier associated with your license key.",
|
||||||
|
"fossorialLicense": "View Fossorial Commercial License & Subscription Terms",
|
||||||
|
"licenseMessageRemove": "This will remove the license key and all associated permissions granted by it.",
|
||||||
|
"licenseMessageConfirm": "To confirm, please type the license key below.",
|
||||||
|
"licenseQuestionRemove": "Are you sure you want to delete the license key {selectedKey} ?",
|
||||||
|
"licenseKeyDelete": "Delete License Key",
|
||||||
|
"licenseKeyDeleteConfirm": "Confirm Delete License Key",
|
||||||
|
"licenseTitle": "Manage License Status",
|
||||||
|
"licenseTitleDescription": "View and manage license keys in the system",
|
||||||
|
"licenseHost": "Host License",
|
||||||
|
"licenseHostDescription": "Manage the main license key for the host.",
|
||||||
|
"notLicensed": "Not Licensed",
|
||||||
|
"hostId": "Host ID",
|
||||||
|
"licenseReckeckAll": "Recheck All Keys",
|
||||||
|
"licenseSiteUsage": "Sites Usage",
|
||||||
|
"licenseSiteUsageDecsription": "View the number of sites using this license.",
|
||||||
|
"licenseNoSiteLimit": "There is no limit on the number of sites using an unlicensed host.",
|
||||||
|
"licensePurchase": "Purchase License",
|
||||||
|
"licensePurchaseSites": "Purchase Additional Sites",
|
||||||
|
"licenseSitesUsedMax": "{usedSites} of {maxSites} sites used",
|
||||||
|
"licenseSitesUsed": "{count, plural, =0 {# sites} =1 {# site} other {# sites}} in system.",
|
||||||
|
"licensePurchaseDescription": "Choose how many sites you want to {selectedMode, select, license {purchase a license for. You can always add more sites later.} other {add to your existing license.}}",
|
||||||
|
"licenseFee": "License fee",
|
||||||
|
"licensePriceSite": "Price per site",
|
||||||
|
"total": "Total",
|
||||||
|
"licenseContinuePayment": "Continue to Payment",
|
||||||
|
"pricingPage": "pricing page",
|
||||||
|
"licensePricingPage": "For the most up-to-date pricing and discounts, please visit the "
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { LicenseKeyCache } from "@server/license/license";
|
||||||
import { ArrowUpDown } from "lucide-react";
|
import { ArrowUpDown } from "lucide-react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import CopyToClipboard from "@app/components/CopyToClipboard";
|
import CopyToClipboard from "@app/components/CopyToClipboard";
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
type LicenseKeysDataTableProps = {
|
type LicenseKeysDataTableProps = {
|
||||||
licenseKeys: LicenseKeyCache[];
|
licenseKeys: LicenseKeyCache[];
|
||||||
|
@ -32,6 +33,9 @@ export function LicenseKeysDataTable({
|
||||||
onDelete,
|
onDelete,
|
||||||
onCreate
|
onCreate
|
||||||
}: LicenseKeysDataTableProps) {
|
}: LicenseKeysDataTableProps) {
|
||||||
|
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
const columns: ColumnDef<LicenseKeyCache>[] = [
|
const columns: ColumnDef<LicenseKeyCache>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "licenseKey",
|
accessorKey: "licenseKey",
|
||||||
|
@ -43,7 +47,7 @@ export function LicenseKeysDataTable({
|
||||||
column.toggleSorting(column.getIsSorted() === "asc")
|
column.toggleSorting(column.getIsSorted() === "asc")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
License Key
|
{t('licenseKey')}
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -68,7 +72,7 @@ export function LicenseKeysDataTable({
|
||||||
column.toggleSorting(column.getIsSorted() === "asc")
|
column.toggleSorting(column.getIsSorted() === "asc")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Valid
|
{t('valid')}
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -87,7 +91,7 @@ export function LicenseKeysDataTable({
|
||||||
column.toggleSorting(column.getIsSorted() === "asc")
|
column.toggleSorting(column.getIsSorted() === "asc")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Type
|
{t('type')}
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -112,7 +116,7 @@ export function LicenseKeysDataTable({
|
||||||
column.toggleSorting(column.getIsSorted() === "asc")
|
column.toggleSorting(column.getIsSorted() === "asc")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Number of Sites
|
{t('numberOfSites')}
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -126,7 +130,7 @@ export function LicenseKeysDataTable({
|
||||||
variant="outlinePrimary"
|
variant="outlinePrimary"
|
||||||
onClick={() => onDelete(row.original)}
|
onClick={() => onDelete(row.original)}
|
||||||
>
|
>
|
||||||
Delete
|
{t('delete')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -138,10 +142,10 @@ export function LicenseKeysDataTable({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={licenseKeys}
|
data={licenseKeys}
|
||||||
title="License Keys"
|
title="License Keys"
|
||||||
searchPlaceholder="Search license keys..."
|
searchPlaceholder={t('licenseKeySearch')}
|
||||||
searchColumn="licenseKey"
|
searchColumn="licenseKey"
|
||||||
onAdd={onCreate}
|
onAdd={onCreate}
|
||||||
addButtonText="Add License Key"
|
addButtonText={t('licenseKeyAdd')}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
CredenzaHeader,
|
CredenzaHeader,
|
||||||
CredenzaTitle
|
CredenzaTitle
|
||||||
} from "@app/components/Credenza";
|
} from "@app/components/Credenza";
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
type SitePriceCalculatorProps = {
|
type SitePriceCalculatorProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
@ -60,27 +61,26 @@ export function SitePriceCalculator({
|
||||||
? licenseFlatRate + siteCount * pricePerSite
|
? licenseFlatRate + siteCount * pricePerSite
|
||||||
: siteCount * pricePerSite;
|
: siteCount * pricePerSite;
|
||||||
|
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Credenza open={isOpen} onOpenChange={onOpenChange}>
|
<Credenza open={isOpen} onOpenChange={onOpenChange}>
|
||||||
<CredenzaContent>
|
<CredenzaContent>
|
||||||
<CredenzaHeader>
|
<CredenzaHeader>
|
||||||
<CredenzaTitle>
|
<CredenzaTitle>
|
||||||
{mode === "license"
|
{mode === "license"
|
||||||
? "Purchase License"
|
? t('licensePurchase')
|
||||||
: "Purchase Additional Sites"}
|
: t('licensePurchaseSites')}
|
||||||
</CredenzaTitle>
|
</CredenzaTitle>
|
||||||
<CredenzaDescription>
|
<CredenzaDescription>
|
||||||
Choose how many sites you want to{" "}
|
{t('licensePurchaseDescription', {selectedMode: mode})}
|
||||||
{mode === "license"
|
|
||||||
? "purchase a license for. You can always add more sites later."
|
|
||||||
: "add to your existing license."}
|
|
||||||
</CredenzaDescription>
|
</CredenzaDescription>
|
||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
<CredenzaBody>
|
<CredenzaBody>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex flex-col items-center space-y-4">
|
<div className="flex flex-col items-center space-y-4">
|
||||||
<div className="text-sm font-medium text-muted-foreground">
|
<div className="text-sm font-medium text-muted-foreground">
|
||||||
Number of Sites
|
{t('numberOfSites')}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<Button
|
<Button
|
||||||
|
@ -110,7 +110,7 @@ export function SitePriceCalculator({
|
||||||
{mode === "license" && (
|
{mode === "license" && (
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-sm font-medium">
|
<span className="text-sm font-medium">
|
||||||
License fee:
|
{t('licenseFee')}:
|
||||||
</span>
|
</span>
|
||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
${licenseFlatRate.toFixed(2)}
|
${licenseFlatRate.toFixed(2)}
|
||||||
|
@ -119,7 +119,7 @@ export function SitePriceCalculator({
|
||||||
)}
|
)}
|
||||||
<div className="flex justify-between items-center mt-2">
|
<div className="flex justify-between items-center mt-2">
|
||||||
<span className="text-sm font-medium">
|
<span className="text-sm font-medium">
|
||||||
Price per site:
|
{t('licensePriceSite')}:
|
||||||
</span>
|
</span>
|
||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
${pricePerSite.toFixed(2)}
|
${pricePerSite.toFixed(2)}
|
||||||
|
@ -127,25 +127,24 @@ export function SitePriceCalculator({
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center mt-2">
|
<div className="flex justify-between items-center mt-2">
|
||||||
<span className="text-sm font-medium">
|
<span className="text-sm font-medium">
|
||||||
Number of sites:
|
{t('numberOfSites')}:
|
||||||
</span>
|
</span>
|
||||||
<span className="font-medium">{siteCount}</span>
|
<span className="font-medium">{siteCount}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center mt-4 text-lg font-bold">
|
<div className="flex justify-between items-center mt-4 text-lg font-bold">
|
||||||
<span>Total:</span>
|
<span>{t('total')}:</span>
|
||||||
<span>${totalCost.toFixed(2)} / mo</span>
|
<span>${totalCost.toFixed(2)} / mo</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-muted-foreground text-sm mt-2 text-center">
|
<p className="text-muted-foreground text-sm mt-2 text-center">
|
||||||
For the most up-to-date pricing and discounts,
|
{t('licensePricingPage')}
|
||||||
please visit the{" "}
|
|
||||||
<a
|
<a
|
||||||
href="https://docs.fossorial.io/pricing"
|
href="https://docs.fossorial.io/pricing"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="underline"
|
className="underline"
|
||||||
>
|
>
|
||||||
pricing page
|
{t('pricingPage')}
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
@ -154,10 +153,10 @@ export function SitePriceCalculator({
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<CredenzaClose asChild>
|
<CredenzaClose asChild>
|
||||||
<Button variant="outline">Cancel</Button>
|
<Button variant="outline">{t('cancel')}</Button>
|
||||||
</CredenzaClose>
|
</CredenzaClose>
|
||||||
<Button onClick={continueToPayment}>
|
<Button onClick={continueToPayment}>
|
||||||
Continue to Payment
|
{t('licenseContinuePayment')}
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaFooter>
|
</CredenzaFooter>
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
|
|
|
@ -57,6 +57,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||||
import { SitePriceCalculator } from "./components/SitePriceCalculator";
|
import { SitePriceCalculator } from "./components/SitePriceCalculator";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Checkbox } from "@app/components/ui/checkbox";
|
import { Checkbox } from "@app/components/ui/checkbox";
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
licenseKey: z
|
licenseKey: z
|
||||||
|
@ -77,6 +78,7 @@ function obfuscateLicenseKey(key: string): string {
|
||||||
|
|
||||||
export default function LicensePage() {
|
export default function LicensePage() {
|
||||||
const api = createApiClient(useEnvContext());
|
const api = createApiClient(useEnvContext());
|
||||||
|
const t = useTranslations();
|
||||||
const [rows, setRows] = useState<LicenseKeyCache[]>([]);
|
const [rows, setRows] = useState<LicenseKeyCache[]>([]);
|
||||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||||
|
@ -129,11 +131,8 @@ export default function LicensePage() {
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast({
|
toast({
|
||||||
title: "Failed to load license keys",
|
title: t('licenseErrorKeyLoad'),
|
||||||
description: formatAxiosError(
|
description: formatAxiosError(e, t('licenseErrorKeyLoadDescription'))
|
||||||
e,
|
|
||||||
"An error occurred loading license keys"
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,17 +147,14 @@ export default function LicensePage() {
|
||||||
}
|
}
|
||||||
await loadLicenseKeys();
|
await loadLicenseKeys();
|
||||||
toast({
|
toast({
|
||||||
title: "License key deleted",
|
title: t('licenseKeyDeleted'),
|
||||||
description: "The license key has been deleted"
|
description: t('licenseKeyDeletedDescription')
|
||||||
});
|
});
|
||||||
setIsDeleteModalOpen(false);
|
setIsDeleteModalOpen(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast({
|
toast({
|
||||||
title: "Failed to delete license key",
|
title: t('licenseErrorKeyDelete'),
|
||||||
description: formatAxiosError(
|
description: formatAxiosError(e, t('licenseErrorKeyDeleteDescription'))
|
||||||
e,
|
|
||||||
"An error occurred deleting license key"
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsDeletingLicense(false);
|
setIsDeletingLicense(false);
|
||||||
|
@ -174,16 +170,13 @@ export default function LicensePage() {
|
||||||
}
|
}
|
||||||
await loadLicenseKeys();
|
await loadLicenseKeys();
|
||||||
toast({
|
toast({
|
||||||
title: "License keys rechecked",
|
title: t('licenseErrorKeyRechecked'),
|
||||||
description: "All license keys have been rechecked"
|
description: t('licenseErrorKeyRecheckedDescription')
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast({
|
toast({
|
||||||
title: "Failed to recheck license keys",
|
title: t('licenseErrorKeyRecheck'),
|
||||||
description: formatAxiosError(
|
description: formatAxiosError(e, t('licenseErrorKeyRecheckDescription'))
|
||||||
e,
|
|
||||||
"An error occurred rechecking license keys"
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsRecheckingLicense(false);
|
setIsRecheckingLicense(false);
|
||||||
|
@ -201,8 +194,8 @@ export default function LicensePage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "License key activated",
|
title: t('licenseKeyActivated'),
|
||||||
description: "The license key has been successfully activated."
|
description: t('licenseKeyActivatedDescription')
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
|
@ -211,11 +204,8 @@ export default function LicensePage() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Failed to activate license key",
|
title: t('licenseErrorKeyActivate'),
|
||||||
description: formatAxiosError(
|
description: formatAxiosError(e, t('licenseErrorKeyActivateDescription'))
|
||||||
e,
|
|
||||||
"An error occurred while activating the license key."
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsActivatingLicense(false);
|
setIsActivatingLicense(false);
|
||||||
|
@ -245,9 +235,9 @@ export default function LicensePage() {
|
||||||
>
|
>
|
||||||
<CredenzaContent>
|
<CredenzaContent>
|
||||||
<CredenzaHeader>
|
<CredenzaHeader>
|
||||||
<CredenzaTitle>Activate License Key</CredenzaTitle>
|
<CredenzaTitle>{t('licenseActivateKey')}</CredenzaTitle>
|
||||||
<CredenzaDescription>
|
<CredenzaDescription>
|
||||||
Enter a license key to activate it.
|
{t('licenseActivateKeyDescription')}
|
||||||
</CredenzaDescription>
|
</CredenzaDescription>
|
||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
<CredenzaBody>
|
<CredenzaBody>
|
||||||
|
@ -262,7 +252,7 @@ export default function LicensePage() {
|
||||||
name="licenseKey"
|
name="licenseKey"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>License Key</FormLabel>
|
<FormLabel>{t('licenseKey')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} />
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
@ -285,12 +275,7 @@ export default function LicensePage() {
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<div className="space-y-1 leading-none">
|
<div className="space-y-1 leading-none">
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
By checking this box, you
|
{t('licenseAgreement')}
|
||||||
confirm that you have read
|
|
||||||
and agree to the license
|
|
||||||
terms corresponding to the
|
|
||||||
tier associated with your
|
|
||||||
license key.
|
|
||||||
<br />
|
<br />
|
||||||
<Link
|
<Link
|
||||||
href="https://fossorial.io/license.html"
|
href="https://fossorial.io/license.html"
|
||||||
|
@ -298,9 +283,7 @@ export default function LicensePage() {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
View Fossorial
|
{t('fossorialLicense')}
|
||||||
Commercial License &
|
|
||||||
Subscription Terms
|
|
||||||
</Link>
|
</Link>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
@ -313,7 +296,7 @@ export default function LicensePage() {
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<CredenzaClose asChild>
|
<CredenzaClose asChild>
|
||||||
<Button variant="outline">Close</Button>
|
<Button variant="outline">{t('close')}</Button>
|
||||||
</CredenzaClose>
|
</CredenzaClose>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@ -321,7 +304,7 @@ export default function LicensePage() {
|
||||||
loading={isActivatingLicense}
|
loading={isActivatingLicense}
|
||||||
disabled={isActivatingLicense}
|
disabled={isActivatingLicense}
|
||||||
>
|
>
|
||||||
Activate License
|
{t('licenseActivate')}
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaFooter>
|
</CredenzaFooter>
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
|
@ -336,47 +319,40 @@ export default function LicensePage() {
|
||||||
}}
|
}}
|
||||||
dialog={
|
dialog={
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p>
|
<p>
|
||||||
Are you sure you want to delete the license key{" "}
|
{t('licenseQuestionRemove', {selectedKey: obfuscateLicenseKey(selectedLicenseKey.licenseKey)})}
|
||||||
<b>
|
|
||||||
{obfuscateLicenseKey(
|
|
||||||
selectedLicenseKey.licenseKey
|
|
||||||
)}
|
|
||||||
</b>
|
|
||||||
?
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
This will remove the license key and all
|
{t('licenseMessageRemove')}
|
||||||
associated permissions granted by it.
|
|
||||||
</b>
|
</b>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
To confirm, please type the license key below.
|
{t('licenseMessageConfirm')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
buttonText="Confirm Delete License Key"
|
buttonText={t('licenseKeyDeleteConfirm')}
|
||||||
onConfirm={async () =>
|
onConfirm={async () =>
|
||||||
deleteLicenseKey(selectedLicenseKey.licenseKeyEncrypted)
|
deleteLicenseKey(selectedLicenseKey.licenseKeyEncrypted)
|
||||||
}
|
}
|
||||||
string={selectedLicenseKey.licenseKey}
|
string={selectedLicenseKey.licenseKey}
|
||||||
title="Delete License Key"
|
title={t('licenseKeyDelete')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<SettingsSectionTitle
|
<SettingsSectionTitle
|
||||||
title="Manage License Status"
|
title={t('licenseTitle')}
|
||||||
description="View and manage license keys in the system"
|
description={t('licenseTitleDescription')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingsContainer>
|
<SettingsContainer>
|
||||||
<SettingsSectionGrid cols={2}>
|
<SettingsSectionGrid cols={2}>
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<SettingsSectionHeader>
|
<SettingsSectionHeader>
|
||||||
<SSTitle>Host License</SSTitle>
|
<SSTitle>{t('licenseHost')}</SSTitle>
|
||||||
<SettingsSectionDescription>
|
<SettingsSectionDescription>
|
||||||
Manage the main license key for the host.
|
{t('licenseHostDescription')}
|
||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
@ -397,7 +373,7 @@ export default function LicensePage() {
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-2xl">
|
<div className="text-2xl">
|
||||||
Not Licensed
|
{t('notLicensed')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -405,7 +381,7 @@ export default function LicensePage() {
|
||||||
{licenseStatus?.hostId && (
|
{licenseStatus?.hostId && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-sm font-medium">
|
<div className="text-sm font-medium">
|
||||||
Host ID
|
{t('hostId')}
|
||||||
</div>
|
</div>
|
||||||
<CopyTextBox text={licenseStatus.hostId} />
|
<CopyTextBox text={licenseStatus.hostId} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -413,7 +389,7 @@ export default function LicensePage() {
|
||||||
{hostLicense && (
|
{hostLicense && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-sm font-medium">
|
<div className="text-sm font-medium">
|
||||||
License Key
|
{t('licenseKey')}
|
||||||
</div>
|
</div>
|
||||||
<CopyTextBox
|
<CopyTextBox
|
||||||
text={hostLicense}
|
text={hostLicense}
|
||||||
|
@ -431,39 +407,33 @@ export default function LicensePage() {
|
||||||
disabled={isRecheckingLicense}
|
disabled={isRecheckingLicense}
|
||||||
loading={isRecheckingLicense}
|
loading={isRecheckingLicense}
|
||||||
>
|
>
|
||||||
Recheck All Keys
|
{t('licenseReckeckAll')}
|
||||||
</Button>
|
</Button>
|
||||||
</SettingsSectionFooter>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<SettingsSectionHeader>
|
<SettingsSectionHeader>
|
||||||
<SSTitle>Sites Usage</SSTitle>
|
<SSTitle>{t('licenseSiteUsage')}</SSTitle>
|
||||||
<SettingsSectionDescription>
|
<SettingsSectionDescription>
|
||||||
View the number of sites using this license.
|
{t('licenseSiteUsageDecsription')}
|
||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-2xl">
|
<div className="text-2xl">
|
||||||
{licenseStatus?.usedSites || 0}{" "}
|
{t('licenseSitesUsed', {count: licenseStatus?.usedSites || 0})}
|
||||||
{licenseStatus?.usedSites === 1
|
|
||||||
? "site"
|
|
||||||
: "sites"}{" "}
|
|
||||||
in system
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!licenseStatus?.isHostLicensed && (
|
{!licenseStatus?.isHostLicensed && (
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
There is no limit on the number of sites
|
{t('licenseNoSiteLimit')}
|
||||||
using an unlicensed host.
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{licenseStatus?.maxSites && (
|
{licenseStatus?.maxSites && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
{licenseStatus.usedSites || 0} of{" "}
|
{t('licenseSitesUsedMax', {usedSites: licenseStatus.usedSites || 0, maxSites: licenseStatus.maxSites})}
|
||||||
{licenseStatus.maxSites} sites used
|
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
{Math.round(
|
{Math.round(
|
||||||
|
@ -495,7 +465,7 @@ export default function LicensePage() {
|
||||||
setIsPurchaseModalOpen(true);
|
setIsPurchaseModalOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Purchase License
|
{t('licensePurchase')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
@ -507,7 +477,7 @@ export default function LicensePage() {
|
||||||
setIsPurchaseModalOpen(true);
|
setIsPurchaseModalOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Purchase Additional Sites
|
{t('licensePurchaseSites')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue