Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Builder v2 Alpha #4442

Merged
merged 14 commits into from
Mar 24, 2025
Merged

Type Builder v2 Alpha #4442

merged 14 commits into from
Mar 24, 2025

Conversation

rart
Copy link
Member

@rart rart commented Mar 21, 2025

  • Type Builder 2 Base
  • FE2 parts refactored for reusage on TB2
  • Refactor dialogs related to content type (new content, change type) for consistency with new development
  • Refactored other components for more flexibility and facilitate required features

craftercms/craftercms#7418

Summary by CodeRabbit

  • New Features

    • Introduced enhanced color picking capability for a more intuitive selection experience.
    • Rolled out new dialog interfaces and workflows for creating and editing content types, offering a streamlined user interaction.
    • Added a new custom hook for fetching allowed content types based on a specified path.
    • Added a new component for managing and displaying content type details, including actions for editing and deleting.
    • Introduced a new utility for color format conversions.
    • Added a new component for displaying content type details with action buttons for editing and deleting.
  • Refactor

    • Consolidated several legacy dialogs and removed outdated components to simplify interactions.
    • Updated layouts, toolbars, and styling across content type management screens for improved responsiveness.
    • Simplified state management and rendering logic in the New Content Dialog component.
    • Enhanced type safety and clarity in content type management utilities.
    • Restructured dialog component handling logic for improved modularity and organization.
    • Streamlined the NewContentDialog component by removing unused functionality and modifying property handling.
  • Chore

    • Added a new dependency to support the enhanced color selection feature.

rart added 3 commits March 21, 2025 19:30
- Type Builder 2 Base
- FE2 parts refactored for reusage on TB2
- Refactor dialogs related to content type (new content, change type) for consistency with new development
- Refactored other components for more flexibility and facilitate required features
Copy link

coderabbitai bot commented Mar 21, 2025

Walkthrough

The pull request implements extensive refactoring, component removals, and new feature integrations. Updates include adding a new dependency, revising dialog and state properties (replacing properties such as “compact” with “initialCompact”), and streamlining UI components. Numerous new utility hooks, descriptor files, and helper functions have been introduced across content management, forms engine, and various UI modules, along with improved type safety in models and services.

Changes

File(s) Change Summary
ui/app/package.json Added dependency "react-colorful" for color selection functionality.
ui/app/src/CHANGELOG.md Documented removal, modification, and restructuring of several components and props.
ui/app/src/components/ChangeContentTypeDialog/... (e.g. ChangeContentTypeDialog.tsx, ChangeContentTypeDialogContainer.tsx, utils.ts) Removed props (rootPath, compact, selectedContentType), added initialCompact, updated dialog header text, and refactored fetching logic with new hooks.
ui/app/src/components/ContentTypesFilter/ContentTypesFilter.tsx Refactored component to use Material‑UI’s Select component instead of a button and menu system with updated prop types and i18n.
ui/app/src/components/ContentTypeManagement/...
(multiple component and descriptor files, e.g. CreateTypeDialog.tsx, EditTypeView.tsx, descriptors in descriptors/controls/*.ts)
Major updates: removed legacy components (e.g. NewContentCard, ContentTypesGrid), added new components (e.g. CreateTypeDialog, EditTypeView, SelectTypeView), and introduced numerous descriptor files with new control interfaces for content type management.
ui/app/src/components/FormsEngine/...
(Files such as FormsEngine.tsx, FormBackToTop.tsx, FormLayout.tsx, SectionAccordion.tsx, ColorPicker.tsx, and various lib files)
Refactored FormsEngine components: introduced a dedicated back‑to‑top component, replaced custom resize handling with useResizeObserver, updated control map (e.g. added colorPicker, repositioned repeat), and enhanced XML serialization and form utility functions.
ui/app/src/components/NewContentDialog/...
(including NewContentDialog.tsx, NewContentDialogContainer.tsx, index.ts, utils.ts)
Streamlined NewContentDialog by removing legacy grid/loader components, updating prop signatures (switching from compact to initialCompact), and simplifying content type selection logic.
ui/app/src/state/reducers/dialogs/...
(changeContentType.ts, newContent.ts)
Removed obsolete state properties (compact, rootPath) and added initialCompact; adjusted reducer logic accordingly.
ui/app/src/models/ContentType.ts
ui/app/src/services/contentTypes.ts
Updated interfaces with additional properties (e.g. description, mergeStrategy, paths) and enhanced type safety in parsing and service functions.
ui/app/src/hooks/...
(useFetchAllowedTypesForPath.tsx, useIsDarkModeTheme.tsx, useResizeObserver.ts)
Introduced new custom hooks to fetch allowed content types, detect dark mode, and observe element resize events.
ui/app/src/utils/...
(Files such as color.ts, contentType.ts, itemActions.ts, object.ts, path.ts, string.ts, system.ts, ui.tsx)
Added various utility functions for color conversion, content type filtering, path normalization, object manipulation, string checks, and UI styling.
Other UI components (e.g. ItemDisplay.tsx, ResizeableDrawer.tsx, SearchBar.tsx, ViewToolbar.tsx) Minor updates including dynamic element types, style adjustments, enhanced type safety, and refactored toolbars with forwardRef and memoization.
ui/app/src/utils/system.ts
ui/app/src/components/GlobalDialogManager/DialogStackItemContainer.tsx
Added new context hook creation functions and dialog helper methods for unknown component handling and callback prop generation.
ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx Introduced a new header component to display content type details and actions with internationalized date and user information.

Sequence Diagram(s)

sequenceDiagram
  participant N as NewContentDialogContainer
  participant H as useFetchAllowedTypesForPath
  participant S as SelectTypeView
  participant D as Dialog UI

  N->>H: Request allowed content types for given path
  H-->>N: Return { isFetching, contentTypes }
  N->>S: Pass content types and initialCompact prop
  S->>D: Render dialog with updated type selection view
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

🧹 Nitpick comments (98)
ui/app/src/components/ContentTypeManagement/descriptors/controls/disabled.ts (1)

17-23: Descriptor Definition and Type Safety Suggestion:
The disabledDescriptor object is clearly defined with the properties id, name, description, sections, and fields that precisely represent a disabled field control. For stronger type safety and maintainability in the TypeScript environment, consider adding an explicit type annotation (or interface) for descriptors.

ui/app/src/components/ContentTypeManagement/components/TypeBuilderAddButton.tsx (1)

19-28: Clarify or Clean Up Commented Styling Code
There is a TODO along with commented-out styled code. Consider either adding a brief explanation on when or why this custom styling might be re-enabled, or remove the commented code if it isn’t needed anymore. This helps maintain clarity in the codebase.

ui/app/src/components/ContentTypeManagement/components/EditTypeViewLayout.tsx (5)

51-51: Improve ref initialization with proper typing.

The anchorElRef is initialized with undefined, which should be null and should include proper typing for better type safety.

- const anchorElRef = useRef(undefined);
+ const anchorElRef = useRef<HTMLButtonElement | null>(null);

95-96: Improve accessibility by providing a proper aria-labelledby value.

The empty string for aria-labelledby doesn't provide proper accessibility for screen readers.

- slotProps={{ list: { 'aria-labelledby': '' } }}
+ slotProps={{ list: { 'aria-labelledby': 'content-type-actions-menu' } }}

And add an id to the button:

- <IconButton ref={anchorElRef} onClick={handleOpenMenuButton}>
+ <IconButton id="content-type-actions-menu" ref={anchorElRef} onClick={handleOpenMenuButton}>

33-33: Consider simplifying the event type.

The MenuItemOrButtonEvent type is overly complex. Since both event types are React.MouseEvent variants, you can simplify this.

- type MenuItemOrButtonEvent = Parameters<MenuItemProps['onClick']>[0] | Parameters<ButtonProps['onClick']>[0];
+ type MenuItemOrButtonEvent = React.MouseEvent<HTMLElement>;

40-47: Optimize the actionsMap definition.

The current actionsMap is redundant since keys and values are identical. Consider simplifying or making it more meaningful.

- const actionsMap: Record<EditAppLayoutAction, EditAppLayoutAction> = {
-   exit: 'exit',
-   save: 'save',
-   viewXml: 'viewXml',
-   diff: 'diff',
-   history: 'history',
-   rollback: 'rollback'
- };
+ // Create an object with EditAppLayoutAction keys and values for data attributes
+ const actionsMap = Object.fromEntries(
+   (['exit', 'save', 'viewXml', 'diff', 'history', 'rollback'] as const).map(
+     action => [action, action]
+   )
+ ) as Record<EditAppLayoutAction, EditAppLayoutAction>;

Or, given the redundancy, you might consider simplifying this approach altogether and just use the action strings directly in your data attributes.


17-30: Consider organizing imports for better maintainability.

Group imports by external dependencies, MUI components, and internal components.

+ // React & core imports
import React, { forwardRef, useRef, useState } from 'react';
import { FormattedMessage } from 'react-intl';

+ // Material UI imports
import Box from '@mui/material/Box';
import Tooltip from '@mui/material/Tooltip';
import IconButton, { IconButtonProps } from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import Button, { ButtonProps } from '@mui/material/Button';
import Menu, { MenuProps } from '@mui/material/Menu';
import MenuItem, { MenuItemProps } from '@mui/material/MenuItem';

+ // Material UI icons
import ArrowBackRounded from '@mui/icons-material/ArrowBackRounded';
import MoreVertRounded from '@mui/icons-material/MoreVertRounded';

+ // Internal components & hooks
import Layout, { LayoutProps } from './Layout';
import { useShowAlert } from '../../FormsEngine/lib/formUtils';
ui/app/src/components/ContentTypeManagement/components/TypeBuilderFormsEngine.tsx (3)

176-195: Attach handlers to "Move" and "Delete" icons for fields
Currently, the icons only display a tooltip but lack an implementation for the related actions. Consider adding onClick event handlers or methods to perform the intended operations, such as moving or deleting a field.


197-222: Implement "Swap Field" button functionality
The "Swap Field" icon appears when field.type === 'file-name', but no logic is provided for swapping fields. If this is intentional, consider adding a “TODO” comment or an onClick handler to clarify future plans.


267-279: Provide a fallback return in pickPanelTitleByMode
If none of the conditions are met, the function returns undefined. Consider providing a default return to avoid potential rendering issues.

ui/app/src/components/ContentTypeManagement/components/TypeCardMedia.tsx (1)

1-70: Well structured and implemented component.

The TypeCardMedia component is well-designed for displaying content type preview images with proper loading states. The use of useEffect for image fetching with proper cleanup in the return function demonstrates good React practices.

A few minor suggestions to improve robustness:

  1. Consider adding error handling to the fetchPreviewImage subscription to handle potential failed image requests
  2. The ref initialization could use null instead of undefined to better align with React's typing: useRef<HTMLImageElement>(null)
-  const elementRef = useRef<HTMLImageElement>(undefined);
+  const elementRef = useRef<HTMLImageElement>(null);

   useEffect(() => {
     if (!typeId) return;
-    const sub = fetchPreviewImage(siteId, typeId).subscribe((response) => {
-      const img = elementRef.current;
-      const imgUrl = URL.createObjectURL(new Blob([response.response]));
-      img.src = imgUrl;
-      img.onload = () => {
-        // Image has loaded, revoke the object URL to free memory.
-        URL.revokeObjectURL(imgUrl);
-      };
-    });
+    const sub = fetchPreviewImage(siteId, typeId).subscribe({
+      next: (response) => {
+        const img = elementRef.current;
+        if (img) {
+          const imgUrl = URL.createObjectURL(new Blob([response.response]));
+          img.src = imgUrl;
+          img.onload = () => {
+            // Image has loaded, revoke the object URL to free memory.
+            URL.revokeObjectURL(imgUrl);
+          };
+        }
+      },
+      error: (error) => {
+        console.error('Error fetching preview image:', error);
+      }
+    });
ui/app/src/hooks/useResizeObserver.ts (1)

22-36: Consider enhancing the resize observer callback with size information

The hook correctly sets up the ResizeObserver and handles cleanup, but currently it only notifies that a resize occurred without providing the actual dimensions of the element. This limits the hook's utility.

Consider passing the dimensions to the callback function:

-export function useResizeObserver(containerRef: RefObject<HTMLElement>, observer: () => void, delay = 300): void {
+export function useResizeObserver(containerRef: RefObject<HTMLElement>, observer: (entry?: ResizeObserverEntry) => void, delay = 300): void {
	const refs = useUpdateRefs({ observer, delay });
	useLayoutEffect(() => {
		if (containerRef.current) {
			const resize$ = new Subject<void>();
-			const resizeObserver = new ResizeObserver(() => resize$.next());
+			const resizeObserver = new ResizeObserver((entries) => resize$.next(entries[0]));
-			const subscription = resize$.pipe(debounceTime(delay)).subscribe(() => refs.current.observer());
+			const subscription = resize$.pipe(debounceTime(delay)).subscribe((entry) => refs.current.observer(entry));
			resizeObserver.observe(containerRef.current);
			return () => {
				resizeObserver.disconnect();
				subscription.unsubscribe();
			};
		}
	}, [delay, containerRef, refs]);
}
ui/app/src/components/ContentTypeManagement/components/TypeList.tsx (2)

43-48: Improve null handling in conditional rendering

The first condition can be simplified, and the second condition needs better null handling to prevent potential errors.

-	if (!skeleton && !contentTypes) {
+	if (!skeleton && !contentTypes) {
 		return <></>;
 	}
-	if (!skeleton && contentTypes?.length === 0) {
+	if (!skeleton && Array.isArray(contentTypes) && contentTypes.length === 0) {
 		return <EmptyState title={<FormattedMessage defaultMessage="No content types available for display." />} />;
 	}

64-64: Consider using theme variables for selected item styling

Hardcoding the styling for selected cards reduces maintainability and theme consistency.

-								sx={[isSelected && { border: `2px solid ${palette.blue.tint}`, opacity: 0.7, boxShadow: 0 }]}
+								sx={[isSelected && (theme) => ({ 
+                                   border: `2px solid ${theme.palette.primary.main}`,
+                                   opacity: 0.7, 
+                                   boxShadow: 0 
+                                })]}
ui/app/src/utils/object.ts (1)

80-91: Add warning about non-unique values in reverseLookupTable

The utility function is well-implemented, but it assumes values in the original object are unique, which might lead to data loss.

 /**
- * { K: V } => { V: K }
+ * Transforms an object by swapping its keys and values.
+ * { K: V } => { V: K }
+ * 
+ * Note: If multiple keys map to the same value in the original object,
+ * only one entry will be preserved in the reversed object.
  **/
 export function reverseLookupTable<K extends string | number | symbol, V extends string | number | symbol>(
 	original: Record<K, V>
 ): Record<V, K> {
ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (1)

53-57: Return structure is straightforward and clean.
The returned { isFetching, contentTypes } is nicely minimal, simplifying consumer usage. Make sure to include adequate test coverage for scenarios with no content types returned.

ui/app/src/components/SearchBar/SearchBar.tsx (1)

164-171: Flexible ref assignment is well-handled.
The logic correctly handles both callback and object refs, ensuring robust integration. Be mindful if you ever need to support multiple refs; consider a library like useMergedRef if that arises.

ui/app/src/utils/path.ts (1)

283-283: Good documentation for future refactoring.

The TODO comment correctly identifies the duplication between stripDuplicateSlashes and ensureSingleSlash functions. This is helpful for future code cleanup.

Consider consolidating these duplicate functions in a future cleanup to improve maintainability. When you do, ensure you update all references to use a single function.

ui/app/src/components/ResizeableDrawer/ResizeableDrawer.tsx (1)

118-120: UI adjustment with good documentation.

Changing the top value from 65 to 57 pixels will adjust the vertical positioning of the drawer when below the toolbar. The TODO comment is valuable as it recommends making this value a global constant rather than having it hardcoded in multiple places.

Consider implementing the TODO sooner rather than later by creating a global constant for toolbar height in a theme or constants file. This would improve maintainability by centralizing this value and making future UI adjustments easier.

ui/app/src/components/ContentTypeManagement/descriptors/controls/localeSelector.ts (2)

18-18: Consider using a more descriptive name for validation object

The imported foo variable is an empty frozen object being used for validations. Using a more descriptive name like emptyValidation or noValidation would make the code more self-documenting.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidation } from '../../../../utils/object';

And then update its usage accordingly.


29-35: Consider extracting common field patterns

Both "readonly" and "required" fields follow identical patterns with the same field type and structure. Consider creating a helper function to generate these common checkbox fields to reduce duplication across descriptor files.

// In a shared utils file:
+export function createCommonBooleanField(id: string, name: string) {
+  return {
+    id,
+    type: 'checkbox',
+    name,
+    defaultValue: undefined,
+    validations: foo
+  };
+}

// In this file:
-  fields: {
-    readonly: {
-      id: 'readonly',
-      type: 'checkbox',
-      name: 'Read Only',
-      defaultValue: undefined,
-      validations: foo
-    },
-    required: {
-      id: 'required',
-      type: 'checkbox',
-      name: 'Required',
-      defaultValue: undefined,
-      validations: foo
-    }
-  }
+  fields: {
+    readonly: createCommonBooleanField('readonly', 'Read Only'),
+    required: createCommonBooleanField('required', 'Required')
+  }

Also applies to: 36-42

ui/app/src/components/ContentTypeManagement/descriptors/controls/label.ts (2)

20-34: Add explicit typing for consistency with other descriptors

For consistency with other descriptor files (like localeSelector.ts), consider explicitly typing labelDescriptor as PartialContentType.

-export const labelDescriptor = {
+import { PartialContentType } from '../../utils';
+export const labelDescriptor: PartialContentType = {

18-18: Consider using a more descriptive name for validation object

Similar to the localeSelector file, the imported foo variable is an empty frozen object used for validations. A more descriptive name would improve code clarity.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidation } from '../../../../utils/object';
ui/app/src/components/ContentTypeManagement/descriptors/controls/autoFileName.ts (2)

20-44: Consider reducing duplication with localeSelector descriptor

The structure of this descriptor is almost identical to the localeSelector descriptor, with only the id, name, and description being different. Consider extracting a factory function to create these similar descriptors and reduce code duplication.

// In a shared utils file:
+export function createBasicControlDescriptor(
+  id: string,
+  name: string,
+  description: string
+): PartialContentType {
+  return {
+    id,
+    name,
+    description,
+    sections: [
+      createVirtualSection({ title: 'Options', fields: ['readonly'] }),
+      createVirtualSection({ title: 'Constraints', fields: ['required'] })
+    ],
+    fields: {
+      readonly: {
+        id: 'readonly',
+        type: 'checkbox',
+        name: 'Read Only',
+        defaultValue: undefined,
+        validations: foo
+      },
+      required: {
+        id: 'required',
+        type: 'checkbox',
+        name: 'Required',
+        defaultValue: undefined,
+        validations: foo
+      }
+    }
+  };
+}

// In this file:
-export const autoFileNameDescriptor: PartialContentType = {
-  id: 'auto-filename',
-  name: 'Auto Filename',
-  description: 'Automatically generated filename',
-  sections: [
-    createVirtualSection({ title: 'Options', fields: ['readonly'] }),
-    createVirtualSection({ title: 'Constraints', fields: ['required'] })
-  ],
-  fields: {
-    readonly: {
-      id: 'readonly',
-      type: 'checkbox',
-      name: 'Read Only',
-      defaultValue: undefined,
-      validations: foo
-    },
-    required: {
-      id: 'required',
-      type: 'checkbox',
-      name: 'Required',
-      defaultValue: undefined,
-      validations: foo
-    }
-  }
-};
+export const autoFileNameDescriptor: PartialContentType = createBasicControlDescriptor(
+  'auto-filename',
+  'Auto Filename',
+  'Automatically generated filename'
+);

18-18: Consider using a more descriptive name for validation object

Similar to the other descriptor files, the imported foo variable name doesn't clearly convey its purpose as an empty validation object.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidation } from '../../../../utils/object';
ui/app/src/components/ContentTypeManagement/descriptors/controls/time.ts (2)

17-18: Import naming could be improved for clarity

The import of foo from the object utility seems to be a non-descriptive name for what appears to be an empty validation object. Consider renaming this import to better reflect its purpose, such as emptyValidation or noValidations.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidations } from '../../../../utils/object';

20-44: Consider adding type annotation for consistency

The timeDescriptor constant lacks a type annotation, unlike some other similar descriptors (like linkInputDescriptor) that are explicitly typed as PartialContentType. Adding a type annotation would improve type safety and consistency.

-export const timeDescriptor = {
+export const timeDescriptor: PartialContentType = {
ui/app/src/components/ContentTypeManagement/descriptors/controls/checkbox.ts (3)

17-18: Import naming could be improved for clarity

The import of foo from the object utility seems to be a non-descriptive name for what appears to be an empty validation object. Consider renaming this import to better reflect its purpose, such as emptyValidation or noValidations.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidations } from '../../../../utils/object';

20-44: Consider adding type annotation for consistency

The checkboxDescriptor constant lacks a type annotation, unlike some other similar descriptors (like linkInputDescriptor) that are explicitly typed as PartialContentType. Adding a type annotation would improve type safety and consistency.

-export const checkboxDescriptor = {
+export const checkboxDescriptor: PartialContentType = {

1-46: Consider extracting a factory function for descriptors

There's significant repetition across descriptor files with identical sections and field structures. Consider creating a factory function to generate these descriptors with common elements, reducing duplication.

// Example factory function
function createSimpleControlDescriptor(id: string, name: string, description: string): PartialContentType {
  return {
    id,
    name,
    description,
    sections: [
      createVirtualSection({ title: 'Options', fields: ['readonly'] }),
      createVirtualSection({ title: 'Constraints', fields: ['required'] })
    ],
    fields: {
      readonly: {
        id: 'readonly',
        type: 'checkbox',
        name: 'Read Only',
        defaultValue: undefined,
        validations: foo
      },
      required: {
        id: 'required',
        type: 'checkbox',
        name: 'Required',
        defaultValue: undefined,
        validations: foo
      }
    }
  };
}
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkInput.ts (1)

17-18: Import naming could be improved for clarity

The import of foo from the object utility seems to be a non-descriptive name for what appears to be an empty validation object. Consider renaming this import to better reflect its purpose, such as emptyValidation or noValidations.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidations } from '../../../../utils/object';
ui/app/src/components/ContentTypeManagement/descriptors/controls/videoPicker.ts (2)

1-2: Missing copyright header

Unlike the other descriptor files, this file is missing the standard copyright and license header that's present in the other files. Consider adding the standard header for consistency.

+/*
+ * Copyright (C) 2007-2025 Crafter Software Corporation. All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 import { foo } from '../../../../utils/object';
 import { createVirtualSection, PartialContentType } from '../../utils';

1-1: Import naming could be improved for clarity

The import of foo from the object utility seems to be a non-descriptive name for what appears to be an empty validation object. Consider renaming this import to better reflect its purpose, such as emptyValidation or noValidations.

-import { foo } from '../../../../utils/object';
+import { foo as emptyValidations } from '../../../../utils/object';
ui/app/src/components/FormsEngine/lib/formConsts.ts (1)

26-27: Consider the TODO comment about stackFormCountAtom placement.

The comment suggests that stackFormCountAtom should be defined in GlobalFormContext. As part of this refactoring effort, it would be beneficial to address this TODO and move the atom to its proper location.

ui/app/src/components/ContentTypeManagement/descriptors/controls/repeat.ts (1)

24-27: Consider adding constraints to ensure minOccurs ≤ maxOccurs.

When using a repeating group, there should be validation to ensure that the minimum occurrences is less than or equal to the maximum occurrences.

Consider adding cross-field validation or UI guidance to enforce this constraint:

createVirtualSection({ title: 'Options', fields: ['minOccurs', 'maxOccurs', 'readonly'] }),
+// Add helper text or validation logic to ensure minOccurs ≤ maxOccurs
ui/app/src/components/ContentTypeManagement/descriptors/controls/imagePicker.ts (1)

31-67: Add meaningful validation and default values to image picker fields.

The descriptor fields use undefined default values and empty validation objects. For numeric fields like thumbnailWidth and thumbnailHeight, consider adding reasonable defaults and validation rules.

Example improvements:

thumbnailWidth: {
  id: 'thumbnailWidth',
  type: 'numeric-input',
  name: 'Thumbnail Width',
-  defaultValue: undefined,
-  validations: foo
+  defaultValue: 150,
+  validations: {
+    min: 50,
+    isInteger: true
+  }
},
thumbnailHeight: {
  id: 'thumbnailHeight',
  type: 'numeric-input',
  name: 'Thumbnail Height',
-  defaultValue: undefined,
-  validations: foo
+  defaultValue: 150,
+  validations: {
+    min: 50,
+    isInteger: true
+  }
},
ui/app/src/components/ContentTypeManagement/descriptors/controls/textarea.ts (2)

29-71: Add meaningful validation and default values to textarea fields.

The fields in this descriptor use undefined default values and empty validation objects. Consider adding reasonable defaults and validation rules for numeric fields like height, width, and maxlength.

Example improvements:

height: {
  id: 'height',
  type: 'numeric-input',
  name: 'Height',
-  defaultValue: undefined,
-  validations: foo
+  defaultValue: 100,
+  validations: {
+    min: 20,
+    isInteger: true
+  }
},
width: {
  id: 'width',
  type: 'numeric-input',
  name: 'Width',
-  defaultValue: undefined,
-  validations: foo
+  defaultValue: 300,
+  validations: {
+    min: 50,
+    isInteger: true
+  }
},
maxlength: {
  id: 'maxlength',
  type: 'numeric-input',
  name: 'Maximum Length',
-  defaultValue: undefined,
-  validations: foo
+  defaultValue: 1000,
+  validations: {
+    min: 1,
+    isInteger: true
+  }
},

57-63: Add a helpful description for the tokenize field.

The "Tokenize for Indexing" field might not be immediately clear to all users. Consider adding a description property to explain its purpose.

tokenize: {
  id: 'tokenize',
  type: 'checkbox',
  name: 'Tokenize for Indexing',
  defaultValue: undefined,
  validations: foo,
+  description: 'When enabled, the text content will be processed for search indexing'
},
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkedDropdown.ts (2)

17-18: Consider absolute imports for better maintainability.

The deep relative imports ('../../utils' and '../../../../utils/object') can be difficult to maintain if files are moved. Consider using absolute imports (e.g., 'src/components/ContentTypeManagement/utils') for better maintainability.


28-57: Consider adding meaningful validations instead of empty object.

The foo object used for validations is currently an empty frozen object. While this works as a placeholder, consider implementing actual validation rules for these fields to ensure data integrity.

Also, all fields have defaultValue: undefined. Consider providing appropriate default values where applicable (e.g., false for checkboxes) to improve the user experience.

- validations: foo
+ validations: {
+   // Add appropriate validation rules
+ }

- defaultValue: undefined
+ defaultValue: false  // For boolean fields like readonly/required
ui/app/src/components/ContentTypeManagement/descriptors/controls/numericInput.ts (1)

43-56: Consider adding relationship validation between minValue and maxValue.

The minValue and maxValue fields should have a relationship constraint to ensure minValue is always less than or equal to maxValue. Consider implementing this validation to prevent potential invalid configurations.

maxValue: {
  id: 'maxValue',
  type: 'numeric-input',
  name: 'Maximum Value',
  defaultValue: undefined,
- validations: foo
+ validations: {
+   // Add validation to ensure maxValue is greater than or equal to minValue
+ }
}
ui/app/src/components/ContentTypeManagement/descriptors/controls/dropdown.ts (3)

20-24: Add type annotation for consistency with other descriptors.

Unlike other descriptors, dropdownDescriptor lacks a type annotation. Consider adding : PartialContentType to maintain consistency with the other descriptor files.

- export const dropdownDescriptor = {
+ export const dropdownDescriptor: PartialContentType = {

29-35: Define structure for repeat field options.

The options field is of type repeat but doesn't specify the structure for each repeated item. Consider defining a clear structure for dropdown options (e.g., label/value pairs) to ensure consistent data entry.


43-49: Consider providing true as defaultValue for allowEmpty.

Since most dropdowns should allow users to select nothing by default, consider setting defaultValue: true for the allowEmpty field to improve usability.

allowEmpty: {
  id: 'allowEmpty',
  type: 'checkbox',
  name: 'Allow Empty',
- defaultValue: undefined,
+ defaultValue: true,
  validations: foo
}
ui/app/src/components/ContentTypeManagement/descriptors/controls/input.ts (3)

40-46: Inconsistent field name casing.

The readonly field uses lowercase for the name property, while other fields use proper capitalization or camelCase. Consider standardizing the naming convention for better UI consistency.

readonly: {
  id: 'readonly',
  type: 'checkbox',
- name: 'readonly',
+ name: 'Read Only',
  defaultValue: undefined,
  validations: foo
}

54-60: Inconsistent field name casing.

Similar to the readonly field, the escapeContent field uses camelCase for the name property without spaces, while other fields use proper spacing or different conventions. Standardize naming for UI consistency.

escapeContent: {
  id: 'escapeContent',
  type: 'checkbox',
- name: 'escapeContent',
+ name: 'Escape Content',
  defaultValue: undefined,
  validations: foo
}

68-74: Add helpful description for pattern field.

The pattern field is a text input for entering regex patterns, which can be complex for non-technical users. Consider adding a description or placeholder with an example pattern to help users.

pattern: {
  id: 'pattern',
  type: 'input',
  name: 'pattern',
  defaultValue: undefined,
+ description: 'Regular expression pattern (e.g., [0-9]+ for numbers only)',
  validations: foo
}
ui/app/src/components/FormsEngine/lib/validators.ts (1)

51-52: Consider consistent value types in validatorsMap

The newly added colorPicker entry uses undefined while all other entries in the map use null. While this may be intentional, it creates an inconsistency in the pattern.

Consider using null for consistency:

  'video-picker': null,
- colorPicker: undefined
+ colorPicker: null
ui/app/src/components/ContentTypeManagement/descriptors/controls/boxFileUpload.ts (2)

22-53: Consider using a more specific validation object

The descriptor uses foo (an empty frozen object) for all field validations. This might be a placeholder, but for proper validation, you should consider defining more specific validation rules.

Consider defining appropriate validation rules for each field type. For example, the "path" field might need format validation.


31-37: Consider adding a placeholder or format hint

The path field could benefit from a placeholder value or format hint to guide users on the expected format for Box file paths.

Add a placeholder property to provide guidance:

 path: {
   id: 'path',
   type: 'input',
   name: 'Path',
   defaultValue: undefined,
+  placeholder: 'e.g., /folder/file.ext',
   validations: foo
 },
ui/app/src/components/ContentTypeManagement/descriptors/controls/uuid.ts (2)

20-44: Add type annotation for consistent typing

Unlike the other descriptor files, uuidDescriptor doesn't have an explicit type annotation. For consistency and type safety, consider adding the PartialContentType type.

- export const uuidDescriptor = {
+ export const uuidDescriptor: PartialContentType = {
  id: 'uuid',
  name: 'UUID',
  ...

28-43: Consider adding helptext for fields

The UUID control's fields would benefit from additional helptext to explain their purpose, especially for the 'readonly' field which may not be immediately obvious in the context of a UUID.

Add helptext to provide more context:

 readonly: {
   id: 'readonly',
   type: 'checkbox',
   name: 'Read Only',
   defaultValue: undefined,
+  helpText: 'When enabled, the UUID cannot be modified after creation',
   validations: foo
 },
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkTextarea.ts (2)

20-44: Consider adding field for maximum links

For a control that handles multiple URLs/links, it might be useful to add a configuration option for the maximum number of links allowed.

Consider adding a maxLinks field to the Options section:

 sections: [
-  createVirtualSection({ title: 'Options', fields: ['readonly'] }),
+  createVirtualSection({ title: 'Options', fields: ['readonly', 'maxLinks'] }),
   createVirtualSection({ title: 'Constraints', fields: ['required'] })
 ],
 fields: {
   readonly: {
     id: 'readonly',
     type: 'checkbox',
     name: 'Read Only',
     defaultValue: undefined,
     validations: foo
   },
+  maxLinks: {
+    id: 'maxLinks',
+    type: 'numeric-input',
+    name: 'Maximum Links',
+    defaultValue: undefined,
+    helpText: 'Maximum number of links allowed (leave empty for unlimited)',
+    validations: foo
+  },
   required: {
     // existing code

17-18: Consider descriptive names for utility imports

The import of foo from utils/object is not descriptive of its purpose. Using a more descriptive name would improve code readability.

 import { createVirtualSection, PartialContentType } from '../../utils';
-import { foo } from '../../../../utils/object';
+import { emptyValidations as foo } from '../../../../utils/object';

Alternatively, consider renaming the utility in its source file to better reflect its purpose.

ui/app/src/components/ContentTypeManagement/descriptors/controls/rte.ts (1)

20-65: Add type annotation for improved type safety.

Unlike the other descriptors, rteDescriptor is missing the PartialContentType type annotation. While the structure matches the expected type, adding the explicit type would ensure type safety and consistency with the other descriptor files.

-export const rteDescriptor = {
+export const rteDescriptor: PartialContentType = {
ui/app/src/components/ContentTypeManagement/descriptors/controls/awsFileUpload.ts (3)

17-18: Consider replacing the ambiguous foo import.

The import name foo is not descriptive and may cause confusion. Consider renaming it to something more meaningful like emptyValidations or defaultValidations to better reflect its purpose.

- import { foo } from '../../../../utils/object';
+ import { foo as emptyValidations } from '../../../../utils/object';

20-51: Good implementation of AWS file upload descriptor.

The descriptor is well-structured with appropriate sections for Options and Constraints, following the pattern used for other control descriptors.

Consider adding JSDoc comments for the fields to improve developer understanding of their purpose and expected values.


34-35: Validations definition needs implementation.

The empty frozen object foo is used for validations but doesn't provide any actual validation logic. Consider implementing actual validation rules or documenting why an empty object is sufficient.

- validations: foo
+ validations: {
+   // Add appropriate validation rules for path
+ }
ui/app/src/components/ContentTypeManagement/descriptors/controls/transcodedVideoPicker.ts (2)

17-18: Consider replacing the ambiguous foo import.

The import name foo is not descriptive and may cause confusion. Consider renaming it to something more meaningful like emptyValidations or defaultValidations to better reflect its purpose.

- import { foo } from '../../../../utils/object';
+ import { foo as emptyValidations } from '../../../../utils/object';

20-44: Good implementation of transcoded video picker descriptor.

The descriptor is well-structured with appropriate sections for Options and Constraints, similar to other control descriptors.

Consider adding JSDoc comments for the fields to improve developer understanding of their purpose and expected values.

ui/app/src/components/ContentTypeManagement/descriptors/controls/internalName.ts (1)

31-46: Consider consistency with other descriptors.

The field structure is different from the other descriptors. The required field has a default value of true while other descriptors use undefined. Consider whether this inconsistency is intentional.

ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (1)

28-64: Consider adding documentation to field configurations.

The field configurations lack comments explaining their purpose and expected values, which would improve maintainability.

Consider adding documentation for each field, especially for the options field since it's likely the most complex part of this control. For example:

options: {
  id: 'options',
  type: 'repeat',
  name: 'Options',
  defaultValue: undefined,
+ description: 'Define available options for the checkbox group',
  validations: foo
},
ui/app/src/components/ContentTypeManagement/descriptors/controls/fileName.ts (1)

29-35: Inconsistent naming convention.

The field naming convention is inconsistent throughout the descriptor.

Standardize the field naming convention:

maxlength: {
  id: 'maxlength',
  type: 'numeric-input',
- name: 'maxLength',
+ name: 'Max Length',
  defaultValue: undefined,
  validations: foo
},
readonly: {
  id: 'readonly',
  type: 'checkbox',
- name: 'readonly',
+ name: 'Read Only',
  defaultValue: undefined,
  validations: foo
},

Also applies to: 37-42, 51-56

ui/app/src/components/FormsEngine/components/FormBackToTop.tsx (1)

29-30: Consider adding a safety check for the containerRef.

The component should handle the case when containerRef.current is null, which can happen before the ref is attached.

export function FormBackToTop({ containerRef, getScrollContainer = (e) => e }: FormBackToTopProps) {
+ const handleScrollToTop = () => {
+   const element = containerRef.current;
+   if (element) {
+     getScrollContainer(element).scroll({ top: 0, behavior: 'smooth' });
+   }
+ };
  return (
    <Box minHeight={100} justifyContent="center" alignItems="center" display="flex">
      <Tooltip title={<FormattedMessage defaultMessage="Back to top" />}>
-       <Fab onClick={() => getScrollContainer(containerRef.current).scroll({ top: 0, behavior: 'smooth' })}>
+       <Fab onClick={handleScrollToTop}>
          <ArrowUpward />
        </Fab>
      </Tooltip>
    </Box>
  );
}
ui/app/src/components/ContentTypeManagement/components/MainSection.tsx (1)

20-21: Consider making this a shared component.

The TODO comment correctly identifies that this layout pattern could be reused elsewhere. Since this appears to be a generic drawer layout pattern, consider moving it to a shared components directory instead of keeping it specific to ContentTypeManagement.

ui/app/src/components/FormsEngine/lib/useSaveForm.tsx (1)

119-119: New TODO for package cancellation.

This new comment suggests an upcoming enhancement for the content saving functionality related to package cancellation.

Consider adding a more detailed comment to provide context about when and why packages might need to be canceled during content saving.

ui/app/src/components/ContentTypeManagement/descriptors/controls/forceHttps.ts (1)

17-34: Consider improving validation and default value for the checkbox field

The refactoring to a descriptor-based approach looks good, but there are two concerns:

  1. The use of foo (an empty frozen object) for validations doesn't seem to provide any actual validation logic.
  2. Using undefined as a default value for a checkbox field is unusual; typically, checkboxes should have a boolean default.
 readonly: {
 	id: 'readonly',
 	type: 'checkbox',
 	name: 'Read Only',
-	defaultValue: undefined,
-	validations: foo
+	defaultValue: false,
+	validations: {
+		// Add actual validation rules if needed
+	}
 }
ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (1)

40-76: Excellent component implementation with proper state management.

The SelectTypeView component demonstrates several good practices:

  1. Uses useState for local state management
  2. Implements debounced input for search performance
  3. Utilizes useEffect for derived state calculations
  4. Properly handles prop-to-state initialization
  5. Implements a clean UI structure with proper component composition

One minor suggestion to improve type safety:

Consider specifying the initial state for filteredTypes to avoid the undefined state:

-const [filteredTypes, setFilteredTypes] = useState<ContentType[]>();
+const [filteredTypes, setFilteredTypes] = useState<ContentType[]>(
+  filterTypesByKeywordsAndObjectType(contentTypesList, keywords, objectTypeFilter)
+);
ui/app/src/components/ContentTypeManagement/components/TypeListingView.tsx (2)

35-35: Consider providing a more specific type for the event parameter

The onTypeSelected callback type is using Parameters<TypeListProps['onCardClick']>[0] for the event parameter. Consider defining a more explicit type to make it clearer what kind of event is expected.


53-55: Consider checking for null before accessing properties

The line const loading = contentTypesList == null; correctly checks for null/undefined, but you should add more comprehensive error handling for when the API call fails to load the content types list.

- const contentTypesList = useContentTypeList();
- const loading = contentTypesList == null;
+ const { data: contentTypesList, error, loading } = useContentTypeList();
+ 
+ // Show error state if the API call fails
+ if (error) {
+   return <ErrorDisplay message="Failed to load content types" error={error} />;
+ }
ui/app/src/components/FormsEngine/controls/ColorPicker.tsx (4)

59-68: Add proper TypeScript typing for the CustomHexColorInput component

The CustomHexColorInput component is missing proper TypeScript props definition. Consider adding an interface for its props.

+interface CustomHexColorInputProps extends ComponentProps<typeof HexColorInput> {}

-const CustomHexColorInput = forwardRef((props, ref) => {
+const CustomHexColorInput = forwardRef<HTMLInputElement, CustomHexColorInputProps>((props, ref) => {

76-81: Remove commented code

There's commented out code that appears to be an earlier implementation. This should be removed to keep the codebase clean.

-	// const presetColors = ['#cd9323', '#1a53d8', '#9a2151', '#0d6416', '#8d2808'];
-	// return (
-	// 	<FormsEngineField field={field}>
-	// 		<RgbaColorPicker color={value} onChange={setValue} />
-	// 	</FormsEngineField>
-	// );

82-83: Add null check before accessing nested properties

The code accesses nested properties without first verifying they exist, which could lead to runtime errors.

-	const alpha = (field.properties.alpha.value as boolean) ?? true;
-	const format = (field.properties.format.value as ColourFormat) ?? 'hex';
+	const alpha = (field.properties?.alpha?.value as boolean) ?? true;
+	const format = (field.properties?.format?.value as ColourFormat) ?? 'hex';

145-154: Move throttle to a utility file

The throttle function is a general utility and should be moved to a common utility file instead of being defined in this component file.

Consider moving this to a file like ui/app/src/utils/function.ts and importing it here. This would make it reusable across the application.

ui/app/src/components/ContentTypeManagement/descriptors/archetypes.ts (1)

19-19: Consider using a more descriptive variable name than 'foo'.

The variable foo is an empty frozen object used for validations, but its name is not descriptive of its purpose. A more meaningful name like emptyValidations or defaultValidations would better communicate its intended use.

-import { foo } from '../../../utils/object';
+import { foo as emptyValidations } from '../../../utils/object';
ui/app/src/components/ContentTypeManagement/components/TypeListControlBar.tsx (1)

61-61: Use specific props for Paper component.

Instead of spreading {...slotProps} directly to the Paper component which might include unrelated properties, explicitly spread only slotProps?.paper to avoid potential issues.

-<Paper {...slotProps} sx={consolidateSx({ p: 1, mb: 2, display: 'flex' }, slotProps?.paper?.sx)}>
+<Paper {...slotProps?.paper} sx={consolidateSx({ p: 1, mb: 2, display: 'flex' }, slotProps?.paper?.sx)}>
ui/app/src/components/ContentTypeManagement/components/TypeDetailsVIewHeader.tsx (3)

36-36: Fix component name typo.

The component name TypeDetailsVIewHeader has a typo (capital 'I' in 'VIew'). For consistency and readability, rename it to TypeDetailsViewHeader.

-export function TypeDetailsVIewHeader({ type, onActionClick }: TypeDetailsHeaderProps) {
+export function TypeDetailsViewHeader({ type, onActionClick }: TypeDetailsHeaderProps) {

Remember to also update the filename and default export accordingly.


45-46: Remove console.log statement before production.

There's a console.log statement that should be removed before deploying to production. Consider using a proper logging system if needed.

-						console.log('Deleted.');
						onActionClick?.(e, 'deleted');

69-79: Implement missing date and user information.

The component includes a TODO comment about missing last update date and user information, but uses hardcoded values. This should be addressed by fetching the actual data from the content type.

-							// TODO: Where does this come from? Add to XML?
-							date: 'today',
-							user: 'John',
+							date: type.lastModifiedDate ? new Date(type.lastModifiedDate).toLocaleString() : 'N/A',
+							user: type.lastModifier || 'N/A',

Would you like me to propose a more comprehensive solution for tracking and displaying this metadata?

ui/app/src/components/GlobalDialogManager/DialogStackItemContainer.tsx (1)

87-94: Handle type discrepancy properly

There's a TODO comment about a type discrepancy between EnhancedDialogProps['onTransitionExited'] and propsRef.current.onTransitionEnd. This should be addressed properly rather than using @ts-expect-error.

Consider either:

  1. Updating the interface definition to align these types
  2. Creating a proper type assertion that converts between the types
  3. Add proper documentation explaining why this discrepancy exists and why the error suppression is necessary
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (2)

36-38: Consider simplifying with a more versatile implementation

The composeFieldPath function only handles two segments. Consider using the commented-out implementation on line 34 which can handle variable numbers of path segments and possibly simplify code that uses this function.

-function composeFieldPath(fieldPath: string, fieldId: string): string {
-	return fieldPath ? `${fieldPath}.${fieldId}` : fieldId;
-}
+function composeFieldPath(...pieces: string[]): string {
+	return pieces.filter(Boolean).join('.');
+}

52-149: Well-structured component with proper error handling and selection states

The FieldChip component is well-implemented with several nice features:

  • Properly handles different field types (repeat vs. other types)
  • Supports error states via fieldPathsWithErrors
  • Handles selection state with visual feedback
  • Recursively renders nested fields for repeat types
  • Properly handles dark/light mode theming

There are a couple of minor concerns:

  1. Type assertions with as ElementType<BoxProps> on lines 60-61
  2. The @ts-expect-error comments on lines 97 and 102

Consider refactoring to avoid the type assertions and TypeScript suppressions by creating more precise type definitions or component wrappers.

ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialogContainer.tsx (2)

32-35: Consider validating item before usage.

Currently, this code destructures props.item and then immediately uses item.path. If there’s any scenario in which item might be undefined or null, this could cause runtime errors. A quick check or assertion before calling withoutIndex(item.path) may help avoid potential null reference issues.


44-71: Optional: Make the skeleton item count configurable.

A fixed skeleton count of “4” might work fine in many cases. However, if you plan to reuse this dialog in contexts requiring more or fewer placeholders, consider making the skeleton item count a prop. This adds flexibility without complicating the UI.

ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (4)

90-94: Potential performance overhead during bulk expansion/collapse.

The setSectionsExpandedState function loops over all section atoms and sets them individually, which may be slightly inefficient for a large number of sections. Consider batching state updates or using an optimized approach if performance becomes a concern with more sections.


110-113: Clarify parameter types for handleDataSourceSelected.

The callback function _ => ... indicates an unused parameter. For clarity and maintainability, consider explicitly naming parameters and providing type annotations (e.g., (event: React.MouseEvent, field: ContentTypeField) => ...) to improve readability and reduce confusion when future developers revise or extend this code.


139-168: Consider user interface for adding fields.

Currently, a "Add Field" button is provided for each section, but the actual creation process isn’t outlined in this snippet. Ensuring a clear workflow (e.g., a dialog or inline prompt for field details) will greatly improve usability and completeness of the “Add Field” functionality.


209-218: Allow user-defined new section title.

The SectionInsertionDialog always inserts a new section with a hardcoded title ("New Section"). You might consider prompting the user for a custom title, which would improve flexibility. This could be done via an additional text field in the dialog or a subsequent edit flow.

ui/app/src/components/ContentTypeManagement/components/CreateTypeDialog.tsx (2)

68-70: Add custom validation logic.

There is a TODO comment regarding validation. Currently, the validate function is a placeholder. Before production, ensure proper checks for unique IDs, invalid characters, or type conflicts to prevent creating faulty or duplicate content types.


139-139: Address the misleading character class warning.

Static analysis complains about the [\\u0300-\\u036f] character range. This approach may have edge cases with more complex diacritical marks. Consider using a library specifically designed for diacritic stripping or an alternative pattern if you need broader coverage.

🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: A character class cannot match a character and a combining character.

A character and a combining character forms a new character. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

ui/app/src/components/ContentTypeManagement/ContentTypeManagement.tsx (2)

47-51: Remove accidental or leftover commented lines.

The lines containing “dispatch(emitSystemEvent(...))” and “onClose?.()” are commented out. Consider removing them if they are no longer needed or uncommenting them if they serve a valid purpose to avoid confusion.


55-66: Add a dedicated “create” pathway.

The state variable view includes 'create', but there is no corresponding UI flow for this mode. If it’s part of an upcoming feature, add a placeholder route or comment to clarify. Otherwise, remove the redundant value from the union type to keep the codebase clean.

ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (2)

53-58: Unused variable check
The dataSourceRootProperties constant is declared but not referenced later in the file. Consider using or removing it to keep the codebase clean.

-const dataSourceRootProperties = ['id', 'type', 'title', 'interface'];
+// Remove or use this variable if needed:
+// const dataSourceRootProperties = ['id', 'type', 'title', 'interface'];

319-396: Section descriptor & extended fields
The sectionDescriptor with a color picker introduces a nice visual enhancement. Fields such as description, expandByDefault, and color are well-defined. Validations rely on foo, but consider adding more robust validations if user input might be malformed.

ui/app/src/models/ContentType.ts (1)

70-127: Extended properties region
The use of a large union of string keys in properties is flexible but could become unwieldy. Consider grouping related properties or using narrower, typed fields to catch mistakes at compile time.

ui/app/src/components/ContentTypeManagement/components/EditTypeView.tsx (1)

467-477: updateTypeFromSectionUpdate()
Creates a shallow copy and updates the matching section by index. The console logging can remain for debugging but consider removing or gating it based on environment.

 console.log(index, selectedSection, updatedValues, updatedType);
-// Consider removing or wrapping in a condition if there's a risk of polluting logs in production
ui/app/src/services/contentTypes.ts (1)

103-115: Consider parseFloat edge cases.
bestGuessParse() treats any partial numeric string (e.g., "123abc") as a valid float. Verify that this behavior is desired or consider stricter checks.

ui/app/src/components/DeleteContentTypeDialog/DeleteContentTypeDialogBody.tsx (1)

107-109: Review: Usage of key Attribute in Inline Element

The added key="" attribute on the <Box> component helps React’s reconciliation when elements are part of a dynamic list. However, using an empty string as a key is not ideal because:

  • If this element isn’t part of an iterated list, the key attribute might be unnecessary.
  • If it is part of a list, an empty key doesn’t provide a unique identifier which may lead to potential reconciliation issues.

Consider either removing the key attribute (if not needed) or assigning a meaningful, unique key.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bda7a90 and eb1c03f.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (99)
  • ui/app/package.json (1 hunks)
  • ui/app/src/CHANGELOG.md (1 hunks)
  • ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialog.tsx (1 hunks)
  • ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialogContainer.tsx (1 hunks)
  • ui/app/src/components/ChangeContentTypeDialog/utils.ts (1 hunks)
  • ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/ContentTypeManagement.tsx (4 hunks)
  • ui/app/src/components/ContentTypeManagement/components/CreateTypeDialog.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/EditTypeView.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/EditTypeViewLayout.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/Layout.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/MainSection.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeBuilderAddButton.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeBuilderFormsEngine.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeCard.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeCardMedia.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeDetailsVIewHeader.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeList.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeListControlBar.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeListingView.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/archetypes.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/autoFileName.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/awsFileUpload.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/boxFileUpload.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/checkbox.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/colorPicker.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/dateTime.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/disabled.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/dropdown.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/fileName.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/forceHttps.ts (2 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/imagePicker.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/input.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/internalName.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/label.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/linkInput.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/linkTextarea.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/linkedDropdown.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/localeSelector.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/nodeSelector.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/numericInput.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/pageNavOrder.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/repeat.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/rte.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/textarea.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/time.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/transcodedVideoPicker.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/uuid.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/videoPicker.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/descriptors/dataSources/components.ts (1 hunks)
  • ui/app/src/components/ContentTypeManagement/utils.ts (1 hunks)
  • ui/app/src/components/DeleteContentTypeDialog/DeleteContentTypeDialogBody.tsx (1 hunks)
  • ui/app/src/components/FormsEngine/FormsEngine.tsx (3 hunks)
  • ui/app/src/components/FormsEngine/components/FormBackToTop.tsx (1 hunks)
  • ui/app/src/components/FormsEngine/components/FormLayout.tsx (3 hunks)
  • ui/app/src/components/FormsEngine/components/SectionAccordion.tsx (1 hunks)
  • ui/app/src/components/FormsEngine/components/TableOfContents.tsx (3 hunks)
  • ui/app/src/components/FormsEngine/controls/ColorPicker.tsx (1 hunks)
  • ui/app/src/components/FormsEngine/lib/controlHelpers.tsx (1 hunks)
  • ui/app/src/components/FormsEngine/lib/controlMap.ts (3 hunks)
  • ui/app/src/components/FormsEngine/lib/formConsts.ts (2 hunks)
  • ui/app/src/components/FormsEngine/lib/formUtils.tsx (3 hunks)
  • ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (3 hunks)
  • ui/app/src/components/FormsEngine/lib/useSaveForm.tsx (2 hunks)
  • ui/app/src/components/FormsEngine/lib/validators.ts (1 hunks)
  • ui/app/src/components/FormsEngine/lib/valueRetrievers.ts (2 hunks)
  • ui/app/src/components/FormsEngine/lib/valueSerializers.ts (2 hunks)
  • ui/app/src/components/GlobalDialogManager/DialogStackItemContainer.tsx (1 hunks)
  • ui/app/src/components/ItemDisplay/ItemDisplay.tsx (1 hunks)
  • ui/app/src/components/LegacyComponentsPanel/utils.ts (2 hunks)
  • ui/app/src/components/NewContentDialog/NewContentCard.tsx (0 hunks)
  • ui/app/src/components/NewContentDialog/NewContentDialog.tsx (2 hunks)
  • ui/app/src/components/NewContentDialog/NewContentDialogContainer.tsx (1 hunks)
  • ui/app/src/components/NewContentDialog/index.ts (0 hunks)
  • ui/app/src/components/NewContentDialog/utils.ts (1 hunks)
  • ui/app/src/components/ResizeableDrawer/ResizeableDrawer.tsx (1 hunks)
  • ui/app/src/components/SearchBar/SearchBar.tsx (5 hunks)
  • ui/app/src/components/ViewToolbar/ViewToolbar.tsx (2 hunks)
  • ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (1 hunks)
  • ui/app/src/hooks/useIsDarkModeTheme.tsx (1 hunks)
  • ui/app/src/hooks/useResizeObserver.ts (1 hunks)
  • ui/app/src/models/ContentType.ts (8 hunks)
  • ui/app/src/services/contentTypes.ts (13 hunks)
  • ui/app/src/state/reducers/dialogs/changeContentType.ts (1 hunks)
  • ui/app/src/state/reducers/dialogs/newContent.ts (1 hunks)
  • ui/app/src/utils/color.ts (1 hunks)
  • ui/app/src/utils/contentType.ts (2 hunks)
  • ui/app/src/utils/itemActions.ts (1 hunks)
  • ui/app/src/utils/object.ts (2 hunks)
  • ui/app/src/utils/path.ts (1 hunks)
  • ui/app/src/utils/string.ts (1 hunks)
  • ui/app/src/utils/system.ts (3 hunks)
  • ui/app/src/utils/ui.tsx (2 hunks)
💤 Files with no reviewable changes (2)
  • ui/app/src/components/NewContentDialog/NewContentCard.tsx
  • ui/app/src/components/NewContentDialog/index.ts
🧰 Additional context used
🧬 Code Definitions (59)
ui/app/src/components/ContentTypeManagement/descriptors/controls/localeSelector.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/label.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/autoFileName.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/imagePicker.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkedDropdown.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/colorPicker.ts (1)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/components/ContentTypeManagement/descriptors/controls/repeat.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/awsFileUpload.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/dateTime.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkTextarea.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/input.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/videoPicker.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/nodeSelector.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkInput.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/time.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/textarea.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/checkbox.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/internalName.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/boxFileUpload.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/pageNavOrder.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/transcodedVideoPicker.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/dataSources/components.ts (1)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/dropdown.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/rte.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialog.tsx (1)
ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialogContainer.tsx (1) (1)
  • ChangeContentTypeDialogContainer (31-73)
ui/app/src/components/LegacyComponentsPanel/utils.ts (1)
ui/app/src/utils/contentType.ts (1) (1)
  • createFormDefinitionPathFromTypeId (207-209)
ui/app/src/components/ContentTypeManagement/descriptors/controls/uuid.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/utils/itemActions.ts (2)
ui/app/src/utils/system.ts (1) (1)
  • pickShowContentFormAction (103-124)
ui/app/src/components/NewContentDialog/utils.ts (1) (1)
  • NewContentDialogProps (28-30)
ui/app/src/components/ContentTypeManagement/descriptors/controls/fileName.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/NewContentDialog/utils.ts (1)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/components/FormsEngine/FormsEngine.tsx (1)
ui/app/src/components/FormsEngine/components/FormBackToTop.tsx (1) (1)
  • FormBackToTop (29-39)
ui/app/src/components/ContentTypeManagement/descriptors/controls/forceHttps.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (2)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/services/contentTypes.ts (2) (2)
  • fetchLegacyContentTypes (557-563)
  • parseLegacyContentType (499-517)
ui/app/src/components/ChangeContentTypeDialog/utils.ts (1)
ui/app/src/components/NewContentDialog/utils.ts (1) (1)
  • NewContentDialogProps (28-30)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsVIewHeader.tsx (2)
ui/app/src/models/ContentType.ts (1) (1)
  • PossibleContentTypeDraft (183-185)
ui/app/src/components/ContentTypeManagement/components/TypeCardMedia.tsx (1) (1)
  • TypeCardMedia (30-67)
ui/app/src/components/FormsEngine/components/FormBackToTop.tsx (1)
ui/app/src/components/FormsEngine/lib/formUtils.tsx (1) (1)
  • getScrollContainer (78-80)
ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialogContainer.tsx (7)
ui/app/src/components/ChangeContentTypeDialog/utils.ts (1) (1)
  • ChangeContentTypeDialogContainerProps (38-40)
ui/app/src/components/ContentTypeManagement/components/TypeList.tsx (1) (1)
  • TypeListProps (25-31)
ui/app/src/utils/path.ts (1) (1)
  • withoutIndex (84-86)
ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (1) (1)
  • useFetchAllowedTypesForPath (26-57)
ui/app/src/utils/contentType.ts (1) (1)
  • getNormalizedFolderPathForApi1GetTypes (202-205)
ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (1) (1)
  • SelectTypeView (40-76)
ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (1) (1)
  • ObjectTypeOption (25-25)
ui/app/src/components/ContentTypeManagement/components/TypeCardMedia.tsx (2)
ui/app/src/services/contentTypes.ts (1) (1)
  • fetchPreviewImage (664-667)
ui/app/src/utils/system.ts (1) (1)
  • consolidateSx (99-101)
ui/app/src/components/FormsEngine/components/FormLayout.tsx (2)
ui/app/src/hooks/useResizeObserver.ts (1) (1)
  • useResizeObserver (22-36)
ui/app/src/utils/ui.tsx (1) (1)
  • getMarginSxProps (49-54)
ui/app/src/components/ContentTypeManagement/descriptors/archetypes.ts (3)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/components/ContentTypeManagement/utils.ts (1) (1)
  • createEmptyTypeStructure (202-221)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/components/TypeCard.tsx (3)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/components/ContentTypeManagement/components/TypeCardMedia.tsx (1) (1)
  • TypeCardMedia (30-67)
ui/app/src/utils/system.ts (1) (1)
  • consolidateSx (99-101)
ui/app/src/components/ContentTypeManagement/descriptors/controls/numericInput.ts (2)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • PartialContentType (200-200)
  • createVirtualSection (274-284)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (1)
ui/app/src/utils/object.ts (1) (1)
  • ref (169-171)
ui/app/src/components/NewContentDialog/NewContentDialogContainer.tsx (7)
ui/app/src/components/NewContentDialog/utils.ts (1) (1)
  • NewContentDialogContainerProps (38-40)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/utils/path.ts (1) (1)
  • withoutIndex (84-86)
ui/app/src/components/ContentTypeManagement/components/TypeList.tsx (1) (1)
  • TypeListProps (25-31)
ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (1) (1)
  • useFetchAllowedTypesForPath (26-57)
ui/app/src/utils/contentType.ts (1) (1)
  • getNormalizedFolderPathForApi1GetTypes (202-205)
ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (1) (1)
  • SelectTypeView (40-76)
ui/app/src/components/ContentTypeManagement/components/TypeListControlBar.tsx (4)
ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (3) (3)
  • ObjectTypeOption (25-25)
  • ContentTypesFilterProps (23-23)
  • ContentTypesFilter (44-55)
ui/app/src/components/SearchBar/SearchBar.tsx (2) (2)
  • SearchBarProps (36-59)
  • SearchBar (61-204)
ui/app/src/utils/system.ts (1) (1)
  • consolidateSx (99-101)
ui/app/src/utils/string.ts (1) (1)
  • isEmpty (283-286)
ui/app/src/components/ContentTypeManagement/components/CreateTypeDialog.tsx (2)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/utils/string.ts (1) (1)
  • camelize (25-29)
ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (26)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentTypeField (62-140)
ui/app/src/utils/object.ts (1) (1)
  • foo (282-282)
ui/app/src/components/ContentTypeManagement/descriptors/controls/autoFileName.ts (1) (1)
  • autoFileNameDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/checkbox.ts (1) (1)
  • checkboxDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (1) (1)
  • checkboxGroupDescriptor (20-65)
ui/app/src/components/ContentTypeManagement/descriptors/controls/dateTime.ts (1) (1)
  • dateTimeDescriptor (20-75)
ui/app/src/components/ContentTypeManagement/descriptors/controls/disabled.ts (1) (1)
  • disabledDescriptor (17-23)
ui/app/src/components/ContentTypeManagement/descriptors/controls/dropdown.ts (1) (1)
  • dropdownDescriptor (20-58)
ui/app/src/components/ContentTypeManagement/descriptors/controls/fileName.ts (1) (1)
  • fileNameDescriptor (20-58)
ui/app/src/components/ContentTypeManagement/descriptors/controls/forceHttps.ts (1) (1)
  • forceHttpsDescriptor (20-34)
ui/app/src/components/ContentTypeManagement/descriptors/controls/imagePicker.ts (1) (1)
  • imagePickerDescriptor (20-68)
ui/app/src/components/ContentTypeManagement/descriptors/controls/input.ts (1) (1)
  • inputDescriptor (20-76)
ui/app/src/components/ContentTypeManagement/descriptors/controls/label.ts (1) (1)
  • labelDescriptor (20-34)
ui/app/src/components/ContentTypeManagement/descriptors/controls/linkedDropdown.ts (1) (1)
  • linkedDropdownDescriptor (20-51)
ui/app/src/components/ContentTypeManagement/descriptors/controls/localeSelector.ts (1) (1)
  • localeSelectorDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/nodeSelector.ts (1) (1)
  • nodeSelectorDescriptor (20-58)
ui/app/src/components/ContentTypeManagement/descriptors/controls/numericInput.ts (1) (1)
  • numericInputDescriptor (20-58)
ui/app/src/components/ContentTypeManagement/descriptors/controls/pageNavOrder.ts (1) (1)
  • pageNavOrderDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/repeat.ts (1) (1)
  • repeatDescriptor (20-58)
ui/app/src/components/ContentTypeManagement/descriptors/controls/rte.ts (1) (1)
  • rteDescriptor (20-65)
ui/app/src/components/ContentTypeManagement/descriptors/controls/textarea.ts (1) (1)
  • textareaDescriptor (20-72)
ui/app/src/components/ContentTypeManagement/descriptors/controls/time.ts (1) (1)
  • timeDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/transcodedVideoPicker.ts (1) (1)
  • transcodedVideoPickerDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/uuid.ts (1) (1)
  • uuidDescriptor (20-44)
ui/app/src/components/ContentTypeManagement/descriptors/controls/videoPicker.ts (1) (1)
  • videoPickerDescriptor (4-28)
ui/app/src/components/ContentTypeManagement/descriptors/controls/colorPicker.ts (1) (1)
  • colorPickerDescriptor (19-32)
ui/app/src/components/NewContentDialog/NewContentDialog.tsx (1)
ui/app/src/components/NewContentDialog/utils.ts (1) (1)
  • NewContentDialogProps (28-30)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (7)
ui/app/src/models/ContentType.ts (4) (4)
  • PossibleContentTypeDraft (183-185)
  • DataSource (146-152)
  • ContentTypeSection (197-206)
  • ContentType (156-181)
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (2) (2)
  • FieldChipProps (40-50)
  • FieldChip (52-149)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsVIewHeader.tsx (2) (2)
  • TypeDetailsHeaderProps (31-34)
  • TypeDetailsVIewHeader (36-100)
ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (2) (2)
  • StableFormContextProps (107-115)
  • StableFormContext (125-125)
ui/app/src/components/ContentTypeManagement/utils.ts (3) (3)
  • createStableFormContextProps (354-389)
  • createVirtualSection (274-284)
  • createVirtualDataSourceFields (286-298)
ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (1) (1)
  • defaultDataSourcesSection (98-102)
ui/app/src/components/FormsEngine/components/SectionAccordion.tsx (1) (1)
  • SectionAccordion (42-85)
ui/app/src/components/ViewToolbar/ViewToolbar.tsx (2)
ui/app/src/utils/object.ts (1) (1)
  • ref (169-171)
ui/app/src/utils/system.ts (1) (1)
  • consolidateSx (99-101)
ui/app/src/components/FormsEngine/components/SectionAccordion.tsx (4)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentTypeSection (197-206)
ui/app/src/hooks/useIsDarkModeTheme.tsx (1) (1)
  • isDarkModeTheme (24-26)
ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (1) (1)
  • StableFormContext (125-125)
ui/app/src/utils/system.ts (1) (1)
  • consolidateSx (99-101)
ui/app/src/components/FormsEngine/controls/ColorPicker.tsx (1)
ui/app/src/utils/color.ts (2) (2)
  • ColourFormat (19-19)
  • toTargetFormat (21-36)
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (4)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentTypeField (62-140)
ui/app/src/hooks/useIsDarkModeTheme.tsx (1) (1)
  • useIsDarkModeTheme (20-22)
ui/app/src/utils/string.ts (1) (1)
  • capitalize (34-36)
ui/app/src/components/ContentTypeManagement/components/TypeBuilderAddButton.tsx (1) (1)
  • TypeBuilderAddButton (30-30)
ui/app/src/utils/contentType.ts (3)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (1) (1)
  • ObjectTypeOption (25-25)
ui/app/src/utils/string.ts (2) (2)
  • isEmpty (283-286)
  • ensureSingleSlash (179-181)
ui/app/src/components/GlobalDialogManager/DialogStackItemContainer.tsx (1)
ui/app/src/utils/ui.tsx (1) (1)
  • displayWithPendingChangesConfirm (25-47)
ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (5)
ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (1) (1)
  • ObjectTypeOption (25-25)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
ui/app/src/components/ContentTypeManagement/components/TypeListControlBar.tsx (2) (2)
  • TypeListControlBarProps (30-44)
  • TypeListControlBar (48-107)
ui/app/src/components/ContentTypeManagement/components/TypeList.tsx (2) (2)
  • TypeListProps (25-31)
  • TypeList (33-70)
ui/app/src/utils/contentType.ts (1) (1)
  • filterTypesByKeywordsAndObjectType (187-200)
ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (1)
ui/app/src/utils/system.ts (1) (1)
  • createUseContextHook (132-145)
ui/app/src/components/FormsEngine/lib/valueSerializers.ts (1)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentType (156-181)
🪛 Biome (1.9.4)
ui/app/src/components/ContentTypeManagement/components/TypeCard.tsx

[error] 87-87: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

ui/app/src/components/ContentTypeManagement/components/CreateTypeDialog.tsx

[error] 139-139: A character class cannot match a character and a combining character.

A character and a combining character forms a new character. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

ui/app/src/components/ContentTypeManagement/components/TypeBuilderFormsEngine.tsx

[error] 169-169: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

ui/app/src/components/ContentTypeManagement/components/EditTypeView.tsx

[error] 393-393: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Travis CI - Pull Request
🔇 Additional comments (221)
ui/app/src/components/ContentTypeManagement/descriptors/controls/disabled.ts (2)

1-15: License Header Verification:
The license header is well formatted and provides the complete GPL information as expected.


25-26: Default Export Verification:
The default export of disabledDescriptor is correctly implemented, facilitating its straightforward import in consuming modules.

ui/app/src/components/ContentTypeManagement/components/TypeBuilderAddButton.tsx (4)

1-15: License Header is Comprehensive and Compliant
The GPL license header is present and clear. No issues here.


17-17: Proper Import of Material-UI Button
The import statement correctly pulls in the Button component from Material-UI.


30-30: Explicit Component Export Strategy
Re-exporting Material-UI’s Button as TypeBuilderAddButton is clear and acceptable given the current requirements. In the future, if customization is required, you might consider wrapping it with additional styling or behavior.


32-32: Default Export is Consistent
The default export aligns with the named export, ensuring consistent usage across the project.

ui/app/src/components/FormsEngine/components/TableOfContents.tsx (2)

124-127: Good practice: Using section IDs instead of titles for keys and identifiers

Changing from section.title to section.id for keys and identifiers is a good practice. IDs are typically more stable and unique than titles, which can change or contain characters that might cause issues when used as DOM identifiers.


115-115:

✅ Verification successful

Verify the purpose of fooArray in this context

Changing from an empty array [] to fooArray for the selectedItems prop may alter component behavior. Ensure this is intentional and that fooArray is properly defined for this use case.


🏁 Script executed:

#!/bin/bash
# Search for the definition of fooArray to understand its purpose
rg "export const fooArray" --type ts

Length of output: 92


Subject: Confirmed Usage of fooArray for selectedItems

After verification, we've confirmed that fooArray is defined in ui/app/src/utils/array.ts as an empty array. This means using fooArray in place of an inline [] does not change the initial value passed to the prop. However, please double-check that sharing the same empty array instance (instead of creating a new one on each render) aligns with the intended component behavior, especially if there's any risk of unintended mutations.

ui/app/src/components/ContentTypeManagement/components/TypeBuilderFormsEngine.tsx (2)

83-89: Avoid potential runtime error for null containerRef
If containerRef.current is still null or undefined at the time of calling scroll(), this may cause a runtime error. Consider adding a safety check:

 useEffect(() => {
-  containerRef.current.scroll({ top: 0, behavior: 'smooth' });
+  containerRef.current?.scroll({ top: 0, behavior: 'smooth' });
 }, [virtualType]);

255-265: Remove or finalize identifyMode if not used
The function identifyMode is flagged with a TODO indicating possible removal. Confirm if it’s used elsewhere or can be safely removed to avoid confusion.

ui/app/src/components/ContentTypeManagement/components/TypeCard.tsx (3)

36-39: Well-defined style constants.

The style constants are clearly defined and follow a good pattern for styling overrides in a React component.


43-63: Good implementation of the TypeCard component structure.

The component has a clean props structure with sensible defaults and proper destructuring.


64-83: Well-designed card structure with flexible layout options.

The card body implementation nicely handles both normal and skeleton states, with good use of the CardHeader component's slot props for styling flexibility.

ui/app/src/hooks/useIsDarkModeTheme.tsx (1)

17-29: Well-structured utility for theme detection!

This hook and utility function are cleanly implemented, providing an easy way to check if the current theme is in dark mode. The separation of concerns between the hook and the standalone utility function provides flexibility for both component and non-component contexts.

ui/app/src/utils/object.ts (1)

282-284: Good use of Object.freeze for immutability

Using Object.freeze ensures these objects cannot be modified at runtime, which is a good practice for constants.

ui/app/src/hooks/useFetchAllowedTypesForPath.tsx (2)

26-30: Consider adding a default return for empty paths.
When path is falsy, this hook does nothing and returns no content types. You may want to clarify whether this is indeed the desired behavior (i.e., returning undefined for contentTypes) or if a fallback is needed for edge cases where path is not provided.

Would you like me to generate a quick test or script to verify that callers handle the undefined state properly?


32-52: Good use of RxJS unsubscribe to prevent memory leaks.
Your subscription is properly disposed of on component unmount, safeguarding against potential memory leaks when path changes rapidly.

ui/app/src/components/SearchBar/SearchBar.tsx (2)

36-59: Improved prop types for icons and input references.
Switching to ElementType for icons and introducing an optional inputRef helps with better typing and external refs integration. Good enhancement for reusability.


106-106: Minor layout adjustments.
By setting minHeight to 40px and adjusting padding, you provide a more compact UI. This is a subtle but welcome improvement for consistent spacing.

Also applies to: 152-153

ui/app/src/components/ContentTypeFilter/ContentTypesFilter.tsx (2)

23-25: Lightweight prop definitions promote reusability.
Adopting SelectProps as the base type, along with ObjectTypeOption, keeps this filter flexible. Ensure you’ve updated all call sites to provide valid value and handler properties.


44-55: Ref forwarding and dynamic localization.
Wrapping the Select in forwardRef provides a clean approach for parent components to access the DOM element, while the direct usage of defineMessages fosters better internationalization.

ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (7)

17-17: Imports look good.

The imports are well organized with createContext from React and createUseContextHook from the utility module.

Also applies to: 27-27


117-117: Pure function annotation for optimization.

Adding the /*#__PURE__*/ comment is a good practice as it helps bundlers like Webpack perform better tree-shaking by indicating this expression has no side effects.


120-121: Pure function annotation for optimization.

Good use of the pure function annotation for the global context creation.


125-125: Pure function annotation for optimization.

Consistent use of the pure function annotation for the form context creation.


128-128: Pure function annotation for optimization.

Good application of pure function annotation to ItemContext creation.


131-131: Pure function annotation for optimization.

Consistent application of pure function annotation to ItemMetaContext creation.


134-148: Hook implementations look good.

All context hooks are consistently implemented using the createUseContextHook utility with pure function annotations, which is a good practice for optimizing bundle size through more effective tree-shaking.

ui/app/package.json (1)

101-101:

❓ Verification inconclusive

New color picker dependency added.

The addition of react-colorful is appropriate for adding color selection capabilities to the UI. This is a lightweight, accessible color picker library that integrates well with React applications.

Ensure that this dependency is used consistently across the codebase where color picking functionality is needed.


🏁 Script executed:

#!/bin/bash
# Check where react-colorful is imported
rg "import.*react-colorful" --type ts --type tsx

Length of output: 78


Below is a revised review comment. It clarifies that the dependency addition is correct, notes that its consistent usage must be verified, and recommends a new verification command using an explicit glob pattern to cover both TypeScript and TSX files.


Action Required: Please verify that the new react-colorful dependency is used consistently across the codebase.

  • File: ui/app/package.json (line 101)
  • Change: Addition of "react-colorful": "^5.6.1", a lightweight, accessible color picker ideal for React.
  • Next Steps: Ensure that all modules requiring color picking integrate react-colorful. The initial verification command failed due to a file type recognition issue. Please re-run the following corrected search command to verify imports:

Once you’ve confirmed consistent usage, kindly update the PR if necessary.


🏁 Script executed:

#!/bin/bash
# Searching for react-colorful import statements in both ts and tsx files using an explicit glob pattern.
rg "import.*react-colorful" --glob "*.{ts,tsx}"

Length of output: 171


Action Required: Please manually verify that the added react-colorful dependency is utilized where color picking functionality is implemented.

  • File: ui/app/package.json (line 101)
  • Change: Addition of "react-colorful": "^5.6.1"
  • Next Steps:
    The automated search using an explicit glob pattern did not yield any results. This may indicate that the dependency is not yet imported in any TypeScript or TSX files (or it is imported in a non-standard way). Please verify manually that:
    • Color picker components are indeed using react-colorful.
    • There isn’t any dynamic or indirect import of react-colorful that might have been missed by the automated search.
ui/app/src/components/ContentTypeManagement/descriptors/controls/colorPicker.ts (1)

17-32: Clean implementation of color picker descriptor

This is a well-structured implementation of a color picker descriptor that follows the established pattern for control descriptors. The use of createVirtualSection for both properties and constraints sections is appropriate and consistent with other control descriptors.

I note this is likely being added to support the new "react-colorful" dependency mentioned in the PR summary.

ui/app/src/utils/ui.tsx (2)

22-24: Good addition of Material-UI type imports

These type imports from Material-UI are appropriate for the new utility function.


49-54: Well-designed utility function for consistent spacing

The getMarginSxProps function is a good abstraction for common spacing patterns. This will help maintain consistent spacing throughout the application and reduce duplication of styling logic across components.

The CSS selectors using :not([hidden]) ~ :not([hidden]) pattern is the correct approach for applying spacing only between visible elements.

ui/app/src/components/FormsEngine/lib/controlHelpers.tsx (1)

71-71: Good defensive programming with optional chaining

This change adds optional chaining to safely access the plugin property, which prevents potential runtime errors if field.properties is undefined or null. This is a good defensive programming practice.

ui/app/src/components/ContentTypeManagement/descriptors/controls/localeSelector.ts (1)

20-44: Structure looks good for the locale selector descriptor

The descriptor is well-structured with clear sections for "Options" and "Constraints", providing a good foundation for the locale selector control within the Type Builder v2 framework.

ui/app/src/components/ContentTypeManagement/descriptors/controls/label.ts (1)

24-33: Well-structured label descriptor

The label descriptor has a clear structure with appropriate fields for the text label control.

ui/app/src/components/ItemDisplay/ItemDisplay.tsx (2)

52-52: Good enhancement to component flexibility

The addition of the component prop and its use in the Box component makes the ItemDisplay more flexible, allowing consumers to specify what HTML element should be rendered. This is a good improvement that follows component composition best practices.

Also applies to: 86-86


73-73: Nice default value for component prop

Setting the default value to 'span' maintains backward compatibility with existing code that relies on the previous hardcoded behavior.

ui/app/src/components/ContentTypeManagement/descriptors/controls/time.ts (1)

46-47: Code structure looks good

The dual export pattern (named and default) provides flexibility for different import styles.

ui/app/src/components/ContentTypeManagement/descriptors/controls/linkInput.ts (1)

20-44: Good use of explicit typing with PartialContentType

The explicit typing of linkInputDescriptor as PartialContentType improves type safety and helps with development tools support.

ui/app/src/components/ContentTypeManagement/descriptors/controls/videoPicker.ts (1)

4-28: Good use of explicit typing with PartialContentType

The explicit typing of videoPickerDescriptor as PartialContentType improves type safety and helps with development tools support.

ui/app/src/components/FormsEngine/lib/formConsts.ts (1)

37-38: XML keys added for enhanced content type functionality.

The addition of disabled and placeInNav to the XmlKeys enum provides necessary support for new content type management features. This aligns well with the Type Builder v2 refactoring effort.

ui/app/src/components/ContentTypeManagement/descriptors/controls/linkedDropdown.ts (1)

20-27: LGTM! Well-structured descriptor with logical section organization.

The linkedDropdown descriptor is clearly organized with appropriate sections for "Options" and "Constraints". This follows the pattern established in other descriptors and provides a consistent user experience.

ui/app/src/components/ContentTypeManagement/descriptors/controls/numericInput.ts (1)

24-27: Well-organized sections with logical field grouping.

The descriptor has a clear separation between "Options" and "Constraints" sections, making the UI more intuitive for users.

ui/app/src/components/ContentTypeManagement/descriptors/controls/input.ts (1)

25-31: Good use of explicit section IDs.

Unlike other descriptors, this one explicitly defines section IDs (properties and constraints), which is good for referencing specific sections. Consider applying this pattern to other descriptors for consistency.

ui/app/src/components/ContentTypeManagement/descriptors/controls/dateTime.ts (1)

1-78: Well-structured content type descriptor for date-time control.

This file creates a well-organized descriptor for the date and time picker component. The structure follows a clean pattern with sections for "Options" and "Constraints" that organize the fields logically. The fields properly define all necessary properties, making this descriptor ready for integration with the Type Builder framework.

One minor note: Consider whether the foo validation object (imported from utils/object.ts) could be renamed to something more descriptive of its purpose, especially as this pattern is being repeated across multiple descriptors.

ui/app/src/components/ContentTypeManagement/descriptors/controls/nodeSelector.ts (1)

1-61: Well-structured content type descriptor for node selector.

The node selector descriptor is well-defined with appropriate sections and fields. The use of createVirtualSection keeps the code DRY and consistent with other descriptors. The type annotation ensures type safety within the Type Builder framework.

ui/app/src/components/ContentTypeManagement/descriptors/controls/pageNavOrder.ts (1)

1-47: Well-structured content type descriptor for page navigation ordering.

This descriptor follows the same pattern as the others, maintaining consistency across the control descriptors. The "Options" and "Constraints" sections are appropriately organized, and all fields have the necessary properties.

ui/app/src/components/ContentTypeManagement/descriptors/controls/internalName.ts (1)

21-21:

❓ Verification inconclusive

Address the TODO comment.

There's a TODO questioning why internal name is a control type. This should be resolved before finalizing the code to ensure all included components are necessary.


🏁 Script executed:

#!/bin/bash
# Description: Search for usage of internalName as a control type

# Look for references to internalName in the codebase
echo "Searching for references to XmlKeys.internalName or internal-name-control..."
rg -i "internalName|internal-name" --type ts --type tsx

Length of output: 248


Below is an updated review comment based on the verification attempt. It highlights that an improved search is now needed—specifically using file globbing—to conclusively determine if the control type is used. Please run the updated search command manually and verify the findings before proceeding with removal or any further refactoring.


Action Required: Verify and Resolve Unused Internal Name Control

There is a TODO in ui/app/src/components/ContentTypeManagement/descriptors/controls/internalName.ts (line 21) questioning why “internal name” is treated as a control type. The initial verification command encountered a file type error with .tsx files, so its output wasn’t conclusive.

  • Next Steps:
    • Manually re-run a revised search using the updated command:
      rg -i 'internalName|internal-name' -g '*.ts' -g '*.tsx'
    • Confirm whether the internal name control is ever referenced in the codebase.
    • If no usage is found, remove or refactor as appropriate. If it’s actually needed, remove the TODO comment and add documentation explaining its purpose.
ui/app/src/utils/itemActions.ts (2)

608-608: Type assertion change improves flexibility.

Changing from NewContentDialogProps to Partial<NewContentDialogProps> allows for more flexibility in what props can be passed to the component, which is beneficial for this refactoring effort.


597-607:

❓ Verification inconclusive

API refactoring improves clarity but verify compatibility.

The refactoring of parameters passed to pickShowContentFormAction improves clarity by using explicit parameters (contentTypeId, isNewContent) rather than relying on rootPath. This aligns well with the Type Builder v2 changes mentioned in PR objectives.

Verify that all callers to this function are updated to handle the new parameter structure:


🏁 Script executed:

#!/bin/bash
# Description: Find all usages of pickShowContentFormAction to verify they're updated
echo "Searching for other uses of pickShowContentFormAction that might need updating..."
rg "pickShowContentFormAction" --type ts --type tsx -A 5 -B 5

Length of output: 262


Action: Verify that all callers of pickShowContentFormAction are updated properly

The initial search command returned an error due to the unrecognized file type "tsx." To address this, please re-run the search using an updated script with glob patterns to include both .ts and .tsx files. For example:

#!/bin/bash
echo "Searching for all usages of pickShowContentFormAction in TypeScript files..."
echo "Searching in .ts files:"
rg "pickShowContentFormAction" -g "*.ts" -A 5 -B 5
echo "Searching in .tsx files:"
rg "pickShowContentFormAction" -g "*.tsx" -A 5 -B 5

Once executed, verify that every caller of pickShowContentFormAction is adjusted to handle the new parameter structure (using explicit parameters like contentTypeId and isNewContent) as per the API refactoring and Type Builder v2 changes.

ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (2)

18-18:

❓ Verification inconclusive

Review the placeholder validation object.

The code imports foo from utils/object.ts which is just an empty frozen object. This appears to be a placeholder.


🏁 Script executed:

#!/bin/bash
# Check if other files are using similar pattern or if this might be intended to be replaced
rg --type ts "validations: foo" -A 1 -B 1

Length of output: 35983


Placeholder Validation Consistency

The import of foo from '../../../../utils/object' in ui/app/src/components/ContentTypeManagement/descriptors/controls/checkboxGroup.ts (line 18) is used as the validation object. Our search shows that this pattern (i.e., using a frozen, empty object as a stand-in for validations) is widespread across many descriptor controls.

  • Confirm whether the use of foo as a placeholder is intentional.
  • If a proper validation mechanism should be implemented later, please add a TODO or inline comment to indicate its temporary nature and plan for updating it.

24-26: ⚠️ Potential issue

Missing implementation for tokenize field.

The section Options includes tokenize in its fields array, but there's no corresponding field implementation in the fields object.

You should either:

  1. Remove 'tokenize' from the fields array in the Options section, or
  2. Add the tokenize field implementation to the fields object:
- createVirtualSection({ title: 'Options', fields: ['options', 'readonly'] }),
+ createVirtualSection({ title: 'Options', fields: ['options', 'readonly'] }),

Likely an incorrect or invalid review comment.

ui/app/src/components/FormsEngine/components/FormBackToTop.tsx (1)

24-39: Well-implemented component with good structure.

The FormBackToTop component is well-structured with clear props interface and proper implementation. It uses Material-UI components effectively and provides smooth scrolling functionality.

ui/app/src/utils/string.ts (2)

283-286: Well implemented string validation utility.

This function properly checks if a string is null or contains only whitespace, which is a common validation need throughout the application. The implementation correctly handles the null case first and then uses trim() to check for empty strings.


288-290: Good addition of type-safe boolean to string conversion.

The function correctly converts boolean values to their string representation with appropriate TypeScript return type union ('true' | 'false'). This will help prevent type errors when string representations of booleans are needed.

ui/app/src/state/reducers/dialogs/changeContentType.ts (1)

25-32: State simplification looks good.

The removal of compact, rootPath, and selectedContentType properties in favor of a single initialCompact property simplifies the state model. This aligns with the broader refactoring efforts mentioned in the PR objectives to enhance reusability within the Type Builder 2 framework.

ui/app/src/components/ContentTypeManagement/components/MainSection.tsx (1)

22-51: Well-implemented responsive layout component.

The Main component is well designed with:

  • Proper TypeScript interface for props
  • Correct implementation of shouldForwardProp to filter non-DOM props
  • Clean transition effects that change based on the drawer state
  • Proper theme integration following Material-UI conventions

This will provide a smooth user experience when interacting with the drawer interface.

ui/app/src/components/LegacyComponentsPanel/utils.ts (1)

24-24: Good refactoring for path generation.

Replacing the hardcoded path with createFormDefinitionPathFromTypeId centralizes the logic for content type path construction. This improves maintainability by ensuring path formats are consistent across the application and only need to be updated in one place if the format changes.

Also applies to: 132-132

ui/app/src/components/FormsEngine/lib/useSaveForm.tsx (1)

166-166: Export changed from named to default.

The function is now exported as a default export rather than a named export, which changes how it must be imported in other files.

This change simplifies imports in other modules and aligns with common React patterns. I verified that the import was also updated in FormsEngine.tsx accordingly.

ui/app/src/state/reducers/dialogs/newContent.ts (1)

26-27: Props structure simplified.

The initial state has been refactored to use initialCompact instead of compact, and rootPath has been removed entirely.

This change aligns with the broader refactoring across dialog components and simplifies the state structure by removing unnecessary properties.

ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialog.tsx (3)

24-24: Props destructuring updated.

The destructuring pattern has been updated to use initialCompact instead of compact, rootPath, and selectedContentType.

This simplification aligns with the changes made to the initial state in newContent.ts and creates a more consistent API across the application.


27-31: Dialog appearance updated.

The dialog has been enhanced with a maxWidth property and updated title and subtitle text that better describes its purpose.

The new text clarifies that this dialog is specifically for changing an existing content type rather than choosing a new one, providing better context to users.


36-36: Prop name updated for container component.

The prop passed to ChangeContentTypeDialogContainer has been updated from compact to initialCompact.

This change ensures consistency with the updated props structure and maintains proper data flow between components.

ui/app/src/components/FormsEngine/FormsEngine.tsx (2)

113-113: Import updated to use default import.

The import of useSaveForm has been changed from a named import to a default import.

This change corresponds to the updated export in useSaveForm.tsx, maintaining consistency across the codebase.


833-833: Back-to-top functionality refactored into a dedicated component.

The inline implementation using Box, Tooltip, and Fab has been replaced with the more concise FormBackToTop component.

This refactoring improves code maintainability by extracting reusable UI functionality into a dedicated component. The FormBackToTop component maintains the same functionality while simplifying the JSX structure.

ui/app/src/components/FormsEngine/lib/valueRetrievers.ts (3)

33-34: Good addition of textOrNullExtractor for better null handling

This function properly returns null when the value is falsy instead of an empty string, providing better type safety for components that need to distinguish between empty strings and null values.


35-36: Improved type handling for numeric inputs

The addition of numberFieldExtractor is a good improvement that ensures numeric values are properly typed as numbers rather than strings, and correctly handles null values.


60-61: Good replacement of text extractor with number extractor for numeric inputs

Replacing textFieldExtractor with numberFieldExtractor for 'numeric-input' makes more sense semantically and improves type safety. The addition of colorPicker with textOrNullExtractor suggests integration with the newly added 'react-colorful' dependency mentioned in the PR.

Also applies to: 67-69

ui/app/src/components/NewContentDialog/NewContentDialog.tsx (2)

24-25: Good simplification of props

Replacing rootPath and compact with initialCompact simplifies the component's API. This change aligns with the PR objective of refactoring to improve reusability.

Also applies to: 41-42


26-36: Improved dialog structure

Moving the title into dialogHeaderProps and adding the maxWidth="lg" property makes the dialog more consistent with the new development standards mentioned in the PR objectives.

ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (1)

55-59: Good implementation of search filtering

The filtering logic properly handles case-insensitive searches across both the name and description fields, providing a user-friendly search experience.

ui/app/src/components/FormsEngine/components/FormLayout.tsx (3)

38-39: Good addition of utility hook and function imports.

The import of getMarginSxProps and useResizeObserver will help simplify the component code by abstracting reusable functionality.


127-135: Cleaner implementation with the useResizeObserver hook.

The resize observer implementation has been refactored to use a custom hook, which significantly improves the code by:

  1. Eliminating manual subscription management
  2. Reducing boilerplate code
  3. Improving cleanup handling

This change follows the React hooks pattern and makes the component more maintainable.


149-149: Good use of utility function for styling.

Replacing inline styling with the getMarginSxProps() utility function improves code maintainability and consistency across the application.

ui/app/src/components/NewContentDialog/utils.ts (3)

17-17: Appropriate update to ContentType import.

Importing the standard ContentType interface aligns with the modernization efforts mentioned in the PR description.


25-25: Improved property naming with initialCompact.

Changing from compact to initialCompact better indicates this is an initial state value that the component can internally manage, following React's controlled component pattern.


29-29: Simplified callback signature.

The onContentTypeSelected signature has been greatly simplified to include only the essential information (path and contentType), reducing coupling between components and making the interface more maintainable.

ui/app/src/components/ContentTypeManagement/components/SelectTypeView.tsx (2)

28-38: Well-structured component interface.

The SelectContentTypeProps interface is clearly defined with:

  • Optional styling
  • Configurable initial states
  • Required content type list
  • Flexible slot props for customization

This provides a good balance between required functionality and customization options.


63-74: Good use of slot props pattern for component customization.

The component uses the slot props pattern effectively, allowing for customization of inner components while maintaining control over their props. This is particularly valuable for a reusable component like this one.

ui/app/src/utils/system.ts (2)

109-110: Enhanced dialog configuration options.

Adding allowFullScreen and allowMinimize properties improves the user experience by providing more control over dialog behavior.


126-145: Excellent utility for context hook creation.

The createUseContextHook utility function:

  1. Provides type-safe context consumption
  2. Offers better error messages when contexts are accessed outside their providers
  3. Allows for property selection through an optional selector function
  4. Creates a consistent pattern for context hooks across the application

This is a well-designed utility that will improve code quality and developer experience.

ui/app/src/components/ContentTypeManagement/components/TypeListingView.tsx (2)

41-49: TODO comment needs to be addressed

There's a TODO comment on line 45 about adding config-based archetypes. Make sure to track this as a future enhancement.

Also, the undefined default value on line 46 could be made more explicit by using a proper defaulting mechanism rather than passing undefined directly.


65-92: LGTM! The component layout and structure are well-organized

The component renders a well-structured UI with proper conditional rendering and prop passing. The organization of the toolbar, content area, and dialog is clean and follows best practices.

ui/app/src/components/ChangeContentTypeDialog/utils.ts (3)

21-21: LGTM! Good improvement in maintaining consistent imports

Adding the import for NewContentDialogProps allows for better type consistency across related dialog components.


23-26: Improved property management with initialCompact

The removal of multiple properties (rootPath, compact, selectedContentType) in favor of a single initialCompact property simplifies the interface and makes it more maintainable.


28-30: Enhanced type safety for callback function

Using NewContentDialogProps['onContentTypeSelected'] for typing the onContentTypeSelected property ensures consistency across dialog components and provides better type safety than the previous any type.

ui/app/src/components/FormsEngine/lib/valueSerializers.ts (2)

135-147: Good refactoring of XML builder creation logic

Extracting the XML builder creation into a separate function improves code modularity and reusability. The TODO comment about moving this to a utils file is appropriate, as this is a utility function that could be used elsewhere.

However, ensure you create a follow-up task to move this function to the utils file as suggested in the TODO comment.


149-157: Function refactoring improves code readability

The updated buildContentXml function now uses the extracted getXmlBuilder function, which improves readability and maintainability. This is a good example of the Single Responsibility Principle.

Follow up on the TODO comment to move this function to content.ts as part of ongoing refactoring efforts.

ui/app/src/components/ContentTypeManagement/components/Layout.tsx (3)

40-66: Well-structured component with good use of React patterns.

The component makes effective use of forwardRef and useImperativeHandle to expose the container reference to parent components. The resize observer implementation provides responsive behavior based on container dimensions.


50-63: Good implementation of responsive layout logic.

The resize observer logic handles viewport resizing well, dynamically adjusting the drawer visibility and width based on available space. The CSS variable approach for dimensions is a clean solution for reactive layouts.


88-137: Clean conditional rendering between Drawer and Dialog.

The component intelligently switches between Drawer and Dialog components based on available screen space, providing a good user experience across different viewport sizes.

ui/app/src/components/ContentTypeManagement/components/TypeListControlBar.tsx (1)

88-91: Improve type safety of ContentTypesFilter props.

The TypeScript cast (slotProps?.contentTypesFilter as Omit<SelectProps, 'variant' | 'ref'>) might be risky. Consider using a more type-safe approach or add runtime validation.

Consider using a TypeScript utility type or adding a runtime check to ensure the props match the expected shape.

ui/app/src/components/GlobalDialogManager/DialogStackItemContainer.tsx (1)

20-121: Well-structured refactoring improves maintainability

The refactoring changes in this file significantly improve code organization by separating concerns into distinct functions:

  1. The main DialogStackItemContainer component is now simplified
  2. pickDialogComponent handles component selection logic
  3. createUnknownComponent handles unknown component rendering
  4. useCreateCallbackProps encapsulates callback creation and state management

This separation of concerns makes the code more maintainable and testable.

ui/app/src/utils/contentType.ts (3)

187-200: Good addition for content type filtering

The filterTypesByKeywordsAndObjectType function provides a clean implementation for filtering content types based on keywords and object types. It includes proper null checks and early returns for edge cases.


202-205: Workaround for API inconsistency with proper documentation

The function correctly handles the folder path normalization required by the API, and the TODO reference to the GitHub issue provides context for why this workaround is necessary.


207-209: Clean path construction with proper handling

The createFormDefinitionPathFromTypeId function uses ensureSingleSlash to properly handle path construction, preventing potential issues with duplicate slashes in paths.

ui/app/src/components/FormsEngine/lib/controlMap.ts (2)

23-51: Improved organization of control types with clear TODOs

The control types have been reordered and labeled with helpful TODO comments indicating which ones:

  • Are planned for removal
  • Are not in use
  • Are not part of business processes

This kind of documentation helps future developers understand the codebase status.


53-83:

✅ Verification successful

New and restored control types improve feature set

The changes restore the checkbox-group control, add support for repeat control, and introduce a new colorPicker control. These additions enhance the forms engine capabilities.

Make sure the new ColorPicker component is properly implemented and tested, as it's a newly added feature.


🏁 Script executed:

#!/bin/bash
# Check if the ColorPicker component exists and is properly implemented
fd "ColorPicker.tsx" --type f --exec cat {} \;

Length of output: 5102


Controls Enhancement Verified

• The restored checkbox-group and newly added repeat controls are properly mapped in the control map.
• The new colorPicker control correctly lazy-loads the ColorPicker component, which has been verified to exist and is fully implemented in the repository.

Please ensure that comprehensive tests are in place to validate the behavior of the new ColorPicker feature.

ui/app/src/components/ChangeContentTypeDialog/ChangeContentTypeDialogContainer.tsx (2)

18-29: No issues with newly introduced imports.

These imports (React, SelectTypeView, path utilities, etc.) appear to be well-structured and meet the component’s requirements. Everything seems consistent; no redundant imports identified.


38-41: Confirm that item.systemType is valid.

When filtering the list of types, you rely on type.type === item.systemType. If item.systemType can be invalid or empty, some content types may inadvertently be excluded. You may wish to verify the correctness of item.systemType or fall back to a default value to avoid missing content types.

ui/app/src/components/FormsEngine/lib/formUtils.tsx (3)

88-88: Ensure unique section.id values.

Switching from indexing by section.title to section.id in the expanded-state atoms is more robust—titles can change, whereas IDs ideally remain stable. Just confirm that each section.id is guaranteed to be unique to avoid accidental collisions in the generated atom map.


251-257: Helpful improvement in alert usage.

The useShowAlert hook’s ability to accept either a string or object minus dispatch nicely streamlines alert invocation. It makes the API friendlier since callers no longer need direct access to dispatch. This approach looks clean and safe for typical usage scenarios.


442-447: Check for consistency with boolean-based keys.

The newly added disabled and placeInNav boolean fields are consistent with the preceding properties that store booleans. Just ensure that downstream consumers expect boolean types instead of string equivalents (e.g., 'false', 'true'). Everything else looks good.

ui/app/src/components/ViewToolbar/ViewToolbar.tsx (5)

18-19: Clean import consolidation.

Importing ToolbarProps and consolidateSx fosters clarity. This makes it more explicit which Material-UI props are extended and helps unify styling logic with consolidateSx.

Also applies to: 23-23


27-27: Enhanced flexibility with slotProps.

Exposing slotProps gives callers more granular control of the underlying Toolbar. This pattern improves extensibility without bloating the main component’s props.

Also applies to: 31-32


34-35: Smooth transition to forwardRef.

Using forwardRef on ViewToolbar is a solid refinement. It allows parent components to capture a reference to the underlying DOM element. This is especially helpful in advanced layouts or scroll handling.

Also applies to: 38-38


51-51: Seamlessly merging styles with consolidateSx.

Spreading in slotProps?.toolbar and merging styles via consolidateSx effectively extends the default Toolbar without losing existing styles. This approach is succinct and consistent with MUI best practices.

Also applies to: 53-66


73-73: Ref and memo synergy.

Wrapping the ViewToolbar in React.memo and re-exporting it as Memo is a clean way to optimize re-renders. This pattern remains flexible while preventing needless re-renders when props don’t change.

Also applies to: 75-75, 77-77

ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (1)

61-75: Consider null/undefined checks for the type prop.

The TypeDetailsView component relies on type and its nested properties (type.sections, type.dataSources, etc.) without an explicit check for null or undefined. If type is not guaranteed to be defined at all times, you may want to add robust null/undefined checks to avoid potential runtime errors.

ui/app/src/components/ContentTypeManagement/ContentTypeManagement.tsx (2)

84-110: Confirm the correctness of the alert severity messages.

The alert switches between 'warning' and 'info' based on the useLegacy flag. Double-check that the user flow is correct: it may be helpful to provide consistent messaging or styling to communicate the difference between the new tool and legacy tool more distinctly.


139-181: Ensure stable unsubscribing from the event stream.

The messagesSubscription.unsubscribe() call in the cleanup function is correct, but confirm that no other subscriptions are left open, especially if you expect multiple messages or expansions of this system in the future. This helps avoid memory leaks and keeps your code scalable.

ui/app/src/components/FormsEngine/components/SectionAccordion.tsx (15)

18-18: Import looks good.
No issues identified with this new import statement.


20-20: Import looks good.
No issues identified with this new import.


21-21: Import looks good.
No issues identified with this new type import.


28-28: Library import check.
Using consolidateSx to merge style props is an effective approach for MUI style consolidation.


29-29: Dark mode detection check.
The isDarkModeTheme hook integrates well with MUI theme logic. No issues found.


31-33: Interface extension.
The addition of children and colorize flags to SectionAccordionProps is clear and consistent.


36-39: Optional slot props.
Allowing partial overrides for summary and details is a good approach to enhance extensibility.


42-49: Function signature update.
Destructuring multiple custom props while extending AccordionProps is aligned with MUI patterns and keeps the component flexible.


51-52: Dark mode usage.
No concerns regarding the logic for retrieving the dark mode value and expanded state from context.


55-56: Elevation props usage.
Conditionally applying elevation based on dark mode is a sensible UI approach.


59-72: Dynamic styling with consolidateSx.
Conditionally applying border styles for colorized sections is appropriate. Ensure that design guidelines permit a 5px left border for highlight.


74-74: AccordionSummary props extension.
Passing down slotProps?.accordionSummary is well aligned with MUI’s new slotProps approach.


76-76: Slot-prop children usage.
Child elements in the summary are appended correctly, providing flexibility for customizing the summary content.


78-81: AccordionDetails usage.
Rendering fields and optional extra children within details is clear. This structure cleanly supports dynamic content.


82-82: Children after AccordionDetails.
Placing children after AccordionDetails can be intentional for custom layouts. No issues found.

ui/app/src/CHANGELOG.md (6)

32-32: Changelog entry for dialog prop changes.
Accurately documents the removal of rootPath, compact, and selectedContentType from ChangeContentTypeDialog plus addition of initialCompact. Good clarity.


33-33: ContentTypesFilter changes.
Notes that it’s “completely redone” to align with @mui/material/SelectProps. Adequate documentation for a breaking change.


34-34: Removal of NewContentCard.
Straightforward, no concerns.


35-35: Removal of ContentTypesGrid.
Change is clearly documented. No issues.


36-36: Removal of ContentTypesLoader.
Clear comment on removal. No concerns.


37-38: NewContentDialog changes.
Reflects removed props and introduces initialCompact, with revised signature for onContentTypeSelected. Documented thoroughly.

ui/app/src/utils/color.ts (8)

1-15: License header and file creation.
No issues with the license text or basic file setup.


17-17: MUI system imports.
Loading decomposeColor, hslToRgb, recomposeColor, and rgbToHex from @mui/system is correct for color transformations.


19-19: ColourFormat type.
Defining 'rgb' | 'hsl' | 'hex' is a straightforward and well-scoped union.


21-36: toTargetFormat function.
Routing color format conversions through the specialized helpers is clean. The fallback logic with switch-case is well structured.


38-51: anyColorToHex function.
Decomposes color, optionally strips alpha channels, and uses rgbToHex. Implementation is clear.


53-64: anyColorToRgb function.
Methodically handles whether alpha is included. Potentially robust for different color inputs.


66-90: anyColorToHsl function.
Nicely re-maps color to HSL format. The approach to remove alpha if allowAlpha is false is consistent with the others.


92-120: rgbValuesToHslValues function.
Computes HSL from RGB with a standard formula. Rounding results to integers is typical for display usage.

ui/app/src/components/NewContentDialog/NewContentDialogContainer.tsx (9)

18-20: Internationalization and React.
Pulling in FormattedMessage and React in separate lines is fine. No issues.


23-23: TypeListProps import.
Needed for referencing the onCardClick type. Straightforward.


25-25: SelectTypeView import.
No conflicts with naming, adheres to new structure.


27-29: Components & hook import.
ItemDisplay, Box, and useFetchAllowedTypesForPath are properly used. No concerns.


32-32: Receiving initialCompact.
Respects the newly added property. Proper destructuring with fallback is good.


34-36: handleContentTypeSelected callback.
Correctly calls onContentTypeSelected with the simplified object containing path and contentType.


38-38: TypeList onCardClick binding.
Maps card clicks to the same handleContentTypeSelected. Straightforward.


40-40: useFetchAllowedTypesForPath usage.
Leverages normalized path. Good practice for consistent folder path retrieval.


43-65: Dialog structure.
Utilizes SelectTypeView with skeleton states and left children showing the target item. The approach is user-friendly and minimal.

ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (2)

1-15: Header & Licensing Check
The GPL license header is correctly placed. No issues found with licensing references.


148-178: Control descriptors registry review
The centralized controlDescriptors record is well-structured and supports multiple built-in control definitions. This approach promotes modularity and improves maintainability. No concerns identified.

ui/app/src/models/ContentType.ts (9)

18-18: New import reference
Importing XmlKeys to handle references in forms. This is coherent with the forms engine integration. Looks good.


159-160: Added description property
Attaching a required description string to the ContentType is clear. Confirm if empty or optional description is disallowed.

Do we ever store or display an empty string when no user description is provided? If so, consider making this field optional.


164-164: New mergeStrategy property
This property extends type configurability. Looks consistent with the PR objective to enhance content type metadata.


183-185: PossibleContentTypeDraft interface
Allowing a NEW flag is useful for distinguishing unsaved types from the existing ones. Implementation looks solid and helps manage creation flows.


187-195: ContentTypeBasicDetails interface
Storing basic content type attributes (controller, imageThumbnail, no-template-required, paths) in one interface is convenient. Good job.


198-206: ContentTypeSection additions
Adding id and color for sections is a user-friendly approach for theming or dark-mode styling. No issues.


250-252: Sections with IDs
The comment clarifies that sections in legacy definitions now require IDs. This helps keep track of them in the new builder.


262-303: SerializeToXmlContentTypeStructure interface
Defines how the content type is serialized to XML. The additions such as description, merge-strategy, and paths match the new content type properties in the system.


335-335: Clarification on form
The comment clarifying (legacyType.form === legacyType.name) is helpful. The code is consistent with legacy references.

ui/app/src/components/ContentTypeManagement/components/EditTypeView.tsx (13)

1-16: File-level overview
A new React component file for editing content types. The licensing header is provided, with no issues.


69-78: Props for EditTypeAppProps
Well-defined interface that includes a user-provided type and callbacks. Clear structure to customize behaviors like onClose.


94-108: EditAppContextProps interface
Tracks form updates, form context, and the selected artefact. This is a neat approach ensuring each form has consistent event streams.


109-401: Core EditTypeView implementation
Overall logic is well-organized, covering the approach of opening/closing forms, merging updates, saving to the server, and using the forms engine. No immediate correctness/security issues, except for the highlight usage below.

🧰 Tools
🪛 Biome (1.9.4)

[error] 393-393: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


403-413: createContextObject()
Initializes app context for field updates and selected artefacts. Straightforward with no concerns.


415-419: getIdFromIdPath
Simple utility that extracts the last portion of a dot-separated path. This is concise and effective.


420-430: insertSection
Inserts a new section at a specified index. The logic is straightforward, no issues found.


426-431: addField
Merges the new field into fields while leaving sections unchanged. Implementation is correct for the current approach.


432-434: updateTypeProps()
Merges partial updated type details into the existing type. Relies on pluckProps to ensure only valid properties get updated. No concerns.


436-465: updateTypeFromFieldUpdate()
Merges updated field values back into the type, handles an ID change by updating the sections array as well. This ensures references remain consistent.


479-489: updateTypeFromDataSourceUpdate()
Generates a shallow copy of dataSources and updates the target. Implementation is consistent with the approach used for fields and sections.


491-503: save()
Serializes the content type to XML, with an option to do a real server write. This modular approach is easy to maintain. Good job.


505-508: validityAtomsHaveErrors()
Checks for any form field validations that are invalid. Clear logic, no concerns.

ui/app/src/services/contentTypes.ts (23)

23-24: Imports look good.
These newly added imports, ContentTypeSection and DataSource, are properly referenced in the file.


33-33: New utility imports.
The added import camelize, capitalize, isBlank, toColor from ../utils/string is consistent with the usage below.


343-343: Local variable usage.
Defining propertyProp simplifies multiple references to legacyField.properties?.property.


345-369: Repeat field validations.
The logic to set min/max counts and mark the field as required if min > 0 is clear and correct.


373-374: Spread usage for validations.
Merging validations with getFieldValidations(propertyProp, dropTargetsLookup) keeps the node-selector case concise.


387-388: Combining validations.
Spreading both generic validations and data-source-specific validations is a neat approach for input/textarea fields.


395-395: Video-picker/rte validations.
Again spreading data-source-specific validations keeps the logic consistent for these field types.


409-410: New arrays and lookups.
sections and dataSources are now strongly typed. This improves clarity and maintainability.


413-414: Conversion to array.
Converting definition.datasources?.datasource to an array ensures uniform iteration.


416-418: Building the local dataSources lookup.
Copying fields from the legacy data source while reinitializing properties is logical for further customization.


420-434: Defaulting invalid numeric properties to 0.
When value is NaN, it's set to 0. Confirm whether 0 is the appropriate fallback or if an error should be raised.


441-442: Iterating over sections.
The approach of enumerating definition.sections?.section into legacySection, index is clear and consistent.


444-449: Passing data sources to field parser.
Adding legacyDataSourceArray to parseLegacyFormDefinitionFields effectively centralizes relevant data for validation.


452-454: Section IDs and titles.
Auto-generating section-${index} as the ID and using fallback color via toColor is a neat pattern.


461-464: Creating the top-level property map.
Using createLookupTable on definition.properties?.property makes property retrieval more efficient.


469-470: Boolean conversion of quickCreate.
.trim() === 'true' properly normalizes the input to a boolean.


473-479: New fields for TypeBuilder 2.
Adding displayTemplate, mergeStrategy, hasJsController, thumbnailFileName, isHeadless, and paths extends the type definition.


487-497: Parsing includes/excludes path arrays.
Returns null if the structure is missing, or an object with paths.includes and paths.excludes. Straightforward approach.


499-507: Stubbed fields for legacy content type.
The fields (hasJsController, isHeadless, paths, thumbnailFileName, etc.) are set to null if not in the legacy data.


520-520: Form definition path creation.
createFormDefinitionPathFromTypeId usage is consistent with the rest of the calls in this file.


565-569: Generic usage response interface.
The FetchContentTypeUsageResponse<T> interface is flexible through type parameterization.


571-585: Extended usage fetch.
fetchContentTypeUsage() now returns Observable<FetchContentTypeUsageResponse<ContentItem>>. Correctly merges usage data with content items.


610-610: Path reusability & binary fetch.
Reusing createFormDefinitionPathFromTypeId for template association/dissociation and fetching preview images keeps the code consistent.

Also applies to: 644-644, 665-665

ui/app/src/components/ContentTypeManagement/utils.ts (25)

1-16: Header license.
These lines introduce the standard open-source GPL v3 license block.


17-42: Imports and references.
Pulling in many models and utility helpers underscores the file’s core function: bridging content type logic with UI forms.


43-54: Mapping field properties to XML.
contentTypeFieldToXmlNameMap clarifies that “name” maps to “title” and “helpText” maps to “help.” Good for consistent serialization.


55-70: TypePropsToEdit definition.
This is a focused subset of ContentType properties, making it easier to manage which fields are editable in the forms.


71-87: ContentTypeValuesObject & props array.
The added structure ensures typed data while editing fundamental content type properties.


88-93: createTypeFormValuesObject().
Plucking relevant props from the content type is a succinct approach; hardcoding groovyController is acceptable as a placeholder.


94-119: createTypeFieldValuesObject().
Iterating over each relevant field property, ignoring known ephemeral ones (sortable, etc.) is a clear approach for building form values.


120-133: Populating field properties.
populateFieldPropertiesValues() gracefully handles the subset of recognized properties while logging unhandled plugin usage.


135-149: Populating validations.
Skipping maxLength avoids overwriting from two sources (properties vs. validations). This is a pragmatic workaround.


151-198: Reversing field values.
reverseTypeFieldValuesObject() re-injects form data into the original ContentTypeField. The noted unhandled plugin property is consistent with the forward parse.


200-221: Creating an empty type structure.
createEmptyTypeStructure() with optional mixin ensures flexibility when initializing new content types.


223-242: createVirtualTypeForField().
Merging commonControlFieldsDescriptors with existing fields allows on-the-fly creation of a “virtual” content type for a single control.


244-250: createVirtualTypeForSection().
Produces a simplified content type with the given sections. Straightforward.


252-273: Not implemented data source factory.
createVirtualTypeForDataSource() explicitly throws an error. Confirm whether you plan to implement this or remove it before merging.


274-284: createVirtualSection().
Auto-generating an ID via nanoid() and applying toColor for the section color is consistent with other logic.


286-298: createVirtualDataSourceFields().
Maps each data source to a content-type field structure. Straightforward approach for bridging data sources into the form.


300-309: Stable global context.
fooStableGlobalContext is a frozen object placeholder used for stable references in forms. No issues.


310-330: createVirtualTypeFormContext().
Creates context references, sets up the default values and atoms for each field. Clean approach to building form states.


332-340: createFieldFormContextApi().
Skeleton of a rollback mechanism for forms. Ensure it fully integrates with your forms engine before production.


341-352: createFieldItemMetaContext().
Offers a minimal context about the item, including path, content type, and placeholders for content.


354-390: createStableFormContextProps().
Centralizes the “atoms” for form state (expanded sections, values, etc.). The optional createRootTypeSections merges extra default sections if needed.


391-398: makeIntoTypeFieldStructPath().
Builds a nested path to reference repeated/child fields. Straightforward splitting and joining logic.


399-454: Serialization to XML preparation.
prepareSerializeToXmlTypeObject() and buildContentTypeXml() define the final structure for publishing a content type as XML.


455-478: convertFieldStructToXmlStruct().
Currently sets placeholders (undefined) for plugin, properties, constraints, with a TODO note. Clean approach with clear next steps.


480-506: convertDataSourceStructToXmlStruct().
Iterates through each property and captures its type. Future enhancements might handle custom property types beyond simple boolean/int/string.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (1)
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (1)

138-141: ⚠️ Potential issue

Missing functionality in Add Field button.

The "Add Field" button is rendered but doesn't have an onClick handler, so it won't actually do anything when clicked. This appears to be incomplete functionality.

-<TypeBuilderAddButton>
+<TypeBuilderAddButton onClick={() => {/* Implement field addition logic */}}>
  <FormattedMessage defaultMessage="Add Field" />
</TypeBuilderAddButton>
🧹 Nitpick comments (10)
ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (2)

55-59: Add empty state handling for search results

The component doesn't handle the case when no controls match the search term. Users would see an empty grid with no feedback.

const filteredFields = fieldTypes.filter(
  (field) =>
    field.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
    field.description.toLowerCase().includes(searchTerm.toLowerCase())
);

return (
  <>
    <DialogBody sx={{ transition: 'height 0.3s ease-in-out' }}>
      <SearchBar keyword={searchTerm} onChange={handleSearchChange} />
+     {filteredFields.length > 0 ? (
        <Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
          {filteredFields.map((field, index) => (
            // ... existing code
          ))}
        </Box>
+     ) : (
+       <Box sx={{ display: 'flex', justifyContent: 'center', padding: 3 }}>
+         <Typography variant="body2" color="textSecondary">
+           <FormattedMessage defaultMessage="No controls match your search" />
+         </Typography>
+       </Box>
+     )}
    </DialogBody>
  </>
);

48-48: Consider adding accessibility improvements

The dialog should have appropriate ARIA attributes for better accessibility, particularly for screen readers.

Consider adding the following improvements:

  1. Add aria-labelledby to the dialog content referencing the dialog title
  2. Ensure that each control item has appropriate keyboard navigation
  3. Add a descriptive aria-label to the search bar
ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx (1)

38-51: Remove console.log statement from production code.

The handleDeleteType function includes a console.log('Deleted.') statement in the onComplete callback. Console logging statements should be removed from production code as they can expose implementation details.

onComplete() {
-  console.log('Deleted.');
  onActionClick?.(e, 'deleted');
}
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (3)

93-94: Fix TypeScript type issue instead of using @ts-expect-error.

The code is using @ts-expect-error to suppress a TypeScript error. It would be better to fix the underlying type issue for better type safety.

-// @ts-expect-error: Handled. Only when it is a button will it receive the onClick.
-onClick={isRepeat ? undefined : onClick}
+onClick={isRepeat ? undefined : onClick as any}

Consider defining proper component type interfaces to avoid type assertions altogether.


98-99: Same type issue as above needs fixing.

Similar to the previous comment, another @ts-expect-error is used to suppress TypeScript errors. The same solution applies.


122-122: Remove empty style object.

The Asterisk component has an empty sx object that can be removed.

-{error && <Asterisk fontSize="small" sx={{}} />}
+{error && <Asterisk fontSize="small" />}
ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (2)

72-75: Refactor store creation with proper memoization.

The TODO comment suggests using "stable memo" for store creation. Since the store is created on every render but only initialized once through the ref pattern, consider using a proper memoization approach.

-const store = useMemo(() => createStore(), []); // TODO: Use stable memo?
+const store = useMemo(() => createStore(), []);

const stableFormContextRef = useRef<StableFormContextProps>(null);
if (stableFormContextRef.current === null)
  stableFormContextRef.current = createStableFormContextProps({ type }, true);

235-235: Specify radix in parseInt call.

When using parseInt, it's best practice to specify the radix to avoid unexpected results with certain input strings.

-onChange={(e) => setPosition(parseInt(e.target.value))}
+onChange={(e) => setPosition(parseInt(e.target.value, 10))}
ui/app/src/models/ContentType.ts (2)

165-177: Document new TypeBuilder 2 properties.

Several new properties have been added for TypeBuilder 2, but they have TODOs and limited documentation. Consider adding JSDoc comments for these properties to better document their purpose and expected values.

For example:

+/**
+ * Indicates whether this content type has a JavaScript controller.
+ */
hasJsController: boolean; // TODO: Should this one be the file name, like `thumbnailFileName`?

+/**
+ * The filename of the thumbnail image associated with this content type.
+ */
thumbnailFileName: string;

266-307: Consider merging similar interfaces as noted in TODO.

As noted in the comments, SerializeToXmlContentTypeStructure and LegacyFormDefinition are very similar. Consider whether they can be consolidated or have a shared base interface to reduce duplication.

// Base interface with common properties
interface BaseContentTypeDefinition {
  'content-type': string;
  title: string;
  description: string;
  // ...other common properties
}

// Extend for specific use cases
interface SerializeToXmlContentTypeStructure extends BaseContentTypeDefinition {
  // ...specific properties
}

interface LegacyFormDefinition extends BaseContentTypeDefinition {
  // ...specific properties
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb1c03f and 6fbbdb3.

📒 Files selected for processing (5)
  • ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (1 hunks)
  • ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx (1 hunks)
  • ui/app/src/models/ContentType.ts (8 hunks)
🧰 Additional context used
🧬 Code Definitions (4)
ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (4)
ui/app/src/models/ContentType.ts (1) (1)
  • ContentTypeField (62-140)
ui/app/src/hooks/useIsDarkModeTheme.tsx (1) (1)
  • useIsDarkModeTheme (20-22)
ui/app/src/utils/string.ts (1) (1)
  • capitalize (34-36)
ui/app/src/components/ContentTypeManagement/components/TypeBuilderAddButton.tsx (1) (1)
  • TypeBuilderAddButton (30-30)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx (1)
ui/app/src/models/ContentType.ts (1) (1)
  • PossibleContentTypeDraft (187-189)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsView.tsx (5)
ui/app/src/models/ContentType.ts (4) (4)
  • PossibleContentTypeDraft (187-189)
  • DataSource (146-152)
  • ContentTypeSection (201-210)
  • ContentType (156-181)
ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx (2) (2)
  • TypeDetailsViewHeaderProps (31-34)
  • TypeDetailsViewHeader (36-100)
ui/app/src/components/FormsEngine/lib/formsEngineContext.ts (2) (2)
  • StableFormContextProps (107-115)
  • StableFormContext (125-125)
ui/app/src/components/ContentTypeManagement/utils.ts (2) (2)
  • createVirtualSection (274-284)
  • createVirtualDataSourceFields (286-298)
ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (1) (1)
  • defaultDataSourcesSection (98-102)
ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (2)
ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts (1) (1)
  • controlDescriptors (148-178)
ui/app/src/components/SearchBar/SearchBar.tsx (2) (2)
  • SearchBarProps (36-59)
  • SearchBar (61-204)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (7)
ui/app/src/components/ContentTypeManagement/components/PickControlDialog.tsx (3)

65-74: Missing selection state for control items

The list of controls doesn't track which item is selected, making it impossible to know which control to return when Accept is clicked.

+const [selectedField, setSelectedField] = useState(null);

// Then in the mapping function:
<ListItemButton 
  key={index}
+ selected={selectedField === field.id}
+ onClick={() => setSelectedField(field.id)}
>

80-82: Missing onClick handler for Accept button

The Accept button doesn't have an onClick handler to process the selected control. This will prevent users from completing their selection.

-<PrimaryButton>
+<PrimaryButton onClick={(e) => {
+   // Get the selected control and pass it to onClose
+   const selectedControl = /* logic to get selected control */;
+   onClose?.(e, selectedControl);
+}}>
   <FormattedMessage defaultMessage="Accept" />
</PrimaryButton>

90-93: Dialog is always open regardless of props

The open prop is hardcoded to true in the EnhancedDialog component, which will cause the dialog to always be open regardless of the actual open value passed in props.

-<EnhancedDialog open title={<FormattedMessage defaultMessage="Pick a Control" />} maxWidth="sm" {...dialogProps}>
+<EnhancedDialog title={<FormattedMessage defaultMessage="Pick a Control" />} maxWidth="sm" {...dialogProps}>
ui/app/src/components/ContentTypeManagement/components/TypeDetailsViewHeader.tsx (1)

92-96: Deletion button logic looks good.

The delete button is correctly conditional based on the NEW property of the content type, preventing deletion of content types that haven't been saved yet.

ui/app/src/components/ContentTypeManagement/components/FieldChip.tsx (1)

56-56: Plan for performance optimization with atom.

The comment indicates a future optimization to make the error check into an atom. This is a good plan for improving performance by avoiding unnecessary re-renders, but should be tracked as a follow-up task.

Are there plans to create a tracking issue for this optimization task?

ui/app/src/models/ContentType.ts (2)

187-189: Well-defined PossibleContentTypeDraft interface.

The interface for PossibleContentTypeDraft is well-designed, providing a clear distinction between new and existing content types.


254-256: Use of id in LegacyFormDefinitionSectionWithId is consistent.

The addition of the id property to sections in the LegacyFormDefinitionSectionWithId interface is consistent with the changes to ContentTypeSection.

@rart rart requested a review from sumerjabri March 22, 2025 13:10
@sumerjabri sumerjabri merged commit fd22eea into craftercms:develop Mar 24, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants