Skip to content

Lime Admin

This chapter delves into how Lime CRM Admin can be customized. Just as with the web client, Lime CRM Admin offers numerous customization options. You can implement a tailored administration experience, providing a more personalized environment according to the needs of your customization.

Introduction

Customizing Lime CRM Admin primarily involves defining a plugin class in the Python backend. This class is responsible for managing the settings associated with your customization, guiding the configuration process.

One key aspect of creating a plugin class is the definition of a schema. This schema is mainly used to validate the data before being saved to the database, but is also used as a roadmap for rendering a form on the client side. It tells Lime CRM Admin how the form should be structured and which fields it should contain.

Please refer to Runtime Configuration for more information on how to generate the plugin class to handle your customization's configuration.

Custom Components in Lime CRM Admin

Although Lime CRM Admin primarily focuses on enabling customization configuration, you can also create custom components to use in various sections or fields within the configuration form. This flexibility allows you to create forms that better meet your requirements and provide a more interactive configuration experience for the users.

Note

To ensure that custom components load in Lime Admin, it's crucial to add platform compatibility information to the package.json file. Specifically, you need to include LimeCRMWebAdminClient in the list under the key lime.platforms. This step informs Lime CRM Admin that your project contains custom components intended for use within the Admin configuration environment. Please refer to Platform Compatibility for more information.

To illustrate, let's start with a basic schema that will render a text field where the user can enter a color:

from marshmallow import Schema, fields

class MySchema(Schema):
    color = fields.String()

Though functional, this setup is not particularly user-friendly. A more intuitive approach would be to render a color picker instead of a standard text input field. Since the form is rendered using the limel-form component from Lime Elements, we can specify a custom component in the schema to achieve this:

from marshmallow import Schema, fields

class MySchema(Schema):
    color = fields.String(
        metadata={
            "lime": {
                "component": {
                    "name": "limel-color-picker",
                }
            }
        }
    )

Now, limel-color-picker from Lime Elements will be rendered instead of the standard input field. You can even create your own components in your customization. These components will also receive the platform and context properties, and all the services available on platform as in the web client.

To create a custom component, the component should implement the FormComponent interface from Lime Elements

Let's use an example where the user needs to configure a position. Rather than having two input fields for the user to manually enter the latitude and longitude, it would be much more user-friendly to simply select the location from a map:

from marshmallow import Schema, fields

class PositionSchema(Schema):
    lat = fields.Float()
    long = fields.Float()

class MySchema(Schema):
    position = fields.Nested(
        nested=PositionSchema,
        metadata={
            "lime": {
                "component": {
                    "name": "my-position-picker"
                }
            }
        }
    )

This new schema will render a position picker instead of the two input fields. Now, we need to implement the component:

import { Component, Prop, Event, EventEmitter } from '@stencil/core';
import { LimeWebComponentContext, LimeWebComponentPlatform } from '@limetech/lime-web-components';
import { FormComponent } from '@limetech/lime-elements';

type Position = { lat: number, long: number };

@Component(
    tag: 'my-position-picker',
    shadow: true,
)
export class PositionPicker implements FormComponent<Position> {
    @Prop()
    public platform: LimeWebComponentPlatform;

    @Prop()
    public context: LimeWebComponentContext;

    @Prop()
    public value: Position;

    @Event()
    public change: EventEmitter<Position>;

    public render() {
        // Render a map that lets the user pick a location
        // handleChangePosition will get called when location is picked
    }

    private handleChangePosition(event: CustomEvent) {
        this.change.emit({
            lat: event.detail.getLatitude(),
            long: event.detail.getLongitude(),
        });
    }
}

This example does not provide a full implementation but should serve as a guide to implementing a custom component. The crucial parts are:

  • The value prop will be the currently selected position. It will be given to the component when it's first rendered or when the position has been changed.
  • The render method should render the component as usual. Here, we assume that the map will emit an event when the position has been changed.
  • The change event should be emitted when the value has been changed. It's important that the type of the input and output value is the same, that is, the value prop and the value in the emitted change event.

Dynamic configuration components

Beta

The authoring of dynamic configuration components within Lime Admin is a pivotal feature designed to enhance the user experience and streamline the configuration process for developers working with web components or commands. By registering these components or commands along with associated metadata, developers enable seamless integration within Lime Admin. This section serves as a comprehensive guide to understanding and implementing this feature effectively.

Key Concepts

  • Registration Process: Developers can register web components or commands within the platform. During registration, metadata such as title, description, icon, color, tags, and a configuration component can be provided.

  • Enhanced User Experience: Registered components or commands are accessible through Lime Admin's various sections, eliminating the need for users to rely on memory or external documentation to enter correct names. This improves discoverability and simplifies configuration processes.

  • Configuration Components: A crucial aspect of registration is the provision of a configuration component. When provided, Lime Admin utilizes this component to generate a user-friendly UI for configuring associated components or commands. In the absence of a configuration component, users must resort to manual JSON configuration, which is less intuitive.

  • Dynamic Rendering: Lime Admin dynamically looks up the configuration component associated with a provided component name or command ID. This ensures that the correct configuration UI is presented for the corresponding entity.

Implementation Guidelines

To register a component or command, utilize the provided services in the platform. Web components are registered using the WebComponentRegistry service, and commands are registered using the CommandBus. Below is an example demonstrating how to register a component with metadata and a configuration component:

platform
    .get(PlatformServiceName.WebComponentRegistry)
    .register('my-component', {
        title: 'My Component',
        description: 'This is the best component',
        icon: {
            name: 'hotdog',
            color: 'rgb(var(--color-magenta-default))',
        },
        configComponent: {
            name: 'my-component-admin-config',
        },        
    });

When developing a configuration component, adherence to defined standards and guidelines is crucial for seamless integration with Lime Admin. The component should implement the FormComponent interface from @limetech/lime-elements. Additionally, it should receive the configuration as an object and emit any changes made to the configuration as events.

Below is a simple example demonstrating how to create a basic configuration component:

@Component({
    tag: 'my-component-admin-config',
    shadow: true,
})
export class MyComponentAdminConfig
    implements LimeWebComponent, FormComponent<Record<string, unknown>>
{
    @Prop()
    public platform: LimeWebComponentPlatform;

    @Prop()
    public context: LimeWebComponentContext;

    @Prop()
    public value: Record<string, unknown> = {};

    @Event()
    public change: EventEmitter<Record<string, unknown>>;    

    public render() {
        // Render the configuration UI
    }
}

In this example, the configuration component implements the FormComponent interface and receives the configuration as an object on the value property. Any changes made to the configuration are emitted back to the parent component using the change event. This ensures seamless interaction between the configuration component and Lime Admin, enabling users to modify properties effectively.

Tip

When developing configuration components, utilizing the appropriate types can greatly enhance clarity and maintainability. Instead of using a generic Record<string, unknown> type for configuration properties, developers can benefit from leveraging the specific type for the corresponding component. This approach allows for better type checking and provides insight into the properties available for configuration.

To achieve this, developers can import the JSX type and derive a custom type that encompasses only the properties intended for configuration. Below is an example demonstrating this approach:

import { JSX } from 'src/components';

// Define a custom type containing properties for configuration
type MyComponentProps = Omit<JSX.MyComponent, 'platform' | 'context'>;

// Implement the configuration component using the custom type
export class MyComponentAdminConfig implements FormComponent<MyComponentProps> {
    @Prop()
    public value: MyComponentProps = {};

    @Event()
    public change: EventEmitter<MyComponentProps>;            
}

In this example, MyComponentProps is a custom type that excludes specific properties (platform and context in this case) from the original JSX.MyComponent type. By utilizing this custom type, developers can ensure that only relevant properties are exposed for configuration within the Lime Admin interface, thereby simplifying the user experience and reducing the risk of configuration errors.

Using tags

In addition to registering components or commands with metadata, developers can utilize tags to enhance categorization and filtering within Lime Admin. When registering a component or command, developers have the option to associate it with one or more tags. These tags serve as descriptors, allowing Lime Admin to display relevant components or commands based on the context in which they are used.

platform
    .get(PlatformServiceName.WebComponentRegistry)
    .register('my-component', {
        title: 'My Component',
        tags: ['card-property'],   
    });

In this example, the component is registered with the tag card-property. The tag serve as a descriptor to categorize the component for specific contexts within Lime Admin.

Within Lime Admin, various sections or interfaces may utilize specific tags to filter and display relevant components or commands. For example, if a section in Lime Admin is configured to display components related to object properties on the card, it may use the card-property tag for filtering purposes.

When users interact with Lime Admin in such contexts, only components or commands associated with the relevant tag(s) will be listed. This targeted filtering ensures that users are presented with options that are specifically relevant to the task at hand, improving efficiency and user experience.

List of tags

At the moment, the following tags are used within Lime Admin to find components and commands in different contexts

Tags for components
Tag Description
action-pad Components suitable for the action pad in the desktop client
activity-feed-composer Components that can replace the composer in the activity feed
card-property Components that replace the default fields in the form on a card
card-widget Components suitable for the widget slot on the card
explorer-table-column Components that will be used in the explorer table view for each row of a column
explorer-view View components that can display a collection of objects
start-page Components for the start page
tab Components that can be used as a tab on the card
Tags for commands
Tag Description
object Commands acting on a single LimeObject
bulk-object Commands acting on a LimeObject collection

Conclusion

As this chapter has shown, the possibilities for customization in Lime CRM Admin are extensive. By implementing a plugin class, defining a suitable schema, and harnessing the power of custom components, you can create a highly personalized administration experience for your users. The flexibility these tools provide means that the forms you create can meet the specific needs of each customization, greatly enhancing usability and interaction.

However, remember that each customization comes with its own set of challenges and requirements. Always plan ahead, considering your users' needs and the specific goals of your customization. Experimenting with the tools discussed in this chapter will help you discover what works best in your particular case.

In the end, a well-customized Lime CRM Admin can help make your team more efficient, your users more satisfied, and your projects more successful. Always keep in mind the power of customization, and never stop exploring the potential it holds.

As you continue your work with Lime CRM, remember to refer back to this guide, our other documentation, and the broader community for assistance and inspiration. Happy customizing!