ConfigurableTargetAdapter

This interface allows your Adapter to be configurable by Valence users when it is used as a target Adapter. What that means is entirely up to you.

Allowing users to alter the behavior of your adapter across different Links gives them a lot of flexibility. As an example, we use this on our Valence local Salesforce adapter to allow users to pick the upsert field they would like to use for each Link.

Depending on which interfaces you have implemented, your Adapter may be a source adapter, a target adapter, or both. There is a different interface if you want to make your adapter configurable as a source adapter.

The explainConfiguration() method gives you an opportunity to share with users a contextually-aware description of what your configuration is doing. Don’t just describe in abstract what can be configured, but rather use the current configuration values the user has chosen to explain to them what effect this will have on your Adapter.

Note

For a deeper look at configurable extensions in Valence, read our guide on Using Dynamic Configurations in your Extension.

Definition

/**
 * Implement this interface if you would like your TargetAdapter to be configurable by Users to behave differently for each Link that uses it.
 */
global interface ConfigurableTargetAdapter {

    /**
     * You can use your own Lightning component to let Users build and edit your configuration. If you want to do this, return the fully qualified
     * name of your component, which looks like this:
     *
     * valence:MyAwesomeAdapterConfigurator
     *
     * Make sure your component is set to global so that Valence can instantiate it.
     *
     * @param context Information about this Link
     *
     * @return The name of your Lightning component that will handle configuration, or null if you don't need your own component
     */
    String getTargetConfigurationLightningComponent(LinkContext context);

    /**
     * If you don't need or don't want to use your own Lightning Component, you can simply describe your configuration shape and we will present
     * the user with some basic input fields to populate values in your configuration.
     *
     * @param context Information about this Link
     *
     * @return A serialized JSON object describing your configuration data structure, or null if you use your own component
     */
    String getTargetConfigurationStructure(LinkContext context);

    /**
     * Given configuration data, return a user-friendly paragraph that explains how this specific configuration
     * is going to be used by your class and what effect that will have on the Link being run.
     *
     * We show this in the user interface to help Users understand the impact of their configurations.
     *
     * @param context Information about this Link
     * @param configuration The raw configuration
     *
     * @return A human-readable and friendly explanation that specifically reflects and explains the configuration passed.
     */
    String explainTargetConfiguration(LinkContext context, String configurationData);

    /**
     * Sets configuration data for your Adapter. This is the first method called on your Adapter during Link execution.
     *
     * @param context Information about this Link and the current execution of it.
     * @param configurationData Configuration data in JSON format, or in whatever format your custom configuration component gave us.
     */
    void setTargetConfiguration(LinkContext context, String configurationData);
}

Example Usage

public MyAdapter implements valence.ConfigurableTargetAdapter {

    private Schema.SObjectField upsertField = null;

    public String getTargetConfigurationLightningComponent(valence.LinkContext context) {
        return 'valence:MyCustomConfigurator';
    }

    public String getTargetConfigurationStructure(valence.LinkContext context) {
        return null;
    }

    public String explainTargetConfiguration(valence.LinkContext context, String configurationData) {

        String defaultMessage = 'Not configured; will default to letting Salesforce use Id as the upsert field.';

        if(String.isBlank(configurationData))
            return defaultMessage;

        try {
            Map<String, Object> config = (Map<String, Object>)JSON.deserializeUntyped(configurationData);

            // set the upsertField by parsing some config data and using that with Schema describe to find a field token
            if(config.containsKey('upsertField')) {
                String upsertFieldName = String.valueOf(config.get('upsertField'));
                upsertField = describeSObject(context.linkTargetName).fields.getMap().get(upsertFieldName);
                if(upsertField != null)
                    return 'This Adapter will use the <strong>' + upsertField.getDescribe().label + '</strong> field as the unique external Id when upserting records into Salesforce.';
                else
                    return '<p class="slds-theme_warning">This Adapter is configured to upsert using <' + upsertFieldName + '> but that field does not exist in <strong>' + context.linkTargetLabel + '</strong>.</p>';
            }
            else
                return defaultMessage;
        }
        catch(Exception e) {
            return '<p class="slds-theme_error">The configuration for this Adapter is malformed.</p>';
        }
    }

    public void setTargetConfiguration(valence.LinkContext context, String configurationData) {
        if(String.isBlank(configurationData))
            return;

        try {
            Map<String, Object> config = (Map<String, Object>)JSON.deserializeUntyped(configurationData);

            // set the upsertField by parsing some config data and using that with Schema describe to find a field token
            if(config.containsKey('upsertField'))
                upsertField = describeSObject(context.linkTargetName).fields.getMap().get(String.valueOf(config.get('upsertField')));
        }
        catch(Exception e) {
            throw new AdapterException('Failed to parse Adapter configuration.', e);
        }
    }
}