Developing your Custom Actions

Learn how to code your own custom Actions for your Diffgram Installation

This guide will help you develop your own custom action for Diffgram. Diffgram actions are small functionality that can be triggered based on events happening in the system.

To develop a full custom action you need the following elements:

  1. Create the Action Template. You need to define the list of events your action can listen to and some important metadata.
  2. Create the ActionRunner class. Here is where the core code for your action execution will reside. This class has to inherit from the diffgram base ActionRunner class.
  3. Create the frontend components for your actions management.

πŸ“˜

We recommend contributing new actions to Diffgram

If you want to avoid having to maintain a fork of Diffgram, we highly recommend you contribute your new actions to Diffgram in a Pull Request.

To generate boilerplate code for custom actions, use the diffgram CLI:

https://github.com/diffgram/diffgram-cli

1. Registering the Action

The first step is to register your new action. To do this first you will have to create a new file with a class that inherits from the action runner object.

Add the file to the event_handlers/action_runners/actions folder.

Here's a sample action runner for your to start with

from action_runners.base.ActionRunner import ActionRunner
from action_runners.base.ActionTrigger import ActionTrigger
from action_runners.base.ActionCondition import ActionCondition
from action_runners.base.ActionCompleteCondition import ActionCompleteCondition
from shared.shared_logger import get_shared_logger

logger = get_shared_logger()

class YourNewAction(ActionRunner):
    public_name = 'Action Name'
    description = 'Description of the action'
    icon = 'http://link-to-your-icon.com'
    kind = 'anction_kind'
    trigger_data = ActionTrigger(default_event = 'event_name',
                                 event_list = ['event_name', 'second_event_name'])
    precondition = ActionCondition(default_event = 'action_completed',
                                   event_list = ['action_completed'])

    completion_condition_data = ActionCompleteCondition(default_event = 'action_completed',
                                                        event_list = ['action_completed'])
    category = 'category'

    def execute_pre_conditions(self, session) -> bool:
        return True

    def test_execute_action(self, session, file_id, connection_id):
        pass

    def execute_action(self, session, do_save_annotations = True) -> dict or None:
        pass

After Creating the class, import it and add it to the list of action runners in event_handlers/action_runners/actions/__init__.py

try:
    from .YourAction import YourAction
    ACTION_RUNNERS_KIND_MAPPER[YourAction.kind] = YourAction
except:
    logger.error(traceback.format_exc())

List of available triggers:

TriggerDescription
input_file_uploadedTriggered when the new file is uploaded
task_createdTriggered when new task is created
task_completedTriggered when the status of the task is changed to "completed"
action_completedTriggered when the previous action in the workflow is completed
manual_triggerTriggered manually from the frontend

2. Implement Action Logic

All the action logic is implemented under the execute_action() function. This function does not return anything. Feel free to use any other classes or helpers from Diffgram to achieve your objective.

3. Create Frontend Components

The only thing that's pending is creating the UI components for customizing your action configuration.

Create a new folder which will contain all your components inside frontend/src/components/action/action_configurations

https://github.com/diffgram/diffgram/tree/master/frontend/src/components/action/action_configurations

Inside your component you will need to use the action_config_base class.

Here's an example:

<template>
  <v-container fluid style="height: 100%">
    <action_config_base
      v-if="steps_config"
      :project_string_id="project_string_id"
      :display_mode="display_mode"
      @open_action_selector="$emit('open_action_selector')"
      :steps_config="steps_config.generate()"
      :actions_list="actions_list"
      :action="action">


      <template v-slot:wizard_action_config>
        <export_config_details :action="action" :project_string_id="project_string_id"></export_config_details>
      </template>



      <template v-slot:form_action_config>
        <export_config_details :action="action" :project_string_id="project_string_id"></export_config_details>
      </template>

      <template v-slot:ongoing_usage>
        <v_export_view
          v-if="action.config_data"
          :project_string_id="$store.state.project.current.project_string_id">
        </v_export_view>
      </template>

    </action_config_base>


  </v-container>
</template>

The configuration is composed of 4 steps:

  1. Triggers: Configures the events that will trigger the action
  2. Pre Conditions: Configures extra conditions to check before executing an action.
  3. Action Configuration: Configures any extra metadata the action needs to run.
  4. Completion Trigger: Configure events that will mark the action as completed.

Each of these steps has a slot for the action_config_base component. You can use these slots to customize the UI and required configs. For example to customize the actions configuration step of the configuration wizard you add the following slot:

      <template v-slot:wizard_action_config>
        <export_config_details :action="action" :project_string_id="project_string_id"></export_config_details>
      </template>

Here's the base class definition if you want to dive deeper:

https://github.com/diffgram/diffgram/blob/master/frontend/src/components/action/actions_config_base/action_config_base.vue