use column for default view

This commit is contained in:
miloschwartz
2026-07-03 09:59:49 -04:00
parent a89509c8bd
commit b53f80d317
8 changed files with 19 additions and 33 deletions
+1 -1
View File
@@ -3621,7 +3621,7 @@
"resourceLauncherSiteGroupingDisabled": "Site grouping is unavailable at this scale. Filter by site to group a smaller set.", "resourceLauncherSiteGroupingDisabled": "Site grouping is unavailable at this scale. Filter by site to group a smaller set.",
"resourceLauncherLabelGroupingDisabled": "Label grouping is unavailable at this scale.", "resourceLauncherLabelGroupingDisabled": "Label grouping is unavailable at this scale.",
"resourceLauncherCompactModeHint": "Showing a simplified list for faster browsing. Use search or filters to narrow results.", "resourceLauncherCompactModeHint": "Showing a simplified list for faster browsing. Use search or filters to narrow results.",
"resourceLauncherCompactGroupingHint": "Apply site or label filters to enable grouping in compact mode.", "resourceLauncherCompactGroupingHint": "Apply site or label filters to enable grouping.",
"resourceLauncherCopiedToClipboard": "Copied to clipboard", "resourceLauncherCopiedToClipboard": "Copied to clipboard",
"resourceLauncherCopiedAccessDescription": "Resource access has been copied to your clipboard.", "resourceLauncherCopiedAccessDescription": "Resource access has been copied to your clipboard.",
"resourceLauncherViewNamePlaceholder": "View name", "resourceLauncherViewNamePlaceholder": "View name",
+1
View File
@@ -232,6 +232,7 @@ export const launcherViews = pgTable("launcherViews", {
}), }),
name: varchar("name").notNull(), name: varchar("name").notNull(),
config: text("config").notNull(), config: text("config").notNull(),
isDefault: boolean("isDefault").notNull().default(false),
createdAt: varchar("createdAt").notNull(), createdAt: varchar("createdAt").notNull(),
updatedAt: varchar("updatedAt").notNull() updatedAt: varchar("updatedAt").notNull()
}); });
+3
View File
@@ -233,6 +233,9 @@ export const launcherViews = sqliteTable("launcherViews", {
}), }),
name: text("name").notNull(), name: text("name").notNull(),
config: text("config").notNull(), config: text("config").notNull(),
isDefault: integer("isDefault", { mode: "boolean" })
.notNull()
.default(false),
createdAt: text("createdAt").notNull(), createdAt: text("createdAt").notNull(),
updatedAt: text("updatedAt").notNull() updatedAt: text("updatedAt").notNull()
}); });
+2 -11
View File
@@ -7,7 +7,6 @@ import moment from "moment";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
import { z } from "zod"; import { z } from "zod";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions"; import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import { isLauncherDefaultOverrideViewName } from "./launcherDefaultView";
import { launcherViewConfigSchema } from "./types"; import { launcherViewConfigSchema } from "./types";
const createLauncherViewBodySchema = z.strictObject({ const createLauncherViewBodySchema = z.strictObject({
@@ -41,15 +40,6 @@ export async function createLauncherView(
); );
} }
if (isLauncherDefaultOverrideViewName(parsed.data.name)) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"This view name is reserved"
)
);
}
if (parsed.data.orgWide) { if (parsed.data.orgWide) {
const canCreateOrgWide = await checkUserActionPermission( const canCreateOrgWide = await checkUserActionPermission(
ActionsEnum.createOrgWideLauncherView, ActionsEnum.createOrgWideLauncherView,
@@ -89,7 +79,8 @@ export async function createLauncherView(
), ),
createdAt: created.createdAt, createdAt: created.createdAt,
updatedAt: created.updatedAt, updatedAt: created.updatedAt,
isOrgWide: created.userId == null isOrgWide: created.userId == null,
isDefault: created.isDefault
}, },
success: true, success: true,
error: false, error: false,
@@ -6,7 +6,6 @@ import { and, eq } from "drizzle-orm";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions"; import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import { isLauncherDefaultOverrideViewName } from "./launcherDefaultView";
export async function deleteLauncherView( export async function deleteLauncherView(
req: Request, req: Request,
@@ -47,7 +46,7 @@ export async function deleteLauncherView(
); );
} }
if (isLauncherDefaultOverrideViewName(existing.name)) { if (existing.isDefault) {
return next( return next(
createHttpError( createHttpError(
HttpCode.BAD_REQUEST, HttpCode.BAD_REQUEST,
+7 -14
View File
@@ -2,17 +2,12 @@ import { db, launcherViews } from "@server/db";
import { and, eq, isNull } from "drizzle-orm"; import { and, eq, isNull } from "drizzle-orm";
import moment from "moment"; import moment from "moment";
import { import {
LAUNCHER_DEFAULT_OVERRIDE_VIEW_NAME,
launcherViewConfigSchema, launcherViewConfigSchema,
type LauncherDefaultViewOverrides, type LauncherDefaultViewOverrides,
type LauncherViewConfig, type LauncherViewConfig,
type LauncherViewRecord type LauncherViewRecord
} from "./types"; } from "./types";
export function isLauncherDefaultOverrideViewName(name: string) {
return name === LAUNCHER_DEFAULT_OVERRIDE_VIEW_NAME;
}
export function mapViewRow( export function mapViewRow(
row: typeof launcherViews.$inferSelect row: typeof launcherViews.$inferSelect
): LauncherViewRecord { ): LauncherViewRecord {
@@ -24,16 +19,15 @@ export function mapViewRow(
config: launcherViewConfigSchema.parse(JSON.parse(row.config)), config: launcherViewConfigSchema.parse(JSON.parse(row.config)),
createdAt: row.createdAt, createdAt: row.createdAt,
updatedAt: row.updatedAt, updatedAt: row.updatedAt,
isOrgWide: row.userId == null isOrgWide: row.userId == null,
isDefault: row.isDefault
}; };
} }
export function extractDefaultViewOverrides( export function extractDefaultViewOverrides(
rows: Array<typeof launcherViews.$inferSelect> rows: Array<typeof launcherViews.$inferSelect>
): LauncherDefaultViewOverrides { ): LauncherDefaultViewOverrides {
const overrideRows = rows.filter((row) => const overrideRows = rows.filter((row) => row.isDefault);
isLauncherDefaultOverrideViewName(row.name)
);
const personalRow = overrideRows.find((row) => row.userId !== null); const personalRow = overrideRows.find((row) => row.userId !== null);
const orgWideRow = overrideRows.find((row) => row.userId === null); const orgWideRow = overrideRows.find((row) => row.userId === null);
@@ -47,9 +41,7 @@ export function extractDefaultViewOverrides(
export function listVisibleLauncherViews( export function listVisibleLauncherViews(
rows: Array<typeof launcherViews.$inferSelect> rows: Array<typeof launcherViews.$inferSelect>
): LauncherViewRecord[] { ): LauncherViewRecord[] {
return rows return rows.filter((row) => !row.isDefault).map(mapViewRow);
.filter((row) => !isLauncherDefaultOverrideViewName(row.name))
.map(mapViewRow);
} }
export async function findDefaultViewOverride( export async function findDefaultViewOverride(
@@ -63,7 +55,7 @@ export async function findDefaultViewOverride(
.where( .where(
and( and(
eq(launcherViews.orgId, orgId), eq(launcherViews.orgId, orgId),
eq(launcherViews.name, LAUNCHER_DEFAULT_OVERRIDE_VIEW_NAME), eq(launcherViews.isDefault, true),
orgWide orgWide
? isNull(launcherViews.userId) ? isNull(launcherViews.userId)
: eq(launcherViews.userId, userId) : eq(launcherViews.userId, userId)
@@ -106,7 +98,8 @@ export async function upsertDefaultViewOverride({
.values({ .values({
orgId, orgId,
userId: orgWide ? null : userId, userId: orgWide ? null : userId,
name: LAUNCHER_DEFAULT_OVERRIDE_VIEW_NAME, name: "",
isDefault: true,
config: JSON.stringify(config), config: JSON.stringify(config),
createdAt: now, createdAt: now,
updatedAt: now updatedAt: now
+1 -2
View File
@@ -89,6 +89,7 @@ export type LauncherViewRecord = {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
isOrgWide: boolean; isOrgWide: boolean;
isDefault: boolean;
}; };
export type LauncherDefaultViewOverrides = { export type LauncherDefaultViewOverrides = {
@@ -181,8 +182,6 @@ export function parseIdListParam(value: string | undefined): number[] {
export const DEFAULT_LAUNCHER_VIEW_ID = "default" as const; export const DEFAULT_LAUNCHER_VIEW_ID = "default" as const;
export const LAUNCHER_DEFAULT_OVERRIDE_VIEW_NAME = "__default__";
export type LauncherViewSelection = export type LauncherViewSelection =
| { type: "default" } | { type: "default" }
| { type: "saved"; viewId: number }; | { type: "saved"; viewId: number };
@@ -9,7 +9,6 @@ import moment from "moment";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
import { z } from "zod"; import { z } from "zod";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions"; import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import { isLauncherDefaultOverrideViewName } from "./launcherDefaultView";
import { launcherViewConfigSchema } from "./types"; import { launcherViewConfigSchema } from "./types";
const updateLauncherViewBodySchema = z.strictObject({ const updateLauncherViewBodySchema = z.strictObject({
@@ -67,7 +66,7 @@ export async function updateLauncherView(
); );
} }
if (isLauncherDefaultOverrideViewName(existing.name)) { if (existing.isDefault) {
return next( return next(
createHttpError( createHttpError(
HttpCode.BAD_REQUEST, HttpCode.BAD_REQUEST,
@@ -145,7 +144,8 @@ export async function updateLauncherView(
), ),
createdAt: updated.createdAt, createdAt: updated.createdAt,
updatedAt: updated.updatedAt, updatedAt: updated.updatedAt,
isOrgWide: updated.userId == null isOrgWide: updated.userId == null,
isDefault: updated.isDefault
}, },
success: true, success: true,
error: false, error: false,