-
-
-
{page.name}
- {page.description && (
- {page.description}
- )}
-
+ {!page.hideHeader && (
+
+
+
{page.name}
+ {page.description && (
+ {page.description}
+ )}
+
+ )}
— bookmarkable regardless of this flag."),
+ hide_header: z.boolean().optional().describe("Hide the platform header (page title + description bar rendered above the widget). Use true for fullscreen reports/dashboards. Default false."),
},
},
- async ({ name, slug, code, description, icon, form_ids, show_in_sidebar }) => {
+ async ({ name, slug, code, description, icon, form_ids, show_in_sidebar, hide_header }) => {
const existing = await storage.getCustomPageBySlug(slug, organizationId);
if (existing) {
return { content: [{ type: "text" as const, text: `A page with slug "${slug}" already exists` }], isError: true };
@@ -1973,6 +1974,7 @@ MANDATORY: Call get_js_coding_reference BEFORE writing any code. Critical rules:
organizationId,
createdBy,
showInSidebar: show_in_sidebar ?? true,
+ hideHeader: hide_header === true,
});
const createResult: Record = {
success: true,
@@ -2012,9 +2014,10 @@ MANDATORY: Call get_js_coding_reference BEFORE writing any code. Critical rules:
form_ids: z.array(z.number().int()).optional().describe("New list of associated form IDs"),
is_active: z.boolean().optional().describe("Enable or disable the page"),
show_in_sidebar: z.boolean().optional().describe("Show/hide in the app sidebar. The page is always reachable by its permanent URL /pages/."),
+ hide_header: z.boolean().optional().describe("Hide the platform header (title + description bar) above the widget"),
},
},
- async ({ page_id, name, code, description, icon, form_ids, is_active, show_in_sidebar }) => {
+ async ({ page_id, name, code, description, icon, form_ids, is_active, show_in_sidebar, hide_header }) => {
const existing = await storage.getCustomPage(page_id, organizationId);
if (!existing) return { content: [{ type: "text" as const, text: "Custom page not found" }], isError: true };
@@ -2029,6 +2032,7 @@ MANDATORY: Call get_js_coding_reference BEFORE writing any code. Critical rules:
if (form_ids !== undefined) updates.formIds = form_ids;
if (is_active !== undefined) updates.isActive = is_active;
if (show_in_sidebar !== undefined) updates.showInSidebar = show_in_sidebar;
+ if (hide_header !== undefined) updates.hideHeader = hide_header;
const page = await storage.updateCustomPage(page_id, organizationId, updates as any);
const result: Record = {
diff --git a/server/routes/content.routes.ts b/server/routes/content.routes.ts
index aaa30b2..969fa25 100644
--- a/server/routes/content.routes.ts
+++ b/server/routes/content.routes.ts
@@ -393,7 +393,7 @@ export function registerContentRoutes(app: import("express").Express): void {
app.post('/api/custom-pages', authenticateToken, tenantIsolation, requirePermission('settings.manage'), async (req: AuthenticatedRequest, res) => {
try {
- const { name, slug, description, code, formIds, icon, showInSidebar } = req.body;
+ const { name, slug, description, code, formIds, icon, showInSidebar, hideHeader } = req.body;
if (!name || !slug) return res.status(400).json({ error: 'name и slug обязательны' });
const page = await storage.createCustomPage({
organizationId: req.organizationId!,
@@ -405,6 +405,7 @@ export function registerContentRoutes(app: import("express").Express): void {
icon: icon ?? 'FileCode',
isActive: true,
showInSidebar: showInSidebar === true,
+ hideHeader: hideHeader === true,
createdBy: req.user!.id,
});
res.status(201).json({ success: true, page });
@@ -418,7 +419,7 @@ export function registerContentRoutes(app: import("express").Express): void {
app.patch('/api/custom-pages/:id', authenticateToken, tenantIsolation, requirePermission('settings.manage'), async (req: AuthenticatedRequest, res) => {
try {
const id = parseInt(req.params.id);
- const { name, slug, description, code, formIds, icon, isActive, showInSidebar } = req.body;
+ const { name, slug, description, code, formIds, icon, isActive, showInSidebar, hideHeader } = req.body;
const updates: Record = {};
if (name !== undefined) updates.name = name;
if (slug !== undefined) updates.slug = slug.toLowerCase().replace(/[^a-z0-9-_]/g, '-');
@@ -428,6 +429,7 @@ export function registerContentRoutes(app: import("express").Express): void {
if (icon !== undefined) updates.icon = icon;
if (isActive !== undefined) updates.isActive = isActive === true;
if (showInSidebar !== undefined) updates.showInSidebar = showInSidebar === true;
+ if (hideHeader !== undefined) updates.hideHeader = hideHeader === true;
const page = await storage.updateCustomPage(id, req.organizationId!, updates);
res.json({ success: true, page });
} catch (error: unknown) {
diff --git a/shared/schema.ts b/shared/schema.ts
index 1d65bc1..f112c55 100644
--- a/shared/schema.ts
+++ b/shared/schema.ts
@@ -2722,6 +2722,7 @@ export const customPages = pgTable("custom_pages", {
icon: varchar("icon", { length: 50 }).default("FileCode"),
isActive: boolean("is_active").default(true),
showInSidebar: boolean("show_in_sidebar").default(false),
+ hideHeader: boolean("hide_header").notNull().default(false),
createdBy: integer("created_by").notNull().references(() => users.id),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),