======== Commands ======== .. include:: ../complete.rst Writing app commands ==================== Commands are code that runs on the server that is triggered by clicking a button on a slice. Custom commands for an app should be placed in a ``commands.py`` file in the top directory of the app. .. code-block:: python app.yaml theme.yaml commands.py <== App commands go here public/ stacks/ Commands are customized by changing the Command Meta class. Here's a simple example of a commands.py file. .. code-block:: python :caption: commands.py from jbcommands.jbcommandbase import JBCommand class NailedItCommand(JBCommand): """ The 'Hello World' of commands. """ class Meta: name = 'nailed-it' label = 'Make a comment' icon = 'icon-comment-o' response_action = 'display' def execute(self): return "It is now {}".format(datetime.now()) Here's what this looks like when run from a slice. .. image:: images/commands-nailed-it-simple.gif :width: 600 Meta options ============ name ---- The ``name`` is how slices refer to a command in ``include_commands``. :Default: None :Optional: No label ----- A label to associate with this command. This label is displayed on the button. :Default: 'please-assign-me-a-label' :Optional: No icon ---- An icon to associate with this command. This can be any icon available in `Font Awesome `_. The icon name should be prefixed with ``icon-``. The icon is visible in both the button and the success and failure messages. :Default: None :Optional: Yes Here's an example with a custom icon. .. code-block:: python class Meta: name = 'nailed-it' label = 'Make a comment' icon = 'icon-comment-o' success_message = 'Let\'s pencil this in as done' .. image:: images/commands-icon-comment-o.gif :width: 600 TODO: point to JBCommand docs. success_message --------------- A message to show the user when the command runs successfully. If omitted, successful commands will complete silently. To change the success message dynamically: :Default: None :Optional: Yes .. code-block:: python class NailedItCommand(JBCommand): """ The 'Hello World' of commands. """ class Meta: name = 'nailed-it' label = 'Make a comment' icon = 'icon-comment-o' response_action = 'display' def execute(self): return "It is now {}".format(datetime.now()) .. image:: images/commands-dynamic-success-message.gif :width: 600 failure_message --------------- A message to show the user when the command fails. :Default: 'Oops! Something went wrong!' :Optional: Yes inputs ------ This option is used to describe a list of inputs that define the dialog presented to the user in the UI to collect the input. Currently support is limited to input and textarea form elements. The structure of the meta option is: .. code-block:: python inputs: [ { 'name': 'username', 'type': 'input', 'label': 'Please enter your username', 'placeholder': 'your username' } ] where: :name: The name of the input field :type: The type of the input. Can be one of ('input', 'input-multiline') :label: The label of the field :placeholder: The placeholder of the input. This property is only for 'input' or 'input-multiline' types. Input validation is done in the command and notified via a failure toast. The user input received from the UI is available on the command instance in the command_input property. The command can use this property to perform any validations in the validate_input method: .. code-block:: python def validate_input(self): if not self.command_input.get('username'): raise JBValidationError('Username cannot be empty') If the validation fails, a 400 Bad Request response is sent. The UI shows the error response received as a failure notification. response_action --------------- :Default: None :Options: 'print'\|'download'\|'display'\|None :Optional: Yes What should happen to the response returned by the command. :print: Response should return a url to print. A print dialog box will be shown with the url as content. :download: Response should be a url to download. The content at this url will be downloaded. :display: Response should be html text. This will be displayed as the success message. :None: Ignore the response. hide ---- :Default: False :Optional: Yes Should the button to trigger the command be hidden. This is useful if you need the command endpoint but don't want to show UI for that command. context ------- :Default: slice :Options: 'slice'\|'discussion'\|None :Optional: Yes The context for this command. It is used by the front-end to pass the context this command was run in. :slice: The command will be passed the id of the slice that ran it, in a parameter called ``slice_id``. data_type --------- :Default: None :Options: 'slice'\|'state'\|None :Optional: Yes The data type for this command. It is used by the front-end to pass the command any contextual data it requires. :slice: The command will be passed the html and css of the slice that ran it, in parameters ``slice_html`` and ``slice_css`` respectively. :state: The command will be passed the state of the slice that ran it - its filters, selected data set and pagination params. help_text --------- :Default: 'Use this to create some help text about this command' :Optional: Yes parameters ----------- :Default: () :Optional: Yes Built-in commands ================= There are several built-in commands :download-data: Creates a downloadable Excel file. :download-image: Downloads an image of the slice. :print-image: Pops a print dialog to print an image of the slice. :post-to-slack: Posts an image of a slice to a Slack channel. Requires app metadata. Configuring commands ==================== Commands can receive configuration that is provided in application metadata. See `/topics/juicebox_reference/apps/index` for more about metadata. Configuration should be placed in a ``commands`` dictionary with a key containing the name of each command that needs configuration. For instance: .. code-block:: yaml metadata: commands: post-to-slack: hook_url: {url} text: "This is cool." image_title: "Current status" These values are available when the command executes in a dictionary ``self.app_command_config``. Customizing built-in commands ----------------------------- Built-in commands can be customized by subclassing a built-in command and giving it a new name and new Meta options. .. code-block:: python from jbcommands.builtincommands import DownloadImageCommand class CustomDownloadImage(DownloadImageCommand): """ A customized Download image command """ class Meta: name = 'custom-download-image' icon = 'icon-camera-retro' label = 'Download an image' data_type = 'slice' context = 'slice' response_action = 'download' Here's what this looks like. .. image:: images/commands-custom-download-image.gif :width: 600