diff --git a/apps/realtime/src/database/operations.ts b/apps/realtime/src/database/operations.ts index 4e7baa85d78..c34df4dd45d 100644 --- a/apps/realtime/src/database/operations.ts +++ b/apps/realtime/src/database/operations.ts @@ -633,6 +633,33 @@ async function handleBlockOperationTx( break } + case BLOCK_OPERATIONS.UPDATE_DESCRIPTION: { + if (!payload.id || payload.description === undefined) { + throw new Error('Missing required fields for update description operation') + } + + const updateResult = await tx + .update(workflowBlocks) + .set({ + data: sql`jsonb_set( + coalesce(${workflowBlocks.data}, '{}'::jsonb), + '{description}', + ${JSON.stringify(payload.description)}::jsonb, + true + )`, + updatedAt: new Date(), + }) + .where(and(eq(workflowBlocks.id, payload.id), eq(workflowBlocks.workflowId, workflowId))) + .returning({ id: workflowBlocks.id }) + + if (updateResult.length === 0) { + throw new Error(`Block ${payload.id} not found in workflow ${workflowId}`) + } + + logger.debug(`Updated block description: ${payload.id}`) + break + } + case BLOCK_OPERATIONS.TOGGLE_ENABLED: { if (!payload.id) { throw new Error('Missing block ID for toggle enabled operation') diff --git a/apps/realtime/src/middleware/permissions.test.ts b/apps/realtime/src/middleware/permissions.test.ts index 4edc05d795a..51e640f8345 100644 --- a/apps/realtime/src/middleware/permissions.test.ts +++ b/apps/realtime/src/middleware/permissions.test.ts @@ -274,6 +274,12 @@ describe('checkRolePermission', () => { { operation: 'update', adminAllowed: true, writeAllowed: true, readAllowed: false }, { operation: 'update-position', adminAllowed: true, writeAllowed: true, readAllowed: false }, { operation: 'update-name', adminAllowed: true, writeAllowed: true, readAllowed: false }, + { + operation: 'update-description', + adminAllowed: true, + writeAllowed: true, + readAllowed: false, + }, { operation: 'toggle-enabled', adminAllowed: true, writeAllowed: true, readAllowed: false }, { operation: 'update-parent', adminAllowed: true, writeAllowed: true, readAllowed: false }, { diff --git a/apps/realtime/src/middleware/permissions.ts b/apps/realtime/src/middleware/permissions.ts index e17678461a6..b004135d016 100644 --- a/apps/realtime/src/middleware/permissions.ts +++ b/apps/realtime/src/middleware/permissions.ts @@ -26,6 +26,7 @@ const WRITE_OPERATIONS: string[] = [ // Block operations BLOCK_OPERATIONS.UPDATE_POSITION, BLOCK_OPERATIONS.UPDATE_NAME, + BLOCK_OPERATIONS.UPDATE_DESCRIPTION, BLOCK_OPERATIONS.TOGGLE_ENABLED, BLOCK_OPERATIONS.UPDATE_PARENT, BLOCK_OPERATIONS.UPDATE_ADVANCED_MODE, diff --git a/apps/sim/app/layout.tsx b/apps/sim/app/layout.tsx index 21688e8470e..ada8f23adf9 100644 --- a/apps/sim/app/layout.tsx +++ b/apps/sim/app/layout.tsx @@ -6,12 +6,7 @@ import { BrandedLayout } from '@/components/branded-layout' import { PostHogProvider } from '@/app/_shell/providers/posthog-provider' import { generateBrandedMetadata, generateThemeCSS } from '@/ee/whitelabeling' import '@/app/_styles/globals.css' -import { - isChatEnabled, - isHosted, - isReactGrabEnabled, - isReactScanEnabled, -} from '@/lib/core/config/env-flags' +import { isHosted, isReactGrabEnabled, isReactScanEnabled } from '@/lib/core/config/env-flags' import { DesktopUpdateGate } from '@/app/_shell/desktop-update-gate' import { HydrationErrorHandler } from '@/app/_shell/hydration-error-handler' import { QueryProvider } from '@/app/_shell/providers/query-provider' @@ -155,10 +150,9 @@ export default function RootLayout({ children }: { children: React.ReactNode }) } var activeTab = panelState && panelState.activeTab; - // A session that used the Chat tab before it was turned off still - // has 'copilot' persisted; without this the CSS hides every tab - // body and the panel paints empty. - if (activeTab === 'copilot' && !${isChatEnabled}) { + // Chat moved out of the right inspector. Migrate the legacy + // persisted tab before first paint so the inspector opens on Blocks. + if (activeTab === 'copilot') { activeTab = 'toolbar'; } if (activeTab) { @@ -260,7 +254,10 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= {isHosted ? : } - + {/* Google Tag Manager (noscript) — hosted only */} {isHosted && (