Skip to content

Commit

Permalink
feat: enables sharing of the database config to other users (openlit#307
Browse files Browse the repository at this point in the history
)
  • Loading branch information
AmanAgarwal041 authored Jul 3, 2024
1 parent 38d1fc4 commit da25e21
Show file tree
Hide file tree
Showing 17 changed files with 1,717 additions and 6,721 deletions.
5,222 changes: 0 additions & 5,222 deletions package-lock.json

This file was deleted.

2,237 changes: 918 additions & 1,319 deletions src/client/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@mui/material": "^5.15.21",
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/client": "^5.15.0",
"@radix-ui/react-checkbox": "^1.1.0",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
Expand Down Expand Up @@ -77,4 +78,4 @@
"prisma": {
"seed": "node prisma/seed.js"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-- CreateTable
CREATE TABLE "DatabaseConfigInvitedUser" (
"databaseConfigId" TEXT NOT NULL,
"email" TEXT NOT NULL,
"canEdit" BOOLEAN NOT NULL DEFAULT false,
"canShare" BOOLEAN NOT NULL DEFAULT false,
"canDelete" BOOLEAN NOT NULL DEFAULT false,
CONSTRAINT "DatabaseConfigInvitedUser_databaseConfigId_fkey" FOREIGN KEY ("databaseConfigId") REFERENCES "databaseconfig" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_databaseconfiguser" (
"databaseConfigId" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"isCurrent" BOOLEAN NOT NULL DEFAULT false,
"canEdit" BOOLEAN NOT NULL DEFAULT false,
"canShare" BOOLEAN NOT NULL DEFAULT false,
"canDelete" BOOLEAN NOT NULL DEFAULT false,
"createdAt" DATETIME DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME,
CONSTRAINT "databaseconfiguser_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "databaseconfiguser_databaseConfigId_fkey" FOREIGN KEY ("databaseConfigId") REFERENCES "databaseconfig" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_databaseconfiguser" ("databaseConfigId", "isCurrent", "user_id") SELECT "databaseConfigId", "isCurrent", "user_id" FROM "databaseconfiguser";
DROP TABLE "databaseconfiguser";
ALTER TABLE "new_databaseconfiguser" RENAME TO "databaseconfiguser";
CREATE UNIQUE INDEX "databaseconfiguser_databaseConfigId_user_id_key" ON "databaseconfiguser"("databaseConfigId", "user_id");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

-- CreateIndex
CREATE UNIQUE INDEX "DatabaseConfigInvitedUser_databaseConfigId_email_key" ON "DatabaseConfigInvitedUser"("databaseConfigId", "email");


-- This migration is for updating the permissions to true for the user who created the db config
BEGIN TRANSACTION;

-- Update canEdit, canShare, and canDelete fields for users who created the DatabaseConfig
UPDATE DatabaseConfigUser
SET
canEdit = TRUE,
canShare = TRUE,
canDelete = TRUE
WHERE
DatabaseConfigUser.user_id IN (SELECT DatabaseConfig.user_id FROM DatabaseConfig WHERE DatabaseConfig.id = DatabaseConfigUser.databaseConfigId);

COMMIT;
37 changes: 27 additions & 10 deletions src/client/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,22 @@ model VerificationRequest {

// Database Config
model DatabaseConfig {
id String @id @default(cuid())
id String @id @default(cuid())
name String
environment String @default("production")
username String @default("admin")
environment String @default("production")
username String @default("admin")
password String?
host String @default("127.0.0.1")
port String @default("8123")
database String @default("openlit")
host String @default("127.0.0.1")
port String @default("8123")
database String @default("openlit")
query String?
dbUsers DatabaseConfigUser[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdByUserId String @map("user_id")
createdByUser User @relation(fields: [createdByUserId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdByUserId String @map("user_id")
createdByUser User @relation(fields: [createdByUserId], references: [id])
OpenGround OpenGround[]
dbInvitedUsers DatabaseConfigInvitedUser[]
@@unique([name])
@@map("databaseconfig")
Expand All @@ -99,6 +100,11 @@ model DatabaseConfigUser {
user User @relation(fields: [userId], references: [id])
databaseConfig DatabaseConfig? @relation(fields: [databaseConfigId], references: [id])
isCurrent Boolean @default(false)
canEdit Boolean @default(false)
canShare Boolean @default(false)
canDelete Boolean @default(false)
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
@@unique([databaseConfigId, userId])
@@map("databaseconfiguser")
Expand All @@ -117,3 +123,14 @@ model OpenGround {
@@map("openground")
}

model DatabaseConfigInvitedUser {
databaseConfigId String
databaseConfig DatabaseConfig? @relation(fields: [databaseConfigId], references: [id])
email String
canEdit Boolean @default(false)
canShare Boolean @default(false)
canDelete Boolean @default(false)
@@unique([databaseConfigId, email])
}
5 changes: 4 additions & 1 deletion src/client/prisma/seed.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
async function main() {
console.log("Inside seeding.....");
console.log("Seeding Start.....");
// const defaultPassword = "openlituser"; ⤵
const hashedPassword =
"$2a$10$gh6Odw7fhLRrE1A1OxaHfeWOWKiZEEQpkOAhhCQ.RHx8VWOngwlHO";
Expand Down Expand Up @@ -47,6 +47,9 @@ async function main() {
userId: user.id,
databaseConfigId: dbConfig.id,
isCurrent: true,
canEdit: true,
canDelete: true,
canShare: true,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { MouseEventHandler } from "react";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Switch } from "@/components/ui/switch";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Trash2 } from "lucide-react";
import ShareDialog from "./share-dialog";
import { Checkbox } from "@/components/ui/checkbox";

export type DatabaseConfigTabItemProps = {
id: string;
name: string;
badge?: string;
isCurrent?: boolean;
canDelete?: boolean;
canShare?: boolean;
canEdit?: boolean;
};

export type DatabaseConfigTabsProps = {
items: DatabaseConfigTabItemProps[];
onClickTab: MouseEventHandler<HTMLElement>;
selectedTabId: string;
onClickItemDelete?: MouseEventHandler<SVGSVGElement>;
onClickItemChangeActive: MouseEventHandler<HTMLDivElement>;
addButton?: boolean;
};

const ADD_NEW_ID = "ADD_NEW_ID";

const getCommonCardClasses = (isActive: boolean) =>
`item-element-card flex flex-col p-4 text-sm cursor-pointer relative group w-64 hover:bg-stone-100 dark:hover:bg-stone-700 ${
isActive ? "bg-stone-100 dark:bg-stone-700" : ""
}`;

export default function DatabaseConfigTabs({
items,
onClickTab,
selectedTabId,
onClickItemDelete,
onClickItemChangeActive,
addButton,
}: DatabaseConfigTabsProps) {
return (
<div className="flex overflow-hidden gap-4">
<div className="grid grid-flow-col gap-4 overflow-y-auto grow">
{items.map((item) => (
<Card
className={getCommonCardClasses(selectedTabId === item.id)}
data-item-id={item.id}
key={item.id}
onClick={onClickTab}
>
<div className="flex w-full">
<div className={`flex flex-col grow`}>
<span className="text-ellipsis overflow-hidden whitespace-nowrap mb-3">
{item.name}
</span>
{item.badge && (
<Badge
variant="default"
className={`mr-auto ${
item.isCurrent
? "border-primary bg-primary text-white dark:border-primary dark:bg-primary dark:text-white hover:bg-primary dark:hover:bg-primary"
: ""
}`}
>
{item.badge}
</Badge>
)}
</div>
<div className="flex flex-col h-full space-y-1 items-end">
<Tooltip>
<TooltipTrigger asChild>
<div onClick={onClickItemChangeActive}>
<Checkbox
checked={!!item.isCurrent}
className="data-[state=checked]:bg-primary dark:data-[state=checked]:bg-primary text-white data-[state=checked]:border-primary dark:data-[state=checked]:border-primary data-[state=checked]:ring-offset-primary dark:text-white data-[state=checked]:text-white dark:data-[state=checked]:text-white"
/>
</div>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={5}>
Mark {item.name} as the active database config
</TooltipContent>
</Tooltip>
{item.canDelete && onClickItemDelete && (
<Trash2
className="w-3 h-3 hidden group-hover:inline text-stone-900 dark:text-stone-100"
onClick={onClickItemDelete}
/>
)}
{item.canShare && (
<ShareDialog
id={item.id}
permissions={{
canEdit: item.canEdit,
canDelete: item.canDelete,
canShare: item.canShare,
}}
/>
)}
</div>
</div>
</Card>
))}
</div>
{addButton && (
<Card
className={`${getCommonCardClasses(
selectedTabId === ADD_NEW_ID
)} items-center justify-center text-stone-400 dark:text-stone-400`}
data-item-id={ADD_NEW_ID}
onClick={onClickTab}
>
Add new
</Card>
)}
</div>
);
}
Loading

0 comments on commit da25e21

Please sign in to comment.