mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-13 17:21:48 +02:00
@@ -3,7 +3,9 @@ import { authCookieHeader } from "@app/lib/api/cookies";
|
|||||||
import { ListOrgLabelsResponse } from "@server/routers/labels/types";
|
import { ListOrgLabelsResponse } from "@server/routers/labels/types";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import OrgLabelsTable from "@app/components/OrgLabelsTable";
|
import OrgLabelsTable from "@app/components/OrgLabelsTable";
|
||||||
|
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
||||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||||
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
|
|
||||||
@@ -49,6 +51,8 @@ export default async function LabelsPage({ params, searchParams }: Props) {
|
|||||||
description={t("orgLabelsDescription")}
|
description={t("orgLabelsDescription")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<PaidFeaturesAlert tiers={tierMatrix.labels} />
|
||||||
|
|
||||||
<OrgLabelsTable
|
<OrgLabelsTable
|
||||||
labels={labels}
|
labels={labels}
|
||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ import {
|
|||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
SettingsSectionFooter,
|
SettingsSectionFooter,
|
||||||
SettingsFormCell,
|
|
||||||
SettingsFormGrid,
|
SettingsFormGrid,
|
||||||
SettingsSectionForm,
|
SettingsSectionForm,
|
||||||
SettingsSectionHeader,
|
SettingsSectionHeader,
|
||||||
SettingsSectionTitle,
|
SettingsSectionTitle,
|
||||||
SettingsSubsectionDescription,
|
SettingsSubsectionDescription,
|
||||||
SettingsSubsectionHeader,
|
SettingsSubsectionHeader,
|
||||||
SettingsSubsectionTitle
|
SettingsSubsectionTitle,
|
||||||
|
SettingsFormCell
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { SwitchInput } from "@app/components/SwitchInput";
|
import { SwitchInput } from "@app/components/SwitchInput";
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
@@ -70,7 +70,7 @@ export default function GeneralForm() {
|
|||||||
|
|
||||||
const api = createApiClient({ env });
|
const api = createApiClient({ env });
|
||||||
|
|
||||||
const showResourcePolicy =
|
const hasResourcePolicies =
|
||||||
build !== "oss" &&
|
build !== "oss" &&
|
||||||
isPaidUser(tierMatrix[TierFeature.ResourcePolicies]);
|
isPaidUser(tierMatrix[TierFeature.ResourcePolicies]);
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ export default function GeneralForm() {
|
|||||||
...orgQueries.resourcePolicy({
|
...orgQueries.resourcePolicy({
|
||||||
resourcePolicyId: selectedSharedPolicyId!
|
resourcePolicyId: selectedSharedPolicyId!
|
||||||
}),
|
}),
|
||||||
enabled: showResourcePolicy && selectedSharedPolicyId !== null
|
enabled: hasResourcePolicies && selectedSharedPolicyId !== null
|
||||||
});
|
});
|
||||||
|
|
||||||
const [resourceFullDomain, setResourceFullDomain] = useState(
|
const [resourceFullDomain, setResourceFullDomain] = useState(
|
||||||
@@ -153,11 +153,10 @@ export default function GeneralForm() {
|
|||||||
|
|
||||||
let resourcePolicyId: number | null | undefined;
|
let resourcePolicyId: number | null | undefined;
|
||||||
|
|
||||||
if (
|
if (!["tcp", "udp"].includes(resource.mode)) {
|
||||||
showResourcePolicy &&
|
if (hasResourcePolicies || selectedSharedPolicyId === null) {
|
||||||
!["tcp", "udp"].includes(resource.mode)
|
resourcePolicyId = selectedSharedPolicyId;
|
||||||
) {
|
}
|
||||||
resourcePolicyId = selectedSharedPolicyId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
@@ -297,28 +296,6 @@ export default function GeneralForm() {
|
|||||||
/>
|
/>
|
||||||
</SettingsFormCell>
|
</SettingsFormCell>
|
||||||
|
|
||||||
<SettingsFormCell span="full">
|
|
||||||
<SettingsSubsectionHeader>
|
|
||||||
<SettingsSubsectionTitle>
|
|
||||||
{t(
|
|
||||||
"resourceGeneralDetailsSubsection"
|
|
||||||
)}
|
|
||||||
</SettingsSubsectionTitle>
|
|
||||||
<SettingsSubsectionDescription>
|
|
||||||
{t(
|
|
||||||
[
|
|
||||||
"tcp",
|
|
||||||
"udp",
|
|
||||||
].includes(
|
|
||||||
resource.mode
|
|
||||||
)
|
|
||||||
? "resourceGeneralDetailsSubsectionPortDescription"
|
|
||||||
: "resourceGeneralDetailsSubsectionDescription"
|
|
||||||
)}
|
|
||||||
</SettingsSubsectionDescription>
|
|
||||||
</SettingsSubsectionHeader>
|
|
||||||
</SettingsFormCell>
|
|
||||||
|
|
||||||
<SettingsFormCell span="half">
|
<SettingsFormCell span="half">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
@@ -476,8 +453,7 @@ export default function GeneralForm() {
|
|||||||
</div>
|
</div>
|
||||||
</SettingsFormCell>
|
</SettingsFormCell>
|
||||||
)}
|
)}
|
||||||
{showResourcePolicy &&
|
{ !["tcp", "udp"].includes(
|
||||||
!["tcp", "udp"].includes(
|
|
||||||
resource.mode
|
resource.mode
|
||||||
) && (
|
) && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export const orgNavSections = (
|
|||||||
href: "/{orgId}/settings/api-keys",
|
href: "/{orgId}/settings/api-keys",
|
||||||
icon: <KeyRound className="size-4 flex-none" />
|
icon: <KeyRound className="size-4 flex-none" />
|
||||||
},
|
},
|
||||||
...(build !== "oss"
|
...(!env?.flags.disableEnterpriseFeatures
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: "labels",
|
title: "labels",
|
||||||
|
|||||||
@@ -12,14 +12,7 @@ import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
|||||||
import { toast } from "@app/hooks/useToast";
|
import { toast } from "@app/hooks/useToast";
|
||||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||||
import { type PaginationState } from "@tanstack/react-table";
|
import { type PaginationState } from "@tanstack/react-table";
|
||||||
import {
|
import { ArrowRight, MoreHorizontal } from "lucide-react";
|
||||||
ArrowDown01Icon,
|
|
||||||
ArrowUp10Icon,
|
|
||||||
ChevronsUpDownIcon,
|
|
||||||
MoreHorizontal,
|
|
||||||
PencilIcon,
|
|
||||||
PencilLineIcon
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { usePathname, useRouter } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
import { useActionState, useMemo, useState, useTransition } from "react";
|
import { useActionState, useMemo, useState, useTransition } from "react";
|
||||||
@@ -109,7 +102,7 @@ export default function OrgLabelsTable({
|
|||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className="flex items-center gap-1.5 group">
|
<div className="flex items-center gap-1.5 group">
|
||||||
<div
|
<div
|
||||||
className="size-2.5 rounded-full bg-(--color) flex-none"
|
className="size-2 rounded-full bg-(--color) flex-none"
|
||||||
style={{
|
style={{
|
||||||
// @ts-expect-error css color
|
// @ts-expect-error css color
|
||||||
"--color": row.original.color
|
"--color": row.original.color
|
||||||
@@ -125,34 +118,40 @@ export default function OrgLabelsTable({
|
|||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
header: () => <span className="p-3"></span>,
|
header: () => <span className="p-3"></span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<DropdownMenu>
|
<div className="flex items-center gap-2 justify-end">
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenu>
|
||||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
<DropdownMenuTrigger asChild>
|
||||||
<span className="sr-only">{t("openMenu")}</span>
|
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<span className="sr-only">
|
||||||
</Button>
|
{t("openMenu")}
|
||||||
</DropdownMenuTrigger>
|
</span>
|
||||||
<DropdownMenuContent align="end">
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
<DropdownMenuItem
|
</Button>
|
||||||
onClick={() => {
|
</DropdownMenuTrigger>
|
||||||
setSelectedLabel(row.original);
|
<DropdownMenuContent align="end">
|
||||||
setIsEditModalOpen(true);
|
<DropdownMenuItem
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setSelectedLabel(row.original);
|
||||||
{t("edit")}
|
setIsDeleteModalOpen(true);
|
||||||
</DropdownMenuItem>
|
}}
|
||||||
<DropdownMenuItem
|
>
|
||||||
onClick={() => {
|
<span className="text-red-500">
|
||||||
setSelectedLabel(row.original);
|
{t("delete")}
|
||||||
setIsDeleteModalOpen(true);
|
</span>
|
||||||
}}
|
</DropdownMenuItem>
|
||||||
>
|
</DropdownMenuContent>
|
||||||
<span className="text-red-500">
|
</DropdownMenu>
|
||||||
{t("delete")}
|
<Button
|
||||||
</span>
|
variant="outline"
|
||||||
</DropdownMenuItem>
|
onClick={() => {
|
||||||
</DropdownMenuContent>
|
setSelectedLabel(row.original);
|
||||||
</DropdownMenu>
|
setIsEditModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("edit")}
|
||||||
|
<ArrowRight className="ml-2 w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ export function EditPolicyForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const policyTiers = tierMatrix[TierFeature.ResourcePolicies];
|
const policyTiers = tierMatrix[TierFeature.ResourcePolicies];
|
||||||
const isDisabled = !isPaidUser(policyTiers);
|
const isInlinePolicy = hidePolicyNameForm && resourceId === undefined;
|
||||||
|
const showPaidAlert = !isInlinePolicy;
|
||||||
|
const isDisabled = showPaidAlert && !isPaidUser(policyTiers);
|
||||||
const effectiveReadonly = readonly || isDisabled;
|
const effectiveReadonly = readonly || isDisabled;
|
||||||
|
|
||||||
const authSection = (
|
const authSection = (
|
||||||
@@ -100,7 +102,7 @@ export function EditPolicyForm({
|
|||||||
if (section === "general") {
|
if (section === "general") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PaidFeaturesAlert tiers={policyTiers} />
|
{showPaidAlert && <PaidFeaturesAlert tiers={policyTiers} />}
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDisabled
|
isDisabled
|
||||||
@@ -117,7 +119,7 @@ export function EditPolicyForm({
|
|||||||
if (section === "authentication") {
|
if (section === "authentication") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PaidFeaturesAlert tiers={policyTiers} />
|
{showPaidAlert && <PaidFeaturesAlert tiers={policyTiers} />}
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDisabled
|
isDisabled
|
||||||
@@ -134,7 +136,7 @@ export function EditPolicyForm({
|
|||||||
if (section === "rules") {
|
if (section === "rules") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PaidFeaturesAlert tiers={policyTiers} />
|
{showPaidAlert && <PaidFeaturesAlert tiers={policyTiers} />}
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDisabled
|
isDisabled
|
||||||
@@ -150,7 +152,7 @@ export function EditPolicyForm({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PaidFeaturesAlert tiers={policyTiers} />
|
{showPaidAlert && <PaidFeaturesAlert tiers={policyTiers} />}
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
isDisabled ? "pointer-events-none opacity-50" : undefined
|
isDisabled ? "pointer-events-none opacity-50" : undefined
|
||||||
|
|||||||
Reference in New Issue
Block a user