mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # prisma/schema.prisma
This commit is contained in:
@@ -11,6 +11,7 @@ import {Card, CardContent, CardHeader} from "@/components/ui/card";
|
|||||||
import {AgentModalKey} from "@/components/wrappers/dashboard/agent/AgentModalKey/AgentModalKey";
|
import {AgentModalKey} from "@/components/wrappers/dashboard/agent/AgentModalKey/AgentModalKey";
|
||||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||||
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard";
|
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard";
|
||||||
|
import {AgentCardKey} from "@/components/wrappers/dashboard/agent/AgentCardKey/AgentCardKey";
|
||||||
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{ agentId: string }>) {
|
export default async function RoutePage(props: PageParams<{ agentId: string }>) {
|
||||||
@@ -53,15 +54,13 @@ export default async function RoutePage(props: PageParams<{ agentId: string }>)
|
|||||||
href={`/dashboard/agents/${agent.id}/edit`}>
|
href={`/dashboard/agents/${agent.id}/edit`}>
|
||||||
<GearIcon className="w-7 h-7"/>
|
<GearIcon className="w-7 h-7"/>
|
||||||
</Link>
|
</Link>
|
||||||
<AgentModalKey agent={agent}>
|
{/*<AgentModalKey agent={agent}>*/}
|
||||||
<Button variant="outline">
|
{/* <Button variant="outline">*/}
|
||||||
<KeyRound/>
|
{/* <KeyRound/>*/}
|
||||||
</Button>
|
{/* </Button>*/}
|
||||||
</AgentModalKey>
|
{/*</AgentModalKey>*/}
|
||||||
</PageTitle>
|
</PageTitle>
|
||||||
<PageActions className="justify-between">
|
|
||||||
<Button>Restore</Button>
|
|
||||||
</PageActions>
|
|
||||||
</div>
|
</div>
|
||||||
<PageDescription className="mt-5 sm:mt-0">{agent.description}</PageDescription>
|
<PageDescription className="mt-5 sm:mt-0">{agent.description}</PageDescription>
|
||||||
<PageContent className="flex flex-col w-full h-full">
|
<PageContent className="flex flex-col w-full h-full">
|
||||||
@@ -88,7 +87,16 @@ export default async function RoutePage(props: PageParams<{ agentId: string }>)
|
|||||||
{formatDateLastContact(agent.lastContact)}
|
{formatDateLastContact(agent.lastContact)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<Card className="w-full sm:w-auto flex-1">
|
||||||
|
<CardHeader className="font-bold text-xl">
|
||||||
|
Edge Key
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<AgentCardKey agent={agent}/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
<CardsWithPagination data={agent.databases} cardItem={DatabaseCard}/>
|
<CardsWithPagination data={agent.databases} cardItem={DatabaseCard}/>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
|
|||||||
</PageTitle>
|
</PageTitle>
|
||||||
<PageActions className="justify-between">
|
<PageActions className="justify-between">
|
||||||
<ButtonDeleteProject
|
<ButtonDeleteProject
|
||||||
|
projectId={projectId}
|
||||||
text={"Delete Project"}
|
text={"Delete Project"}
|
||||||
/>
|
/>
|
||||||
</PageActions>
|
</PageActions>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `isArchived` to the `projects` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "projects" ADD COLUMN "isArchived" BOOLEAN NOT NULL;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "projects" ALTER COLUMN "isArchived" SET DEFAULT false;
|
||||||
@@ -38,10 +38,6 @@ export const LoginForm = (props: loginFormProps) => {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="grid gap-2 text-center mb-2">
|
<div className="grid gap-2 text-center mb-2">
|
||||||
{/*<div className="justify-center text-center flex">*/}
|
|
||||||
{/* <Image src="/logo.png" alt="Logo Portabase" width={100}*/}
|
|
||||||
{/* height={50}/>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<h1 className="text-3xl font-bold">Login</h1>
|
<h1 className="text-3xl font-bold">Login</h1>
|
||||||
<p className="text-balance text-muted-foreground">
|
<p className="text-balance text-muted-foreground">
|
||||||
Enter your informations bellow to login
|
Enter your informations bellow to login
|
||||||
|
|||||||
+12
-9
@@ -2,21 +2,24 @@
|
|||||||
import {signInAction} from "@/features/auth/auth.action";
|
import {signInAction} from "@/features/auth/auth.action";
|
||||||
import {Button} from "@/components/ui/button";
|
import {Button} from "@/components/ui/button";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import {env} from "@/env.mjs";
|
||||||
|
|
||||||
export type SocialAuthButtonProps = {}
|
export type SocialAuthButtonProps = {}
|
||||||
|
|
||||||
export const SocialAuthButton = (props: SocialAuthButtonProps) => {
|
export const SocialAuthButton = (props: SocialAuthButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4 mt-5">
|
<div className="flex flex-col gap-4 mt-5">
|
||||||
<Button
|
{env.NEXT_PUBLIC_GOOGLE_AUTH === "true" ?
|
||||||
onClick={(e) => {
|
<Button
|
||||||
e.preventDefault();
|
onClick={(e) => {
|
||||||
void signInAction("google")
|
e.preventDefault();
|
||||||
}}
|
void signInAction("google")
|
||||||
>
|
}}
|
||||||
<Image src="/google-icon.png" alt="Google OAuth" width={25} height={25}/>
|
>
|
||||||
Sign in with google
|
<Image src="/google-icon.png" alt="Google OAuth" width={25} height={25}/>
|
||||||
</Button>
|
Sign in with google
|
||||||
|
</Button>
|
||||||
|
:null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,8 @@ export async function copyToClipboardWithMeta(value: string) {
|
|||||||
|
|
||||||
|
|
||||||
export type CopyButtonProps = {
|
export type CopyButtonProps = {
|
||||||
value: string
|
value: string,
|
||||||
|
className: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
"use client"
|
||||||
|
import {generateEdgeKey} from "@/utils/edge_key";
|
||||||
|
import {getServerUrl} from "@/utils/get-server-url";
|
||||||
|
import {Agent} from "@prisma/client";
|
||||||
|
import {PasswordInput} from "@/components/wrappers/auth/PaswordInput/password-input";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {CopyButton} from "@/components/wrappers/common/button/copy-button";
|
||||||
|
|
||||||
|
export type AgentCardKeyProps = {
|
||||||
|
agent: Agent
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AgentCardKey = (props: AgentCardKeyProps) => {
|
||||||
|
const edge_key = generateEdgeKey(getServerUrl(), props.agent.id);
|
||||||
|
const [code, setCode] = useState<string>(`${edge_key}`);
|
||||||
|
|
||||||
|
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<PasswordInput value={code} onChange={(value: string) => {setCode(edge_key)} }/>
|
||||||
|
<CopyButton className="mt-5" value={code}/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
+17
-10
@@ -2,29 +2,36 @@
|
|||||||
|
|
||||||
import {Trash2} from "lucide-react";
|
import {Trash2} from "lucide-react";
|
||||||
import {ButtonWithConfirm} from "@/components/wrappers/common/button/button-with-confirm";
|
import {ButtonWithConfirm} from "@/components/wrappers/common/button/button-with-confirm";
|
||||||
|
import {useMutation} from "@tanstack/react-query";
|
||||||
|
import {deleteProjectAction} from "@/components/wrappers/dashboard/projects/ButtonDeleteProject/delete-project.action";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import {toast} from "sonner";
|
||||||
|
|
||||||
export type ButtonDeleteProjectProps = {
|
export type ButtonDeleteProjectProps = {
|
||||||
text? : string
|
text? : string
|
||||||
|
projectId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ButtonDeleteProject = (props: ButtonDeleteProjectProps) => {
|
export const ButtonDeleteProject = (props: ButtonDeleteProjectProps) => {
|
||||||
|
const router = useRouter()
|
||||||
// const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
// mutationFn: () => deleteUserAction(""),
|
mutationFn: () => deleteProjectAction(props.projectId),
|
||||||
// onSuccess: async () => {
|
onSuccess: async (result) => {
|
||||||
// await signOutAction();
|
router.push("/dashboard/projects")
|
||||||
// },
|
if(result.data.success) {
|
||||||
// })
|
toast.success(result.data.actionSuccess.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonWithConfirm
|
<ButtonWithConfirm
|
||||||
text={props.text ? props.text : ""}
|
text={props.text ? props.text : ""}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// mutation.mutate()
|
mutation.mutate()
|
||||||
console.log("ok")
|
|
||||||
}}
|
}}
|
||||||
variant={"destructive"}
|
variant={"destructive"}
|
||||||
// isPending={mutation.isPending}
|
isPending={mutation.isPending}
|
||||||
className="gap-2"
|
className="gap-2"
|
||||||
icon={<Trash2/>}
|
icon={<Trash2/>}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
"use server"
|
||||||
|
import {userAction} from "@/safe-actions";
|
||||||
|
import {z} from "zod";
|
||||||
|
import {v4 as uuidv4} from "uuid";
|
||||||
|
import {prisma} from "@/prisma";
|
||||||
|
import {ServerActionResult} from "@/types/action-type";
|
||||||
|
import {Projects} from "@prisma/client";
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteProjectAction = userAction
|
||||||
|
.schema(z.string())
|
||||||
|
.action(async ({parsedInput, ctx}): Promise<ServerActionResult<Projects>> => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const uuid = uuidv4()
|
||||||
|
|
||||||
|
const project = await prisma.project.update({
|
||||||
|
where: {
|
||||||
|
id: parsedInput
|
||||||
|
},
|
||||||
|
data:{
|
||||||
|
isArchived: true,
|
||||||
|
slug: uuid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
value: project,
|
||||||
|
actionSuccess: {
|
||||||
|
message: "Projects has been successfully archived.",
|
||||||
|
messageParams: {projectName: parsedInput.data.name},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
actionError: {
|
||||||
|
message: "Failed to archived Projects.",
|
||||||
|
status: 500, // Optional: Use a meaningful status code
|
||||||
|
cause: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
messageParams: {projectName: parsedInput.data.name},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -42,7 +42,7 @@ export const createProjectAction = userAction
|
|||||||
success: true,
|
success: true,
|
||||||
value: project,
|
value: project,
|
||||||
actionSuccess: {
|
actionSuccess: {
|
||||||
message: "ProjectsForm has been successfully created.",
|
message: "Projects has been successfully created.",
|
||||||
messageParams: {projectName: parsedInput.data.name},
|
messageParams: {projectName: parsedInput.data.name},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -50,7 +50,7 @@ export const createProjectAction = userAction
|
|||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
actionError: {
|
actionError: {
|
||||||
message: "Failed to create ProjectsForm.",
|
message: "Failed to create Projects.",
|
||||||
status: 500, // Optional: Use a meaningful status code
|
status: 500, // Optional: Use a meaningful status code
|
||||||
cause: error instanceof Error ? error.message : "Unknown error",
|
cause: error instanceof Error ? error.message : "Unknown error",
|
||||||
messageParams: {projectName: parsedInput.data.name},
|
messageParams: {projectName: parsedInput.data.name},
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const env = createEnv({
|
|||||||
S3_USE_SSL: z.string().optional(),
|
S3_USE_SSL: z.string().optional(),
|
||||||
|
|
||||||
STORAGE_TYPE: z.string().optional(),
|
STORAGE_TYPE: z.string().optional(),
|
||||||
|
NEXT_PUBLIC_GOOGLE_AUTH: z.string().optional(),
|
||||||
|
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
@@ -40,6 +41,7 @@ export const env = createEnv({
|
|||||||
*/
|
*/
|
||||||
client: {
|
client: {
|
||||||
NEXT_PUBLIC_DOMAIN_NAME: z.string(),
|
NEXT_PUBLIC_DOMAIN_NAME: z.string(),
|
||||||
|
NEXT_PUBLIC_GOOGLE_AUTH: z.string().optional(),
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
* Due to how Next.js bundles environment variables on Edge and Client,
|
* Due to how Next.js bundles environment variables on Edge and Client,
|
||||||
@@ -62,6 +64,7 @@ export const env = createEnv({
|
|||||||
|
|
||||||
AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID,
|
AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID,
|
||||||
AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET,
|
AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET,
|
||||||
|
NEXT_PUBLIC_GOOGLE_AUTH: process.env.NEXT_PUBLIC_GOOGLE_AUTH,
|
||||||
|
|
||||||
S3_ENDPOINT: process.env.S3_ENDPOINT,
|
S3_ENDPOINT: process.env.S3_ENDPOINT,
|
||||||
S3_ACCESS_KEY: process.env.S3_ACCESS_KEY,
|
S3_ACCESS_KEY: process.env.S3_ACCESS_KEY,
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ export const signInAction = async (type: string, formData?: any) => {
|
|||||||
email: formData.email
|
email: formData.email
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// const signInError = error as CredentialsSignin
|
|
||||||
console.error(error);
|
|
||||||
return {error: "Error loging in, please try again or check your credentials !"};
|
return {error: "Error loging in, please try again or check your credentials !"};
|
||||||
}
|
}
|
||||||
redirect("/")
|
redirect("/")
|
||||||
|
|||||||
Reference in New Issue
Block a user