7.5 KiB
Creating Your First Plugin
This guide will walk you through the process of creating a plugin for BetterSEQTA+, from setup to implementation to testing.
Prerequisites
Before you start creating a plugin, make sure you have:
- Basic knowledge of TypeScript
- Familiarity with the BetterSEQTA+ codebase
- A development environment set up according to the Installation Guide
Plugin Structure
A typical BetterSEQTA+ plugin consists of:
- Plugin Definition: A TypeScript file that defines the plugin's metadata and functionality
- Settings Interface: (Optional) A TypeScript interface that defines the plugin's settings
- Storage Interface: (Optional) A TypeScript interface that defines the plugin's storage structure
Step 1: Planning Your Plugin
Before you start coding, take some time to plan your plugin:
- Identify the Problem: What issue or need does your plugin address?
- Define the Scope: What specific features will your plugin include?
- Consider the User Experience: How will users interact with your plugin?
Step 2: Creating the Plugin File
Create a new TypeScript file for your plugin. The convention is to place it in the src/plugins/ directory, either in the built-in folder or a new folder if it's a third-party plugin.
// src/plugins/my-plugin/index.ts
import { Plugin, PluginAPI, PluginSettings } from '../../core/types';
export interface MyPluginSettings extends PluginSettings {
enabled: {
type: 'boolean';
default: true;
title: 'Enable My Plugin';
description: 'Turn my plugin on or off';
};
// Add more settings as needed
}
export interface MyPluginStorage {
lastRun: string;
// Add more storage fields as needed
}
const myPlugin: Plugin<MyPluginSettings, MyPluginStorage> = {
id: 'my-plugin',
name: 'My Plugin',
description: 'A simple plugin for BetterSEQTA+',
version: '1.0.0',
settings: {
enabled: {
type: 'boolean',
default: true,
title: 'Enable My Plugin',
description: 'Turn my plugin on or off',
},
// Initialize your settings here
},
run: (api) => {
if (!api.settings.enabled) {
return;
}
// Initialize storage with default values if needed
if (api.storage.lastRun === undefined) {
api.storage.lastRun = new Date().toISOString();
}
// Your plugin logic goes here
console.log('My Plugin is running!');
// Access the SEQTA API
api.seqta.onPageLoad('/timetable', () => {
// Code to run when the timetable page loads
});
// Return a cleanup function (optional but recommended)
return () => {
console.log('My Plugin is cleaning up!');
// Cleanup logic goes here
};
},
};
export default myPlugin;
Step 3: Registering Your Plugin
To make your plugin available to BetterSEQTA+, you need to register it with the Plugin Manager. For built-in plugins, you can add your plugin to the src/plugins/built-in/index.ts file:
// src/plugins/built-in/index.ts
import myPlugin from './my-plugin';
// Other imports...
export const builtInPlugins = [
myPlugin,
// Other plugins...
];
For third-party plugins, you'll need to follow a different approach, as detailed in Third-Party Plugins.
Step 4: Implementing Your Plugin Logic
The main functionality of your plugin goes in the run method. Here are some common patterns:
Responding to Page Loads
api.seqta.onPageLoad('/timetable', () => {
// Code to run when the timetable page loads
});
Modifying the UI
api.seqta.onPageLoad('/timetable', () => {
const timetableElement = document.querySelector('.timetable');
if (timetableElement) {
// Modify the timetable element
const controlsDiv = document.createElement('div');
controlsDiv.className = 'my-plugin-controls';
controlsDiv.innerHTML = '<button>Zoom In</button><button>Zoom Out</button>';
timetableElement.appendChild(controlsDiv);
// Add event listeners
controlsDiv.querySelector('button:first-child').addEventListener('click', () => {
// Zoom in logic
});
}
});
Working with Settings
// Get a setting value
const isEnabled = api.settings.enabled;
// Listen for settings changes
api.settings.onChange('enabled', (newValue) => {
if (newValue) {
// Enable functionality
} else {
// Disable functionality
}
});
Working with Storage
// Get a stored value
const lastRun = api.storage.lastRun;
// Set a stored value
api.storage.lastRun = new Date().toISOString();
// Listen for storage changes
api.storage.onChange('lastRun', (newValue) => {
console.log(`Last run updated to: ${newValue}`);
});
Working with Events
// Listen for events
api.events.on('assessmentLoaded', (data) => {
console.log(`Assessment loaded: ${data.id}`);
});
// Emit an event
api.events.emit('myPluginEvent', { message: 'Hello from My Plugin!' });
Step 5: Testing Your Plugin
To test your plugin:
-
Run the development server:
npm run dev -
Open SEQTA Learn in your browser with BetterSEQTA+ enabled.
-
Check the console for any error messages.
-
Verify that your plugin works as expected.
Step 6: Adding Plugin Settings UI
If your plugin has settings, they will automatically appear in the BetterSEQTA+ settings panel. The UI is generated based on the settings interface you defined.
For more control over the settings UI, you can use the decorator-based settings system. See Creating Plugins with Settings for more information.
Best Practices for Plugin Development
-
Follow TypeScript Best Practices: Use proper typing for all variables and functions.
-
Handle Errors Gracefully: Wrap your code in try-catch blocks to prevent crashes.
try { // Your code } catch (error) { console.error('My Plugin Error:', error); } -
Clean Up After Yourself: Always return a cleanup function from your plugin's
runmethod.const cleanup = () => { // Remove event listeners, DOM elements, etc. }; return cleanup; -
Document Your Code: Add comments to explain complex logic or unusual patterns.
-
Keep It Simple: Start with a simple plugin and add features incrementally.
Example Plugins
For inspiration, check out these example plugins in the BetterSEQTA+ codebase:
-
Timetable Plugin: Enhances the SEQTA timetable view with zoom controls and filtering options.
- Location:
src/plugins/built-in/timetable/index.ts
- Location:
-
Notification Collector: Improves the notification system in SEQTA Learn.
- Location:
src/plugins/built-in/notification-collector/index.ts
- Location:
Troubleshooting
Plugin Not Loading
- Check that your plugin is properly registered
- Verify that there are no TypeScript errors
- Look for error messages in the console
Plugin Not Working as Expected
- Ensure that your plugin's
enabledsetting is true - Check that your selectors match the SEQTA DOM structure
- Use
console.logstatements to debug your code
TypeScript Errors
- Make sure your interfaces are properly defined
- Check that you're using the correct types for the plugin API
- Verify that your plugin implements the
Plugininterface correctly