merge: stack widget modernization on dnd kit
This commit is contained in:
940 files changed
+104475
-33649
No files matched your search
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable import/namespace -- Schema tables are selected by validated typed keys. */
|
||||
/* eslint-disable import/namespace -- Schema tables are intentionally selected by typed runtime keys. */
|
||||
import type { InferInsertModel } from "drizzle-orm";
|
||||
|
||||
import { objectEntries } from "@homarr/common";
|
||||
@@ -36,8 +36,10 @@ export const createDbInsertCollectionForTransaction = <TTableKey extends TableKe
|
||||
db.transaction((transaction) => {
|
||||
for (const [key, values] of objectEntries(context)) {
|
||||
if (values.length >= 1) {
|
||||
// oxlint-disable-next-line import/namespace -- TableKey limits key to exported schema tables.
|
||||
const table = schema[key];
|
||||
transaction
|
||||
.insert(schema[key])
|
||||
.insert(table)
|
||||
.values(values as never)
|
||||
.run();
|
||||
}
|
||||
@@ -51,14 +53,15 @@ export const createDbInsertCollectionForTransaction = <TTableKey extends TableKe
|
||||
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);
|
||||
// oxlint-disable-next-line import/namespace -- TableKey limits key to exported schema tables.
|
||||
const table = schema[key] as never;
|
||||
await transaction.insert(table).values(values as never);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const createDbInsertCollectionWithoutTransaction = <TTableKey extends TableKey>(
|
||||
tablesInInsertOrder: TTableKey[],
|
||||
) => {
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/** @vitest-environment node */
|
||||
|
||||
import { parse, stringify } from "superjson";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import { containerSectionOptionsSchema } from "@homarr/validation/shared";
|
||||
|
||||
import {
|
||||
boards,
|
||||
itemLayouts,
|
||||
items,
|
||||
layouts,
|
||||
sectionCollapseStates,
|
||||
sectionLayouts,
|
||||
sections,
|
||||
users,
|
||||
} from "../../schema";
|
||||
import { migrateLegacySectionsToContainersAsync } from "./0004_unify_sections_and_gutters";
|
||||
|
||||
describe("legacy section migration", () => {
|
||||
test("converts a rail category into a resizable container inside a board gutter", async () => {
|
||||
const db = createDb();
|
||||
const userId = createId();
|
||||
const boardId = createId();
|
||||
const layoutId = createId();
|
||||
const mainRootId = createId();
|
||||
const categoryId = createId();
|
||||
const itemId = createId();
|
||||
|
||||
await db.insert(users).values({ id: userId });
|
||||
await db.insert(boards).values({ id: boardId, name: "migration", creatorId: userId });
|
||||
await db.insert(layouts).values({ id: layoutId, name: "Base", boardId, columnCount: 8, breakpoint: 0 });
|
||||
await db.insert(sections).values([
|
||||
{ id: mainRootId, boardId, kind: "empty", xOffset: 0, yOffset: 0 },
|
||||
{
|
||||
id: categoryId,
|
||||
boardId,
|
||||
kind: "category" as never,
|
||||
name: "Pinned apps",
|
||||
xOffset: 0,
|
||||
yOffset: 1,
|
||||
options: stringify({
|
||||
showLabel: false,
|
||||
collapsible: true,
|
||||
showOpenAll: true,
|
||||
railPlacement: "left",
|
||||
columnCount: 2,
|
||||
}),
|
||||
},
|
||||
]);
|
||||
await db.insert(items).values({ id: itemId, boardId, kind: "clock" });
|
||||
await db.insert(sectionCollapseStates).values({
|
||||
sectionId: categoryId,
|
||||
userId,
|
||||
// Legacy categories stored true when the section was open.
|
||||
collapsed: true,
|
||||
});
|
||||
await db.insert(itemLayouts).values({
|
||||
itemId,
|
||||
layoutId,
|
||||
sectionId: categoryId,
|
||||
xOffset: 1,
|
||||
yOffset: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
await migrateLegacySectionsToContainersAsync(db as unknown as Database);
|
||||
|
||||
const migratedLayout = await db.query.layouts.findFirst({ where: eq(layouts.id, layoutId) });
|
||||
expect(migratedLayout?.leftGutterColumnCount).toBe(2);
|
||||
|
||||
const gutterRoot = await db.query.sections.findFirst({
|
||||
where: and(eq(sections.boardId, boardId), eq(sections.kind, "empty"), eq(sections.xOffset, -1)),
|
||||
});
|
||||
expect(gutterRoot).toBeDefined();
|
||||
|
||||
const migratedCategory = await db.query.sections.findFirst({ where: eq(sections.id, categoryId) });
|
||||
expect(migratedCategory?.kind).toBe("container");
|
||||
expect(containerSectionOptionsSchema.parse(parse(migratedCategory?.options ?? "{}"))).toEqual({
|
||||
title: "Pinned apps",
|
||||
customCssClasses: [],
|
||||
borderColor: "",
|
||||
showLabel: false,
|
||||
collapsible: true,
|
||||
showOpenAll: true,
|
||||
});
|
||||
const migratedCollapseState = await db.query.sectionCollapseStates.findFirst({
|
||||
where: and(eq(sectionCollapseStates.sectionId, categoryId), eq(sectionCollapseStates.userId, userId)),
|
||||
});
|
||||
expect(migratedCollapseState?.collapsed).toBe(false);
|
||||
|
||||
const categoryLayout = await db.query.sectionLayouts.findFirst({
|
||||
where: and(eq(sectionLayouts.sectionId, categoryId), eq(sectionLayouts.layoutId, layoutId)),
|
||||
});
|
||||
expect(categoryLayout).toMatchObject({
|
||||
parentSectionId: gutterRoot?.id,
|
||||
width: 2,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
const nestedItem = await db.query.itemLayouts.findFirst({
|
||||
where: and(eq(itemLayouts.itemId, itemId), eq(itemLayouts.layoutId, layoutId)),
|
||||
});
|
||||
expect(nestedItem?.sectionId).toBe(categoryId);
|
||||
});
|
||||
|
||||
test("renames a dynamic section and preserves all container options and geometry", async () => {
|
||||
const db = createDb();
|
||||
const userId = createId();
|
||||
const boardId = createId();
|
||||
const layoutId = createId();
|
||||
const rootId = createId();
|
||||
const sectionId = createId();
|
||||
const options = {
|
||||
title: "Operations",
|
||||
customCssClasses: ["dense", "accent"],
|
||||
borderColor: "#123456",
|
||||
showLabel: false,
|
||||
collapsible: true,
|
||||
showOpenAll: true,
|
||||
};
|
||||
|
||||
await db.insert(users).values({ id: userId });
|
||||
await db.insert(boards).values({ id: boardId, name: "dynamic-migration", creatorId: userId });
|
||||
await db.insert(layouts).values({ id: layoutId, name: "Base", boardId, columnCount: 8, breakpoint: 0 });
|
||||
await db.insert(sections).values([
|
||||
{ id: rootId, boardId, kind: "empty", xOffset: 0, yOffset: 0 },
|
||||
{
|
||||
id: sectionId,
|
||||
boardId,
|
||||
kind: "dynamic" as never,
|
||||
options: stringify(options),
|
||||
},
|
||||
]);
|
||||
await db.insert(sectionLayouts).values({
|
||||
sectionId,
|
||||
layoutId,
|
||||
parentSectionId: rootId,
|
||||
xOffset: 2,
|
||||
yOffset: 3,
|
||||
width: 4,
|
||||
height: 5,
|
||||
});
|
||||
|
||||
await migrateLegacySectionsToContainersAsync(db as unknown as Database);
|
||||
await migrateLegacySectionsToContainersAsync(db as unknown as Database);
|
||||
|
||||
const migrated = await db.query.sections.findFirst({ where: eq(sections.id, sectionId) });
|
||||
expect(migrated?.kind).toBe("container");
|
||||
expect(containerSectionOptionsSchema.parse(parse(migrated?.options ?? "{}"))).toEqual(options);
|
||||
expect(
|
||||
await db.query.sectionLayouts.findFirst({
|
||||
where: and(eq(sectionLayouts.sectionId, sectionId), eq(sectionLayouts.layoutId, layoutId)),
|
||||
}),
|
||||
).toMatchObject({
|
||||
parentSectionId: rootId,
|
||||
xOffset: 2,
|
||||
yOffset: 3,
|
||||
width: 4,
|
||||
height: 5,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,541 @@
|
||||
import { parse, stringify } from "superjson";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { BoardLane } from "@homarr/definitions";
|
||||
import { emptySuperJSON, getRootSectionLane, rootSectionOffsets } from "@homarr/definitions";
|
||||
import { containerSectionOptionsSchema } from "@homarr/validation/shared";
|
||||
|
||||
import { and, eq, handleTransactionsAsync, inArray } from "../..";
|
||||
import type { Database } from "../..";
|
||||
import type { HomarrDatabase } from "../../driver";
|
||||
import { itemLayouts, layouts, sectionCollapseStates, sectionLayouts, sections } from "../../schema";
|
||||
|
||||
interface MigrationPlacement {
|
||||
id: string;
|
||||
type: "item" | "section";
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
}
|
||||
|
||||
interface MigrationBoard {
|
||||
items: {
|
||||
id: string;
|
||||
layouts: {
|
||||
layoutId: string;
|
||||
sectionId: string;
|
||||
xOffset: number;
|
||||
yOffset: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}[];
|
||||
}[];
|
||||
sections: {
|
||||
id: string;
|
||||
kind: string;
|
||||
layouts: {
|
||||
layoutId: string;
|
||||
parentSectionId: string | null;
|
||||
xOffset: number;
|
||||
yOffset: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}[];
|
||||
}[];
|
||||
}
|
||||
|
||||
interface MigrationOperation {
|
||||
applyAsync(db: Database): Promise<void>;
|
||||
applySync(db: HomarrDatabase): void;
|
||||
}
|
||||
|
||||
const legacyCategoryOptionsDefaults = {
|
||||
showLabel: true,
|
||||
collapsible: true,
|
||||
showOpenAll: true,
|
||||
railPlacement: "main",
|
||||
columnCount: 2,
|
||||
} as const;
|
||||
|
||||
const legacyCategoryOptionsSchema = z
|
||||
.object({
|
||||
showLabel: z.boolean().default(legacyCategoryOptionsDefaults.showLabel),
|
||||
collapsible: z.boolean().default(legacyCategoryOptionsDefaults.collapsible),
|
||||
showOpenAll: z.boolean().default(legacyCategoryOptionsDefaults.showOpenAll),
|
||||
railPlacement: z.enum(["main", "left", "right"]).default(legacyCategoryOptionsDefaults.railPlacement),
|
||||
columnCount: z.number().int().min(1).max(24).default(legacyCategoryOptionsDefaults.columnCount),
|
||||
})
|
||||
.default(legacyCategoryOptionsDefaults);
|
||||
|
||||
/**
|
||||
* Convert legacy categories and dynamic sections into durable containers.
|
||||
* Categories were full-width roots and also doubled as side rails, so they
|
||||
* additionally need placement and gutter migration.
|
||||
*/
|
||||
export async function migrateLegacySectionsToContainersAsync(db: Database) {
|
||||
const existingBoards = await db.query.boards.findMany({
|
||||
with: {
|
||||
layouts: true,
|
||||
sections: {
|
||||
with: {
|
||||
collapseStates: true,
|
||||
layouts: true,
|
||||
},
|
||||
},
|
||||
items: {
|
||||
with: {
|
||||
layouts: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let migratedSectionCount = 0;
|
||||
|
||||
for (const board of existingBoards) {
|
||||
const categories = board.sections.filter((section) => (section.kind as string) === "category");
|
||||
const legacyContainers = board.sections.filter((section) => (section.kind as string) === "dynamic");
|
||||
if (categories.length === 0 && legacyContainers.length === 0) continue;
|
||||
const operations: MigrationOperation[] = [];
|
||||
|
||||
const appendLegacyContainerOperations = () => {
|
||||
for (const section of legacyContainers) {
|
||||
operations.push(
|
||||
updateSectionOperation(section.id, {
|
||||
kind: "container",
|
||||
xOffset: null,
|
||||
yOffset: null,
|
||||
name: null,
|
||||
options: stringify(containerSectionOptionsSchema.parse(parse(section.options ?? emptySuperJSON))),
|
||||
}),
|
||||
);
|
||||
migratedSectionCount += 1;
|
||||
}
|
||||
};
|
||||
|
||||
if (categories.length === 0) {
|
||||
appendLegacyContainerOperations();
|
||||
await executeBoardMigrationOperationsAsync(db, operations);
|
||||
continue;
|
||||
}
|
||||
|
||||
const categoryDetails = categories.map((category) => {
|
||||
const options = legacyCategoryOptionsSchema.parse(parse(category.options ?? emptySuperJSON));
|
||||
return {
|
||||
category,
|
||||
lane: options.railPlacement as BoardLane,
|
||||
options,
|
||||
};
|
||||
});
|
||||
const emptyRoots = board.sections.filter((section) => section.kind === "empty");
|
||||
let mainRoot = emptyRoots.find((section) => getRootSectionLane(section.xOffset) === "main");
|
||||
if (!mainRoot) {
|
||||
const id = createId();
|
||||
operations.push(
|
||||
insertSectionsOperation([
|
||||
{
|
||||
id,
|
||||
boardId: board.id,
|
||||
kind: "empty",
|
||||
xOffset: rootSectionOffsets.main,
|
||||
yOffset: 0,
|
||||
options: emptySuperJSON,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mainRoot = {
|
||||
id,
|
||||
boardId: board.id,
|
||||
kind: "empty",
|
||||
xOffset: rootSectionOffsets.main,
|
||||
yOffset: 0,
|
||||
name: null,
|
||||
options: emptySuperJSON,
|
||||
collapseStates: [],
|
||||
layouts: [],
|
||||
};
|
||||
emptyRoots.push(mainRoot);
|
||||
}
|
||||
|
||||
const rootByLane = new Map<BoardLane, (typeof emptyRoots)[number]>([["main", mainRoot]]);
|
||||
for (const lane of ["left", "right"] as const) {
|
||||
const existing = emptyRoots.find((section) => getRootSectionLane(section.xOffset) === lane);
|
||||
if (existing) {
|
||||
rootByLane.set(lane, existing);
|
||||
continue;
|
||||
}
|
||||
if (!categoryDetails.some((detail) => detail.lane === lane)) continue;
|
||||
|
||||
const id = createId();
|
||||
operations.push(
|
||||
insertSectionsOperation([
|
||||
{
|
||||
id,
|
||||
boardId: board.id,
|
||||
kind: "empty",
|
||||
xOffset: rootSectionOffsets[lane],
|
||||
yOffset: 0,
|
||||
options: emptySuperJSON,
|
||||
},
|
||||
]),
|
||||
);
|
||||
rootByLane.set(lane, {
|
||||
id,
|
||||
boardId: board.id,
|
||||
kind: "empty",
|
||||
xOffset: rootSectionOffsets[lane],
|
||||
yOffset: 0,
|
||||
name: null,
|
||||
options: emptySuperJSON,
|
||||
collapseStates: [],
|
||||
layouts: [],
|
||||
});
|
||||
}
|
||||
|
||||
for (const layout of board.layouts) {
|
||||
const requestedLeft = Math.max(
|
||||
0,
|
||||
...categoryDetails.filter((detail) => detail.lane === "left").map((detail) => detail.options.columnCount),
|
||||
);
|
||||
const requestedRight = Math.max(
|
||||
0,
|
||||
...categoryDetails.filter((detail) => detail.lane === "right").map((detail) => detail.options.columnCount),
|
||||
);
|
||||
const left = Math.min(3, requestedLeft, Math.max(0, layout.columnCount - 1));
|
||||
const right = Math.min(3, requestedRight, Math.max(0, layout.columnCount - left - 1));
|
||||
const widths = {
|
||||
left,
|
||||
main: Math.max(1, layout.columnCount - left - right),
|
||||
right,
|
||||
} satisfies Record<BoardLane, number>;
|
||||
|
||||
operations.push(updateLayoutGuttersOperation(layout.id, left, right));
|
||||
|
||||
for (const lane of ["left", "main", "right"] as const) {
|
||||
const targetRoot = rootByLane.get(lane);
|
||||
const laneWidth = widths[lane];
|
||||
if (!targetRoot || laneWidth === 0) continue;
|
||||
|
||||
const sourceRoots = emptyRoots
|
||||
.filter((section) => getRootSectionLane(section.xOffset) === lane)
|
||||
.toSorted((first, second) => (first.yOffset ?? 0) - (second.yOffset ?? 0));
|
||||
const sourceBlocks = [
|
||||
...sourceRoots.map((root) => ({
|
||||
id: root.id,
|
||||
yOffset: root.yOffset ?? 0,
|
||||
type: "root" as const,
|
||||
})),
|
||||
...categoryDetails
|
||||
.filter((detail) => detail.lane === lane)
|
||||
.map((detail) => ({
|
||||
id: detail.category.id,
|
||||
yOffset: detail.category.yOffset ?? 0,
|
||||
type: "category" as const,
|
||||
detail,
|
||||
})),
|
||||
].toSorted(
|
||||
(first, second) =>
|
||||
first.yOffset - second.yOffset ||
|
||||
(first.type === second.type ? first.id.localeCompare(second.id) : first.type === "category" ? -1 : 1),
|
||||
);
|
||||
|
||||
let nextRow = 0;
|
||||
for (const block of sourceBlocks) {
|
||||
if (block.type === "category") {
|
||||
const content = getDirectPlacements(board, layout.id, block.id);
|
||||
const packedContent = packPlacements(content, laneWidth);
|
||||
operations.push(...persistPlacementOperations(layout.id, block.id, packedContent));
|
||||
const height = Math.max(1, getPlacementRowCount(packedContent));
|
||||
const existingLayout = block.detail.category.layouts.find((candidate) => candidate.layoutId === layout.id);
|
||||
const values = {
|
||||
sectionId: block.id,
|
||||
layoutId: layout.id,
|
||||
parentSectionId: targetRoot.id,
|
||||
xOffset: 0,
|
||||
yOffset: nextRow,
|
||||
width: laneWidth,
|
||||
height,
|
||||
};
|
||||
if (existingLayout) {
|
||||
operations.push(updateSectionLayoutOperation(block.id, layout.id, values));
|
||||
} else {
|
||||
operations.push(insertSectionLayoutOperation(values));
|
||||
}
|
||||
nextRow += height;
|
||||
continue;
|
||||
}
|
||||
|
||||
const content = getDirectPlacements(board, layout.id, block.id);
|
||||
const relativePackedContent = packPlacements(content, laneWidth);
|
||||
const packedContent = relativePackedContent.map((placement) => ({
|
||||
...placement,
|
||||
y: placement.y + nextRow,
|
||||
}));
|
||||
operations.push(...persistPlacementOperations(layout.id, targetRoot.id, packedContent));
|
||||
nextRow += getPlacementRowCount(relativePackedContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const { category, options } of categoryDetails) {
|
||||
const legacyCollapseStates = category.collapseStates;
|
||||
for (const state of legacyCollapseStates) {
|
||||
operations.push(updateCollapseStateOperation(category.id, state.userId, !state.collapsed));
|
||||
}
|
||||
|
||||
operations.push(
|
||||
updateSectionOperation(category.id, {
|
||||
kind: "container",
|
||||
xOffset: null,
|
||||
yOffset: null,
|
||||
name: null,
|
||||
options: stringify(
|
||||
containerSectionOptionsSchema.parse({
|
||||
title: (category.name ?? "").slice(0, 64),
|
||||
customCssClasses: [],
|
||||
borderColor: "",
|
||||
showLabel: options.showLabel,
|
||||
collapsible: options.collapsible,
|
||||
showOpenAll: options.showOpenAll,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
);
|
||||
migratedSectionCount += 1;
|
||||
}
|
||||
|
||||
appendLegacyContainerOperations();
|
||||
|
||||
const retainedRootIds = new Set(Array.from(rootByLane.values(), (root) => root.id));
|
||||
const obsoleteRootIds = emptyRoots.filter((root) => !retainedRootIds.has(root.id)).map((root) => root.id);
|
||||
if (obsoleteRootIds.length > 0) {
|
||||
operations.push(deleteSectionsOperation(obsoleteRootIds));
|
||||
}
|
||||
|
||||
await executeBoardMigrationOperationsAsync(db, operations);
|
||||
}
|
||||
|
||||
if (migratedSectionCount > 0) {
|
||||
console.log(`Migrated legacy sections to containers count="${migratedSectionCount}"`);
|
||||
}
|
||||
}
|
||||
|
||||
const getDirectPlacements = (board: MigrationBoard, layoutId: string, sectionId: string): MigrationPlacement[] => [
|
||||
...board.items.flatMap((item) => {
|
||||
const layout = item.layouts.find(
|
||||
(candidate) => candidate.layoutId === layoutId && candidate.sectionId === sectionId,
|
||||
);
|
||||
return layout
|
||||
? [
|
||||
{
|
||||
id: item.id,
|
||||
type: "item" as const,
|
||||
x: layout.xOffset,
|
||||
y: layout.yOffset,
|
||||
w: layout.width,
|
||||
h: layout.height,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
}),
|
||||
...board.sections.flatMap((section) => {
|
||||
if (section.kind !== "dynamic" && section.kind !== "container") return [];
|
||||
const layout = section.layouts.find(
|
||||
(candidate) => candidate.layoutId === layoutId && candidate.parentSectionId === sectionId,
|
||||
);
|
||||
return layout
|
||||
? [
|
||||
{
|
||||
id: section.id,
|
||||
type: "section" as const,
|
||||
x: layout.xOffset,
|
||||
y: layout.yOffset,
|
||||
w: layout.width,
|
||||
h: layout.height,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
}),
|
||||
];
|
||||
|
||||
const executeBoardMigrationOperationsAsync = async (db: Database, operations: readonly MigrationOperation[]) => {
|
||||
await handleTransactionsAsync(db, {
|
||||
async handleAsync(transactionDb) {
|
||||
await transactionDb.transaction(async (transaction) => {
|
||||
for (const operation of operations) {
|
||||
await operation.applyAsync(transaction as unknown as Database);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSync(sqliteDb) {
|
||||
sqliteDb.transaction((transaction) => {
|
||||
for (const operation of operations) {
|
||||
operation.applySync(transaction);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const insertSectionsOperation = (values: (typeof sections.$inferInsert)[]): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db.insert(sections).values(values);
|
||||
},
|
||||
applySync(db) {
|
||||
db.insert(sections).values(values).run();
|
||||
},
|
||||
});
|
||||
|
||||
const updateLayoutGuttersOperation = (
|
||||
layoutId: string,
|
||||
leftGutterColumnCount: number,
|
||||
rightGutterColumnCount: number,
|
||||
): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db.update(layouts).set({ leftGutterColumnCount, rightGutterColumnCount }).where(eq(layouts.id, layoutId));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(layouts).set({ leftGutterColumnCount, rightGutterColumnCount }).where(eq(layouts.id, layoutId)).run();
|
||||
},
|
||||
});
|
||||
|
||||
const persistPlacementOperations = (
|
||||
layoutId: string,
|
||||
sectionId: string,
|
||||
placements: readonly MigrationPlacement[],
|
||||
): MigrationOperation[] =>
|
||||
placements.map((placement) => {
|
||||
const values = {
|
||||
xOffset: placement.x,
|
||||
yOffset: placement.y,
|
||||
width: placement.w,
|
||||
height: placement.h,
|
||||
};
|
||||
if (placement.type === "item") {
|
||||
return {
|
||||
async applyAsync(db) {
|
||||
await db
|
||||
.update(itemLayouts)
|
||||
.set({ ...values, sectionId })
|
||||
.where(and(eq(itemLayouts.itemId, placement.id), eq(itemLayouts.layoutId, layoutId)));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(itemLayouts)
|
||||
.set({ ...values, sectionId })
|
||||
.where(and(eq(itemLayouts.itemId, placement.id), eq(itemLayouts.layoutId, layoutId)))
|
||||
.run();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
async applyAsync(db) {
|
||||
await db
|
||||
.update(sectionLayouts)
|
||||
.set({ ...values, parentSectionId: sectionId })
|
||||
.where(and(eq(sectionLayouts.sectionId, placement.id), eq(sectionLayouts.layoutId, layoutId)));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(sectionLayouts)
|
||||
.set({ ...values, parentSectionId: sectionId })
|
||||
.where(and(eq(sectionLayouts.sectionId, placement.id), eq(sectionLayouts.layoutId, layoutId)))
|
||||
.run();
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const updateSectionLayoutOperation = (
|
||||
sectionId: string,
|
||||
layoutId: string,
|
||||
values: typeof sectionLayouts.$inferInsert,
|
||||
): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db
|
||||
.update(sectionLayouts)
|
||||
.set(values)
|
||||
.where(and(eq(sectionLayouts.sectionId, sectionId), eq(sectionLayouts.layoutId, layoutId)));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(sectionLayouts)
|
||||
.set(values)
|
||||
.where(and(eq(sectionLayouts.sectionId, sectionId), eq(sectionLayouts.layoutId, layoutId)))
|
||||
.run();
|
||||
},
|
||||
});
|
||||
|
||||
const insertSectionLayoutOperation = (values: typeof sectionLayouts.$inferInsert): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db.insert(sectionLayouts).values(values);
|
||||
},
|
||||
applySync(db) {
|
||||
db.insert(sectionLayouts).values(values).run();
|
||||
},
|
||||
});
|
||||
|
||||
const updateCollapseStateOperation = (sectionId: string, userId: string, collapsed: boolean): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db
|
||||
.update(sectionCollapseStates)
|
||||
.set({ collapsed })
|
||||
.where(and(eq(sectionCollapseStates.sectionId, sectionId), eq(sectionCollapseStates.userId, userId)));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(sectionCollapseStates)
|
||||
.set({ collapsed })
|
||||
.where(and(eq(sectionCollapseStates.sectionId, sectionId), eq(sectionCollapseStates.userId, userId)))
|
||||
.run();
|
||||
},
|
||||
});
|
||||
|
||||
const updateSectionOperation = (
|
||||
sectionId: string,
|
||||
values: Partial<typeof sections.$inferInsert>,
|
||||
): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db.update(sections).set(values).where(eq(sections.id, sectionId));
|
||||
},
|
||||
applySync(db) {
|
||||
db.update(sections).set(values).where(eq(sections.id, sectionId)).run();
|
||||
},
|
||||
});
|
||||
|
||||
const deleteSectionsOperation = (sectionIds: string[]): MigrationOperation => ({
|
||||
async applyAsync(db) {
|
||||
await db.delete(sections).where(inArray(sections.id, sectionIds));
|
||||
},
|
||||
applySync(db) {
|
||||
db.delete(sections).where(inArray(sections.id, sectionIds)).run();
|
||||
},
|
||||
});
|
||||
|
||||
const packPlacements = (placements: readonly MigrationPlacement[], columnCount: number): MigrationPlacement[] => {
|
||||
const placed: MigrationPlacement[] = [];
|
||||
const candidates = placements
|
||||
.map((placement) => ({
|
||||
...placement,
|
||||
x: Math.min(Math.max(0, placement.x), Math.max(0, columnCount - Math.min(columnCount, placement.w))),
|
||||
y: Math.max(0, placement.y),
|
||||
w: Math.min(columnCount, Math.max(1, placement.w)),
|
||||
h: Math.max(1, placement.h),
|
||||
}))
|
||||
.toSorted((first, second) => first.y - second.y || first.x - second.x || first.id.localeCompare(second.id));
|
||||
|
||||
for (const candidate of candidates) {
|
||||
let row = 0;
|
||||
while (placed.some((placement) => overlaps({ ...candidate, y: row }, placement))) row += 1;
|
||||
placed.push({ ...candidate, y: row });
|
||||
}
|
||||
|
||||
return placed;
|
||||
};
|
||||
|
||||
const overlaps = (first: MigrationPlacement, second: MigrationPlacement) =>
|
||||
first.x < second.x + second.w &&
|
||||
first.x + first.w > second.x &&
|
||||
first.y < second.y + second.h &&
|
||||
first.y + first.h > second.y;
|
||||
|
||||
const getPlacementRowCount = (placements: readonly MigrationPlacement[]) =>
|
||||
Math.max(0, ...placements.map((placement) => placement.y + placement.h));
|
||||
@@ -3,10 +3,12 @@ import { migrateReleaseWidgetProviderToOptionsAsync } from "./0000_release_widge
|
||||
import { migrateOpnsenseCredentialsAsync } from "./0001_opnsense_credentials";
|
||||
import { migrateAppWidgetShowDescriptionTooltipToDisplayModeAsync } from "./0002_app_widget_show_description_tooltip_to_display_mode";
|
||||
import { migrateWidgetOnlyIntegrationsToOptionsAsync } from "./0003_remove_widget_only_integrations";
|
||||
import { migrateLegacySectionsToContainersAsync } from "./0004_unify_sections_and_gutters";
|
||||
|
||||
export const applyCustomMigrationsAsync = async (db: Database) => {
|
||||
await migrateReleaseWidgetProviderToOptionsAsync(db);
|
||||
await migrateOpnsenseCredentialsAsync(db);
|
||||
await migrateAppWidgetShowDescriptionTooltipToDisplayModeAsync(db);
|
||||
await migrateWidgetOnlyIntegrationsToOptionsAsync(db);
|
||||
await migrateLegacySectionsToContainersAsync(db);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
CREATE TABLE `custom_widget_v2_definition` (
|
||||
`id` varchar(64) NOT NULL,
|
||||
`name` varchar(256) NOT NULL,
|
||||
`description` text,
|
||||
`icon_url` text,
|
||||
`sources` text NOT NULL,
|
||||
`requests` text NOT NULL,
|
||||
`options` text NOT NULL,
|
||||
`template` text NOT NULL,
|
||||
`enabled` boolean DEFAULT true NOT NULL,
|
||||
`created_at` timestamp DEFAULT (now()) NOT NULL,
|
||||
`updated_at` timestamp DEFAULT (now()) NOT NULL,
|
||||
`creator_id` varchar(64),
|
||||
CONSTRAINT `custom_widget_v2_definition_id` PRIMARY KEY(`id`)
|
||||
);--> statement-breakpoint
|
||||
CREATE TABLE `custom_widget_v2_secret` (
|
||||
`source_id` varchar(64) NOT NULL,
|
||||
`kind` varchar(64) NOT NULL,
|
||||
`encrypted_value` text NOT NULL,
|
||||
`updated_at` timestamp NOT NULL,
|
||||
`definition_id` varchar(64) NOT NULL,
|
||||
CONSTRAINT `custom_widget_v2_secret_definition_id_source_id_kind_pk` PRIMARY KEY(`definition_id`,`source_id`,`kind`)
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE `custom_widget_v2_definition` ADD CONSTRAINT `custom_widget_v2_definition_creator_id_user_id_fk` FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `custom_widget_v2_secret` ADD CONSTRAINT `custom_widget_v2_secret_definition_id_fk` FOREIGN KEY (`definition_id`) REFERENCES `custom_widget_v2_definition`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
DELETE FROM `groupPermission` WHERE `permission` IN ('custom-widget-manage', 'custom-widget-secret-write');
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `layout` ADD `left_gutter_column_count` tinyint DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `layout` ADD `right_gutter_column_count` tinyint DEFAULT 0 NOT NULL;
|
||||
@@ -88,9 +88,7 @@
|
||||
"indexes": {
|
||||
"userId_idx": {
|
||||
"name": "userId_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -99,12 +97,8 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -112,10 +106,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"name": "account_provider_provider_account_id_pk",
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
]
|
||||
"columns": ["provider", "provider_account_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -152,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -165,9 +152,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"apiKey_id": {
|
||||
"name": "apiKey_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -224,9 +209,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"app_id": {
|
||||
"name": "app_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -263,12 +246,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -276,12 +255,8 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -289,11 +264,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -330,12 +301,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -343,12 +310,8 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -356,11 +319,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -518,12 +477,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -531,17 +486,13 @@
|
||||
"compositePrimaryKeys": {
|
||||
"board_id": {
|
||||
"name": "board_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"checkConstraint": {}
|
||||
@@ -577,9 +528,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"cron_job_configuration_name": {
|
||||
"name": "cron_job_configuration_name",
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -609,12 +558,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -622,12 +567,8 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -635,10 +576,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"name": "groupMember_group_id_user_id_pk",
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["group_id", "user_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -668,12 +606,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -734,12 +668,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -747,12 +677,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -760,12 +686,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -773,17 +695,13 @@
|
||||
"compositePrimaryKeys": {
|
||||
"group_id": {
|
||||
"name": "group_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"checkConstraint": {}
|
||||
@@ -811,9 +729,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"iconRepository_id": {
|
||||
"name": "iconRepository_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -864,12 +780,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -877,9 +789,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"icon_id": {
|
||||
"name": "icon_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -916,12 +826,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -929,12 +835,8 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -942,11 +844,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_group_permission__pk": {
|
||||
"name": "integration_group_permission__pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -976,12 +874,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -989,12 +883,8 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1002,10 +892,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"name": "integration_item_item_id_integration_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
]
|
||||
"columns": ["item_id", "integration_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1046,16 +933,12 @@
|
||||
"indexes": {
|
||||
"integration_secret__kind_idx": {
|
||||
"name": "integration_secret__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
},
|
||||
"integration_secret__updated_at_idx": {
|
||||
"name": "integration_secret__updated_at_idx",
|
||||
"columns": [
|
||||
"updated_at"
|
||||
],
|
||||
"columns": ["updated_at"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1064,12 +947,8 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1077,10 +956,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"name": "integrationSecret_integration_id_kind_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["integration_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1117,12 +993,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1130,12 +1002,8 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1143,11 +1011,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1195,9 +1059,7 @@
|
||||
"indexes": {
|
||||
"integration__kind_idx": {
|
||||
"name": "integration__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1206,12 +1068,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1219,9 +1077,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_id": {
|
||||
"name": "integration_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1265,12 +1121,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1278,17 +1130,13 @@
|
||||
"compositePrimaryKeys": {
|
||||
"invite_id": {
|
||||
"name": "invite_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"checkConstraint": {}
|
||||
@@ -1352,12 +1200,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1365,12 +1209,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1378,12 +1218,8 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1391,11 +1227,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["item_id", "section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1448,12 +1280,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1461,9 +1289,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"item_id": {
|
||||
"name": "item_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1515,12 +1341,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1528,9 +1350,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"layout_id": {
|
||||
"name": "layout_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1596,12 +1416,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1609,9 +1425,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"media_id": {
|
||||
"name": "media_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1647,9 +1461,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"onboarding_id": {
|
||||
"name": "onboarding_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1722,12 +1534,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1735,17 +1543,13 @@
|
||||
"compositePrimaryKeys": {
|
||||
"search_engine_id": {
|
||||
"name": "search_engine_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"columns": [
|
||||
"short"
|
||||
]
|
||||
"columns": ["short"]
|
||||
}
|
||||
},
|
||||
"checkConstraint": {}
|
||||
@@ -1782,12 +1586,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1795,12 +1595,8 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1808,10 +1604,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"name": "section_collapse_state_user_id_section_id_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
]
|
||||
"columns": ["user_id", "section_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1876,12 +1669,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1889,12 +1678,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1902,12 +1687,8 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1915,10 +1696,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"name": "section_layout_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1984,12 +1762,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1997,9 +1771,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_id": {
|
||||
"name": "section_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2029,17 +1801,13 @@
|
||||
"compositePrimaryKeys": {
|
||||
"serverSetting_setting_key": {
|
||||
"name": "serverSetting_setting_key",
|
||||
"columns": [
|
||||
"setting_key"
|
||||
]
|
||||
"columns": ["setting_key"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"columns": [
|
||||
"setting_key"
|
||||
]
|
||||
"columns": ["setting_key"]
|
||||
}
|
||||
},
|
||||
"checkConstraint": {}
|
||||
@@ -2072,9 +1840,7 @@
|
||||
"indexes": {
|
||||
"user_id_idx": {
|
||||
"name": "user_id_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -2083,12 +1849,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2096,9 +1858,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"session_session_token": {
|
||||
"name": "session_session_token",
|
||||
"columns": [
|
||||
"session_token"
|
||||
]
|
||||
"columns": ["session_token"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2225,12 +1985,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2238,12 +1994,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2251,12 +2003,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2264,9 +2012,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"columns": [
|
||||
"id"
|
||||
]
|
||||
"columns": ["id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2302,10 +2048,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"name": "verificationToken_identifier_token_pk",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
]
|
||||
"columns": ["identifier", "token"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2341,10 +2084,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
]
|
||||
"columns": ["hostname", "thumbprint"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2361,4 +2101,4 @@
|
||||
"tables": {},
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -309,6 +309,20 @@
|
||||
"when": 1783852800000,
|
||||
"tag": "0043_add_right_click_preference",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 44,
|
||||
"version": "5",
|
||||
"when": 1784305537309,
|
||||
"tag": "0044_custom_widget_v2_tables",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 45,
|
||||
"version": "5",
|
||||
"when": 1786212549933,
|
||||
"tag": "0045_shiny_sir_ram",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE "custom_widget_v2_definition" (
|
||||
"id" varchar(64) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(256) NOT NULL,
|
||||
"description" text,
|
||||
"icon_url" text,
|
||||
"sources" text NOT NULL,
|
||||
"requests" text NOT NULL,
|
||||
"options" text NOT NULL,
|
||||
"template" text NOT NULL,
|
||||
"enabled" boolean DEFAULT true NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
"creator_id" varchar(64)
|
||||
);--> statement-breakpoint
|
||||
CREATE TABLE "custom_widget_v2_secret" (
|
||||
"source_id" varchar(64) NOT NULL,
|
||||
"kind" varchar(64) NOT NULL,
|
||||
"encrypted_value" text NOT NULL,
|
||||
"updated_at" timestamp NOT NULL,
|
||||
"definition_id" varchar(64) NOT NULL,
|
||||
CONSTRAINT "custom_widget_v2_secret_definition_id_source_id_kind_pk" PRIMARY KEY("definition_id","source_id","kind")
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "custom_widget_v2_definition" ADD CONSTRAINT "custom_widget_v2_definition_creator_id_user_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "custom_widget_v2_secret" ADD CONSTRAINT "custom_widget_v2_secret_definition_id_fk" FOREIGN KEY ("definition_id") REFERENCES "public"."custom_widget_v2_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
DELETE FROM "groupPermission" WHERE "permission" IN ('custom-widget-manage', 'custom-widget-secret-write');
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "layout" ADD COLUMN "left_gutter_column_count" smallint DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "layout" ADD COLUMN "right_gutter_column_count" smallint DEFAULT 0 NOT NULL;
|
||||
@@ -97,12 +97,8 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -110,10 +106,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"name": "account_provider_provider_account_id_pk",
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
]
|
||||
"columns": ["provider", "provider_account_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -150,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -244,12 +233,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -257,12 +242,8 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -270,11 +251,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -311,12 +288,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -324,12 +297,8 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -337,11 +306,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -483,12 +448,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -498,9 +459,7 @@
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -646,12 +605,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -697,12 +652,8 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -710,10 +661,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"name": "custom_widget_secret_definition_id_kind_pk",
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["definition_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -744,12 +692,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -757,12 +701,8 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -770,10 +710,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"name": "groupMember_group_id_user_id_pk",
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["group_id", "user_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -804,12 +741,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -867,12 +800,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -880,12 +809,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -893,12 +818,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -908,9 +829,7 @@
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -983,12 +902,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1028,12 +943,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1041,12 +952,8 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1054,11 +961,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_group_permission__pk": {
|
||||
"name": "integration_group_permission__pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1089,12 +992,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1102,12 +1001,8 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1115,10 +1010,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"name": "integration_item_item_id_integration_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
]
|
||||
"columns": ["item_id", "integration_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1192,12 +1084,8 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1205,10 +1093,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"name": "integrationSecret_integration_id_kind_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["integration_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1245,12 +1130,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1258,12 +1139,8 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1271,11 +1148,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1340,12 +1213,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1391,12 +1260,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1406,9 +1271,7 @@
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1468,12 +1331,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1481,12 +1340,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1494,12 +1349,8 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1507,11 +1358,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["item_id", "section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1562,12 +1409,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1620,12 +1463,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1690,12 +1529,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1797,12 +1632,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1812,9 +1643,7 @@
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"short"
|
||||
]
|
||||
"columns": ["short"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1851,12 +1680,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1864,12 +1689,8 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1877,10 +1698,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"name": "section_collapse_state_user_id_section_id_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
]
|
||||
"columns": ["user_id", "section_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1941,12 +1759,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1954,12 +1768,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1967,12 +1777,8 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1980,10 +1786,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"name": "section_layout_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2045,12 +1848,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2086,9 +1885,7 @@
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"setting_key"
|
||||
]
|
||||
"columns": ["setting_key"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2140,12 +1937,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2277,12 +2070,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2290,12 +2079,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2303,12 +2088,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2347,10 +2128,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"name": "verificationToken_identifier_token_pk",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
]
|
||||
"columns": ["identifier", "token"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2386,10 +2164,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
]
|
||||
"columns": ["hostname", "thumbprint"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2409,4 +2184,4 @@
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,12 +97,8 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -110,10 +106,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"name": "account_provider_provider_account_id_pk",
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
]
|
||||
"columns": ["provider", "provider_account_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -150,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -244,12 +233,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -257,12 +242,8 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -270,11 +251,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -311,12 +288,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -324,12 +297,8 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -337,11 +306,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -483,12 +448,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -498,9 +459,7 @@
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -647,12 +606,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -698,12 +653,8 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -711,10 +662,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"name": "custom_widget_secret_definition_id_kind_pk",
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["definition_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -745,12 +693,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -758,12 +702,8 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -771,10 +711,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"name": "groupMember_group_id_user_id_pk",
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["group_id", "user_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -805,12 +742,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -868,12 +801,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -881,12 +810,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -894,12 +819,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -909,9 +830,7 @@
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -984,12 +903,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1029,12 +944,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1042,12 +953,8 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1055,11 +962,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_group_permission__pk": {
|
||||
"name": "integration_group_permission__pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1090,12 +993,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1103,12 +1002,8 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1116,10 +1011,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"name": "integration_item_item_id_integration_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
]
|
||||
"columns": ["item_id", "integration_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1193,12 +1085,8 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1206,10 +1094,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"name": "integrationSecret_integration_id_kind_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["integration_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1246,12 +1131,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1259,12 +1140,8 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1272,11 +1149,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1341,12 +1214,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1392,12 +1261,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1407,9 +1272,7 @@
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1469,12 +1332,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1482,12 +1341,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1495,12 +1350,8 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1508,11 +1359,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["item_id", "section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1563,12 +1410,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1621,12 +1464,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1691,12 +1530,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1798,12 +1633,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1813,9 +1644,7 @@
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"short"
|
||||
]
|
||||
"columns": ["short"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1852,12 +1681,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1865,12 +1690,8 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1878,10 +1699,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"name": "section_collapse_state_user_id_section_id_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
]
|
||||
"columns": ["user_id", "section_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1942,12 +1760,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1955,12 +1769,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1968,12 +1778,8 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1981,10 +1787,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"name": "section_layout_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2046,12 +1849,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2087,9 +1886,7 @@
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"setting_key"
|
||||
]
|
||||
"columns": ["setting_key"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2141,12 +1938,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2278,12 +2071,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2291,12 +2080,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2304,12 +2089,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2348,10 +2129,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"name": "verificationToken_identifier_token_pk",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
]
|
||||
"columns": ["identifier", "token"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2387,10 +2165,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
]
|
||||
"columns": ["hostname", "thumbprint"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
|
||||
@@ -97,12 +97,8 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -110,10 +106,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"name": "account_provider_provider_account_id_pk",
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
]
|
||||
"columns": ["provider", "provider_account_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -150,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -244,12 +233,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -257,12 +242,8 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -270,11 +251,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -311,12 +288,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -324,12 +297,8 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -337,11 +306,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["board_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -483,12 +448,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -498,9 +459,7 @@
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -647,12 +606,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -698,12 +653,8 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -711,10 +662,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"name": "custom_widget_secret_definition_id_kind_pk",
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["definition_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -745,12 +693,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -758,12 +702,8 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -771,10 +711,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"name": "groupMember_group_id_user_id_pk",
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["group_id", "user_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -805,12 +742,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -868,12 +801,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -881,12 +810,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -894,12 +819,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -909,9 +830,7 @@
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"name"
|
||||
]
|
||||
"columns": ["name"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -984,12 +903,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1029,12 +944,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1042,12 +953,8 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1055,11 +962,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_group_permission__pk": {
|
||||
"name": "integration_group_permission__pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "group_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1090,12 +993,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1103,12 +1002,8 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1116,10 +1011,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"name": "integration_item_item_id_integration_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
]
|
||||
"columns": ["item_id", "integration_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1193,12 +1085,8 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1206,10 +1094,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"name": "integrationSecret_integration_id_kind_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
]
|
||||
"columns": ["integration_id", "kind"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1246,12 +1131,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1259,12 +1140,8 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1272,11 +1149,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
]
|
||||
"columns": ["integration_id", "user_id", "permission"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1341,12 +1214,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1392,12 +1261,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1407,9 +1272,7 @@
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1469,12 +1332,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1482,12 +1341,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1495,12 +1350,8 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1508,11 +1359,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["item_id", "section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1563,12 +1410,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1621,12 +1464,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1691,12 +1530,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1798,12 +1633,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1813,9 +1644,7 @@
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"short"
|
||||
]
|
||||
"columns": ["short"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -1852,12 +1681,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1865,12 +1690,8 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1878,10 +1699,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"name": "section_collapse_state_user_id_section_id_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
]
|
||||
"columns": ["user_id", "section_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1942,12 +1760,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1955,12 +1769,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1968,12 +1778,8 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1981,10 +1787,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"name": "section_layout_section_id_layout_id_pk",
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
]
|
||||
"columns": ["section_id", "layout_id"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2046,12 +1849,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2087,9 +1886,7 @@
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"setting_key"
|
||||
]
|
||||
"columns": ["setting_key"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2141,12 +1938,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2278,12 +2071,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2291,12 +2080,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2304,12 +2089,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2348,10 +2129,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"name": "verificationToken_identifier_token_pk",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
]
|
||||
"columns": ["identifier", "token"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2387,10 +2165,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
]
|
||||
"columns": ["hostname", "thumbprint"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -2434,22 +2209,15 @@
|
||||
"tableFrom": "widget_secret",
|
||||
"tableTo": "item",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"widget_secret_item_id_kind_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["item_id", "kind"],
|
||||
"name": "widget_secret_item_id_kind_pk"
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -71,6 +71,20 @@
|
||||
"when": 1783786677702,
|
||||
"tag": "0009_add_right_click_preference",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "7",
|
||||
"when": 1784305412862,
|
||||
"tag": "0010_custom_widget_v2_tables",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "7",
|
||||
"when": 1786212457549,
|
||||
"tag": "0011_futuristic_valkyrie",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+18
-115
@@ -1,7 +1,7 @@
|
||||
import SuperJSON from "superjson";
|
||||
|
||||
import { createId, objectKeys } from "@homarr/common";
|
||||
import { customWidgetImportSchema } from "@homarr/validation/custom-widget";
|
||||
import { BUNDLED_CUSTOM_WIDGETS, customWidgetDefinitionSchema } from "@homarr/custom-widgets/core";
|
||||
import {
|
||||
createDocumentationLink,
|
||||
credentialsAdminGroup,
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
import {
|
||||
apps,
|
||||
boards,
|
||||
customWidgetDefinitions,
|
||||
groupMembers,
|
||||
groupPermissions,
|
||||
groups,
|
||||
@@ -39,102 +40,11 @@ import {
|
||||
searchEngines,
|
||||
sections,
|
||||
users,
|
||||
customWidgetDefinitions,
|
||||
} from "../schema";
|
||||
import type { Integration } from "../schema";
|
||||
|
||||
const isTruthyEnv = (value: string | undefined) => ["1", "yes", "t", "true"].includes((value ?? "").toLowerCase());
|
||||
|
||||
const CUSTOM_WIDGET_SEEDS: Array<{ id: string; data: Record<string, unknown> }> = [
|
||||
{
|
||||
id: "seed-dog-facts",
|
||||
data: {
|
||||
$schema: "homarr-custom-widget-v2",
|
||||
name: "Random Dog Fact",
|
||||
description: "Displays a random fun fact about dogs",
|
||||
url: "https://dogapi.dog/api/v2/facts",
|
||||
authType: "none",
|
||||
method: "GET",
|
||||
displayType: "singleValue",
|
||||
displayConfig: {
|
||||
type: "singleValue",
|
||||
jsonPath: "$.data[0].attributes.body",
|
||||
label: "Dog Fact",
|
||||
unit: "",
|
||||
valueSize: "sm",
|
||||
labelPosition: "above",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "seed-currency-exchange",
|
||||
data: {
|
||||
$schema: "homarr-custom-widget-v2",
|
||||
name: "Currency Exchange (JPY)",
|
||||
description: "Converts 50 Japanese Yen to EUR and USD using European Central Bank rates",
|
||||
url: "https://api.frankfurter.dev/v1/latest?from=JPY&to=EUR,USD&amount=50",
|
||||
authType: "none",
|
||||
method: "GET",
|
||||
displayType: "keyValue",
|
||||
displayConfig: {
|
||||
type: "keyValue",
|
||||
mappings: [
|
||||
{ label: "50 JPY → EUR", jsonPath: "$.rates.EUR", unit: "€" },
|
||||
{ label: "50 JPY → USD", jsonPath: "$.rates.USD", unit: "$" },
|
||||
],
|
||||
layout: "list",
|
||||
columns: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "seed-jellyfin",
|
||||
data: {
|
||||
$schema: "homarr-custom-widget-v2",
|
||||
name: "Jellyfin library",
|
||||
description: "Counts the number of movies, series, episodes and songs in the library",
|
||||
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyfin.svg",
|
||||
url: "https://jellyfin.homelab.com/Items/Counts",
|
||||
authType: "apiKeyHeader",
|
||||
headerName: "X-Emby-Token",
|
||||
method: "GET",
|
||||
requestBody: null,
|
||||
displayType: "countGrid",
|
||||
displayConfig: {
|
||||
type: "countGrid",
|
||||
items: [
|
||||
{ label: "Movies", jsonPath: "$.MovieCount", unit: "" },
|
||||
{ label: "Series", jsonPath: "$.SeriesCount", unit: "" },
|
||||
{ label: "Episodes", jsonPath: "$.EpisodeCount", unit: "" },
|
||||
{ label: "Songs", jsonPath: "$.SongCount", unit: "" },
|
||||
],
|
||||
columns: 4,
|
||||
valueSize: "lg",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "seed-pokedex",
|
||||
data: {
|
||||
$schema: "homarr-custom-widget-v2",
|
||||
name: "Pokédex",
|
||||
description: "Browseable Pokémon list",
|
||||
iconUrl: "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png",
|
||||
url: "https://pokeapi.co/api/v2/pokemon?limit=75",
|
||||
authType: "none",
|
||||
headerName: null,
|
||||
method: "GET",
|
||||
requestBody: null,
|
||||
displayType: "customJsx",
|
||||
displayConfig: {
|
||||
type: "customJsx",
|
||||
template:
|
||||
'<Stack gap="md" p="xs">\n <Card\n withBorder\n radius="xl"\n p="md"\n shadow="md"\n style={{\n background: "linear-gradient(135deg, rgba(250,82,82,0.22), rgba(253,126,20,0.10), rgba(255,255,255,0.03))",\n border: "1px solid rgba(250,82,82,0.35)",\n overflow: "hidden"\n }}\n >\n <Group justify="space-between" wrap="nowrap">\n <Stack gap={2}>\n <Title order={3}>Pokédex</Title>\n </Stack>\n </Group>\n </Card>\n\n <PaginatedList pageSize={12}>\n <Grid gutter="sm">\n {data.results.map((pokemon, i) =>\n <Grid.Col span={1.5}>\n <Anchor href={pokemon.url} target="_blank" underline="never">\n <Card\n withBorder\n radius="xl"\n p="xs"\n shadow="md"\n style={{\n cursor: "pointer",\n position: "relative",\n overflow: "hidden",\n minHeight: 190,\n background: "linear-gradient(160deg, rgba(255,255,255,0.12), rgba(250,82,82,0.10), rgba(0,0,0,0.04))",\n border: "1px solid rgba(250,82,82,0.28)",\n transition: "transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease, background 180ms ease"\n }}\n >\n <Stack gap="sm" align="center">\n <Group justify="space-between" wrap="nowrap" style={{ width: "100%" }}>\n <Badge size="sm" color="red" variant="filled">\n #{String(i + 1).padStart(3, "0")}\n </Badge>\n <Text fw={800} tt="capitalize" ta="right" truncate style={{ maxWidth: 120 }}>\n {pokemon.name}\n </Text>\n </Group>\n\n <Paper\n radius="xl"\n p="xs"\n withBorder\n style={{\n background: "radial-gradient(circle, rgba(255,255,255,0.95), rgba(250,82,82,0.16))",\n border: "1px solid rgba(255,255,255,0.45)",\n boxShadow: "inset 0 0 20px rgba(255,255,255,0.25)"\n }}\n >\n <Avatar\n src={"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/" + String(i + 1) + ".png"}\n alt={pokemon.name}\n size={92}\n radius="xl"\n style={{\n transition: "transform 180ms ease",\n filter: "drop-shadow(0 8px 10px rgba(0,0,0,0.25))"\n }}\n />\n </Paper>\n </Stack>\n </Card>\n </Anchor>\n </Grid.Col>\n )}\n </Grid>\n </PaginatedList>\n</Stack>',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const seedDataAsync = async (db: Database) => {
|
||||
if (isTruthyEnv(process.env.UNSAFE_ENABLE_MOCK_INTEGRATION)) {
|
||||
console.warn(
|
||||
@@ -646,40 +556,33 @@ const seedDemoUserAsync = async (db: Database) => {
|
||||
};
|
||||
|
||||
const seedDefaultCustomWidgetsAsync = async (db: Database) => {
|
||||
const seedIds = CUSTOM_WIDGET_SEEDS.map((s) => s.id);
|
||||
const seedIds = BUNDLED_CUSTOM_WIDGETS.map(({ id }) => id);
|
||||
const existing = await db.query.customWidgetDefinitions.findMany({
|
||||
columns: { id: true },
|
||||
where: inArray(customWidgetDefinitions.id, seedIds),
|
||||
});
|
||||
const existingIds = new Set(existing.map((row) => row.id));
|
||||
|
||||
const seedValues = CUSTOM_WIDGET_SEEDS.filter((seed) => !existingIds.has(seed.id)).map((seed) => {
|
||||
const parsed = customWidgetImportSchema.parse(seed.data);
|
||||
const existingIds = new Set(existing.map(({ id }) => id));
|
||||
const values = BUNDLED_CUSTOM_WIDGETS.filter(({ id }) => !existingIds.has(id)).map(({ id, widget }) => {
|
||||
const definition = customWidgetDefinitionSchema.parse(widget);
|
||||
return {
|
||||
id: seed.id,
|
||||
name: parsed.name,
|
||||
description: parsed.description ?? null,
|
||||
iconUrl: parsed.iconUrl ?? null,
|
||||
url: parsed.url,
|
||||
authType: parsed.authType,
|
||||
headerName: parsed.headerName ?? null,
|
||||
method: parsed.method,
|
||||
requestBody: parsed.requestBody ?? null,
|
||||
displayType: parsed.displayType,
|
||||
displayConfig: SuperJSON.stringify(parsed.displayConfig),
|
||||
id,
|
||||
name: definition.name,
|
||||
description: definition.description ?? null,
|
||||
iconUrl: definition.iconUrl ?? null,
|
||||
sources: SuperJSON.stringify(definition.sources),
|
||||
requests: SuperJSON.stringify(definition.requests),
|
||||
options: SuperJSON.stringify(definition.options),
|
||||
template: definition.template,
|
||||
enabled: false,
|
||||
creatorId: null,
|
||||
};
|
||||
});
|
||||
|
||||
if (seedValues.length === 0) {
|
||||
console.log("Skipping seeding of default custom widgets as they already exist");
|
||||
if (values.length === 0) {
|
||||
console.log("Skipping seeding of bundled custom widgets because they already exist");
|
||||
return;
|
||||
}
|
||||
|
||||
await db.insert(customWidgetDefinitions).values(seedValues);
|
||||
|
||||
console.log(`Created ${seedValues.length} default custom widgets through seeding process`);
|
||||
await db.insert(customWidgetDefinitions).values(values);
|
||||
console.log(`Created ${values.length} bundled custom widgets through seeding process`);
|
||||
};
|
||||
|
||||
const seedBoardWidgetsAsync = async (db: Database) => {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE `custom_widget_v2_definition` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`description` text,
|
||||
`icon_url` text,
|
||||
`sources` text NOT NULL,
|
||||
`requests` text NOT NULL,
|
||||
`options` text NOT NULL,
|
||||
`template` text NOT NULL,
|
||||
`enabled` integer DEFAULT true NOT NULL,
|
||||
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
|
||||
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
|
||||
`creator_id` text,
|
||||
FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE set null
|
||||
);--> statement-breakpoint
|
||||
CREATE TABLE `custom_widget_v2_secret` (
|
||||
`source_id` text NOT NULL,
|
||||
`kind` text NOT NULL,
|
||||
`encrypted_value` text NOT NULL,
|
||||
`updated_at` integer NOT NULL,
|
||||
`definition_id` text NOT NULL,
|
||||
PRIMARY KEY(`definition_id`, `source_id`, `kind`),
|
||||
FOREIGN KEY (`definition_id`) REFERENCES `custom_widget_v2_definition`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);--> statement-breakpoint
|
||||
DELETE FROM `groupPermission` WHERE `permission` IN ('custom-widget-manage', 'custom-widget-secret-write');
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `layout` ADD `left_gutter_column_count` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `layout` ADD `right_gutter_column_count` integer DEFAULT 0 NOT NULL;
|
||||
@@ -88,9 +88,7 @@
|
||||
"indexes": {
|
||||
"userId_idx": {
|
||||
"name": "userId_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -99,22 +97,15 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
],
|
||||
"columns": ["provider", "provider_account_id"],
|
||||
"name": "account_provider_provider_account_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -152,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -249,12 +236,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -262,23 +245,15 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "group_id", "permission"],
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -316,12 +291,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -329,23 +300,15 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "user_id", "permission"],
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -501,9 +464,7 @@
|
||||
"indexes": {
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -512,12 +473,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -679,12 +636,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -731,22 +684,15 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["definition_id", "kind"],
|
||||
"name": "custom_widget_secret_definition_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -777,12 +723,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -790,22 +732,15 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["group_id", "user_id"],
|
||||
"name": "groupMember_group_id_user_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -836,12 +771,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -899,9 +830,7 @@
|
||||
"indexes": {
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -910,12 +839,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -923,12 +848,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -936,12 +857,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1019,12 +936,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1064,12 +977,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1077,23 +986,15 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "group_id", "permission"],
|
||||
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1124,12 +1025,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1137,22 +1034,15 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
],
|
||||
"columns": ["item_id", "integration_id"],
|
||||
"name": "integration_item_item_id_integration_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1194,16 +1084,12 @@
|
||||
"indexes": {
|
||||
"integration_secret__kind_idx": {
|
||||
"name": "integration_secret__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
},
|
||||
"integration_secret__updated_at_idx": {
|
||||
"name": "integration_secret__updated_at_idx",
|
||||
"columns": [
|
||||
"updated_at"
|
||||
],
|
||||
"columns": ["updated_at"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1212,22 +1098,15 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["integration_id", "kind"],
|
||||
"name": "integrationSecret_integration_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -1265,12 +1144,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1278,23 +1153,15 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "user_id", "permission"],
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1343,9 +1210,7 @@
|
||||
"indexes": {
|
||||
"integration__kind_idx": {
|
||||
"name": "integration__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1354,12 +1219,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1403,9 +1264,7 @@
|
||||
"indexes": {
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"columns": [
|
||||
"token"
|
||||
],
|
||||
"columns": ["token"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1414,12 +1273,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1487,12 +1342,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1500,12 +1351,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1513,23 +1360,15 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["item_id", "section_id", "layout_id"],
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1583,12 +1422,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1643,12 +1478,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1717,12 +1548,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1826,9 +1653,7 @@
|
||||
"indexes": {
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"columns": [
|
||||
"short"
|
||||
],
|
||||
"columns": ["short"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1837,12 +1662,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1883,12 +1704,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1896,22 +1713,15 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
],
|
||||
"columns": ["user_id", "section_id"],
|
||||
"name": "section_collapse_state_user_id_section_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1977,12 +1787,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1990,12 +1796,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2003,22 +1805,15 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["section_id", "layout_id"],
|
||||
"name": "section_layout_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -2085,12 +1880,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2121,9 +1912,7 @@
|
||||
"indexes": {
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"columns": [
|
||||
"setting_key"
|
||||
],
|
||||
"columns": ["setting_key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -2160,9 +1949,7 @@
|
||||
"indexes": {
|
||||
"user_id_idx": {
|
||||
"name": "user_id_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -2171,12 +1958,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2214,10 +1997,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
],
|
||||
"columns": ["hostname", "thumbprint"],
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
|
||||
}
|
||||
},
|
||||
@@ -2361,12 +2141,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2374,12 +2150,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2387,12 +2159,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2430,10 +2198,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
],
|
||||
"columns": ["identifier", "token"],
|
||||
"name": "verificationToken_identifier_token_pk"
|
||||
}
|
||||
},
|
||||
@@ -2451,4 +2216,4 @@
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,9 +88,7 @@
|
||||
"indexes": {
|
||||
"userId_idx": {
|
||||
"name": "userId_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -99,22 +97,15 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
],
|
||||
"columns": ["provider", "provider_account_id"],
|
||||
"name": "account_provider_provider_account_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -152,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -249,12 +236,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -262,23 +245,15 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "group_id", "permission"],
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -316,12 +291,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -329,23 +300,15 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "user_id", "permission"],
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -501,9 +464,7 @@
|
||||
"indexes": {
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -512,12 +473,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -680,12 +637,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -732,22 +685,15 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["definition_id", "kind"],
|
||||
"name": "custom_widget_secret_definition_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -778,12 +724,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -791,22 +733,15 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["group_id", "user_id"],
|
||||
"name": "groupMember_group_id_user_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -837,12 +772,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -900,9 +831,7 @@
|
||||
"indexes": {
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -911,12 +840,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -924,12 +849,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -937,12 +858,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1020,12 +937,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1065,12 +978,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1078,23 +987,15 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "group_id", "permission"],
|
||||
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1125,12 +1026,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1138,22 +1035,15 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
],
|
||||
"columns": ["item_id", "integration_id"],
|
||||
"name": "integration_item_item_id_integration_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1195,16 +1085,12 @@
|
||||
"indexes": {
|
||||
"integration_secret__kind_idx": {
|
||||
"name": "integration_secret__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
},
|
||||
"integration_secret__updated_at_idx": {
|
||||
"name": "integration_secret__updated_at_idx",
|
||||
"columns": [
|
||||
"updated_at"
|
||||
],
|
||||
"columns": ["updated_at"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1213,22 +1099,15 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["integration_id", "kind"],
|
||||
"name": "integrationSecret_integration_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -1266,12 +1145,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1279,23 +1154,15 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "user_id", "permission"],
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1344,9 +1211,7 @@
|
||||
"indexes": {
|
||||
"integration__kind_idx": {
|
||||
"name": "integration__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1355,12 +1220,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1404,9 +1265,7 @@
|
||||
"indexes": {
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"columns": [
|
||||
"token"
|
||||
],
|
||||
"columns": ["token"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1415,12 +1274,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1488,12 +1343,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1501,12 +1352,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1514,23 +1361,15 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["item_id", "section_id", "layout_id"],
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1584,12 +1423,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1644,12 +1479,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1718,12 +1549,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1827,9 +1654,7 @@
|
||||
"indexes": {
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"columns": [
|
||||
"short"
|
||||
],
|
||||
"columns": ["short"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1838,12 +1663,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1884,12 +1705,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1897,22 +1714,15 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
],
|
||||
"columns": ["user_id", "section_id"],
|
||||
"name": "section_collapse_state_user_id_section_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1978,12 +1788,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1991,12 +1797,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2004,22 +1806,15 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["section_id", "layout_id"],
|
||||
"name": "section_layout_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -2086,12 +1881,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2122,9 +1913,7 @@
|
||||
"indexes": {
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"columns": [
|
||||
"setting_key"
|
||||
],
|
||||
"columns": ["setting_key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -2161,9 +1950,7 @@
|
||||
"indexes": {
|
||||
"user_id_idx": {
|
||||
"name": "user_id_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -2172,12 +1959,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2215,10 +1998,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
],
|
||||
"columns": ["hostname", "thumbprint"],
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
|
||||
}
|
||||
},
|
||||
@@ -2362,12 +2142,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2375,12 +2151,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2388,12 +2160,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2431,10 +2199,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
],
|
||||
"columns": ["identifier", "token"],
|
||||
"name": "verificationToken_identifier_token_pk"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -88,9 +88,7 @@
|
||||
"indexes": {
|
||||
"userId_idx": {
|
||||
"name": "userId_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -99,22 +97,15 @@
|
||||
"name": "account_user_id_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"account_provider_provider_account_id_pk": {
|
||||
"columns": [
|
||||
"provider",
|
||||
"provider_account_id"
|
||||
],
|
||||
"columns": ["provider", "provider_account_id"],
|
||||
"name": "account_provider_provider_account_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -152,12 +143,8 @@
|
||||
"name": "apiKey_user_id_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -249,12 +236,8 @@
|
||||
"name": "boardGroupPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -262,23 +245,15 @@
|
||||
"name": "boardGroupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "boardGroupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardGroupPermission_board_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "group_id", "permission"],
|
||||
"name": "boardGroupPermission_board_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -316,12 +291,8 @@
|
||||
"name": "boardUserPermission_board_id_board_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -329,23 +300,15 @@
|
||||
"name": "boardUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "boardUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"boardUserPermission_board_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"board_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["board_id", "user_id", "permission"],
|
||||
"name": "boardUserPermission_board_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -501,9 +464,7 @@
|
||||
"indexes": {
|
||||
"board_name_unique": {
|
||||
"name": "board_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -512,12 +473,8 @@
|
||||
"name": "board_creator_id_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -680,12 +637,8 @@
|
||||
"name": "custom_widget_definition_creator_id_user_id_fk",
|
||||
"tableFrom": "custom_widget_definition",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -732,22 +685,15 @@
|
||||
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
"tableFrom": "custom_widget_secret",
|
||||
"tableTo": "custom_widget_definition",
|
||||
"columnsFrom": [
|
||||
"definition_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["definition_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"custom_widget_secret_definition_id_kind_pk": {
|
||||
"columns": [
|
||||
"definition_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["definition_id", "kind"],
|
||||
"name": "custom_widget_secret_definition_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -778,12 +724,8 @@
|
||||
"name": "groupMember_group_id_group_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -791,22 +733,15 @@
|
||||
"name": "groupMember_user_id_user_id_fk",
|
||||
"tableFrom": "groupMember",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"groupMember_group_id_user_id_pk": {
|
||||
"columns": [
|
||||
"group_id",
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["group_id", "user_id"],
|
||||
"name": "groupMember_group_id_user_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -837,12 +772,8 @@
|
||||
"name": "groupPermission_group_id_group_id_fk",
|
||||
"tableFrom": "groupPermission",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -900,9 +831,7 @@
|
||||
"indexes": {
|
||||
"group_name_unique": {
|
||||
"name": "group_name_unique",
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"columns": ["name"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -911,12 +840,8 @@
|
||||
"name": "group_owner_id_user_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["owner_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -924,12 +849,8 @@
|
||||
"name": "group_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -937,12 +858,8 @@
|
||||
"name": "group_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "group",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1020,12 +937,8 @@
|
||||
"name": "icon_icon_repository_id_iconRepository_id_fk",
|
||||
"tableFrom": "icon",
|
||||
"tableTo": "iconRepository",
|
||||
"columnsFrom": [
|
||||
"icon_repository_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["icon_repository_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1065,12 +978,8 @@
|
||||
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1078,23 +987,15 @@
|
||||
"name": "integrationGroupPermissions_group_id_group_id_fk",
|
||||
"tableFrom": "integrationGroupPermissions",
|
||||
"tableTo": "group",
|
||||
"columnsFrom": [
|
||||
"group_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["group_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"group_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "group_id", "permission"],
|
||||
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1125,12 +1026,8 @@
|
||||
"name": "integration_item_item_id_item_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1138,22 +1035,15 @@
|
||||
"name": "integration_item_integration_id_integration_id_fk",
|
||||
"tableFrom": "integration_item",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integration_item_item_id_integration_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"integration_id"
|
||||
],
|
||||
"columns": ["item_id", "integration_id"],
|
||||
"name": "integration_item_item_id_integration_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1195,16 +1085,12 @@
|
||||
"indexes": {
|
||||
"integration_secret__kind_idx": {
|
||||
"name": "integration_secret__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
},
|
||||
"integration_secret__updated_at_idx": {
|
||||
"name": "integration_secret__updated_at_idx",
|
||||
"columns": [
|
||||
"updated_at"
|
||||
],
|
||||
"columns": ["updated_at"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1213,22 +1099,15 @@
|
||||
"name": "integrationSecret_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationSecret",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationSecret_integration_id_kind_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["integration_id", "kind"],
|
||||
"name": "integrationSecret_integration_id_kind_pk"
|
||||
}
|
||||
},
|
||||
@@ -1266,12 +1145,8 @@
|
||||
"name": "integrationUserPermission_integration_id_integration_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1279,23 +1154,15 @@
|
||||
"name": "integrationUserPermission_user_id_user_id_fk",
|
||||
"tableFrom": "integrationUserPermission",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"integrationUserPermission_integration_id_user_id_permission_pk": {
|
||||
"columns": [
|
||||
"integration_id",
|
||||
"user_id",
|
||||
"permission"
|
||||
],
|
||||
"columns": ["integration_id", "user_id", "permission"],
|
||||
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
|
||||
}
|
||||
},
|
||||
@@ -1344,9 +1211,7 @@
|
||||
"indexes": {
|
||||
"integration__kind_idx": {
|
||||
"name": "integration__kind_idx",
|
||||
"columns": [
|
||||
"kind"
|
||||
],
|
||||
"columns": ["kind"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -1355,12 +1220,8 @@
|
||||
"name": "integration_app_id_app_id_fk",
|
||||
"tableFrom": "integration",
|
||||
"tableTo": "app",
|
||||
"columnsFrom": [
|
||||
"app_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["app_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1404,9 +1265,7 @@
|
||||
"indexes": {
|
||||
"invite_token_unique": {
|
||||
"name": "invite_token_unique",
|
||||
"columns": [
|
||||
"token"
|
||||
],
|
||||
"columns": ["token"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1415,12 +1274,8 @@
|
||||
"name": "invite_creator_id_user_id_fk",
|
||||
"tableFrom": "invite",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1488,12 +1343,8 @@
|
||||
"name": "item_layout_item_id_item_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1501,12 +1352,8 @@
|
||||
"name": "item_layout_section_id_section_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1514,23 +1361,15 @@
|
||||
"name": "item_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "item_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"item_layout_item_id_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["item_id", "section_id", "layout_id"],
|
||||
"name": "item_layout_item_id_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1584,12 +1423,8 @@
|
||||
"name": "item_board_id_board_id_fk",
|
||||
"tableFrom": "item",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1644,12 +1479,8 @@
|
||||
"name": "layout_board_id_board_id_fk",
|
||||
"tableFrom": "layout",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1718,12 +1549,8 @@
|
||||
"name": "media_creator_id_user_id_fk",
|
||||
"tableFrom": "media",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"creator_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["creator_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1827,9 +1654,7 @@
|
||||
"indexes": {
|
||||
"search_engine_short_unique": {
|
||||
"name": "search_engine_short_unique",
|
||||
"columns": [
|
||||
"short"
|
||||
],
|
||||
"columns": ["short"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -1838,12 +1663,8 @@
|
||||
"name": "search_engine_integration_id_integration_id_fk",
|
||||
"tableFrom": "search_engine",
|
||||
"tableTo": "integration",
|
||||
"columnsFrom": [
|
||||
"integration_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["integration_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1884,12 +1705,8 @@
|
||||
"name": "section_collapse_state_user_id_user_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1897,22 +1714,15 @@
|
||||
"name": "section_collapse_state_section_id_section_id_fk",
|
||||
"tableFrom": "section_collapse_state",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_collapse_state_user_id_section_id_pk": {
|
||||
"columns": [
|
||||
"user_id",
|
||||
"section_id"
|
||||
],
|
||||
"columns": ["user_id", "section_id"],
|
||||
"name": "section_collapse_state_user_id_section_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -1978,12 +1788,8 @@
|
||||
"name": "section_layout_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1991,12 +1797,8 @@
|
||||
"name": "section_layout_layout_id_layout_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "layout",
|
||||
"columnsFrom": [
|
||||
"layout_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["layout_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2004,22 +1806,15 @@
|
||||
"name": "section_layout_parent_section_id_section_id_fk",
|
||||
"tableFrom": "section_layout",
|
||||
"tableTo": "section",
|
||||
"columnsFrom": [
|
||||
"parent_section_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["parent_section_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"section_layout_section_id_layout_id_pk": {
|
||||
"columns": [
|
||||
"section_id",
|
||||
"layout_id"
|
||||
],
|
||||
"columns": ["section_id", "layout_id"],
|
||||
"name": "section_layout_section_id_layout_id_pk"
|
||||
}
|
||||
},
|
||||
@@ -2086,12 +1881,8 @@
|
||||
"name": "section_board_id_board_id_fk",
|
||||
"tableFrom": "section",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2122,9 +1913,7 @@
|
||||
"indexes": {
|
||||
"serverSetting_settingKey_unique": {
|
||||
"name": "serverSetting_settingKey_unique",
|
||||
"columns": [
|
||||
"setting_key"
|
||||
],
|
||||
"columns": ["setting_key"],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
@@ -2161,9 +1950,7 @@
|
||||
"indexes": {
|
||||
"user_id_idx": {
|
||||
"name": "user_id_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"columns": ["user_id"],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
@@ -2172,12 +1959,8 @@
|
||||
"name": "session_user_id_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2215,10 +1998,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"trusted_certificate_hostname_hostname_thumbprint_pk": {
|
||||
"columns": [
|
||||
"hostname",
|
||||
"thumbprint"
|
||||
],
|
||||
"columns": ["hostname", "thumbprint"],
|
||||
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
|
||||
}
|
||||
},
|
||||
@@ -2362,12 +2142,8 @@
|
||||
"name": "user_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2375,12 +2151,8 @@
|
||||
"name": "user_mobile_home_board_id_board_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "board",
|
||||
"columnsFrom": [
|
||||
"mobile_home_board_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["mobile_home_board_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2388,12 +2160,8 @@
|
||||
"name": "user_default_search_engine_id_search_engine_id_fk",
|
||||
"tableFrom": "user",
|
||||
"tableTo": "search_engine",
|
||||
"columnsFrom": [
|
||||
"default_search_engine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["default_search_engine_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2431,10 +2199,7 @@
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token_pk": {
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
],
|
||||
"columns": ["identifier", "token"],
|
||||
"name": "verificationToken_identifier_token_pk"
|
||||
}
|
||||
},
|
||||
@@ -2479,22 +2244,15 @@
|
||||
"name": "widget_secret_item_id_item_id_fk",
|
||||
"tableFrom": "widget_secret",
|
||||
"tableTo": "item",
|
||||
"columnsFrom": [
|
||||
"item_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["item_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"widget_secret_item_id_kind_pk": {
|
||||
"columns": [
|
||||
"item_id",
|
||||
"kind"
|
||||
],
|
||||
"columns": ["item_id", "kind"],
|
||||
"name": "widget_secret_item_id_kind_pk"
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -295,6 +295,20 @@
|
||||
"when": 1783786658943,
|
||||
"tag": "0041_add_right_click_preference",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 42,
|
||||
"version": "6",
|
||||
"when": 1784305283910,
|
||||
"tag": "0042_custom_widget_v2_tables",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 43,
|
||||
"version": "6",
|
||||
"when": 1786212459480,
|
||||
"tag": "0043_numerous_forgotten_one",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"exports": {
|
||||
".": "./index.ts",
|
||||
"./collection": "./collection.ts",
|
||||
"./proxy-reader": "./proxy-reader.ts",
|
||||
"./schema": "./schema/index.ts",
|
||||
"./test": "./test/index.ts",
|
||||
"./queries": "./queries/index.ts",
|
||||
@@ -46,6 +47,7 @@
|
||||
"@auth/core": "catalog:",
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/custom-widgets": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"@homarr/server-settings": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// @vitest-environment node
|
||||
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import Database from "better-sqlite3";
|
||||
import { MySqlContainer } from "@testcontainers/mysql";
|
||||
import { PostgreSqlContainer } from "@testcontainers/postgresql";
|
||||
import mysql from "mysql2/promise";
|
||||
import { Client } from "pg";
|
||||
import { stringify } from "superjson";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
dbEnv: {} as Record<string, unknown>,
|
||||
}));
|
||||
|
||||
vi.mock("@homarr/core/infrastructure/db/env", () => ({ dbEnv: mocks.dbEnv }));
|
||||
|
||||
const configureDriver = (values: Record<string, unknown>) => {
|
||||
vi.resetModules();
|
||||
for (const key of Object.keys(mocks.dbEnv)) delete mocks.dbEnv[key];
|
||||
Object.assign(mocks.dbEnv, values);
|
||||
};
|
||||
|
||||
const readSettingsAsync = async () => {
|
||||
const reader = await import("./proxy-reader");
|
||||
const result = {
|
||||
locale: await reader.getDefaultLocaleForProxyAsync(),
|
||||
onboardingStep: await reader.getOnboardingStepForProxyAsync(),
|
||||
};
|
||||
await reader.closeProxySettingsReaderAsync();
|
||||
return result;
|
||||
};
|
||||
|
||||
describe("proxy settings reader database compatibility", () => {
|
||||
test("reads SQLite settings and falls back for malformed culture data", async () => {
|
||||
const databasePath = path.join(os.tmpdir(), `homarr-proxy-reader-${process.pid}-${Date.now()}.sqlite`);
|
||||
const database = new Database(databasePath);
|
||||
database.exec("CREATE TABLE onboarding (step TEXT NOT NULL)");
|
||||
database.exec('CREATE TABLE "serverSetting" (setting_key TEXT NOT NULL, value TEXT NOT NULL)');
|
||||
database.prepare("INSERT INTO onboarding (step) VALUES (?)").run("finish");
|
||||
database
|
||||
.prepare('INSERT INTO "serverSetting" (setting_key, value) VALUES (?, ?)')
|
||||
.run("culture", stringify({ defaultLocale: "de" }));
|
||||
database.close();
|
||||
|
||||
try {
|
||||
configureDriver({ DRIVER: "better-sqlite3", URL: databasePath });
|
||||
await expect(readSettingsAsync()).resolves.toEqual({ locale: "de", onboardingStep: "finish" });
|
||||
|
||||
const malformedDatabase = new Database(databasePath);
|
||||
malformedDatabase.prepare('UPDATE "serverSetting" SET value = ? WHERE setting_key = ?').run("{", "culture");
|
||||
malformedDatabase.close();
|
||||
vi.resetModules();
|
||||
await expect(readSettingsAsync()).resolves.toEqual({ locale: "en", onboardingStep: "finish" });
|
||||
} finally {
|
||||
await fs.rm(databasePath, { force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("reads MySQL settings through the bounded host configuration", async () => {
|
||||
const container = await new MySqlContainer("mysql:latest").start();
|
||||
try {
|
||||
const connection = await mysql.createConnection({
|
||||
host: container.getHost(),
|
||||
port: container.getPort(),
|
||||
database: container.getDatabase(),
|
||||
user: container.getUsername(),
|
||||
password: container.getUserPassword(),
|
||||
});
|
||||
await connection.execute("CREATE TABLE onboarding (step VARCHAR(32) NOT NULL)");
|
||||
await connection.execute("CREATE TABLE serverSetting (setting_key VARCHAR(64) NOT NULL, value TEXT NOT NULL)");
|
||||
await connection.execute("INSERT INTO onboarding (step) VALUES (?)", ["finish"]);
|
||||
await connection.execute("INSERT INTO serverSetting (setting_key, value) VALUES (?, ?)", [
|
||||
"culture",
|
||||
stringify({ defaultLocale: "fr" }),
|
||||
]);
|
||||
await connection.end();
|
||||
|
||||
configureDriver({
|
||||
DRIVER: "mysql2",
|
||||
HOST: container.getHost(),
|
||||
PORT: container.getPort(),
|
||||
NAME: container.getDatabase(),
|
||||
USER: container.getUsername(),
|
||||
PASSWORD: container.getUserPassword(),
|
||||
});
|
||||
await expect(readSettingsAsync()).resolves.toEqual({ locale: "fr", onboardingStep: "finish" });
|
||||
} finally {
|
||||
await container.stop();
|
||||
}
|
||||
}, 120_000);
|
||||
|
||||
test("reads PostgreSQL settings through the bounded host configuration", async () => {
|
||||
const container = await new PostgreSqlContainer("postgres:latest").start();
|
||||
try {
|
||||
const connection = new Client({
|
||||
host: container.getHost(),
|
||||
port: container.getPort(),
|
||||
database: container.getDatabase(),
|
||||
user: container.getUsername(),
|
||||
password: container.getPassword(),
|
||||
});
|
||||
await connection.connect();
|
||||
await connection.query("CREATE TABLE onboarding (step TEXT NOT NULL)");
|
||||
await connection.query('CREATE TABLE "serverSetting" (setting_key TEXT NOT NULL, value TEXT NOT NULL)');
|
||||
await connection.query("INSERT INTO onboarding (step) VALUES ($1)", ["finish"]);
|
||||
await connection.query('INSERT INTO "serverSetting" (setting_key, value) VALUES ($1, $2)', [
|
||||
"culture",
|
||||
stringify({ defaultLocale: "es" }),
|
||||
]);
|
||||
await connection.end();
|
||||
|
||||
configureDriver({
|
||||
DRIVER: "node-postgres",
|
||||
HOST: container.getHost(),
|
||||
PORT: container.getPort(),
|
||||
NAME: container.getDatabase(),
|
||||
USER: container.getUsername(),
|
||||
PASSWORD: container.getPassword(),
|
||||
});
|
||||
await expect(readSettingsAsync()).resolves.toEqual({ locale: "es", onboardingStep: "finish" });
|
||||
} finally {
|
||||
await container.stop();
|
||||
}
|
||||
}, 120_000);
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const query = {
|
||||
where: vi.fn(),
|
||||
limit: vi.fn().mockResolvedValue([{ step: "finish" }]),
|
||||
};
|
||||
query.where.mockReturnValue(query);
|
||||
|
||||
return {
|
||||
dbEnv: {
|
||||
DRIVER: "mysql2",
|
||||
URL: "mysql://homarr:test@localhost:3306/homarr",
|
||||
} as Record<string, unknown>,
|
||||
mysqlCreatePool: vi.fn(() => ({})),
|
||||
postgresPool: vi.fn(function PostgresPool() {
|
||||
return {};
|
||||
}),
|
||||
database: {
|
||||
select: vi.fn(() => ({ from: vi.fn(() => query) })),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@homarr/core/infrastructure/db/env", () => ({ dbEnv: mocks.dbEnv }));
|
||||
vi.mock("mysql2", () => ({ default: { createPool: mocks.mysqlCreatePool } }));
|
||||
vi.mock("pg", () => ({ Pool: mocks.postgresPool }));
|
||||
vi.mock("drizzle-orm/mysql2", () => ({ drizzle: vi.fn(() => mocks.database) }));
|
||||
vi.mock("drizzle-orm/node-postgres", () => ({ drizzle: vi.fn(() => mocks.database) }));
|
||||
vi.mock("./proxy/mysql", () => ({
|
||||
proxySchema: { onboarding: { step: {} }, serverSettings: { settingKey: {}, value: {} } },
|
||||
}));
|
||||
vi.mock("./proxy/postgresql", () => ({
|
||||
proxySchema: { onboarding: { step: {} }, serverSettings: { settingKey: {}, value: {} } },
|
||||
}));
|
||||
|
||||
const initializeProxyReader = async () => {
|
||||
const { getOnboardingStepForProxyAsync } = await import("./proxy-reader");
|
||||
await getOnboardingStepForProxyAsync();
|
||||
};
|
||||
|
||||
describe("proxy database pools", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
for (const key of Object.keys(mocks.dbEnv)) delete mocks.dbEnv[key];
|
||||
mocks.mysqlCreatePool.mockReturnValue({});
|
||||
});
|
||||
|
||||
it("bounds MySQL URL pools instead of falling back to the driver defaults", async () => {
|
||||
Object.assign(mocks.dbEnv, {
|
||||
DRIVER: "mysql2",
|
||||
URL: "mysql://homarr:test@localhost:3306/homarr",
|
||||
});
|
||||
|
||||
await initializeProxyReader();
|
||||
|
||||
expect(mocks.mysqlCreatePool).toHaveBeenCalledWith({
|
||||
uri: "mysql://homarr:test@localhost:3306/homarr",
|
||||
connectionLimit: 1,
|
||||
maxIdle: 1,
|
||||
idleTimeout: 60_000,
|
||||
enableKeepAlive: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("bounds MySQL host pools instead of falling back to the driver defaults", async () => {
|
||||
Object.assign(mocks.dbEnv, {
|
||||
DRIVER: "mysql2",
|
||||
HOST: "localhost",
|
||||
PORT: 3306,
|
||||
NAME: "homarr",
|
||||
USER: "homarr",
|
||||
PASSWORD: "test",
|
||||
});
|
||||
|
||||
await initializeProxyReader();
|
||||
|
||||
expect(mocks.mysqlCreatePool).toHaveBeenCalledWith(expect.objectContaining({ connectionLimit: 1, maxIdle: 1 }));
|
||||
});
|
||||
|
||||
it("bounds PostgreSQL URL pools instead of falling back to the driver defaults", async () => {
|
||||
Object.assign(mocks.dbEnv, {
|
||||
DRIVER: "node-postgres",
|
||||
URL: "postgresql://homarr:test@localhost:5432/homarr",
|
||||
});
|
||||
|
||||
await initializeProxyReader();
|
||||
|
||||
expect(mocks.postgresPool).toHaveBeenCalledWith({
|
||||
connectionString: "postgresql://homarr:test@localhost:5432/homarr",
|
||||
max: 1,
|
||||
idleTimeoutMillis: 60_000,
|
||||
allowExitOnIdle: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("bounds PostgreSQL host pools instead of falling back to the driver defaults", async () => {
|
||||
Object.assign(mocks.dbEnv, {
|
||||
DRIVER: "node-postgres",
|
||||
HOST: "localhost",
|
||||
PORT: 5432,
|
||||
NAME: "homarr",
|
||||
USER: "homarr",
|
||||
PASSWORD: "test",
|
||||
});
|
||||
|
||||
await initializeProxyReader();
|
||||
|
||||
expect(mocks.postgresPool).toHaveBeenCalledWith(expect.objectContaining({ max: 1 }));
|
||||
});
|
||||
|
||||
it("retries initialization after a transient driver failure", async () => {
|
||||
Object.assign(mocks.dbEnv, {
|
||||
DRIVER: "mysql2",
|
||||
URL: "mysql://homarr:test@localhost:3306/homarr",
|
||||
});
|
||||
mocks.mysqlCreatePool.mockImplementationOnce(() => {
|
||||
throw new Error("database unavailable");
|
||||
});
|
||||
|
||||
const { getOnboardingStepForProxyAsync } = await import("./proxy-reader");
|
||||
|
||||
await expect(getOnboardingStepForProxyAsync()).rejects.toThrow("database unavailable");
|
||||
await expect(getOnboardingStepForProxyAsync()).resolves.toBe("finish");
|
||||
expect(mocks.mysqlCreatePool).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,173 @@
|
||||
import { parse as parseSuperJson } from "superjson";
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
import type { SQLWrapper } from "drizzle-orm";
|
||||
import { defaultServerSettings } from "@homarr/server-settings";
|
||||
import { dbEnv } from "@homarr/core/infrastructure/db/env";
|
||||
|
||||
type ProxyRow = Record<string, unknown>;
|
||||
type ProxySchema = {
|
||||
onboarding: { step: SQLWrapper };
|
||||
serverSettings: { settingKey: SQLWrapper; value: SQLWrapper };
|
||||
};
|
||||
type ProxyQuery = {
|
||||
where(condition: unknown): ProxyQuery;
|
||||
limit(count: number): Promise<ProxyRow[]>;
|
||||
};
|
||||
type ProxyDatabase = {
|
||||
select(selection: Record<string, unknown>): { from(table: unknown): ProxyQuery };
|
||||
};
|
||||
|
||||
type ProxyReader = {
|
||||
closeAsync: () => Promise<void>;
|
||||
getOnboardingStepAsync: () => Promise<string>;
|
||||
getDefaultLocaleAsync: () => Promise<string>;
|
||||
};
|
||||
|
||||
// The proxy is long-lived and only performs two single-row reads. Keep its
|
||||
// independent pool deliberately smaller than the application pool.
|
||||
const proxyPoolConnectionLimit = 1;
|
||||
|
||||
const createProxyReader = (database: unknown, schema: ProxySchema, closeAsync: () => Promise<void>): ProxyReader => {
|
||||
const queryDatabase = database as ProxyDatabase;
|
||||
|
||||
return {
|
||||
closeAsync,
|
||||
async getOnboardingStepAsync() {
|
||||
const rows = await queryDatabase.select({ step: schema.onboarding.step }).from(schema.onboarding).limit(1);
|
||||
const step = rows[0]?.step;
|
||||
return typeof step === "string" ? step : "start";
|
||||
},
|
||||
async getDefaultLocaleAsync() {
|
||||
const rows = await queryDatabase
|
||||
.select({ value: schema.serverSettings.value })
|
||||
.from(schema.serverSettings)
|
||||
.where(eq(schema.serverSettings.settingKey, "culture"))
|
||||
.limit(1);
|
||||
const value = rows[0]?.value;
|
||||
if (typeof value !== "string") return defaultServerSettings.culture.defaultLocale;
|
||||
|
||||
try {
|
||||
const culture: unknown = parseSuperJson(value);
|
||||
if (
|
||||
typeof culture === "object" &&
|
||||
culture !== null &&
|
||||
"defaultLocale" in culture &&
|
||||
typeof culture.defaultLocale === "string"
|
||||
) {
|
||||
return culture.defaultLocale;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to the default when a legacy or malformed value cannot be decoded.
|
||||
}
|
||||
|
||||
return defaultServerSettings.culture.defaultLocale;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const createProxyReaderAsync = async (): Promise<ProxyReader> => {
|
||||
switch (dbEnv.DRIVER) {
|
||||
case "better-sqlite3": {
|
||||
const [{ default: Database }, { drizzle }, { proxySchema }] = await Promise.all([
|
||||
import("better-sqlite3"),
|
||||
import("drizzle-orm/better-sqlite3"),
|
||||
import("./proxy/sqlite"),
|
||||
]);
|
||||
const connection = new Database(dbEnv.URL);
|
||||
const database = drizzle(connection, { schema: proxySchema });
|
||||
return createProxyReader(database, proxySchema, async () => {
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
case "mysql2": {
|
||||
const [{ default: mysql }, { drizzle }, { proxySchema }] = await Promise.all([
|
||||
import("mysql2"),
|
||||
import("drizzle-orm/mysql2"),
|
||||
import("./proxy/mysql"),
|
||||
]);
|
||||
const connection = dbEnv.HOST
|
||||
? mysql.createPool({
|
||||
host: dbEnv.HOST,
|
||||
port: dbEnv.PORT,
|
||||
database: dbEnv.NAME,
|
||||
user: dbEnv.USER,
|
||||
password: dbEnv.PASSWORD,
|
||||
connectionLimit: proxyPoolConnectionLimit,
|
||||
maxIdle: 1,
|
||||
idleTimeout: 60_000,
|
||||
enableKeepAlive: true,
|
||||
})
|
||||
: mysql.createPool({
|
||||
uri: dbEnv.URL,
|
||||
connectionLimit: proxyPoolConnectionLimit,
|
||||
maxIdle: 1,
|
||||
idleTimeout: 60_000,
|
||||
enableKeepAlive: true,
|
||||
});
|
||||
const database = drizzle(connection, { schema: proxySchema, mode: "default" });
|
||||
return createProxyReader(
|
||||
database,
|
||||
proxySchema,
|
||||
async () =>
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
connection.end((error) => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
case "node-postgres": {
|
||||
const [{ Pool }, { drizzle }, { proxySchema }] = await Promise.all([
|
||||
import("pg"),
|
||||
import("drizzle-orm/node-postgres"),
|
||||
import("./proxy/postgresql"),
|
||||
]);
|
||||
const connection = dbEnv.HOST
|
||||
? new Pool({
|
||||
host: dbEnv.HOST,
|
||||
port: dbEnv.PORT,
|
||||
database: dbEnv.NAME,
|
||||
user: dbEnv.USER,
|
||||
password: dbEnv.PASSWORD,
|
||||
max: proxyPoolConnectionLimit,
|
||||
idleTimeoutMillis: 60_000,
|
||||
allowExitOnIdle: false,
|
||||
})
|
||||
: new Pool({
|
||||
connectionString: dbEnv.URL,
|
||||
max: proxyPoolConnectionLimit,
|
||||
idleTimeoutMillis: 60_000,
|
||||
allowExitOnIdle: false,
|
||||
});
|
||||
const database = drizzle({ client: connection, schema: proxySchema });
|
||||
return createProxyReader(database, proxySchema, async () => {
|
||||
await connection.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let proxyReaderPromise: Promise<ProxyReader> | null = null;
|
||||
|
||||
const getProxyReaderAsync = () => {
|
||||
if (!proxyReaderPromise) {
|
||||
proxyReaderPromise = createProxyReaderAsync().catch((error: unknown) => {
|
||||
proxyReaderPromise = null;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
return proxyReaderPromise;
|
||||
};
|
||||
|
||||
export const getOnboardingStepForProxyAsync = async () => (await getProxyReaderAsync()).getOnboardingStepAsync();
|
||||
|
||||
export const getDefaultLocaleForProxyAsync = async () => (await getProxyReaderAsync()).getDefaultLocaleAsync();
|
||||
|
||||
export const closeProxySettingsReaderAsync = async () => {
|
||||
if (!proxyReaderPromise) return;
|
||||
const reader = await proxyReaderPromise;
|
||||
proxyReaderPromise = null;
|
||||
await reader.closeAsync();
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { mysqlTable, text, varchar } from "drizzle-orm/mysql-core";
|
||||
|
||||
export const proxySchema = {
|
||||
onboarding: mysqlTable("onboarding", {
|
||||
step: varchar("step", { length: 32 }).notNull(),
|
||||
}),
|
||||
serverSettings: mysqlTable("serverSetting", {
|
||||
settingKey: varchar("setting_key", { length: 64 }).notNull(),
|
||||
value: text("value").notNull(),
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { pgTable, text } from "drizzle-orm/pg-core";
|
||||
|
||||
export const proxySchema = {
|
||||
onboarding: pgTable("onboarding", {
|
||||
step: text("step").notNull(),
|
||||
}),
|
||||
serverSettings: pgTable("serverSetting", {
|
||||
settingKey: text("setting_key").notNull(),
|
||||
value: text("value").notNull(),
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const proxySchema = {
|
||||
onboarding: sqliteTable("onboarding", {
|
||||
step: text("step").notNull(),
|
||||
}),
|
||||
serverSettings: sqliteTable("serverSetting", {
|
||||
settingKey: text("setting_key").notNull(),
|
||||
value: text("value").notNull(),
|
||||
}),
|
||||
};
|
||||
@@ -51,6 +51,8 @@ export const {
|
||||
cronJobConfigurations,
|
||||
customWidgetDefinitions,
|
||||
customWidgetSecrets,
|
||||
legacyCustomWidgetDefinitions,
|
||||
legacyCustomWidgetSecrets,
|
||||
widgetSecrets,
|
||||
} = schema;
|
||||
|
||||
@@ -62,3 +64,5 @@ export type Integration = InferSelectModel<typeof schema.integrations>;
|
||||
export type IntegrationSecret = InferSelectModel<typeof schema.integrationSecrets>;
|
||||
export type CustomWidgetDefinition = InferSelectModel<typeof schema.customWidgetDefinitions>;
|
||||
export type CustomWidgetSecret = InferSelectModel<typeof schema.customWidgetSecrets>;
|
||||
export type LegacyCustomWidgetDefinition = InferSelectModel<typeof schema.legacyCustomWidgetDefinitions>;
|
||||
export type LegacyCustomWidgetSecret = InferSelectModel<typeof schema.legacyCustomWidgetSecrets>;
|
||||
+86
-22
@@ -6,6 +6,7 @@ import type { AnyMySqlColumn } from "drizzle-orm/mysql-core";
|
||||
import {
|
||||
boolean,
|
||||
customType,
|
||||
foreignKey,
|
||||
index,
|
||||
int,
|
||||
mysqlTable,
|
||||
@@ -39,12 +40,7 @@ import type {
|
||||
SupportedAuthProvider,
|
||||
WidgetKind,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
CustomWidgetAuthType,
|
||||
CustomWidgetDisplayType,
|
||||
CustomWidgetMethod,
|
||||
CustomWidgetSecretKind,
|
||||
} from "@homarr/validation/custom-widget";
|
||||
import type { CustomWidgetSecretKind } from "@homarr/custom-widgets/core";
|
||||
|
||||
const customBlob = customType<{ data: Buffer }>({
|
||||
dataType() {
|
||||
@@ -211,8 +207,8 @@ export const integrations = mysqlTable(
|
||||
kind: varchar({ length: 128 }).$type<IntegrationKind>().notNull(),
|
||||
appId: varchar({ length: 128 }).references(() => apps.id, { onDelete: "set null" }),
|
||||
},
|
||||
(integrations) => ({
|
||||
kindIdx: index("integration__kind_idx").on(integrations.kind),
|
||||
(table) => ({
|
||||
kindIdx: index("integration__kind_idx").on(table.kind),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -344,6 +340,8 @@ export const layouts = mysqlTable("layout", {
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
columnCount: tinyint().notNull(),
|
||||
leftGutterColumnCount: tinyint().notNull().default(0),
|
||||
rightGutterColumnCount: tinyint().notNull().default(0),
|
||||
breakpoint: smallint().notNull().default(0),
|
||||
});
|
||||
|
||||
@@ -505,18 +503,65 @@ export const onboarding = mysqlTable("onboarding", {
|
||||
previousStep: varchar({ length: 64 }).$type<OnboardingStep>(),
|
||||
});
|
||||
|
||||
export const customWidgetDefinitions = mysqlTable("custom_widget_definition", {
|
||||
/**
|
||||
* Read-only v1 definitions retained during the Custom JSX v2 upgrade.
|
||||
* Their original physical table names keep the database readable by a v1 binary.
|
||||
*/
|
||||
export const legacyCustomWidgetDefinitions = mysqlTable(
|
||||
"custom_widget_definition",
|
||||
{
|
||||
id: varchar({ length: 64 }).notNull().primaryKey(),
|
||||
name: varchar({ length: 256 }).notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: varchar({ length: 32 }).notNull().default("none"),
|
||||
headerName: varchar({ length: 256 }),
|
||||
method: varchar({ length: 16 }).notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: varchar({ length: 32 }).notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
enabled: boolean().notNull().default(true),
|
||||
createdAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
updatedAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
creatorId: varchar({ length: 64 }),
|
||||
},
|
||||
(table) => ({
|
||||
creatorFk: foreignKey({
|
||||
columns: [table.creatorId],
|
||||
foreignColumns: [users.id],
|
||||
name: "custom_widget_definition_creator_id_user_id_fk",
|
||||
}).onDelete("set null"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const legacyCustomWidgetSecrets = mysqlTable(
|
||||
"custom_widget_secret",
|
||||
{
|
||||
kind: varchar({ length: 64 }).$type<CustomWidgetSecretKind>().notNull(),
|
||||
encryptedValue: text("value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: timestamp().notNull(),
|
||||
definitionId: varchar({ length: 64 }).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({ columns: [table.definitionId, table.kind] }),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [legacyCustomWidgetDefinitions.id],
|
||||
name: "cw_secret_definition_id_cw_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const customWidgetDefinitions = mysqlTable("custom_widget_v2_definition", {
|
||||
id: varchar({ length: 64 }).notNull().primaryKey(),
|
||||
name: varchar({ length: 256 }).notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: varchar({ length: 32 }).$type<CustomWidgetAuthType>().notNull().default("none"),
|
||||
headerName: varchar({ length: 256 }),
|
||||
method: varchar({ length: 16 }).$type<CustomWidgetMethod>().notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: varchar({ length: 32 }).$type<CustomWidgetDisplayType>().notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
sources: text().notNull(),
|
||||
requests: text().notNull(),
|
||||
options: text().notNull(),
|
||||
template: text().notNull(),
|
||||
enabled: boolean().notNull().default(true),
|
||||
createdAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
updatedAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
@@ -524,21 +569,25 @@ export const customWidgetDefinitions = mysqlTable("custom_widget_definition", {
|
||||
});
|
||||
|
||||
export const customWidgetSecrets = mysqlTable(
|
||||
"custom_widget_secret",
|
||||
"custom_widget_v2_secret",
|
||||
{
|
||||
sourceId: varchar({ length: 64 }).notNull(),
|
||||
kind: varchar({ length: 64 }).$type<CustomWidgetSecretKind>().notNull(),
|
||||
value: text().$type<`${string}.${string}`>().notNull(),
|
||||
encryptedValue: text("encrypted_value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: timestamp()
|
||||
.$onUpdateFn(() => new Date())
|
||||
.notNull(),
|
||||
definitionId: varchar({ length: 64 })
|
||||
.notNull()
|
||||
.references(() => customWidgetDefinitions.id, { onDelete: "cascade" }),
|
||||
definitionId: varchar({ length: 64 }).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({
|
||||
columns: [table.definitionId, table.kind],
|
||||
columns: [table.definitionId, table.sourceId, table.kind],
|
||||
}),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [customWidgetDefinitions.id],
|
||||
name: "custom_widget_v2_secret_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -854,3 +903,18 @@ export const customWidgetSecretRelations = relations(customWidgetSecrets, ({ one
|
||||
references: [customWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetDefinitionRelations = relations(legacyCustomWidgetDefinitions, ({ many, one }) => ({
|
||||
secrets: many(legacyCustomWidgetSecrets),
|
||||
creator: one(users, {
|
||||
fields: [legacyCustomWidgetDefinitions.creatorId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetSecretRelations = relations(legacyCustomWidgetSecrets, ({ one }) => ({
|
||||
definition: one(legacyCustomWidgetDefinitions, {
|
||||
fields: [legacyCustomWidgetSecrets.definitionId],
|
||||
references: [legacyCustomWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
@@ -6,6 +6,7 @@ import type { AnyPgColumn } from "drizzle-orm/pg-core";
|
||||
import {
|
||||
boolean,
|
||||
customType,
|
||||
foreignKey,
|
||||
index,
|
||||
integer,
|
||||
pgTable,
|
||||
@@ -38,12 +39,7 @@ import type {
|
||||
SupportedAuthProvider,
|
||||
WidgetKind,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
CustomWidgetAuthType,
|
||||
CustomWidgetDisplayType,
|
||||
CustomWidgetMethod,
|
||||
CustomWidgetSecretKind,
|
||||
} from "@homarr/validation/custom-widget";
|
||||
import type { CustomWidgetSecretKind } from "@homarr/custom-widgets/core";
|
||||
|
||||
const customBlob = customType<{ data: Buffer }>({
|
||||
dataType() {
|
||||
@@ -210,8 +206,8 @@ export const integrations = pgTable(
|
||||
kind: varchar({ length: 128 }).$type<IntegrationKind>().notNull(),
|
||||
appId: varchar({ length: 128 }).references(() => apps.id, { onDelete: "set null" }),
|
||||
},
|
||||
(integrations) => ({
|
||||
kindIdx: index("integration__kind_idx").on(integrations.kind),
|
||||
(table) => ({
|
||||
kindIdx: index("integration__kind_idx").on(table.kind),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -343,6 +339,8 @@ export const layouts = pgTable("layout", {
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
columnCount: smallint().notNull(),
|
||||
leftGutterColumnCount: smallint().notNull().default(0),
|
||||
rightGutterColumnCount: smallint().notNull().default(0),
|
||||
breakpoint: smallint().notNull().default(0),
|
||||
});
|
||||
|
||||
@@ -504,18 +502,65 @@ export const onboarding = pgTable("onboarding", {
|
||||
previousStep: varchar({ length: 64 }).$type<OnboardingStep>(),
|
||||
});
|
||||
|
||||
export const customWidgetDefinitions = pgTable("custom_widget_definition", {
|
||||
/**
|
||||
* Read-only v1 definitions retained during the Custom JSX v2 upgrade.
|
||||
* Their original physical table names keep the database readable by a v1 binary.
|
||||
*/
|
||||
export const legacyCustomWidgetDefinitions = pgTable(
|
||||
"custom_widget_definition",
|
||||
{
|
||||
id: varchar({ length: 64 }).notNull().primaryKey(),
|
||||
name: varchar({ length: 256 }).notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: varchar({ length: 32 }).notNull().default("none"),
|
||||
headerName: varchar({ length: 256 }),
|
||||
method: varchar({ length: 16 }).notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: varchar({ length: 32 }).notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
enabled: boolean().notNull().default(true),
|
||||
createdAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
updatedAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
creatorId: varchar({ length: 64 }),
|
||||
},
|
||||
(table) => ({
|
||||
creatorFk: foreignKey({
|
||||
columns: [table.creatorId],
|
||||
foreignColumns: [users.id],
|
||||
name: "custom_widget_definition_creator_id_user_id_fk",
|
||||
}).onDelete("set null"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const legacyCustomWidgetSecrets = pgTable(
|
||||
"custom_widget_secret",
|
||||
{
|
||||
kind: varchar({ length: 64 }).$type<CustomWidgetSecretKind>().notNull(),
|
||||
encryptedValue: text("value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: timestamp().notNull(),
|
||||
definitionId: varchar({ length: 64 }).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({ columns: [table.definitionId, table.kind] }),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [legacyCustomWidgetDefinitions.id],
|
||||
name: "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const customWidgetDefinitions = pgTable("custom_widget_v2_definition", {
|
||||
id: varchar({ length: 64 }).notNull().primaryKey(),
|
||||
name: varchar({ length: 256 }).notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: varchar({ length: 32 }).$type<CustomWidgetAuthType>().notNull().default("none"),
|
||||
headerName: varchar({ length: 256 }),
|
||||
method: varchar({ length: 16 }).$type<CustomWidgetMethod>().notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: varchar({ length: 32 }).$type<CustomWidgetDisplayType>().notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
sources: text().notNull(),
|
||||
requests: text().notNull(),
|
||||
options: text().notNull(),
|
||||
template: text().notNull(),
|
||||
enabled: boolean().notNull().default(true),
|
||||
createdAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
updatedAt: timestamp({ mode: "date" }).notNull().defaultNow(),
|
||||
@@ -523,21 +568,25 @@ export const customWidgetDefinitions = pgTable("custom_widget_definition", {
|
||||
});
|
||||
|
||||
export const customWidgetSecrets = pgTable(
|
||||
"custom_widget_secret",
|
||||
"custom_widget_v2_secret",
|
||||
{
|
||||
sourceId: varchar({ length: 64 }).notNull(),
|
||||
kind: varchar({ length: 64 }).$type<CustomWidgetSecretKind>().notNull(),
|
||||
value: text().$type<`${string}.${string}`>().notNull(),
|
||||
encryptedValue: text("encrypted_value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: timestamp()
|
||||
.$onUpdateFn(() => new Date())
|
||||
.notNull(),
|
||||
definitionId: varchar({ length: 64 })
|
||||
.notNull()
|
||||
.references(() => customWidgetDefinitions.id, { onDelete: "cascade" }),
|
||||
definitionId: varchar({ length: 64 }).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({
|
||||
columns: [table.definitionId, table.kind],
|
||||
columns: [table.definitionId, table.sourceId, table.kind],
|
||||
}),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [customWidgetDefinitions.id],
|
||||
name: "custom_widget_v2_secret_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -853,3 +902,18 @@ export const customWidgetSecretRelations = relations(customWidgetSecrets, ({ one
|
||||
references: [customWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetDefinitionRelations = relations(legacyCustomWidgetDefinitions, ({ many, one }) => ({
|
||||
secrets: many(legacyCustomWidgetSecrets),
|
||||
creator: one(users, {
|
||||
fields: [legacyCustomWidgetDefinitions.creatorId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetSecretRelations = relations(legacyCustomWidgetSecrets, ({ one }) => ({
|
||||
definition: one(legacyCustomWidgetDefinitions, {
|
||||
fields: [legacyCustomWidgetSecrets.definitionId],
|
||||
references: [legacyCustomWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
@@ -3,7 +3,7 @@ import type { MantineSize } from "@mantine/core";
|
||||
import type { DayOfWeek } from "@mantine/dates";
|
||||
import { relations, sql } from "drizzle-orm";
|
||||
import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core";
|
||||
import { blob, index, int, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
import { blob, foreignKey, index, int, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
|
||||
import {
|
||||
backgroundImageAttachments,
|
||||
@@ -27,12 +27,7 @@ import type {
|
||||
SupportedAuthProvider,
|
||||
WidgetKind,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
CustomWidgetAuthType,
|
||||
CustomWidgetDisplayType,
|
||||
CustomWidgetMethod,
|
||||
CustomWidgetSecretKind,
|
||||
} from "@homarr/validation/custom-widget";
|
||||
import type { CustomWidgetSecretKind } from "@homarr/custom-widgets/core";
|
||||
|
||||
export * from "@homarr/core/infrastructure/certificates/hostnames/db/sqlite";
|
||||
|
||||
@@ -197,8 +192,8 @@ export const integrations = sqliteTable(
|
||||
kind: text().$type<IntegrationKind>().notNull(),
|
||||
appId: text().references(() => apps.id, { onDelete: "set null" }),
|
||||
},
|
||||
(integrations) => ({
|
||||
kindIdx: index("integration__kind_idx").on(integrations.kind),
|
||||
(table) => ({
|
||||
kindIdx: index("integration__kind_idx").on(table.kind),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -329,6 +324,8 @@ export const layouts = sqliteTable("layout", {
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
columnCount: int().notNull(),
|
||||
leftGutterColumnCount: int().notNull().default(0),
|
||||
rightGutterColumnCount: int().notNull().default(0),
|
||||
breakpoint: int().notNull().default(0),
|
||||
});
|
||||
|
||||
@@ -490,18 +487,69 @@ export const onboarding = sqliteTable("onboarding", {
|
||||
previousStep: text().$type<OnboardingStep>(),
|
||||
});
|
||||
|
||||
export const customWidgetDefinitions = sqliteTable("custom_widget_definition", {
|
||||
/**
|
||||
* Read-only v1 definitions retained during the Custom JSX v2 upgrade.
|
||||
* Their original physical table names keep the database readable by a v1 binary.
|
||||
*/
|
||||
export const legacyCustomWidgetDefinitions = sqliteTable(
|
||||
"custom_widget_definition",
|
||||
{
|
||||
id: text().notNull().primaryKey(),
|
||||
name: text().notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: text().notNull().default("none"),
|
||||
headerName: text(),
|
||||
method: text().notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: text().notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
enabled: int({ mode: "boolean" }).notNull().default(true),
|
||||
createdAt: int({ mode: "timestamp" })
|
||||
.notNull()
|
||||
.default(sql`(unixepoch())`),
|
||||
updatedAt: int({ mode: "timestamp" })
|
||||
.notNull()
|
||||
.default(sql`(unixepoch())`),
|
||||
creatorId: text(),
|
||||
},
|
||||
(table) => ({
|
||||
creatorFk: foreignKey({
|
||||
columns: [table.creatorId],
|
||||
foreignColumns: [users.id],
|
||||
name: "custom_widget_definition_creator_id_user_id_fk",
|
||||
}).onDelete("set null"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const legacyCustomWidgetSecrets = sqliteTable(
|
||||
"custom_widget_secret",
|
||||
{
|
||||
kind: text().$type<CustomWidgetSecretKind>().notNull(),
|
||||
encryptedValue: text("value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: int({ mode: "timestamp" }).notNull(),
|
||||
definitionId: text().notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({ columns: [table.definitionId, table.kind] }),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [legacyCustomWidgetDefinitions.id],
|
||||
name: "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const customWidgetDefinitions = sqliteTable("custom_widget_v2_definition", {
|
||||
id: text().notNull().primaryKey(),
|
||||
name: text().notNull(),
|
||||
description: text(),
|
||||
iconUrl: text(),
|
||||
url: text().notNull(),
|
||||
authType: text().$type<CustomWidgetAuthType>().notNull().default("none"),
|
||||
headerName: text(),
|
||||
method: text().$type<CustomWidgetMethod>().notNull().default("GET"),
|
||||
requestBody: text(),
|
||||
displayType: text().$type<CustomWidgetDisplayType>().notNull().default("singleValue"),
|
||||
displayConfig: text().default(emptySuperJSON).notNull(),
|
||||
sources: text().notNull(),
|
||||
requests: text().notNull(),
|
||||
options: text().notNull(),
|
||||
template: text().notNull(),
|
||||
enabled: int({ mode: "boolean" }).notNull().default(true),
|
||||
createdAt: int({ mode: "timestamp" })
|
||||
.notNull()
|
||||
@@ -513,21 +561,25 @@ export const customWidgetDefinitions = sqliteTable("custom_widget_definition", {
|
||||
});
|
||||
|
||||
export const customWidgetSecrets = sqliteTable(
|
||||
"custom_widget_secret",
|
||||
"custom_widget_v2_secret",
|
||||
{
|
||||
sourceId: text().notNull(),
|
||||
kind: text().$type<CustomWidgetSecretKind>().notNull(),
|
||||
value: text().$type<`${string}.${string}`>().notNull(),
|
||||
encryptedValue: text("encrypted_value").$type<`${string}.${string}`>().notNull(),
|
||||
updatedAt: int({ mode: "timestamp" })
|
||||
.$onUpdateFn(() => new Date())
|
||||
.notNull(),
|
||||
definitionId: text()
|
||||
.notNull()
|
||||
.references(() => customWidgetDefinitions.id, { onDelete: "cascade" }),
|
||||
definitionId: text().notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
compoundKey: primaryKey({
|
||||
columns: [table.definitionId, table.kind],
|
||||
columns: [table.definitionId, table.sourceId, table.kind],
|
||||
}),
|
||||
definitionFk: foreignKey({
|
||||
columns: [table.definitionId],
|
||||
foreignColumns: [customWidgetDefinitions.id],
|
||||
name: "custom_widget_v2_secret_definition_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -843,3 +895,18 @@ export const customWidgetSecretRelations = relations(customWidgetSecrets, ({ one
|
||||
references: [customWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetDefinitionRelations = relations(legacyCustomWidgetDefinitions, ({ many, one }) => ({
|
||||
secrets: many(legacyCustomWidgetSecrets),
|
||||
creator: one(users, {
|
||||
fields: [legacyCustomWidgetDefinitions.creatorId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const legacyCustomWidgetSecretRelations = relations(legacyCustomWidgetSecrets, ({ one }) => ({
|
||||
definition: one(legacyCustomWidgetDefinitions, {
|
||||
fields: [legacyCustomWidgetSecrets.definitionId],
|
||||
references: [legacyCustomWidgetDefinitions.id],
|
||||
}),
|
||||
}));
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"$schema": "homarr-custom-widget-v2",
|
||||
"name": "Currency Exchange (JPY)",
|
||||
"description": "Converts 50 Japanese Yen to EUR and USD using European Central Bank rates",
|
||||
"url": "https://api.frankfurter.dev/v1/latest?from=JPY&to=EUR,USD&amount=50",
|
||||
"authType": "none",
|
||||
"method": "GET",
|
||||
"displayType": "keyValue",
|
||||
"displayConfig": {
|
||||
"type": "keyValue",
|
||||
"mappings": [
|
||||
{ "label": "50 JPY → EUR", "jsonPath": "$.rates.EUR", "unit": "€" },
|
||||
{ "label": "50 JPY → USD", "jsonPath": "$.rates.USD", "unit": "$" }
|
||||
],
|
||||
"layout": "list",
|
||||
"columns": 2
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"$schema": "homarr-custom-widget-v2",
|
||||
"name": "Random Dog Fact",
|
||||
"description": "Displays a random fun fact about dogs",
|
||||
"url": "https://dogapi.dog/api/v2/facts",
|
||||
"authType": "none",
|
||||
"method": "GET",
|
||||
"displayType": "singleValue",
|
||||
"displayConfig": {
|
||||
"type": "singleValue",
|
||||
"jsonPath": "$.data[0].attributes.body",
|
||||
"label": "Dog Fact",
|
||||
"unit": "",
|
||||
"valueSize": "sm",
|
||||
"labelPosition": "above"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"$schema": "homarr-custom-widget-v2",
|
||||
"name": "Jellyfin library",
|
||||
"description": "Counts the number of movies, series, episodes and songs in the library",
|
||||
"iconUrl": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyfin.svg",
|
||||
"url": "https://jellyfin.homelab.com/Items/Counts",
|
||||
"authType": "apiKeyHeader",
|
||||
"headerName": "X-Emby-Token",
|
||||
"method": "GET",
|
||||
"requestBody": null,
|
||||
"displayType": "countGrid",
|
||||
"displayConfig": {
|
||||
"type": "countGrid",
|
||||
"items": [
|
||||
{ "label": "Movies", "jsonPath": "$.MovieCount", "unit": "" },
|
||||
{ "label": "Series", "jsonPath": "$.SeriesCount", "unit": "" },
|
||||
{ "label": "Episodes", "jsonPath": "$.EpisodeCount", "unit": "" },
|
||||
{ "label": "Songs", "jsonPath": "$.SongCount", "unit": "" }
|
||||
],
|
||||
"columns": 4,
|
||||
"valueSize": "lg"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"$schema": "homarr-custom-widget-v2",
|
||||
"name": "Pokédex — Charizard",
|
||||
"description": "Detailed Pokémon card with types, stats, tabs, pagination, and collapsible info",
|
||||
"iconUrl": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png",
|
||||
"url": "https://pokeapi.co/api/v2/pokemon/charizard",
|
||||
"authType": "none",
|
||||
"method": "GET",
|
||||
"displayType": "customJsx",
|
||||
"displayConfig": {
|
||||
"type": "customJsx",
|
||||
"template": "<Stack gap=\"sm\" p=\"xs\">\n <Group wrap=\"nowrap\">\n <Avatar\n src={data.sprites.front_default}\n size={80}\n radius=\"sm\"\n />\n <Stack gap={4} style={{flex: 1}}>\n <Title order={3} tt=\"capitalize\">{data.name}</Title>\n <Text size=\"xs\" c=\"dimmed\">#{String(data.id).padStart(3, \"0\")} · {data.height / 10} m · {data.weight / 10} kg</Text>\n <Group gap=\"xs\">\n {data.types.map(t =>\n <TypeBadge type={t.type.name} />\n )}\n </Group>\n </Stack>\n </Group>\n <TabsContainer defaultTab=\"stats\">\n <TabPanel value=\"stats\" label=\"Stats\">\n <Stack gap=\"xs\" pt=\"xs\">\n {data.stats.map(s =>\n <StatBar label={s.stat.name} value={s.base_stat} max={255} color={s.base_stat > 100 ? \"green\" : s.base_stat > 60 ? \"yellow\" : \"red\"} />\n )}\n </Stack>\n </TabPanel>\n <TabPanel value=\"abilities\" label=\"Abilities\">\n <Collapsible title=\"Abilities\" defaultOpen={true}>\n <Group gap=\"xs\" pt=\"xs\">\n {data.abilities.map(a =>\n <Badge variant={a.is_hidden ? \"outline\" : \"filled\"} color={a.is_hidden ? \"gray\" : \"blue\"} tt=\"capitalize\">\n {a.ability.name}{a.is_hidden ? \" (hidden)\" : \"\"}\n </Badge>\n )}\n </Group>\n </Collapsible>\n </TabPanel>\n <TabPanel value=\"moves\" label=\"Moves\">\n <PaginatedList pageSize={12}>\n {data.moves.map(m =>\n <Badge size=\"xs\" variant=\"light\" tt=\"capitalize\" mb={4}>{m.move.name}</Badge>\n )}\n </PaginatedList>\n </TabPanel>\n </TabsContainer>\n</Stack>"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { parse } from "superjson";
|
||||
import { expect } from "vitest";
|
||||
|
||||
import { BUNDLED_CUSTOM_WIDGETS, customWidgetDefinitionSchema } from "@homarr/custom-widgets/core";
|
||||
|
||||
import type { Database } from "..";
|
||||
import { eq } from "..";
|
||||
import { seedDataAsync } from "../migrations/seed";
|
||||
import { customWidgetDefinitions, customWidgetSecrets } from "../schema";
|
||||
|
||||
const expectedSeedIds = BUNDLED_CUSTOM_WIDGETS.map(({ id }) => id).toSorted();
|
||||
|
||||
const reconstructWidget = (definition: typeof customWidgetDefinitions.$inferSelect) =>
|
||||
customWidgetDefinitionSchema.parse({
|
||||
$schema: "homarr-custom-widget-v2",
|
||||
name: definition.name,
|
||||
...(definition.description === null ? {} : { description: definition.description }),
|
||||
...(definition.iconUrl === null ? {} : { iconUrl: definition.iconUrl }),
|
||||
sources: parse(definition.sources),
|
||||
requests: parse(definition.requests),
|
||||
options: parse(definition.options),
|
||||
template: definition.template,
|
||||
});
|
||||
|
||||
export const expectBundledCustomWidgetsSeeded = async (db: Database) => {
|
||||
const definitions = await db.query.customWidgetDefinitions.findMany({
|
||||
where: (table, { like }) => like(table.id, "seed-%"),
|
||||
});
|
||||
|
||||
expect(definitions.map(({ id }) => id).toSorted()).toEqual(expectedSeedIds);
|
||||
expect(definitions.every(({ enabled }) => !enabled)).toBe(true);
|
||||
expect(definitions.every(({ creatorId }) => creatorId === null)).toBe(true);
|
||||
expect(await db.$count(customWidgetSecrets)).toBe(0);
|
||||
|
||||
for (const definition of definitions) {
|
||||
const expected = BUNDLED_CUSTOM_WIDGETS.find(({ id }) => id === definition.id);
|
||||
expect(expected).toBeDefined();
|
||||
expect(reconstructWidget(definition)).toEqual(customWidgetDefinitionSchema.parse(expected?.widget));
|
||||
}
|
||||
|
||||
await db
|
||||
.update(customWidgetDefinitions)
|
||||
.set({ name: "User-edited dog facts", enabled: true })
|
||||
.where(eq(customWidgetDefinitions.id, "seed-dog-facts"));
|
||||
await db.delete(customWidgetDefinitions).where(eq(customWidgetDefinitions.id, "seed-currency-exchange"));
|
||||
|
||||
await seedDataAsync(db);
|
||||
|
||||
const reseededDefinitions = await db.query.customWidgetDefinitions.findMany({
|
||||
where: (table, { like }) => like(table.id, "seed-%"),
|
||||
});
|
||||
const editedDefinition = reseededDefinitions.find(({ id }) => id === "seed-dog-facts");
|
||||
const reseededCurrency = reseededDefinitions.find(({ id }) => id === "seed-currency-exchange");
|
||||
|
||||
expect(reseededDefinitions.map(({ id }) => id).toSorted()).toEqual(expectedSeedIds);
|
||||
expect(editedDefinition).toMatchObject({ name: "User-edited dog facts", enabled: true, creatorId: null });
|
||||
expect(reseededDefinitions.filter(({ id }) => id !== "seed-dog-facts").every(({ enabled }) => !enabled)).toBe(true);
|
||||
if (!reseededCurrency) throw new Error("Currency Exchange seed was not restored");
|
||||
expect(reconstructWidget(reseededCurrency)).toEqual(
|
||||
customWidgetDefinitionSchema.parse(
|
||||
BUNDLED_CUSTOM_WIDGETS.find(({ id }) => id === "seed-currency-exchange")?.widget,
|
||||
),
|
||||
);
|
||||
expect(await db.$count(customWidgetSecrets)).toBe(0);
|
||||
};
|
||||
@@ -1,13 +1,28 @@
|
||||
import path from "path";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { MySqlContainer } from "@testcontainers/mysql";
|
||||
import { drizzle } from "drizzle-orm/mysql2";
|
||||
import { migrate } from "drizzle-orm/mysql2/migrator";
|
||||
import mysql from "mysql2";
|
||||
import { describe, test } from "vitest";
|
||||
import SuperJSON from "superjson";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
|
||||
|
||||
import * as mysqlSchema from "../schema/mysql";
|
||||
import type { Database } from "..";
|
||||
import { seedDataAsync } from "../migrations/seed";
|
||||
import { expectBundledCustomWidgetsSeeded } from "./custom-widget-seed-assertions";
|
||||
|
||||
const applyMigration = async (connection: mysql.Connection, fileName: string) => {
|
||||
const migration = readFileSync(path.join(__dirname, "..", "migrations", "mysql", fileName), "utf8");
|
||||
for (const statement of migration
|
||||
.split("--> statement-breakpoint")
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean)) {
|
||||
await connection.promise().query(statement);
|
||||
}
|
||||
};
|
||||
|
||||
describe("Mysql Migration", () => {
|
||||
test("should add all tables and keys specified in migration files", async () => {
|
||||
@@ -31,11 +46,157 @@ describe("Mysql Migration", () => {
|
||||
await migrate(database, {
|
||||
migrationsFolder: path.join(__dirname, "..", "migrations", "mysql"),
|
||||
});
|
||||
await seedDataAsync(database as unknown as Database);
|
||||
|
||||
// Check if users table exists
|
||||
await database.query.users.findMany();
|
||||
await expectBundledCustomWidgetsSeeded(database as unknown as Database);
|
||||
const [customWidgetTables] = await connection
|
||||
.promise()
|
||||
.query<mysql.RowDataPacket[]>("SHOW TABLES LIKE 'custom_widget%'");
|
||||
expect(customWidgetTables).toHaveLength(4);
|
||||
|
||||
connection.end();
|
||||
await mysqlContainer.stop();
|
||||
}, 120_000);
|
||||
|
||||
test("Custom Widget v2 migration preserves v1 data and board references", async () => {
|
||||
const mysqlContainer = await new MySqlContainer("mysql:latest").start();
|
||||
const connection = mysql.createConnection({
|
||||
host: mysqlContainer.getHost(),
|
||||
database: mysqlContainer.getDatabase(),
|
||||
port: mysqlContainer.getPort(),
|
||||
user: mysqlContainer.getUsername(),
|
||||
password: mysqlContainer.getUserPassword(),
|
||||
multipleStatements: true,
|
||||
});
|
||||
const sql = connection.promise();
|
||||
try {
|
||||
const legacyPlacementOptions = SuperJSON.stringify({ definitionId: "legacy-weather", refreshInterval: 30 });
|
||||
await sql.query(`
|
||||
CREATE TABLE \`user\` (\`id\` varchar(64) NOT NULL PRIMARY KEY);
|
||||
CREATE TABLE \`groupPermission\` (
|
||||
\`group_id\` varchar(64) NOT NULL,
|
||||
\`permission\` text NOT NULL
|
||||
);
|
||||
CREATE TABLE \`item\` (
|
||||
\`id\` varchar(64) NOT NULL PRIMARY KEY,
|
||||
\`kind\` varchar(64) NOT NULL,
|
||||
\`options\` text NOT NULL
|
||||
);
|
||||
CREATE TABLE \`custom_widget_definition\` (
|
||||
\`id\` varchar(64) NOT NULL PRIMARY KEY,
|
||||
\`name\` varchar(256) NOT NULL,
|
||||
\`description\` text,
|
||||
\`icon_url\` text,
|
||||
\`url\` text NOT NULL,
|
||||
\`auth_type\` varchar(32) NOT NULL DEFAULT 'none',
|
||||
\`header_name\` varchar(256),
|
||||
\`method\` varchar(16) NOT NULL DEFAULT 'GET',
|
||||
\`request_body\` text,
|
||||
\`display_type\` varchar(32) NOT NULL DEFAULT 'singleValue',
|
||||
\`display_config\` text NOT NULL,
|
||||
\`enabled\` boolean NOT NULL DEFAULT true,
|
||||
\`created_at\` timestamp NOT NULL,
|
||||
\`updated_at\` timestamp NOT NULL,
|
||||
\`creator_id\` varchar(64),
|
||||
CONSTRAINT \`custom_widget_definition_creator_id_user_id_fk\`
|
||||
FOREIGN KEY (\`creator_id\`) REFERENCES \`user\`(\`id\`) ON DELETE SET NULL
|
||||
);
|
||||
CREATE TABLE \`custom_widget_secret\` (
|
||||
\`kind\` varchar(64) NOT NULL,
|
||||
\`value\` text NOT NULL,
|
||||
\`updated_at\` timestamp NOT NULL,
|
||||
\`definition_id\` varchar(64) NOT NULL,
|
||||
PRIMARY KEY (\`definition_id\`, \`kind\`),
|
||||
CONSTRAINT \`cw_secret_definition_id_cw_definition_id_fk\`
|
||||
FOREIGN KEY (\`definition_id\`) REFERENCES \`custom_widget_definition\`(\`id\`) ON DELETE CASCADE
|
||||
);
|
||||
INSERT INTO \`user\` (\`id\`) VALUES ('owner');
|
||||
INSERT INTO \`custom_widget_definition\` (
|
||||
\`id\`, \`name\`, \`url\`, \`auth_type\`, \`method\`, \`display_type\`, \`display_config\`,
|
||||
\`enabled\`, \`created_at\`, \`updated_at\`, \`creator_id\`
|
||||
) VALUES (
|
||||
'legacy-weather', 'Weather', 'https://example.test/weather', 'bearer', 'GET', 'singleValue',
|
||||
'{"type":"singleValue","jsonPath":"$.temperature"}', true,
|
||||
'2023-11-14 00:00:00', '2023-11-14 00:00:01', 'owner'
|
||||
);
|
||||
INSERT INTO \`custom_widget_secret\` (\`kind\`, \`value\`, \`updated_at\`, \`definition_id\`)
|
||||
VALUES ('apiKey', 'encrypted.value', '2023-11-14 00:00:01', 'legacy-weather');
|
||||
INSERT INTO \`groupPermission\` (\`group_id\`, \`permission\`) VALUES
|
||||
('editors', 'custom-widget-manage'),
|
||||
('editors', 'custom-widget-secret-write'),
|
||||
('editors', 'board-create');
|
||||
`);
|
||||
await sql.execute("INSERT INTO `item` (`id`, `kind`, `options`) VALUES ('weather-item', 'customApi', ?)", [
|
||||
legacyPlacementOptions,
|
||||
]);
|
||||
|
||||
await applyMigration(connection, "0044_custom_widget_v2_tables.sql");
|
||||
await sql.query(`
|
||||
INSERT INTO \`custom_widget_v2_definition\` (
|
||||
\`id\`, \`name\`, \`sources\`, \`requests\`, \`options\`, \`template\`, \`enabled\`,
|
||||
\`created_at\`, \`updated_at\`, \`creator_id\`
|
||||
) VALUES (
|
||||
'legacy-weather', 'Weather v2', '[]', '[]', '[]', '<Text>Weather</Text>', true,
|
||||
'2023-11-14 00:00:02', '2023-11-14 00:00:03', 'owner'
|
||||
);
|
||||
INSERT INTO \`custom_widget_v2_secret\` (
|
||||
\`source_id\`, \`kind\`, \`encrypted_value\`, \`updated_at\`, \`definition_id\`
|
||||
) VALUES ('weather', 'apiKey', 'encrypted.v2-value', '2023-11-14 00:00:03', 'legacy-weather');
|
||||
`);
|
||||
|
||||
const [definitions] = await sql.query<mysql.RowDataPacket[]>(
|
||||
"SELECT id, name, url, enabled, creator_id FROM custom_widget_definition",
|
||||
);
|
||||
const [secrets] = await sql.query<mysql.RowDataPacket[]>(
|
||||
"SELECT definition_id, kind, value FROM custom_widget_secret",
|
||||
);
|
||||
expect(definitions).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "legacy-weather",
|
||||
name: "Weather",
|
||||
url: "https://example.test/weather",
|
||||
enabled: 1,
|
||||
creator_id: "owner",
|
||||
}),
|
||||
]);
|
||||
expect(secrets).toEqual([
|
||||
expect.objectContaining({ definition_id: "legacy-weather", kind: "apiKey", value: "encrypted.value" }),
|
||||
]);
|
||||
const [v2Definitions] = await sql.query<mysql.RowDataPacket[]>(
|
||||
"SELECT id, name, template FROM custom_widget_v2_definition",
|
||||
);
|
||||
const [v2Secrets] = await sql.query<mysql.RowDataPacket[]>(
|
||||
"SELECT definition_id, source_id, kind, encrypted_value FROM custom_widget_v2_secret",
|
||||
);
|
||||
expect(v2Definitions).toEqual([
|
||||
expect.objectContaining({ id: "legacy-weather", name: "Weather v2", template: "<Text>Weather</Text>" }),
|
||||
]);
|
||||
expect(v2Secrets).toEqual([
|
||||
expect.objectContaining({
|
||||
definition_id: "legacy-weather",
|
||||
source_id: "weather",
|
||||
kind: "apiKey",
|
||||
encrypted_value: "encrypted.v2-value",
|
||||
}),
|
||||
]);
|
||||
const [items] = await sql.query<mysql.RowDataPacket[]>("SELECT options FROM item WHERE id = 'weather-item'");
|
||||
expect(items).toEqual([{ options: legacyPlacementOptions }]);
|
||||
const [permissions] = await sql.query<mysql.RowDataPacket[]>(
|
||||
"SELECT permission FROM groupPermission ORDER BY permission",
|
||||
);
|
||||
expect(permissions).toEqual([{ permission: "board-create" }]);
|
||||
const [v1Columns] = await sql.query<mysql.RowDataPacket[]>("SHOW COLUMNS FROM custom_widget_definition");
|
||||
expect(v1Columns.map((column) => column.Field)).toEqual(
|
||||
expect.arrayContaining(["id", "url", "auth_type", "display_type", "display_config"]),
|
||||
);
|
||||
expect(v1Columns.map((column) => column.Field)).not.toContain("sources");
|
||||
const [legacyTables] = await sql.query<mysql.RowDataPacket[]>("SHOW TABLES LIKE 'legacy_custom_widget%'");
|
||||
expect(legacyTables).toEqual([]);
|
||||
} finally {
|
||||
await sql.end();
|
||||
await mysqlContainer.stop();
|
||||
}
|
||||
}, 120_000);
|
||||
});
|
||||
@@ -1,13 +1,28 @@
|
||||
import path from "path";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { PostgreSqlContainer } from "@testcontainers/postgresql";
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||
import { Pool } from "pg";
|
||||
import { describe, test } from "vitest";
|
||||
import SuperJSON from "superjson";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
|
||||
|
||||
import * as pgSchema from "../schema/postgresql";
|
||||
import type { Database } from "..";
|
||||
import { seedDataAsync } from "../migrations/seed";
|
||||
import { expectBundledCustomWidgetsSeeded } from "./custom-widget-seed-assertions";
|
||||
|
||||
const applyMigration = async (pool: Pool, fileName: string) => {
|
||||
const migration = readFileSync(path.join(__dirname, "..", "migrations", "postgresql", fileName), "utf8");
|
||||
for (const statement of migration
|
||||
.split("--> statement-breakpoint")
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean)) {
|
||||
await pool.query(statement);
|
||||
}
|
||||
};
|
||||
|
||||
describe("PostgreSql Migration", () => {
|
||||
test("should add all tables and keys specified in migration files", async () => {
|
||||
@@ -36,13 +51,159 @@ describe("PostgreSql Migration", () => {
|
||||
await migrate(database, {
|
||||
migrationsFolder: path.join(__dirname, "..", "migrations", "postgresql"),
|
||||
});
|
||||
await seedDataAsync(database as unknown as Database);
|
||||
|
||||
// Check if users table exists
|
||||
await database.query.users.findMany();
|
||||
await expectBundledCustomWidgetsSeeded(database as unknown as Database);
|
||||
expect(
|
||||
(
|
||||
await pool.query(
|
||||
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE 'custom_widget%'",
|
||||
)
|
||||
).rows,
|
||||
).toHaveLength(4);
|
||||
|
||||
// Close the pool to release resources
|
||||
await pool.end();
|
||||
// Stop the container
|
||||
await postgreSqlContainer.stop();
|
||||
}, 40_000);
|
||||
|
||||
test("Custom Widget v2 migration preserves v1 data and board references", async () => {
|
||||
const postgreSqlContainer = await new PostgreSqlContainer("postgres:latest").start();
|
||||
const pool = new Pool({
|
||||
user: postgreSqlContainer.getUsername(),
|
||||
database: postgreSqlContainer.getDatabase(),
|
||||
password: postgreSqlContainer.getPassword(),
|
||||
port: postgreSqlContainer.getPort(),
|
||||
host: postgreSqlContainer.getHost(),
|
||||
});
|
||||
try {
|
||||
const legacyPlacementOptions = SuperJSON.stringify({ definitionId: "legacy-weather", refreshInterval: 30 });
|
||||
await pool.query(`
|
||||
CREATE TABLE "user" ("id" varchar(64) PRIMARY KEY NOT NULL);
|
||||
CREATE TABLE "groupPermission" (
|
||||
"group_id" varchar(64) NOT NULL,
|
||||
"permission" text NOT NULL
|
||||
);
|
||||
CREATE TABLE "item" (
|
||||
"id" varchar(64) PRIMARY KEY NOT NULL,
|
||||
"kind" varchar(64) NOT NULL,
|
||||
"options" text NOT NULL
|
||||
);
|
||||
CREATE TABLE "custom_widget_definition" (
|
||||
"id" varchar(64) PRIMARY KEY NOT NULL,
|
||||
"name" varchar(256) NOT NULL,
|
||||
"description" text,
|
||||
"icon_url" text,
|
||||
"url" text NOT NULL,
|
||||
"auth_type" varchar(32) DEFAULT 'none' NOT NULL,
|
||||
"header_name" varchar(256),
|
||||
"method" varchar(16) DEFAULT 'GET' NOT NULL,
|
||||
"request_body" text,
|
||||
"display_type" varchar(32) DEFAULT 'singleValue' NOT NULL,
|
||||
"display_config" text NOT NULL,
|
||||
"enabled" boolean DEFAULT true NOT NULL,
|
||||
"created_at" timestamp NOT NULL,
|
||||
"updated_at" timestamp NOT NULL,
|
||||
"creator_id" varchar(64),
|
||||
CONSTRAINT "custom_widget_definition_creator_id_user_id_fk"
|
||||
FOREIGN KEY ("creator_id") REFERENCES "user"("id") ON DELETE SET NULL
|
||||
);
|
||||
CREATE TABLE "custom_widget_secret" (
|
||||
"kind" varchar(64) NOT NULL,
|
||||
"value" text NOT NULL,
|
||||
"updated_at" timestamp NOT NULL,
|
||||
"definition_id" varchar(64) NOT NULL,
|
||||
CONSTRAINT "custom_widget_secret_definition_id_kind_pk" PRIMARY KEY("definition_id", "kind"),
|
||||
CONSTRAINT "custom_widget_secret_definition_id_custom_widget_definition_id_fk"
|
||||
FOREIGN KEY ("definition_id") REFERENCES "custom_widget_definition"("id") ON DELETE CASCADE
|
||||
);
|
||||
INSERT INTO "user" ("id") VALUES ('owner');
|
||||
INSERT INTO "custom_widget_definition" (
|
||||
"id", "name", "url", "auth_type", "method", "display_type", "display_config", "enabled",
|
||||
"created_at", "updated_at", "creator_id"
|
||||
) VALUES (
|
||||
'legacy-weather', 'Weather', 'https://example.test/weather', 'bearer', 'GET', 'singleValue',
|
||||
'{"type":"singleValue","jsonPath":"$.temperature"}', true,
|
||||
'2023-11-14 00:00:00', '2023-11-14 00:00:01', 'owner'
|
||||
);
|
||||
INSERT INTO "custom_widget_secret" ("kind", "value", "updated_at", "definition_id")
|
||||
VALUES ('apiKey', 'encrypted.value', '2023-11-14 00:00:01', 'legacy-weather');
|
||||
INSERT INTO "groupPermission" ("group_id", "permission") VALUES
|
||||
('editors', 'custom-widget-manage'),
|
||||
('editors', 'custom-widget-secret-write'),
|
||||
('editors', 'board-create');
|
||||
`);
|
||||
await pool.query(`INSERT INTO "item" ("id", "kind", "options") VALUES ('weather-item', 'customApi', $1)`, [
|
||||
legacyPlacementOptions,
|
||||
]);
|
||||
|
||||
await applyMigration(pool, "0010_custom_widget_v2_tables.sql");
|
||||
await pool.query(`
|
||||
INSERT INTO "custom_widget_v2_definition" (
|
||||
"id", "name", "sources", "requests", "options", "template", "enabled",
|
||||
"created_at", "updated_at", "creator_id"
|
||||
) VALUES (
|
||||
'legacy-weather', 'Weather v2', '[]', '[]', '[]', '<Text>Weather</Text>', true,
|
||||
'2023-11-14 00:00:02', '2023-11-14 00:00:03', 'owner'
|
||||
);
|
||||
INSERT INTO "custom_widget_v2_secret" (
|
||||
"source_id", "kind", "encrypted_value", "updated_at", "definition_id"
|
||||
) VALUES ('weather', 'apiKey', 'encrypted.v2-value', '2023-11-14 00:00:03', 'legacy-weather');
|
||||
`);
|
||||
|
||||
expect(
|
||||
(await pool.query("SELECT id, name, url, enabled, creator_id FROM custom_widget_definition")).rows,
|
||||
).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "legacy-weather",
|
||||
name: "Weather",
|
||||
url: "https://example.test/weather",
|
||||
enabled: true,
|
||||
creator_id: "owner",
|
||||
}),
|
||||
]);
|
||||
expect((await pool.query("SELECT definition_id, kind, value FROM custom_widget_secret")).rows).toEqual([
|
||||
expect.objectContaining({ definition_id: "legacy-weather", kind: "apiKey", value: "encrypted.value" }),
|
||||
]);
|
||||
expect((await pool.query("SELECT id, name, template FROM custom_widget_v2_definition")).rows).toEqual([
|
||||
expect.objectContaining({ id: "legacy-weather", name: "Weather v2", template: "<Text>Weather</Text>" }),
|
||||
]);
|
||||
expect(
|
||||
(await pool.query("SELECT definition_id, source_id, kind, encrypted_value FROM custom_widget_v2_secret")).rows,
|
||||
).toEqual([
|
||||
expect.objectContaining({
|
||||
definition_id: "legacy-weather",
|
||||
source_id: "weather",
|
||||
kind: "apiKey",
|
||||
encrypted_value: "encrypted.v2-value",
|
||||
}),
|
||||
]);
|
||||
expect((await pool.query("SELECT options FROM item WHERE id = 'weather-item'")).rows).toEqual([
|
||||
{ options: legacyPlacementOptions },
|
||||
]);
|
||||
expect((await pool.query('SELECT "permission" FROM "groupPermission" ORDER BY "permission"')).rows).toEqual([
|
||||
{ permission: "board-create" },
|
||||
]);
|
||||
const v1Columns = (
|
||||
await pool.query(
|
||||
"SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'custom_widget_definition'",
|
||||
)
|
||||
).rows.map((column: { column_name: string }) => column.column_name);
|
||||
expect(v1Columns).toEqual(expect.arrayContaining(["id", "url", "auth_type", "display_type", "display_config"]));
|
||||
expect(v1Columns).not.toContain("sources");
|
||||
expect(
|
||||
(
|
||||
await pool.query(
|
||||
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name LIKE 'legacy_custom_widget%'",
|
||||
)
|
||||
).rows,
|
||||
).toEqual([]);
|
||||
} finally {
|
||||
await pool.end();
|
||||
await postgreSqlContainer.stop();
|
||||
}
|
||||
}, 40_000);
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable import/namespace -- The test compares matching schema tables by their shared keys. */
|
||||
/* eslint-disable import/namespace -- This test compares equivalent schema exports by shared dynamic keys. */
|
||||
import type { Column, InferSelectModel } from "drizzle-orm";
|
||||
import type { ForeignKey as MysqlForeignKey, MySqlTableWithColumns } from "drizzle-orm/mysql-core";
|
||||
import type { PgTableWithColumns, ForeignKey as PostgresqlForeignKey } from "drizzle-orm/pg-core";
|
||||
@@ -24,7 +24,6 @@ type FixedMysqlConfig = {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type FixedPostgresqlConfig = {
|
||||
[key in keyof PostgreisqlConfig]: {
|
||||
[column in keyof PostgreisqlConfig[key]]: {
|
||||
@@ -64,6 +63,7 @@ test("schemas should match", () => {
|
||||
if (!("uniqueName" in sqliteColumn)) return;
|
||||
if (!("primary" in sqliteColumn)) return;
|
||||
|
||||
// oxlint-disable-next-line import/namespace -- this test intentionally compares matching dynamic schema keys.
|
||||
const mysqlTable = mysqlSchema[tableName];
|
||||
|
||||
const mysqlColumn = mysqlTable[columnName as keyof typeof mysqlTable] as object;
|
||||
@@ -85,6 +85,7 @@ test("schemas should match", () => {
|
||||
).toEqual(mysqlColumn.primary);
|
||||
});
|
||||
|
||||
// oxlint-disable-next-line import/namespace -- this test intentionally compares matching dynamic schema keys.
|
||||
const mysqlTable = mysqlSchema[tableName];
|
||||
const sqliteForeignKeys = sqliteTable[Symbol.for("drizzle:SQLiteInlineForeignKeys") as keyof typeof sqliteTable] as
|
||||
| SqliteForeignKey[]
|
||||
@@ -145,6 +146,7 @@ test("schemas should match for postgresql", () => {
|
||||
objectEntries(sqliteSchema).forEach(([tableName, sqliteTable]) => {
|
||||
// keys of sqliteSchema and postgresqlSchema are the same, so we can safely use tableName as key
|
||||
// skipcq: JS-E1007
|
||||
// oxlint-disable-next-line import/namespace -- this test intentionally compares matching dynamic schema keys.
|
||||
const postgresqlTable = postgresqlSchema[tableName];
|
||||
Object.entries(sqliteTable).forEach(([columnName, sqliteColumn]: [string, object]) => {
|
||||
if (!("isUnique" in sqliteColumn)) return;
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
import path from "path";
|
||||
import { readFileSync } from "node:fs";
|
||||
import BetterSqlite3 from "better-sqlite3";
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import SuperJSON from "superjson";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
|
||||
|
||||
import type { Database } from "..";
|
||||
import { seedDataAsync } from "../migrations/seed";
|
||||
import * as sqliteSchema from "../schema/sqlite";
|
||||
import { expectBundledCustomWidgetsSeeded } from "./custom-widget-seed-assertions";
|
||||
|
||||
const applyMigration = (connection: BetterSqlite3.Database, fileName: string) => {
|
||||
const migration = readFileSync(path.join(__dirname, "..", "migrations", "sqlite", fileName), "utf8");
|
||||
for (const statement of migration
|
||||
.split("--> statement-breakpoint")
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean)) {
|
||||
connection.exec(statement);
|
||||
}
|
||||
};
|
||||
|
||||
test("SQLite migrations seed the five disabled bundled custom widgets", async () => {
|
||||
const connection = new BetterSqlite3(":memory:");
|
||||
const database = drizzle(connection, { schema: sqliteSchema, casing: DB_CASING });
|
||||
|
||||
migrate(database, { migrationsFolder: path.join(__dirname, "..", "migrations", "sqlite") });
|
||||
await seedDataAsync(database as unknown as Database);
|
||||
|
||||
await expectBundledCustomWidgetsSeeded(database as unknown as Database);
|
||||
expect(
|
||||
connection
|
||||
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'custom_widget%' ORDER BY name")
|
||||
.all(),
|
||||
).toEqual([
|
||||
{ name: "custom_widget_definition" },
|
||||
{ name: "custom_widget_secret" },
|
||||
{ name: "custom_widget_v2_definition" },
|
||||
{ name: "custom_widget_v2_secret" },
|
||||
]);
|
||||
|
||||
connection.close();
|
||||
});
|
||||
|
||||
test("Custom Widget v2 migration preserves v1 data and board references", () => {
|
||||
const connection = new BetterSqlite3(":memory:");
|
||||
const legacyPlacementOptions = SuperJSON.stringify({ definitionId: "legacy-weather", refreshInterval: 30 });
|
||||
connection.exec(`
|
||||
CREATE TABLE user (id text PRIMARY KEY NOT NULL);
|
||||
CREATE TABLE groupPermission (
|
||||
group_id text NOT NULL,
|
||||
permission text NOT NULL
|
||||
);
|
||||
CREATE TABLE item (
|
||||
id text PRIMARY KEY NOT NULL,
|
||||
kind text NOT NULL,
|
||||
options text NOT NULL
|
||||
);
|
||||
CREATE TABLE custom_widget_definition (
|
||||
id text PRIMARY KEY NOT NULL,
|
||||
name text NOT NULL,
|
||||
description text,
|
||||
icon_url text,
|
||||
url text NOT NULL,
|
||||
auth_type text DEFAULT 'none' NOT NULL,
|
||||
header_name text,
|
||||
method text DEFAULT 'GET' NOT NULL,
|
||||
request_body text,
|
||||
display_type text DEFAULT 'singleValue' NOT NULL,
|
||||
display_config text DEFAULT '{}' NOT NULL,
|
||||
enabled integer DEFAULT true NOT NULL,
|
||||
created_at integer NOT NULL,
|
||||
updated_at integer NOT NULL,
|
||||
creator_id text REFERENCES user(id) ON DELETE SET NULL
|
||||
);
|
||||
CREATE TABLE custom_widget_secret (
|
||||
kind text NOT NULL,
|
||||
value text NOT NULL,
|
||||
updated_at integer NOT NULL,
|
||||
definition_id text NOT NULL REFERENCES custom_widget_definition(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY(definition_id, kind)
|
||||
);
|
||||
INSERT INTO user (id) VALUES ('owner');
|
||||
INSERT INTO custom_widget_definition (
|
||||
id, name, url, auth_type, method, display_type, display_config, enabled, created_at, updated_at, creator_id
|
||||
) VALUES ('legacy-weather', 'Weather', 'https://example.test/weather', 'bearer', 'GET', 'singleValue',
|
||||
'{"type":"singleValue","jsonPath":"$.temperature"}', true, 1700000000, 1700000001, 'owner');
|
||||
INSERT INTO custom_widget_secret (kind, value, updated_at, definition_id)
|
||||
VALUES ('apiKey', 'encrypted.value', 1700000001, 'legacy-weather');
|
||||
INSERT INTO groupPermission (group_id, permission) VALUES
|
||||
('editors', 'custom-widget-manage'),
|
||||
('editors', 'custom-widget-secret-write'),
|
||||
('editors', 'board-create');
|
||||
`);
|
||||
connection
|
||||
.prepare("INSERT INTO item (id, kind, options) VALUES ('weather-item', 'customApi', ?)")
|
||||
.run(legacyPlacementOptions);
|
||||
|
||||
applyMigration(connection, "0042_custom_widget_v2_tables.sql");
|
||||
connection.exec(`
|
||||
INSERT INTO custom_widget_v2_definition (
|
||||
id, name, sources, requests, options, template, enabled, created_at, updated_at, creator_id
|
||||
) VALUES (
|
||||
'legacy-weather', 'Weather v2', '[]', '[]', '[]', '<Text>Weather</Text>', true,
|
||||
1700000002, 1700000003, 'owner'
|
||||
);
|
||||
INSERT INTO custom_widget_v2_secret (source_id, kind, encrypted_value, updated_at, definition_id)
|
||||
VALUES ('weather', 'apiKey', 'encrypted.v2-value', 1700000003, 'legacy-weather');
|
||||
`);
|
||||
|
||||
expect(connection.prepare("SELECT * FROM custom_widget_definition").get()).toMatchObject({
|
||||
id: "legacy-weather",
|
||||
name: "Weather",
|
||||
url: "https://example.test/weather",
|
||||
enabled: 1,
|
||||
creator_id: "owner",
|
||||
});
|
||||
expect(connection.prepare("SELECT * FROM custom_widget_secret").get()).toMatchObject({
|
||||
definition_id: "legacy-weather",
|
||||
kind: "apiKey",
|
||||
value: "encrypted.value",
|
||||
});
|
||||
expect(connection.prepare("SELECT * FROM custom_widget_v2_definition").get()).toMatchObject({
|
||||
id: "legacy-weather",
|
||||
name: "Weather v2",
|
||||
template: "<Text>Weather</Text>",
|
||||
});
|
||||
expect(connection.prepare("SELECT * FROM custom_widget_v2_secret").get()).toMatchObject({
|
||||
definition_id: "legacy-weather",
|
||||
source_id: "weather",
|
||||
encrypted_value: "encrypted.v2-value",
|
||||
});
|
||||
expect(connection.prepare("SELECT options FROM item WHERE id = 'weather-item'").get()).toEqual({
|
||||
options: legacyPlacementOptions,
|
||||
});
|
||||
expect(connection.prepare("SELECT permission FROM groupPermission ORDER BY permission").all()).toEqual([
|
||||
{ permission: "board-create" },
|
||||
]);
|
||||
expect(
|
||||
connection
|
||||
.prepare(
|
||||
`SELECT id, name, url, auth_type, header_name, method, request_body, display_type, display_config,
|
||||
enabled, created_at, updated_at, creator_id
|
||||
FROM custom_widget_definition`,
|
||||
)
|
||||
.get(),
|
||||
).toMatchObject({
|
||||
id: "legacy-weather",
|
||||
auth_type: "bearer",
|
||||
display_type: "singleValue",
|
||||
});
|
||||
expect(
|
||||
connection
|
||||
.prepare(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'legacy_custom_widget%' ORDER BY name",
|
||||
)
|
||||
.all(),
|
||||
).toEqual([]);
|
||||
|
||||
connection.close();
|
||||
});
|
||||
@@ -4,5 +4,5 @@
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "migrations/*/migrate.cjs"]
|
||||
}
|
||||
Reference in new issue
Block a user