/ opencodehub / src / db / schema / inbox-sections.ts
swadhinbiswas Fix: Add date validation in analysis.ts to prevent RangeError · 1/20/2026
a7662cd
104 lines · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
 * Inbox Sections Schema - Drizzle ORM
 * Custom inbox sections with user-defined filters (Graphite-style)
 */

import { relations } from "drizzle-orm";
import { boolean, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { users } from "./users";

/**
 * Custom inbox sections allow users to create personalized PR views
 * Similar to Graphite's customizable inbox
 */
export const inboxSections = pgTable("inbox_sections", {
    id: text("id").primaryKey(),
    userId: text("user_id")
        .notNull()
        .references(() => users.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    icon: text("icon"), // lucide icon name
    color: text("color"), // hex color
    filters: text("filters"), // JSON - filter configuration
    position: integer("position").notNull().default(0),
    isDefault: boolean("is_default").default(false),
    isCollapsed: boolean("is_collapsed").default(false),
    showCount: boolean("show_count").default(true),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

/**
 * Filter configuration structure:
 * {
 *   author: string[],      // filter by PR author usernames
 *   reviewer: string[],    // filter by requested reviewer
 *   label: string[],       // filter by labels
 *   repository: string[],  // filter by repo (owner/name)
 *   state: 'open' | 'closed' | 'merged' | 'draft',
 *   ciStatus: 'pending' | 'success' | 'failure',
 *   isAssignedToMe: boolean,
 *   isReviewRequested: boolean,
 *   hasMyReview: boolean,
 *   isInStack: boolean,
 *   updatedWithin: '1h' | '1d' | '1w' | '1m',
 *   excludeLabels: string[],
 *   excludeAuthors: string[],
 * }
 */

/**
 * Shared inbox sections for team collaboration
 */
export const sharedInboxSections = pgTable("shared_inbox_sections", {
    id: text("id").primaryKey(),
    sectionId: text("section_id")
        .notNull()
        .references(() => inboxSections.id, { onDelete: "cascade" }),
    sharedWithUserId: text("shared_with_user_id")
        .references(() => users.id, { onDelete: "cascade" }),
    sharedWithTeamId: text("shared_with_team_id"), // Team ID if shared with team
    permission: text("permission").notNull().default("view"), // view, edit
    createdAt: timestamp("created_at").notNull().defaultNow(),
});

// Relations
export const inboxSectionsRelations = relations(inboxSections, ({ one, many }) => ({
    user: one(users, {
        fields: [inboxSections.userId],
        references: [users.id],
    }),
    sharedWith: many(sharedInboxSections),
}));

export const sharedInboxSectionsRelations = relations(sharedInboxSections, ({ one }) => ({
    section: one(inboxSections, {
        fields: [sharedInboxSections.sectionId],
        references: [inboxSections.id],
    }),
    sharedWithUser: one(users, {
        fields: [sharedInboxSections.sharedWithUserId],
        references: [users.id],
    }),
}));

// Types
export type InboxSection = typeof inboxSections.$inferSelect;
export type SharedInboxSection = typeof sharedInboxSections.$inferSelect;

export interface InboxSectionFilters {
    author?: string[];
    reviewer?: string[];
    label?: string[];
    repository?: string[];
    state?: "open" | "closed" | "merged" | "draft";
    ciStatus?: "pending" | "success" | "failure";
    isAssignedToMe?: boolean;
    isReviewRequested?: boolean;
    hasMyReview?: boolean;
    isInStack?: boolean;
    updatedWithin?: "1h" | "1d" | "1w" | "1m";
    excludeLabels?: string[];
    excludeAuthors?: string[];
}