mirror of
https://github.com/fosrl/pangolin.git
synced 2025-05-12 13:20:35 +01:00
env context and refactor api support different ports
This commit is contained in:
parent
d79760dad9
commit
d3d2fe398b
35 changed files with 287 additions and 135 deletions
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"tabWidth": 4,
|
||||
"printWidth": 80
|
||||
"printWidth": 80,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
|
|
|
@ -3,10 +3,15 @@ import cors from "cors";
|
|||
import cookieParser from "cookie-parser";
|
||||
import config from "@server/config";
|
||||
import logger from "@server/logger";
|
||||
import { errorHandlerMiddleware, notFoundMiddleware, rateLimitMiddleware } from "@server/middlewares";
|
||||
import {
|
||||
errorHandlerMiddleware,
|
||||
notFoundMiddleware,
|
||||
rateLimitMiddleware,
|
||||
} from "@server/middlewares";
|
||||
import { authenticated, unauthenticated } from "@server/routers/external";
|
||||
import { router as wsRouter, handleWSUpgrade } from "@server/routers/ws";
|
||||
import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
||||
import helmet from "helmet";
|
||||
|
||||
const dev = process.env.ENVIRONMENT !== "prod";
|
||||
const externalPort = config.server.external_port;
|
||||
|
@ -16,7 +21,17 @@ export function createApiServer() {
|
|||
|
||||
// Middleware setup
|
||||
apiServer.set("trust proxy", 1);
|
||||
if (dev) {
|
||||
apiServer.use(
|
||||
cors({
|
||||
origin: `http://localhost:${config.server.next_port}`,
|
||||
credentials: true,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
apiServer.use(cors());
|
||||
apiServer.use(helmet());
|
||||
}
|
||||
apiServer.use(cookieParser());
|
||||
apiServer.use(express.json());
|
||||
|
||||
|
@ -26,7 +41,7 @@ export function createApiServer() {
|
|||
windowMin: config.rate_limit.window_minutes,
|
||||
max: config.rate_limit.max_requests,
|
||||
type: "IP_ONLY",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,7 +61,9 @@ export function createApiServer() {
|
|||
// Create HTTP server
|
||||
const httpServer = apiServer.listen(externalPort, (err?: any) => {
|
||||
if (err) throw err;
|
||||
logger.info(`API server is running on http://localhost:${externalPort}`);
|
||||
logger.info(
|
||||
`API server is running on http://localhost:${externalPort}`,
|
||||
);
|
||||
});
|
||||
|
||||
// Handle WebSocket upgrades
|
||||
|
|
|
@ -124,6 +124,7 @@ if (!parsedConfig.success) {
|
|||
throw new Error(`Invalid configuration file: ${errors}`);
|
||||
}
|
||||
|
||||
process.env.NEXT_PORT = parsedConfig.data.server.next_port.toString();
|
||||
process.env.SERVER_EXTERNAL_PORT =
|
||||
parsedConfig.data.server.external_port.toString();
|
||||
process.env.SERVER_INTERNAL_PORT =
|
||||
|
|
|
@ -15,7 +15,7 @@ async function startServers() {
|
|||
return {
|
||||
apiServer,
|
||||
nextServer,
|
||||
internalServer
|
||||
internalServer,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,53 @@
|
|||
import axios from "axios";
|
||||
import { env } from "@app/lib/types/env";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
|
||||
let origin;
|
||||
if (typeof window !== "undefined") {
|
||||
origin = window.location.origin;
|
||||
let apiInstance: AxiosInstance | null = null;
|
||||
|
||||
export function createApiClient({ env }: { env: env }): AxiosInstance {
|
||||
if (apiInstance) {
|
||||
return apiInstance;
|
||||
}
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: `${origin}/api/v1`,
|
||||
let baseURL;
|
||||
const suffix = "api/v1";
|
||||
|
||||
if (window.location.port === env.NEXT_PORT) {
|
||||
// this means the user is addressing the server directly
|
||||
baseURL = `${window.location.protocol}//${window.location.hostname}:${env.SERVER_EXTERNAL_PORT}/${suffix}`;
|
||||
axios.defaults.withCredentials = true;
|
||||
} else {
|
||||
// user is accessing through a proxy
|
||||
baseURL = window.location.origin + `/${suffix}`;
|
||||
}
|
||||
|
||||
if (!baseURL) {
|
||||
throw new Error("Failed to create api client, invalid environment");
|
||||
}
|
||||
|
||||
apiInstance = axios.create({
|
||||
baseURL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
return apiInstance;
|
||||
}
|
||||
|
||||
// we can pull from env var here becuase it is only used in the server
|
||||
export const internal = axios.create({
|
||||
baseURL: `http://localhost:${process.env.SERVER_EXTERNAL_PORT}/api/v1`,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
export const priv = axios.create({
|
||||
baseURL: `http://localhost:${process.env.SERVER_INTERNAL_PORT}/api/v1`,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
export default api;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -30,6 +29,8 @@ import {
|
|||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { CreateRoleBody, CreateRoleResponse } from "@server/routers/role";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
type CreateRoleFormProps = {
|
||||
open: boolean;
|
||||
|
@ -52,6 +53,8 @@ export default function CreateRoleForm({
|
|||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -37,6 +36,8 @@ import {
|
|||
} from "@app/components/ui/select";
|
||||
import { RoleRow } from "./RolesTable";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
type CreateRoleFormProps = {
|
||||
open: boolean;
|
||||
|
@ -61,6 +62,8 @@ export default function DeleteRoleForm({
|
|||
const [loading, setLoading] = useState(false);
|
||||
const [roles, setRoles] = useState<ListRolesResponse["roles"]>([]);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchRoles() {
|
||||
const res = await api
|
||||
|
|
|
@ -11,13 +11,14 @@ import { Button } from "@app/components/ui/button";
|
|||
import { ArrowUpDown, Crown, MoreHorizontal } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import api from "@app/api";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { RolesDataTable } from "./RolesDataTable";
|
||||
import { Role } from "@server/db/schema";
|
||||
import CreateRoleForm from "./CreateRoleForm";
|
||||
import DeleteRoleForm from "./DeleteRoleForm";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
export type RoleRow = Role;
|
||||
|
||||
|
@ -33,6 +34,8 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
|
||||
const [roleToRemove, setUserToRemove] = useState<RoleRow | null>(null);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const { org } = useOrgContext();
|
||||
const { toast } = useToast();
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
|
@ -30,6 +29,8 @@ import { useParams } from "next/navigation";
|
|||
import { Button } from "@app/components/ui/button";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z.string().email({ message: "Please enter a valid email" }),
|
||||
|
@ -40,6 +41,8 @@ export default function AccessControlsPage() {
|
|||
const { toast } = useToast();
|
||||
const { orgUser: user } = userOrgUserContext();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const { orgId } = useParams();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -39,6 +38,8 @@ import {
|
|||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { ListRolesResponse } from "@server/routers/role";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
type InviteUserFormProps = {
|
||||
open: boolean;
|
||||
|
@ -55,6 +56,8 @@ export default function InviteUserForm({ open, setOpen }: InviteUserFormProps) {
|
|||
const { toast } = useToast();
|
||||
const { org } = useOrgContext();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [inviteLink, setInviteLink] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [expiresInDays, setExpiresInDays] = useState(1);
|
||||
|
|
|
@ -14,12 +14,13 @@ import { useState } from "react";
|
|||
import InviteUserForm from "./InviteUserForm";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { useUserContext } from "@app/hooks/useUserContext";
|
||||
import api from "@app/api";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
export type UserRow = {
|
||||
id: string;
|
||||
|
@ -42,6 +43,8 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const user = useUserContext();
|
||||
const { org } = useOrgContext();
|
||||
const { toast } = useToast();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { Avatar, AvatarFallback } from "@app/components/ui/avatar";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
|
@ -33,6 +33,7 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@app/components/ui/select";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { cn, formatAxiosError } from "@app/lib/utils";
|
||||
import { ListOrgsResponse } from "@server/routers/org";
|
||||
|
@ -55,6 +56,8 @@ export default function Header({ email, orgId, name, orgs }: HeaderProps) {
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
function getInitials() {
|
||||
if (name) {
|
||||
const [firstName, lastName] = name.split(" ");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -30,6 +29,8 @@ import {
|
|||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { Resource } from "@server/db/schema";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const setPasswordFormSchema = z.object({
|
||||
password: z.string().min(4).max(100),
|
||||
|
@ -56,6 +57,8 @@ export default function SetResourcePasswordForm({
|
|||
}: SetPasswordFormProps) {
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const form = useForm<SetPasswordFormValues>({
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -35,6 +34,8 @@ import {
|
|||
InputOTPGroup,
|
||||
InputOTPSlot,
|
||||
} from "@app/components/ui/input-otp";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const setPincodeFormSchema = z.object({
|
||||
pincode: z.string().length(6),
|
||||
|
@ -63,6 +64,8 @@ export default function SetResourcePincodeForm({
|
|||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const form = useForm<SetPincodeFormValues>({
|
||||
resolver: zodResolver(setPincodeFormSchema),
|
||||
defaultValues,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import api from "@app/api";
|
||||
import { ListRolesResponse } from "@server/routers/role";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
|
@ -36,6 +35,8 @@ import { Binary, Key, ShieldCheck } from "lucide-react";
|
|||
import SetResourcePasswordForm from "./components/SetResourcePasswordForm";
|
||||
import { Separator } from "@app/components/ui/separator";
|
||||
import SetResourcePincodeForm from "./components/SetResourcePincodeForm";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const UsersRolesFormSchema = z.object({
|
||||
roles: z.array(
|
||||
|
@ -58,6 +59,8 @@ export default function ResourceAuthenticationPage() {
|
|||
const { resource, updateResource, authInfo, updateAuthInfo } =
|
||||
useResourceContext();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [pageLoading, setPageLoading] = useState(true);
|
||||
|
||||
const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>(
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import api from "@app/api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ListTargetsResponse } from "@server/routers/target/listTargets";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
@ -49,9 +48,9 @@ import { useToast } from "@app/hooks/useToast";
|
|||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { useResourceContext } from "@app/hooks/useResourceContext";
|
||||
import { ArrayElement } from "@server/types/ArrayElement";
|
||||
import { Dot } from "lucide-react";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { Separator } from "@radix-ui/react-separator";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { createApiClient } from "@app/api";
|
||||
|
||||
const addTargetSchema = z.object({
|
||||
ip: z.string().ip(),
|
||||
|
@ -83,6 +82,8 @@ export default function ReverseProxyTargets(props: {
|
|||
const { toast } = useToast();
|
||||
const { resource, updateResource } = useResourceContext();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [targets, setTargets] = useState<LocalTarget[]>([]);
|
||||
const [targetsToRemove, setTargetsToRemove] = useState<number[]>([]);
|
||||
const [sslEnabled, setSslEnabled] = useState(resource.ssl);
|
||||
|
|
|
@ -33,7 +33,6 @@ import { useResourceContext } from "@app/hooks/useResourceContext";
|
|||
import { ListSitesResponse } from "@server/routers/site";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AxiosResponse } from "axios";
|
||||
import api from "@app/api";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { GetResourceAuthInfoResponse } from "@server/routers/resource";
|
||||
|
@ -43,6 +42,8 @@ import { useOrgContext } from "@app/hooks/useOrgContext";
|
|||
import CustomDomainInput from "../components/CustomDomainInput";
|
||||
import ResourceInfoBox from "../components/ResourceInfoBox";
|
||||
import { subdomainSchema } from "@server/schemas/subdomainSchema";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const GeneralFormSchema = z.object({
|
||||
name: z.string(),
|
||||
|
@ -61,6 +62,8 @@ export default function GeneralForm() {
|
|||
|
||||
const orgId = params.orgId;
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [sites, setSites] = useState<ListSitesResponse["sites"]>([]);
|
||||
const [saveLoading, setSaveLoading] = useState(false);
|
||||
const [domainSuffix, setDomainSuffix] = useState(org.org.domain);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button, buttonVariants } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -9,7 +8,7 @@ import {
|
|||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
FormMessage
|
||||
} from "@app/components/ui/form";
|
||||
import { Input } from "@app/components/ui/input";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
|
@ -25,7 +24,7 @@ import {
|
|||
CredenzaDescription,
|
||||
CredenzaFooter,
|
||||
CredenzaHeader,
|
||||
CredenzaTitle,
|
||||
CredenzaTitle
|
||||
} from "@app/components/Credenza";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { ListSitesResponse } from "@server/routers/site";
|
||||
|
@ -34,7 +33,7 @@ import { CheckIcon } from "lucide-react";
|
|||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import {
|
||||
Command,
|
||||
|
@ -42,7 +41,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandList
|
||||
} from "@app/components/ui/command";
|
||||
import { CaretSortIcon } from "@radix-ui/react-icons";
|
||||
import CustomDomainInput from "../[resourceId]/components/CustomDomainInput";
|
||||
|
@ -50,11 +49,13 @@ import { Axios, AxiosResponse } from "axios";
|
|||
import { Resource } from "@server/db/schema";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { subdomainSchema } from "@server/schemas/subdomainSchema";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const accountFormSchema = z.object({
|
||||
subdomain: subdomainSchema,
|
||||
name: z.string(),
|
||||
siteId: z.number(),
|
||||
siteId: z.number()
|
||||
});
|
||||
|
||||
type AccountFormValues = z.infer<typeof accountFormSchema>;
|
||||
|
@ -66,10 +67,12 @@ type CreateResourceFormProps = {
|
|||
|
||||
export default function CreateResourceForm({
|
||||
open,
|
||||
setOpen,
|
||||
setOpen
|
||||
}: CreateResourceFormProps) {
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const params = useParams();
|
||||
|
||||
|
@ -85,8 +88,8 @@ export default function CreateResourceForm({
|
|||
resolver: zodResolver(accountFormSchema),
|
||||
defaultValues: {
|
||||
subdomain: "",
|
||||
name: "My Resource",
|
||||
},
|
||||
name: "My Resource"
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -96,7 +99,7 @@ export default function CreateResourceForm({
|
|||
|
||||
const fetchSites = async () => {
|
||||
const res = await api.get<AxiosResponse<ListSitesResponse>>(
|
||||
`/org/${orgId}/sites/`,
|
||||
`/org/${orgId}/sites/`
|
||||
);
|
||||
setSites(res.data.data.sites);
|
||||
|
||||
|
@ -116,9 +119,9 @@ export default function CreateResourceForm({
|
|||
`/org/${orgId}/site/${data.siteId}/resource/`,
|
||||
{
|
||||
name: data.name,
|
||||
subdomain: data.subdomain,
|
||||
subdomain: data.subdomain
|
||||
// subdomain: data.subdomain,
|
||||
},
|
||||
}
|
||||
)
|
||||
.catch((e) => {
|
||||
toast({
|
||||
|
@ -126,8 +129,8 @@ export default function CreateResourceForm({
|
|||
title: "Error creating resource",
|
||||
description: formatAxiosError(
|
||||
e,
|
||||
"An error occurred when creating the resource",
|
||||
),
|
||||
"An error occurred when creating the resource"
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -198,7 +201,7 @@ export default function CreateResourceForm({
|
|||
onChange={(value) =>
|
||||
form.setValue(
|
||||
"subdomain",
|
||||
value,
|
||||
value
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@ -227,14 +230,14 @@ export default function CreateResourceForm({
|
|||
className={cn(
|
||||
"w-[350px] justify-between",
|
||||
!field.value &&
|
||||
"text-muted-foreground",
|
||||
"text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value
|
||||
? sites.find(
|
||||
(site) =>
|
||||
site.siteId ===
|
||||
field.value,
|
||||
field.value
|
||||
)?.name
|
||||
: "Select site"}
|
||||
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
|
@ -261,7 +264,7 @@ export default function CreateResourceForm({
|
|||
onSelect={() => {
|
||||
form.setValue(
|
||||
"siteId",
|
||||
site.siteId,
|
||||
site.siteId
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
@ -271,14 +274,14 @@ export default function CreateResourceForm({
|
|||
site.siteId ===
|
||||
field.value
|
||||
? "opacity-100"
|
||||
: "opacity-0",
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{
|
||||
site.name
|
||||
}
|
||||
</CommandItem>
|
||||
),
|
||||
)
|
||||
)}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
|
|
|
@ -21,13 +21,14 @@ import {
|
|||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import api from "@app/api";
|
||||
import CreateResourceForm from "./CreateResourceForm";
|
||||
import { useState } from "react";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { set } from "zod";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
export type ResourceRow = {
|
||||
id: number;
|
||||
|
@ -49,6 +50,8 @@ export default function SitesTable({ resources, orgId }: ResourcesTableProps) {
|
|||
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [selectedResource, setSelectedResource] =
|
||||
|
|
|
@ -15,11 +15,12 @@ import {
|
|||
import { Input } from "@/components/ui/input";
|
||||
import { useSiteContext } from "@app/hooks/useSiteContext";
|
||||
import { useForm } from "react-hook-form";
|
||||
import api from "@app/api";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { useRouter } from "next/navigation";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const GeneralFormSchema = z.object({
|
||||
name: z.string(),
|
||||
|
@ -31,6 +32,8 @@ export default function GeneralPage() {
|
|||
const { site, updateSite } = useSiteContext();
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<GeneralFormValues>({
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button, buttonVariants } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -41,6 +40,8 @@ import {
|
|||
SelectValue,
|
||||
} from "@app/components/ui/select";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const method = [
|
||||
{ label: "Newt", value: "newt" },
|
||||
|
@ -74,6 +75,8 @@ type CreateSiteFormProps = {
|
|||
export default function CreateSiteForm({ open, setOpen }: CreateSiteFormProps) {
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const params = useParams();
|
||||
|
|
|
@ -12,13 +12,14 @@ import { Button } from "@app/components/ui/button";
|
|||
import { ArrowRight, ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import api from "@app/api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useState } from "react";
|
||||
import CreateSiteForm from "./CreateSiteForm";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { useToast } from "@app/hooks/useToast";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
export type SiteRow = {
|
||||
id: number;
|
||||
|
@ -44,6 +45,8 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
|
|||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [selectedSite, setSelectedSite] = useState<SiteRow | null>(null);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const callApi = async () => {
|
||||
const res = await api.put<AxiosResponse<any>>(`/newt`);
|
||||
console.log(res);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useSyncExternalStore } from "react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
@ -29,7 +29,6 @@ import {
|
|||
InputOTPGroup,
|
||||
InputOTPSlot,
|
||||
} from "@app/components/ui/input-otp";
|
||||
import api from "@app/api";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Alert, AlertDescription } from "@app/components/ui/alert";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
|
@ -38,6 +37,8 @@ import LoginForm from "@app/components/LoginForm";
|
|||
import { AuthWithPasswordResponse } from "@server/routers/resource";
|
||||
import { redirect } from "next/dist/server/api-utils";
|
||||
import ResourceAccessDenied from "./ResourceAccessDenied";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const pinSchema = z.object({
|
||||
pin: z
|
||||
|
@ -83,6 +84,8 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
|||
const [accessDenied, setAccessDenied] = useState<boolean>(false);
|
||||
const [loadingLogin, setLoadingLogin] = useState(false);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
function getDefaultSelectedMethod() {
|
||||
if (props.methods.sso) {
|
||||
return "sso";
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
InputOTPGroup,
|
||||
InputOTPSlot,
|
||||
} from "@/components/ui/input-otp";
|
||||
import api from "@app/api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { VerifyEmailResponse } from "@server/routers/auth";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
@ -35,6 +34,8 @@ import { Alert, AlertDescription } from "../../../components/ui/alert";
|
|||
import { useToast } from "@app/hooks/useToast";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
const FormSchema = z.object({
|
||||
email: z.string().email({ message: "Invalid email address" }),
|
||||
|
@ -61,6 +62,8 @@ export default function VerifyEmailForm({
|
|||
|
||||
const { toast } = useToast();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 20 5.0% 10.0%;
|
||||
--foreground: 0 0.0% 10.0%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 20 5.0% 10.0%;
|
||||
--popover: 0 0% 100%;
|
||||
|
@ -33,7 +33,7 @@
|
|||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 5.0% 10.0%;
|
||||
--background: 0 0.0% 10.0%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
--card: 20 5.0% 10.0%;
|
||||
--card-foreground: 60 9.1% 97.8%;
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardTitle
|
||||
} from "@app/components/ui/card";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { XCircle } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
|
@ -19,10 +20,12 @@ type InviteStatusCardProps = {
|
|||
|
||||
export default function InviteStatusCard({
|
||||
type,
|
||||
token,
|
||||
token
|
||||
}: InviteStatusCardProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
async function goToLogin() {
|
||||
await api.post("/auth/logout", {});
|
||||
router.push(`/auth/login?redirect=/invite?token=${token}`);
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import { Figtree, IBM_Plex_Sans, Inter, Work_Sans } from "next/font/google";
|
||||
import { Figtree } from "next/font/google";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { ThemeProvider } from "@app/providers/ThemeProvider";
|
||||
import EnvProvider from "@app/providers/EnvProvider";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: `Dashboard - Pangolin`,
|
||||
description: "",
|
||||
description: ""
|
||||
};
|
||||
|
||||
// const font = Inter({ subsets: ["latin"] });
|
||||
// const font = Noto_Sans_Mono({ subsets: ["latin"] });
|
||||
// const font = Work_Sans({ subsets: ["latin"] });
|
||||
// const font = Space_Grotesk({subsets: ["latin"]})
|
||||
// const font = IBM_Plex_Sans({subsets: ["latin"], weight: "400"})
|
||||
const font = Figtree({ subsets: ["latin"] });
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
children
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
|
@ -29,8 +25,19 @@ export default async function RootLayout({
|
|||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<EnvProvider
|
||||
// it's import not to pass all of process.env here in case of secrets
|
||||
// select only the necessary ones
|
||||
env={{
|
||||
NEXT_PORT: process.env.NEXT_PORT as string,
|
||||
SERVER_EXTERNAL_PORT: process.env
|
||||
.SERVER_EXTERNAL_PORT as string,
|
||||
ENVIRONMENT: process.env.ENVIRONMENT as string
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</EnvProvider>
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
|
|
|
@ -4,7 +4,6 @@ import { Button } from "@/components/ui/button";
|
|||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import Link from "next/link";
|
||||
import api from "@app/api";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
|
@ -16,6 +15,8 @@ import {
|
|||
} from "@app/components/ui/card";
|
||||
import CopyTextBox from "@app/components/CopyTextBox";
|
||||
import { formatAxiosError } from "@app/lib/utils";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
type Step = "org" | "site" | "resources";
|
||||
|
||||
|
@ -28,6 +29,8 @@ export default function StepperForm() {
|
|||
const [orgCreated, setOrgCreated] = useState(false);
|
||||
const [orgIdTaken, setOrgIdTaken] = useState(false);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const checkOrgIdAvailability = useCallback(async (value: string) => {
|
||||
try {
|
||||
const res = await api.get(`/org/checkId`, {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import api from "@app/api";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
|
@ -42,6 +41,8 @@ import {
|
|||
} from "@app/components/Credenza";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { Description } from "@radix-ui/react-toast";
|
||||
import { createApiClient } from "@app/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
|
||||
type InviteUserFormProps = {
|
||||
open: boolean;
|
||||
|
@ -64,6 +65,8 @@ export default function InviteUserForm({
|
|||
}: InviteUserFormProps) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const formSchema = z.object({
|
||||
string: z.string().refine((val) => val === string, {
|
||||
message: "Invalid confirmation",
|
||||
|
|
10
src/contexts/envContext.ts
Normal file
10
src/contexts/envContext.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { env } from "@app/lib/types/env";
|
||||
import { createContext } from "react";
|
||||
|
||||
interface EnvContextType {
|
||||
env: env;
|
||||
}
|
||||
|
||||
const EnvContext = createContext<EnvContextType | undefined>(undefined);
|
||||
|
||||
export default EnvContext;
|
10
src/hooks/useEnvContext.ts
Normal file
10
src/hooks/useEnvContext.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import EnvContext from "@app/contexts/envContext";
|
||||
import { useContext } from "react";
|
||||
|
||||
export function useEnvContext() {
|
||||
const context = useContext(EnvContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useEnvContext must be used within an EnvProvider");
|
||||
}
|
||||
return context;
|
||||
}
|
5
src/lib/types/env.ts
Normal file
5
src/lib/types/env.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export type env = {
|
||||
SERVER_EXTERNAL_PORT: string;
|
||||
NEXT_PORT: string;
|
||||
ENVIRONMENT: string;
|
||||
};
|
17
src/providers/EnvProvider.tsx
Normal file
17
src/providers/EnvProvider.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
"use client";
|
||||
|
||||
import EnvContext from "@app/contexts/envContext";
|
||||
import { env } from "@app/lib/types/env";
|
||||
|
||||
interface ApiProviderProps {
|
||||
children: React.ReactNode;
|
||||
env: env;
|
||||
}
|
||||
|
||||
export function EnvProvider({ children, env }: ApiProviderProps) {
|
||||
return (
|
||||
<EnvContext.Provider value={{ env }}>{children}</EnvContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default EnvProvider;
|
Loading…
Reference in a new issue