# Extending with plugins
Notifications is built to be a modular, easily extendable system. Using plugins, it is easy to support different data sources or integrate with other systems. For example you could add GraphQL support send events to a analytics platform.
# Core plugins (built-in)
- JSON - A flexible plugin for using JSON data sources, including HTTP/REST endpoints
# Existing Plugins
- JSON Plugin - a flexible plugin that expects an endpoint, api options, and a function to map data to the Notifications default ui.
- Azure Search Plugin - extends Plugin-JSON to autofill necessary assumptions to make queries agains Azure Search.
- Plugin CC Messages - Specifically tailored toward Academy District 20, extends Azure Search plugin to autofill query paramiters in Azure Search, like categories, locations and expiration date - times. Assumes a defined schema.
# Planned Plugins
- GraphQL - A flexible plugin for using a GraphQl endpoint for querying data
- ICS - Use iCal/CalDav endpoints as notification sources
- RSS - Use RSS feeds as notification sources
- Google Analytics - Generate metrics for notification usage
# Using plugins
# Via imports
import Asd20NotificationsClient from '@asd20/notifications-client'
import Asd20NotificationsPluginJson from '@asd20/notifications-graphql'
// Create the client
const myClient = new Asd20NotificationsClient()
// Use the plugin passing into config
const myClient = Asd20NotificationsClient({
plugins: [
// Use the plugin
Asd20NotificationsJson({
// Configure the plugin...
endpoint: 'https://mywebsite.com/endpoint'
// ...
})
]
})
# Using CDN in HTML/JS
<html>
<body>
<script src="//unpkg.com/@asd20/notifications-client"></script>
<script src="//unpkg.com/@asd20/notifications-plugin-json"></script>
<script>
// Create the client
const myClient = Asd20NotificationsClient({
plugins: [
// Use the plugin
Asd20NotificationsJson({
// Configure the plugin...
endpoint: 'https://mywebsite.com/endpoint'
// ...
})
]
})
</script>
</body>
</html>
# Creating your own plugins
NOTE: This section is a work-in-progress
Creating new plugins is pretty straight forward. To get started, simply install our hygen generator and create a plugin following the spec.
Note:
When naming packages, we recommend using the following naming convention.
asd20-notifications-[your-plugin-name]
# Install hygen (https://www.hygen.io/)
npm i -g hygen-add hygen
# Create a project directory
mkdir asd20-notifications-my-plugin
cd asd20-notifications-my-plugin
# Add the generator
hygen-add https://github.com/academydistrict20/notifications-package-generator
# Generate a package
hygen package new
# Plugin Specifications
Each plugin should provide a function with returns an object matching the NotificationsPlugin interface.
// Example simple component
export default function MySimplePlugin(config) {
return {
/**
* The unique name of the plugin.
*
* e.g. 'jsonPlugin'
*
* @type {string}
* @memberof NotificationsPlugin
*/
name: 'MyPlugin'
/**
* Loads notifications.
*
* @returns {Promise<Notification[]>}
* @memberof NotificationsPlugin
*/
async load() {
// 1. Load notifications from a source (e.g. API / file, etc.)
// 2. Map data to an array notifications
// 3. return the array
}
/**
* Given an array of notification,
* return notifications grouped by type.
*
* @param {Notification[]} notifications
* @returns {NotificationsByType}
* @memberof NotificationsPlugin
*/
groupByType(notifications) {
// Return an object with properties for each type of notification
return {
banner: [],
floating: [],
inline: [],
status: []
}
},
/**
* Return false to prevent dismission
*
* @param {Notification} notification
* @returns {boolean}
* @memberof NotificationsPlugin
*/
beforeDismiss(notification) {
// Your plugin can optionally Decide if it's ok to dismiss a notification
return true
}
/**
* Called when a notification has been dismissed
*
* @param {Notification} notification
* @memberof NotificationsPlugin
*/
onDismiss(notification) {
// Your plugin could react to a notification being dismissed.
// For example, you could trigger an analytics event
}
/**
* Called when a notification has been clicked
*
* @param {Notification} notification
* @memberof NotificationsPlugin
*/
onClick(notification) {
// Your plugin could react to a notification being clicked.
// For example, you could trigger an analytics event
}
},
}
# Plugin Configuration
When using plugins, users can pass in configuration. This can be different for each plugin, but by default it looks something like the following:
const jsonPlugin: JsonNotificationsPlugin = {
name: 'azureSearchPlugin',
async load(): Promise<Notification[]> {
if (!config || !config.endpoint) return []
const config: NotificationsPluginConfig = {
...config,
config: {
data: {
allCategories: ['Weather'],
allLocations: ['District'],
},
endpoint: 'https://asd20-search-dev.search.windows.net/indexes/messages-index/docs/search',
requestOptions: {
method: 'POST',
},
dataTransformer(data) {
return data.value.map((d) => ({
id: d.id,
title: d.title,
summary: d.description,
description: d.description,
startDateTime: d.startDateTime,
endDateTime: d.endDateTime,
categories: d.categories,
}))
},
},
}
let data = await request(config.endpoint, config.requestOptions)
if (config.dataTransformer && typeof config.dataTransformer === 'function') {
data = config.dataTransformer(data)
}
if (Array.isArray(data)) {
data = data.map((d) => mapObjectToNotification(d, config.propertyMap))
} else {
data = [mapObjectToNotification(data, config.propertyMap)]
}
return data
},
groupByType(notifications: Notification[]): NotificationsByType {
return {
banner: notifications.filter((n) => n.categories.includes('Emergency')),
floating: notifications.filter((n) => !n.categories.includes('Emergency')),
}
},
}