Testing in local validated.

This commit is contained in:
charlesgauthereau
2025-07-16 20:16:18 +02:00
parent de9fe33194
commit 5e704ec18a
21 changed files with 598 additions and 591 deletions
@@ -11,6 +11,7 @@ import {deleteUserAction} from "@/components/wrappers/dashboard/profile/ButtonDe
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
import {User} from "@/db/schema/01_user";
import {useSession} from "@/lib/auth/auth-client";
import {formatFrenchDate} from "@/utils/date-formatting";
export const usersColumnsAdmin: ColumnDef<User>[] = [
{
@@ -54,9 +55,7 @@ export const usersColumnsAdmin: ColumnDef<User>[] = [
accessorKey: "updatedAt",
header: "Updated At",
cell: ({row}) => {
return new Date(row.getValue("updatedAt")).toLocaleString("fr-FR", {
timeZone: "Europe/Paris",
});
return formatFrenchDate(row.getValue("updatedAt"))
},
},
{
@@ -1,8 +1,8 @@
"use client";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Database } from "@/db/schema";
import { formatDateLastContact } from "@/utils/date-formatting";
import {Card, CardContent, CardHeader} from "@/components/ui/card";
import {formatDateLastContact} from "@/utils/date-formatting";
import {Database} from "@/db/schema/06_database";
export type DatabaseKpiPro = {
successRate: any;
@@ -41,10 +41,9 @@ export const DatabaseTabs = (props: DatabaseTabsProps) => {
</TabsList>
<TabsContent className="h-full justify-between" value="backup">
{/*
<DataTable columns={backupColumns} data={props.backups} extendedProps={props.isAlreadyRestore} />
*/}
<DataTable columns={backupColumns} data={props.backups} enablePagination />
{/*<DataTable columns={backupColumns} data={props.backups} extendedProps={props.isAlreadyRestore} />*/}
<DataTable columns={backupColumns(props.isAlreadyRestore)} data={props.backups} enablePagination />
</TabsContent>
<TabsContent className="h-full justify-between" value="restore">
@@ -24,7 +24,6 @@ export type projectFormProps = {
export const ProjectForm = (props: projectFormProps) => {
const router = useRouter();
const isCreate = !Boolean(props.defaultValues);
const formatDatabasesList = (databases: DatabaseWith[]) => {
return databases.map((database) => ({
value: database.id,
@@ -1,4 +1,4 @@
CREATE TYPE "public"."dbms_status" AS ENUM('active', 'inactive');--> statement-breakpoint
CREATE TYPE "public"."dbms_status" AS ENUM('postgresql', 'mongodb');--> statement-breakpoint
CREATE TYPE "public"."status" AS ENUM('waiting', 'ongoing', 'failed', 'success');--> statement-breakpoint
CREATE TYPE "public"."type_storage" AS ENUM('local', 's3');--> statement-breakpoint
CREATE TABLE "settings" (
@@ -45,6 +45,7 @@ CREATE TABLE "session" (
"user_agent" text,
"user_id" uuid NOT NULL,
"impersonated_by" text,
"active_organization_id" text,
CONSTRAINT "session_token_unique" UNIQUE("token")
);
--> statement-breakpoint
@@ -73,25 +74,6 @@ CREATE TABLE "verification" (
"updated_at" timestamp
);
--> statement-breakpoint
CREATE TABLE "invitation" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"organization_id" uuid NOT NULL,
"email" text NOT NULL,
"role" text,
"status" text NOT NULL,
"expires_at" timestamp NOT NULL,
"inviter_id" uuid NOT NULL
);
--> statement-breakpoint
CREATE TABLE "member" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"organization_id" uuid NOT NULL,
"user_id" uuid NOT NULL,
"role" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp
);
--> statement-breakpoint
CREATE TABLE "organization" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
@@ -103,6 +85,25 @@ CREATE TABLE "organization" (
CONSTRAINT "organization_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
CREATE TABLE "member" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"organization_id" uuid NOT NULL,
"user_id" uuid NOT NULL,
"role" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp
);
--> statement-breakpoint
CREATE TABLE "invitation" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"organization_id" uuid NOT NULL,
"email" text NOT NULL,
"role" text,
"status" text NOT NULL,
"expires_at" timestamp NOT NULL,
"inviter_id" uuid NOT NULL
);
--> statement-breakpoint
CREATE TABLE "projects" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"slug" text NOT NULL,
@@ -114,17 +115,6 @@ CREATE TABLE "projects" (
CONSTRAINT "projects_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
CREATE TABLE "agents" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"slug" text NOT NULL,
"name" text NOT NULL,
"description" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp,
"last_contact" timestamp,
CONSTRAINT "agents_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
CREATE TABLE "backups" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"status" "status" DEFAULT 'waiting' NOT NULL,
@@ -139,7 +129,7 @@ CREATE TABLE "databases" (
"agent_database_id" uuid DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
"dbms" "dbms_status" NOT NULL,
"description" text NOT NULL,
"description" text,
"backup_policy" text,
"is_waiting_for_backup" boolean DEFAULT false NOT NULL,
"backup_to_restore" text,
@@ -147,7 +137,7 @@ CREATE TABLE "databases" (
"updated_at" timestamp,
"agent_id" uuid NOT NULL,
"last_contact" timestamp,
"project_id" uuid NOT NULL
"project_id" uuid
);
--> statement-breakpoint
CREATE TABLE "restorations" (
@@ -159,12 +149,23 @@ CREATE TABLE "restorations" (
"database_id" uuid
);
--> statement-breakpoint
CREATE TABLE "agents" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"slug" text NOT NULL,
"name" text NOT NULL,
"description" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp,
"last_contact" timestamp,
CONSTRAINT "agents_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "projects" ADD CONSTRAINT "projects_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "backups" ADD CONSTRAINT "backups_database_id_databases_id_fk" FOREIGN KEY ("database_id") REFERENCES "public"."databases"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "databases" ADD CONSTRAINT "databases_agent_id_agents_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "session" ADD COLUMN "active_organization_id" text;
+1
View File
@@ -0,0 +1 @@
DROP INDEX "database_id_status_unique";
+219 -213
View File
@@ -1,5 +1,5 @@
{
"id": "d29f51ca-2c37-4d42-9fb5-19235fb84b32",
"id": "3d165821-b11d-4be7-b3fb-83c4485e44a8",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
@@ -279,6 +279,12 @@
"type": "text",
"primaryKey": false,
"notNull": false
},
"active_organization_id": {
"name": "active_organization_id",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
@@ -457,6 +463,149 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.organization": {
"name": "organization",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"logo": {
"name": "logo",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"metadata": {
"name": "metadata",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"organization_slug_unique": {
"name": "organization_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.member": {
"name": "member",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"organization_id": {
"name": "organization_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"member_organization_id_organization_id_fk": {
"name": "member_organization_id_organization_id_fk",
"tableFrom": "member",
"tableTo": "organization",
"columnsFrom": [
"organization_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"member_user_id_user_id_fk": {
"name": "member_user_id_user_id_fk",
"tableFrom": "member",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.invitation": {
"name": "invitation",
"schema": "",
@@ -540,149 +689,6 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.member": {
"name": "member",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"organization_id": {
"name": "organization_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"member_organization_id_organization_id_fk": {
"name": "member_organization_id_organization_id_fk",
"tableFrom": "member",
"tableTo": "organization",
"columnsFrom": [
"organization_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"member_user_id_user_id_fk": {
"name": "member_user_id_user_id_fk",
"tableFrom": "member",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.organization": {
"name": "organization",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"logo": {
"name": "logo",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"metadata": {
"name": "metadata",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"organization_slug_unique": {
"name": "organization_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.projects": {
"name": "projects",
"schema": "",
@@ -763,71 +769,6 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.agents": {
"name": "agents",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"last_contact": {
"name": "last_contact",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"agents_slug_unique": {
"name": "agents_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.backups": {
"name": "backups",
"schema": "",
@@ -952,7 +893,7 @@
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
"notNull": false
},
"backup_policy": {
"name": "backup_policy",
@@ -1002,7 +943,7 @@
"name": "project_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
"notNull": false
}
},
"indexes": {},
@@ -1119,6 +1060,71 @@
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.agents": {
"name": "agents",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"last_contact": {
"name": "last_contact",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"agents_slug_unique": {
"name": "agents_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
@@ -1126,8 +1132,8 @@
"name": "dbms_status",
"schema": "public",
"values": [
"active",
"inactive"
"postgresql",
"mongodb"
]
},
"public.status": {
+160 -182
View File
@@ -1,6 +1,6 @@
{
"id": "4989b61d-a294-467d-a743-2727ab6f28b5",
"prevId": "d29f51ca-2c37-4d42-9fb5-19235fb84b32",
"id": "d782a269-0b75-41b0-b70e-e3bf214f4f80",
"prevId": "3d165821-b11d-4be7-b3fb-83c4485e44a8",
"version": "7",
"dialect": "postgresql",
"tables": {
@@ -463,8 +463,8 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.invitation": {
"name": "invitation",
"public.organization": {
"name": "organization",
"schema": "",
"columns": {
"id": {
@@ -474,74 +474,56 @@
"notNull": true,
"default": "gen_random_uuid()"
},
"organization_id": {
"name": "organization_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"logo": {
"name": "logo",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
"notNull": true,
"default": "now()"
},
"inviter_id": {
"name": "inviter_id",
"type": "uuid",
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true
"notNull": false
},
"metadata": {
"name": "metadata",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"invitation_organization_id_organization_id_fk": {
"name": "invitation_organization_id_organization_id_fk",
"tableFrom": "invitation",
"tableTo": "organization",
"columnsFrom": [
"organization_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"invitation_inviter_id_user_id_fk": {
"name": "invitation_inviter_id_user_id_fk",
"tableFrom": "invitation",
"tableTo": "user",
"columnsFrom": [
"inviter_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"organization_slug_unique": {
"name": "organization_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
@@ -624,8 +606,8 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.organization": {
"name": "organization",
"public.invitation": {
"name": "invitation",
"schema": "",
"columns": {
"id": {
@@ -635,56 +617,74 @@
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"organization_id": {
"name": "organization_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true
},
"logo": {
"name": "logo",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"expires_at": {
"name": "expires_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
"notNull": true
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"inviter_id": {
"name": "inviter_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"metadata": {
"name": "metadata",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"organization_slug_unique": {
"name": "organization_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
"foreignKeys": {
"invitation_organization_id_organization_id_fk": {
"name": "invitation_organization_id_organization_id_fk",
"tableFrom": "invitation",
"tableTo": "organization",
"columnsFrom": [
"organization_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"invitation_inviter_id_user_id_fk": {
"name": "invitation_inviter_id_user_id_fk",
"tableFrom": "invitation",
"tableTo": "user",
"columnsFrom": [
"inviter_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
@@ -769,71 +769,6 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.agents": {
"name": "agents",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"last_contact": {
"name": "last_contact",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"agents_slug_unique": {
"name": "agents_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.backups": {
"name": "backups",
"schema": "",
@@ -879,29 +814,7 @@
"notNull": true
}
},
"indexes": {
"database_id_status_unique": {
"name": "database_id_status_unique",
"columns": [
{
"expression": "database_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "status",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"indexes": {},
"foreignKeys": {
"backups_database_id_databases_id_fk": {
"name": "backups_database_id_databases_id_fk",
@@ -958,7 +871,7 @@
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
"notNull": false
},
"backup_policy": {
"name": "backup_policy",
@@ -1008,7 +921,7 @@
"name": "project_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
"notNull": false
}
},
"indexes": {},
@@ -1125,6 +1038,71 @@
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.agents": {
"name": "agents",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"last_contact": {
"name": "last_contact",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"agents_slug_unique": {
"name": "agents_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
@@ -1132,8 +1110,8 @@
"name": "dbms_status",
"schema": "public",
"values": [
"active",
"inactive"
"postgresql",
"mongodb"
]
},
"public.status": {
+4 -4
View File
@@ -5,15 +5,15 @@
{
"idx": 0,
"version": "7",
"when": 1744888916262,
"tag": "0000_round_king_cobra",
"when": 1752684754669,
"tag": "0000_awesome_nomad",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1747319063637,
"tag": "0001_small_anthem",
"when": 1752689557905,
"tag": "0001_wealthy_leo",
"breakpoints": true
}
]
+1 -1
View File
@@ -38,7 +38,7 @@ export const backup = pgTable(
.notNull()
.references(() => database.id, { onDelete: "cascade" }),
},
(table) => [uniqueIndex("database_id_status_unique").on(table.databaseId, table.status)]
// (table) => [uniqueIndex("database_id_status_unique").on(table.databaseId, table.status)]
);
export const restoration = pgTable("restorations", {
+1 -1
View File
@@ -2,7 +2,7 @@ import { pgEnum } from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const dbmsEnum = pgEnum("dbms_status", ["active", "inactive"]);
export const dbmsEnum = pgEnum("dbms_status", ["postgresql", "mongodb"]);
export const statusEnum = pgEnum("status", ["waiting", "ongoing", "failed", "success"]);
export const typeStorageEnum = pgEnum("type_storage", ["local", "s3"]);
+125 -116
View File
@@ -1,6 +1,6 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import {ColumnDef} from "@tanstack/react-table";
import {
DropdownMenu,
DropdownMenuContent,
@@ -9,134 +9,143 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Download, MoreHorizontal, Trash2 } from "lucide-react";
import { ReloadIcon } from "@radix-ui/react-icons";
import { Backup } from "@prisma/client";
import { getFileUrlPresignedLocal } from "@/features/upload/private/upload.action";
import { useMutation } from "@tanstack/react-query";
import { createRestorationAction, deleteBackupAction } from "@/features/dashboard/restore/restore.action";
import { toast } from "sonner";
import { useRouter } from "next/navigation";
import { StatusBadge } from "@/components/wrappers/common/status-badge";
import { TooltipCustom } from "@/components/wrappers/common/tooltipCustom/TooltipCustom";
import {Button} from "@/components/ui/button";
import {Download, MoreHorizontal, Trash2} from "lucide-react";
import {ReloadIcon} from "@radix-ui/react-icons";
import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action";
import {useMutation} from "@tanstack/react-query";
import {createRestorationAction, deleteBackupAction} from "@/features/dashboard/restore/restore.action";
import {toast} from "sonner";
import {useRouter} from "next/navigation";
import {StatusBadge} from "@/components/wrappers/common/status-badge";
import {TooltipCustom} from "@/components/wrappers/common/tooltipCustom/TooltipCustom";
import {Backup} from "@/db/schema/06_database";
import {formatFrenchDate} from "@/utils/date-formatting";
export const backupColumns: ColumnDef<Backup>[] = [
{
accessorKey: "id",
header: "Reference",
},
{
accessorKey: "createdAt",
header: "Created At",
cell: ({ row }) => {
return new Date(row.getValue("createdAt")).toLocaleString("fr-FR");
export function backupColumns(isAlreadyRestore: boolean): ColumnDef<Backup>[] {
return [
{
accessorKey: "id",
header: "Reference",
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return <StatusBadge status={row.getValue("status")} />;
{
accessorKey: "createdAt",
header: "Created At",
cell: ({row}) => {
return formatFrenchDate(row.getValue("createdAt"))
},
},
},
{
id: "actions",
cell: ({ row, table }) => {
const status = row.getValue("status");
const rowData: Backup = row.original;
const fileName = rowData.file;
// @ts-ignore
const { extendedProps } = table.options.meta;
{
accessorKey: "status",
header: "Status",
cell: ({row}) => {
return <StatusBadge status={row.getValue("status")}/>;
},
},
{
id: "actions",
cell: ({row, table}) => {
const status = row.getValue("status");
const rowData: Backup = row.original;
const fileName = rowData.file;
const router = useRouter();
const router = useRouter();
const mutationRestore = useMutation({
mutationFn: async () => {
const restoration = await createRestorationAction({
backupId: rowData.id,
databaseId: rowData.databaseId,
});
if (restoration.data.success) {
toast.success(restoration.data.actionSuccess?.message || "Restoration created successfully!");
router.refresh();
} else {
toast.error(restoration.serverError || "Failed to create restoration.");
}
},
});
const mutationRestore = useMutation({
mutationFn: async () => {
const restoration = await createRestorationAction({
backupId: rowData.id,
databaseId: rowData.databaseId,
});
// @ts-ignore
if (restoration.data.success) {
// @ts-ignore
toast.success(restoration.data.actionSuccess?.message || "Restoration created successfully!");
router.refresh();
} else {
// @ts-ignore
toast.error(restoration.serverError || "Failed to create restoration.");
}
},
});
const mutationDeleteBackup = useMutation({
mutationFn: async () => {
const restoration = await deleteBackupAction({
backupId: rowData.id,
databaseId: rowData.databaseId,
});
if (restoration.data.success) {
toast.success(restoration.data.actionSuccess.message);
router.refresh();
} else {
toast.error(restoration.data.actionError.message);
}
},
});
const mutationDeleteBackup = useMutation({
mutationFn: async () => {
const restoration = await deleteBackupAction({
backupId: rowData.id,
databaseId: rowData.databaseId,
});
// @ts-ignore
if (restoration.data.success) {
// @ts-ignore
toast.success(restoration.data.actionSuccess.message);
router.refresh();
} else {
// @ts-ignore
toast.error(restoration.data.actionError.message);
}
},
});
const handleRestore = async () => {
await mutationRestore.mutateAsync();
};
const handleRestore = async () => {
await mutationRestore.mutateAsync();
};
const handleDelete = async () => {
await mutationDeleteBackup.mutateAsync();
};
const handleDelete = async () => {
await mutationDeleteBackup.mutateAsync();
};
const handleDownload = async (fileName: string) => {
const url = await getFileUrlPresignedLocal(fileName);
window.open(url, "_self");
};
const handleDownload = async (fileName: string) => {
const url = await getFileUrlPresignedLocal(fileName);
window.open(url, "_self");
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
{status == "success" ? (
<>
<TooltipCustom disabled={extendedProps} text="Already a restoration waiting">
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4"/>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
{status == "success" ? (
<>
<TooltipCustom disabled={isAlreadyRestore} text="Already a restoration waiting">
<DropdownMenuItem
disabled={mutationRestore.isPending || isAlreadyRestore}
onClick={async () => {
await handleRestore();
}}
>
<ReloadIcon/> Restore
</DropdownMenuItem>
</TooltipCustom>
<DropdownMenuItem
disabled={mutationRestore.isPending || extendedProps}
onClick={async () => {
await handleRestore();
await handleDownload(fileName ?? "");
}}
>
<ReloadIcon /> Restore
<Download/> Download
</DropdownMenuItem>
</TooltipCustom>
<DropdownMenuItem
onClick={async () => {
await handleDownload(fileName);
}}
>
<Download /> Download
</DropdownMenuItem>
</>
) : null}
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-red-600"
onClick={async () => {
await handleDelete();
}}
>
<Trash2 /> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
</>
) : null}
<DropdownMenuSeparator/>
<DropdownMenuItem
className="text-red-600"
onClick={async () => {
await handleDelete();
}}
>
<Trash2/> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
},
];
];
}
+2 -1
View File
@@ -7,6 +7,7 @@ import { MoreHorizontal } from "lucide-react";
import { ReloadIcon } from "@radix-ui/react-icons";
import { StatusBadge } from "@/components/wrappers/common/status-badge";
import {Restoration} from "@/db/schema/06_database";
import {formatFrenchDate} from "@/utils/date-formatting";
export const restoreColumns: ColumnDef<Restoration>[] = [
{
@@ -17,7 +18,7 @@ export const restoreColumns: ColumnDef<Restoration>[] = [
accessorKey: "createdAt",
header: "Created At",
cell: ({ row }) => {
return new Date(row.getValue("createdAt")).toLocaleString("fr-FR");
return formatFrenchDate(row.getValue("createdAt"))
},
},
{
@@ -1,3 +1,4 @@
"use server"
import { userAction } from "@/safe-actions";
import { z } from "zod";
import { ServerActionResult } from "@/types/action-type";
@@ -58,6 +59,7 @@ export const deleteBackupAction = userAction
}
});
// Create Restoration Action (Drizzle version)
export const createRestorationAction = userAction
.schema(
+7 -1
View File
@@ -12,6 +12,12 @@ export function timeAgo(rawDate: string | number | Date) {
export function formatDateLastContact(lastContact: string | number | Date | null) {
console.log(lastContact)
return lastContact
? format(new Date(lastContact), 'dd/MM/yyyy HH:mm')
? formatFrenchDate(lastContact)
: "Never connected."
}
export function formatFrenchDate(date: string | number | Date) {
return new Date(date).toLocaleString("fr-FR", {
timeZone: "Europe/Paris",
});
}
+2 -2
View File
@@ -5,7 +5,7 @@ export const getServerUrl = () => {
return window.location.origin;
}
if (env.NODE_ENV === "development") {
return `http://${env.NEXT_PUBLIC_PROJECT_URL}`;
return `${env.NEXT_PUBLIC_PROJECT_URL}`;
}
return `https://${env.NEXT_PUBLIC_PROJECT_URL}`;
return `${env.NEXT_PUBLIC_PROJECT_URL}`;
};