fea47aa9f8
## Summary
- Re-implements `eslint-plugin-project-structure`'s folder structure
enforcement as a custom oxlint rule (`twenty/folder-structure`),
recovering functionality lost during the ESLint → Oxlint migration
- Validates `src/modules/` structure: kebab-case module folder names,
allowed subdirectories (hooks, utils, components, states, types,
graphql, etc.), hook file naming (`use{PascalCase}.(ts|tsx)`), util file
naming (`{camelCase}.(ts|tsx)`), and module nesting depth (max 4 levels)
- Enabled as `"warn"` in twenty-front with 403 pre-existing violations
to address incrementally
## What the rule checks
| Check | Example valid | Example invalid |
|-------|-------------|-----------------|
| Module names kebab-case | `object-record/` | `graphWidgetBarChart/` |
| Allowed subdirs only | `hooks/`, `components/`, `utils/` |
`random-stuff/` |
| Hook file naming | `useMyHook.ts` | `badName.ts` |
| Util file naming | `buildQuery.ts` | `build-query.ts` |
| Max nesting depth 4 | `a/b/c/d/hooks/` | `a/b/c/d/e/hooks/` |
| Utils kebab-case subfolders | `utils/cron-to-human/` |
`utils/camelCase/` |
## Pre-existing violations (403 total)
| Category | Count | Examples |
|----------|-------|---------|
| Non-kebab-case module names | 160 | `graphWidgetBarChart`,
`AIChatThreads` |
| Module depth > 4 | 215 |
`settings/roles/role-permissions/object-level-permissions/field-permissions`
|
| Util file naming | 22 | `.util.ts` suffix, kebab-case, PascalCase
filenames |
| Misc (hooks, tests) | 6 | Non-hook files in hooks/, folders in test
dirs |
80 lines
5.2 KiB
TypeScript
80 lines
5.2 KiB
TypeScript
import { SidePanelAIChatThreadsPage } from '@/side-panel/pages/ai-chat-threads/components/SidePanelAIChatThreadsPage';
|
|
import { SidePanelAskAIPage } from '@/side-panel/pages/ask-ai/components/SidePanelAskAIPage';
|
|
import { SidePanelCalendarEventPage } from '@/side-panel/pages/calendar-event/components/SidePanelCalendarEventPage';
|
|
import { SidePanelFrontComponentPage } from '@/side-panel/pages/front-component/components/SidePanelFrontComponentPage';
|
|
import { SidePanelMessageThreadPage } from '@/side-panel/pages/message-thread/components/SidePanelMessageThreadPage';
|
|
import { SidePanelNavigationMenuItemEditPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNavigationMenuItemEditPage';
|
|
import { SidePanelNewSidebarItemPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemPage';
|
|
import { SidePanelPageLayoutChartSettings } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutChartSettings';
|
|
import { SidePanelPageLayoutFieldsLayout } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsLayout';
|
|
import { SidePanelPageLayoutFieldsSettings } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsSettings';
|
|
import { SidePanelPageLayoutGraphFilter } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutGraphFilter';
|
|
import { SidePanelPageLayoutIframeSettings } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutIframeSettings';
|
|
import { SidePanelPageLayoutTabSettings } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutTabSettings';
|
|
import { SidePanelPageLayoutWidgetTypeSelect } from '@/side-panel/pages/page-layout/components/SidePanelPageLayoutWidgetTypeSelect';
|
|
import { SidePanelMergeRecordPage } from '@/side-panel/pages/record-page/components/SidePanelMergeRecordPage';
|
|
import { SidePanelRecordPage } from '@/side-panel/pages/record-page/components/SidePanelRecordPage';
|
|
import { SidePanelUpdateMultipleRecords } from '@/side-panel/pages/record-page/components/SidePanelUpdateMultipleRecords';
|
|
import { SidePanelEditRichTextPage } from '@/side-panel/pages/rich-text-page/components/SidePanelEditRichTextPage';
|
|
import { SidePanelRootPage } from '@/side-panel/pages/root/components/SidePanelRootPage';
|
|
import { SidePanelSearchRecordsPage } from '@/side-panel/pages/search/components/SidePanelSearchRecordsPage';
|
|
import { SidePanelWorkflowCreateStep } from '@/side-panel/pages/workflow/step/create/components/SidePanelWorkflowCreateStep';
|
|
import { SidePanelWorkflowEditStep } from '@/side-panel/pages/workflow/step/edit/components/SidePanelWorkflowEditStep';
|
|
import { SidePanelWorkflowEditStepType } from '@/side-panel/pages/workflow/step/edit/components/SidePanelWorkflowEditStepType';
|
|
import { SidePanelWorkflowRunViewStep } from '@/side-panel/pages/workflow/step/view-run/components/SidePanelWorkflowRunViewStep';
|
|
import { SidePanelWorkflowViewStep } from '@/side-panel/pages/workflow/step/view/components/SidePanelWorkflowViewStep';
|
|
import { SidePanelWorkflowSelectTriggerType } from '@/side-panel/pages/workflow/trigger-type/components/SidePanelWorkflowSelectTriggerType';
|
|
import { SidePanelPages } from 'twenty-shared/types';
|
|
|
|
export const SIDE_PANEL_PAGES_CONFIG = new Map<SidePanelPages, React.ReactNode>(
|
|
[
|
|
[SidePanelPages.Root, <SidePanelRootPage />],
|
|
[SidePanelPages.ViewRecord, <SidePanelRecordPage />],
|
|
[SidePanelPages.MergeRecords, <SidePanelMergeRecordPage />],
|
|
[SidePanelPages.UpdateRecords, <SidePanelUpdateMultipleRecords />],
|
|
[SidePanelPages.ViewEmailThread, <SidePanelMessageThreadPage />],
|
|
[SidePanelPages.ViewCalendarEvent, <SidePanelCalendarEventPage />],
|
|
[SidePanelPages.EditRichText, <SidePanelEditRichTextPage />],
|
|
[
|
|
SidePanelPages.WorkflowTriggerSelectType,
|
|
<SidePanelWorkflowSelectTriggerType />,
|
|
],
|
|
[SidePanelPages.WorkflowStepCreate, <SidePanelWorkflowCreateStep />],
|
|
[SidePanelPages.WorkflowStepEditType, <SidePanelWorkflowEditStepType />],
|
|
[SidePanelPages.WorkflowStepEdit, <SidePanelWorkflowEditStep />],
|
|
[SidePanelPages.WorkflowStepView, <SidePanelWorkflowViewStep />],
|
|
[SidePanelPages.WorkflowRunStepView, <SidePanelWorkflowRunViewStep />],
|
|
[SidePanelPages.SearchRecords, <SidePanelSearchRecordsPage />],
|
|
[SidePanelPages.AskAI, <SidePanelAskAIPage />],
|
|
[SidePanelPages.ViewPreviousAIChats, <SidePanelAIChatThreadsPage />],
|
|
[
|
|
SidePanelPages.PageLayoutWidgetTypeSelect,
|
|
<SidePanelPageLayoutWidgetTypeSelect />,
|
|
],
|
|
[
|
|
SidePanelPages.PageLayoutGraphTypeSelect,
|
|
<SidePanelPageLayoutChartSettings />,
|
|
],
|
|
[SidePanelPages.PageLayoutGraphFilter, <SidePanelPageLayoutGraphFilter />],
|
|
[
|
|
SidePanelPages.PageLayoutIframeSettings,
|
|
<SidePanelPageLayoutIframeSettings />,
|
|
],
|
|
[SidePanelPages.PageLayoutTabSettings, <SidePanelPageLayoutTabSettings />],
|
|
[
|
|
SidePanelPages.PageLayoutFieldsSettings,
|
|
<SidePanelPageLayoutFieldsSettings />,
|
|
],
|
|
[
|
|
SidePanelPages.PageLayoutFieldsLayout,
|
|
<SidePanelPageLayoutFieldsLayout />,
|
|
],
|
|
[SidePanelPages.ViewFrontComponent, <SidePanelFrontComponentPage />],
|
|
[
|
|
SidePanelPages.NavigationMenuItemEdit,
|
|
<SidePanelNavigationMenuItemEditPage />,
|
|
],
|
|
[SidePanelPages.NavigationMenuAddItem, <SidePanelNewSidebarItemPage />],
|
|
],
|
|
);
|