Skip to content

Commit c1268b0

Browse files
committed
Imported components from totaljs/flow
1 parent f4b74d1 commit c1268b0

File tree

117 files changed

+5990
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+5990
-0
lines changed

analytics/analytics-run.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// TEST INTERFACE FOR TOTAL.JS FLOW COMPONENT
2+
require('total.js');
3+
require('./flow');
4+
FLOWINIT(require('./' + U.getName(process.argv[1].replace(/\-run\.js$/, ''))));
5+
6+
// `assert` is a global variable
7+
8+
// ====================
9+
// GLOBAL METHODS
10+
// ====================
11+
12+
// FLOWDATA(data) - sends data to component
13+
// FLOWCLICK() - performs click event
14+
// FLOWSIGNAL([data]) - sends signal to component
15+
// FLOWEMIT(event, [data]) - emits an event
16+
// FLOWOPTIONS(options) - simulates a change of options
17+
// FLOWCLOSE([callback]) - simulates closing
18+
// FLOWTRIGGER(name, [data]) - simulates trigger
19+
// FLOWDEBUG(true/false) - enables internal output from console (default: true)
20+
// FLOWUNINSTALL() - uninstalls component
21+
// FLOWINSTANCE - a component instance
22+
23+
// ====================
24+
// EVENTS FOR UNIT-TEST
25+
// ====================
26+
27+
// ON('flow.ready') - triggered when the flow system is ready
28+
// ON('flow.data', fn(data)) - triggered when FLOWDATA() is executed
29+
// ON('flow.send', fn(index, data)) - triggered when the component performs `component.send()`
30+
// ON('flow.options', fn(options)) - triggered when FLOWPTIONS() is executed
31+
// ON('flow.signal', fn(index, data)) - triggered when FLOWSIGNAL() is executed
32+
// ON('flow.status', fn(text, style)) - triggered when the component performs `component.status()`
33+
// ON('flow.debug', fn(data, style)) - triggered when the component performs `component.debug()`
34+
// ON('flow.close') - triggered when the component is closed
35+
36+
ON('flow.ready', function() {
37+
FLOWOPTIONS({ fn: 'next(value.temperature)', type: 'max', format: '{0}%' });
38+
setTimeout(function() {
39+
FLOWDATA({ temperature: 30 });
40+
FLOWEMIT('service', 1);
41+
FLOWDATA({ temperature: 33 });
42+
FLOWEMIT('service', 2);
43+
FLOWDATA({ temperature: 25 });
44+
FLOWDATA({ temperature: 20 });
45+
FLOWDATA({ temperature: 35 });
46+
FLOWEMIT('service', 3);
47+
FLOWDATA({ temperature: 35 });
48+
FLOWDATA({ temperature: 35 });
49+
FLOWDATA({ temperature: 35 });
50+
FLOWDATA({ temperature: 35 });
51+
}, 1000);
52+
});

analytics/analytics.js

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
exports.id = 'analytics';
2+
exports.title = 'Analytics';
3+
exports.version = '1.0.0';
4+
exports.author = 'Peter Širka';
5+
exports.group = 'Databases';
6+
exports.color = '#D770AD';
7+
exports.input = true;
8+
exports.output = 1;
9+
exports.options = { fn: 'next(value.temperature);', format: '{0} °C', decimals: 2 };
10+
exports.readme = `# Analytics
11+
12+
Creates analytics automatically according a value. The value must be a number. The output is \`Object\`:
13+
14+
\`\`\`javascript
15+
{
16+
count: 2, // {Number} count of analyzed values in the hour
17+
decimals: 0, // {Number} count of decimals
18+
format: '{0} °C', // {String} custom defined format, "{0}" will be a value
19+
period: 'hourly' // {String} period "hourly" or "daily"
20+
previous: 15, // {Number} previous calculated value
21+
raw: 32.3 // {Number} last raw value
22+
type: 'max', // {String} type of analytics
23+
value: 32.3, // {Number} last calculated value
24+
}
25+
\`\`\``;
26+
27+
exports.html = `<div class="padding">
28+
<div data-jc="dropdown" data-jc-path="type" class="m" data-options=";@(Hourly: Sum values)|sum;@(Hourly: A maximum value)|max;@(Hourly: A minimum value)|min;@(Hourly: An average value)|avg;@(Hourly: An average (median) value)|median;@(Daily: Sum values)|Dsum;@(Daily: A maximum value)|Dmax;@(Daily: A minimum value)|Dmin;@(Daily: An average value)|Davg;@(Daily: An average (median) value)|Dmedian" data-required="true">@(Type)</div>
29+
<div data-jc="codemirror" data-jc-path="fn" data-type="javascript" class="m">@(Analyzator)</div>
30+
<div class="row">
31+
<div class="col-md-3 m">
32+
<div data-jc="textbox" data-jc-path="format" data-placeholder="@(e.g. {0} °C)" data-maxlength="10" data-align="center">@(Format)</div>
33+
</div>
34+
<div class="col-md-3 m">
35+
<div data-jc="textbox" data-jc-path="decimals" data-maxlength="10" data-align="center" data-increment="true" data-jc-type="number">@(Decimals)</div>
36+
</div>
37+
</div>
38+
</div>`;
39+
40+
exports.install = function(instance) {
41+
42+
const Fs = require('fs');
43+
const DOC = {};
44+
45+
var fn = null;
46+
var dbname = 'analytics_' + instance.id;
47+
var temporary = F.path.databases(dbname + '.json');
48+
var cache = {};
49+
var current = {};
50+
51+
cache.datetime = F.datetime;
52+
cache.count = 0;
53+
cache.avg = { count: 0, sum: 0 };
54+
cache.number = 0;
55+
cache.raw = 0;
56+
cache.median = [];
57+
58+
instance.on('close', function() {
59+
Fs.unlink(temporary, NOOP);
60+
});
61+
62+
instance.on('data', function(response) {
63+
fn && fn(response.data, function(err, value) {
64+
65+
if (err || value == null)
66+
return;
67+
68+
var type = typeof(value);
69+
if (type === 'string') {
70+
value = value.parseFloat2();
71+
type = 'number';
72+
}
73+
74+
if (isNaN(value))
75+
return;
76+
77+
cache.count++;
78+
cache.raw = value;
79+
80+
switch (instance.options.type) {
81+
case 'max':
82+
case 'Dmax':
83+
cache.number = cache.number === null ? value : Math.max(cache.number, value);
84+
break;
85+
case 'min':
86+
case 'Dmin':
87+
cache.number = cache.number === null ? value : Math.min(cache.number, value);
88+
break;
89+
case 'sum':
90+
case 'Dsum':
91+
cache.number = cache.number === null ? value : cache.number + value;
92+
break;
93+
case 'avg':
94+
case 'Davg':
95+
cache.avg.count++;
96+
cache.avg.sum += value;
97+
cache.number = cache.avg.sum / cache.avg.count;
98+
break;
99+
case 'median':
100+
case 'Dmedian':
101+
cache.median.push(value);
102+
cache.median.sort((a, b) => a - b);
103+
var half = Math.floor(cache.median.length / 2);
104+
cache.number = cache.median.length % 2 ? cache.median[half] : (cache.median[half - 1] + cache.median[half]) / 2.0;
105+
break;
106+
}
107+
108+
current.previous = current.value;
109+
current.value = cache.number;
110+
current.raw = cache.raw;
111+
current.format = instance.options.format;
112+
current.type = instance.options.type[0] === 'D' ? instance.options.type.substring(1) : instance.options.type;
113+
current.count = cache.count;
114+
current.period = instance.options.type[0] === 'D' ? 'daily' : 'hourly';
115+
current.decimals = instance.options.decimals;
116+
current.datetime = F.datetime;
117+
instance.connections && instance.send(current);
118+
instance.custom.status();
119+
EMIT('flow.analytics', instance, current);
120+
});
121+
});
122+
123+
instance.on('service', function() {
124+
if (fn) {
125+
instance.custom.save();
126+
instance.custom.save_temporary();
127+
}
128+
});
129+
130+
instance.custom.status = function() {
131+
var number = cache.number;
132+
if (number == null)
133+
return;
134+
number = number.format(instance.options.decimals || 0);
135+
instance.status(cache.format ? cache.format.format(number) : number);
136+
};
137+
138+
instance.custom.save_temporary = function() {
139+
Fs.writeFile(temporary, JSON.stringify(cache), NOOP);
140+
};
141+
142+
instance.custom.current = function() {
143+
return current;
144+
};
145+
146+
instance.custom.save = function() {
147+
148+
if (instance.options.type[0] === 'D') {
149+
if (cache.datetime.getDate() === F.datetime.getDate())
150+
return;
151+
} else {
152+
if (cache.datetime.getHours() === F.datetime.getHours())
153+
return;
154+
}
155+
156+
DOC.id = +cache.datetime.format('yyyyMMddHH');
157+
DOC.year = cache.datetime.getFullYear();
158+
DOC.month = cache.datetime.getMonth() + 1;
159+
DOC.day = cache.datetime.getDate();
160+
DOC.hour = cache.datetime.getHours();
161+
DOC.week = +cache.datetime.format('w');
162+
DOC.count = cache.count;
163+
DOC.value = cache.number;
164+
DOC.type = cache.type[0] === 'D' ? cache.type.substring(1) : cache.type;
165+
DOC.period = cache.type[0] === 'D' ? 'daily' : 'hourly';
166+
DOC.format = cache.format;
167+
DOC.datecreated = F.datetime;
168+
169+
NOSQL(dbname).update(DOC, DOC).where('id', DOC.id);
170+
171+
cache.count = 0;
172+
cache.number = null;
173+
174+
switch (instance.options.type) {
175+
case 'median':
176+
case 'Dmedian':
177+
cache.median = [];
178+
break;
179+
case 'avg':
180+
case 'Davg':
181+
cache.avg.count = 0;
182+
cache.avg.sum = 0;
183+
break;
184+
}
185+
186+
cache.datetime = F.datetime;
187+
};
188+
189+
instance.custom.reconfigure = function() {
190+
var options = instance.options;
191+
192+
if (!options.type) {
193+
instance.status('Not configured', 'red');
194+
fn = null;
195+
return;
196+
}
197+
198+
cache.type = options.type;
199+
cache.format = options.format;
200+
201+
fn = SCRIPT(options.fn);
202+
instance.custom.status();
203+
};
204+
205+
instance.on('options', instance.custom.reconfigure);
206+
instance.custom.stats = (callback) => callback(null, NOSQL(dbname));
207+
instance.custom.reconfigure();
208+
209+
Fs.readFile(temporary, function(err, data) {
210+
if (err)
211+
return;
212+
var dt = cache.datetime || F.datetime;
213+
var tmp = data.toString('utf8').parseJSON(true);
214+
if (tmp && tmp.datetime) {
215+
cache = tmp;
216+
if (cache.type[0] === 'D')
217+
cache.datetime.getDate() !== dt.getDate() && instance.custom.save();
218+
else
219+
cache.datetime.getHours() !== dt.getHours() && instance.custom.save();
220+
instance.custom.status();
221+
}
222+
});
223+
};

analytics/readme.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Analytics
2+
3+
Creates analytics automatically according a value. The value must be a number. The output is `Object`:
4+
5+
```javascript
6+
{
7+
count: 2, // {Number} count of analyzed values in the hour
8+
decimals: 0, // {Number} count of decimals
9+
format: '{0} °C', // {String} custom defined format, "{0}" will be a value
10+
period: 'hourly' // {String} period "hourly" or "daily"
11+
previous: 15, // {Number} previous calculated value
12+
raw: 32.3 // {Number} last raw value
13+
type: 'max', // {String} type of analytics
14+
value: 32.3, // {Number} last calculated value
15+
}
16+
```

comment/comment.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
exports.id = 'comment';
2+
exports.title = 'Comment';
3+
exports.group = 'Common';
4+
exports.color = '#704cff';
5+
exports.author = 'Martin Smola';
6+
exports.icon = '';
7+
exports.readme = `# Comment`;
8+
9+
exports.install = function(instance) {
10+
11+
};

comment/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Comment

condition/condition-run.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// TEST INTERFACE FOR TOTAL.JS FLOW COMPONENT
2+
require('total.js');
3+
require('./flow');
4+
FLOWINIT(require('./' + U.getName(process.argv[1].replace(/\-run\.js$/, ''))));
5+
6+
// `assert` is a global variable
7+
8+
// ====================
9+
// GLOBAL METHODS
10+
// ====================
11+
12+
// FLOWDATA(data) - sends data to component
13+
// FLOWCLICK() - performs click event
14+
// FLOWSIGNAL([data]) - sends signal to component
15+
// FLOWEMIT(event, [data]) - emits an event
16+
// FLOWOPTIONS(options) - simulates a change of options
17+
// FLOWCLOSE([callback]) - simulates closing
18+
// FLOWTRIGGER(name, [data]) - simulates trigger
19+
// FLOWDEBUG(true/false) - enables internal output from console (default: true)
20+
// FLOWUNINSTALL() - uninstalls component
21+
// FLOWINSTANCE - a component instance
22+
23+
// ====================
24+
// EVENTS FOR UNIT-TEST
25+
// ====================
26+
27+
// ON('flow.ready') - triggered when the flow system is ready
28+
// ON('flow.data', fn(data)) - triggered when FLOWDATA() is executed
29+
// ON('flow.send', fn(index, data)) - triggered when the component performs `component.send()`
30+
// ON('flow.options', fn(options)) - triggered when FLOWPTIONS() is executed
31+
// ON('flow.signal', fn(index, data)) - triggered when FLOWSIGNAL() is executed
32+
// ON('flow.status', fn(text, style)) - triggered when the component performs `component.status()`
33+
// ON('flow.debug', fn(data, style)) - triggered when the component performs `component.debug()`
34+
// ON('flow.close') - triggered when the component is closed
35+
36+
ON('flow.ready', function() {
37+
FLOWOPTIONS({ condition: 'return value === \'FLOW\'' });
38+
FLOWDATA('TOTAL');
39+
FLOWDATA('FLOW');
40+
});

0 commit comments

Comments
 (0)