feat(boards): add responsive layout system (#2271)

This commit is contained in:
Meier Lukas
2025-02-23 17:34:56 +01:00
committed by GitHub
parent 2085b5ece2
commit 7761dc29c8
98 changed files with 11770 additions and 1694 deletions

67
packages/db/collection.ts Normal file
View File

@@ -0,0 +1,67 @@
import type { InferInsertModel } from "drizzle-orm";
import { objectEntries } from "@homarr/common";
import type { HomarrDatabase, HomarrDatabaseMysql } from "./driver";
import { env } from "./env";
import * as schema from "./schema";
type TableKey = {
[K in keyof typeof schema]: (typeof schema)[K] extends { _: { brand: "Table" } } ? K : never;
}[keyof typeof schema];
export const createDbInsertCollectionForTransaction = <TTableKey extends TableKey>(
tablesInInsertOrder: TTableKey[],
) => {
const context = tablesInInsertOrder.reduce(
(acc, key) => {
acc[key] = [];
return acc;
},
{} as { [K in TTableKey]: InferInsertModel<(typeof schema)[K]>[] },
);
return {
...context,
insertAll: (db: HomarrDatabase) => {
db.transaction((transaction) => {
for (const [key, values] of objectEntries(context)) {
if (values.length >= 1) {
transaction
.insert(schema[key])
.values(values as never)
.run();
}
}
});
},
insertAllAsync: async (db: HomarrDatabaseMysql) => {
await db.transaction(async (transaction) => {
for (const [key, values] of objectEntries(context)) {
if (values.length >= 1) {
// Below is actually the mysqlSchema when the driver is mysql
await transaction.insert(schema[key] as never).values(values as never);
}
}
});
},
};
};
export const createDbInsertCollectionWithoutTransaction = <TTableKey extends TableKey>(
tablesInInsertOrder: TTableKey[],
) => {
const { insertAll, insertAllAsync, ...collection } = createDbInsertCollectionForTransaction(tablesInInsertOrder);
return {
...collection,
insertAllAsync: async (db: HomarrDatabase) => {
if (env.DB_DRIVER !== "mysql2") {
insertAll(db);
return;
}
await insertAllAsync(db as unknown as HomarrDatabaseMysql);
},
};
};

View File

@@ -0,0 +1,50 @@
CREATE TABLE `item_layout` (
`item_id` varchar(64) NOT NULL,
`section_id` varchar(64) NOT NULL,
`layout_id` varchar(64) NOT NULL,
`x_offset` int NOT NULL,
`y_offset` int NOT NULL,
`width` int NOT NULL,
`height` int NOT NULL,
CONSTRAINT `item_layout_item_id_section_id_layout_id_pk` PRIMARY KEY(`item_id`,`section_id`,`layout_id`)
);
--> statement-breakpoint
CREATE TABLE `layout` (
`id` varchar(64) NOT NULL,
`name` varchar(32) NOT NULL,
`board_id` varchar(64) NOT NULL,
`column_count` tinyint NOT NULL,
`breakpoint` smallint NOT NULL DEFAULT 0,
CONSTRAINT `layout_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `section_layout` (
`section_id` varchar(64) NOT NULL,
`layout_id` varchar(64) NOT NULL,
`parent_section_id` varchar(64),
`x_offset` int NOT NULL,
`y_offset` int NOT NULL,
`width` int NOT NULL,
`height` int NOT NULL,
CONSTRAINT `section_layout_section_id_layout_id_pk` PRIMARY KEY(`section_id`,`layout_id`)
);
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_item_id_item_id_fk` FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_layout_id_layout_id_fk` FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `layout` ADD CONSTRAINT `layout_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_layout_id_layout_id_fk` FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_parent_section_id_section_id_fk` FOREIGN KEY (`parent_section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
INSERT INTO `layout`(`id`, `name`, `board_id`, `column_count`) SELECT `id`, 'Base', `id`, `column_count` FROM `board`;
--> statement-breakpoint
INSERT INTO `item_layout`(`item_id`, `section_id`, `layout_id`, `x_offset`, `y_offset`, `width`, `height`) SELECT `item`.`id`, `section`.`id`, `board`.`id`, `item`.`x_offset`, `item`.`y_offset`, `item`.`width`, `item`.`height` FROM `board` LEFT JOIN `section` ON `section`.`board_id`=`board`.`id` LEFT JOIN `item` ON `item`.`section_id`=`section`.`id` WHERE `item`.`id` IS NOT NULL;
--> statement-breakpoint
INSERT INTO `section_layout`(`section_id`, `layout_id`, `parent_section_id`, `x_offset`, `y_offset`, `width`, `height`) SELECT `section`.`id`, `board`.`id`, `section`.`parent_section_id`, `section`.`x_offset`, `section`.`y_offset`, `section`.`width`, `section`.`height` FROM `board` LEFT JOIN `section` ON `section`.`board_id`=`board`.`id` WHERE `section`.`id` IS NOT NULL AND `section`.`kind` = 'dynamic';

View File

@@ -0,0 +1,36 @@
-- Custom SQL migration file, put your code below! --
ALTER TABLE `item` DROP FOREIGN KEY `item_section_id_section_id_fk`;
--> statement-breakpoint
ALTER TABLE `section` DROP FOREIGN KEY `section_parent_section_id_section_id_fk`;
--> statement-breakpoint
ALTER TABLE `section` MODIFY COLUMN `x_offset` int;
--> statement-breakpoint
ALTER TABLE `section` MODIFY COLUMN `y_offset` int;
--> statement-breakpoint
ALTER TABLE `item` ADD `board_id` varchar(64);
--> statement-breakpoint
ALTER TABLE `item` ADD CONSTRAINT `item_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
UPDATE `item` JOIN `section` ON `item`.`section_id`=`section`.`id` SET `item`.`board_id` = `section`.`board_id`;
--> statement-breakpoint
ALTER TABLE `item` MODIFY COLUMN `board_id` varchar(64) NOT NULL;
--> statement-breakpoint
ALTER TABLE `board` DROP COLUMN `column_count`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `section_id`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `x_offset`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `y_offset`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `width`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `height`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `width`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `height`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `parent_section_id`;
--> statement-breakpoint
UPDATE `section` SET `x_offset` = NULL, `y_offset` = NULL WHERE `kind` = 'dynamic';

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -204,6 +204,20 @@
"when": 1740086765989,
"tag": "0028_add_app_ping_url",
"breakpoints": true
},
{
"idx": 29,
"version": "5",
"when": 1740255915876,
"tag": "0029_add_layouts",
"breakpoints": true
},
{
"idx": 30,
"version": "5",
"when": 1740256006328,
"tag": "0030_migrate_item_and_section_for_layouts",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,42 @@
CREATE TABLE `item_layout` (
`item_id` text NOT NULL,
`section_id` text NOT NULL,
`layout_id` text NOT NULL,
`x_offset` integer NOT NULL,
`y_offset` integer NOT NULL,
`width` integer NOT NULL,
`height` integer NOT NULL,
PRIMARY KEY(`item_id`, `section_id`, `layout_id`),
FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `layout` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`board_id` text NOT NULL,
`column_count` integer NOT NULL,
`breakpoint` integer DEFAULT 0 NOT NULL,
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `section_layout` (
`section_id` text NOT NULL,
`layout_id` text NOT NULL,
`parent_section_id` text,
`x_offset` integer NOT NULL,
`y_offset` integer NOT NULL,
`width` integer NOT NULL,
`height` integer NOT NULL,
PRIMARY KEY(`section_id`, `layout_id`),
FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`parent_section_id`) REFERENCES `section`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO "layout"("id", "name", "board_id", "column_count") SELECT id, 'Base', id, column_count FROM board;
--> statement-breakpoint
INSERT INTO "item_layout"("item_id", "section_id", "layout_id", "x_offset", "y_offset", "width", "height") SELECT item.id, section.id, board.id, item.x_offset, item.y_offset, item.width, item.height FROM board LEFT JOIN section ON section.board_id=board.id LEFT JOIN item ON item.section_id=section.id WHERE item.id IS NOT NULL;
--> statement-breakpoint
INSERT INTO "section_layout"("section_id", "layout_id", "parent_section_id", "x_offset", "y_offset", "width", "height") SELECT section.id, board.id, section.parent_section_id, section.x_offset, section.y_offset, section.width, section.height FROM board LEFT JOIN section ON section.board_id=board.id WHERE section.id IS NOT NULL AND section.kind = 'dynamic';

View File

@@ -0,0 +1,47 @@
-- Custom SQL migration file, put your code below! --
COMMIT TRANSACTION;
--> statement-breakpoint
PRAGMA foreign_keys=OFF;
--> statement-breakpoint
BEGIN TRANSACTION;
--> statement-breakpoint
CREATE TABLE `__new_item` (
`id` text PRIMARY KEY NOT NULL,
`board_id` text NOT NULL,
`kind` text NOT NULL,
`options` text DEFAULT '{"json": {}}' NOT NULL,
`advanced_options` text DEFAULT '{"json": {}}' NOT NULL,
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_item`("id", "board_id", "kind", "options", "advanced_options") SELECT "item"."id", "section"."board_id", "item"."kind", "item"."options", "item"."advanced_options" FROM `item` LEFT JOIN `section` ON section.id=item.section_id;
--> statement-breakpoint
DROP TABLE `item`;
--> statement-breakpoint
ALTER TABLE `__new_item` RENAME TO `item`;
--> statement-breakpoint
CREATE TABLE `__new_section` (
`id` text PRIMARY KEY NOT NULL,
`board_id` text NOT NULL,
`kind` text NOT NULL,
`x_offset` integer,
`y_offset` integer,
`name` text,
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_section`("id", "board_id", "kind", "x_offset", "y_offset", "name") SELECT "id", "board_id", "kind", "x_offset", "y_offset", "name" FROM `section`;
--> statement-breakpoint
DROP TABLE `section`;
--> statement-breakpoint
ALTER TABLE `__new_section` RENAME TO `section`;
--> statement-breakpoint
UPDATE `section` SET `x_offset` = NULL, `y_offset` = NULL WHERE `kind` = 'dynamic';
--> statement-breakpoint
ALTER TABLE `board` DROP COLUMN `column_count`;
--> statement-breakpoint
COMMIT TRANSACTION;
--> statement-breakpoint
PRAGMA foreign_keys=ON;
--> statement-breakpoint
BEGIN TRANSACTION;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -204,6 +204,20 @@
"when": 1740086746417,
"tag": "0028_add_app_ping_url",
"breakpoints": true
},
{
"idx": 29,
"version": "6",
"when": 1740255687392,
"tag": "0029_add_layouts",
"breakpoints": true
},
{
"idx": 30,
"version": "6",
"when": 1740255968549,
"tag": "0030_migrate_item_and_section_for_layouts",
"breakpoints": true
}
]
}

View File

@@ -7,6 +7,7 @@
"exports": {
".": "./index.ts",
"./client": "./client.ts",
"./collection": "./collection.ts",
"./schema": "./schema/index.ts",
"./test": "./test/index.ts",
"./queries": "./queries/index.ts",

View File

@@ -36,6 +36,9 @@ export const {
users,
verificationTokens,
sectionCollapseStates,
layouts,
itemLayouts,
sectionLayouts,
} = schema;
export type User = InferSelectModel<typeof schema.users>;

View File

@@ -280,7 +280,6 @@ export const boards = mysqlTable("board", {
secondaryColor: text().default("#fd7e14").notNull(),
opacity: int().default(100).notNull(),
customCss: text(),
columnCount: int().default(10).notNull(),
iconColor: text(),
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
disableStatus: boolean().default(false).notNull(),
@@ -322,20 +321,73 @@ export const boardGroupPermissions = mysqlTable(
}),
);
export const layouts = mysqlTable("layout", {
id: varchar({ length: 64 }).notNull().primaryKey(),
name: varchar({ length: 32 }).notNull(),
boardId: varchar({ length: 64 })
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
columnCount: tinyint().notNull(),
breakpoint: smallint().notNull().default(0),
});
export const itemLayouts = mysqlTable(
"item_layout",
{
itemId: varchar({ length: 64 })
.notNull()
.references(() => items.id, { onDelete: "cascade" }),
sectionId: varchar({ length: 64 })
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
layoutId: varchar({ length: 64 })
.notNull()
.references(() => layouts.id, { onDelete: "cascade" }),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.itemId, table.sectionId, table.layoutId],
}),
}),
);
export const sectionLayouts = mysqlTable(
"section_layout",
{
sectionId: varchar({ length: 64 })
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
layoutId: varchar({ length: 64 })
.notNull()
.references(() => layouts.id, { onDelete: "cascade" }),
parentSectionId: varchar({ length: 64 }).references((): AnyMySqlColumn => sections.id, {
onDelete: "cascade",
}),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.sectionId, table.layoutId],
}),
}),
);
export const sections = mysqlTable("section", {
id: varchar({ length: 64 }).notNull().primaryKey(),
boardId: varchar({ length: 64 })
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
kind: text().$type<SectionKind>().notNull(),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int(),
height: int(),
xOffset: int(),
yOffset: int(),
name: text(),
parentSectionId: varchar({ length: 64 }).references((): AnyMySqlColumn => sections.id, {
onDelete: "cascade",
}),
});
export const sectionCollapseStates = mysqlTable(
@@ -358,14 +410,10 @@ export const sectionCollapseStates = mysqlTable(
export const items = mysqlTable("item", {
id: varchar({ length: 64 }).notNull().primaryKey(),
sectionId: varchar({ length: 64 })
boardId: varchar({ length: 64 })
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
.references(() => boards.id, { onDelete: "cascade" }),
kind: text().$type<WidgetKind>().notNull(),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
options: text().default('{"json": {}}').notNull(), // empty superjson object
advancedOptions: text().default('{"json": {}}').notNull(), // empty superjson object
});
@@ -590,12 +638,14 @@ export const integrationSecretRelations = relations(integrationSecrets, ({ one }
export const boardRelations = relations(boards, ({ many, one }) => ({
sections: many(sections),
items: many(items),
creator: one(users, {
fields: [boards.creatorId],
references: [users.id],
}),
userPermissions: many(boardUserPermissions),
groupPermissions: many(boardGroupPermissions),
layouts: many(layouts),
groupHomes: many(groups, {
relationName: "groupRelations__board__homeBoardId",
}),
@@ -605,12 +655,17 @@ export const boardRelations = relations(boards, ({ many, one }) => ({
}));
export const sectionRelations = relations(sections, ({ many, one }) => ({
items: many(items),
board: one(boards, {
fields: [sections.boardId],
references: [boards.id],
}),
collapseStates: many(sectionCollapseStates),
layouts: many(sectionLayouts, {
relationName: "sectionLayoutRelations__section__sectionId",
}),
children: many(sectionLayouts, {
relationName: "sectionLayoutRelations__section__parentSectionId",
}),
}));
export const sectionCollapseStateRelations = relations(sectionCollapseStates, ({ one }) => ({
@@ -625,11 +680,12 @@ export const sectionCollapseStateRelations = relations(sectionCollapseStates, ({
}));
export const itemRelations = relations(items, ({ one, many }) => ({
section: one(sections, {
fields: [items.sectionId],
references: [sections.id],
}),
integrations: many(integrationItems),
layouts: many(itemLayouts),
board: one(boards, {
fields: [items.boardId],
references: [boards.id],
}),
}));
export const integrationItemRelations = relations(integrationItems, ({ one }) => ({
@@ -650,3 +706,44 @@ export const searchEngineRelations = relations(searchEngines, ({ one, many }) =>
}),
usersWithDefault: many(users),
}));
export const itemLayoutRelations = relations(itemLayouts, ({ one }) => ({
item: one(items, {
fields: [itemLayouts.itemId],
references: [items.id],
}),
section: one(sections, {
fields: [itemLayouts.sectionId],
references: [sections.id],
}),
layout: one(layouts, {
fields: [itemLayouts.layoutId],
references: [layouts.id],
}),
}));
export const sectionLayoutRelations = relations(sectionLayouts, ({ one }) => ({
section: one(sections, {
fields: [sectionLayouts.sectionId],
references: [sections.id],
relationName: "sectionLayoutRelations__section__sectionId",
}),
layout: one(layouts, {
fields: [sectionLayouts.layoutId],
references: [layouts.id],
}),
parentSection: one(sections, {
fields: [sectionLayouts.parentSectionId],
references: [sections.id],
relationName: "sectionLayoutRelations__section__parentSectionId",
}),
}));
export const layoutRelations = relations(layouts, ({ one, many }) => ({
items: many(itemLayouts),
sections: many(sectionLayouts),
board: one(boards, {
fields: [layouts.boardId],
references: [boards.id],
}),
}));

View File

@@ -265,7 +265,6 @@ export const boards = sqliteTable("board", {
secondaryColor: text().default("#fd7e14").notNull(),
opacity: int().default(100).notNull(),
customCss: text(),
columnCount: int().default(10).notNull(),
iconColor: text(),
itemRadius: text().$type<MantineSize>().default("lg").notNull(),
disableStatus: int({ mode: "boolean" }).default(false).notNull(),
@@ -307,20 +306,73 @@ export const boardGroupPermissions = sqliteTable(
}),
);
export const layouts = sqliteTable("layout", {
id: text().notNull().primaryKey(),
name: text().notNull(),
boardId: text()
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
columnCount: int().notNull(),
breakpoint: int().notNull().default(0),
});
export const itemLayouts = sqliteTable(
"item_layout",
{
itemId: text()
.notNull()
.references(() => items.id, { onDelete: "cascade" }),
sectionId: text()
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
layoutId: text()
.notNull()
.references(() => layouts.id, { onDelete: "cascade" }),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.itemId, table.sectionId, table.layoutId],
}),
}),
);
export const sectionLayouts = sqliteTable(
"section_layout",
{
sectionId: text()
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
layoutId: text()
.notNull()
.references(() => layouts.id, { onDelete: "cascade" }),
parentSectionId: text().references((): AnySQLiteColumn => sections.id, {
onDelete: "cascade",
}),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
},
(table) => ({
compoundKey: primaryKey({
columns: [table.sectionId, table.layoutId],
}),
}),
);
export const sections = sqliteTable("section", {
id: text().notNull().primaryKey(),
boardId: text()
.notNull()
.references(() => boards.id, { onDelete: "cascade" }),
kind: text().$type<SectionKind>().notNull(),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int(),
height: int(),
xOffset: int(),
yOffset: int(),
name: text(),
parentSectionId: text().references((): AnySQLiteColumn => sections.id, {
onDelete: "cascade",
}),
});
export const sectionCollapseStates = sqliteTable(
@@ -343,14 +395,10 @@ export const sectionCollapseStates = sqliteTable(
export const items = sqliteTable("item", {
id: text().notNull().primaryKey(),
sectionId: text()
boardId: text()
.notNull()
.references(() => sections.id, { onDelete: "cascade" }),
.references(() => boards.id, { onDelete: "cascade" }),
kind: text().$type<WidgetKind>().notNull(),
xOffset: int().notNull(),
yOffset: int().notNull(),
width: int().notNull(),
height: int().notNull(),
options: text().default('{"json": {}}').notNull(), // empty superjson object
advancedOptions: text().default('{"json": {}}').notNull(), // empty superjson object
});
@@ -576,12 +624,14 @@ export const integrationSecretRelations = relations(integrationSecrets, ({ one }
export const boardRelations = relations(boards, ({ many, one }) => ({
sections: many(sections),
items: many(items),
creator: one(users, {
fields: [boards.creatorId],
references: [users.id],
}),
userPermissions: many(boardUserPermissions),
groupPermissions: many(boardGroupPermissions),
layouts: many(layouts),
groupHomes: many(groups, {
relationName: "groupRelations__board__homeBoardId",
}),
@@ -591,12 +641,17 @@ export const boardRelations = relations(boards, ({ many, one }) => ({
}));
export const sectionRelations = relations(sections, ({ many, one }) => ({
items: many(items),
board: one(boards, {
fields: [sections.boardId],
references: [boards.id],
}),
collapseStates: many(sectionCollapseStates),
layouts: many(sectionLayouts, {
relationName: "sectionLayoutRelations__section__sectionId",
}),
children: many(sectionLayouts, {
relationName: "sectionLayoutRelations__section__parentSectionId",
}),
}));
export const sectionCollapseStateRelations = relations(sectionCollapseStates, ({ one }) => ({
@@ -611,11 +666,12 @@ export const sectionCollapseStateRelations = relations(sectionCollapseStates, ({
}));
export const itemRelations = relations(items, ({ one, many }) => ({
section: one(sections, {
fields: [items.sectionId],
references: [sections.id],
}),
integrations: many(integrationItems),
layouts: many(itemLayouts),
board: one(boards, {
fields: [items.boardId],
references: [boards.id],
}),
}));
export const integrationItemRelations = relations(integrationItems, ({ one }) => ({
@@ -636,3 +692,44 @@ export const searchEngineRelations = relations(searchEngines, ({ one, many }) =>
}),
usersWithDefault: many(users),
}));
export const itemLayoutRelations = relations(itemLayouts, ({ one }) => ({
item: one(items, {
fields: [itemLayouts.itemId],
references: [items.id],
}),
section: one(sections, {
fields: [itemLayouts.sectionId],
references: [sections.id],
}),
layout: one(layouts, {
fields: [itemLayouts.layoutId],
references: [layouts.id],
}),
}));
export const sectionLayoutRelations = relations(sectionLayouts, ({ one }) => ({
section: one(sections, {
fields: [sectionLayouts.sectionId],
references: [sections.id],
relationName: "sectionLayoutRelations__section__sectionId",
}),
layout: one(layouts, {
fields: [sectionLayouts.layoutId],
references: [layouts.id],
}),
parentSection: one(sections, {
fields: [sectionLayouts.parentSectionId],
references: [sections.id],
relationName: "sectionLayoutRelations__section__parentSectionId",
}),
}));
export const layoutRelations = relations(layouts, ({ one, many }) => ({
items: many(itemLayouts),
sections: many(sectionLayouts),
board: one(boards, {
fields: [layouts.boardId],
references: [boards.id],
}),
}));