diff --git a/README.md b/README.md index 22b8af2c..2692e51c 100644 --- a/README.md +++ b/README.md @@ -458,18 +458,37 @@ So the idea is that we have a `uiCommands` object and at a point, there will be ### Learning Analytics Dashboard integration -- `sendGenericDataForLearningAnalyticsDashboard`: This function will send data for the bbb to render inside the plugin's table +This integration allow you to insert/update entry in LAD (Learning Analytics Dashboard) via `upsertUserData` function and also delete entries via `deleteUserData` function. -The object structure of this function's argument must be: +It's an object available in the `pluginApi` that wraps those 3 functions: + +- `pluginApi.learningAnalyticsDashboard.upsertUserData` +- `pluginApi.learningAnalyticsDashboard.deleteUserData` +- `pluginApi.learningAnalyticsDashboard.clearAllUsersData` + +For the `upsert` function, the argument's data object structure must be: ```ts -interface GenericDataForLearningAnalyticsDashboard { - cardTitle: string; // Yet to be implemented (future updates) +interface LearningAnalyticsDashboardUserData { + cardTitle: string; columnTitle: string; value: string; } ``` +For the `deleteUserData` function, the argument's data object structure must be: + +```ts +interface LearningAnalyticsDashboardDeleteUserData { + cardTitle: string; + columnTitle: string; +} +``` + +For the `clearAllUsersData` function, the argument is the cardTitle (optionally), and when it's not sent, all the entries for a specific plugin will be deleted. (And if the card ends up empty, it will be removed) + +If the user is a moderator, there is the possibility to publish data on behalf of other users by using the second **optional** parameter named `targetUserId` + So that the data will appear in the following form: | User | Count | `` | @@ -477,6 +496,36 @@ So that the data will appear in the following form: | user-name | 1 | `` | +See example of use ahead: + +```ts +const targetUserId = 'abcd-efg'; +pluginApi.learningAnalyticsDashboard.upsertUserData( + { + cardTitle: 'Example Title', + columnTitle: 'link sent by user', + value: '[link](https://my-website.com/abc.png)' + }, + targetUserId, +); + +pluginApi.learningAnalyticsDashboard.deleteUserData( + { + cardTitle: 'Example Title', + columnTitle: 'link sent by user', + }, + targetUserId, +); + +pluginApi.learningAnalyticsDashboard.clearAllUsersData(columnTitle); + +pluginApi.learningAnalyticsDashboard.clearAllUsersData(); // Or without the Column Title +``` + +Note 1: the `value` field (in the upsert function's argument) supports markdown, so feel free to use it as you wish. + +Note 2: pluginApi.sendGenericDataForLearningAnalyticsDashboard is now being deprecated, but has the same data structure as upsert (without the possibility to send entry on behalf of another user) + ### External data resources This is the new integration with external servers to fetch data in a secure manner. diff --git a/src/core/api/BbbPluginSdk.ts b/src/core/api/BbbPluginSdk.ts index 90d06ded..3fe568fa 100644 --- a/src/core/api/BbbPluginSdk.ts +++ b/src/core/api/BbbPluginSdk.ts @@ -46,7 +46,12 @@ import { useUiData } from '../../ui-data/hooks/hooks'; import { UseMeetingFunction } from '../../data-consumption/domain/meeting/from-core/types'; import { useMeeting } from '../../data-consumption/domain/meeting/from-core/hooks'; import { serverCommands } from '../../server-commands/commands'; -import { sendGenericDataForLearningAnalyticsDashboard } from '../../learning-analytics-dashboard/hooks'; +import { + clearAllUsersData, + deleteUserData, + sendGenericDataForLearningAnalyticsDashboard, + upsertUserData, +} from '../../learning-analytics-dashboard/commands'; import { GenericDataForLearningAnalyticsDashboard } from '../../learning-analytics-dashboard/types'; import { getRemoteData } from '../../remote-data/utils'; import { persistEventFunctionWrapper } from '../../event-persistence/hooks'; @@ -131,6 +136,22 @@ export abstract class BbbPluginSdk { pluginApi.sendGenericDataForLearningAnalyticsDashboard = ( data: GenericDataForLearningAnalyticsDashboard, ) => sendGenericDataForLearningAnalyticsDashboard(data, pluginName); + pluginApi.learningAnalyticsDashboard = { + upsertUserData: (data, targetUserId) => upsertUserData( + data, + pluginName, + targetUserId, + ), + deleteUserData: (data, targetUserId) => deleteUserData( + data, + pluginName, + targetUserId, + ), + clearAllUsersData: (cardTitle?: string) => clearAllUsersData( + pluginName, + cardTitle, + ), + }; pluginApi.getRemoteData = ( dataSourceName: string, ) => getRemoteData(dataSourceName, pluginName); diff --git a/src/core/api/types.ts b/src/core/api/types.ts index 48a66821..24c19b3f 100644 --- a/src/core/api/types.ts +++ b/src/core/api/types.ts @@ -27,7 +27,7 @@ import { GenericContentInterface } from '../../extensible-areas/generic-content- import { UseUiDataFunction } from '../../ui-data/hooks/types'; import { UseMeetingFunction } from '../../data-consumption/domain/meeting/from-core/types'; import { ServerCommands } from '../../server-commands/types'; -import { SendGenericDataForLearningAnalyticsDashboard } from '../../learning-analytics-dashboard/types'; +import { LearningAnalyticsDashboardWrapperObject, SendGenericDataForLearningAnalyticsDashboard } from '../../learning-analytics-dashboard/types'; import { UseUserCameraDomElementsFunction } from '../../dom-element-manipulation/user-camera/types'; import { ScreenshareHelperInterface, UserCameraHelperInterface } from '../../extensible-areas'; import { GetDataSource } from '../../remote-data/types'; @@ -287,12 +287,22 @@ export interface PluginApi { */ useLocaleMessages?: UseLocaleMessagesFunction /** + * @deprecated Use {@link learningAnalyticsDashboard.upsertUserData} object instead. + * * Send data to the Learning analytics dashboard * * @param data - object in which one can render in the learning analytics dashboard * */ sendGenericDataForLearningAnalyticsDashboard?: SendGenericDataForLearningAnalyticsDashboard; + /** + * Wrapper object of functions related to the learning analytics dashboard. + * It contains the following functions: + * - deleteGenericData: Deletes a certain entry in the learning dashboard generic-data; + * - upsertGenericData: Updates or insert a generic data entry in the learning dashboard; + * + */ + learningAnalyticsDashboard?: LearningAnalyticsDashboardWrapperObject; /** * Fetches external data from pre-defined data-source in manifest. * diff --git a/src/learning-analytics-dashboard/commands.ts b/src/learning-analytics-dashboard/commands.ts new file mode 100644 index 00000000..c7bf6b2b --- /dev/null +++ b/src/learning-analytics-dashboard/commands.ts @@ -0,0 +1,81 @@ +import { + LearningAnalyticsDashboardEventDetails, + GenericDataForLearningAnalyticsDashboard, + LearningAnalyticsDashboardUserData, + LearningAnalyticsDashboardDeleteUserData, + ClearLearningAnalyticsDashboardEventDetails, +} from './types'; +import { LearningAnalyticsDashboardEvents } from './enums'; + +export const sendGenericDataForLearningAnalyticsDashboard = ( + data: GenericDataForLearningAnalyticsDashboard, + pluginName: string, +) => { + window.dispatchEvent( + new CustomEvent< + LearningAnalyticsDashboardEventDetails>(LearningAnalyticsDashboardEvents.GENERIC_DATA_SENT, { + detail: { + pluginName, + data, + }, + }), + ); +}; + +export const upsertUserData = ( + data: LearningAnalyticsDashboardUserData, + pluginName: string, + targetUserId?: string, +) => { + window.dispatchEvent( + new CustomEvent< + LearningAnalyticsDashboardEventDetails>( + LearningAnalyticsDashboardEvents.UPSERT_USER_DATA_COMMAND_SENT, + { + detail: { + pluginName, + data, + targetUserId, + }, + }, + ), + ); +}; + +export const deleteUserData = ( + data: LearningAnalyticsDashboardDeleteUserData, + pluginName: string, + targetUserId?: string, +) => { + window.dispatchEvent( + new CustomEvent< + LearningAnalyticsDashboardEventDetails>( + LearningAnalyticsDashboardEvents.DELETE_USER_DATA_COMMAND_SENT, + { + detail: { + pluginName, + data, + targetUserId, + }, + }, + ), + ); +}; + +export const clearAllUsersData = ( + pluginName: string, + cardTitle?: string, +) => { + window.dispatchEvent( + new CustomEvent< + ClearLearningAnalyticsDashboardEventDetails>( + LearningAnalyticsDashboardEvents.CLEAR_ALL_USERS_DATA_COMMAND_SENT, + { + detail: { + pluginName, + cardTitle, + }, + }, + ), + ); +}; diff --git a/src/learning-analytics-dashboard/enums.ts b/src/learning-analytics-dashboard/enums.ts index fe5b568d..e229c343 100644 --- a/src/learning-analytics-dashboard/enums.ts +++ b/src/learning-analytics-dashboard/enums.ts @@ -1,3 +1,6 @@ export enum LearningAnalyticsDashboardEvents { GENERIC_DATA_SENT = 'GENERIC_DATA_FOR_LEARNING_ANALYTICS_DASHBOARD_SENT', + UPSERT_USER_DATA_COMMAND_SENT = 'UPSERT_USER_DATA_COMMAND_FOR_LEARNING_ANALYTICS_DASHBOARD_SENT', + DELETE_USER_DATA_COMMAND_SENT = 'DELETE_USER_DATA_COMMAND_FOR_LEARNING_ANALYTICS_DASHBOARD_SENT', + CLEAR_ALL_USERS_DATA_COMMAND_SENT = 'CLEAR_ALL_USERS_DATA_COMMAND_SENT_COMMAND_FOR_LEARNING_ANALYTICS_DASHBOARD_SENT', } diff --git a/src/learning-analytics-dashboard/hooks.ts b/src/learning-analytics-dashboard/hooks.ts deleted file mode 100644 index 1a1a3766..00000000 --- a/src/learning-analytics-dashboard/hooks.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - LearningAnalyticsDashboardEventDetails, - GenericDataForLearningAnalyticsDashboard, -} from './types'; -import { LearningAnalyticsDashboardEvents } from './enums'; - -export const sendGenericDataForLearningAnalyticsDashboard = ( - data: GenericDataForLearningAnalyticsDashboard, - pluginName: string, -) => { - window.dispatchEvent( - new CustomEvent< - LearningAnalyticsDashboardEventDetails>(LearningAnalyticsDashboardEvents.GENERIC_DATA_SENT, { - detail: { - pluginName, - data, - }, - }), - ); -}; diff --git a/src/learning-analytics-dashboard/types.ts b/src/learning-analytics-dashboard/types.ts index a93c426d..139e93cc 100644 --- a/src/learning-analytics-dashboard/types.ts +++ b/src/learning-analytics-dashboard/types.ts @@ -1,13 +1,70 @@ +// Deprecated Send data function export interface GenericDataForLearningAnalyticsDashboard { cardTitle: string; columnTitle: string; value: string; } +export type SendGenericDataForLearningAnalyticsDashboard = ( + data: GenericDataForLearningAnalyticsDashboard) => void; + +// Upsert function +export interface LearningAnalyticsDashboardUserData { + cardTitle: string; + columnTitle: string; + value: string; +} + +export type UpsertUserDataFunction = ( + data: LearningAnalyticsDashboardUserData, + targetUserId?: string, +) => void; + +// Delete function +export interface LearningAnalyticsDashboardDeleteUserData { + cardTitle: string; + columnTitle: string; +} + +export type DeleteUserDataFunction = ( + data: LearningAnalyticsDashboardDeleteUserData, + targetUserId?: string, +) => void; + +export type ClearUsersDataFunction = (cardTitle?: string) => void; + +// General typing. export interface LearningAnalyticsDashboardEventDetails { pluginName: string; - data: GenericDataForLearningAnalyticsDashboard; + data: GenericDataForLearningAnalyticsDashboard + | LearningAnalyticsDashboardUserData | LearningAnalyticsDashboardDeleteUserData; + targetUserId?: string; } -export type SendGenericDataForLearningAnalyticsDashboard = ( - data: GenericDataForLearningAnalyticsDashboard) => void; +export interface ClearLearningAnalyticsDashboardEventDetails { + pluginName: string; + cardTitle?: string; +} + +export interface LearningAnalyticsDashboardWrapperObject { + /** + * Updates or insert a generic data entry in the learning dashboard for a target user + * (if target user is not passed, current user will be considered); + * + * @param data Data to insert or update + * @targetUserId string representing the internal userId of the target user (Optional) + */ + upsertUserData: UpsertUserDataFunction; + /** + * Deletes generic data entry for target user (if target user is not passed, + * current user will be considered). + * + * @param data Data to be deleted + * @targetUserId string representing the internal userId of the target user (Optional) + */ + deleteUserData: DeleteUserDataFunction; + /** + * Clears all Users Data for a specific plugin. (No arguments required) + */ + clearAllUsersData: ClearUsersDataFunction; +}