Redesign application content tab + logic function settings; add Layout detail pages (#20056)
## Summary Iterative redesign of two related areas in settings, plus a new `pages/settings/layout/` folder for read-only entity detail pages. ### Application content tab - **Grouped into three sections** — Data / Layout / Logic — each with one H2 + multiple `TableSection`-wrapped sub-tables (mirrors the role-permissions pattern). Replaces six per-category table/row components with one uniform `<SettingsApplicationContentSubtable>` + `ApplicationContentRow` shape (net **−~700 lines** across the refactor). - **All 10 row categories now clickable** for installed apps: - Objects / Fields / Logic functions / Front components → existing detail pages - Agents → existing `AiAgentDetail` - Skills → existing `AiSkillDetail` (looked up by `Skill.applicationId + name`) - Roles → existing `RoleDetail` (looked up by `Role.universalIdentifier`) - Views / Page layouts / Navigation menu items → **new** detail pages (see below) - **Lifecycle hooks visible** — `pre-install` / `post-install` logic functions are surfaced in the Trigger column instead of appearing as empty/misconfigured. ### Logic function settings (Triggers + Test tabs) - Triggers tab is now editable (HTTP / Cron / Database event / AI tool) with a `<SettingsLogicFunctionTriggerSection>` wrapper that owns the toggle, header, and read-only short-circuit. - HTTP section gets a Live URL field with copy-to-clipboard. - Each section shows a **Sample input** preview (the JSON the function will receive) using the same payload builders the Test tab uses. - Test tab: **Simulate trigger** buttons that prefill the JSON input from the configured trigger's schema. Replaces an unclickable `<Select>` (which auto-disables when there's only one option — the typical case). - Read-only behavior for installed-app functions: explicit `<Callout>` notice when there's no trigger; trigger sections render as disabled controls when there is one. - Removed the empty Environment Variables section from the Settings tab (it just told the user to go elsewhere). ### New `pages/settings/layout/` folder Three new app-scoped detail pages so users can drill into entities the GraphQL `Application` type doesn't expose by id (keyed by manifest `universalIdentifier`): - `ApplicationViewDetail` — type, object, visibility + Fields / Filters / Sorts subsections (field UIDs resolved to readable labels via `useFieldLabelByUid`) - `ApplicationPageLayoutDetail` — type, object + per-tab subsections listing widgets - `ApplicationNavigationMenuItemDetail` — type, destination (resolved), icon, color, position Each page reads from the marketplace manifest the parent app page already loads (no extra queries). Folder set up so a future "Layout" settings tab can grow here (analogous to the existing `data-model/` folder under the Data tab). ### Other consistency fixes - Breadcrumbs on every app-scoped entity detail page now include a category crumb so users know what they're looking at: `Workspace / Applications / Timely / Navigation menu items / Time entry`. - Title fallback for nav menu items uses the resolved destination (`"Time entry"`) instead of the raw enum (`"OBJECT"`). - New shared utils: `getNavigationMenuItemDestination`, `resolveManifestObjectLabel`, `getLogicFunctionTriggerLabel`, `<MonoText>`. ## Backend changes Only one minor schema-shape change (additive): added `applicationId` to the `SkillFields` GraphQL fragment and `universalIdentifier` to the `RoleFragment` so the new lookups have what they need. Generated metadata schema patched in-tree to match — regenerate with `nx run twenty-front:graphql:generate --configuration=metadata` if it drifts. ## Test plan - [ ] Application content tab on an installed app shows the 3 grouped sections; rows in each section are clickable - [ ] Click an Object → existing object detail page - [ ] Click a Field → existing field-edit page - [ ] Click an Agent / Skill / Role → existing detail page - [ ] Click a View / Page layout / Navigation menu item → new read-only detail page; subsections (Fields/Filters/Sorts for views, per-tab widgets for page layouts) populate correctly - [ ] Breadcrumbs on every entity detail page have 5 crumbs ending in `<Category> / <Entity name>` - [ ] Logic function Triggers tab: toggle each trigger type on/off, see the Sample input preview update; for installed apps, sections render as read-only - [ ] Test tab: each "Simulate trigger" button prefills the JSON editor with the matching payload shape - [ ] Functions list: a function configured as `post-install` shows "Post-install" in the Trigger column 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: claude[bot] <claude[bot]@users.noreply.github.com>
This commit is contained in:
+16
@@ -1,6 +1,11 @@
|
||||
import { useGetOneLogicFunction } from '@/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
type CronTriggerSettings,
|
||||
type DatabaseEventTriggerSettings,
|
||||
type HttpRouteTriggerSettings,
|
||||
} from 'twenty-shared/application';
|
||||
import { type LogicFunction } from '~/generated-metadata/graphql';
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
import { DEFAULT_TOOL_INPUT_SCHEMA } from 'twenty-shared/logic-function';
|
||||
@@ -12,6 +17,9 @@ export type LogicFunctionFormValues = {
|
||||
timeoutSeconds: number;
|
||||
sourceHandlerCode: string;
|
||||
toolInputSchema?: object;
|
||||
cronTriggerSettings: CronTriggerSettings | null;
|
||||
databaseEventTriggerSettings: DatabaseEventTriggerSettings | null;
|
||||
httpRouteTriggerSettings: HttpRouteTriggerSettings | null;
|
||||
};
|
||||
|
||||
type SetLogicFunctionFormValues = Dispatch<
|
||||
@@ -35,6 +43,9 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
sourceHandlerCode: '',
|
||||
timeoutSeconds: 300,
|
||||
toolInputSchema: DEFAULT_TOOL_INPUT_SCHEMA,
|
||||
cronTriggerSettings: null,
|
||||
databaseEventTriggerSettings: null,
|
||||
httpRouteTriggerSettings: null,
|
||||
});
|
||||
|
||||
const { sourceHandlerCode, loading: logicFunctionSourceCodeLoading } =
|
||||
@@ -57,6 +68,11 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
timeoutSeconds: logicFunction.timeoutSeconds ?? 300,
|
||||
toolInputSchema:
|
||||
logicFunction.toolInputSchema || DEFAULT_TOOL_INPUT_SCHEMA,
|
||||
cronTriggerSettings: logicFunction.cronTriggerSettings ?? null,
|
||||
databaseEventTriggerSettings:
|
||||
logicFunction.databaseEventTriggerSettings ?? null,
|
||||
httpRouteTriggerSettings:
|
||||
logicFunction.httpRouteTriggerSettings ?? null,
|
||||
}));
|
||||
}
|
||||
}, [logicFunction]);
|
||||
|
||||
Reference in New Issue
Block a user