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