-
Notifications
You must be signed in to change notification settings - Fork 27
Activity Package
An activity package is an npm package which exports one or more activity types conforming to the ActivityPackageT specification. Each activity package carries with it its own metadata, configuration specification along with its version, its activity runner, and possibly a dashboard. Activity packages should live in ./ac/
, and have an id and a directory name starting with ac-
.
To make FROG aware of an activity package, it needs to be added to ./frog/package.json
, as well as to ./frog/imports/activityTypes.js
. This is done automatically by the createPackage.js
script.
The type definition of an activity type is as follows.
export type ActivityPackageT = {
id: string,
type: 'react-component',
configVersion: number,
upgradeFunctions?: { [version: string]: (Object) => Object },
meta: {
name: string,
shortName?: string,
shortDesc: string,
description: string,
exampleData?: {
title: string,
config?: Object,
data?: any,
learningItems?: any,
type?: 'deeplink'
}[],
preview?: boolean
},
config: Object,
configUI?: Object,
dataStructure?: any,
validateConfig?: validateConfigFnT[],
mergeFunction?: (dataUnitStructT, Object, any, ?Object) => void,
dashboards?: { [name: string]: DashboardT },
exportData?: (config: Object, product: activityDataT) => string,
formatProduct?: (
config: Object,
item: any,
instanceId: string,
username?: string
) => any,
ConfigComponent?: React.ComponentType<{
configData: Object,
setConfigData: Object => void,
formContext: Object
}>,
LearningItems?: LearningItemT<*>[]
};
This type definition should be explicitly imported into the index.js
of an activity package, and used on the default export. Here is an example:
export default ({
id: 'ac-video',
type: 'react-component',
configVersion: 1,
meta,
config,
ActivityRunner,
Dashboard: null,
dataStructure,
mergeFunction
}: ActivityPackageT);
This means that the shape of all the required or optional objects and functions are automatically checked, and ensures that you will find out if the central API changes in the future.
All activity types have a unique id (id
), which should be the same as the package directory name, and the package name in package.json (except in the case of a single activity package exporting several activity types).
Currently, the only supported type
is 'react-component'.
The meta
object contains the name
, which will be shown in the graph editor and preview interface, a shortDesc
and description
, which will be shown in the activity picker in the graph editor, as well as an exampleData
object.
Example data is used in the preview functionality (and might in the future be used for automatic testing). The structure should be for each array item, a title (shown in the preview picker), a config object, and a data object. For example from ac-chat
:
const meta = {
name: 'Chat',
shortDesc: 'Chat component',
description: 'Persistent text chat',
exampleData: [
{
title: 'Empty chat',
config: { title: 'Example chat' },
data: []
},
{
title: 'Chat with some messages',
config: { title: 'Example chat' },
data: [
{ id: '1', msg: 'This is the first message', user: 'Ole' },
{
id: '2',
msg: "I don't agree, but we can discuss it",
user: 'Petter'
}
]
}
]
};
Activities are usually configurable - this could be necessary information, like the url
for a video player, or modifying how the activity works, like whether the video should be autoplaying, whether the students should be allowed to enter new ideas in a brainstorming interface, etc. When the designer adds an activity to a graph, and chooses this activity type, they will be asked to configure the activity based on the configuration specification.
We use react-jsonschema-form
to render the configuration forms. You can experiment with their live playground. In addition to the standard fields, we also offer a special fields, socialAttribute
, which lets designers pick an incoming groupingKey
that has not been used as the activity's primary groupingKey
(see Flow of social structure. This could be used if you wanted students to see or have access to different actions based on their social structure.
You can configure the display of the form through configUI
, for example to make fields conditional of other fields (ie. if condition is not fulfilled, a field will not be displayed). The condition can either be the string id of another field (which should be a boolean), or a function that takes formData
as input, and outputs true/false. Example:
const configUI = {
socialEdit: { conditional: 'formBoolean' },
grouping: { conditional: formData => !formData.individual }
}
It is important to be able to validate the configuration of the activity, to make sure that activities will have the information it needs at run time. To do this, there are two approaches. The first is to add obligatory fields to the config definition itself. Here is an example:
const config = {
type: 'object',
required: ['text'],
properties: {
text: {
type: 'string',
title: 'Guidelines'
},
formBoolean: {
type: 'boolean',
title: 'Should students submit new ideas?',
default: true
}
}
};
Fields are also automatically validated according to their types (string, number, etc). For more complex validations, we offer the field validateConfig
, which should contain an array of functions taking formData
as input, and returning either null, or an error object. Example:
const validateConfig = [
data =>
data.image && data.quadrants
? {
err:
'You cannot have both a background image and quadrants at the same time'
}
: null
];