Rendering a Uniform StaticAppBar Component across all SUSI Web Clients on all Routes.

The Problem - We have three SUSI Web Clients namely Webchat Skills CMS Accounts And it’s important to keep the design guidelines in sync across all the clients, StaticAppBar is a component which forms the header of all the pages and thus it is important to keep it uniform in all clients which was clearly missing before. There is also a lot of code duplication of the AppBar component (in accounts app) since it is used on all the pages so our approach will be to prepare a single component and render it on all routes. Tackling the problem - Since the StaticAppBar component is present on all the clients we simply make the menu items uniform across all the clients and apply a check on those menu items on which are a premium feature or should appear only once the user is logged in. Building blocks of the StaticAppBar component AppBar SUSI logo on the left end Drop down hamburger menu on the right Here’s how the JSX for the StaticAppBar component in CMS looks like, it uses an AppBar component from the material-ui library and has several props and styling as per the requirement. <AppBar className='topAppBar' id='appBar' title={<div id='rightIconButton' ><Link to='/' style={{ float: 'left', marginTop: '-10px',height:'25px',width:'122px' }}> <img src={susiWhite} alt='susi-logo' className='siteTitle' /></Link></div>} style={{ backgroundColor: colors.header, height: '46px', boxShadow: 'none', margin: '0 auto', }} iconStyleRight={{ marginTop: '-2px' }} iconElementRight={<TopRightMenu />} />   TopRightMenu is a function that returns JSX for the hamburger dropdown and is rendered in the AppBar as depicted below. It is a conditional menubar meaning some menu items are only rendered when the user is logged in and thus this helps cover those features which should only be available to logged in users. After that we use a popover component which shows up when the 3 dots or the expander on the top right is clicked. Almost all of the components in material ui has a style prop so styling is easy for the components moreover the workflow for the popover click goes like once the expander is clicked a boolean state variable named showOptions is toggled which in turn toggles the opening or closing state of the Popover as per the open prop. let TopRightMenu = (props) => ( <div onScroll={this.handleScroll}> <div> {cookies.get('loggedIn') ? (<label style={{color: 'white', fontSize: '16px', verticalAlign:'super'}}> {cookies.get('emailId')} </label>) : (<label> </label>) } <IconMenu {...props} iconButtonElement={ <IconButton iconStyle={{ fill: 'white' }}><MoreVertIcon /></IconButton> } targetOrigin={{ horizontal: 'right', vertical: 'top' }} anchorOrigin={{ horizontal: 'right', vertical: 'top' }} onTouchTap={this.showOptions} > </IconMenu> <Popover {...props} animated={false} style={{ float: 'right', position: 'relative', marginTop: '46px', marginLeft: leftGap }} open={this.state.showOptions} anchorEl={this.state.anchorEl} anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} targetOrigin={{ horizontal: 'right', vertical: 'top' }} onRequestClose={this.closeOptions} > <TopRightMenuItems /> {cookies.get('loggedIn') ? (<MenuItem primaryText='Botbuilder' containerElement={<Link to='/botbuilder' />} rightIcon={<Extension />} />) : null } <MenuItem primaryText='Settings' containerElement={<Link to='/settings' />} rightIcon={<Settings />} /> {cookies.get('loggedIn') ? (<MenuItem primaryText='Logout' containerElement={<Link to='/logout' />} rightIcon={<Exit />} />) : (<MenuItem primaryText='Login' onTouchTap={this.handleLogin} rightIcon={<LoginIcon />} />) } </Popover> </div> </div> ); Handling the conditional display of menu items based on the…

Continue ReadingRendering a Uniform StaticAppBar Component across all SUSI Web Clients on all Routes.

Displaying skill rating for each skill on skill page of SUSI SKILL CMS

SUSI exhibits several skills which are managed by the SUSI Skill CMS, it essentially is a client which allows users to create/update skills conveniently since for each skill it is important to have the functionality of rating system so developers can get to know which skills are performing better than the rest and consequently improve them, thus a skill rating system which allows the users to give positive or negative feedback for each skill is implemented on the server. Fetching skill_rating from the server Fetch skill data for which ratings are to be displayed through ajax calls API Endpoint - /cms/getSkillMetadata.json?… Parse the received metadata object to get positive and negative ratings for that skill if(skillData.skill_rating) { let positive_rating = skillData.skill_rating.positive; let negative_rating = skillData.skill_rating.negative; } Sample API response { "skill_metadata": { "model": "general", "group": "Knowledge", "language": "en", "developer_privacy_policy": null, "descriptions": "Want to know about fossasia, just ask susi to tell that, Susi tells about the SUSI.AI creators", "image": "images/creator_info.png", "author": "madhav rathi", "author_url": "https://github.com/madhavrathi", "author_email": null, "skill_name": "Creator Info", "terms_of_use": null, "dynamic_content": false, "examples": [ "Who created you?", "what is fossasia?" ], "skill_rating": { "negative": "0", "positive": "0", "stars": { "one_star": 0, "four_star": 0, "five_star": 0, "total_star": 0, "three_star": 0, "avg_star": 0, "two_star": 0 }, "feedback_count": 0 }, "creationTime": "2018-03-17T16:38:29Z", "lastAccessTime": "2018-06-15T15:51:50Z", "lastModifiedTime": "2018-03-17T16:38:29Z" }, "accepted": true, "message": "Success: Fetched Skill's Metadata", "session": {"identity": { "type": "host", "name": "162.158.166.37_d80fb5c9", "anonymous": true }} } Set the react state of the component to store positive and negative rating. this.setState({ positive_rating, negative_rating }) Use react-icons to fetch like and dislike icon components from font-awesome. npm i -S react-icons Import the corresponding icons in the SkillPage component import { FaThumbsOUp, FaThumbsODown } from 'react-icons/lib/fa/' Display the rating count along with their icons <div className="rating"> <div className="positive"> <FaThumbsOUp /> {this.state.positive_rating} </div> <div className="negative"> <FaThumbsODown /> {this.state.negative_rating} </div> </div> Example References react-icons npm package Blog on icons as react components - https://medium.com/@david.gilbertson/icons-as-react-components-de3e33cb8792

Continue ReadingDisplaying skill rating for each skill on skill page of SUSI SKILL CMS

Using a Git repo as a Storage & Managing skills through susi_skill_cms

In this post, I’ll be talking about SUSI’s skill management and the workflow of creating new skills The SUSI skills are maintained in a separate github repository susi_skill_data which provides the features of version controlling and the ability to rollback to a previous version implemented in SUSI Server. The workflow is as explained in the featured image of this blog, SUSI CMS provides the user with a GUI through which user can talk to the SUSI Server and using it’s api calls, it can manipulate the susi skills present/stored on the susi_skill_data repository. When the user opts to create a new skill, a new createSkill component is loaded with an editor to define rules of the skill. Once the form is submitted, an AJAX POST request is made to the server which actually commits the skill data to the repository and thus it is visible in the CMS from that point on. Grab the skill details within the editor and put them in a form which is to be sent via the POST request. let form = new FormData(); form.append('model', 'general'); form.append('group', this.state.groupValue); form.append('language', this.state.languageValue); form.append('skill', this.state.expertValue.trim().replace(/\s/g,'_')); form.append('image', this.state.file); form.append('content', this.state.code); form.append('image_name', this.state.imageUrl.replace('images/','')); form.append('access_token', cookies.get('loggedIn')); Configure POST request settings object let settings = { 'async': true, 'crossDomain': true, 'url': urls.API_URL + '/cms/createSkill.json', 'method': 'POST', 'processData': false, 'contentType': false, 'mimeType': 'multipart/form-data', 'data': form }; Make an AJAX request using the settings above to upload the skill to the server and send a notification when the request is successful. $.ajax(settings) .done(function (response) { self.setState({ loading:false }); notification.open({ message: 'Accepted', description: 'Your Skill has been uploaded to the server', icon: <Icon type='check-circle' style={{ color: '#00C853' }} />, }); Parse the received response as JSON and if the accept key in the response is true, we push the new skill data to the history API and set relevant states. let data = JSON.parse(response); if(data.accepted===true){ self.props.history.push({ pathname: '/' + self.state.groupValue + '/' + self.state.expertValue.trim().replace(/\s/g,'_') + '/' + self.state.languageValue, state: { from_upload: true, expertValue: self.state.expertValue, groupValue: self.state.groupValue , languageValue: self.state.languageValue, }}); If the accepted key of the server response is not true, display a notification. else{ self.setState({ loading:false }); notification.open({ message: 'Error Processing your Request', description: String(data.message), icon: <Icon type='close-circle' style={{ color: '#f44336' }} />, }); }}) Handle cases when AJAX request fails and send a corresponding notification .fail(function (jqXHR, textStatus) { ... notification.open({ message: 'Error Processing your Request', description: String(textStatus), icon: <Icon type='close-circle' style={{ color: '#f44336' }} />, }); }); I hope after reading this post, the objectives of susi_skill_data are more clear and you understood how CMS handles the creation of skills. Resources 1.AJAX Jquery - AJAX request using Jquery 2. React State - Read about React states and lifecycle hooks.

Continue ReadingUsing a Git repo as a Storage & Managing skills through susi_skill_cms