Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swik 1827 loading indicator for info panel #754

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7e59b60
Improved the efficiency when loading InfoPanel and InfoPanelView.
Feb 8, 2018
24d0af9
Removed temporary logging for debugging purposes.
Feb 9, 2018
a696627
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
kadevgraaf Feb 9, 2018
011a371
fix linking errors
kadevgraaf Feb 9, 2018
cd39196
Fixed the code style problem.
Feb 9, 2018
8cecbee
Merge branch 'swik-1827-loading-indicator-for-info-panel' of github.c…
Feb 9, 2018
e3d66ab
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
kadevgraaf Feb 19, 2018
0ecf5b9
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
Feb 22, 2018
91c8dba
Added loading indicator on the right side of the slide view.
Feb 23, 2018
dc110f2
Removed unnecessary logging.
Feb 23, 2018
ea22d0c
When removing the loading indicator taken into account if the activit…
Feb 23, 2018
86b7419
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
kadevgraaf Mar 14, 2018
32a917b
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
kadevgraaf Apr 23, 2018
06e3372
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
kadevgraaf Jun 7, 2018
aa0ad36
Merge remote-tracking branch 'origin/master' into swik-1827-loading-i…
Sep 20, 2018
645f55f
Merge remote-tracking branch 'origin/swik-1827-loading-indicator-for-…
Sep 20, 2018
2026f74
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
abijames Sep 24, 2018
4417aed
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
vkovtun Oct 23, 2018
71898e1
Fixed merging error.
Oct 23, 2018
9a75ebe
update reveal.js
kadevgraaf Oct 29, 2018
9befdbe
Merge branch 'master' into swik-1827-loading-indicator-for-info-panel
Nov 30, 2018
6aef2be
Fixed not working loading indicator after someone deleted InfoPanel.j…
Nov 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ migrate
.idea/
package-lock.json
custom_modules
*.iml
2 changes: 2 additions & 0 deletions actions/activityfeed/loadActivities.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default function loadActivities(context, payload, done) {
return;
}

context.dispatch('LOAD_ACTIVITIES_LOAD', {loadingIndicator: true});

context.service.read('activities.list', payload, {timeout: 20 * 1000}, (err, res) => {
if (err) {
log.error(context, {filepath: __filename});
Expand Down
9 changes: 5 additions & 4 deletions actions/loadContributors.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ export default function loadContributors(context, payload, done) {
return;
}

if (!payload.params.language) payload.params.language = context.getStore(TranslationStore).currentLang;
context.dispatch('LOAD_CONTRIBUTORS_LOAD', {loadingIndicator: true});

if (!payload.params.language) {
payload.params.language = context.getStore(TranslationStore).currentLang;
}

context.service.read('contributors.list', payload, {timeout: 20 * 1000}, (err, res) => {
if (err) {
Expand All @@ -30,9 +34,6 @@ export default function loadContributors(context, payload, done) {
// context.dispatch('UPDATE_MODULE_TYPE_SUCCESS', {moduleType: 'contributors'});
}
let pageTitle = shortTitle + ' | Contributors | ' + payload.params.stype + ' | ' + payload.params.sid;
//context.dispatch('UPDATE_PAGE_TITLE', {
// pageTitle: pageTitle
//});
done();
});
}
36 changes: 36 additions & 0 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,42 @@ export default {
return a.substring(0,2).toLowerCase() === b.substring(0,2).toLowerCase();
},

equals: (x, y) => {
if (x === y) return true;
// if both x and y are null or undefined and exactly the same

if (! (x instanceof Object) || ! (y instanceof Object)) return false;
// if they are not strictly equal, they both need to be Objects

if (x.constructor !== y.constructor) return false;
// they must have the exact same prototype chain, the closest we can do is
// test there constructor.

for (let p in x) {
if (! x.hasOwnProperty(p)) continue;
// other properties were tested using x.constructor === y.constructor

if (! y.hasOwnProperty(p)) return false;
// allows to compare x[p] and y[p] when set to undefined

if (x[p] === y[p]) continue;
// if they have the same strict value or identity then they are equal

if (typeof(x[p]) !== 'object') return false;
// Numbers, Strings, Functions, Booleans must be strictly equal

if (! exports.default.equals(x[p], y[p])) return false;
// Objects and Arrays must be tested recursively
}

for (let p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) return false;
// allows x[p] to be set to undefined
}

return true;
},

//ISO6391 language codes from https://pkgstore.datahub.io/core/language-codes/language-codes_csv/data/b65af208b52970a4683fa8fde9af8e9f/language-codes_csv.csv
translationLanguages: [
'de',
Expand Down
3 changes: 1 addition & 2 deletions components/Deck/ActivityFeedPanel/ActivityFeedPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ class ActivityFeedPanel extends React.Component {

return (
<div ref="activityFeedPanel">
<h4 className="ui header" >Activity Feed
</h4>
<h4 className="ui header" >Activity Feed</h4>
<div className="ui basic segment" style={panelDIVStyles}>
{activityDIV}
</div>
Expand Down
2 changes: 2 additions & 0 deletions components/Deck/ActivityFeedPanel/ActivityList.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class ActivityList extends React.Component {
// TODO: same as in the ActivityFeedStore; check if there is more elegant way to tell the component that action loadMoreActivities (in the onScroll function) was executed
if (!nextProps.ActivityFeedStore.wasFetch) return;
this.loading = false;
let activitiesCount = this.props.ActivityFeedStore.activities.length;
console.log('ActivityList.componentWillReceiveProps() [' + 'activitiesCount=' + activitiesCount + ']');
}
render() {
return (
Expand Down
52 changes: 40 additions & 12 deletions components/Deck/Deck.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,49 @@ import SlideEditLeftPanel from './SlideEditLeftPanel/SlideEditLeftPanel';
import ContentPanel from './ContentPanel/ContentPanel';
import NavigationPanel from './NavigationPanel/NavigationPanel';
import ContentModulesPanel from './ContentModulesPanel/ContentModulesPanel';
//import ActivityFeedPanel from './ActivityFeedPanel/ActivityFeedPanel';
//import ServiceUnavailable from '../Error/ServiceUnavailable';//NOTE error code has been refactored - this component doesn't exist anymore, code was moved to Error.js in same directory
import InfoPanelInfoView from './InfoPanel/InfoPanelInfoView';
import TranslationStore from '../../stores/TranslationStore';
import { FormattedMessage, defineMessages } from 'react-intl';
import ContributorsStore from '../../stores/ContributorsStore';
import {equals} from '../../common';

class Deck extends React.Component {

handleExpandClick(){
this.context.executeAction(hideLeftColumn, {});
return false;
constructor(props) {
super(props);
this.isLoading = this.isContentUndefined();
}
handleCollapseClick(){
this.context.executeAction(restoreDeckPageLayout, {});
return false;

// handleExpandClick(){
// this.context.executeAction(hideLeftColumn, {});
// return false;
// }
//
// handleCollapseClick(){
// this.context.executeAction(restoreDeckPageLayout, {});
// return false;
// }

shouldComponentUpdate(nextProps, nextState) {
let samePropsState = equals(this.props, nextProps);
this.isLoading = this.isContentUndefined();
// Content should be updated only when properties have changed.
return !this.isLoading && !samePropsState;
}

componentWillReceiveProps(nextProps) {
this.isLoading = this.isContentUndefined();
}

componentWillUnmount() {
this.props.ContributorsStore.contributors = [];
this.isLoading = true;
}

isContentUndefined() {
return this.props.ContributorsStore.contributors === undefined
|| this.props.ContributorsStore.contributors === [];
}

render() {
const error = this.props.ServiceErrorStore.error;
let status = this.props.DeckPageStore.componentsStatus;
Expand Down Expand Up @@ -212,7 +239,7 @@ class Deck extends React.Component {
rightPanel = (
<div className={rightColClass}>
<div className={treePanelClass}>
<InfoPanelInfoView />
<InfoPanelInfoView loadingIndicator={this.props.ContributorsStore.loadingIndicator}/>
</div>

<div className="ui hidden divider"></div>
Expand Down Expand Up @@ -251,12 +278,13 @@ Deck.contextTypes = {
executeAction: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
Deck = connectToStores(Deck, [DeckPageStore, ServiceErrorStore, UserProfileStore, TranslationStore], (context, props) => {
Deck = connectToStores(Deck, [DeckPageStore, ServiceErrorStore, UserProfileStore, TranslationStore, ContributorsStore], (context, props) => {
return {
DeckPageStore: context.getStore(DeckPageStore).getState(),
ServiceErrorStore: context.getStore(ServiceErrorStore).getState(),
UserProfileStore: context.getStore(UserProfileStore).getState(),
TranslationStore: context.getStore(TranslationStore).getState()
TranslationStore: context.getStore(TranslationStore).getState(),
ContributorsStore: context.getStore(ContributorsStore).getState()
};
});
export default Deck;
17 changes: 14 additions & 3 deletions components/Deck/InfoPanel/InfoPanelInfoView.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ActivityFeedPanel from '../ActivityFeedPanel/ActivityFeedPanel';
import ContributorsPanel from '../ContentModulesPanel/ContributorsPanel/ContributorsPanel';
import PresentationsPanel from './PresentationsPanel';
import ActivityFeedStore from '../../../stores/ActivityFeedStore';
import {getLanguageName, equals} from '../../../common';
import TranslationStore from '../../../stores/TranslationStore';
import PermissionsStore from '../../../stores/PermissionsStore';
import {defineMessages} from 'react-intl';
Expand All @@ -16,8 +17,9 @@ import ContentStore from '../../../stores/ContentStore';

class InfoPanelInfoView extends React.Component {

constructor(props){
constructor(props) {
super(props);
this.isLoading = true;
this.messages = defineMessages({
});

Expand All @@ -26,6 +28,13 @@ class InfoPanelInfoView extends React.Component {
this.resetZoom = this.resetZoom.bind(this);
}

shouldComponentUpdate(nextProps, nextState) {
const samePropsState = equals(this.props, nextProps);
this.isLoading = nextProps.loadingIndicator;
// Content should be updated only when properties have changed.
return !samePropsState;
}

zoomIn() {
this.context.executeAction(zoom, { mode: this.props.ContentStore.mode, direction: 'in' });
}
Expand All @@ -43,12 +52,13 @@ class InfoPanelInfoView extends React.Component {
let showZoomControls = this.props.ContentStore.selector.stype === 'slide';

let deckId = selector.get('id');
if (deckId) {
if (deckId) {
deckId = deckId.split('-')[0];
}

return (
<div className="ui container" ref="infoPanel" role="complementary" aria-labelledby="infopanel-title">
{this.isLoading && <div className="ui active dimmer"><div className="ui text loader">Loading</div></div>}
{
showZoomControls &&
<div className="ui top attached basic buttons menu" role="menu">
Expand Down Expand Up @@ -78,8 +88,8 @@ class InfoPanelInfoView extends React.Component {
</NavLink>
</div>
}
<div className="ui attached segment">

<div className="ui attached segment">
<ContributorsPanel />
</div>
<div className="ui attached segment">
Expand Down Expand Up @@ -110,6 +120,7 @@ InfoPanelInfoView.contextTypes = {
executeAction: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};

InfoPanelInfoView= connectToStores(InfoPanelInfoView, [ActivityFeedStore, DeckTreeStore, TranslationStore, PermissionsStore, ContentStore], (context, props) => {
return {
ActivityFeedStore: context.getStore(ActivityFeedStore).getState(),
Expand Down
15 changes: 14 additions & 1 deletion stores/ActivityFeedStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ class ActivityFeedStore extends BaseStore {
this.selector = {};
this.hasMore = true;
this.presentations = [];
this.loadingIndicator = false;
}
updateActivities(payload) {
this.activities = payload.activities;
this.activityType = payload.activityType;
this.selector = payload.selector;
this.hasMore = payload.hasMore;
this.loadingIndicator = false;
this.emitChange();
}
loadMoreActivities(payload) {
Expand All @@ -29,6 +31,7 @@ class ActivityFeedStore extends BaseStore {
}
updateActivityType(payload) {
this.activityType = payload.activityType;
this.loadingIndicator = false;
this.emitChange();
}
// incrementLikes(payload) {
Expand Down Expand Up @@ -61,6 +64,7 @@ class ActivityFeedStore extends BaseStore {
// }
addActivity(payload) {
const activity = payload.activity;
this.loadingIndicator = false;
if (activity_types_to_display.includes(activity.activity_type) && (this.selector.stype === activity.content_kind && this.selector.sid.split('-')[0] === activity.content_id.split('-')[0] ||
activity.activity_type === 'move' && this.selector.stype === 'deck' && this.selector.sid.split('-')[0] === activity.move_info.source_id.split('-')[0])) {
this.activities.unshift(activity);//add to the beginning
Expand All @@ -72,6 +76,7 @@ class ActivityFeedStore extends BaseStore {
}
}
addActivities(payload) {
this.loadingIndicator = false;
payload.activities.forEach((activity) => {
if (activity_types_to_display.includes(activity.activity_type) && (this.selector.stype === activity.content_kind && this.selector.sid.split('-')[0] === activity.content_id.split('-')[0])) {
this.activities.unshift(activity);//add to the beginning
Expand All @@ -84,6 +89,7 @@ class ActivityFeedStore extends BaseStore {
this.emitChange();
}
addLikeActivity(payload) {
this.loadingIndicator = false;
if (payload.selector.stype === 'deck') {
let activity = {
activity_type: 'react',
Expand All @@ -105,6 +111,7 @@ class ActivityFeedStore extends BaseStore {
}
}
removeLikeActivity(payload) {
this.loadingIndicator = false;
//find like activity and remove it
if (payload.selector.stype === 'deck') {
let i = 0;
Expand All @@ -121,6 +128,7 @@ class ActivityFeedStore extends BaseStore {
}
}
updatePresentations(payload) {
this.loadingIndicator = false;
// console.log('ActivityFeedStore: updatePresentations', payload);
this.presentations = payload;
this.emitChange();
Expand All @@ -145,6 +153,10 @@ class ActivityFeedStore extends BaseStore {
this.hasMore = state.hasMore;
this.presentations = state.presentations;
}
loading(payload){
this.loadingIndicator = payload.loadingIndicator;
this.emitChange();
}
}

ActivityFeedStore.storeName = 'ActivityFeedStore';
Expand All @@ -159,7 +171,8 @@ ActivityFeedStore.handlers = {
'ADD_ACTIVITIES_SUCCESS': 'addActivities',
'LIKE_ACTIVITY_SUCCESS': 'addLikeActivity',
'DISLIKE_ACTIVITY_SUCCESS': 'removeLikeActivity',
'LOAD_PRESENTATIONS_SUCCESS': 'updatePresentations'
'LOAD_PRESENTATIONS_SUCCESS': 'updatePresentations',
'LOAD_ACTIVITIES_LOAD': 'loading'
};

export default ActivityFeedStore;
13 changes: 11 additions & 2 deletions stores/ContributorsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ class ContributorsStore extends BaseStore {
this.translators = [];
this.listName = '';
this.selector = {};
this.loadingIndicator = false;
}
loading(payload){
this.loadingIndicator = payload.loadingIndicator;
this.emitChange();
}
updateContributors(payload) {
this.contributors = this.getContributors(payload.contributors);
this.creator = this.getCreator(payload.contributors);
this.translators = this.getTranslators(payload.contributors);
this.listName = payload.listName;
this.selector = payload.selector;
this.loadingIndicator = false;
this.emitChange();
}

Expand All @@ -24,7 +30,8 @@ class ContributorsStore extends BaseStore {
contributors: this.contributors,
creator: this.creator,
translators: this.translators,
selector: this.selector
selector: this.selector,
loadingIndicator: this.loadingIndicator
};
}
dehydrate() {
Expand All @@ -35,6 +42,7 @@ class ContributorsStore extends BaseStore {
this.creator = state.creator;
this.translators = state.translators;
this.selector = state.selector;
this.loadingIndicator = state.loadingIndicator;
}

getBasedonRole(role, list) {
Expand All @@ -60,7 +68,8 @@ class ContributorsStore extends BaseStore {

ContributorsStore.storeName = 'ContributorsStore';
ContributorsStore.handlers = {
'LOAD_CONTRIBUTORS_SUCCESS': 'updateContributors'
'LOAD_CONTRIBUTORS_SUCCESS': 'updateContributors',
'LOAD_CONTRIBUTORS_LOAD': 'loading'
};

export default ContributorsStore;