mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Organize db exports into client and server versions (#32)
This commit is contained in:
parent
b167eaec1d
commit
67c63b5b46
19 changed files with 130 additions and 112 deletions
|
|
@ -3,7 +3,7 @@
|
|||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import { logger } from '@/lib/server/logger';
|
||||
import { client as db, users, orgs } from '@/db';
|
||||
import { client as db, users, orgs } from '@/db/server';
|
||||
|
||||
import { syncCurrentUser } from '../sync';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { eq } from 'drizzle-orm';
|
|||
import { clerkClient } from '@clerk/nextjs/server';
|
||||
|
||||
import { logger } from '@/lib/server/logger';
|
||||
import { client as db, orgs } from '@/db';
|
||||
import { client as db, orgs } from '@/db/server';
|
||||
|
||||
import { syncOrg } from '../sync';
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ import {
|
|||
|
||||
import type { TimePeriod } from '@/types';
|
||||
import { analytics } from '@/lib/server';
|
||||
import * as db from '@/db';
|
||||
import { inArray } from 'drizzle-orm';
|
||||
import { type User, getUsersById } from '@/db/server';
|
||||
|
||||
/**
|
||||
* captureEvent
|
||||
|
|
@ -106,7 +105,7 @@ const developerUsageSchema = z.object({
|
|||
});
|
||||
|
||||
export type DeveloperUsage = z.infer<typeof developerUsageSchema> & {
|
||||
user: db.User;
|
||||
user: User;
|
||||
};
|
||||
|
||||
export const getDeveloperUsage = async ({
|
||||
|
|
@ -140,25 +139,9 @@ export const getDeveloperUsage = async ({
|
|||
.array(developerUsageSchema)
|
||||
.parse(await resultSet.json());
|
||||
|
||||
const users = (
|
||||
await db.client
|
||||
.select()
|
||||
.from(db.users)
|
||||
.where(
|
||||
inArray(
|
||||
db.users.id,
|
||||
developerUsages.map(({ userId }) => userId),
|
||||
),
|
||||
)
|
||||
).reduce(
|
||||
(acc, user) => ({ ...acc, [user.id]: user }),
|
||||
{} as Record<string, db.User>,
|
||||
);
|
||||
const users = await getUsersById(developerUsages.map(({ userId }) => userId));
|
||||
|
||||
return developerUsages
|
||||
.map((usage) => ({
|
||||
...usage,
|
||||
user: users[usage.userId],
|
||||
}))
|
||||
.map((usage) => ({ ...usage, user: users[usage.userId] }))
|
||||
.filter((usage): usage is DeveloperUsage => !!usage.user);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
type CreateAuditLog,
|
||||
client as db,
|
||||
auditLogs,
|
||||
} from '@/db';
|
||||
} from '@/db/server';
|
||||
|
||||
export const getAuditLogs = async ({
|
||||
orgId,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { sql } from 'drizzle-orm';
|
|||
import { z } from 'zod';
|
||||
|
||||
import { type ApiResponse, ORGANIZATION_ALLOW_ALL } from '@/types';
|
||||
import { client as db, AuditLogTargetType, orgSettings } from '@/db';
|
||||
import { AuditLogTargetType, client as db, orgSettings } from '@/db/server';
|
||||
import { isAuthSuccess, handleError } from '@/lib/server';
|
||||
|
||||
import { validateAuth } from './auth';
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
organizationAllowListSchema,
|
||||
organizationDefaultSettingsSchema,
|
||||
} from '@/types';
|
||||
import { client as db, AuditLogTargetType, orgSettings } from '@/db';
|
||||
import { AuditLogTargetType, client as db, orgSettings } from '@/db/server';
|
||||
import { handleError, isAuthSuccess } from '@/lib/server';
|
||||
|
||||
import { validateAuth } from './auth';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { z } from 'zod';
|
|||
|
||||
import type { ApiResponse } from '@/types';
|
||||
import { handleError, isAuthSuccess } from '@/lib/server';
|
||||
import { AuditLogTargetType } from '@/db';
|
||||
import { AuditLogTargetType } from '@/db/server';
|
||||
|
||||
import { validateAuth } from './auth';
|
||||
import { createAuditLog } from './auditLogs';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
client as db,
|
||||
users,
|
||||
orgs,
|
||||
} from '@/db';
|
||||
} from '@/db/server';
|
||||
import { logger } from '@/lib/server';
|
||||
|
||||
export async function syncCurrentUser({
|
||||
|
|
|
|||
|
|
@ -1,46 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import { ArrowRight, Calendar, Clock, User } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { ArrowRight, Calendar, Clock, User } from 'lucide-react';
|
||||
|
||||
import type { AuditLog } from '@/db';
|
||||
|
||||
type AuditLogDetailsProps = {
|
||||
log: AuditLog;
|
||||
};
|
||||
|
||||
const formatValue = (value: unknown) => {
|
||||
if (value === null || value === undefined) {
|
||||
return <span className="italic text-muted-foreground">None</span>;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return (
|
||||
<ul className="list-disc pl-5">
|
||||
{value.map((item, index) => (
|
||||
<li key={index}>{String(item)}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
{Object.entries(value).map(([key, val]) => (
|
||||
<div key={key} className="grid grid-cols-2 gap-2">
|
||||
<span className="text-sm font-medium">{key}:</span>
|
||||
<span className="text-sm">{String(val)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return String(value);
|
||||
};
|
||||
|
||||
export const AuditLogDetails = ({ log }: AuditLogDetailsProps) => (
|
||||
export const AuditLogDetails = ({ log }: { log: AuditLog }) => (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-2 text-sm text-muted-foreground">
|
||||
|
|
@ -78,3 +41,34 @@ export const AuditLogDetails = ({ log }: AuditLogDetailsProps) => (
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const formatValue = (value: unknown) => {
|
||||
if (value === null || value === undefined) {
|
||||
return <span className="italic text-muted-foreground">None</span>;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return (
|
||||
<ul className="list-disc pl-5">
|
||||
{value.map((item, index) => (
|
||||
<li key={index}>{String(item)}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
{Object.entries(value).map(([key, val]) => (
|
||||
<div key={key} className="grid grid-cols-2 gap-2">
|
||||
<span className="text-sm font-medium">{key}:</span>
|
||||
<span className="text-sm">{String(val)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return String(value);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,26 +1,13 @@
|
|||
import { formatDistance } from 'date-fns';
|
||||
import { Settings, Sliders, Users } from 'lucide-react';
|
||||
|
||||
import { type AuditLog, AuditLogTargetType } from '@/db/schema';
|
||||
import { type AuditLog, AuditLogTargetType } from '@/db';
|
||||
|
||||
type AuditLogEntryProps = {
|
||||
log: AuditLog;
|
||||
onClick: (log: AuditLog) => void;
|
||||
};
|
||||
|
||||
const getIconByType = (type: AuditLogTargetType) => {
|
||||
switch (type) {
|
||||
case AuditLogTargetType.PROVIDER_WHITELIST:
|
||||
return <Settings className="size-4 text-purple-500" />;
|
||||
case AuditLogTargetType.DEFAULT_PARAMETERS:
|
||||
return <Sliders className="size-4 text-green-500" />;
|
||||
case AuditLogTargetType.MEMBER_CHANGE:
|
||||
return <Users className="size-4 text-amber-500" />;
|
||||
default:
|
||||
return <Settings className="size-4 text-gray-500" />;
|
||||
}
|
||||
};
|
||||
|
||||
export const AuditLogEntry = ({ log, onClick }: AuditLogEntryProps) => (
|
||||
<div
|
||||
onClick={() => onClick(log)}
|
||||
|
|
@ -40,3 +27,16 @@ export const AuditLogEntry = ({ log, onClick }: AuditLogEntryProps) => (
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const getIconByType = (type: AuditLogTargetType) => {
|
||||
switch (type) {
|
||||
case AuditLogTargetType.PROVIDER_WHITELIST:
|
||||
return <Settings className="size-4 text-purple-500" />;
|
||||
case AuditLogTargetType.DEFAULT_PARAMETERS:
|
||||
return <Sliders className="size-4 text-green-500" />;
|
||||
case AuditLogTargetType.MEMBER_CHANGE:
|
||||
return <Users className="size-4 text-amber-500" />;
|
||||
default:
|
||||
return <Settings className="size-4 text-gray-500" />;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
5
src/db/enums.ts
Normal file
5
src/db/enums.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum AuditLogTargetType {
|
||||
PROVIDER_WHITELIST = 1,
|
||||
DEFAULT_PARAMETERS = 2,
|
||||
MEMBER_CHANGE = 3, // TODO: Currently no logs of this type are collected.
|
||||
}
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
export * from './client';
|
||||
export * from './schema';
|
||||
// These can safely be imported in client or server environments.
|
||||
|
||||
export * from './enums';
|
||||
export * from './types';
|
||||
|
|
|
|||
1
src/db/queries/index.ts
Normal file
1
src/db/queries/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './users';
|
||||
13
src/db/queries/users.ts
Normal file
13
src/db/queries/users.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { inArray } from 'drizzle-orm';
|
||||
|
||||
import { client as db } from '../db';
|
||||
import { users } from '../schema';
|
||||
import type { User } from '../types';
|
||||
|
||||
export const getUsersById = async (
|
||||
ids: string[],
|
||||
): Promise<Record<string, User>> =>
|
||||
(await db.select().from(users).where(inArray(users.id, ids))).reduce(
|
||||
(acc, user) => ({ ...acc, [user.id]: user }),
|
||||
{} as Record<string, User>,
|
||||
);
|
||||
|
|
@ -15,6 +15,8 @@ import {
|
|||
ORGANIZATION_ALLOW_ALL,
|
||||
} from '@/types';
|
||||
|
||||
import { AuditLogTargetType } from './enums';
|
||||
|
||||
/**
|
||||
* users
|
||||
*/
|
||||
|
|
@ -48,10 +50,6 @@ export const userRelations = relations(users, ({ one }) => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
export type User = typeof users.$inferSelect;
|
||||
|
||||
export type CreateUser = Omit<typeof users.$inferInsert, 'id' | 'createdAt'>;
|
||||
|
||||
/**
|
||||
* organizations
|
||||
*/
|
||||
|
|
@ -83,10 +81,6 @@ export const orgsRelations = relations(orgs, ({ many, one }) => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
export type Org = typeof orgs.$inferSelect;
|
||||
|
||||
export type CreateOrg = Omit<typeof orgs.$inferInsert, 'id' | 'createdAt'>;
|
||||
|
||||
/**
|
||||
* organization_settings
|
||||
*/
|
||||
|
|
@ -122,8 +116,6 @@ export const orgSettingsRelations = relations(orgSettings, ({ one }) => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
export type OrgSettings = typeof orgSettings.$inferSelect;
|
||||
|
||||
/**
|
||||
* audit_logs
|
||||
*/
|
||||
|
|
@ -138,7 +130,7 @@ export const auditLogs = pgTable(
|
|||
orgId: text('organization_id')
|
||||
.notNull()
|
||||
.references(() => orgs.id),
|
||||
targetType: integer('target_type').notNull(), // AuditLogTargetType
|
||||
targetType: integer('target_type').$type<AuditLogTargetType>().notNull(),
|
||||
targetId: text('target_id').notNull(),
|
||||
newValue: jsonb('new_value').notNull(),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
|
|
@ -162,20 +154,3 @@ export const auditLogsRelations = relations(auditLogs, ({ one }) => ({
|
|||
references: [orgs.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export enum AuditLogTargetType {
|
||||
PROVIDER_WHITELIST = 1,
|
||||
DEFAULT_PARAMETERS = 2,
|
||||
MEMBER_CHANGE = 3, // TODO: Currently no logs of this type are collected.
|
||||
}
|
||||
|
||||
export type AuditLog = typeof auditLogs.$inferSelect & {
|
||||
targetType: AuditLogTargetType;
|
||||
};
|
||||
|
||||
export type CreateAuditLog = Omit<
|
||||
typeof auditLogs.$inferInsert,
|
||||
'id' | 'createdAt'
|
||||
> & {
|
||||
targetType: AuditLogTargetType;
|
||||
};
|
||||
|
|
|
|||
7
src/db/server.ts
Normal file
7
src/db/server.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// These can only be imported in a server (node.js) environment.
|
||||
|
||||
export * from './index';
|
||||
|
||||
export * from './db';
|
||||
export * from './schema';
|
||||
export * from './queries';
|
||||
38
src/db/types.ts
Normal file
38
src/db/types.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import type { users, orgs, orgSettings, auditLogs } from './schema';
|
||||
|
||||
type Generated = 'id' | 'createdAt' | 'updatedAt';
|
||||
|
||||
/**
|
||||
* users
|
||||
*/
|
||||
|
||||
export type User = typeof users.$inferSelect;
|
||||
|
||||
export type CreateUser = Omit<typeof users.$inferInsert, Generated>;
|
||||
|
||||
/**
|
||||
* orgs
|
||||
*/
|
||||
|
||||
export type Org = typeof orgs.$inferSelect;
|
||||
|
||||
export type CreateOrg = Omit<typeof orgs.$inferInsert, Generated>;
|
||||
|
||||
/**
|
||||
* orgSettings
|
||||
*/
|
||||
|
||||
export type OrgSettings = typeof orgSettings.$inferSelect;
|
||||
|
||||
export type CreateOrgSettings = Omit<
|
||||
typeof orgSettings.$inferInsert,
|
||||
Generated
|
||||
>;
|
||||
|
||||
/**
|
||||
* auditLogs
|
||||
*/
|
||||
|
||||
export type AuditLog = typeof auditLogs.$inferSelect;
|
||||
|
||||
export type CreateAuditLog = Omit<typeof auditLogs.$inferInsert, Generated>;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { sql } from 'drizzle-orm';
|
||||
|
||||
import { Env } from '@/lib/server';
|
||||
import { testDb, disconnect } from '@/db';
|
||||
import { testDb, disconnect } from '@/db/server';
|
||||
|
||||
async function resetTestDatabase() {
|
||||
const db = testDb!;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue