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

feat: Add CustomizableRenderComponent for dynamic component rendering and update component usage #4634

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

abhijith-trenser
Copy link
Contributor

@abhijith-trenser abhijith-trenser commented Dec 30, 2024

Context

  • Implemented a new CustomizableRenderComponent for dynamic rendering of both customization service components and default OSS components.
  • Integrated the new customizable rendering component into the LabellingFlow and LoadingIndicators components.
  • Created a custom hook and provider to manage and share services across the application.
  • This PR has been incorporated by FlyWheel.io

Changes & Results

  • Implemented a new functional component, CustomizableRenderComponent, to facilitate easy switching between OSS default components and customization service-provided components through dynamic rendering.
  • Developed a new hook and provider for accessing services directly across the application, eliminating the need to pass them through props.

Testing

  • Introduce a new customization method for a component.
  • Use CustomizableRenderComponent in the main component and add the default component as fallback.
  • Add the customizationId to link the component with the customization service.
  • User can render the customization-provided component in the application by registering it with the customizationId.

Checklist

PR

  • My Pull Request title is descriptive, accurate and follows the
    semantic-release format and guidelines.

Code

  • My code has been well-documented (function documentation, inline comments,
    etc.)

Public Documentation Updates

  • The documentation page has been updated as necessary for any public API
    additions or removals.

Tested Environment

  • OS: Windows 10
  • Node version: 18.19.0
  • Browser: Chrome 131.0.6778.205

Copy link

netlify bot commented Dec 30, 2024

Deploy Preview for ohif-dev canceled.

Name Link
🔨 Latest commit fff021f
🔍 Latest deploy log https://app.netlify.com/sites/ohif-dev/deploys/679770ae005b200008cd44fa

Copy link

netlify bot commented Dec 30, 2024

Deploy Preview for ohif-platform-docs canceled.

Name Link
🔨 Latest commit fff021f
🔍 Latest deploy log https://app.netlify.com/sites/ohif-platform-docs/deploys/679770ae711d860008cde24e

@sedghi
Copy link
Member

sedghi commented Jan 8, 2025

we are reworking the customizationService so stay tuned until it is done

@abhijith-trenser
Copy link
Contributor Author

we are reworking the customizationService so stay tuned until it is done

Thank you for the information, @sedghi. Would you happen to have a feature branch or work item that could serve as a reference for the implementation?

@abhijith-trenser abhijith-trenser marked this pull request as draft January 22, 2025 09:50
@abhijith-trenser abhijith-trenser changed the title feat: Integrate CustomizationService with UiDialogService and support customized components in Annotation Labelling feat: Add CustomizableRenderComponent for dynamic component rendering and update component usage Jan 23, 2025
@abhijith-trenser abhijith-trenser force-pushed the feat/integrate-customization-service-with-ui-dialog-service branch from 247b7a3 to 8e39169 Compare January 23, 2025 09:27
@sedghi
Copy link
Member

sedghi commented Jan 23, 2025

Can you rebase on top of the new customization service and follow what's done there please? Sorry for the inconvenience

@abhijith-trenser abhijith-trenser force-pushed the feat/integrate-customization-service-with-ui-dialog-service branch from d9d5415 to 79b8f42 Compare January 24, 2025 06:04
@abhijith-trenser abhijith-trenser marked this pull request as ready for review January 27, 2025 04:59
@abhijith-trenser
Copy link
Contributor Author

Can you rebase on top of the new customization service and follow what's done there please? Sorry for the inconvenience

@sedghi I have updated the branch based on the latest changes in the customization service. Would you mind reviewing it when you have a moment?

@@ -0,0 +1,9 @@
export default {
'ui.ContextMenuItem': {
$set: CustomContextMenuItem,
Copy link
Member

Choose a reason for hiding this comment

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

Clarifying the $ Sign and Customization Behavior

  1. The $ Sign and Default Customizations
    If a customization is part of the default set (i.e., it has name: 'default'), you don’t need to use the $ operators. This is because default customizations are automatically applied and serve as the base template.

    However, if a customization is not part of the default set, it won’t be applied automatically. This raises two questions:

    • a) How do we apply it?
    • b) What happens when it’s applied?

Answering Question (a): Applying Customizations

To apply a non-default customization, you reference it by its module path. For example:

customizationService.setCustomizations([
  '@ohif/extension-cornerstone-dicom-seg.customizationModule.dicom-seg-sorts',
]);

This assumes the customization is defined in the @ohif/extension-cornerstone-dicom-seg extension under the name dicom-seg-sorts. You can apply it either in your mode or globally via configuration.


Answering Question (b): Behavior When Applied

When applying a customization, you need to define how it interacts with the existing configuration. Should it append, merge, replace, or delete? This is where the $ operators come into play.

For example, in the datasources customization:

{
  name: 'datasources',
  value: datasourcesCustomization,
},

The $push operator is used to append to an array:

export default {
  'routes.customRoutes': {
    routes: {
      $push: [
        {
          path: '/datasources',
          children: DataSourceSelector,
        },
      ],
    },
  },
};

This means that when the datasources customization is applied, it will push the new route into the existing array of routes (which defaults to [] if empty).

@@ -0,0 +1,9 @@
export default {
'measurement.labellingComponent': {
$set: CustomLabellingFlow,
Copy link
Member

Choose a reason for hiding this comment

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

same for all of these

@@ -98,6 +98,7 @@ export interface Menu {
selector?: Types.Predicate;

items: MenuItem[];
customClassName: string;
Copy link
Member

Choose a reason for hiding this comment

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

just call it className

The CustomizableRenderComponent dynamically renders a custom component based on a customizationId. If a component for the given ID is found, it is rendered with the provided props; otherwise, a fallback component is rendered. To set a custom component for a specific customizationId, you must register it using the customizationService, where the custom component is added within an object under the component key. If no component is found for the specified customizationId, the FallbackComponent will be rendered instead.
```
customizationService.setCustomizations({
Copy link
Member

Choose a reason for hiding this comment

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

this is wrong, please update based on my explanation

@@ -18,14 +18,14 @@ import classNames from 'classnames';
* we import to instantiate cornerstone
*/
import guid from './../../../core/src/utils/guid';

import { CustomizationService } from '@ohif/core';
Copy link
Member

Choose a reason for hiding this comment

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

do we need this?

function ProgressLoadingBar({ progress }) {
return CustomizableRenderComponent({
customizationId: 'ui.ProgressLoadingBar',
FallbackComponent: FallbackProgressLoadingBar,
Copy link
Member

Choose a reason for hiding this comment

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

Fallbacks should be defined in the getCustomizationModules. Here, we should simply call .getCustomization or, ideally, pass the component as props to render. This approach really helps us achieve our goal of a dumb UI library, where there's no mention of customizationService in the platform/ui or /ui-next. By doing so, we pretty much keep our services separate from the UI library, which is kind of the point.

loadingText,
targetText,
}: Props) {
return CustomizableRenderComponent({
Copy link
Member

Choose a reason for hiding this comment

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

pass component as prop

function LoadingIndicatorProgress({ className, textBlock, progress }) {
return CustomizableRenderComponent({
Copy link
Member

Choose a reason for hiding this comment

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

same

items={this.currentItems}
columns={1}
onSelected={this.selectTreeSelectCalback}
<CustomizableRenderComponent
Copy link
Member

Choose a reason for hiding this comment

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

same

@@ -43,4 +37,33 @@ ContextMenu.propTypes = {
),
};

const FallbackContextMenuItem = ({ index, item, ...props }) => {
Copy link
Member

Choose a reason for hiding this comment

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

fallbacks should get registered in the extension getCustomizationModule

Copy link
Member

@sedghi sedghi left a comment

Choose a reason for hiding this comment

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

See my comments thanks

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.

4 participants