Skip to content

Commit

Permalink
Support for activity file validation and display of multiple error me…
Browse files Browse the repository at this point in the history
…ssages.
  • Loading branch information
barnettwilliam committed Nov 3, 2023
1 parent b0193a5 commit 9649dc8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 37 deletions.
94 changes: 74 additions & 20 deletions platform/src/ActivityManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ActivityManager {
customActivitiesUrl = false;
toolsUrl;
customToolsUrl= false;
configErrors = [];
activities = {};
activeSubMenu;

Expand Down Expand Up @@ -42,7 +43,7 @@ class ActivityManager {
}
}

this.fetchActivities();
this.configErrors = this.configErrors.concat(this.fetchActivities());

for(var activityKey of Object.keys(this.activities)) {
this.resolveActionReferences( this.activities[activityKey].id );
Expand Down Expand Up @@ -90,42 +91,88 @@ class ActivityManager {
/**
* Fetches all the activities from activitiesUrl
* and populates the activities array
* @returns errors from parsing and validation
*/
fetchActivities() {

let file = this.fileHandler.fetchFile( this.activitiesUrl , urlParamPrivateRepo() )
let fileContent = file.content;

let errors = [];

if (fileContent != null){

let config = parseConfigFile(fileContent);
let validatedConfig = this.parseAndValidateActivityConfig(fileContent);

if ( validatedConfig.errors.length == 0 ){

this.createActivitiesMenu(validatedConfig.config);

} else {
// Error config file parsing error
errors = errors.concat(validatedConfig.errors);
}
}

return errors;
}

/**
* Parses and validates an activity file
* @param {*} activityFile
* @returns object containing the validated config file object and an array of errors
*/
parseAndValidateActivityConfig(activityFile){
let validationResult = {};

validationResult.errors = [];

let config = parseConfigFile(activityFile);

if ( !(config instanceof Error) ){

for (const activity of config.activities) {
validationResult.config = config;
// TODO - validate activity configuration

if (activity.id) {
this.storeActivity(activity);
this.createActivityMenuEntry(null, activity);
}
else {
var active = false;
for (const nestedActivity of activity.activities) {
this.storeActivity(nestedActivity);
if (nestedActivity.id == this.activityId) {
active = true;
}
}
} else {
validationResult.errors.push(config);
validationResult.config = null;
}

return validationResult;
}

var subMenu = this.createActivitiesSubMenu(activity.title, active);
/**
* Create the activities menu
* @param {*} config valid activities configuration object
*/
createActivitiesMenu(config){

for (const nestedActivity of activity.activities) {
this.createActivityMenuEntry(subMenu, nestedActivity);
for (const activity of config.activities) {

if (activity.id) {
this.storeActivity(activity);
this.createActivityMenuEntry(null, activity);
}
else {
var active = false;
for (const nestedActivity of activity.activities) {
this.storeActivity(nestedActivity);
if (nestedActivity.id == this.activityId) {
active = true;
}
}
}
}

var subMenu = this.createActivitiesSubMenu(activity.title, active);

for (const nestedActivity of activity.activities) {
this.createActivityMenuEntry(subMenu, nestedActivity);
}
}
}
}


subMenuNumber = 0;

createActivitiesSubMenu(title, active = false) {
Expand Down Expand Up @@ -406,6 +453,13 @@ class ActivityManager {
}
}

/**
* Returns the errors found parsing and validating the activty configuration file
* @returns array of errors
*/
getConfigErrors(){
return this.configErrors;
}

}

Expand Down
13 changes: 13 additions & 0 deletions platform/src/EducationPlatformError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

class EducationPlatformError extends Error {

constructor(message){

super(message);

this.name= "EducationPlatformError";
}

}

export {EducationPlatformError}
16 changes: 11 additions & 5 deletions platform/src/Playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'metro4';
import { FileHandler } from './FileHandler.js';
import { ActivityManager } from './ActivityManager.js';
import { ToolManager as ToolsManager } from './ToolsManager.js';
import { EducationPlatformError } from './EducationPlatformError.js'

import { ConsolePanel } from "./ConsolePanel.js";
import { ProgramPanel } from "./ProgramPanel.js";
Expand Down Expand Up @@ -140,8 +141,16 @@ function initialiseActivity(){
initialisePanels();

} else {

// No activity configuration has been given
displayErrors([new EducationPlatformError("No activity configuration has been specified.")]);
}
}

function displayErrors(errors){

let errorText = "";
errors.forEach((err) => errorText += err.message + " \n\n");

const contentPanelName = "content-panel";

panels.push(new BlankPanel(contentPanelName));
Expand All @@ -155,9 +164,8 @@ function initialiseActivity(){
fit();

var contentPanelDiv = document.getElementById(contentPanelName);
var content = document.createTextNode("No activity configuration has been specified.");
var content = document.createTextNode(errorText);
contentPanelDiv.append(content);
}
}

function initialisePanels() {
Expand Down Expand Up @@ -200,8 +208,6 @@ function initialisePanels() {
}




/**
* Create a panel for a given panel config entry
*
Expand Down
30 changes: 18 additions & 12 deletions platform/src/Utility.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { parse as yamlParse} from 'yaml'
import { parse as yamlParse, YAMLParseError} from 'yaml'

export const ARRAY_ANY_ELEMENT = '*';

Expand Down Expand Up @@ -179,25 +179,31 @@ export function isAuthenticated(){
* Parses the platform configuration files, YAML and JSON types are supported.
* @param {String} contents the configuration file contents
* @param {String} extension the configuration file extenstion
* @returns the parsed configuration object
* @returns the parsed configuration object or an error
*/
export function parseConfigFile(contents, extension="yml"){

let configObject;

switch(extension){
case "json":
configObject= JSON.parse(contents);
break;
try {
switch(extension){
case "json":
configObject= JSON.parse(contents);
break;


case "yml":
configObject= yamlParse(contents);
break;
case "yml":
configObject= yamlParse(contents);
break;

default:
console.log("Cannont parse unsupported configuration file type '" + extension + "'.");
configObject = null;
default:
console.log("Cannont parse unsupported configuration file type '" + extension + "'.");
configObject = null;
}
} catch(e){
if (e instanceof YAMLParseError || e instanceof SyntaxError){
configObject = e;
}
}

return configObject;
Expand Down
17 changes: 17 additions & 0 deletions platform/test/spec/testUtilitySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ describe("Utility", () => {
expect(result).toEqual(expectedObject);
})

it("parseConfigFile - an invald yaml file returns an error", ()=> {

let result = parseConfigFile(INVALID_FILE, "yml");

expect(result).toBeInstanceOf(Error);
})

it("parseConfigFile - an invald json file returns an error", ()=> {

let result = parseConfigFile(INVALID_FILE, "json");

expect(result).toBeInstanceOf(Error);
})
})

const JSON_ACTIVITY_CONFIG= "{\n"
Expand Down Expand Up @@ -542,3 +555,7 @@ const YML_ACTIVITY_CONFIG= "activities:\n"
+ " tools:\n"
+ " - http://127.0.0.1:8070/epsilon_tool.json\n"
+ "";

const INVALID_FILE = "{ \n"
+ "----------------- \n"
+ "]";

0 comments on commit 9649dc8

Please sign in to comment.