feat: added bordercolor option for dynamic section (#2334)
This commit is contained in:
@@ -27,7 +27,13 @@ import {
|
||||
users,
|
||||
} from "@homarr/db/schema";
|
||||
import type { WidgetKind } from "@homarr/definitions";
|
||||
import { everyoneGroup, getPermissionsWithChildren, getPermissionsWithParents, widgetKinds } from "@homarr/definitions";
|
||||
import {
|
||||
emptySuperJSON,
|
||||
everyoneGroup,
|
||||
getPermissionsWithChildren,
|
||||
getPermissionsWithParents,
|
||||
widgetKinds,
|
||||
} from "@homarr/definitions";
|
||||
import { importOldmarrAsync } from "@homarr/old-import";
|
||||
import { importJsonFileSchema } from "@homarr/old-import/shared";
|
||||
import { oldmarrConfigSchema } from "@homarr/old-schema";
|
||||
@@ -736,6 +742,7 @@ export const boardRouter = createTRPCRouter({
|
||||
kind: section.kind,
|
||||
yOffset: section.kind !== "dynamic" ? section.yOffset : null,
|
||||
xOffset: section.kind === "dynamic" ? null : 0,
|
||||
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
|
||||
name: "name" in section ? section.name : null,
|
||||
boardId: dbBoard.id,
|
||||
})),
|
||||
@@ -861,6 +868,7 @@ export const boardRouter = createTRPCRouter({
|
||||
.set({
|
||||
yOffset: prev?.kind !== "dynamic" && "yOffset" in section ? section.yOffset : null,
|
||||
xOffset: prev?.kind !== "dynamic" && "yOffset" in section ? 0 : null,
|
||||
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
|
||||
name: prev?.kind === "category" && "name" in section ? section.name : null,
|
||||
})
|
||||
.where(eq(schema.sections.id, section.id));
|
||||
@@ -934,6 +942,7 @@ export const boardRouter = createTRPCRouter({
|
||||
kind: section.kind,
|
||||
yOffset: section.kind !== "dynamic" ? section.yOffset : null,
|
||||
xOffset: section.kind === "dynamic" ? null : 0,
|
||||
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
|
||||
name: "name" in section ? section.name : null,
|
||||
boardId: dbBoard.id,
|
||||
})),
|
||||
@@ -1069,6 +1078,7 @@ export const boardRouter = createTRPCRouter({
|
||||
.set({
|
||||
yOffset: prev?.kind !== "dynamic" && "yOffset" in section ? section.yOffset : null,
|
||||
xOffset: prev?.kind !== "dynamic" && "yOffset" in section ? 0 : null,
|
||||
options: section.kind === "dynamic" ? superjson.stringify(section.options) : emptySuperJSON,
|
||||
name: prev?.kind === "category" && "name" in section ? section.name : null,
|
||||
})
|
||||
.where(eq(sections.id, section.id))
|
||||
@@ -1561,6 +1571,7 @@ const getFullBoardWithWhereAsync = async (db: Database, where: SQL<unknown>, use
|
||||
...section,
|
||||
xOffset: section.xOffset,
|
||||
yOffset: section.yOffset,
|
||||
options: superjson.parse(section.options ?? emptySuperJSON),
|
||||
layouts: section.layouts.map((layout) => ({
|
||||
xOffset: layout.xOffset,
|
||||
yOffset: layout.yOffset,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `section` ADD `options` text DEFAULT ('{"json": {}}');
|
||||
2020
packages/db/migrations/mysql/meta/0031_snapshot.json
Normal file
2020
packages/db/migrations/mysql/meta/0031_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -218,6 +218,13 @@
|
||||
"when": 1740256006328,
|
||||
"tag": "0030_migrate_item_and_section_for_layouts",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "5",
|
||||
"when": 1740784837957,
|
||||
"tag": "0031_add_dynamic_section_options",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `section` ADD `options` text DEFAULT '{"json": {}}';
|
||||
1940
packages/db/migrations/sqlite/meta/0031_snapshot.json
Normal file
1940
packages/db/migrations/sqlite/meta/0031_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -218,6 +218,13 @@
|
||||
"when": 1740255968549,
|
||||
"tag": "0030_migrate_item_and_section_for_layouts",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "6",
|
||||
"when": 1740784849045,
|
||||
"tag": "0031_add_dynamic_section_options",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ import {
|
||||
varchar,
|
||||
} from "drizzle-orm/mysql-core";
|
||||
|
||||
import {
|
||||
backgroundImageAttachments,
|
||||
backgroundImageRepeats,
|
||||
backgroundImageSizes,
|
||||
emptySuperJSON,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
BackgroundImageAttachment,
|
||||
BackgroundImageRepeat,
|
||||
@@ -33,7 +39,6 @@ import type {
|
||||
SupportedAuthProvider,
|
||||
WidgetKind,
|
||||
} from "@homarr/definitions";
|
||||
import { backgroundImageAttachments, backgroundImageRepeats, backgroundImageSizes } from "@homarr/definitions";
|
||||
|
||||
const customBlob = customType<{ data: Buffer }>({
|
||||
dataType() {
|
||||
@@ -388,6 +393,7 @@ export const sections = mysqlTable("section", {
|
||||
xOffset: int(),
|
||||
yOffset: int(),
|
||||
name: text(),
|
||||
options: text().default(emptySuperJSON),
|
||||
});
|
||||
|
||||
export const sectionCollapseStates = mysqlTable(
|
||||
@@ -414,8 +420,8 @@ export const items = mysqlTable("item", {
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
kind: text().$type<WidgetKind>().notNull(),
|
||||
options: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
advancedOptions: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
options: text().default(emptySuperJSON).notNull(),
|
||||
advancedOptions: text().default(emptySuperJSON).notNull(),
|
||||
});
|
||||
|
||||
export const apps = mysqlTable("app", {
|
||||
@@ -461,7 +467,7 @@ export const iconRepositories = mysqlTable("iconRepository", {
|
||||
|
||||
export const serverSettings = mysqlTable("serverSetting", {
|
||||
settingKey: varchar({ length: 64 }).notNull().unique().primaryKey(),
|
||||
value: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
value: text().default(emptySuperJSON).notNull(),
|
||||
});
|
||||
|
||||
export const apiKeyRelations = relations(apiKeys, ({ one }) => ({
|
||||
|
||||
@@ -5,7 +5,12 @@ 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 { backgroundImageAttachments, backgroundImageRepeats, backgroundImageSizes } from "@homarr/definitions";
|
||||
import {
|
||||
backgroundImageAttachments,
|
||||
backgroundImageRepeats,
|
||||
backgroundImageSizes,
|
||||
emptySuperJSON,
|
||||
} from "@homarr/definitions";
|
||||
import type {
|
||||
BackgroundImageAttachment,
|
||||
BackgroundImageRepeat,
|
||||
@@ -373,6 +378,7 @@ export const sections = sqliteTable("section", {
|
||||
xOffset: int(),
|
||||
yOffset: int(),
|
||||
name: text(),
|
||||
options: text().default(emptySuperJSON),
|
||||
});
|
||||
|
||||
export const sectionCollapseStates = sqliteTable(
|
||||
@@ -399,8 +405,8 @@ export const items = sqliteTable("item", {
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
kind: text().$type<WidgetKind>().notNull(),
|
||||
options: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
advancedOptions: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
options: text().default(emptySuperJSON).notNull(),
|
||||
advancedOptions: text().default(emptySuperJSON).notNull(),
|
||||
});
|
||||
|
||||
export const apps = sqliteTable("app", {
|
||||
@@ -446,7 +452,7 @@ export const iconRepositories = sqliteTable("iconRepository", {
|
||||
|
||||
export const serverSettings = sqliteTable("serverSetting", {
|
||||
settingKey: text().notNull().unique().primaryKey(),
|
||||
value: text().default('{"json": {}}').notNull(), // empty superjson object
|
||||
value: text().default(emptySuperJSON).notNull(),
|
||||
});
|
||||
|
||||
export const apiKeyRelations = relations(apiKeys, ({ one }) => ({
|
||||
|
||||
1
packages/definitions/src/emptysuperjson.ts
Normal file
1
packages/definitions/src/emptysuperjson.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const emptySuperJSON = '{"json": {}}';
|
||||
@@ -11,3 +11,4 @@ export * from "./docs";
|
||||
export * from "./cookie";
|
||||
export * from "./search-engine";
|
||||
export * from "./onboarding";
|
||||
export * from "./emptysuperjson";
|
||||
|
||||
@@ -972,6 +972,11 @@
|
||||
"create": "New dynamic section",
|
||||
"remove": "Remove dynamic section"
|
||||
},
|
||||
"option": {
|
||||
"borderColor": {
|
||||
"label": "Border color"
|
||||
}
|
||||
},
|
||||
"remove": {
|
||||
"title": "Remove dynamic section",
|
||||
"message": "Are you sure you want to remove this dynamic section? Items will be moved at the same location in the parent section."
|
||||
|
||||
@@ -32,6 +32,7 @@ export {
|
||||
sectionSchema,
|
||||
itemAdvancedOptionsSchema,
|
||||
sharedItemSchema,
|
||||
dynamicSectionOptionsSchema,
|
||||
type BoardItemAdvancedOptions,
|
||||
type BoardItemIntegration,
|
||||
} from "./shared";
|
||||
|
||||
@@ -58,9 +58,14 @@ const emptySectionSchema = z.object({
|
||||
xOffset: z.number(),
|
||||
});
|
||||
|
||||
export const dynamicSectionOptionsSchema = z.object({
|
||||
borderColor: z.string().default(""),
|
||||
});
|
||||
|
||||
const dynamicSectionSchema = z.object({
|
||||
id: z.string(),
|
||||
kind: z.literal("dynamic"),
|
||||
options: dynamicSectionOptionsSchema,
|
||||
layouts: z.array(
|
||||
z.object({
|
||||
layoutId: z.string(),
|
||||
|
||||
Reference in New Issue
Block a user