Merge branch 'dev' into refactor/domain-picker-default-value

This commit is contained in:
Fred KISSIE
2025-12-17 00:52:32 +01:00
92 changed files with 1714 additions and 575 deletions

View File

@@ -304,7 +304,7 @@ export default function ExitNodesTable({
setSelectedNode(null);
}}
dialog={
<div>
<div className="space-y-2">
<p>{t("remoteExitNodeQuestionRemove")}</p>
<p>{t("remoteExitNodeMessageRemove")}</p>

View File

@@ -289,7 +289,7 @@ export default function GeneralPage() {
setIsDeleteModalOpen(val);
}}
dialog={
<div>
<div className="space-y-2">
<p>{t("orgQuestionRemove")}</p>
<p>{t("orgMessageRemove")}</p>
</div>
@@ -303,7 +303,7 @@ export default function GeneralPage() {
open={isSecurityPolicyConfirmOpen}
setOpen={setIsSecurityPolicyConfirmOpen}
dialog={
<div>
<div className="space-y-2">
<p>{t("securityPolicyChangeDescription")}</p>
</div>
}

View File

@@ -1,16 +1,12 @@
"use client";
import { Button } from "@app/components/ui/button";
import { toast } from "@app/hooks/useToast";
import { useState, useRef, useEffect } from "react";
import { useState, useRef, useEffect, useTransition } from "react";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useTranslations } from "next-intl";
import {
getStoredPageSize,
LogDataTable,
setStoredPageSize
} from "@app/components/LogDataTable";
import { LogDataTable } from "@app/components/LogDataTable";
import { ColumnDef } from "@tanstack/react-table";
import { DateTimeValue } from "@app/components/DateTimePicker";
import { ArrowUpRight, Key, User } from "lucide-react";
@@ -21,21 +17,22 @@ import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusCo
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
import { build } from "@server/build";
import { Alert, AlertDescription } from "@app/components/ui/alert";
import { getSevenDaysAgo } from "@app/lib/getSevenDaysAgo";
import axios from "axios";
import { useStoredPageSize } from "@app/hooks/useStoredPageSize";
export default function GeneralPage() {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const router = useRouter();
const searchParams = useSearchParams();
const api = createApiClient(useEnvContext());
const t = useTranslations();
const { env } = useEnvContext();
const { orgId } = useParams();
const subscription = useSubscriptionStatusContext();
const { isUnlocked } = useLicenseStatusContext();
const [rows, setRows] = useState<any[]>([]);
const [isRefreshing, setIsRefreshing] = useState(false);
const [isExporting, setIsExporting] = useState(false);
const [isExporting, startTransition] = useTransition();
const [filterAttributes, setFilterAttributes] = useState<{
actors: string[];
resources: {
@@ -70,9 +67,7 @@ export default function GeneralPage() {
const [isLoading, setIsLoading] = useState(false);
// Initialize page size from storage or default
const [pageSize, setPageSize] = useState<number>(() => {
return getStoredPageSize("access-audit-logs", 20);
});
const [pageSize, setPageSize] = useStoredPageSize("access-audit-logs", 20);
// Set default date range to last 24 hours
const getDefaultDateRange = () => {
@@ -91,11 +86,11 @@ export default function GeneralPage() {
}
const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const lastWeek = getSevenDaysAgo();
return {
startDate: {
date: yesterday
date: lastWeek
},
endDate: {
date: now
@@ -148,7 +143,6 @@ export default function GeneralPage() {
// Handle page size changes
const handlePageSizeChange = (newPageSize: number) => {
setPageSize(newPageSize);
setStoredPageSize(newPageSize, "access-audit-logs");
setCurrentPage(0); // Reset to first page when changing page size
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
};
@@ -309,8 +303,6 @@ export default function GeneralPage() {
const exportData = async () => {
try {
setIsExporting(true);
// Prepare query params for export
const params: any = {
timeStart: dateRange.startDate?.date
@@ -339,11 +331,21 @@ export default function GeneralPage() {
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
setIsExporting(false);
} catch (error) {
let apiErrorMessage: string | null = null;
if (axios.isAxiosError(error) && error.response) {
const data = error.response.data;
if (data instanceof Blob && data.type === "application/json") {
// Parse the Blob as JSON
const text = await data.text();
const errorData = JSON.parse(text);
apiErrorMessage = errorData.message;
}
}
toast({
title: t("error"),
description: t("exportError"),
description: apiErrorMessage ?? t("exportError"),
variant: "destructive"
});
}
@@ -631,7 +633,7 @@ export default function GeneralPage() {
title={t("accessLogs")}
onRefresh={refreshData}
isRefreshing={isRefreshing}
onExport={exportData}
onExport={() => startTransition(exportData)}
isExporting={isExporting}
onDateRangeChange={handleDateRangeChange}
dateRange={{

View File

@@ -1,32 +1,28 @@
"use client";
import { Button } from "@app/components/ui/button";
import { toast } from "@app/hooks/useToast";
import { useState, useRef, useEffect } from "react";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useTranslations } from "next-intl";
import {
getStoredPageSize,
LogDataTable,
setStoredPageSize
} from "@app/components/LogDataTable";
import { ColumnDef } from "@tanstack/react-table";
import { DateTimeValue } from "@app/components/DateTimePicker";
import { Key, User } from "lucide-react";
import { ColumnFilter } from "@app/components/ColumnFilter";
import { DateTimeValue } from "@app/components/DateTimePicker";
import { LogDataTable } from "@app/components/LogDataTable";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusContext";
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
import { build } from "@server/build";
import { Alert, AlertDescription } from "@app/components/ui/alert";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
import { useStoredPageSize } from "@app/hooks/useStoredPageSize";
import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient } from "@app/lib/api";
import { getSevenDaysAgo } from "@app/lib/getSevenDaysAgo";
import { build } from "@server/build";
import { ColumnDef } from "@tanstack/react-table";
import axios from "axios";
import { Key, User } from "lucide-react";
import { useTranslations } from "next-intl";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState, useTransition } from "react";
export default function GeneralPage() {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const router = useRouter();
const api = createApiClient(useEnvContext());
const t = useTranslations();
const { env } = useEnvContext();
const { orgId } = useParams();
const searchParams = useSearchParams();
const subscription = useSubscriptionStatusContext();
@@ -34,7 +30,7 @@ export default function GeneralPage() {
const [rows, setRows] = useState<any[]>([]);
const [isRefreshing, setIsRefreshing] = useState(false);
const [isExporting, setIsExporting] = useState(false);
const [isExporting, startTransition] = useTransition();
const [filterAttributes, setFilterAttributes] = useState<{
actors: string[];
actions: string[];
@@ -58,9 +54,7 @@ export default function GeneralPage() {
const [isLoading, setIsLoading] = useState(false);
// Initialize page size from storage or default
const [pageSize, setPageSize] = useState<number>(() => {
return getStoredPageSize("action-audit-logs", 20);
});
const [pageSize, setPageSize] = useStoredPageSize("action-audit-logs", 20);
// Set default date range to last 24 hours
const getDefaultDateRange = () => {
@@ -79,11 +73,11 @@ export default function GeneralPage() {
}
const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const lastWeek = getSevenDaysAgo();
return {
startDate: {
date: yesterday
date: lastWeek
},
endDate: {
date: now
@@ -136,7 +130,6 @@ export default function GeneralPage() {
// Handle page size changes
const handlePageSizeChange = (newPageSize: number) => {
setPageSize(newPageSize);
setStoredPageSize(newPageSize, "action-audit-logs");
setCurrentPage(0); // Reset to first page when changing page size
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
};
@@ -293,8 +286,6 @@ export default function GeneralPage() {
const exportData = async () => {
try {
setIsExporting(true);
// Prepare query params for export
const params: any = {
timeStart: dateRange.startDate?.date
@@ -323,11 +314,21 @@ export default function GeneralPage() {
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
setIsExporting(false);
} catch (error) {
let apiErrorMessage: string | null = null;
if (axios.isAxiosError(error) && error.response) {
const data = error.response.data;
if (data instanceof Blob && data.type === "application/json") {
// Parse the Blob as JSON
const text = await data.text();
const errorData = JSON.parse(text);
apiErrorMessage = errorData.message;
}
}
toast({
title: t("error"),
description: t("exportError"),
description: apiErrorMessage ?? t("exportError"),
variant: "destructive"
});
}
@@ -484,7 +485,7 @@ export default function GeneralPage() {
searchColumn="action"
onRefresh={refreshData}
isRefreshing={isRefreshing}
onExport={exportData}
onExport={() => startTransition(exportData)}
isExporting={isExporting}
onDateRangeChange={handleDateRangeChange}
dateRange={{

View File

@@ -1,34 +1,32 @@
"use client";
import { Button } from "@app/components/ui/button";
import { toast } from "@app/hooks/useToast";
import { useState, useRef, useEffect } from "react";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useTranslations } from "next-intl";
import {
getStoredPageSize,
LogDataTable,
setStoredPageSize
} from "@app/components/LogDataTable";
import { ColumnDef } from "@tanstack/react-table";
import { DateTimeValue } from "@app/components/DateTimePicker";
import { Key, RouteOff, User, Lock, Unlock, ArrowUpRight } from "lucide-react";
import Link from "next/link";
import { ColumnFilter } from "@app/components/ColumnFilter";
import { DateTimeValue } from "@app/components/DateTimePicker";
import { LogDataTable } from "@app/components/LogDataTable";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { Button } from "@app/components/ui/button";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient } from "@app/lib/api";
import { useTranslations } from "next-intl";
import { getSevenDaysAgo } from "@app/lib/getSevenDaysAgo";
import { ColumnDef } from "@tanstack/react-table";
import axios from "axios";
import { ArrowUpRight, Key, Lock, Unlock, User } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState, useTransition } from "react";
import { useStoredPageSize } from "@app/hooks/useStoredPageSize";
export default function GeneralPage() {
const router = useRouter();
const api = createApiClient(useEnvContext());
const t = useTranslations();
const { env } = useEnvContext();
const { orgId } = useParams();
const searchParams = useSearchParams();
const [rows, setRows] = useState<any[]>([]);
const [isRefreshing, setIsRefreshing] = useState(false);
const [isExporting, setIsExporting] = useState(false);
const [isExporting, startTransition] = useTransition();
// Pagination state
const [totalCount, setTotalCount] = useState<number>(0);
@@ -36,9 +34,7 @@ export default function GeneralPage() {
const [isLoading, setIsLoading] = useState(false);
// Initialize page size from storage or default
const [pageSize, setPageSize] = useState<number>(() => {
return getStoredPageSize("request-audit-logs", 20);
});
const [pageSize, setPageSize] = useStoredPageSize("request-audit-logs", 20);
const [filterAttributes, setFilterAttributes] = useState<{
actors: string[];
@@ -95,11 +91,11 @@ export default function GeneralPage() {
}
const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const lastWeek = getSevenDaysAgo();
return {
startDate: {
date: yesterday
date: lastWeek
},
endDate: {
date: now
@@ -152,7 +148,6 @@ export default function GeneralPage() {
// Handle page size changes
const handlePageSizeChange = (newPageSize: number) => {
setPageSize(newPageSize);
setStoredPageSize(newPageSize, "request-audit-logs");
setCurrentPage(0); // Reset to first page when changing page size
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
};
@@ -302,8 +297,6 @@ export default function GeneralPage() {
const exportData = async () => {
try {
setIsExporting(true);
// Prepare query params for export
const params: any = {
timeStart: dateRange.startDate?.date
@@ -335,11 +328,21 @@ export default function GeneralPage() {
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
setIsExporting(false);
} catch (error) {
let apiErrorMessage: string | null = null;
if (axios.isAxiosError(error) && error.response) {
const data = error.response.data;
if (data instanceof Blob && data.type === "application/json") {
// Parse the Blob as JSON
const text = await data.text();
const errorData = JSON.parse(text);
apiErrorMessage = errorData.message;
}
}
toast({
title: t("error"),
description: t("exportError"),
description: apiErrorMessage ?? t("exportError"),
variant: "destructive"
});
}
@@ -773,7 +776,7 @@ export default function GeneralPage() {
searchColumn="host"
onRefresh={refreshData}
isRefreshing={isRefreshing}
onExport={exportData}
onExport={() => startTransition(exportData)}
isExporting={isExporting}
onDateRangeChange={handleDateRangeChange}
dateRange={{

View File

@@ -67,7 +67,10 @@ export default async function ClientResourcesPage(
// destinationPort: siteResource.destinationPort,
alias: siteResource.alias || null,
siteNiceId: siteResource.siteNiceId,
niceId: siteResource.niceId
niceId: siteResource.niceId,
tcpPortRangeString: siteResource.tcpPortRangeString || null,
udpPortRangeString: siteResource.udpPortRangeString || null,
disableIcmp: siteResource.disableIcmp || false,
};
}
);

View File

@@ -225,7 +225,7 @@ export default function GeneralForm() {
name: data.name,
niceId: data.niceId,
subdomain: data.subdomain,
fullDomain: resource.fullDomain,
fullDomain: updated.fullDomain,
proxyPort: data.proxyPort
// ...(!resource.http && {
// enableProxy: data.enableProxy

View File

@@ -449,15 +449,16 @@ export default function ResourceRules(props: {
type="number"
onClick={(e) => e.currentTarget.focus()}
onBlur={(e) => {
const parsed = z
const parsed = z.coerce
.number()
.int()
.optional()
.safeParse(e.target.value);
if (!parsed.data) {
if (!parsed.success) {
toast({
variant: "destructive",
title: t("rulesErrorInvalidIpAddress"), // correct priority or IP?
title: t("rulesErrorInvalidPriority"), // correct priority or IP?
description: t(
"rulesErrorInvalidPriorityDescription"
)

View File

@@ -315,7 +315,7 @@ export default function LicensePage() {
setSelectedLicenseKey(null);
}}
dialog={
<div>
<div className="space-y-2">
<p>{t("licenseQuestionRemove")}</p>
<p>
<b>{t("licenseMessageRemove")}</b>
@@ -360,7 +360,8 @@ export default function LicensePage() {
<div className="space-y-2 text-green-500">
<div className="text-2xl flex items-center gap-2">
<Check />
{t("licensed")}
{t("licensed") +
`${licenseStatus?.tier === "personal" ? ` (${t("personalUseOnly")})` : ""}`}
</div>
</div>
) : (

View File

@@ -243,7 +243,7 @@ export default function UsersTable({ users }: Props) {
setSelected(null);
}}
dialog={
<div>
<div className="space-y-2">
<p>{t("userQuestionRemove")}</p>
<p>{t("userMessageRemove")}</p>

View File

@@ -23,6 +23,7 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
const t = await getTranslations();
let hideFooter = false;
let licenseStatus: GetLicenseStatusResponse | null = null;
if (build == "enterprise") {
const licenseStatusRes = await cache(
async () =>
@@ -30,10 +31,12 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
"/license/status"
)
)();
licenseStatus = licenseStatusRes.data.data;
if (
env.branding.hideAuthLayoutFooter &&
licenseStatusRes.data.data.isHostLicensed &&
licenseStatusRes.data.data.isLicenseValid
licenseStatusRes.data.data.isLicenseValid &&
licenseStatusRes.data.data.tier !== "personal"
) {
hideFooter = true;
}
@@ -83,6 +86,23 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
? t("enterpriseEdition")
: t("pangolinCloud")}
</span>
{build === "enterprise" &&
licenseStatus?.isHostLicensed &&
licenseStatus?.isLicenseValid &&
licenseStatus?.tier === "personal" ? (
<>
<Separator orientation="vertical" />
<span>{t("personalUseOnly")}</span>
</>
) : null}
{build === "enterprise" &&
(!licenseStatus?.isHostLicensed ||
!licenseStatus?.isLicenseValid) ? (
<>
<Separator orientation="vertical" />
<span>{t("unlicensed")}</span>
</>
) : null}
{build === "saas" && (
<>
<Separator orientation="vertical" />