diff --git a/apps/api/src/auth/token.ts b/apps/api/src/auth/token.ts index bcc21249..5490071d 100644 --- a/apps/api/src/auth/token.ts +++ b/apps/api/src/auth/token.ts @@ -110,6 +110,7 @@ export async function sessionFromCookies( email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, workspaces: true, @@ -130,6 +131,7 @@ export async function sessionFromCookies( email: user.email, name: user.name, picture: user.picture, + lastVisitedWorkspaceId: user.lastVisitedWorkspaceId, createdAt: user.createdAt, updatedAt: user.updatedAt, }, @@ -319,9 +321,7 @@ export const isAuthorizedForDataSource = async ( return result !== null } case 'databrickssql': { - const result = await prisma().databricksSQLDataSource.findFirst( - query, - ) + const result = await prisma().databricksSQLDataSource.findFirst(query) return result !== null } } diff --git a/apps/api/src/websocket/workspace/index.ts b/apps/api/src/websocket/workspace/index.ts index c988af54..b3e3de31 100644 --- a/apps/api/src/websocket/workspace/index.ts +++ b/apps/api/src/websocket/workspace/index.ts @@ -37,6 +37,12 @@ export const joinWorkspace = if (!socket.rooms.has(workspaceId)) { await socket.join(workspaceId) + await prisma().user.update({ + where: { id: session.user.id }, + data: { + lastVisitedWorkspaceId: workspaceId, + }, + }) } await emitInitialData(io, socket, workspaceId) diff --git a/apps/api/src/workspace/index.ts b/apps/api/src/workspace/index.ts index 7d3168e5..668b6ba3 100644 --- a/apps/api/src/workspace/index.ts +++ b/apps/api/src/workspace/index.ts @@ -50,6 +50,7 @@ export class WorkspaceCreator implements IWorkspaceCreator { email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, diff --git a/apps/api/src/yjs/v2/executor/executor.ts b/apps/api/src/yjs/v2/executor/executor.ts index 2206bb4b..80c05791 100644 --- a/apps/api/src/yjs/v2/executor/executor.ts +++ b/apps/api/src/yjs/v2/executor/executor.ts @@ -63,6 +63,7 @@ export function unknownUser(): ApiUser { name: 'unknown', email: 'unknown', picture: null, + lastVisitedWorkspaceId: null, createdAt: new Date(), updatedAt: new Date(), } diff --git a/apps/web/src/hooks/useSessionRedirect.ts b/apps/web/src/hooks/useSessionRedirect.ts index 2db02647..ea3813b3 100644 --- a/apps/web/src/hooks/useSessionRedirect.ts +++ b/apps/web/src/hooks/useSessionRedirect.ts @@ -38,10 +38,19 @@ export const useSessionRedirect = (shouldRedirect = true) => { } else { redirectToLogin(router) } - } else if (workspaces.data.length === 0) { - signOut() } else { - router.replace(`/workspaces/${workspaces.data[0].id}/documents`) + const user = session.data + const workspace = + workspaces.data.find( + (workspace) => workspace.id === user.lastVisitedWorkspaceId + ) ?? + workspaces.data.find((workspace) => workspace.ownerId === user.id) ?? + workspaces.data[0] + if (workspace) { + router.replace(`/workspaces/${workspace.id}/documents`) + } else { + signOut() + } } }, [properties, workspaces, session, router, shouldRedirect, signOut]) } diff --git a/apps/web/src/pages/workspaces/index.tsx b/apps/web/src/pages/workspaces/index.tsx index 9a561a58..5224d370 100644 --- a/apps/web/src/pages/workspaces/index.tsx +++ b/apps/web/src/pages/workspaces/index.tsx @@ -1,4 +1,4 @@ -import { useSignout } from '@/hooks/useAuth' +import { useSession, useSignout } from '@/hooks/useAuth' import { useWorkspaces } from '@/hooks/useWorkspaces' import { useRouter } from 'next/router' import { useEffect } from 'react' @@ -7,13 +7,19 @@ export default function WorkspacesPage() { const router = useRouter() const [{ isLoading, data }] = useWorkspaces() const signOut = useSignout() + const session = useSession() useEffect(() => { - if (isLoading) { + if (isLoading || session.isLoading) { return } - const workspace = data[0] + const workspace = + data.find( + (workspace) => workspace.id === session.data?.lastVisitedWorkspaceId + ) ?? + data.find((workspace) => workspace.ownerId === session.data?.id) ?? + data[0] if (!workspace) { signOut() } else { diff --git a/packages/database/prisma/migrations/20241129202947_add_last_visited_workspace_id/migration.sql b/packages/database/prisma/migrations/20241129202947_add_last_visited_workspace_id/migration.sql new file mode 100644 index 00000000..eecb2e5c --- /dev/null +++ b/packages/database/prisma/migrations/20241129202947_add_last_visited_workspace_id/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "lastVisitedWorkspaceId" UUID; + +-- AddForeignKey +ALTER TABLE "User" ADD CONSTRAINT "User_lastVisitedWorkspaceId_fkey" FOREIGN KEY ("lastVisitedWorkspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma index 2deb6944..cc5ba673 100644 --- a/packages/database/prisma/schema.prisma +++ b/packages/database/prisma/schema.prisma @@ -398,11 +398,13 @@ model User { createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt - workspacesInvitees UserWorkspace[] @relation("UserWorkspaceInviter") - workspaces UserWorkspace[] @relation("UserWorkspaceUser") - ownedWorkspaces Workspace[] - confirmedAt DateTime? + workspacesInvitees UserWorkspace[] @relation("UserWorkspaceInviter") + workspaces UserWorkspace[] @relation("UserWorkspaceUser") + ownedWorkspaces Workspace[] + confirmedAt DateTime? + lastVisitedWorkspaceId String? @db.Uuid + lastVisitedWorkspace Workspace? @relation(fields: [lastVisitedWorkspaceId], references: [id], name: "lastVisitedWorkspace", onDelete: SetNull) comments Comment[] Favorite Favorite[] UserYjsAppDocument UserYjsAppDocument[] @@ -502,6 +504,7 @@ model Workspace { snowflakeDataSources SnowflakeDataSource[] databricksSQLDataSources DatabricksSQLDataSource[] environmentVariables EnvironmentVariable[] + lastVisitors User[] @relation("lastVisitedWorkspace") } enum UserWorkspaceRole { diff --git a/packages/database/src/users.ts b/packages/database/src/users.ts index 2f4412a0..7652b38d 100644 --- a/packages/database/src/users.ts +++ b/packages/database/src/users.ts @@ -26,6 +26,7 @@ export async function createUser( picture: true, createdAt: true, updatedAt: true, + lastVisitedWorkspaceId: true, }, }) } @@ -40,6 +41,7 @@ export async function getUserById(id: string): Promise { email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, @@ -58,6 +60,7 @@ export async function getUserByEmail(email: string): Promise { email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, @@ -78,6 +81,7 @@ export async function listWorkspaceUsers( email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, @@ -111,6 +115,7 @@ export async function addUserToWorkspace( email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, @@ -143,6 +148,7 @@ export async function deleteUserFromWorkspace( email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, }, @@ -170,6 +176,7 @@ export async function confirmUser(userId: string): Promise { email: true, name: true, picture: true, + lastVisitedWorkspaceId: true, createdAt: true, updatedAt: true, },