Skip to content
This repository was archived by the owner on Nov 25, 2020. It is now read-only.

Commit ae5d6e2

Browse files
committed
LeftPanel : listen to the alerts widget and display a notification using the tasks when there is something new.
1 parent e3872ab commit ae5d6e2

File tree

3 files changed

+165
-20
lines changed

3 files changed

+165
-20
lines changed

core/src/plugins/gui.ajax/res/js/ui/reactjs/jsx/LeftNavigation.js

Lines changed: 136 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
getInitialState:function(){
5252
return {
5353
statusOpen:true,
54+
blinkingBell: false,
5455
additionalContents:this.parseComponentConfigs(),
5556
workspaces: this.props.pydio.user.getRepositoriesList()
5657
};
@@ -107,6 +108,40 @@
107108
this._timer = global.setTimeout(this.closeNavigation, 300);
108109
},
109110

111+
onAlertPanelBadgeChange: function(paneData, newValue, oldValue, memoData){
112+
if(paneData.id !== 'navigation_alerts'){
113+
return;
114+
}
115+
if(newValue){
116+
this.setState({blinkingBell: newValue, blinkingBellClass:paneData.options['titleClassName']});
117+
}else{
118+
this.setState({blinkingBell: false});
119+
}
120+
121+
if(newValue && newValue !== oldValue){
122+
if(Object.isNumber(newValue)){
123+
if(oldValue !== '' && newValue > oldValue){
124+
let notifText = 'Something happened!';
125+
if(memoData instanceof PydioDataModel){
126+
let node = memoData.getRootNode().getFirstChildIfExists();
127+
if(node){
128+
if(paneData.options['tipAttribute']){
129+
notifText = node.getMetadata().get(paneData.options['tipAttribute']);
130+
}else{
131+
notifText = node.getLabel();
132+
}
133+
}
134+
}
135+
AlertTask.setCloser(this.openNavigation.bind(this));
136+
let title = global.pydio.MessageHash[paneData.options.title] || paneData.options.title;
137+
let alert = new AlertTask(title, notifText);
138+
alert.show();
139+
}
140+
}
141+
}
142+
143+
},
144+
110145
render:function(){
111146
const additional = this.state.additionalContents.map(function(paneData){
112147
if(paneData.type == 'ListProvider'){
@@ -115,17 +150,23 @@
115150
pydio={this.props.pydio}
116151
paneData={paneData}
117152
nodeClicked={this.listNodeClicked}
153+
onBadgeChange={this.onAlertPanelBadgeChange}
118154
/>
119155
);
120156
}else{
121157
return null;
122158
}
123159
}.bind(this));
124160

161+
let badge;
162+
if(this.state.blinkingBell){
163+
badge = <span className={"badge-icon icon-bell-alt"}/>;
164+
}
165+
125166
return (
126167
<span>
127168
<div id="repo_chooser" onClick={this.openNavigation} onMouseOver={this.openNavigation} className={this.state.statusOpen?"open":""}>
128-
<span className="icon-reorder"/>
169+
<span className="icon-reorder"/>{badge}
129170
</div>
130171
<div className={"left-panel" + (this.state.statusOpen?'':' hidden')} onMouseOver={this.closeMouseover} onMouseOut={this.closeMouseout}>
131172
{additional}
@@ -139,45 +180,107 @@
139180
}
140181
});
141182

183+
class AlertTask extends PydioTasks.Task{
184+
185+
constructor(label, statusMessage){
186+
super({
187+
id : 'local-alert-task-' + Math.random(),
188+
userId : global.pydio.user.id,
189+
wsId : global.pydio.user.activeRepository,
190+
label : label,
191+
status : PydioTasks.Task.STATUS_PENDING,
192+
statusMessage : statusMessage,
193+
className : 'alert-task'
194+
});
195+
}
196+
197+
show(){
198+
this._timer = global.setTimeout(function(){
199+
this.updateStatus(PydioTasks.Task.STATUS_COMPLETE);
200+
}.bind(this), 7000);
201+
PydioTasks.Store.getInstance().enqueueLocalTask(this);
202+
}
203+
204+
updateStatus(status, statusMessage = ''){
205+
this._internal['status'] = status;
206+
this._internal['statusMessage'] = statusMessage;
207+
this.notifyMainStore();
208+
}
209+
210+
notifyMainStore(){
211+
PydioTasks.Store.getInstance().notify("tasks_updated");
212+
}
213+
214+
hasOpenablePane(){
215+
return true;
216+
}
217+
openDetailPane(){
218+
AlertTask.close();
219+
}
220+
221+
static setCloser(click){
222+
AlertTask.__CLOSER = click;
223+
}
224+
225+
static close(){
226+
AlertTask.__CLOSER();
227+
}
228+
229+
}
230+
231+
232+
142233
var DataModelBadge = React.createClass({
143234

144235
propTypes:{
145236
dataModel:React.PropTypes.instanceOf(PydioDataModel),
146-
options:React.PropTypes.object
237+
options:React.PropTypes.object,
238+
onBadgeIncrease: React.PropTypes.func,
239+
onBadgeChange: React.PropTypes.func
147240
},
148241

149242
getInitialState:function(){
150243
return {value:''};
151244
},
152245

153246
componentDidMount:function(){
154-
var options = this.props.options;
155-
var dm = this.props.dataModel;
247+
let options = this.props.options;
248+
let dm = this.props.dataModel;
249+
let newValue = '';
156250
this._observer = function(){
157251
switch (options.property){
158252
case "root_children":
159253
var l = dm.getRootNode().getChildren().size;
160-
this.setState({value:l?l:''});
254+
newValue = l ? l : 0;
161255
break;
162256
case "root_label":
163-
this.setState({value:dm.getRootNode().getLabel()});
257+
newValue = dm.getRootNode().getLabel();
164258
break;
165259
case "root_children_empty":
166260
var cLength = dm.getRootNode().getChildren().size;
167-
this.setState({value:!cLength?options['emptyMessage']:''});
261+
newValue = !cLength?options['emptyMessage']:'';
168262
break;
169263
case "metadata":
170264
if(options['metadata_sum']){
171-
var sum = 0;
265+
newValue = 0;
172266
dm.getRootNode().getChildren().forEach(function(c){
173-
if(c.getMetadata().get(options['metadata_sum'])) sum += parseInt(c.getMetadata().get(options['metadata_sum']));
267+
if(c.getMetadata().get(options['metadata_sum'])) newValue += parseInt(c.getMetadata().get(options['metadata_sum']));
174268
});
175-
this.setState({value:sum?sum:''});
176269
}
177270
break;
178271
default:
179272
break;
180273
}
274+
let prevValue = this.state.value;
275+
if(newValue && newValue !== prevValue){
276+
if(Object.isNumber(newValue) && this.props.onBadgeIncrease){
277+
if(prevValue !== '' && newValue > prevValue) this.props.onBadgeIncrease(newValue, prevValue ? prevValue : 0, this.props.dataModel);
278+
}
279+
}
280+
if(this.props.onBadgeChange){
281+
this.props.onBadgeChange(newValue, prevValue, this.props.dataModel);
282+
}
283+
this.setState({value: newValue});
181284
}.bind(this);
182285
dm.getRootNode().observe("loaded", this._observer);
183286
},
@@ -202,7 +305,9 @@
202305
paneData:React.PropTypes.object,
203306
pydio:React.PropTypes.instanceOf(Pydio),
204307
nodeClicked:React.PropTypes.func,
205-
startOpen:React.PropTypes.bool
308+
startOpen:React.PropTypes.bool,
309+
onBadgeIncrease: React.PropTypes.func,
310+
onBadgeChange: React.PropTypes.func
206311
},
207312

208313
getInitialState:function(){
@@ -225,6 +330,20 @@
225330
this.setState({open:!this.state.open, componentLaunched:true});
226331
},
227332

333+
onBadgeIncrease: function(newValue, prevValue, memoData){
334+
if(this.props.onBadgeIncrease){
335+
this.props.onBadgeIncrease(this.props.paneData, newValue, prevValue, memoData);
336+
if(!this.state.open) this.toggleOpen();
337+
}
338+
},
339+
340+
onBadgeChange(newValue, prevValue, memoData){
341+
if(this.props.onBadgeChange){
342+
this.props.onBadgeChange(this.props.paneData, newValue, prevValue, memoData);
343+
if(!this.state.open) this.toggleOpen();
344+
}
345+
},
346+
228347
render:function(){
229348

230349
var messages = this.props.pydio.MessageHash;
@@ -236,7 +355,12 @@
236355

237356
var badge;
238357
if(paneData.options.dataModelBadge){
239-
badge = <DataModelBadge dataModel={this.state.dataModel} options={paneData.options.dataModelBadge} />;
358+
badge = <DataModelBadge
359+
dataModel={this.state.dataModel}
360+
options={paneData.options.dataModelBadge}
361+
onBadgeIncrease={this.onBadgeIncrease}
362+
onBadgeChange={this.onBadgeChange}
363+
/>;
240364
}
241365
var emptyMessage;
242366
if(paneData.options.emptyChildrenMessage){

core/src/plugins/gui.ajax/res/themes/orbit/css/pydio.css

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6725,15 +6725,27 @@ div.dialogButtons.inlineEdition input {
67256725
height: 20px;
67266726
width: 15px;
67276727
transition: all 550ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
6728+
position: relative;
67286729
}
6729-
#repo_chooser:hover {
6730-
background-color: #353535;
6731-
color: white;
6730+
#repo_chooser span.badge-icon {
6731+
display: inline;
6732+
position: absolute;
6733+
font-size: 7px;
6734+
top: 32px;
6735+
left: 24px;
6736+
background-color: #222;
6737+
padding: 2px 2px;
6738+
border-radius: 7px;
6739+
color: #fff;
6740+
transition: all 550ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
67326741
}
67336742
#repo_chooser.disabled {
67346743
display: none;
67356744
}
6736-
#repo_chooser.open {
6745+
#repo_chooser:hover,
6746+
#repo_chooser:hover span.badge-icon,
6747+
#repo_chooser.open,
6748+
#repo_chooser.open span.badge-icon {
67376749
background-color: #353535;
67386750
}
67396751
#repo_chooser span.icon-sitemap {

core/src/plugins/gui.ajax/res/themes/orbit/css/theme/widgets.less

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,23 @@
1414
height: 20px;
1515
width: 15px;
1616
transition: @bezier_transition;
17-
&:hover{
18-
background-color: @leftpanel_background_color;
19-
color: white;
17+
position: relative;
18+
span.badge-icon{
19+
display: inline;
20+
position: absolute;
21+
font-size: 7px;
22+
top: 32px;
23+
left: 24px;
24+
background-color: #222;
25+
padding: 2px 2px;
26+
border-radius: 7px;
27+
color: #fff;
28+
transition: @bezier_transition;
2029
}
2130
&.disabled{
2231
display:none;
2332
}
24-
&.open{
33+
&:hover, &:hover span.badge-icon, &.open, &.open span.badge-icon{
2534
background-color: @leftpanel_background_color;
2635
}
2736
span.icon-sitemap {

0 commit comments

Comments
 (0)