Plugin Quickstart Guide

Plugins

Plugin Structure Description

Plugins are independent modules that can be connected to a course. There are three types of plugins:

  • View Plugins - display information in the course, such as text, images, videos, etc.

  • Trainer Plugins - allow students to complete exercises like quizzes, tasks, exercises, etc.

  • Assignment Plugins - allow students to complete tasks that need to be reviewed by the teacher.

A plugin is a directory containing the necessary files and folders for its operation. In the root of the plugin, there must be a manifest.json file that describes the plugin's structure.

Example of the manifest.json file for the Single Choose plugin:

{
  "status": "active",
  "version": "1.0",
  "name": "Single Choose",
  "description": "simple single choose",
  "short_description": "simple single choose",
  "icon": "./dist/icon.png",

  "settings" : {
    "answerRequired": true
  },

  "entry": {
    "state": "./dist/state.json",
    "handler": "./dist/handler.lua",
    "settings": "./dist/settings.json",
    "edit": "./dist/edit.html",
    "view": "./dist/view.html"
  }
}
  • status - status of the plugin (active, inactive, deprecated)

  • is_public - whether the plugin is public or private

  • version - plugin version

  • name - name of the plugin

  • description - detailed description of the plugin

  • short_description - brief description of the plugin

  • icon - path to the plugin icon

  • settings - plugin settings

  • settings.answerRequired (boolean) - whether an answer is required

  • settings.assignmentApproveRequired (boolean) - whether teacher approval is required for the student's answer

  • entry - plugin files

  • entry.state - state file for the plugin

  • entry.handler - plugin handler file

  • entry.settings - plugin settings file

  • entry.edit - HTML file for editing the plugin

  • entry.view - HTML file for displaying the plugin

Plugins can contain additional files and folders necessary for their operation and the compilation of key HTML files (edit and view).

Technical Requirements for Plugins:

  • Plugins can be written in any language that can transpile to JavaScript (TypeScript, CoffeeScript, Babel, etc.).

  • Plugins should be compiled into a single file (e.g., using Webpack) — one edit.html and one view.html.


Plugin State File (state.json)

Each plugin must have a state file where the current state of the plugin is stored. The state file should contain a JSON object that describes the state variables of the plugin. The plugin's interface is generated based on the state file.

Example of the Single Choose plugin state file:

{
  "question": "",
  "options": []
}

Plugin Settings File (settings.json)

Each plugin can have a settings file where its settings are stored. This file is separate from the state file because settings may be used to configure the plugin but do not affect its state.

Example of the Single Choose plugin settings file:

{
  "JSONSchema": {
    "properties": {
      "isIgnoreErrorAnswer": {
        "type": "boolean",
        "title": "Ignore error answer",
        "default": false
      },
      "completedMessages": {
        "type": "object",
        "title": "Messages",
        "properties": {
          "success": {
            "title": "Success message",
            "type": "string",
            "default": "You did a great job!"
          },
          "wrong": {
            "title": "Wrong message",
            "type": "string",
            "default": "Sorry, you are wrong."
          }
        }
      }
    }
  },
  "UISchema": {
    "isIgnoreErrorAnswer": {
      "ui:widget": "checkbox",
      "ui:help": "If checked, the answer will be ignored if an error occurs."
    }
  }
}

The settings file is a JSON Schema object that describes the structure of the dynamic form in react-jsonschema-form (https://rjsf-team.github.io/react-jsonschema-form/).


Plugin Handler File (handler.lua)

Each "trainer" plugin must have a handler file that describes the logic of the plugin. Based on the plugin state and the input data (student’s response), the output data (result of the answer check) is generated. The Lua programming language is used.

Example of the Single Choose plugin handler file:

function main()
    local message = "Answer is required"

    -- Check and set default values for components
    local options = bx_state.component.options or {}
    local answer = bx_state.request.answer
    local settings = bx_state.component._settings or {}
    local isIgnoreErrorAnswer = settings.isIgnoreErrorAnswer or false
    local completedMessages = settings.completedMessages or {
        success = "Correct answer!",
        wrong = "Incorrect answer. Please try again."
    }

    -- Check if the answer is provided
    if not answer then
        return false, message
    end

    -- Increment the answer index, assuming the answer is an index
    answer = answer + 1

    -- Check if the answer index is valid
    if not options[answer] then
        return false, "Answer is invalid"
    end

    local messageType = "wrong"
    local isCorrect = false
    -- Check if the answer is correct
    if options[answer].isCorrect then
        isCorrect = true
        message = completedMessages.success
        messageType = "success"
    else
        -- Check if there is an explanation for the wrong answer
        if not options[answer].explanation or options[answer].explanation == "" then
            message = completedMessages.wrong
        else
            message = options[answer].explanation
        end

        -- Check if wrong answers should be ignored
        if isIgnoreErrorAnswer then
            return true, "[" .. messageType .. "]:" .. message
        end
    end

    return isCorrect, message
end
  • bx_state - global variable containing the plugin state and input data (student's answer)

    • bx_state.request - input data (student's answer)

    • bx_state.component - plugin state

    • bx_state.component._settings - plugin settings


Example of a Hook for Saving Plugin State in view.html (Student's Answer)

// Sync local state with global component state
$_bx.event().on("before_submit", (v) => {
  if (this.state.answer === null || this.state.answer === undefined || this.state.answer === "" || this.state.answer < 0) {
    $_bx.showErrorMessage("Error: Please select an option to continue.");
    return;
  }
  v.state.answer = this.state.answer;
});


Deploying the Plugin

coobcli is a command-line tool that allows you to manage plugins and their versions, as well as publish them to the plugin repository.

Installing coobcli:

npm i coobcli

Using coobcli:

Commands:
index.js login    Authenticate on coob.app
index.js publish  Publish plugin on coob.app

Options:
--version  Show version number                                       [boolean]
--help     Show help

Last updated