mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
802 Commits
0.18.5
...
0.20.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
f309a9d537 | ||
|
a786b37cb9 | ||
|
6a519a30a2 | ||
|
81ae552e69 | ||
|
0ec04a3624 | ||
|
81d5b47fce | ||
|
ed31a0cf15 | ||
|
201d1926bc | ||
|
9ee6655bfa | ||
|
c4beab6b0d | ||
|
34b6643913 | ||
|
98e391b867 | ||
|
19eb8e9a6d | ||
|
43b7aa40c3 | ||
|
747af44fc1 | ||
|
d5ef428edd | ||
|
5fa4d227b8 | ||
|
cc7e3b0c26 | ||
|
473a2ae275 | ||
|
7f5d47f39d | ||
|
6031f146aa | ||
|
020a469f3b | ||
|
091de3aa66 | ||
|
b837f7608c | ||
|
afe9367bac | ||
|
9bd9023cb6 | ||
|
8502cf8498 | ||
|
33dade0584 | ||
|
84cc2ad0fa | ||
|
dc2d3bc7c0 | ||
|
64df557423 | ||
|
715cc77e76 | ||
|
b80d1af3d7 | ||
|
f05f534fd2 | ||
|
c0837ead0e | ||
|
a1f135bd66 | ||
|
978f4ecc58 | ||
|
46a8d96997 | ||
|
c283224000 | ||
|
a6ef755139 | ||
|
29a257d17a | ||
|
368b76a183 | ||
|
8bb861124d | ||
|
2f884ec778 | ||
|
8c561e92c8 | ||
|
633b9180d7 | ||
|
0e2d0e1b6f | ||
|
ea4d65ceee | ||
|
d47ac84d2e | ||
|
a97759aa35 | ||
|
3fcfd4abdd | ||
|
6d771da9a9 | ||
|
6201247875 | ||
|
8c367bcc53 | ||
|
8198132ca7 | ||
|
cf3b4e9e63 | ||
|
987dbf8a92 | ||
|
acf8c9bc4a | ||
|
7173895d36 | ||
|
43530d4a5f | ||
|
fefabef9ee | ||
|
0dd40a941b | ||
|
24b6670bc4 | ||
|
76661abbf5 | ||
|
e9dc9eff9b | ||
|
2f160743bc | ||
|
98616e772c | ||
|
bc014fec9b | ||
|
732598d9d2 | ||
|
2979acd5b8 | ||
|
fd20cd524e | ||
|
7b80ae42e1 | ||
|
b7012674c6 | ||
|
c76bd39280 | ||
|
09cd710f66 | ||
|
d9aadf9d98 | ||
|
86716b5ffb | ||
|
96e3aab3b4 | ||
|
72c78fe3ad | ||
|
abe746020b | ||
|
8e1c15419c | ||
|
ee47646cf7 | ||
|
32d9acdaa5 | ||
|
4eb3bd496b | ||
|
3c4f4d27d6 | ||
|
2060af8a92 | ||
|
21bf74a467 | ||
|
677833a277 | ||
|
0b5e4f2dd7 | ||
|
06a1f30350 | ||
|
c1ff241550 | ||
|
5717f75eac | ||
|
6b3b68a4e5 | ||
|
8bda2d0add | ||
|
bc02c9573c | ||
|
8167608f04 | ||
|
514e31aef9 | ||
|
20a31a6d38 | ||
|
4f0aa1bc02 | ||
|
be0ef6e594 | ||
|
93a8dbd31a | ||
|
cf931e8ddf | ||
|
510bfbf268 | ||
|
2f93bb969b | ||
|
27365c9f7b | ||
|
b1d2e188f5 | ||
|
e4f67df2a1 | ||
|
e094ea3d2a | ||
|
7515b745b5 | ||
|
0e902a7e71 | ||
|
2dfb443625 | ||
|
e6e7747ae1 | ||
|
d80ea6c0f5 | ||
|
ac6e3988a8 | ||
|
bfd98f3767 | ||
|
cc8bc1339f | ||
|
542d1dc600 | ||
|
1c66c88f95 | ||
|
dc880c672a | ||
|
073f38c68c | ||
|
6a6d13b075 | ||
|
9bb7e72c69 | ||
|
7436e01188 | ||
|
3d272d0f10 | ||
|
ee66a12dad | ||
|
47de85b012 | ||
|
f85b63a972 | ||
|
e630919ef8 | ||
|
2e3fd49b40 | ||
|
dd54af2c08 | ||
|
737bf411ff | ||
|
5070b1a6b5 | ||
|
c849da92cf | ||
|
6a4e7201fe | ||
|
ffa6dea452 | ||
|
30c1d31a99 | ||
|
6934a2d5c3 | ||
|
b9906ced9a | ||
|
5500b4fe35 | ||
|
2353f12cd6 | ||
|
1b8cab0f58 | ||
|
869c1d4ea4 | ||
|
9b938195a8 | ||
|
bb3c52821a | ||
|
81c8ae95e2 | ||
|
6098570ab7 | ||
|
d033c24fe5 | ||
|
4995e52dd6 | ||
|
c685a31056 | ||
|
c32ce3bb7b | ||
|
c0d8f904b3 | ||
|
8dba0dac9e | ||
|
d0bf4a5329 | ||
|
7b28ba6078 | ||
|
e6466c3c3a | ||
|
d96d3064d6 | ||
|
d4589ed7e3 | ||
|
5cfc52ea18 | ||
|
3fcacd8339 | ||
|
49fe13f22f | ||
|
4d27ba1bda | ||
|
b715ac8bf4 | ||
|
d96049416f | ||
|
1c4df785fd | ||
|
8f94c5efeb | ||
|
7cffa1ece7 | ||
|
1ac18d7b33 | ||
|
1111d2518b | ||
|
ba7416450e | ||
|
3b02d36acb | ||
|
c2aa9a5337 | ||
|
70fb181b7b | ||
|
e64f4e3f39 | ||
|
e4d518749f | ||
|
7dcca2c907 | ||
|
4a027b8a79 | ||
|
c2c6e6080e | ||
|
4f87ebdf0a | ||
|
09abec15b1 | ||
|
33d0d12bc8 | ||
|
f488869635 | ||
|
6382564727 | ||
|
7476b4c7db | ||
|
daf3e6a47a | ||
|
19b6cba398 | ||
|
5bd3d12c7b | ||
|
c9db74ebca | ||
|
f8a88cc1a4 | ||
|
4a081bf125 | ||
|
8a68a3e861 | ||
|
7a9dd9ad9c | ||
|
6c01d0f9d8 | ||
|
45a53ac168 | ||
|
dabb2790c9 | ||
|
c66c5ea53c | ||
|
0a98ba6985 | ||
|
bb8e491856 | ||
|
5590d31336 | ||
|
dc7e48dc53 | ||
|
371d357218 | ||
|
f22960ad59 | ||
|
34ead436b0 | ||
|
808d5a75ae | ||
|
55e897faac | ||
|
5a5dda21e4 | ||
|
f085655daa | ||
|
5cf9c07b73 | ||
|
9751089807 | ||
|
211eeea05d | ||
|
b2516117f5 | ||
|
2816b3edae | ||
|
242398c724 | ||
|
289583325d | ||
|
0f793ebd65 | ||
|
ce014044ea | ||
|
1064e531f0 | ||
|
dc3128fb3e | ||
|
51a3521834 | ||
|
d40aa7260f | ||
|
fc8c4063f2 | ||
|
f204c77ba3 | ||
|
7a8545273c | ||
|
6a9575e9f4 | ||
|
c13e79e9c3 | ||
|
62088259ae | ||
|
925ebcc06e | ||
|
a20eaf852f | ||
|
84a6a5235e | ||
|
8235b7b96d | ||
|
0376e0d711 | ||
|
6bd0682e8c | ||
|
e24c22f9be | ||
|
673a6bbe2c | ||
|
cf32a33984 | ||
|
f4ca8cd738 | ||
|
98c1bc276d | ||
|
629536b562 | ||
|
422109868d | ||
|
bcc7834650 | ||
|
1161e4f6c1 | ||
|
14435c24ac | ||
|
22ede79799 | ||
|
6cb3699ee9 | ||
|
6c65d3830e | ||
|
cdcf39fe82 | ||
|
1441042458 | ||
|
71403e5acd | ||
|
3d70bc722a | ||
|
b2f50da322 | ||
|
2a50c66df8 | ||
|
8de47c0a6e | ||
|
023391e22a | ||
|
a4ddfd404f | ||
|
7307e558cb | ||
|
47356f5221 | ||
|
c6f8950b64 | ||
|
58c8311d56 | ||
|
071f4eacde | ||
|
f96bdc578e | ||
|
e03a0fffa9 | ||
|
8e2c12f8d9 | ||
|
114420e8fd | ||
|
ba49b2c681 | ||
|
5391fc962a | ||
|
7cec7ae608 | ||
|
d6211af5bd | ||
|
ef114e31c2 | ||
|
fd74a03479 | ||
|
428bf634e9 | ||
|
c49f722e4f | ||
|
d4d95a43b6 | ||
|
8789d983ed | ||
|
10faa96bcf | ||
|
42d31b9ee6 | ||
|
c9dc9b4fe9 | ||
|
a345089c8b | ||
|
67c268e13d | ||
|
f13e02a1a9 | ||
|
d887ab126b | ||
|
1a7868159a | ||
|
c6a1c8e8c4 | ||
|
fba339f666 | ||
|
09d41a9708 | ||
|
ce85c8d986 | ||
|
4630a162af | ||
|
fde157ff50 | ||
|
51f875c02d | ||
|
f0957c838f | ||
|
f5bebef37f | ||
|
80a15089b4 | ||
|
cb35604ef5 | ||
|
61681bb1d6 | ||
|
8edf399631 | ||
|
d5ffd1432f | ||
|
e73bf03615 | ||
|
665fe0e01e | ||
|
1a226c4dc6 | ||
|
a866aa9c18 | ||
|
d9089b798c | ||
|
d34ebd4d1b | ||
|
716aa74004 | ||
|
2aae76c9bc | ||
|
5fc3ca0e23 | ||
|
5bb27109bf | ||
|
7406ab6017 | ||
|
08fccc4e77 | ||
|
c1d50e82e1 | ||
|
9777af7cb5 | ||
|
fd86035865 | ||
|
a8ec032553 | ||
|
66ee27c5fa | ||
|
17a737ca88 | ||
|
f30ff7a2fd | ||
|
c102828a99 | ||
|
cb0e631b85 | ||
|
75e7c0e50d | ||
|
62b2adab78 | ||
|
fc0cf1ff51 | ||
|
0f4d46671f | ||
|
048f9c0294 | ||
|
0529eed0c9 | ||
|
ca77842b5b | ||
|
8c169dc82b | ||
|
195342f7db | ||
|
cfaaef7860 | ||
|
e939d5e96e | ||
|
6fa8b7f5f1 | ||
|
a2d03c14ae | ||
|
c667a0e74c | ||
|
8123828113 | ||
|
72b8dbb45b | ||
|
9f4628cf0a | ||
|
ec4d24af91 | ||
|
7703875740 | ||
|
6442bb8a13 | ||
|
51373f59e2 | ||
|
6cc56879d3 | ||
|
f29d7c9252 | ||
|
2f7f53ed96 | ||
|
da89460830 | ||
|
9e006d42bb | ||
|
4c02bab4ee | ||
|
5800ed41f1 | ||
|
18b5b4901f | ||
|
368418cf56 | ||
|
94031a52a5 | ||
|
d67f91e7ed | ||
|
3e6cadf3d8 | ||
|
f37697c4fb | ||
|
0c5a76b391 | ||
|
69448c7329 | ||
|
8e9815fb91 | ||
|
bf1afcfe8a | ||
|
2980818f0d | ||
|
9da58dbaf0 | ||
|
4cdd7978cf | ||
|
40d81358f4 | ||
|
c7b62aed91 | ||
|
55d71659f8 | ||
|
c0e7d6d826 | ||
|
f809377de8 | ||
|
9767bd9697 | ||
|
3a55528552 | ||
|
56197ffe3a | ||
|
0f0d0c046c | ||
|
8d5b546763 | ||
|
19c9707d62 | ||
|
ecc4973645 | ||
|
79e004a040 | ||
|
3169f93cc2 | ||
|
c1a1a73599 | ||
|
48308db45b | ||
|
3f37e96f78 | ||
|
db1b0ccb79 | ||
|
df161ce672 | ||
|
4e21a5e557 | ||
|
72fe30892e | ||
|
19fa69811b | ||
|
0ddb4c625d | ||
|
d373105b32 | ||
|
36dc1d2f97 | ||
|
11fa2cb35d | ||
|
546f07156f | ||
|
7e7117632d | ||
|
954226da0d | ||
|
38a1291c5b | ||
|
998bf92ad4 | ||
|
974ba40f28 | ||
|
e57d8ba0ef | ||
|
6b79c6135f | ||
|
28b311b7ed | ||
|
dcda513901 | ||
|
72c400794c | ||
|
a747d8c2d5 | ||
|
a3aec6b939 | ||
|
042409f870 | ||
|
5b8f4f4069 | ||
|
d132d63c1d | ||
|
4374506981 | ||
|
ef8b936069 | ||
|
36e3bfffb4 | ||
|
91a38bdb60 | ||
|
f169a68319 | ||
|
ee886f98dd | ||
|
a3826cc6a7 | ||
|
ba33b832ba | ||
|
f6c017176b | ||
|
7a01b115bb | ||
|
1dc021e871 | ||
|
c9f916ebab | ||
|
ff627fd128 | ||
|
bba57f8d2b | ||
|
695873d35a | ||
|
15da19dcea | ||
|
4312a01707 | ||
|
ecd8f97d8b | ||
|
d5bdc1600b | ||
|
dfa077fd5f | ||
|
06abe63fb1 | ||
|
5155770213 | ||
|
9d507b09ca | ||
|
9c4a712dc7 | ||
|
f1d5bbb036 | ||
|
69ed0aebc3 | ||
|
549e56e220 | ||
|
450f4d9a5a | ||
|
6533a9793c | ||
|
2000cadb17 | ||
|
083c321efa | ||
|
f64c4a981f | ||
|
3ac8ce03bf | ||
|
66fca8710e | ||
|
1e245ece46 | ||
|
81efce03ba | ||
|
4e549dd426 | ||
|
52f74ff7e0 | ||
|
3c71b815f5 | ||
|
9efd48fe51 | ||
|
4609ee75b6 | ||
|
963ea4177e | ||
|
17e6940a42 | ||
|
315a9ceba3 | ||
|
a2bdeedb09 | ||
|
da5700d2d7 | ||
|
90e7f30247 | ||
|
3ccf6ba892 | ||
|
e50cd5b745 | ||
|
db77be5d72 | ||
|
c36870c23e | ||
|
e9be007040 | ||
|
9e400d9aa6 | ||
|
490c8dae75 | ||
|
3bcffe375d | ||
|
9f81a591e1 | ||
|
3db5306c70 | ||
|
45029dd084 | ||
|
b01cd30339 | ||
|
09329e1104 | ||
|
ab0fc2ecfa | ||
|
bf5d36d6bd | ||
|
a29527ec96 | ||
|
45e7ad8049 | ||
|
4d54663efd | ||
|
29d386cc51 | ||
|
ba1a67969b | ||
|
390ea5419e | ||
|
0fdeec7cc4 | ||
|
e34d883e50 | ||
|
507871687b | ||
|
ed58f62cd1 | ||
|
94bc4e7125 | ||
|
5832f7930d | ||
|
0066a20c22 | ||
|
774e4bfced | ||
|
054c7a76a4 | ||
|
c7f3b77aac | ||
|
a6a4620374 | ||
|
5148c62d1c | ||
|
6fc863a91e | ||
|
e066a154a1 | ||
|
d432edaed2 | ||
|
8f34f4e80b | ||
|
39b751acf5 | ||
|
bd5e8ba961 | ||
|
ed20327c41 | ||
|
991c68c394 | ||
|
2acc31a4e7 | ||
|
b9733e3dfa | ||
|
bb106bfce7 | ||
|
daf1388a6a | ||
|
8226f1fa75 | ||
|
e675512fa3 | ||
|
65e67b6c3e | ||
|
7612481570 | ||
|
f6c7cb5804 | ||
|
2201c9062f | ||
|
ca3da262da | ||
|
5847f92bef | ||
|
31ee1be81e | ||
|
6bccdd015f | ||
|
cecea318da | ||
|
8663ec6880 | ||
|
9b03f128aa | ||
|
8a51f97616 | ||
|
ee74ed9ce9 | ||
|
0f947c756e | ||
|
cae7949a48 | ||
|
be58b614e1 | ||
|
b0a01fa4b2 | ||
|
9734228001 | ||
|
9df1d44bc4 | ||
|
13d887028a | ||
|
83a8979309 | ||
|
75c29f1cb7 | ||
|
d9d15e41c7 | ||
|
d3598d5854 | ||
|
3a8aaee5d7 | ||
|
4fcf57d42c | ||
|
adb0891335 | ||
|
d21e719cc1 | ||
|
5807ab82c1 | ||
|
65cb04da63 | ||
|
312e3611b1 | ||
|
46acc62279 | ||
|
529b358c9b | ||
|
7fca04404e | ||
|
3a1cc6a2be | ||
|
5b76c91004 | ||
|
cf87837f7d | ||
|
5a0a7b907b | ||
|
6a2b1669b3 | ||
|
ca8264b3f4 | ||
|
b44ecd8819 | ||
|
987942959e | ||
|
91992b48c1 | ||
|
c9a335a6f9 | ||
|
b7ed159b50 | ||
|
c72961a52a | ||
|
afe6afca36 | ||
|
050acd239c | ||
|
24505ee4f5 | ||
|
63a249aba3 | ||
|
7bd94df2a0 | ||
|
761161a8e5 | ||
|
513579a7ee | ||
|
7165483d83 | ||
|
f8bcf219cb | ||
|
590506e306 | ||
|
9a5439c580 | ||
|
6b2f5fbb19 | ||
|
051c147b41 | ||
|
9111adf15f | ||
|
ba18b27371 | ||
|
2a287b2ae6 | ||
|
fc9040f715 | ||
|
0029022ef6 | ||
|
94f728d3fd | ||
|
d53ced7830 | ||
|
053d8c44c2 | ||
|
9f5767ea16 | ||
|
e8d76b0555 | ||
|
c2675600f6 | ||
|
6f087b4ec1 | ||
|
e94708606d | ||
|
c248f1a762 | ||
|
28402b0894 | ||
|
7dd98e99f9 | ||
|
dba195b396 | ||
|
88b153bc12 | ||
|
d4a47dc974 | ||
|
fe3ea6edfd | ||
|
6c8fc4846b | ||
|
b14a0e0dde | ||
|
e982f5076f | ||
|
54d9656f09 | ||
|
42188b9f49 | ||
|
49da324c5d | ||
|
9bf87697fd | ||
|
f368f5a9c4 | ||
|
eea85485e6 | ||
|
1a544b3b82 | ||
|
8b38fe9fe0 | ||
|
1bf4addf63 | ||
|
407e16e900 | ||
|
6e9fe3248a | ||
|
d8cf86fd6f | ||
|
f8aa4a9588 | ||
|
c249907846 | ||
|
57c1524a9a | ||
|
d8d82e2ba3 | ||
|
807b512ef7 | ||
|
b2f06b6777 | ||
|
d7adff9a65 | ||
|
b0d7e11d48 | ||
|
fc9cdb61f2 | ||
|
9c00492dc2 | ||
|
1a6babd199 | ||
|
1b693eed37 | ||
|
afb566b6b4 | ||
|
f870e9ed3e | ||
|
4bcf13cb58 | ||
|
50e2dcbcd5 | ||
|
6104bb98f1 | ||
|
946a6d6041 | ||
|
372c213c2c | ||
|
a5a79d3ab7 | ||
|
e6c5cfb703 | ||
|
7843eccae8 | ||
|
7ca153abd0 | ||
|
33b4774c49 | ||
|
c243481432 | ||
|
80873e4ea9 | ||
|
4e4a1f11e6 | ||
|
9bbe405cd0 | ||
|
c440a4c730 | ||
|
a1251371d7 | ||
|
7d702e8332 | ||
|
43d7c8d48c | ||
|
7423583508 | ||
|
08b0838f9a | ||
|
038d821a7c | ||
|
6a218814d3 | ||
|
905f89b0f5 | ||
|
14882bda78 | ||
|
781fa4634b | ||
|
cdb173fd6e | ||
|
466cb4be89 | ||
|
c39e2ffd56 | ||
|
17bf09e276 | ||
|
bc01f9f8fd | ||
|
c0870c5694 | ||
|
3b5174a2ea | ||
|
af6885f3e8 | ||
|
e01996095f | ||
|
5d86f7b6ba | ||
|
8d6ac6406d | ||
|
40ff54f67e | ||
|
cce7ac09d0 | ||
|
73a18891c5 | ||
|
fe22cedc1d | ||
|
fa09c7c8b2 | ||
|
15e28e3cc0 | ||
|
2cb4f6b1fc | ||
|
b17a483b85 | ||
|
7c3e5443ab | ||
|
f95a2851c8 | ||
|
2b2eee352f | ||
|
11569d8056 | ||
|
bdf87452b6 | ||
|
0c6bf81c24 | ||
|
f2fa26fb07 | ||
|
f5e212ff1e | ||
|
461e6562ca | ||
|
fd67d08402 | ||
|
e6411d11b1 | ||
|
dd81d947fc | ||
|
23b887c30e | ||
|
c4eae3f130 | ||
|
41a04a2849 | ||
|
ed1d34e678 | ||
|
f44487338d | ||
|
7aced85a31 | ||
|
fbe0e2d6eb | ||
|
6e34f0697c | ||
|
a835f9f0cb | ||
|
16715673c3 | ||
|
c48c74f173 | ||
|
f262348497 | ||
|
7185bcd51f | ||
|
28d05e2449 | ||
|
7fafa21a1b | ||
|
84f598e143 | ||
|
e30f8628db | ||
|
0be9c88106 | ||
|
e046fc1ac5 | ||
|
3a476ac493 | ||
|
e33ec0cf50 | ||
|
b4b70a988e | ||
|
e66b381070 | ||
|
771b598c09 | ||
|
cd44f13171 | ||
|
aa6b72ac87 | ||
|
a467fe5ed7 | ||
|
467411c6c3 | ||
|
2648b7ca54 | ||
|
de35c7024a | ||
|
9d219c163d | ||
|
f7434b5ec8 | ||
|
5ed3360c0b | ||
|
6f5974f875 | ||
|
56db1da3cf | ||
|
fef71f29c4 | ||
|
d46b66878a | ||
|
6cad80c4ad | ||
|
68779caa2e | ||
|
2a122ed283 | ||
|
17c5fdf0d5 | ||
|
0835fdd0d1 | ||
|
f6274445a2 | ||
|
3b0300b834 | ||
|
4fbf1fe780 | ||
|
dcf44fed58 | ||
|
7136dc1c72 | ||
|
0e4cedbc5e | ||
|
dc139bcc30 | ||
|
b204b183de | ||
|
ab788bc1e3 | ||
|
95b4c8d515 | ||
|
b025644525 | ||
|
9e87a60597 | ||
|
5a70bea67a | ||
|
2a95af3928 | ||
|
0a0ca380d3 | ||
|
4cfbf7f71c | ||
|
de43148341 | ||
|
0a2aab7d68 | ||
|
745821c420 | ||
|
57c4c754d0 | ||
|
4b5c437533 | ||
|
8d63b6a1ed | ||
|
245a8adbf9 | ||
|
4f7d98aace | ||
|
b0c693cc3a | ||
|
b2cca10e8b | ||
|
a84b2ab5bb | ||
|
4565342b05 | ||
|
0ad54cc2d1 | ||
|
865853da19 | ||
|
392ed706fd | ||
|
0ff0f25aaf | ||
|
c157960846 | ||
|
a5c00b5c81 | ||
|
472bbdb59f | ||
|
7877093713 | ||
|
8cb2e51407 | ||
|
d5cee81fb6 | ||
|
bca020bc4d | ||
|
5069f2844c | ||
|
252df81f59 | ||
|
7f89a4a26f | ||
|
40f4167894 | ||
|
0ef16989cd | ||
|
3df3d6f516 | ||
|
10395ef254 | ||
|
83854c28db | ||
|
fcbea2629c | ||
|
522360dcb7 | ||
|
26bc142cc2 | ||
|
a4eb8e11c3 | ||
|
9fd5d1db56 | ||
|
1d05b4c981 | ||
|
61f6535be8 | ||
|
7dd329b5ee | ||
|
b761904424 | ||
|
36105412b1 | ||
|
184b1b018c | ||
|
f3e1b85d82 | ||
|
626d012775 | ||
|
9ad9c0ec6a | ||
|
e13fed9fc6 | ||
|
eb6d093e56 | ||
|
979713c4db | ||
|
af1ea610ea | ||
|
d4d9190919 | ||
|
4d3d1a02a8 | ||
|
30c2aa96d6 | ||
|
4edb1f80b0 | ||
|
0a82459233 | ||
|
db87b0dfa5 | ||
|
e41d5c249f | ||
|
f82a779817 | ||
|
cd42cf7583 | ||
|
2d5980ff2a | ||
|
df8a8ea204 | ||
|
8957d33e49 | ||
|
d49c7a3adb | ||
|
28fe1e4c8f | ||
|
0c7f4e2168 | ||
|
b22956bd99 | ||
|
42516206d9 | ||
|
fc4edde6e6 | ||
|
54cc04fd96 | ||
|
80062b6a62 | ||
|
99af79fcf3 | ||
|
11d87205d7 | ||
|
5866d414ce | ||
|
9a972b0b8a | ||
|
e6aeeea8c1 | ||
|
5d064aa1d7 | ||
|
34832d5942 | ||
|
e3b1179a21 | ||
|
f94a36613c | ||
|
efc3cc24f4 | ||
|
b47f8aaf70 | ||
|
94ca4607bc | ||
|
2dab1d3e6e | ||
|
825b0fb22f | ||
|
1cdb039ea2 | ||
|
7409cb3abb | ||
|
e8e8f70c27 | ||
|
6e2e36e7a0 | ||
|
9994df9601 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/packages/node_modules/** linguist-generated=false
|
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@@ -8,7 +8,9 @@ If your issue is:
|
||||
- a feature request or suggestion for a change,
|
||||
- or problems with 3rd party (`node-red-contrib-`) nodes
|
||||
|
||||
please use the [mailing list](https://groups.google.com/forum/#!forum/node-red), [slack team](https://nodered.org/slack) or ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -16,7 +16,7 @@ Put an `x` in the boxes that apply
|
||||
<!--
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it **may well get rejected** if it hasn't been discussed on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
|
||||
the [forum](https://discourse.nodered.org) or
|
||||
[slack team](https://nodered.org/slack) first.
|
||||
|
||||
-->
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -17,3 +17,8 @@ node_modules
|
||||
public
|
||||
locales/zz-ZZ
|
||||
nodes/core/locales/zz-ZZ
|
||||
!packages/node_modules
|
||||
packages/node_modules/@node-red/editor-client/public
|
||||
!test/**/node_modules
|
||||
docs
|
||||
!packages/node_modules/**/docs
|
||||
|
@@ -1,5 +1,4 @@
|
||||
/Gruntfile.js
|
||||
/.git/*
|
||||
/lib/*
|
||||
*.backup
|
||||
/public/*
|
||||
|
@@ -1,7 +0,0 @@
|
||||
.settings
|
||||
.jshintignore
|
||||
.jshintrc
|
||||
.project
|
||||
.tern-project
|
||||
.travis.yml
|
||||
.git
|
@@ -4,9 +4,7 @@ matrix:
|
||||
include:
|
||||
- node_js: "10"
|
||||
script:
|
||||
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
||||
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul coveralls
|
||||
- node_js: "8"
|
||||
- node_js: "6"
|
||||
- node_js: "4"
|
||||
|
305
CHANGELOG.md
305
CHANGELOG.md
@@ -1,3 +1,308 @@
|
||||
#### 0.20.0-beta.3: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Update palette manager view properly when module updated
|
||||
- Add TreeList common widget
|
||||
- Fix visual jump when opening Comment editor on Safari Part of #2008
|
||||
- Fix vertical align of markdown editor in Safari Fixes #2008
|
||||
- Avoid marking node as changed if label state is default Fixes #2009
|
||||
- Highlight port on node hover while joining
|
||||
- Support drag-wiring of link nodes
|
||||
- Allow TypeSearch to include a filter option
|
||||
- Improve diff colouring
|
||||
- Allow sections to toggle in 2-element stack
|
||||
- Add support for ${} env var syntax when skipping validation Closes #1980
|
||||
- i18 support for markdown editor tooltip
|
||||
- Add RED.editor.registerTypeEditor for custom type editors
|
||||
- Tidy up markdown toolbar handling across all editors
|
||||
- Added validation while export into library
|
||||
- Reuse notification boxes rather than stack multiple of the same type
|
||||
- Make ssh key dialog accessible when opened from new proj dialog
|
||||
|
||||
Runtime
|
||||
|
||||
- Bump JSONata to 1.6.4 Fixes #2023
|
||||
- Add audit logging to admin api
|
||||
- Fix failure of RED.require #2010
|
||||
- Allow oauth strategy callback method to be customised Closes #1998
|
||||
- Ensure fs context cache is flushed on close Fixes #2001
|
||||
- Fix library Buffer( to Buffer.alloc( for node 10
|
||||
- Catch file-not-found on startup when non-existant flow file specified
|
||||
- Actively expire login sesssions and notify user
|
||||
- Add quotation marks for basic auth challenge #1976
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: remove promises to improve performance
|
||||
- Debug: add ability to apply JSONata expression to message
|
||||
- Join: remove promises to improve performance
|
||||
- JSON: delete msg.schema before sending msg to avoid conflicts
|
||||
- Link: update UI to use common TreeList widget
|
||||
- Switch: remove promises to improve performance
|
||||
|
||||
#### 0.20.0-beta.2: Beta Release
|
||||
|
||||
- Split Node-RED internals into multiple sub-modules
|
||||
|
||||
Editor
|
||||
|
||||
- Allow the editor to use a custom admin api url root
|
||||
- Improve performance of Flow Diff dialog - @TothiViseo #1989
|
||||
- Add 'open project' option to Projects Welcome dialog
|
||||
- Add 'type already registered' check in palette editor
|
||||
- Handle missing tab.disabled property
|
||||
- Handle missing wires prop and string x/y props on import
|
||||
- Add RED.notifications.hide flag - for UI testing
|
||||
- Improve alignment of node label edit inputs
|
||||
- Show arrow-in node when invalid font-awesome icon name was specified for default icon
|
||||
- Add ability to delete context values from sidebar
|
||||
- Allow copy-to-clipboard copy whole tabs
|
||||
- Make disabled flows more obvious in editor
|
||||
- Allow import/export from file in editor
|
||||
- Allow config nodes to be selected in sidebar and deleted
|
||||
- Show port label of subflow with input port
|
||||
- Support ctrl-click selection of flow tabs
|
||||
- Allow left-hand node button to act as toggle
|
||||
- Support dbl-click in tab bar to add new flow in position
|
||||
- Fix duplicate subflow detection on import
|
||||
- Add import notification with info on what has been imported Closes #1862
|
||||
- Show error details when trying to import invalid json
|
||||
- Show default icon when non-existent font-awesome icon was specified
|
||||
- Add configurable option for showing node label
|
||||
- Avoid http redirects as Safari doesn't reuse Auth header Fixes #1903
|
||||
- Tidy up ace tooltip styling
|
||||
- Add event log to editor
|
||||
- Add tooltips to multiple editor elements
|
||||
- Allow palette to be hidden
|
||||
- Add node module into to sidebar and palette popover
|
||||
- Mark all newly imported nodes as changed
|
||||
- Allow a node label to be hidden
|
||||
- Add markdown formatting toolbar
|
||||
- Add markdown toolbar to various editors
|
||||
- Fix i18n handling for ja-JP locale on Safari/MacOS
|
||||
- Add node body tooltip
|
||||
- Decrease opacity of flow-navigator
|
||||
- Update tooltip style
|
||||
- Update ACE to 1.4.1-src-min-noconflict
|
||||
- Cache node locales by language
|
||||
- Show icon element with either icon image or fa-icon
|
||||
- Added font-awesome icons to user defined icon
|
||||
- Update info side bar with node description section
|
||||
- One-click search of config node users
|
||||
- Redesign node edit dialog to tabbed style
|
||||
- Add 'restart flows' option to deploy menu
|
||||
- Add node description property UI
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- Allow a project to be loaded from cmdline
|
||||
- Handle lookup of undefined property in Global context Fixes #1978
|
||||
- Refuse to enable Manage Palette if npm too old
|
||||
- Remove restriction on upgrading non-local modules
|
||||
- Remove deprecated Buffer constructor usage Fixes #1709
|
||||
- Update httpServerOptions doc in settings.js
|
||||
- Exclude non-testable .js files from the unit tests
|
||||
- Add --safe mode flag to allow starting without flows running
|
||||
- Add setting-defined accessToken for automated access to the adminAPI - #1789
|
||||
|
||||
Nodes
|
||||
|
||||
- Move all core node EN help to their own locale files - #1990
|
||||
- CSV: better regex for number detection
|
||||
- Debug: hide button if not configured to send to sidebar
|
||||
- Delay: report queue activity when in by-topic mode
|
||||
- Delay: add msg.flush mode
|
||||
- Exec: Preserve existing properties on msg object
|
||||
- File: remove CR/LF from incoming filename
|
||||
- Function: create custom ace javascript mode to handle ES6 Fixes #1911
|
||||
- Function: add env.get
|
||||
- HTTP Request: Add http-proxy config #1913
|
||||
- HTTP Request: add msg.redirectList to output
|
||||
- HTTP Request: add msg.requestTimeout option for per-message setting - @natcl #1959
|
||||
- MQTT: add auto-detect and base64 output to mqtt node Fixes #1912 - @DurandA
|
||||
- MQTT: only unsubscribe node that is being removed
|
||||
- Sentiment: move to node-red-node-sentiment
|
||||
- Switch: add missing edit dialog icon
|
||||
- Tail: move to node-red-node-tail
|
||||
- TCPGet: clear status if user changes target per message
|
||||
- Template: tidy up edit dialog
|
||||
- UDP: more resilient binding to correct port for udp, give input side priority
|
||||
- Split/Join: add msg.reset to info panel
|
||||
- Split/Join: reset join without sending part array
|
||||
- Watch: add msg.filename so can feed direct to file in node
|
||||
- WebSocket: preserve \_session on msg but don't send as part of wholemsg
|
||||
|
||||
|
||||
#### 0.19.5: Maintenance Release
|
||||
|
||||
- Recognize pip installs of RPi.GPIO (#1934)
|
||||
- Merge pull request #1941 from node-red-hitachi/master-batch
|
||||
- Merge pull request #1931 from node-red-hitachi/master-typedinput
|
||||
- Set min value of properties and spinners for batch
|
||||
- Fix that unnecessary optionMenu remains
|
||||
- Merge pull request #1894 from node-red-hitachi/fix-overlapping-file-node-execution
|
||||
- Merge pull request #1924 from imZack/patch-1
|
||||
- Add missing comma
|
||||
- Do not disable context sidebar during node edit Fixes #1921
|
||||
- Don't allow virtual links to be spliced Fixes #1920
|
||||
- Merge project package changes to avoid overwritten changes
|
||||
- Handle manually added project deps that are unused Fixes #1908
|
||||
- update close & input handling of File node
|
||||
- make close handler argument only one
|
||||
- Merge pull request #1907 from amilajack/patch-2
|
||||
- Change repo badge to point to master branch
|
||||
- invoke callbacks if async handler is specified
|
||||
- Merge pull request #1891 from camlow325/resolve-example-path-for-windows-support
|
||||
- Merge pull request #1900 from kazuhitoyokoi/master-addtestcases4settings.js
|
||||
- wait closing while pending messages exist
|
||||
- Add test cases for red/api/editor/settings.js
|
||||
- Ensure all palette categories are opened properly Closes #1893
|
||||
- Resolve path when sending example file for Windows support
|
||||
- fix multiple input message processing of file node
|
||||
|
||||
#### 0.19.4: Maintenance Release
|
||||
|
||||
- Fix race condition in non-cache lfs context Fixes #1888
|
||||
- LocalFileSystem Context: Remove extra flush code
|
||||
- Prevent race condition in caching mode of lfs context (#1889)
|
||||
- Allow context store name to be provided in the key
|
||||
- Switch node: only use promises when absolutely necessary
|
||||
- Fix dbl-click handling on webkit-based browsers
|
||||
- Ensure context.flow/global cannot be deleted or enumerated
|
||||
- Handle context.get with multiple levels of unknown key Fixes #1883
|
||||
- Fix global.get("foo.bar") for functionGlobalContext set values
|
||||
- Fix node color bug (#1877)
|
||||
- Merge pull request #1857 from cclauss/patch-1
|
||||
- Define raw_input() in Python 3 & fix time.sleep()
|
||||
|
||||
#### 0.19.3: Maintenance Release
|
||||
|
||||
- Split node - fix complete to send msg for k/v object
|
||||
- Remove unused Join node merged object key typed input
|
||||
- Set the JavaScript editor to full-screen
|
||||
- Filter global modules installed locally
|
||||
- Add svg to permitted icon extension list
|
||||
- Debug node - indicate status all the time if selected to do so
|
||||
- pi nodes - increase test coverage slightly
|
||||
- TCP-request node - only write payload
|
||||
- JSON schema: perform validation when obj -> obj or str -> str
|
||||
- JSON schema: add draft-06 support (via $schema keyword)
|
||||
- Mqtt proxy configuration for websocket connection, #1651.
|
||||
- Allows MQTT Shared Subscriptions for MQTT-In core node
|
||||
- Fix use of HTML tag or CSS class specification as icon of typedInput
|
||||
|
||||
#### 0.19.2: Maintenance Release
|
||||
|
||||
- Ensure node default colour is used if palette.theme has no match
|
||||
- fix lost messages / properties in TCPRequest Node; closes #1863 (#1864)
|
||||
- Fix typo in template.html
|
||||
- Improve error reporting from context plugin loading
|
||||
- Prevent no-op edit of node marking as changed due to icon
|
||||
- Change node must handle empty rule set
|
||||
|
||||
#### 0.19.1: Maintenance Release
|
||||
|
||||
- Pull in latest twitter node
|
||||
- Handle windows paths for context storage
|
||||
- Handle persisting objects with circular refs in context
|
||||
- Ensure js editor can expand to fill available space
|
||||
- Add example localfilesystem contextStorage to settings
|
||||
- Fix template node handling of nested context tags
|
||||
|
||||
#### 0.19: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add editorTheme.palette.theme to allow overriding colours
|
||||
- Index all node properties when searching Fixes #1446
|
||||
- Handle NaN and Infinity properly in debug sidebar Fixes #1778 #1779
|
||||
- Prevent horizontal scroll when palette name cannot wrap
|
||||
- Ignore middle-click on node/ports to enable panning
|
||||
- Better wire layout when looping back
|
||||
- fix appearence of retry button of remote branch management dialog
|
||||
- Handle releasing ctrl when using quick-add node dialog
|
||||
- Add $env function to JSONata expressions
|
||||
- Widen support for env var to use ${} or $() syntax
|
||||
- Add env-var support to TypedInput
|
||||
- Show unknown node properties in info tab
|
||||
- Add node icon picker widget
|
||||
- Only edit nodes on dbl click on primary button with no modifiers
|
||||
- Allow subflows to be put in any palette category
|
||||
- Add flow navigator widget
|
||||
- Cache flow library result to improve response time Fixes #1753
|
||||
- Add middle-button-drag to pan the workspace
|
||||
- allow multi-line category name in editor
|
||||
- Redesign sidebar tabs
|
||||
- Do not disable the export-clipboard menu option with empty selection
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Ensure runtime errors in Change node can be caught Fixes #1769
|
||||
- File: Add output to File Out node
|
||||
- Function: add expandable JavaScript editor pane
|
||||
- Function: allow id and name reference in function node code (#1731)
|
||||
- HTTP Request: Move to request module
|
||||
- HTTP: Ensure apiMaxLength applies to HTTP Nodes Fixes #1278
|
||||
- Join: accumulate top level properties
|
||||
- Join: allow environment variable as reduce init value
|
||||
- JSON: add JSON schema validation via msg.schema
|
||||
- Pi: Let nrgpio code work with python 3
|
||||
- Pi: let Pi nodes be visible/editable on all platforms
|
||||
- Switch: add isEmpty rule
|
||||
- TCP: queue messages while connecting; closes #1414
|
||||
- TLS: Add servername option to TLS config node for SNI Fixes #1805
|
||||
- UDP: Don't accidentally re-use udp port when set to not do so
|
||||
|
||||
Persistent Context
|
||||
|
||||
- Add Context data sidebar
|
||||
- Add persistable context option
|
||||
- Add default memory store
|
||||
- Add file-based context store
|
||||
- Add async mode to evaluateJSONataExpression
|
||||
- Update RED.util.evaluateNodeProperty to support context stores
|
||||
|
||||
Runtime
|
||||
|
||||
- Support flow.disabled and .info in /flow API
|
||||
- Node errors should be Strings not Errors Fixes #1781
|
||||
- Add detection of connection timeout in git communication Fixes #1770
|
||||
- Handle loading empty nodesDir
|
||||
- Add 'private' property to userDir generated package.json
|
||||
- Add RED.require to allow nodes to access other modules
|
||||
- Ensure add/remove modules are run sequentially
|
||||
|
||||
#### 0.18.7: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Relax twitter node version ready for major version bump
|
||||
- Pass Date into the Function node sandbox to fix instanceof tests
|
||||
- let TCP in node report remote ip and port when in single packet mode
|
||||
- typo fix in node help (#1735)
|
||||
|
||||
Other Fixes
|
||||
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
|
||||
- Bump jsonata version
|
||||
|
||||
#### 0.18.6: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Handle a node having wires in the editor on ports it no longer has Fixes #1724
|
||||
- Add missing ACE snippet files
|
||||
- Fix wireClippedNodes is not defined Fixes #1726
|
||||
- Split node html to isolate bad nodes when loading
|
||||
- Avoid unnecessary use of .html() where .text() will do
|
||||
|
||||
- Add editorTheme.projects.enabled to default settings.js"
|
||||
|
||||
#### 0.18.5: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
@@ -30,13 +30,13 @@ At a minimum, please include:
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
|
||||
|
||||
## Pull-Requests
|
||||
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
the [forum](https://discourse.nodered.org) first.
|
||||
|
||||
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. You can read the details of the agreement
|
||||
|
369
Gruntfile.js
369
Gruntfile.js
@@ -24,6 +24,10 @@ module.exports = function(grunt) {
|
||||
nodemonArgs.push(flowFile);
|
||||
}
|
||||
|
||||
var nonHeadless = grunt.option('non-headless');
|
||||
if (nonHeadless) {
|
||||
process.env.NODE_RED_NON_HEADLESS = 'true';
|
||||
}
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
paths: {
|
||||
@@ -38,7 +42,7 @@ module.exports = function(grunt) {
|
||||
reporter: 'spec'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
webdriver: {
|
||||
@@ -53,10 +57,11 @@ module.exports = function(grunt) {
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both'
|
||||
print: 'both',
|
||||
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
jshint: {
|
||||
@@ -76,16 +81,14 @@ module.exports = function(grunt) {
|
||||
all: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js',
|
||||
'nodes/core/*/*.js',
|
||||
'editor/js/**/*.js'
|
||||
'packages/**/*.js'
|
||||
],
|
||||
core: {
|
||||
files: {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js'
|
||||
'packages/**/*.js',
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -116,78 +119,85 @@ module.exports = function(grunt) {
|
||||
src: [
|
||||
// Ensure editor source files are concatenated in
|
||||
// the right order
|
||||
"editor/js/red.js",
|
||||
"editor/js/events.js",
|
||||
"editor/js/i18n.js",
|
||||
"editor/js/settings.js",
|
||||
"editor/js/user.js",
|
||||
"editor/js/comms.js",
|
||||
"editor/js/text/bidi.js",
|
||||
"editor/js/text/format.js",
|
||||
"editor/js/ui/state.js",
|
||||
"editor/js/nodes.js",
|
||||
"editor/js/history.js",
|
||||
"editor/js/validators.js",
|
||||
"editor/js/ui/utils.js",
|
||||
"editor/js/ui/common/editableList.js",
|
||||
"editor/js/ui/common/checkboxSet.js",
|
||||
"editor/js/ui/common/menu.js",
|
||||
"editor/js/ui/common/panels.js",
|
||||
"editor/js/ui/common/popover.js",
|
||||
"editor/js/ui/common/searchBox.js",
|
||||
"editor/js/ui/common/tabs.js",
|
||||
"editor/js/ui/common/stack.js",
|
||||
"editor/js/ui/common/typedInput.js",
|
||||
"editor/js/ui/actions.js",
|
||||
"editor/js/ui/deploy.js",
|
||||
"editor/js/ui/diff.js",
|
||||
"editor/js/ui/keyboard.js",
|
||||
"editor/js/ui/workspaces.js",
|
||||
"editor/js/ui/view.js",
|
||||
"editor/js/ui/sidebar.js",
|
||||
"editor/js/ui/palette.js",
|
||||
"editor/js/ui/tab-info.js",
|
||||
"editor/js/ui/tab-config.js",
|
||||
"editor/js/ui/palette-editor.js",
|
||||
"editor/js/ui/editor.js",
|
||||
"editor/js/ui/tray.js",
|
||||
"editor/js/ui/clipboard.js",
|
||||
"editor/js/ui/library.js",
|
||||
"editor/js/ui/notifications.js",
|
||||
"editor/js/ui/search.js",
|
||||
"editor/js/ui/typeSearch.js",
|
||||
"editor/js/ui/subflow.js",
|
||||
"editor/js/ui/userSettings.js",
|
||||
"editor/js/ui/projects/projects.js",
|
||||
"editor/js/ui/projects/projectSettings.js",
|
||||
"editor/js/ui/projects/projectUserSettings.js",
|
||||
"editor/js/ui/projects/tab-versionControl.js",
|
||||
"editor/js/ui/touch/radialMenu.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
|
||||
],
|
||||
dest: "public/red/red.js"
|
||||
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
|
||||
},
|
||||
vendor: {
|
||||
files: {
|
||||
"public/vendor/vendor.js": [
|
||||
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"editor/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"editor/vendor/marked/marked.min.js",
|
||||
"editor/vendor/d3/d3.v3.min.js",
|
||||
"editor/vendor/i18next/i18next.min.js"
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js"
|
||||
],
|
||||
"public/vendor/vendor.css": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
|
||||
// TODO: resolve relative resource paths in
|
||||
// bootstrap/FA/jquery
|
||||
],
|
||||
"public/vendor/jsonata/jsonata.min.js": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/jsonata/jsonata.min.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"editor/vendor/jsonata/formatter.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js"
|
||||
],
|
||||
"public/vendor/ace/worker-jsonata.js": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"editor/vendor/jsonata/worker-jsonata.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -195,10 +205,10 @@ module.exports = function(grunt) {
|
||||
uglify: {
|
||||
build: {
|
||||
files: {
|
||||
'public/red/red.min.js': 'public/red/red.js',
|
||||
'public/red/main.min.js': 'public/red/main.js',
|
||||
'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js',
|
||||
'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -208,50 +218,50 @@ module.exports = function(grunt) {
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
files: [{
|
||||
dest: 'public/red/style.min.css',
|
||||
src: 'editor/sass/style.scss'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
|
||||
},
|
||||
{
|
||||
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'editor/vendor/bootstrap/css/bootstrap.css'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/css/bootstrap.css'
|
||||
}]
|
||||
}
|
||||
},
|
||||
jsonlint: {
|
||||
messages: {
|
||||
src: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
]
|
||||
},
|
||||
keymaps: {
|
||||
src: [
|
||||
'editor/js/keymap.json'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
]
|
||||
}
|
||||
},
|
||||
attachCopyright: {
|
||||
js: {
|
||||
src: [
|
||||
'public/red/red.min.js',
|
||||
'public/red/main.min.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
src: [
|
||||
'public/red/style.min.css'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
|
||||
]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
build: {
|
||||
src: [
|
||||
"public/red",
|
||||
"public/index.html",
|
||||
"public/favicon.ico",
|
||||
"public/icons",
|
||||
"public/vendor"
|
||||
"packages/node_modules/@node-red/editor-client/public/red",
|
||||
"packages/node_modules/@node-red/editor-client/public/index.html",
|
||||
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
|
||||
"packages/node_modules/@node-red/editor-client/public/icons",
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor"
|
||||
]
|
||||
},
|
||||
release: {
|
||||
@@ -263,27 +273,27 @@ module.exports = function(grunt) {
|
||||
watch: {
|
||||
js: {
|
||||
files: [
|
||||
'editor/js/**/*.js'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
|
||||
],
|
||||
tasks: ['copy:build','concat','uglify','attachCopyright:js']
|
||||
},
|
||||
sass: {
|
||||
files: [
|
||||
'editor/sass/**/*.scss'
|
||||
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
|
||||
],
|
||||
tasks: ['sass','attachCopyright:css']
|
||||
},
|
||||
json: {
|
||||
files: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
],
|
||||
tasks: ['jsonlint:messages']
|
||||
},
|
||||
keymaps: {
|
||||
files: [
|
||||
'editor/js/keymap.json'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
],
|
||||
tasks: ['jsonlint:keymaps','copy:build']
|
||||
},
|
||||
@@ -298,12 +308,13 @@ module.exports = function(grunt) {
|
||||
nodemon: {
|
||||
/* uses .nodemonignore */
|
||||
dev: {
|
||||
script: 'red.js',
|
||||
script: 'packages/node_modules/node-red/red.js',
|
||||
options: {
|
||||
args: nodemonArgs,
|
||||
ext: 'js,html,json',
|
||||
watch: [
|
||||
'red','nodes'
|
||||
'packages/node_modules',
|
||||
'!packages/node_modules/@node-red/editor-client'
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -322,21 +333,21 @@ module.exports = function(grunt) {
|
||||
build: {
|
||||
files:[
|
||||
{
|
||||
src: 'editor/js/main.js',
|
||||
dest: 'public/red/main.js'
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
|
||||
},
|
||||
{
|
||||
src: 'editor/js/keymap.json',
|
||||
dest: 'public/red/keymap.json'
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/images',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/red/images/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/vendor',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
|
||||
src: [
|
||||
'ace/**',
|
||||
//'bootstrap/css/**',
|
||||
@@ -345,46 +356,35 @@ module.exports = function(grunt) {
|
||||
'font-awesome/**'
|
||||
],
|
||||
expand: true,
|
||||
dest: 'public/vendor/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/icons',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/icons/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: ['editor/index.html','editor/favicon.ico'],
|
||||
dest: 'public/',
|
||||
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/',
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'public/red/about'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'packages/node_modules/node-red/'
|
||||
},
|
||||
{
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
|
||||
}
|
||||
]
|
||||
},
|
||||
release: {
|
||||
files: [{
|
||||
mode: true,
|
||||
expand: true,
|
||||
src: [
|
||||
'*.md',
|
||||
'LICENSE',
|
||||
'package.json',
|
||||
'settings.js',
|
||||
'red.js',
|
||||
'lib/.gitignore',
|
||||
'nodes/*.demo',
|
||||
'nodes/core/**',
|
||||
'red/**',
|
||||
'public/**',
|
||||
'editor/templates/**',
|
||||
'bin/**'
|
||||
],
|
||||
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
|
||||
}]
|
||||
}
|
||||
},
|
||||
chmod: {
|
||||
@@ -393,19 +393,89 @@ module.exports = function(grunt) {
|
||||
},
|
||||
release: {
|
||||
src: [
|
||||
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
|
||||
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
|
||||
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
|
||||
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
|
||||
]
|
||||
}
|
||||
},
|
||||
'npm-command': {
|
||||
options: {
|
||||
cmd: "pack",
|
||||
cwd: "<%= paths.dist %>/modules"
|
||||
},
|
||||
'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } },
|
||||
'@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } },
|
||||
'@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } },
|
||||
'@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } },
|
||||
'@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } },
|
||||
'@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } },
|
||||
'@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } }
|
||||
|
||||
|
||||
},
|
||||
mkdir: {
|
||||
release: {
|
||||
options: {
|
||||
create: ['<%= paths.dist %>/modules']
|
||||
},
|
||||
},
|
||||
},
|
||||
compress: {
|
||||
release: {
|
||||
options: {
|
||||
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
||||
},
|
||||
expand: true,
|
||||
cwd: '<%= paths.dist %>/',
|
||||
src: ['node-red-<%= pkg.version %>/**']
|
||||
cwd: 'packages/node_modules/',
|
||||
src: [
|
||||
'**',
|
||||
'!@node-red/editor-client/src/**'
|
||||
]
|
||||
}
|
||||
},
|
||||
jsdoc : {
|
||||
modules: {
|
||||
src: [
|
||||
'packages/node_modules/node-red/lib/red.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js',
|
||||
'packages/node_modules/@node-red/util/**/*.js',
|
||||
],
|
||||
options: {
|
||||
destination: 'docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
},
|
||||
editor: {
|
||||
src: [
|
||||
'packages/node_modules/@node-red/editor-client/src/js'
|
||||
],
|
||||
options: {
|
||||
destination: 'packages/node_modules/@node-red/editor-client/docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
jsdoc2md: {
|
||||
runtimeAPI: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: [
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js'
|
||||
],
|
||||
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
|
||||
},
|
||||
nodeREDUtil: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
||||
dest: 'packages/node_modules/@node-red/util/docs/api.md'
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -425,6 +495,10 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-jsonlint');
|
||||
grunt.loadNpmTasks('grunt-mocha-istanbul');
|
||||
grunt.loadNpmTasks('grunt-webdriver');
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
|
||||
grunt.loadNpmTasks('grunt-npm-command');
|
||||
grunt.loadNpmTasks('grunt-mkdir');
|
||||
|
||||
grunt.registerMultiTask('attachCopyright', function() {
|
||||
var files = this.data.src;
|
||||
@@ -466,6 +540,18 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('verifyPackageDependencies', function() {
|
||||
var done = this.async();
|
||||
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
|
||||
verifyDependencies().then(function(failures) {
|
||||
if (failures.length > 0) {
|
||||
failures.forEach(f => grunt.log.error(f));
|
||||
grunt.fail.fatal("Failed to verify package dependencies");
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('setDevEnv',
|
||||
'Sets NODE_ENV=development so non-minified assets are used',
|
||||
function () {
|
||||
@@ -474,7 +560,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','test-core','test-editor','test-nodes']);
|
||||
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
@@ -502,9 +588,18 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('release',
|
||||
'Create distribution zip file',
|
||||
['build','clean:release','copy:release','chmod:release','compress:release']);
|
||||
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules']);
|
||||
|
||||
grunt.registerTask('pack-modules',
|
||||
'Create module pack files for release',
|
||||
['mkdir:release','npm-command']);
|
||||
|
||||
|
||||
grunt.registerTask('coverage',
|
||||
'Run Istanbul code test coverage task',
|
||||
['build','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('docs',
|
||||
'Generates API documentation',
|
||||
['jsdoc','jsdoc2md']);
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
http://nodered.org
|
||||
|
||||
[](https://travis-ci.org/node-red/node-red)
|
||||
[](https://travis-ci.org/node-red/node-red)
|
||||
[](https://coveralls.io/r/node-red/node-red?branch=master)
|
||||
|
||||
A visual tool for wiring the Internet of Things.
|
||||
@@ -22,8 +22,7 @@ started.
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the
|
||||
[mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
## Developers
|
||||
|
||||
@@ -45,9 +44,6 @@ If you want to run the latest code from git, here's how to get started:
|
||||
4. Run
|
||||
|
||||
npm start
|
||||
or
|
||||
|
||||
node red.js
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
RED.panels = (function() {
|
||||
|
||||
function createPanel(options) {
|
||||
var container = options.container || $("#"+options.id);
|
||||
var children = container.children();
|
||||
if (children.length !== 2) {
|
||||
throw new Error("Container must have exactly two children");
|
||||
}
|
||||
|
||||
container.addClass("red-ui-panels");
|
||||
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
|
||||
var startPosition;
|
||||
var panelHeights = [];
|
||||
var modifiedHeights = false;
|
||||
var panelRatio;
|
||||
|
||||
separator.draggable({
|
||||
axis: "y",
|
||||
containment: container,
|
||||
scroll: false,
|
||||
start:function(event,ui) {
|
||||
var height = container.height();
|
||||
startPosition = ui.position.top;
|
||||
panelHeights = [$(children[0]).height(),$(children[1]).height()];
|
||||
},
|
||||
drag: function(event,ui) {
|
||||
var height = container.height();
|
||||
var delta = ui.position.top-startPosition;
|
||||
var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta];
|
||||
$(children[0]).height(newHeights[0]);
|
||||
$(children[1]).height(newHeights[1]);
|
||||
if (options.resize) {
|
||||
options.resize(newHeights[0],newHeights[1]);
|
||||
}
|
||||
ui.position.top -= delta;
|
||||
panelRatio = newHeights[0]/height;
|
||||
},
|
||||
stop:function(event,ui) {
|
||||
modifiedHeights = true;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
resize: function(height) {
|
||||
var panelHeights = [$(children[0]).height(),$(children[1]).height()];
|
||||
container.height(height);
|
||||
if (modifiedHeights) {
|
||||
var topPanelHeight = panelRatio*height;
|
||||
var bottomPanelHeight = height - topPanelHeight - 48;
|
||||
panelHeights = [topPanelHeight,bottomPanelHeight];
|
||||
$(children[0]).height(panelHeights[0]);
|
||||
$(children[1]).height(panelHeights[1]);
|
||||
}
|
||||
if (options.resize) {
|
||||
options.resize(panelHeights[0],panelHeights[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPanel
|
||||
}
|
||||
})();
|
@@ -1,149 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.popover = (function() {
|
||||
var deltaSizes = {
|
||||
"default": {
|
||||
top: 10,
|
||||
leftRight: 17,
|
||||
leftLeft: 25
|
||||
},
|
||||
"small": {
|
||||
top: 5,
|
||||
leftRight: 17,
|
||||
leftLeft: 16
|
||||
}
|
||||
}
|
||||
function createPopover(options) {
|
||||
var target = options.target;
|
||||
var direction = options.direction || "right";
|
||||
var trigger = options.trigger;
|
||||
var content = options.content;
|
||||
var delay = options.delay;
|
||||
var autoClose = options.autoClose;
|
||||
var width = options.width||"auto";
|
||||
var size = options.size||"default";
|
||||
if (!deltaSizes[size]) {
|
||||
throw new Error("Invalid RED.popover size value:",size);
|
||||
}
|
||||
|
||||
var timer = null;
|
||||
var active;
|
||||
var div;
|
||||
|
||||
var openPopup = function(instant) {
|
||||
if (active) {
|
||||
div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>').appendTo("body");
|
||||
if (size !== "default") {
|
||||
div.addClass("red-ui-popover-size-"+size);
|
||||
}
|
||||
if (typeof content === 'function') {
|
||||
content.call(res).appendTo(div);
|
||||
} else {
|
||||
div.html(content);
|
||||
}
|
||||
if (width !== "auto") {
|
||||
div.width(width);
|
||||
}
|
||||
|
||||
|
||||
var targetPos = target.offset();
|
||||
var targetWidth = target.width();
|
||||
var targetHeight = target.height();
|
||||
var divHeight = div.height();
|
||||
var divWidth = div.width();
|
||||
if (direction === 'right') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
|
||||
} else if (direction === 'left') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
|
||||
}
|
||||
if (instant) {
|
||||
div.show();
|
||||
} else {
|
||||
div.fadeIn("fast");
|
||||
}
|
||||
}
|
||||
}
|
||||
var closePopup = function(instant) {
|
||||
if (!active) {
|
||||
if (div) {
|
||||
if (instant) {
|
||||
$(this).remove();
|
||||
} else {
|
||||
div.fadeOut("fast",function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
div = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trigger === 'hover') {
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
active = true;
|
||||
timer = setTimeout(openPopup,delay.show);
|
||||
});
|
||||
target.on('mouseleave', function(e) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
active = false;
|
||||
setTimeout(closePopup,delay.hide);
|
||||
});
|
||||
} else if (trigger === 'click') {
|
||||
target.click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
active = !active;
|
||||
if (!active) {
|
||||
closePopup();
|
||||
} else {
|
||||
openPopup();
|
||||
}
|
||||
});
|
||||
} else if (autoClose) {
|
||||
setTimeout(function() {
|
||||
active = false;
|
||||
closePopup();
|
||||
},autoClose);
|
||||
}
|
||||
var res = {
|
||||
setContent: function(_content) {
|
||||
content = _content;
|
||||
return res;
|
||||
},
|
||||
open: function (instant) {
|
||||
active = true;
|
||||
openPopup(instant);
|
||||
return res;
|
||||
},
|
||||
close: function (instant) {
|
||||
active = false;
|
||||
closePopup(instant);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPopover
|
||||
}
|
||||
|
||||
})();
|
@@ -1,379 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
|
||||
RED.tabs = (function() {
|
||||
function createTabs(options) {
|
||||
var tabs = {};
|
||||
var currentTabWidth;
|
||||
var currentActiveTabWidth = 0;
|
||||
|
||||
var ul = options.element || $("#"+options.id);
|
||||
var wrapper = ul.wrap( "<div>" ).parent();
|
||||
var scrollContainer = ul.wrap( "<div>" ).parent();
|
||||
wrapper.addClass("red-ui-tabs");
|
||||
if (options.vertical) {
|
||||
wrapper.addClass("red-ui-tabs-vertical");
|
||||
}
|
||||
if (options.addButton && typeof options.addButton === 'function') {
|
||||
wrapper.addClass("red-ui-tabs-add");
|
||||
var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
|
||||
addButton.find('a').click(function(evt) {
|
||||
evt.preventDefault();
|
||||
options.addButton();
|
||||
})
|
||||
|
||||
}
|
||||
var scrollLeft;
|
||||
var scrollRight;
|
||||
|
||||
if (options.scrollable) {
|
||||
wrapper.addClass("red-ui-tabs-scrollable");
|
||||
scrollContainer.addClass("red-ui-tabs-scroll-container");
|
||||
scrollContainer.scroll(updateScroll);
|
||||
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
|
||||
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
|
||||
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
}
|
||||
function scrollEventHandler(evt,dir) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
var currentScrollLeft = scrollContainer.scrollLeft();
|
||||
scrollContainer.animate( { scrollLeft: dir }, 100);
|
||||
var interval = setInterval(function() {
|
||||
var newScrollLeft = scrollContainer.scrollLeft()
|
||||
if (newScrollLeft === currentScrollLeft) {
|
||||
clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
currentScrollLeft = newScrollLeft;
|
||||
scrollContainer.animate( { scrollLeft: dir }, 100);
|
||||
},100);
|
||||
$(this).one('mouseup',function() {
|
||||
clearInterval(interval);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
ul.children().first().addClass("active");
|
||||
ul.children().addClass("red-ui-tab");
|
||||
|
||||
function onTabClick() {
|
||||
if (options.onclick) {
|
||||
options.onclick(tabs[$(this).attr('href').slice(1)]);
|
||||
}
|
||||
activateTab($(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateScroll() {
|
||||
if (ul.children().length !== 0) {
|
||||
var sl = scrollContainer.scrollLeft();
|
||||
var scWidth = scrollContainer.width();
|
||||
var ulWidth = ul.width();
|
||||
if (sl === 0) {
|
||||
scrollLeft.hide();
|
||||
} else {
|
||||
scrollLeft.show();
|
||||
}
|
||||
if (sl === ulWidth-scWidth) {
|
||||
scrollRight.hide();
|
||||
} else {
|
||||
scrollRight.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
function onTabDblClick() {
|
||||
if (options.ondblclick) {
|
||||
options.ondblclick(tabs[$(this).attr('href').slice(1)]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function activateTab(link) {
|
||||
if (typeof link === "string") {
|
||||
link = ul.find("a[href='#"+link+"']");
|
||||
}
|
||||
if (link.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!link.parent().hasClass("active")) {
|
||||
ul.children().removeClass("active");
|
||||
ul.children().css({"transition": "width 100ms"});
|
||||
link.parent().addClass("active");
|
||||
if (options.scrollable) {
|
||||
var pos = link.parent().position().left;
|
||||
if (pos-21 < 0) {
|
||||
scrollContainer.animate( { scrollLeft: '+='+(pos-50) }, 300);
|
||||
} else if (pos + 120 > scrollContainer.width()) {
|
||||
scrollContainer.animate( { scrollLeft: '+='+(pos + 140-scrollContainer.width()) }, 300);
|
||||
}
|
||||
}
|
||||
if (options.onchange) {
|
||||
options.onchange(tabs[link.attr('href').slice(1)]);
|
||||
}
|
||||
updateTabWidths();
|
||||
setTimeout(function() {
|
||||
ul.children().css({"transition": ""});
|
||||
},100);
|
||||
}
|
||||
}
|
||||
function activatePreviousTab() {
|
||||
var previous = ul.find("li.active").prev();
|
||||
if (previous.length > 0) {
|
||||
activateTab(previous.find("a"));
|
||||
}
|
||||
}
|
||||
function activateNextTab() {
|
||||
var next = ul.find("li.active").next();
|
||||
if (next.length > 0) {
|
||||
activateTab(next.find("a"));
|
||||
}
|
||||
}
|
||||
|
||||
function updateTabWidths() {
|
||||
if (options.vertical) {
|
||||
return;
|
||||
}
|
||||
var tabs = ul.find("li.red-ui-tab");
|
||||
var width = wrapper.width();
|
||||
var tabCount = tabs.size();
|
||||
var tabWidth = (width-12-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = currentTabWidth+"%";
|
||||
if (options.scrollable) {
|
||||
tabWidth = Math.max(tabWidth,140);
|
||||
currentTabWidth = tabWidth+"px";
|
||||
currentActiveTabWidth = 0;
|
||||
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
|
||||
ul.width(listWidth);
|
||||
updateScroll();
|
||||
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
|
||||
if (tabWidth < options.minimumActiveTabWidth) {
|
||||
tabCount -= 1;
|
||||
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
|
||||
} else {
|
||||
currentActiveTabWidth = 0;
|
||||
}
|
||||
}
|
||||
tabs.css({width:currentTabWidth});
|
||||
if (tabWidth < 50) {
|
||||
ul.find(".red-ui-tab-close").hide();
|
||||
ul.find(".red-ui-tab-icon").hide();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
|
||||
} else {
|
||||
ul.find(".red-ui-tab-close").show();
|
||||
ul.find(".red-ui-tab-icon").show();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:""})
|
||||
}
|
||||
if (currentActiveTabWidth !== 0) {
|
||||
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
|
||||
setTimeout(function() {
|
||||
updateTabWidths();
|
||||
},0);
|
||||
|
||||
|
||||
function removeTab(id) {
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (li.hasClass("active")) {
|
||||
var tab = li.prev();
|
||||
if (tab.size() === 0) {
|
||||
tab = li.next();
|
||||
}
|
||||
activateTab(tab.find("a"));
|
||||
}
|
||||
li.remove();
|
||||
if (options.onremove) {
|
||||
options.onremove(tabs[id]);
|
||||
}
|
||||
delete tabs[id];
|
||||
updateTabWidths();
|
||||
}
|
||||
|
||||
return {
|
||||
addTab: function(tab) {
|
||||
tabs[tab.id] = tab;
|
||||
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
|
||||
li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-")));
|
||||
li.data("tabId",tab.id);
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
if (tab.icon) {
|
||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||
}
|
||||
var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link);
|
||||
span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label));
|
||||
|
||||
link.on("click",onTabClick);
|
||||
link.on("dblclick",onTabDblClick);
|
||||
if (tab.closeable) {
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-times" />');
|
||||
|
||||
closeLink.on("click",function(event) {
|
||||
event.preventDefault();
|
||||
removeTab(tab.id);
|
||||
});
|
||||
}
|
||||
updateTabWidths();
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
}
|
||||
link.attr("title",tab.label);
|
||||
if (ul.find("li.red-ui-tab").size() == 1) {
|
||||
activateTab(link);
|
||||
}
|
||||
if (options.onreorder) {
|
||||
var originalTabOrder;
|
||||
var tabDragIndex;
|
||||
var tabElements = [];
|
||||
var startDragIndex;
|
||||
|
||||
li.draggable({
|
||||
axis:"x",
|
||||
distance: 20,
|
||||
start: function(event,ui) {
|
||||
originalTabOrder = [];
|
||||
tabElements = [];
|
||||
ul.children().each(function(i) {
|
||||
tabElements[i] = {
|
||||
el:$(this),
|
||||
text: $(this).text(),
|
||||
left: $(this).position().left,
|
||||
width: $(this).width()
|
||||
};
|
||||
if ($(this).is(li)) {
|
||||
tabDragIndex = i;
|
||||
startDragIndex = i;
|
||||
}
|
||||
originalTabOrder.push($(this).data("tabId"));
|
||||
});
|
||||
ul.children().each(function(i) {
|
||||
if (i!==tabDragIndex) {
|
||||
$(this).css({
|
||||
position: 'absolute',
|
||||
left: tabElements[i].left+"px",
|
||||
width: tabElements[i].width+2,
|
||||
transition: "left 0.3s"
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
if (!li.hasClass('active')) {
|
||||
li.css({'zIndex':1});
|
||||
}
|
||||
},
|
||||
drag: function(event,ui) {
|
||||
ui.position.left += tabElements[tabDragIndex].left+scrollContainer.scrollLeft();
|
||||
var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2 - scrollContainer.scrollLeft();
|
||||
for (var i=0;i<tabElements.length;i++) {
|
||||
if (i === tabDragIndex) {
|
||||
continue;
|
||||
}
|
||||
if (tabCenter > tabElements[i].left && tabCenter < tabElements[i].left+tabElements[i].width) {
|
||||
if (i < tabDragIndex) {
|
||||
tabElements[i].left += tabElements[tabDragIndex].width+8;
|
||||
tabElements[tabDragIndex].el.detach().insertBefore(tabElements[i].el);
|
||||
} else {
|
||||
tabElements[i].left -= tabElements[tabDragIndex].width+8;
|
||||
tabElements[tabDragIndex].el.detach().insertAfter(tabElements[i].el);
|
||||
}
|
||||
tabElements[i].el.css({left:tabElements[i].left+"px"});
|
||||
|
||||
tabElements.splice(i, 0, tabElements.splice(tabDragIndex, 1)[0]);
|
||||
|
||||
tabDragIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
stop: function(event,ui) {
|
||||
ul.children().css({position:"relative",left:"",transition:""});
|
||||
if (!li.hasClass('active')) {
|
||||
li.css({zIndex:""});
|
||||
}
|
||||
updateTabWidths();
|
||||
if (startDragIndex !== tabDragIndex) {
|
||||
options.onreorder(originalTabOrder, $.makeArray(ul.children().map(function() { return $(this).data('tabId');})));
|
||||
}
|
||||
activateTab(tabElements[tabDragIndex].el.data('tabId'));
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
removeTab: removeTab,
|
||||
activateTab: activateTab,
|
||||
nextTab: activateNextTab,
|
||||
previousTab: activatePreviousTab,
|
||||
resize: updateTabWidths,
|
||||
count: function() {
|
||||
return ul.find("li.red-ui-tab").size();
|
||||
},
|
||||
contains: function(id) {
|
||||
return ul.find("a[href='#"+id+"']").length > 0;
|
||||
},
|
||||
renameTab: function(id,label) {
|
||||
tabs[id].label = label;
|
||||
var tab = ul.find("a[href='#"+id+"']");
|
||||
tab.attr("title",label);
|
||||
tab.find("span.bidiAware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
|
||||
updateTabWidths();
|
||||
},
|
||||
order: function(order) {
|
||||
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
|
||||
if (existingTabOrder.length !== order.length) {
|
||||
return
|
||||
}
|
||||
var i;
|
||||
var match = true;
|
||||
for (i=0;i<order.length;i++) {
|
||||
if (order[i] !== existingTabOrder[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return;
|
||||
}
|
||||
var existingTabMap = {};
|
||||
var existingTabs = ul.children().detach().each(function() {
|
||||
existingTabMap[$(this).data("tabId")] = $(this);
|
||||
});
|
||||
for (i=0;i<order.length;i++) {
|
||||
existingTabMap[order[i]].appendTo(ul);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
create: createTabs
|
||||
}
|
||||
})();
|
@@ -1,8 +0,0 @@
|
||||
.ace_gutter {
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.ace_scroller {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
#notifications {
|
||||
z-index: 100;
|
||||
width: 500px;
|
||||
margin-left: -250px;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
}
|
||||
.notification {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 4px;
|
||||
box-shadow: 0 1px 1px 1px rgba(0,0,0, 0.15);
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
border: 1px solid #325C80;
|
||||
border-left-width: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.notification p:first-child {
|
||||
font-size: 1.1em;
|
||||
font-weight: 400;
|
||||
}
|
||||
.notification a {
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-success {
|
||||
border-color: #4B8400;
|
||||
}
|
||||
.notification-warning {
|
||||
border-color: #D74108;
|
||||
}
|
||||
.notification-error {
|
||||
border-color: #AD1625;
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
.red-ui-popover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
padding: 10px;
|
||||
height: auto;
|
||||
background: #fff;
|
||||
|
||||
z-index: 1000;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
@include component-shadow;
|
||||
}
|
||||
|
||||
.red-ui-popover:after, .red-ui-popover:before {
|
||||
top: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before {
|
||||
right: 100%;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
|
||||
.red-ui-popover.red-ui-popover-right:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
border-right-color: #fff;
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-right:before {
|
||||
border-color: rgba(194, 225, 245, 0);
|
||||
border-right-color: $primary-border-color;
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
|
||||
.red-ui-popover.red-ui-popover-left:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
border-left-color: #fff;
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-left:before {
|
||||
border-color: rgba(194, 225, 245, 0);
|
||||
border-left-color: $primary-border-color;
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
|
||||
.red-ui-popover-size-small {
|
||||
font-size: 11px;
|
||||
padding: 5px;
|
||||
|
||||
&.red-ui-popover-right:after {
|
||||
border-width: 5px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
&.red-ui-popover-right:before {
|
||||
border-width: 6px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
||||
&.red-ui-popover-left:after {
|
||||
border-width: 5px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
&.red-ui-popover-left:before {
|
||||
border-width: 6px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
}
|
@@ -1,224 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<head>
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="icon" type="image/png" href="{{ page.favicon }}">
|
||||
<link rel="mask-icon" href="{{ page.tabicon }}" color="#8f0000">
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="vendor/vendor.css">
|
||||
<link rel="stylesheet" href="red/style.min.css">
|
||||
{{#page.css}}
|
||||
<link rel="stylesheet" href="{{.}}">
|
||||
{{/page.css}}
|
||||
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
<div id="header">
|
||||
<span class="logo">{{#header.url}}<a href="{{.}}">{{/header.url}}{{#header.image}}<img src="{{.}}" title="{{version}}">{{/header.image}} <span>{{ header.title }}</span>{{#header.url}}</a>{{/header.url}}</span>
|
||||
<ul class="header-toolbar hide">
|
||||
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
||||
</ul>
|
||||
<div id="header-shade" class="hide"></div>
|
||||
</div>
|
||||
<div id="main-container" class="sidebar-closed hide">
|
||||
<div id="workspace">
|
||||
<ul id="workspace-tabs"></ul>
|
||||
<div id="chart" tabindex="1"></div>
|
||||
<div id="workspace-toolbar"></div>
|
||||
<div id="workspace-footer">
|
||||
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||
</div>
|
||||
<div id="editor-shade" class="hide"></div>
|
||||
</div>
|
||||
<div id="editor-stack"></div>
|
||||
<div id="palette">
|
||||
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
||||
<div id="palette-search" class="palette-search hide">
|
||||
<input type="text" data-i18n="[placeholder]palette.filter"></input>
|
||||
</div>
|
||||
<div id="palette-container" class="palette-scroll hide"></div>
|
||||
<div id="palette-footer">
|
||||
<a class="palette-button" id="palette-collapse-all" href="#"><i class="fa fa-angle-double-up"></i></a>
|
||||
<a class="palette-button" id="palette-expand-all" href="#"><i class="fa fa-angle-double-down"></i></a>
|
||||
</div>
|
||||
<div id="palette-shade" class="hide"></div>
|
||||
</div><!-- /palette -->
|
||||
<div id="sidebar">
|
||||
<ul id="sidebar-tabs"></ul>
|
||||
<div id="sidebar-content"></div>
|
||||
<div id="sidebar-footer"></div>
|
||||
<div id="sidebar-shade" class="hide"></div>
|
||||
</div>
|
||||
|
||||
<div id="sidebar-separator"></div>
|
||||
|
||||
</div>
|
||||
<div id="full-shade" class="hide"></div>
|
||||
|
||||
<div id="notifications"></div>
|
||||
<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
|
||||
|
||||
<div id="node-dialog-library-save-confirm" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div style="text-align: center; padding-top: 30px;" id="node-dialog-library-save-content">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-folder" data-i18n="[append]library.folder"><i class="fa fa-folder-open"></i> </label>
|
||||
<input type="text" id="node-dialog-library-save-folder" data-i18n="[placeholder]library.folderPlaceholder">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-filename" data-i18n="[append]library.filename"><i class="fa fa-file"></i> </label>
|
||||
<input type="text" id="node-dialog-library-save-filename" data-i18n="[placeholder]library.filenamePlaceholder">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-lookup" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
|
||||
<li class="active"><a href="#" data-i18n="[append]library.breadcrumb"></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
|
||||
<div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
|
||||
</div>
|
||||
<div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
|
||||
<div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/x-red" data-template-name="subflow">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="subflow-template">
|
||||
<div class="form-row">
|
||||
<i class="fa fa-tag"></i>
|
||||
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom: 0px;">
|
||||
<label for="subflow-input-info" data-i18n="editor:subflow.info"></label>
|
||||
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div>
|
||||
</div>
|
||||
<div class="form-row form-tips" id="subflow-dialog-user-count"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="_expression">
|
||||
<div id="node-input-expression-panels">
|
||||
<div id="node-input-expression-panel-expr" class="red-ui-panel">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<span class="node-input-expression-legacy"><i class="fa fa-exclamation-circle"></i> <span data-i18n="expressionEditor.compatMode"></span></span>
|
||||
<button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="expressionEditor.format"></span></button>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div class="node-text-editor" id="node-input-expression"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="node-input-expression-panel-info" class="red-ui-panel">
|
||||
<div class="form-row">
|
||||
<ul id="node-input-expression-tabs"></ul>
|
||||
<div id="node-input-expression-tab-help" class="node-input-expression-tab-content hide">
|
||||
<div>
|
||||
<select id="node-input-expression-func"></select>
|
||||
<button id="node-input-expression-func-insert" class="editor-button" data-i18n="expressionEditor.insert"></button>
|
||||
</div>
|
||||
<div id="node-input-expression-help"></div>
|
||||
</div>
|
||||
<div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide">
|
||||
<div>
|
||||
<span style="display: inline-block; width: calc(50% - 5px);">
|
||||
<span data-i18n="expressionEditor.data"></span>
|
||||
<button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
|
||||
</span>
|
||||
<span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span>
|
||||
</div>
|
||||
<div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div>
|
||||
<div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-result"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_json">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_markdown">
|
||||
<div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;">
|
||||
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_buffer">
|
||||
<div id="node-input-buffer-panels">
|
||||
<div id="node-input-buffer-panel-str" class="red-ui-panel">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div class="node-text-editor" id="node-input-buffer-str"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="node-input-buffer-panel-bin" class="red-ui-panel">
|
||||
<div class="form-row node-text-editor-row" style="margin-top: 10px">
|
||||
<div class="node-text-editor" id="node-input-buffer-bin"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/jsonata/jsonata.min.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||
<script src="{{ asset.red }}"></script>
|
||||
<script src="{{ asset.main }}"></script>
|
||||
{{# page.scripts }}
|
||||
<script src="{{.}}"></script>
|
||||
{{/ page.scripts }}
|
||||
|
||||
</body>
|
||||
</html>
|
14
editor/vendor/ace/ace.js
vendored
14
editor/vendor/ace/ace.js
vendored
File diff suppressed because one or more lines are too long
5
editor/vendor/ace/ext-language_tools.js
vendored
5
editor/vendor/ace/ext-language_tools.js
vendored
File diff suppressed because one or more lines are too long
5
editor/vendor/ace/ext-searchbox.js
vendored
5
editor/vendor/ace/ext-searchbox.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-css.js
vendored
1
editor/vendor/ace/mode-css.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-handlebars.js
vendored
1
editor/vendor/ace/mode-handlebars.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-html.js
vendored
1
editor/vendor/ace/mode-html.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-javascript.js
vendored
1
editor/vendor/ace/mode-javascript.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-markdown.js
vendored
1
editor/vendor/ace/mode-markdown.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-python.js
vendored
1
editor/vendor/ace/mode-python.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/mode/python_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield|async|await",t="True|False|None|NotImplemented|Ellipsis|__debug__",n="abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",r=this.createKeywordMapper({"invalid.deprecated":"debugger","support.function":n,"constant.language":t,keyword:e},"identifier"),i="(?:r|u|ur|R|U|UR|Ur|uR)?",s="(?:(?:[1-9]\\d*)|(?:0))",o="(?:0[oO]?[0-7]+)",u="(?:0[xX][\\dA-Fa-f]+)",a="(?:0[bB][01]+)",f="(?:"+s+"|"+o+"|"+u+"|"+a+")",l="(?:[eE][+-]?\\d+)",c="(?:\\.\\d+)",h="(?:\\d+)",p="(?:(?:"+h+"?"+c+")|(?:"+h+"\\.))",d="(?:(?:"+p+"|"+h+")"+l+")",v="(?:"+d+"|"+p+")",m="\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"string",regex:i+'"{3}',next:"qqstring3"},{token:"string",regex:i+'"(?=.)',next:"qqstring"},{token:"string",regex:i+"'{3}",next:"qstring3"},{token:"string",regex:i+"'(?=.)",next:"qstring"},{token:"constant.numeric",regex:"(?:"+v+"|\\d+)[jJ]\\b"},{token:"constant.numeric",regex:v},{token:"constant.numeric",regex:f+"[lL]\\b"},{token:"constant.numeric",regex:f+"\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\[\\(\\{]"},{token:"paren.rparen",regex:"[\\]\\)\\}]"},{token:"text",regex:"\\s+"}],qqstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:'"{3}',next:"start"},{defaultToken:"string"}],qstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:"'{3}",next:"start"},{defaultToken:"string"}],qqstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"start"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"start"},{defaultToken:"string"}]}};r.inherits(s,i),t.PythonHighlightRules=s}),ace.define("ace/mode/folding/pythonic",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=t.FoldMode=function(e){this.foldingStartMarker=new RegExp("([\\[{])(?:\\s*)$|("+e+")(?:\\s*)(?:#.*)?$")};r.inherits(s,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i)return i[1]?this.openingBracketBlock(e,i[1],n,i.index):i[2]?this.indentationBlock(e,n,i.index+i[2].length):this.indentationBlock(e,n)}}.call(s.prototype)}),ace.define("ace/mode/python",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/python_highlight_rules","ace/mode/folding/pythonic","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./python_highlight_rules").PythonHighlightRules,o=e("./folding/pythonic").FoldMode,u=e("../range").Range,a=function(){this.HighlightRules=s,this.foldingRules=new o("\\:"),this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart="#",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[:]\s*$/);o&&(r+=n)}return r};var e={pass:1,"return":1,raise:1,"break":1,"continue":1};this.checkOutdent=function(t,n,r){if(r!=="\r\n"&&r!=="\r"&&r!=="\n")return!1;var i=this.getTokenizer().getLineTokens(n.trim(),t).tokens;if(!i)return!1;do var s=i.pop();while(s&&(s.type=="comment"||s.type=="text"&&s.value.match(/^\s+$/)));return s?s.type=="keyword"&&e[s.value]:!1},this.autoOutdent=function(e,t,n){n+=1;var r=this.$getIndent(t.getLine(n)),i=t.getTabString();r.slice(-i.length)==i&&t.remove(new u(n,r.length-i.length,n,r.length))},this.$id="ace/mode/python"}.call(a.prototype),t.Mode=a})
|
1
editor/vendor/ace/mode-swift.js
vendored
1
editor/vendor/ace/mode-swift.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/snippets/handlebars.js
vendored
1
editor/vendor/ace/snippets/handlebars.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/handlebars",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="handlebars"})
|
1
editor/vendor/ace/snippets/properties.js
vendored
1
editor/vendor/ace/snippets/properties.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/properties",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="properties"})
|
1
editor/vendor/ace/snippets/text.js
vendored
1
editor/vendor/ace/snippets/text.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="text"})
|
1
editor/vendor/ace/snippets/yaml.js
vendored
1
editor/vendor/ace/snippets/yaml.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/yaml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="yaml"})
|
1
editor/vendor/ace/worker-html.js
vendored
1
editor/vendor/ace/worker-html.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/worker-javascript.js
vendored
1
editor/vendor/ace/worker-javascript.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/worker-json.js
vendored
1
editor/vendor/ace/worker-json.js
vendored
File diff suppressed because one or more lines are too long
26
jsdoc.json
Normal file
26
jsdoc.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"opts": {
|
||||
"template": "./node_modules/jsdoc-nr-template",
|
||||
"destination": "./docs",
|
||||
"recurse": true
|
||||
},
|
||||
"tags": {
|
||||
"allowUnknownTags": false,
|
||||
"dictionaries": ["jsdoc"]
|
||||
},
|
||||
"source": {
|
||||
"_include": [
|
||||
"./packages/node_modules/@node-red/runtime/lib/api"
|
||||
]
|
||||
},
|
||||
"templates": {
|
||||
"systemName": "Node-RED Runtime API",
|
||||
"theme":"yeti",
|
||||
"footer": "",
|
||||
"copyright": "Released under the Apache License v2.0",
|
||||
"default": {
|
||||
"outputSourceFiles": false
|
||||
}
|
||||
},
|
||||
"plugins": ["plugins/markdown"]
|
||||
}
|
1
lib/.gitignore
vendored
1
lib/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*
|
@@ -1,57 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="sentiment">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>Analyses the chosen property, default <code>payload</code>, and adds a <code>sentiment</code> object.</p>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">object</span></dt>
|
||||
<dd>contains the resulting AFINN-111 sentiment.</dd>
|
||||
<dt>sentiment.score <span class="property-type">number</span></dt>
|
||||
<dd>the sentiment score.</dd>
|
||||
</dl>
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">object</span></dt>
|
||||
<dd>an object of word score overrides can be supplied - <code>{ word:score,... }</code>.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>A score greater than zero is positive and less than zero is negative.</p>
|
||||
<p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
|
||||
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('sentiment',{
|
||||
category: 'analysis-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"sentiment";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.property === undefined) {
|
||||
$("#node-input-property").val("payload");
|
||||
}
|
||||
$("#node-input-property").typedInput({default:'msg',types:['msg']});
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,23 +0,0 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var sentiment = require('sentiment');
|
||||
|
||||
function SentimentNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.property = n.property||"payload";
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
if (value !== undefined) {
|
||||
sentiment(value, msg.overrides || null, function (err, result) {
|
||||
msg.sentiment = result;
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
else { node.send(msg); } // If no matching property - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("sentiment",SentimentNode);
|
||||
}
|
@@ -1,255 +0,0 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var util = require("util");
|
||||
var events = require("events");
|
||||
var path = require("path");
|
||||
var safeJSONStringify = require("json-stringify-safe");
|
||||
var debuglength = RED.settings.debugMaxLength || 1000;
|
||||
var useColors = RED.settings.debugUseColors || false;
|
||||
util.inspect.styles.boolean = "red";
|
||||
|
||||
function DebugNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
this.complete = (n.complete||"payload").toString();
|
||||
if (this.complete === "false") { this.complete = "payload"; }
|
||||
this.console = ""+(n.console || false);
|
||||
this.tostatus = n.tostatus || false;
|
||||
this.tosidebar = n.tosidebar;
|
||||
if (this.tosidebar === undefined) { this.tosidebar = true; }
|
||||
this.severity = n.severity || 40;
|
||||
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
|
||||
this.status({});
|
||||
|
||||
var node = this;
|
||||
var levels = {
|
||||
off: 1,
|
||||
fatal: 10,
|
||||
error: 20,
|
||||
warn: 30,
|
||||
info: 40,
|
||||
debug: 50,
|
||||
trace: 60,
|
||||
audit: 98,
|
||||
metric: 99
|
||||
};
|
||||
var colors = {
|
||||
"0": "grey",
|
||||
"10": "grey",
|
||||
"20": "red",
|
||||
"30": "yellow",
|
||||
"40": "grey",
|
||||
"50": "green",
|
||||
"60": "blue"
|
||||
};
|
||||
|
||||
this.on("input",function(msg) {
|
||||
if (this.complete === "true") {
|
||||
// debug complete msg object
|
||||
if (this.console === "true") {
|
||||
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
|
||||
}
|
||||
if (this.active && this.tosidebar) {
|
||||
sendDebug({id:node.id, name:node.name, topic:msg.topic, msg:msg, _path:msg._path});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// debug user defined msg property
|
||||
var property = "payload";
|
||||
var output = msg[property];
|
||||
if (this.complete !== "false" && typeof this.complete !== "undefined") {
|
||||
property = this.complete;
|
||||
try {
|
||||
output = RED.util.getMessageProperty(msg,this.complete);
|
||||
} catch(err) {
|
||||
output = undefined;
|
||||
}
|
||||
}
|
||||
if (this.console === "true") {
|
||||
if (typeof output === "string") {
|
||||
node.log((output.indexOf("\n") !== -1 ? "\n" : "") + output);
|
||||
} else if (typeof output === "object") {
|
||||
node.log("\n"+util.inspect(output, {colors:useColors, depth:10}));
|
||||
} else {
|
||||
node.log(util.inspect(output, {colors:useColors}));
|
||||
}
|
||||
}
|
||||
if (this.active) {
|
||||
if (this.tosidebar == true) {
|
||||
sendDebug({id:node.id, z:node.z, name:node.name, topic:msg.topic, property:property, msg:output, _path:msg._path});
|
||||
}
|
||||
if (this.tostatus === true) {
|
||||
var st = util.inspect(output);
|
||||
if (st.length > 32) { st = st.substr(0,32) + "..."; }
|
||||
node.oldStatus = {fill:colors[node.severity], shape:"dot", text:st};
|
||||
node.status(node.oldStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("debug",DebugNode, {
|
||||
settings: {
|
||||
debugUseColors: {
|
||||
value: false,
|
||||
},
|
||||
debugMaxLength: {
|
||||
value: 1000,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function sendDebug(msg) {
|
||||
// don't put blank errors in sidebar (but do add to logs)
|
||||
//if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; }
|
||||
if (msg.msg instanceof Error) {
|
||||
msg.format = "error";
|
||||
var errorMsg = {};
|
||||
if (msg.msg.name) {
|
||||
errorMsg.name = msg.msg.name;
|
||||
}
|
||||
if (msg.msg.hasOwnProperty('message')) {
|
||||
errorMsg.message = msg.msg.message;
|
||||
} else {
|
||||
errorMsg.message = msg.msg.toString();
|
||||
}
|
||||
msg.msg = JSON.stringify(errorMsg);
|
||||
} else if (msg.msg instanceof Buffer) {
|
||||
msg.format = "buffer["+msg.msg.length+"]";
|
||||
msg.msg = msg.msg.toString('hex');
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength);
|
||||
}
|
||||
} else if (msg.msg && typeof msg.msg === 'object') {
|
||||
try {
|
||||
msg.format = msg.msg.constructor.name || "Object";
|
||||
// Handle special case of msg.req/res objects from HTTP In node
|
||||
if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") {
|
||||
msg.format = "Object";
|
||||
}
|
||||
} catch(err) {
|
||||
msg.format = "Object";
|
||||
}
|
||||
if (/error/i.test(msg.format)) {
|
||||
msg.msg = JSON.stringify({
|
||||
name: msg.msg.name,
|
||||
message: msg.msg.message
|
||||
});
|
||||
} else {
|
||||
var isArray = util.isArray(msg.msg);
|
||||
if (isArray) {
|
||||
msg.format = "array["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
// msg.msg = msg.msg.slice(0,debuglength);
|
||||
msg.msg = {
|
||||
__encoded__: true,
|
||||
type: "array",
|
||||
data: msg.msg.slice(0,debuglength),
|
||||
length: msg.msg.length
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isArray || (msg.format === "Object")) {
|
||||
msg.msg = safeJSONStringify(msg.msg, function(key, value) {
|
||||
if (key === '_req' || key === '_res') {
|
||||
value = "[internal]"
|
||||
} else if (value instanceof Error) {
|
||||
value = value.toString()
|
||||
} else if (util.isArray(value) && value.length > debuglength) {
|
||||
value = {
|
||||
__encoded__: true,
|
||||
type: "array",
|
||||
data: value.slice(0,debuglength),
|
||||
length: value.length
|
||||
}
|
||||
} else if (typeof value === 'string') {
|
||||
if (value.length > debuglength) {
|
||||
value = value.substring(0,debuglength)+"...";
|
||||
}
|
||||
} else if (value && value.constructor) {
|
||||
if (value.type === "Buffer") {
|
||||
value.__encoded__ = true;
|
||||
value.length = value.data.length;
|
||||
if (value.length > debuglength) {
|
||||
value.data = value.data.slice(0,debuglength);
|
||||
}
|
||||
} else if (value.constructor.name === "ServerResponse") {
|
||||
value = "[internal]"
|
||||
} else if (value.constructor.name === "Socket") {
|
||||
value = "[internal]"
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}," ");
|
||||
} else {
|
||||
try { msg.msg = msg.msg.toString(); }
|
||||
catch(e) { msg.msg = "[Type not printable]"; }
|
||||
}
|
||||
}
|
||||
} else if (typeof msg.msg === "boolean") {
|
||||
msg.format = "boolean";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (typeof msg.msg === "number") {
|
||||
msg.format = "number";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (msg.msg === 0) {
|
||||
msg.format = "number";
|
||||
msg.msg = "0";
|
||||
} else if (msg.msg === null || typeof msg.msg === "undefined") {
|
||||
msg.format = (msg.msg === null)?"null":"undefined";
|
||||
msg.msg = "(undefined)";
|
||||
} else {
|
||||
msg.format = "string["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength)+"...";
|
||||
}
|
||||
}
|
||||
// if (msg.msg.length > debuglength) {
|
||||
// msg.msg = msg.msg.substr(0,debuglength) +" ....";
|
||||
// }
|
||||
RED.comms.publish("debug",msg);
|
||||
}
|
||||
|
||||
DebugNode.logHandler = new events.EventEmitter();
|
||||
DebugNode.logHandler.on("log",function(msg) {
|
||||
if (msg.level === RED.log.WARN || msg.level === RED.log.ERROR) {
|
||||
sendDebug(msg);
|
||||
}
|
||||
});
|
||||
RED.log.addHandler(DebugNode.logHandler);
|
||||
|
||||
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
|
||||
var node = RED.nodes.getNode(req.params.id);
|
||||
var state = req.params.state;
|
||||
if (node !== null && typeof node !== "undefined" ) {
|
||||
if (state === "enable") {
|
||||
node.active = true;
|
||||
res.sendStatus(200);
|
||||
if (node.tostatus) { node.status({}); }
|
||||
} else if (state === "disable") {
|
||||
node.active = false;
|
||||
res.sendStatus(201);
|
||||
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
|
||||
node.oldStatus.shape = "ring";
|
||||
node.status(node.oldStatus);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
// As debug/view/debug-utils.js is loaded via <script> tag, it won't get
|
||||
// the auth header attached. So do not use RED.auth.needsPermission here.
|
||||
RED.httpAdmin.get("/debug/view/*",function(req,res) {
|
||||
var options = {
|
||||
root: __dirname + '/lib/debug/',
|
||||
dotfiles: 'deny'
|
||||
};
|
||||
res.sendFile(req.params[0], options);
|
||||
});
|
||||
};
|
@@ -1,319 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="link in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row node-input-link-row"></div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="link out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row node-input-link-row"></div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="link in">
|
||||
<p>Create virtual wires between flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>The node can be connected to any <code>link out</code> node that exists on any tab.
|
||||
Once connected, they behave as if they were wired together.</p>
|
||||
<p>The wires between link nodes are only displayed when a link node is selected.
|
||||
If there are any wires to other tabs, a virtual node is shown that can be clicked
|
||||
on to jump to the appropriate tab.</p>
|
||||
<p><b>Note: </b>Links cannot be created going into, or out of, a subflow.</p>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="link out">
|
||||
<p>Create virtual wires between flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>The node can be connected to any <code>link in</code> node that exists on any tab.
|
||||
Once connected, they behave as if they were wired together.</p>
|
||||
<p>The wires between link nodes are only displayed when a link node is selected.
|
||||
If there are any wires to other tabs, a virtual node is show that can be clicked
|
||||
on to jump to the appropriate tab.</p>
|
||||
<p><b>Note: </b>Links cannot be created going into, or out of, a subflow.</p>
|
||||
</script>
|
||||
<style>
|
||||
#node-input-link-container {
|
||||
position: relative;
|
||||
}
|
||||
#node-input-link-container li {
|
||||
padding: 2px 5px;
|
||||
background: none;
|
||||
font-size: 0.8em;
|
||||
margin:0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#node-input-link-container li label {
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#node-input-link-container li label input {
|
||||
vertical-align: top;
|
||||
width:15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
#node-input-link-container li:hover,
|
||||
#node-input-link-container li:hover .node-input-target-node-sublabel {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.node-input-link-node-sublabel {
|
||||
position:absolute;
|
||||
right: 0px;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
|
||||
function sortNodeList(nodeList,sortOn,sortOnSecond) {
|
||||
var currentSort = nodeList.data('currentSort');
|
||||
var currentSortOrder = nodeList.data('currentSortOrder');
|
||||
|
||||
if (!currentSort) {
|
||||
currentSort = sortOn;
|
||||
currentSortOrder = 'a';
|
||||
} else {
|
||||
if (currentSort === sortOn) {
|
||||
currentSortOrder = (currentSortOrder === 'a'?'d':'a');
|
||||
} else {
|
||||
currentSortOrder = 'a';
|
||||
}
|
||||
currentSort = sortOn;
|
||||
}
|
||||
nodeList.data('currentSort',currentSort);
|
||||
nodeList.data('currentSortOrder',currentSortOrder);
|
||||
|
||||
$("#node-input-link-container-div .fa").hide();
|
||||
$(".node-input-link-sort-"+currentSort+"-"+currentSortOrder).show();
|
||||
|
||||
|
||||
var items = nodeList.find("li").get();
|
||||
items.sort(function(a,b) {
|
||||
var labelA = $(a).find(".node-input-link-node-"+currentSort).text().toLowerCase();
|
||||
var labelB = $(b).find(".node-input-link-node-"+currentSort).text().toLowerCase();
|
||||
if (labelA < labelB) { return currentSortOrder==='a'?-1:1; }
|
||||
if (labelA > labelB) { return currentSortOrder==='a'?1:-1; }
|
||||
|
||||
if (sortOnSecond) {
|
||||
labelA = $(a).find(".node-input-link-node-"+sortOnSecond).text().toLowerCase();
|
||||
labelB = $(b).find(".node-input-link-node-"+sortOnSecond).text().toLowerCase();
|
||||
if (labelA < labelB) { return currentSortOrder==='a'?-1:1; }
|
||||
if (labelA > labelB) { return currentSortOrder==='a'?1:-1; }
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
$.each(items, function(i, li) {
|
||||
nodeList.append(li);
|
||||
});
|
||||
}
|
||||
function onEditPrepare(node,targetType) {
|
||||
if (!node.links) {
|
||||
node.links = [];
|
||||
}
|
||||
node.oldLinks = [];
|
||||
|
||||
$('<div id="node-input-link-container-div" style="min-height: 100px;position: relative; box-sizing: border-box; border-radius: 2px; height: 180px; border: 1px solid #ccc;overflow:hidden; ">'+
|
||||
' <div style="box-sizing: border-box; line-height: 20px; font-size: 0.8em; border-bottom: 1px solid #ddd; height: 20px;">'+
|
||||
' <div style="display: inline-block;margin-left: 5px;"><a id="node-input-link-sort-label" href="#" data-i18n="[title]node-red:link.label.sortByLabel"><span data-i18n="node-red:link.label.node">name</span> <i class="node-input-link-sort-label-a fa fa-caret-down"></i><i class="node-input-link-sort-label-d fa fa-caret-up"></i></a></div>'+
|
||||
' <div style="position: absolute; right: 10px; width: 50px; display: inline-block; text-align: right;"><a id="node-input-link-sort-type" href="#" data-i18n="[title]node-red:link.label.sortByFlow"><i class="node-input-link-sort-sublabel-a fa fa-caret-down"></i><i class="node-input-link-sort-sublabel-d fa fa-caret-up"></i> <span data-i18n="node-red:link.label.type">flow</span></a></div>'+
|
||||
' </div>'+
|
||||
' <div style="background: #fbfbfb; box-sizing: border-box; position:absolute; top:20px;bottom:0;left:0px;right:0px; overflow-y: scroll; overflow-x: hidden;">'+
|
||||
' <ul id="node-input-link-container" style=" list-style-type:none; margin: 0;"></ul>'+
|
||||
' </div>'+
|
||||
'</div>').appendTo('.node-input-link-row');
|
||||
|
||||
var nodeList = $("#node-input-link-container");
|
||||
var candidateNodes = RED.nodes.filterNodes({type:targetType});
|
||||
var inSubflow = !!RED.nodes.subflow(node.z);
|
||||
candidateNodes.forEach(function(n) {
|
||||
if (inSubflow) {
|
||||
if (n.z !== node.z) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!!RED.nodes.subflow(n.z)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var isChecked = false;
|
||||
|
||||
isChecked = (node.links.indexOf(n.id) !== -1) || (n.links||[]).indexOf(node.id) !== -1;
|
||||
|
||||
if (isChecked) {
|
||||
node.oldLinks.push(n.id);
|
||||
}
|
||||
|
||||
var container = $('<li/>',{class:"node-input-link-node"});
|
||||
var row = $('<label/>',{for:"node-input-link-node-"+n.id}).appendTo(container);
|
||||
$('<input>',{type:"checkbox",class:"node-input-link-node-checkbox",id:"node-input-link-node-"+n.id})
|
||||
.data('node-id',n.id)
|
||||
.prop('checked', isChecked)
|
||||
.appendTo(row);
|
||||
container.on('mouseover',function(e) {
|
||||
n.highlighted = true;
|
||||
n.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
container.on('mouseout',function(e) {
|
||||
n.highlighted = false;
|
||||
n.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
var labelSpan = $('<span>');
|
||||
var label = n.name||n.id;
|
||||
var sublabel;
|
||||
var tab = RED.nodes.workspace(n.z);
|
||||
if (tab) {
|
||||
sublabel = tab.label||tab.id;
|
||||
} else {
|
||||
tab = RED.nodes.subflow(n.z);
|
||||
sublabel = "subflow : "+tab.name;
|
||||
}
|
||||
$('<span>',{class:"node-input-link-node-label",style:"white-space:nowrap"}).text(label).appendTo(row);
|
||||
if (sublabel) {
|
||||
$('<span>',{class:"node-input-link-node-sublabel"}).text(sublabel).appendTo(row);
|
||||
}
|
||||
container.appendTo(nodeList);
|
||||
});
|
||||
|
||||
sortNodeList(nodeList,'sublabel','label');
|
||||
|
||||
$("#node-input-link-sort-label").click(function(e) {
|
||||
e.preventDefault();
|
||||
sortNodeList(nodeList,'label');
|
||||
});
|
||||
|
||||
$("#node-input-link-sort-type").click(function(e) {
|
||||
e.preventDefault();
|
||||
sortNodeList(nodeList,'sublabel');
|
||||
});
|
||||
}
|
||||
|
||||
function resizeNodeList() {
|
||||
var rows = $("#dialog-form>div:not(.node-input-link-row)");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0;i<rows.size();i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-input-link-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-link-container-div").css("height",height+"px");
|
||||
}
|
||||
|
||||
function onEditSave(node) {
|
||||
node.links = [];
|
||||
$(".node-input-link-node-checkbox").each(function(n) {
|
||||
if ($(this).prop("checked")) {
|
||||
node.links.push($(this).data('node-id'));
|
||||
}
|
||||
});
|
||||
node.oldLinks.sort();
|
||||
node.links.sort();
|
||||
var nodeMap = {};
|
||||
var length = Math.max(node.oldLinks.length,node.links.length);
|
||||
for (var i=0;i<length;i++) {
|
||||
if (i<node.oldLinks.length) {
|
||||
nodeMap[node.oldLinks[i]] = nodeMap[node.oldLinks[i]]||{};
|
||||
nodeMap[node.oldLinks[i]].old = true;
|
||||
}
|
||||
if (i<node.links.length) {
|
||||
nodeMap[node.links[i]] = nodeMap[node.links[i]]||{};
|
||||
nodeMap[node.links[i]].new = true;
|
||||
}
|
||||
}
|
||||
var n;
|
||||
for (var id in nodeMap) {
|
||||
if (nodeMap.hasOwnProperty(id)) {
|
||||
n = RED.nodes.node(id);
|
||||
if (n) {
|
||||
if (nodeMap[id].old && !nodeMap[id].new) {
|
||||
// Removed id
|
||||
i = n.links.indexOf(node.id);
|
||||
if (i > -1) {
|
||||
n.links.splice(i,1);
|
||||
}
|
||||
} else if (!nodeMap[id].old && nodeMap[id].new) {
|
||||
// Added id
|
||||
i = n.links.indexOf(id);
|
||||
if (i === -1) {
|
||||
n.links.push(node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAdd() {
|
||||
for (var i=0;i<this.links.length;i++) {
|
||||
var n = RED.nodes.node(this.links[i]);
|
||||
if (n && n.links.indexOf(this.id) === -1) {
|
||||
n.links.push(this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType('link in',{
|
||||
category: 'input',
|
||||
color:"#ddd",//"#87D8CF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
links: { value: [] }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "link-out.png",
|
||||
outputLabels: function(i) {
|
||||
return this.name||this._("link.linkIn");
|
||||
},
|
||||
label: function() {
|
||||
return this.name||this._("link.linkIn");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
onEditPrepare(this,"link out");
|
||||
},
|
||||
oneditsave: function() {
|
||||
onEditSave(this);
|
||||
},
|
||||
onadd: onAdd,
|
||||
oneditresize: resizeNodeList
|
||||
});
|
||||
|
||||
RED.nodes.registerType('link out',{
|
||||
category: 'output',
|
||||
color:"#ddd",//"#87D8CF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
links: { value: []}
|
||||
},
|
||||
align:"right",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "link-out.png",
|
||||
inputLabels: function(i) {
|
||||
return this.name||this._("link.linkOut");
|
||||
},
|
||||
label: function() {
|
||||
return this.name||this._("link.linkOut");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
onEditPrepare(this,"link in");
|
||||
},
|
||||
oneditsave: function() {
|
||||
onEditSave(this);
|
||||
},
|
||||
onadd: onAdd,
|
||||
oneditresize: resizeNodeList
|
||||
});
|
||||
})();
|
||||
</script>
|
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
var yaml = require("js-yaml");
|
||||
|
||||
|
||||
/**
|
||||
* Custom Mustache Context capable to resolve message property and node
|
||||
* flow and global context
|
||||
*/
|
||||
function NodeContext(msg, nodeContext, parent, escapeStrings) {
|
||||
this.msgContext = new mustache.Context(msg,parent);
|
||||
this.nodeContext = nodeContext;
|
||||
this.escapeStrings = escapeStrings;
|
||||
}
|
||||
|
||||
NodeContext.prototype = new mustache.Context();
|
||||
|
||||
NodeContext.prototype.lookup = function (name) {
|
||||
// try message first:
|
||||
try {
|
||||
var value = this.msgContext.lookup(name);
|
||||
if (value !== undefined) {
|
||||
if (this.escapeStrings && typeof value === "string") {
|
||||
value = value.replace(/\\/g, "\\\\");
|
||||
value = value.replace(/\n/g, "\\n");
|
||||
value = value.replace(/\t/g, "\\t");
|
||||
value = value.replace(/\r/g, "\\r");
|
||||
value = value.replace(/\f/g, "\\f");
|
||||
value = value.replace(/[\b]/g, "\\b");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// try node context:
|
||||
var dot = name.indexOf(".");
|
||||
/* istanbul ignore else */
|
||||
if (dot > 0) {
|
||||
var contextName = name.substr(0, dot);
|
||||
var variableName = name.substr(dot + 1);
|
||||
|
||||
if (contextName === "flow" && this.nodeContext.flow) {
|
||||
return this.nodeContext.flow.get(variableName);
|
||||
}
|
||||
else if (contextName === "global" && this.nodeContext.global) {
|
||||
return this.nodeContext.global.get(variableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
NodeContext.prototype.push = function push (view) {
|
||||
return new NodeContext(view, this.nodeContext,this.msgContext);
|
||||
};
|
||||
|
||||
function TemplateNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
this.field = n.field || "payload";
|
||||
this.template = n.template;
|
||||
this.syntax = n.syntax || "mustache";
|
||||
this.fieldType = n.fieldType || "msg";
|
||||
this.outputFormat = n.output || "str";
|
||||
|
||||
var node = this;
|
||||
node.on("input", function(msg) {
|
||||
try {
|
||||
var value;
|
||||
/***
|
||||
* Allow template contents to be defined externally
|
||||
* through inbound msg.template IFF node.template empty
|
||||
*/
|
||||
var template = node.template;
|
||||
if (msg.hasOwnProperty("template")) {
|
||||
if (template == "" || template === null) {
|
||||
template = msg.template;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.syntax === "mustache") {
|
||||
if (node.outputFormat === "json") {
|
||||
value = mustache.render(template,new NodeContext(msg, node.context(), null, true));
|
||||
} else {
|
||||
value = mustache.render(template,new NodeContext(msg, node.context(), null, false));
|
||||
}
|
||||
} else {
|
||||
value = template;
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (node.outputFormat === "json") {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (node.outputFormat === "yaml") {
|
||||
value = yaml.load(value);
|
||||
}
|
||||
|
||||
if (node.fieldType === 'msg') {
|
||||
RED.util.setMessageProperty(msg,node.field,value);
|
||||
} else if (node.fieldType === 'flow') {
|
||||
node.context().flow.set(node.field,value);
|
||||
} else if (node.fieldType === 'global') {
|
||||
node.context().global.set(node.field,value);
|
||||
}
|
||||
node.send(msg);
|
||||
}
|
||||
catch(err) {
|
||||
node.error(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("template",TemplateNode);
|
||||
RED.library.register("templates");
|
||||
}
|
@@ -1,173 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
function TriggerNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.bytopic = n.bytopic || "all";
|
||||
this.op1 = n.op1 || "1";
|
||||
this.op2 = n.op2 || "0";
|
||||
this.op1type = n.op1type || "str";
|
||||
this.op2type = n.op2type || "str";
|
||||
|
||||
if (this.op1type === 'val') {
|
||||
if (this.op1 === 'true' || this.op1 === 'false') {
|
||||
this.op1type = 'bool'
|
||||
} else if (this.op1 === 'null') {
|
||||
this.op1type = 'null';
|
||||
this.op1 = null;
|
||||
} else {
|
||||
this.op1type = 'str';
|
||||
}
|
||||
}
|
||||
if (this.op2type === 'val') {
|
||||
if (this.op2 === 'true' || this.op2 === 'false') {
|
||||
this.op2type = 'bool'
|
||||
} else if (this.op2 === 'null') {
|
||||
this.op2type = 'null';
|
||||
this.op2 = null;
|
||||
} else {
|
||||
this.op2type = 'str';
|
||||
}
|
||||
}
|
||||
this.extend = n.extend || "false";
|
||||
this.units = n.units || "ms";
|
||||
this.reset = n.reset || '';
|
||||
this.duration = parseFloat(n.duration);
|
||||
if (isNaN(this.duration)) {
|
||||
this.duration = 250;
|
||||
}
|
||||
if (this.duration < 0) {
|
||||
this.loop = true;
|
||||
this.duration = this.duration * -1;
|
||||
this.extend = false;
|
||||
}
|
||||
|
||||
if (this.units == "s") { this.duration = this.duration * 1000; }
|
||||
if (this.units == "min") { this.duration = this.duration * 1000 * 60; }
|
||||
if (this.units == "hr") { this.duration = this.duration * 1000 *60 * 60; }
|
||||
|
||||
this.op1Templated = (this.op1type === 'str' && this.op1.indexOf("{{") != -1);
|
||||
this.op2Templated = (this.op2type === 'str' && this.op2.indexOf("{{") != -1);
|
||||
if ((this.op1type === "num") && (!isNaN(this.op1))) { this.op1 = Number(this.op1); }
|
||||
if ((this.op2type === "num") && (!isNaN(this.op2))) { this.op2 = Number(this.op2); }
|
||||
//if (this.op1 == "null") { this.op1 = null; }
|
||||
//if (this.op2 == "null") { this.op2 = null; }
|
||||
//try { this.op1 = JSON.parse(this.op1); }
|
||||
//catch(e) { this.op1 = this.op1; }
|
||||
//try { this.op2 = JSON.parse(this.op2); }
|
||||
//catch(e) { this.op2 = this.op2; }
|
||||
|
||||
var node = this;
|
||||
node.topics = {};
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var topic = msg.topic || "_none";
|
||||
if (node.bytopic === "all") { topic = "_none"; }
|
||||
node.topics[topic] = node.topics[topic] || {};
|
||||
if (msg.hasOwnProperty("reset") || ((node.reset !== '') && msg.hasOwnProperty("payload") && (msg.payload !== null) && msg.payload.toString && (msg.payload.toString() == node.reset)) ) {
|
||||
if (node.loop === true) { clearInterval(node.topics[topic].tout); }
|
||||
else { clearTimeout(node.topics[topic].tout); }
|
||||
delete node.topics[topic];
|
||||
node.status({});
|
||||
}
|
||||
else {
|
||||
if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) {
|
||||
if (node.op2type === "pay" || node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
else if (node.op2Templated) { node.topics[topic].m2 = mustache.render(node.op2,msg); }
|
||||
else if (node.op2type !== "nul") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
|
||||
if (node.op1type === "pay") { }
|
||||
else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
|
||||
else if (node.op1type !== "nul") {
|
||||
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
|
||||
}
|
||||
|
||||
if (node.duration === 0) { node.topics[topic].tout = 0; }
|
||||
else if (node.loop === true) {
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[topic].tout) { clearInterval(node.topics[topic].tout); }
|
||||
/* istanbul ignore else */
|
||||
if (node.op1type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, node.duration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!node.topics[topic].tout) {
|
||||
node.topics[topic].tout = setTimeout(function() {
|
||||
var msg2 = null;
|
||||
if (node.op2type !== "nul") {
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
delete node.topics[topic];
|
||||
node.send(msg2);
|
||||
}
|
||||
else { delete node.topics[topic]; }
|
||||
node.status({});
|
||||
}, node.duration);
|
||||
}
|
||||
}
|
||||
node.status({fill:"blue",shape:"dot",text:" "});
|
||||
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
|
||||
}
|
||||
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
|
||||
/* istanbul ignore else */
|
||||
if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[topic].tout) { clearTimeout(node.topics[topic].tout); }
|
||||
node.topics[topic].tout = setTimeout(function() {
|
||||
var msg2 = null;
|
||||
if (node.op2type !== "nul") {
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
if (node.topics[topic] !== undefined) {
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
}
|
||||
}
|
||||
delete node.topics[topic];
|
||||
node.status({});
|
||||
node.send(msg2);
|
||||
}, node.duration);
|
||||
}
|
||||
else {
|
||||
if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
}
|
||||
}
|
||||
});
|
||||
this.on("close", function() {
|
||||
for (var t in node.topics) {
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[t]) {
|
||||
if (node.loop === true) { clearInterval(node.topics[t].tout); }
|
||||
else { clearTimeout(node.topics[t].tout); }
|
||||
delete node.topics[t];
|
||||
}
|
||||
}
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("trigger",TriggerNode);
|
||||
}
|
@@ -1,332 +0,0 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var exec = require('child_process').exec;
|
||||
var spawn = require('child_process').spawn;
|
||||
var fs = require('fs');
|
||||
|
||||
var gpioCommand = __dirname+'/nrgpio';
|
||||
|
||||
try {
|
||||
var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString();
|
||||
if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); }
|
||||
} catch(err) {
|
||||
throw "Info : "+RED._("rpi-gpio.errors.ignorenode");
|
||||
}
|
||||
|
||||
try {
|
||||
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
|
||||
// /usr/lib/python2.7/dist-packages/RPi/GPIO
|
||||
} catch(err) {
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
|
||||
}
|
||||
catch(err) {
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/dist-packages/RPi/GPIO"); // test on Hypriot
|
||||
}
|
||||
catch(err) {
|
||||
RED.log.warn(RED._("rpi-gpio.errors.libnotfound"));
|
||||
throw "Warning : "+RED._("rpi-gpio.errors.libnotfound");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
|
||||
RED.log.error(RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
|
||||
throw "Error : "+RED._("rpi-gpio.errors.mustbeexecutable");
|
||||
}
|
||||
|
||||
// the magic to make python print stuff immediately
|
||||
process.env.PYTHONUNBUFFERED = 1;
|
||||
|
||||
var pinsInUse = {};
|
||||
var pinTypes = {"out":RED._("rpi-gpio.types.digout"), "tri":RED._("rpi-gpio.types.input"), "up":RED._("rpi-gpio.types.pullup"), "down":RED._("rpi-gpio.types.pulldown"), "pwm":RED._("rpi-gpio.types.pwmout")};
|
||||
|
||||
function GPIOInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.buttonState = -1;
|
||||
this.pin = n.pin;
|
||||
this.intype = n.intype;
|
||||
this.read = n.read || false;
|
||||
this.debounce = Number(n.debounce || 25);
|
||||
if (this.read) { this.buttonState = -2; }
|
||||
var node = this;
|
||||
if (!pinsInUse.hasOwnProperty(this.pin)) {
|
||||
pinsInUse[this.pin] = this.intype;
|
||||
}
|
||||
else {
|
||||
if ((pinsInUse[this.pin] !== this.intype)||(pinsInUse[this.pin] === "pwm")) {
|
||||
node.warn(RED._("rpi-gpio.errors.alreadyset",{pin:this.pin,type:pinTypes[pinsInUse[this.pin]]}));
|
||||
}
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
|
||||
node.running = true;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var d = data.toString().trim().split("\n");
|
||||
for (var i = 0; i < d.length; i++) {
|
||||
if (d[i] === '') { return; }
|
||||
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
|
||||
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
|
||||
}
|
||||
node.buttonState = d[i];
|
||||
node.status({fill:"green",shape:"dot",text:d[i]});
|
||||
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
|
||||
}
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
|
||||
|
||||
function GPIOOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.pin = n.pin;
|
||||
this.set = n.set || false;
|
||||
this.level = n.level || 0;
|
||||
this.freq = n.freq || 100;
|
||||
this.out = n.out || "out";
|
||||
var node = this;
|
||||
if (!pinsInUse.hasOwnProperty(this.pin)) {
|
||||
pinsInUse[this.pin] = this.out;
|
||||
}
|
||||
else {
|
||||
if ((pinsInUse[this.pin] !== this.out)||(pinsInUse[this.pin] === "pwm")) {
|
||||
node.warn(RED._("rpi-gpio.errors.alreadyset",{pin:this.pin,type:pinTypes[pinsInUse[this.pin]]}));
|
||||
}
|
||||
}
|
||||
|
||||
function inputlistener(msg) {
|
||||
if (msg.payload === "true") { msg.payload = true; }
|
||||
if (msg.payload === "false") { msg.payload = false; }
|
||||
var out = Number(msg.payload);
|
||||
var limit = 1;
|
||||
if (node.out === "pwm") { limit = 100; }
|
||||
if ((out >= 0) && (out <= limit)) {
|
||||
if (RED.settings.verbose) { node.log("out: "+out); }
|
||||
if (node.child !== null) {
|
||||
node.child.stdin.write(out+"\n");
|
||||
node.status({fill:"green",shape:"dot",text:msg.payload.toString()});
|
||||
}
|
||||
else {
|
||||
node.error(RED._("rpi-gpio.errors.pythoncommandnotfound"),msg);
|
||||
node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.not-running"});
|
||||
}
|
||||
}
|
||||
else { node.warn(RED._("rpi-gpio.errors.invalidinput")+": "+out); }
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
if (node.set && (node.out === "out")) {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
|
||||
node.status({fill:"green",shape:"dot",text:node.level});
|
||||
} else {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.freq]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
}
|
||||
node.running = true;
|
||||
|
||||
node.on("input", inputlistener);
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
function PiMouseNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.butt = n.butt || 7;
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
data = Number(data);
|
||||
if (data === 1) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
|
||||
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-mouse",PiMouseNode);
|
||||
|
||||
function PiKeyboardNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var b = data.toString().trim().split(",");
|
||||
var act = "up";
|
||||
if (b[1] === "1") { act = "down"; }
|
||||
if (b[1] === "2") { act = "repeat"; }
|
||||
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-keyboard",PiKeyboardNode);
|
||||
|
||||
var pitype = { type:"" };
|
||||
exec(gpioCommand+" info", function(err,stdout,stderr) {
|
||||
if (err) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.version"));
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
|
||||
pitype.type = info["TYPE"];
|
||||
}
|
||||
catch(e) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/rpi-gpio/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
|
||||
res.json(pitype);
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/rpi-pins/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
|
||||
res.json(pinsInUse);
|
||||
});
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var util = require("util");
|
||||
var mqtt = require("./mqtt");
|
||||
var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
|
||||
|
||||
util.log("[warn] nodes/core/io/lib/mqttConnectionPool.js is deprecated and will be removed in a future release of Node-RED. Please report this usage to the Node-RED mailing list.");
|
||||
|
||||
var connections = {};
|
||||
|
||||
function matchTopic(ts,t) {
|
||||
if (ts == "#") {
|
||||
return true;
|
||||
}
|
||||
var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
||||
return re.test(t);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: function(broker,port,clientid,username,password,will) {
|
||||
var id = "["+(username||"")+":"+(password||"")+"]["+(clientid||"")+"]@"+broker+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var uid = (1+Math.random()*4294967295).toString(16);
|
||||
var client = mqtt.createClient(port,broker);
|
||||
client.uid = uid;
|
||||
client.setMaxListeners(0);
|
||||
var options = {keepalive:15};
|
||||
options.clientId = clientid || 'mqtt_' + (1+Math.random()*4294967295).toString(16);
|
||||
options.username = username;
|
||||
options.password = password;
|
||||
options.will = will;
|
||||
var queue = [];
|
||||
var subscriptions = {};
|
||||
var connecting = false;
|
||||
var obj = {
|
||||
_instances: 0,
|
||||
publish: function(msg) {
|
||||
if (client.isConnected()) {
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
} else {
|
||||
if (!connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
queue.push(msg);
|
||||
}
|
||||
},
|
||||
subscribe: function(topic,qos,callback,ref) {
|
||||
ref = ref||0;
|
||||
subscriptions[topic] = subscriptions[topic]||{};
|
||||
|
||||
var sub = {
|
||||
topic:topic,
|
||||
qos:qos,
|
||||
handler:function(mtopic,mpayload,mqos,mretain) {
|
||||
if (matchTopic(topic,mtopic)) {
|
||||
callback(mtopic,mpayload,mqos,mretain);
|
||||
}
|
||||
},
|
||||
ref: ref
|
||||
};
|
||||
subscriptions[topic][ref] = sub;
|
||||
client.on('message',sub.handler);
|
||||
if (client.isConnected()) {
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
},
|
||||
unsubscribe: function(topic,ref) {
|
||||
ref = ref||0;
|
||||
var sub = subscriptions[topic];
|
||||
if (sub) {
|
||||
if (sub[ref]) {
|
||||
client.removeListener('message',sub[ref].handler);
|
||||
delete sub[ref];
|
||||
}
|
||||
if (Object.keys(sub).length == 0) {
|
||||
delete subscriptions[topic];
|
||||
client.unsubscribe(topic);
|
||||
}
|
||||
}
|
||||
},
|
||||
on: function(a,b){
|
||||
client.on(a,b);
|
||||
},
|
||||
once: function(a,b){
|
||||
client.once(a,b);
|
||||
},
|
||||
connect: function() {
|
||||
if (client && !client.isConnected() && !connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
},
|
||||
disconnect: function(ref) {
|
||||
|
||||
this._instances -= 1;
|
||||
if (this._instances == 0) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
delete connections[id];
|
||||
}
|
||||
},
|
||||
isConnected: function() {
|
||||
return client.isConnected();
|
||||
}
|
||||
};
|
||||
client.on('connect',function() {
|
||||
if (client) {
|
||||
util.log('[mqtt] ['+uid+'] connected to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
for (var s in subscriptions) {
|
||||
var topic = s;
|
||||
var qos = 0;
|
||||
for (var r in subscriptions[s]) {
|
||||
qos = Math.max(qos,subscriptions[s][r].qos);
|
||||
}
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
//console.log("connected - publishing",queue.length,"messages");
|
||||
while(queue.length) {
|
||||
var msg = queue.shift();
|
||||
//console.log(msg);
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.on('connectionlost', function(err) {
|
||||
util.log('[mqtt] ['+uid+'] connection lost to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
setTimeout(function() {
|
||||
obj.connect();
|
||||
}, settings.mqttReconnectTime||5000);
|
||||
});
|
||||
client.on('disconnect', function() {
|
||||
connecting = false;
|
||||
util.log('[mqtt] ['+uid+'] disconnected from broker tcp://'+broker+':'+port);
|
||||
});
|
||||
|
||||
return obj
|
||||
}();
|
||||
}
|
||||
connections[id]._instances += 1;
|
||||
return connections[id];
|
||||
}
|
||||
};
|
@@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>指定したプロパティ(デフォルトは<code>payload</code>)を分析し、<code>sentiment</code>オブジェクトを追加します。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>AFINN-111による感情分析の結果</dd>
|
||||
<dt>sentiment.score <span class="property-type">数値</span></dt>
|
||||
<dd>感情分析スコア</dd>
|
||||
</dl>
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>ゼロ以上のスコアはポジティブ、ゼロ以下はネガティブを意味します。</p>
|
||||
<p>スコアの範囲は通常-5から+5ですが、より大きかったり小さかったりすることもあります。</p>
|
||||
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>を参照してください。</p>
|
||||
</script>
|
@@ -1,372 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
var operators = {
|
||||
'eq': function(a, b) { return a == b; },
|
||||
'neq': function(a, b) { return a != b; },
|
||||
'lt': function(a, b) { return a < b; },
|
||||
'lte': function(a, b) { return a <= b; },
|
||||
'gt': function(a, b) { return a > b; },
|
||||
'gte': function(a, b) { return a >= b; },
|
||||
'btwn': function(a, b, c) { return a >= b && a <= c; },
|
||||
'cont': function(a, b) { return (a + "").indexOf(b) != -1; },
|
||||
'regex': function(a, b, c, d) { return (a + "").match(new RegExp(b,d?'i':'')); },
|
||||
'true': function(a) { return a === true; },
|
||||
'false': function(a) { return a === false; },
|
||||
'null': function(a) { return (typeof a == "undefined" || a === null); },
|
||||
'nnull': function(a) { return (typeof a != "undefined" && a !== null); },
|
||||
'istype': function(a, b) {
|
||||
if (b === "array") { return Array.isArray(a); }
|
||||
else if (b === "buffer") { return Buffer.isBuffer(a); }
|
||||
else if (b === "json") {
|
||||
try { JSON.parse(a); return true; } // or maybe ??? a !== null; }
|
||||
catch(e) { return false;}
|
||||
}
|
||||
else if (b === "null") { return a === null; }
|
||||
else { return typeof a === b && !Array.isArray(a) && !Buffer.isBuffer(a) && a !== null; }
|
||||
},
|
||||
'head': function(a, b, c, d, parts) {
|
||||
var count = Number(b);
|
||||
return (parts.index < count);
|
||||
},
|
||||
'tail': function(a, b, c, d, parts) {
|
||||
var count = Number(b);
|
||||
return (parts.count -count <= parts.index);
|
||||
},
|
||||
'index': function(a, b, c, d, parts) {
|
||||
var min = Number(b);
|
||||
var max = Number(c);
|
||||
var index = parts.index;
|
||||
return ((min <= index) && (index <= max));
|
||||
},
|
||||
'jsonata_exp': function(a, b) { return (b === true); },
|
||||
'else': function(a) { return a === true; }
|
||||
};
|
||||
|
||||
var _max_kept_msgs_count = undefined;
|
||||
|
||||
function max_kept_msgs_count(node) {
|
||||
if (_max_kept_msgs_count === undefined) {
|
||||
var name = "nodeMessageBufferMaxLength";
|
||||
if (RED.settings.hasOwnProperty(name)) {
|
||||
_max_kept_msgs_count = RED.settings[name];
|
||||
}
|
||||
else {
|
||||
_max_kept_msgs_count = 0;
|
||||
}
|
||||
}
|
||||
return _max_kept_msgs_count;
|
||||
}
|
||||
|
||||
function SwitchNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
this.rules = n.rules || [];
|
||||
this.property = n.property;
|
||||
this.propertyType = n.propertyType || "msg";
|
||||
|
||||
if (this.propertyType === 'jsonata') {
|
||||
try {
|
||||
this.property = RED.util.prepareJSONataExpression(this.property,this);
|
||||
} catch(err) {
|
||||
this.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkall = n.checkall || "true";
|
||||
this.previousValue = null;
|
||||
var node = this;
|
||||
var valid = true;
|
||||
var repair = n.repair;
|
||||
var needs_count = repair;
|
||||
for (var i=0; i<this.rules.length; i+=1) {
|
||||
var rule = this.rules[i];
|
||||
needs_count = needs_count || ((rule.t === "tail") || (rule.t === "jsonata_exp"));
|
||||
if (!rule.vt) {
|
||||
if (!isNaN(Number(rule.v))) {
|
||||
rule.vt = 'num';
|
||||
} else {
|
||||
rule.vt = 'str';
|
||||
}
|
||||
}
|
||||
if (rule.vt === 'num') {
|
||||
if (!isNaN(Number(rule.v))) {
|
||||
rule.v = Number(rule.v);
|
||||
}
|
||||
} else if (rule.vt === "jsonata") {
|
||||
try {
|
||||
rule.v = RED.util.prepareJSONataExpression(rule.v,node);
|
||||
} catch(err) {
|
||||
this.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (typeof rule.v2 !== 'undefined') {
|
||||
if (!rule.v2t) {
|
||||
if (!isNaN(Number(rule.v2))) {
|
||||
rule.v2t = 'num';
|
||||
} else {
|
||||
rule.v2t = 'str';
|
||||
}
|
||||
}
|
||||
if (rule.v2t === 'num') {
|
||||
rule.v2 = Number(rule.v2);
|
||||
} else if (rule.v2t === 'jsonata') {
|
||||
try {
|
||||
rule.v2 = RED.util.prepareJSONataExpression(rule.v2,node);
|
||||
} catch(err) {
|
||||
this.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pending_count = 0;
|
||||
var pending_id = 0;
|
||||
var pending_in = {};
|
||||
var pending_out = {};
|
||||
var received = {};
|
||||
|
||||
function add2group_in(id, msg, parts) {
|
||||
if (!(id in pending_in)) {
|
||||
pending_in[id] = {
|
||||
count: undefined,
|
||||
msgs: [],
|
||||
seq_no: pending_id++
|
||||
};
|
||||
}
|
||||
var group = pending_in[id];
|
||||
group.msgs.push(msg);
|
||||
pending_count++;
|
||||
var max_msgs = max_kept_msgs_count(node);
|
||||
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||
clear_pending();
|
||||
node.error(RED._("switch.errors.too-many"), msg);
|
||||
}
|
||||
if (parts.hasOwnProperty("count")) {
|
||||
group.count = parts.count;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
function del_group_in(id, group) {
|
||||
pending_count -= group.msgs.length;
|
||||
delete pending_in[id];
|
||||
}
|
||||
|
||||
function add2pending_in(msg) {
|
||||
var parts = msg.parts;
|
||||
if (parts.hasOwnProperty("id") &&
|
||||
parts.hasOwnProperty("index")) {
|
||||
var group = add2group_in(parts.id, msg, parts);
|
||||
var msgs = group.msgs;
|
||||
var count = group.count;
|
||||
if (count === msgs.length) {
|
||||
for (var i = 0; i < msgs.length; i++) {
|
||||
var msg = msgs[i];
|
||||
msg.parts.count = count;
|
||||
process_msg(msg, false);
|
||||
}
|
||||
del_group_in(parts.id, group);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function send_group(onwards, port_count) {
|
||||
var counts = new Array(port_count).fill(0);
|
||||
for (var i = 0; i < onwards.length; i++) {
|
||||
var onward = onwards[i];
|
||||
for (var j = 0; j < port_count; j++) {
|
||||
counts[j] += (onward[j] !== null) ? 1 : 0
|
||||
}
|
||||
}
|
||||
var ids = new Array(port_count);
|
||||
for (var j = 0; j < port_count; j++) {
|
||||
ids[j] = RED.util.generateId();
|
||||
}
|
||||
var ports = new Array(port_count);
|
||||
var indexes = new Array(port_count).fill(0);
|
||||
for (var i = 0; i < onwards.length; i++) {
|
||||
var onward = onwards[i];
|
||||
for (var j = 0; j < port_count; j++) {
|
||||
var msg = onward[j];
|
||||
if (msg) {
|
||||
var new_msg = RED.util.cloneMessage(msg);
|
||||
var parts = new_msg.parts;
|
||||
parts.id = ids[j];
|
||||
parts.index = indexes[j];
|
||||
parts.count = counts[j];
|
||||
ports[j] = new_msg;
|
||||
indexes[j]++;
|
||||
}
|
||||
else {
|
||||
ports[j] = null;
|
||||
}
|
||||
}
|
||||
node.send(ports);
|
||||
}
|
||||
}
|
||||
|
||||
function send2ports(onward, msg) {
|
||||
var parts = msg.parts;
|
||||
var gid = parts.id;
|
||||
received[gid] = ((gid in received) ? received[gid] : 0) +1;
|
||||
var send_ok = (received[gid] === parts.count);
|
||||
|
||||
if (!(gid in pending_out)) {
|
||||
pending_out[gid] = {
|
||||
onwards: []
|
||||
};
|
||||
}
|
||||
var group = pending_out[gid];
|
||||
var onwards = group.onwards;
|
||||
onwards.push(onward);
|
||||
pending_count++;
|
||||
if (send_ok) {
|
||||
send_group(onwards, onward.length, msg);
|
||||
pending_count -= onward.length;
|
||||
delete pending_out[gid];
|
||||
delete received[gid];
|
||||
}
|
||||
var max_msgs = max_kept_msgs_count(node);
|
||||
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||
clear_pending();
|
||||
node.error(RED._("switch.errors.too-many"), msg);
|
||||
}
|
||||
}
|
||||
|
||||
function msg_has_parts(msg) {
|
||||
if (msg.hasOwnProperty("parts")) {
|
||||
var parts = msg.parts;
|
||||
return (parts.hasOwnProperty("id") &&
|
||||
parts.hasOwnProperty("index"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function process_msg(msg, check_parts) {
|
||||
var has_parts = msg_has_parts(msg);
|
||||
if (needs_count && check_parts && has_parts &&
|
||||
add2pending_in(msg)) {
|
||||
return;
|
||||
}
|
||||
var onward = [];
|
||||
try {
|
||||
var prop;
|
||||
if (node.propertyType === 'jsonata') {
|
||||
prop = RED.util.evaluateJSONataExpression(node.property,msg);
|
||||
} else {
|
||||
prop = RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg);
|
||||
}
|
||||
var elseflag = true;
|
||||
for (var i=0; i<node.rules.length; i+=1) {
|
||||
var rule = node.rules[i];
|
||||
var test = prop;
|
||||
var v1,v2;
|
||||
if (rule.vt === 'prev') {
|
||||
v1 = node.previousValue;
|
||||
} else if (rule.vt === 'jsonata') {
|
||||
try {
|
||||
var exp = rule.v;
|
||||
if (rule.t === 'jsonata_exp') {
|
||||
if (has_parts) {
|
||||
exp.assign("I", msg.parts.index);
|
||||
exp.assign("N", msg.parts.count);
|
||||
}
|
||||
}
|
||||
v1 = RED.util.evaluateJSONataExpression(exp,msg);
|
||||
} catch(err) {
|
||||
node.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
return;
|
||||
}
|
||||
} else if (rule.vt === 'json') {
|
||||
v1 = "json";
|
||||
} else if (rule.vt === 'null') {
|
||||
v1 = "null";
|
||||
} else {
|
||||
try {
|
||||
v1 = RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg);
|
||||
} catch(err) {
|
||||
v1 = undefined;
|
||||
}
|
||||
}
|
||||
v2 = rule.v2;
|
||||
if (rule.v2t === 'prev') {
|
||||
v2 = node.previousValue;
|
||||
} else if (rule.v2t === 'jsonata') {
|
||||
try {
|
||||
v2 = RED.util.evaluateJSONataExpression(rule.v2,msg);
|
||||
} catch(err) {
|
||||
node.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
return;
|
||||
}
|
||||
} else if (typeof v2 !== 'undefined') {
|
||||
try {
|
||||
v2 = RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg);
|
||||
} catch(err) {
|
||||
v2 = undefined;
|
||||
}
|
||||
}
|
||||
if (rule.t == "else") { test = elseflag; elseflag = true; }
|
||||
if (operators[rule.t](test,v1,v2,rule.case,msg.parts)) {
|
||||
onward.push(msg);
|
||||
elseflag = false;
|
||||
if (node.checkall == "false") { break; }
|
||||
} else {
|
||||
onward.push(null);
|
||||
}
|
||||
}
|
||||
node.previousValue = prop;
|
||||
if (!repair || !has_parts) {
|
||||
node.send(onward);
|
||||
}
|
||||
else {
|
||||
send2ports(onward, msg);
|
||||
}
|
||||
} catch(err) {
|
||||
node.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
function clear_pending() {
|
||||
pending_count = 0;
|
||||
pending_id = 0;
|
||||
pending_in = {};
|
||||
pending_out = {};
|
||||
received = {};
|
||||
}
|
||||
|
||||
this.on('input', function(msg) {
|
||||
process_msg(msg, true);
|
||||
});
|
||||
|
||||
this.on('close', function() {
|
||||
clear_pending();
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("switch", SwitchNode);
|
||||
}
|
@@ -1,256 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function ChangeNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
var node = this;
|
||||
|
||||
this.rules = n.rules;
|
||||
var rule;
|
||||
if (!this.rules) {
|
||||
rule = {
|
||||
t:(n.action=="replace"?"set":n.action),
|
||||
p:n.property||""
|
||||
}
|
||||
|
||||
if ((rule.t === "set")||(rule.t === "move")) {
|
||||
rule.to = n.to||"";
|
||||
} else if (rule.t === "change") {
|
||||
rule.from = n.from||"";
|
||||
rule.to = n.to||"";
|
||||
rule.re = (n.reg===null||n.reg);
|
||||
}
|
||||
this.rules = [rule];
|
||||
}
|
||||
|
||||
var valid = true;
|
||||
for (var i=0;i<this.rules.length;i++) {
|
||||
rule = this.rules[i];
|
||||
// Migrate to type-aware rules
|
||||
if (!rule.pt) {
|
||||
rule.pt = "msg";
|
||||
}
|
||||
if (rule.t === "change" && rule.re) {
|
||||
rule.fromt = 're';
|
||||
delete rule.re;
|
||||
}
|
||||
if (rule.t === "set" && !rule.tot) {
|
||||
if (rule.to.indexOf("msg.") === 0 && !rule.tot) {
|
||||
rule.to = rule.to.substring(4);
|
||||
rule.tot = "msg";
|
||||
}
|
||||
}
|
||||
if (!rule.tot) {
|
||||
rule.tot = "str";
|
||||
}
|
||||
if (!rule.fromt) {
|
||||
rule.fromt = "str";
|
||||
}
|
||||
if (rule.t === "change" && rule.fromt !== 'msg' && rule.fromt !== 'flow' && rule.fromt !== 'global') {
|
||||
rule.fromRE = rule.from;
|
||||
if (rule.fromt !== 're') {
|
||||
rule.fromRE = rule.fromRE.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
}
|
||||
try {
|
||||
rule.fromRE = new RegExp(rule.fromRE, "g");
|
||||
} catch (e) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-from",{error:e.message}));
|
||||
}
|
||||
}
|
||||
if (rule.tot === 'num') {
|
||||
rule.to = Number(rule.to);
|
||||
} else if (rule.tot === 'json' || rule.tot === 'bin') {
|
||||
try {
|
||||
// check this is parsable JSON
|
||||
JSON.parse(rule.to);
|
||||
} catch(e2) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-json"));
|
||||
}
|
||||
} else if (rule.tot === 'bool') {
|
||||
rule.to = /^true$/i.test(rule.to);
|
||||
} else if (rule.tot === 'jsonata') {
|
||||
try {
|
||||
rule.to = RED.util.prepareJSONataExpression(rule.to,this);
|
||||
} catch(e) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyRule(msg,rule) {
|
||||
try {
|
||||
var property = rule.p;
|
||||
var value = rule.to;
|
||||
if (rule.tot === 'json') {
|
||||
value = JSON.parse(rule.to);
|
||||
} else if (rule.tot === 'bin') {
|
||||
value = Buffer.from(JSON.parse(rule.to))
|
||||
}
|
||||
var current;
|
||||
var fromValue;
|
||||
var fromType;
|
||||
var fromRE;
|
||||
if (rule.tot === "msg") {
|
||||
value = RED.util.getMessageProperty(msg,rule.to);
|
||||
} else if (rule.tot === 'flow') {
|
||||
value = node.context().flow.get(rule.to);
|
||||
} else if (rule.tot === 'global') {
|
||||
value = node.context().global.get(rule.to);
|
||||
} else if (rule.tot === 'date') {
|
||||
value = Date.now();
|
||||
} else if (rule.tot === 'jsonata') {
|
||||
try{
|
||||
value = RED.util.evaluateJSONataExpression(rule.to,msg);
|
||||
} catch(err) {
|
||||
node.error(RED._("change.errors.invalid-expr",{error:err.message}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (rule.t === 'change') {
|
||||
if (rule.fromt === 'msg' || rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
if (rule.fromt === "msg") {
|
||||
fromValue = RED.util.getMessageProperty(msg,rule.from);
|
||||
} else if (rule.fromt === 'flow') {
|
||||
fromValue = node.context().flow.get(rule.from);
|
||||
} else if (rule.fromt === 'global') {
|
||||
fromValue = node.context().global.get(rule.from);
|
||||
}
|
||||
if (typeof fromValue === 'number' || fromValue instanceof Number) {
|
||||
fromType = 'num';
|
||||
} else if (typeof fromValue === 'boolean') {
|
||||
fromType = 'bool'
|
||||
} else if (fromValue instanceof RegExp) {
|
||||
fromType = 're';
|
||||
fromRE = fromValue;
|
||||
} else if (typeof fromValue === 'string') {
|
||||
fromType = 'str';
|
||||
fromRE = fromValue.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
try {
|
||||
fromRE = new RegExp(fromRE, "g");
|
||||
} catch (e) {
|
||||
valid = false;
|
||||
node.error(RED._("change.errors.invalid-from",{error:e.message}));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
node.error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)}));
|
||||
return
|
||||
}
|
||||
} else {
|
||||
fromType = rule.fromt;
|
||||
fromValue = rule.from;
|
||||
fromRE = rule.fromRE;
|
||||
}
|
||||
}
|
||||
if (rule.pt === 'msg') {
|
||||
if (rule.t === 'delete') {
|
||||
RED.util.setMessageProperty(msg,property,undefined);
|
||||
} else if (rule.t === 'set') {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else if (rule.t === 'change') {
|
||||
current = RED.util.getMessageProperty(msg,property);
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
RED.util.setMessageProperty(msg,property,current);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var target;
|
||||
if (rule.pt === 'flow') {
|
||||
target = node.context().flow;
|
||||
} else if (rule.pt === 'global') {
|
||||
target = node.context().global;
|
||||
}
|
||||
if (target) {
|
||||
if (rule.t === 'delete') {
|
||||
target.set(property,undefined);
|
||||
} else if (rule.t === 'set') {
|
||||
target.set(property,value);
|
||||
} else if (rule.t === 'change') {
|
||||
current = target.get(property);
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
target.set(property,value);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
target.set(property,current);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
target.set(property,value);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
target.set(property,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {/*console.log(err.stack)*/}
|
||||
return msg;
|
||||
}
|
||||
if (valid) {
|
||||
this.on('input', function(msg) {
|
||||
for (var i=0; i<this.rules.length; i++) {
|
||||
if (this.rules[i].t === "move") {
|
||||
var r = this.rules[i];
|
||||
if ((r.tot !== r.pt) || (r.p.indexOf(r.to) !== -1)) {
|
||||
msg = applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:r.p, tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:r.p, pt:r.pt});
|
||||
}
|
||||
else { // 2 step move if we are moving from a child
|
||||
msg = applyRule(msg,{t:"set", p:"_temp_move", pt:r.tot, to:r.p, tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:r.p, pt:r.pt});
|
||||
msg = applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:"_temp_move", tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:"_temp_move", pt:r.pt});
|
||||
}
|
||||
} else {
|
||||
msg = applyRule(msg,this.rules[i]);
|
||||
}
|
||||
if (msg === null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("change", ChangeNode);
|
||||
};
|
@@ -1,218 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
var _max_kept_msgs_count = undefined;
|
||||
|
||||
function max_kept_msgs_count(node) {
|
||||
if (_max_kept_msgs_count === undefined) {
|
||||
var name = "nodeMessageBufferMaxLength";
|
||||
if (RED.settings.hasOwnProperty(name)) {
|
||||
_max_kept_msgs_count = RED.settings[name];
|
||||
}
|
||||
else {
|
||||
_max_kept_msgs_count = 0;
|
||||
}
|
||||
}
|
||||
return _max_kept_msgs_count;
|
||||
}
|
||||
|
||||
function eval_jsonata(node, code, val) {
|
||||
try {
|
||||
return RED.util.evaluateJSONataExpression(code, val);
|
||||
}
|
||||
catch (e) {
|
||||
node.error(RED._("sort.invalid-exp"));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function get_context_val(node, name, dval) {
|
||||
var context = node.context();
|
||||
var val = context.get(name);
|
||||
if (val === undefined) {
|
||||
context.set(name, dval);
|
||||
return dval;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
function SortNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
var node = this;
|
||||
var pending = get_context_val(node, 'pending', {})
|
||||
var pending_count = 0;
|
||||
var pending_id = 0;
|
||||
var order = n.order || "ascending";
|
||||
var as_num = n.as_num || false;
|
||||
var target_prop = n.target || "payload";
|
||||
var target_is_prop = (n.targetType === 'msg');
|
||||
var key_is_exp = target_is_prop ? (n.msgKeyType === "jsonata") : (n.seqKeyType === "jsonata");
|
||||
var key_prop = n.seqKey || "payload";
|
||||
var key_exp = target_is_prop ? n.msgKey : n.seqKey;
|
||||
|
||||
if (key_is_exp) {
|
||||
try {
|
||||
key_exp = RED.util.prepareJSONataExpression(key_exp, this);
|
||||
}
|
||||
catch (e) {
|
||||
node.error(RED._("sort.invalid-exp"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
var dir = (order === "ascending") ? 1 : -1;
|
||||
var conv = as_num
|
||||
? function(x) { return Number(x); }
|
||||
: function(x) { return x; };
|
||||
|
||||
function gen_comp(key) {
|
||||
return function(x, y) {
|
||||
var xp = conv(key(x));
|
||||
var yp = conv(key(y));
|
||||
if (xp === yp) { return 0; }
|
||||
if (xp > yp) { return dir; }
|
||||
return -dir;
|
||||
};
|
||||
}
|
||||
|
||||
function send_group(group) {
|
||||
var key = key_is_exp
|
||||
? function(msg) {
|
||||
return eval_jsonata(node, key_exp, msg);
|
||||
}
|
||||
: function(msg) {
|
||||
return RED.util.getMessageProperty(msg, key_prop);
|
||||
};
|
||||
var comp = gen_comp(key);
|
||||
var msgs = group.msgs;
|
||||
try {
|
||||
msgs.sort(comp);
|
||||
}
|
||||
catch (e) {
|
||||
return; // not send when error
|
||||
}
|
||||
for (var i = 0; i < msgs.length; i++) {
|
||||
var msg = msgs[i];
|
||||
msg.parts.index = i;
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function sort_payload(msg) {
|
||||
var data = RED.util.getMessageProperty(msg, target_prop);
|
||||
if (Array.isArray(data)) {
|
||||
var key = key_is_exp
|
||||
? function(elem) {
|
||||
return eval_jsonata(node, key_exp, elem);
|
||||
}
|
||||
: function(elem) { return elem; };
|
||||
var comp = gen_comp(key);
|
||||
try {
|
||||
data.sort(comp);
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function check_parts(parts) {
|
||||
if (parts.hasOwnProperty("id") &&
|
||||
parts.hasOwnProperty("index")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function clear_pending() {
|
||||
for(var key in pending) {
|
||||
node.log(RED._("sort.clear"), pending[key].msgs[0]);
|
||||
delete pending[key];
|
||||
}
|
||||
pending_count = 0;
|
||||
}
|
||||
|
||||
function remove_oldest_pending() {
|
||||
var oldest = undefined;
|
||||
var oldest_key = undefined;
|
||||
for(var key in pending) {
|
||||
var item = pending[key];
|
||||
if((oldest === undefined) ||
|
||||
(oldest.seq_no > item.seq_no)) {
|
||||
oldest = item;
|
||||
oldest_key = key;
|
||||
}
|
||||
}
|
||||
if(oldest !== undefined) {
|
||||
delete pending[oldest_key];
|
||||
return oldest.msgs.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function process_msg(msg) {
|
||||
if (target_is_prop) {
|
||||
if (sort_payload(msg)) {
|
||||
node.send(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var parts = msg.parts;
|
||||
if (!check_parts(parts)) {
|
||||
return;
|
||||
}
|
||||
var gid = parts.id;
|
||||
if (!pending.hasOwnProperty(gid)) {
|
||||
pending[gid] = {
|
||||
count: undefined,
|
||||
msgs: [],
|
||||
seq_no: pending_id++
|
||||
};
|
||||
}
|
||||
var group = pending[gid];
|
||||
var msgs = group.msgs;
|
||||
msgs.push(msg);
|
||||
if (parts.hasOwnProperty("count")) {
|
||||
group.count = parts.count;
|
||||
}
|
||||
pending_count++;
|
||||
if (group.count === msgs.length) {
|
||||
delete pending[gid]
|
||||
send_group(group);
|
||||
pending_count -= msgs.length;
|
||||
}
|
||||
var max_msgs = max_kept_msgs_count(node);
|
||||
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||
pending_count -= remove_oldest_pending();
|
||||
node.error(RED._("sort.too-many"), msg);
|
||||
}
|
||||
}
|
||||
|
||||
this.on("input", function(msg) {
|
||||
process_msg(msg);
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
clear_pending();
|
||||
})
|
||||
}
|
||||
|
||||
RED.nodes.registerType("sort", SortNode);
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function JSONNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.indent = n.pretty ? 4 : 0;
|
||||
this.action = n.action||"";
|
||||
this.property = n.property||"payload";
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
if (value !== undefined) {
|
||||
if (typeof value === "string") {
|
||||
if (node.action === "" || node.action === "obj") {
|
||||
try {
|
||||
RED.util.setMessageProperty(msg,node.property,JSON.parse(value));
|
||||
node.send(msg);
|
||||
}
|
||||
catch(e) { node.error(e.message,msg); }
|
||||
} else {
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else if (typeof value === "object") {
|
||||
if (node.action === "" || node.action === "str") {
|
||||
if (!Buffer.isBuffer(value)) {
|
||||
try {
|
||||
RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent));
|
||||
node.send(msg);
|
||||
}
|
||||
catch(e) { node.error(RED._("json.errors.dropped-error")); }
|
||||
}
|
||||
else { node.warn(RED._("json.errors.dropped-object")); }
|
||||
} else {
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else { node.warn(RED._("json.errors.dropped")); }
|
||||
}
|
||||
else { node.send(msg); } // If no property - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("json",JSONNode);
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="tail">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="tail.label.filename"></span></label>
|
||||
<input id="node-input-filename" type="text">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-filetype"><i class="fa fa-file-text-o"></i> <span data-i18n="tail.label.type"></span></label>
|
||||
<select type="text" id="node-input-filetype">
|
||||
<option value="text" data-i18n="tail.action.text"></option>
|
||||
<option value="binary" data-i18n="tail.action.binary"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="node-tail-split">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-split" style="width: 70%;"><span data-i18n="tail.label.splitlines"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tail">
|
||||
<p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p>
|
||||
<p>This will not work on Windows filesystems, as it relies on the <b>tail -F</b> command.</p>
|
||||
<h3>Outputs</h3>
|
||||
<ul>
|
||||
<li>Text (UTF-8) files will be returned as strings.</li>
|
||||
<li>Binary files will be returned as Buffer objects.</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tail',{
|
||||
category: 'storage-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filetype: {value:"text"},
|
||||
split: {value:false},
|
||||
filename: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "file.png",
|
||||
label: function() {
|
||||
return this.name||this.filename||this._("tail.tail");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-filetype").on("change",function() {
|
||||
if (this.value === "text") { $("#node-tail-split").show(); }
|
||||
else { $("#node-tail-split").hide(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var spawn = require('child_process').spawn;
|
||||
var plat = require('os').platform();
|
||||
|
||||
if (plat.match(/^win/)) {
|
||||
throw RED._("tail.errors.windowsnotsupport");
|
||||
}
|
||||
|
||||
function TailNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.filetype = n.filetype || "text";
|
||||
this.split = n.split || false;
|
||||
var node = this;
|
||||
|
||||
var err = "";
|
||||
// TODO: rewrite to use node-tail
|
||||
var tail = spawn("tail", ["-F", "-n", "0", this.filename]);
|
||||
tail.stdout.on("data", function (data) {
|
||||
var msg = { topic:node.filename };
|
||||
if (node.filetype === "text") {
|
||||
if (node.split) {
|
||||
// TODO: allow customisation of the line break - as we do elsewhere
|
||||
var strings = data.toString().split("\n");
|
||||
for (var s in strings) {
|
||||
//TODO: should we really filter blanks? Is that expected?
|
||||
if (strings[s] !== "") {
|
||||
node.send({
|
||||
topic: node.filename,
|
||||
payload: strings[s]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data.toString();
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data;
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
tail.stderr.on("data", function(data) {
|
||||
node.error(data.toString());
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
/* istanbul ignore else */
|
||||
if (tail) { tail.kill(); }
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tail",TailNode);
|
||||
}
|
230
package.json
230
package.json
@@ -1,117 +1,121 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.18.5",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"main": "red/red.js",
|
||||
"scripts": {
|
||||
"start": "node red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build"
|
||||
},
|
||||
"bin": {
|
||||
"node-red": "./red.js",
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-beta.3",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start": "node packages/node_modules/node-red/red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build",
|
||||
"docs": "grunt docs"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.6.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.2",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.6.0",
|
||||
"denque": "1.4.0",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
"fs-extra": "7.0.1",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "13.1.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.6.3",
|
||||
"media-typer": "1.0.1",
|
||||
"memorystore": "1.6.0",
|
||||
"mime": "2.4.0",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "3.0.1",
|
||||
"node-red-node-email": "1.0.*",
|
||||
"node-red-node-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
"node-red-node-tail": "^0.0.1",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
"semver": "5.6.0",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.2",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "2.45.0",
|
||||
"grunt": "~1.0.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.2",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.4.0",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-jsdoc-to-markdown": "^4.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mkdir": "~1.0.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-npm-command": "~0.1.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "^5.2.0",
|
||||
"mosca": "^2.8.3",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "3.3.0",
|
||||
"wdio-chromedriver-service": "^0.1.5",
|
||||
"wdio-mocha-framework": "^0.6.4",
|
||||
"wdio-spec-reporter": "^0.1.5",
|
||||
"webdriverio": "^4.14.1",
|
||||
"node-red-node-test-helper": "node-red/node-red-node-test-helper",
|
||||
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"editor",
|
||||
"messaging",
|
||||
"iot",
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"basic-auth": "2.0.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.2",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.1",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.3.0",
|
||||
"express": "4.16.3",
|
||||
"express-session": "1.15.6",
|
||||
"follow-redirects": "1.4.1",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"i18next": "1.10.6",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.11.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.3",
|
||||
"media-typer": "0.3.0",
|
||||
"memorystore": "1.6.0",
|
||||
"mqtt": "2.17.0",
|
||||
"multer": "1.3.0",
|
||||
"mustache": "2.3.0",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "0.1.*",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-twitter": "0.1.*",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"semver": "5.5.0",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.3.24",
|
||||
"when": "3.7.8",
|
||||
"ws": "1.1.5",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "^2.33.2",
|
||||
"grunt": "~1.0.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.2.0",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.3.0",
|
||||
"grunt-contrib-watch": "~1.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"mocha": "^5.1.1",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.0.6",
|
||||
"supertest": "3.0.0",
|
||||
"wdio-chromedriver-service": "^0.1.1",
|
||||
"wdio-mocha-framework": "^0.5.11",
|
||||
"wdio-spec-reporter": "^0.1.3",
|
||||
"webdriverio": "^4.9.11",
|
||||
"node-red-node-test-helper": "^0.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
}
|
||||
|
2
packages/node_modules/@node-red/editor-api/.npmignore
vendored
Normal file
2
packages/node_modules/@node-red/editor-api/.npmignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
src
|
||||
docs
|
178
packages/node_modules/@node-red/editor-api/LICENSE
vendored
Normal file
178
packages/node_modules/@node-red/editor-api/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
12
packages/node_modules/@node-red/editor-api/README.md
vendored
Normal file
12
packages/node_modules/@node-red/editor-api/README.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
@node-red/editor-api
|
||||
====================
|
||||
|
||||
Node-RED editor api module.
|
||||
|
||||
This provides an Express application that can be used to serve the Node-RED
|
||||
editor.
|
||||
|
||||
|
||||
### Source
|
||||
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
56
packages/node_modules/@node-red/editor-api/lib/admin/context.js
vendored
Normal file
56
packages/node_modules/@node-red/editor-api/lib/admin/context.js
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
scope: req.params.scope,
|
||||
id: req.params.id,
|
||||
key: req.params[0],
|
||||
store: req.query['store']
|
||||
}
|
||||
runtimeAPI.context.getValue(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
scope: req.params.scope,
|
||||
id: req.params.id,
|
||||
key: req.params[0],
|
||||
store: req.query['store']
|
||||
}
|
||||
runtimeAPI.context.delete(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
69
packages/node_modules/@node-red/editor-api/lib/admin/flow.js
vendored
Normal file
69
packages/node_modules/@node-red/editor-api/lib/admin/flow.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.getFlow(opts).then(function(result) {
|
||||
return res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.addFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
put: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.updateFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.deleteFlow(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
70
packages/node_modules/@node-red/editor-api/lib/admin/flows.js
vendored
Normal file
70
packages/node_modules/@node-red/editor-api/lib/admin/flows.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.flows.getFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.json(result.flows);
|
||||
} else if (version === "v2") {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
deploymentType: req.get("Node-RED-Deployment-Type")||"full"
|
||||
}
|
||||
|
||||
if (opts.deploymentType !== 'reload') {
|
||||
if (version === "v1") {
|
||||
opts.flows = {flows: req.body}
|
||||
} else {
|
||||
opts.flows = req.body;
|
||||
}
|
||||
}
|
||||
|
||||
runtimeAPI.flows.setFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.status(204).end();
|
||||
} else {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
@@ -19,15 +19,17 @@ var express = require("express");
|
||||
var nodes = require("./nodes");
|
||||
var flows = require("./flows");
|
||||
var flow = require("./flow");
|
||||
var context = require("./context");
|
||||
var auth = require("../auth");
|
||||
|
||||
var apiUtil = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
flows.init(runtime);
|
||||
flow.init(runtime);
|
||||
nodes.init(runtime);
|
||||
init: function(runtimeAPI) {
|
||||
flows.init(runtimeAPI);
|
||||
flow.init(runtimeAPI);
|
||||
nodes.init(runtimeAPI);
|
||||
context.init(runtimeAPI);
|
||||
|
||||
var needsPermission = auth.needsPermission;
|
||||
|
||||
@@ -46,12 +48,25 @@ module.exports = {
|
||||
// Nodes
|
||||
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
|
||||
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
|
||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler);
|
||||
adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
|
||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
|
||||
|
||||
// Context
|
||||
adminApp.get("/context/:scope(global)",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(global)/*",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(node|flow)/:id",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(node|flow)/:id/*",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
|
||||
// adminApp.delete("/context/:scope(global)",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
adminApp.delete("/context/:scope(global)/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
// adminApp.delete("/context/:scope(node|flow)/:id",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
adminApp.delete("/context/:scope(node|flow)/:id/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
|
||||
return adminApp;
|
||||
}
|
||||
}
|
173
packages/node_modules/@node-red/editor-api/lib/admin/nodes.js
vendored
Normal file
173
packages/node_modules/@node-red/editor-api/lib/admin/nodes.js
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
getAll: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
if (req.get("accept") == "application/json") {
|
||||
runtimeAPI.nodes.getNodeList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) {
|
||||
res.send(configs);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.body.module,
|
||||
version: req.body.version
|
||||
}
|
||||
runtimeAPI.nodes.addModule(opts).then(function(info) {
|
||||
res.json(info);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.removeModule(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getSet: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2]
|
||||
}
|
||||
if (req.get("accept") === "application/json") {
|
||||
runtimeAPI.nodes.getNodeInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfig(opts).then(function(result) {
|
||||
return res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getModule: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.getModuleInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putSet: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setNodeSetState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putModule: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setModuleState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
getModuleCatalog: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getModuleCatalogs: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getIcons: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.nodes.getIconList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
});
|
||||
}
|
||||
};
|
@@ -25,7 +25,7 @@ var permissions = require("./permissions");
|
||||
var theme = require("../editor/theme");
|
||||
|
||||
var settings = null;
|
||||
var log = null
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
|
||||
passport.use(strategies.bearerStrategy.BearerStrategy);
|
||||
@@ -36,13 +36,12 @@ var server = oauth2orize.createServer();
|
||||
|
||||
server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));
|
||||
|
||||
function init(runtime) {
|
||||
settings = runtime.settings;
|
||||
log = runtime.log;
|
||||
function init(_settings,storage) {
|
||||
settings = _settings;
|
||||
if (settings.adminAuth) {
|
||||
Users.init(settings.adminAuth);
|
||||
Tokens.init(settings.adminAuth,runtime.storage);
|
||||
strategies.init(runtime);
|
||||
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
||||
Users.init(mergedAdminAuth);
|
||||
Tokens.init(mergedAdminAuth,storage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,23 +80,24 @@ function getToken(req,res,next) {
|
||||
function login(req,res) {
|
||||
var response = {};
|
||||
if (settings.adminAuth) {
|
||||
if (settings.adminAuth.type === "credentials") {
|
||||
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
||||
if (mergedAdminAuth.type === "credentials") {
|
||||
response = {
|
||||
"type":"credentials",
|
||||
"prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
|
||||
}
|
||||
} else if (settings.adminAuth.type === "strategy") {
|
||||
} else if (mergedAdminAuth.type === "strategy") {
|
||||
|
||||
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot;
|
||||
response = {
|
||||
"type":"strategy",
|
||||
"prompts":[{type:"button",label:settings.adminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
}
|
||||
if (settings.adminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = settings.adminAuth.strategy.icon;
|
||||
if (mergedAdminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = mergedAdminAuth.strategy.icon;
|
||||
}
|
||||
if (settings.adminAuth.strategy.image) {
|
||||
response.prompts[0].image = theme.serveFile('/login/',settings.adminAuth.strategy.image);
|
||||
if (mergedAdminAuth.strategy.image) {
|
||||
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
|
||||
}
|
||||
}
|
||||
if (theme.context().login && theme.context().login.image) {
|
||||
@@ -182,7 +182,12 @@ function genericStrategy(adminApp,strategy) {
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
||||
adminApp.get('/auth/strategy/callback',
|
||||
|
||||
var callbackMethodFunc = adminApp.get;
|
||||
if (/^post$/i.test(options.callbackMethod)) {
|
||||
callbackMethodFunc = adminApp.post;
|
||||
}
|
||||
callbackMethodFunc('/auth/strategy/callback',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
@@ -26,7 +26,7 @@ var Users = require("./users");
|
||||
var Clients = require("./clients");
|
||||
var permissions = require("./permissions");
|
||||
|
||||
var log;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
var bearerStrategy = function (accessToken, done) {
|
||||
// is this a valid token?
|
||||
@@ -124,9 +124,6 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
log = runtime.log;
|
||||
},
|
||||
bearerStrategy: bearerStrategy,
|
||||
clientPasswordStrategy: clientPasswordStrategy,
|
||||
passwordTokenExchange: passwordTokenExchange,
|
@@ -25,25 +25,39 @@ function generateToken(length) {
|
||||
|
||||
|
||||
var storage;
|
||||
|
||||
var sessionExpiryTime
|
||||
|
||||
var sessions = {};
|
||||
|
||||
var loadedSessions = null;
|
||||
var apiAccessTokens;
|
||||
var sessionExpiryListeners = [];
|
||||
var expiryTimeout;
|
||||
|
||||
function expireSessions() {
|
||||
if (expiryTimeout) {
|
||||
clearTimeout(expiryTimeout);
|
||||
expiryTimeout = null;
|
||||
}
|
||||
var nextExpiry = Number.MAX_SAFE_INTEGER;
|
||||
var now = Date.now();
|
||||
var modified = false;
|
||||
for (var t in sessions) {
|
||||
if (sessions.hasOwnProperty(t)) {
|
||||
var session = sessions[t];
|
||||
if (!session.hasOwnProperty("expires") || session.expires < now) {
|
||||
sessionExpiryListeners.forEach(listener => { listener(session) })
|
||||
delete sessions[t];
|
||||
modified = true;
|
||||
} else {
|
||||
if (session.expires < nextExpiry) {
|
||||
nextExpiry = session.expires;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextExpiry < Number.MAX_SAFE_INTEGER) {
|
||||
// Allow 5 seconds grace
|
||||
expiryTimeout = setTimeout(expireSessions,(nextExpiry - Date.now()) + 5000)
|
||||
}
|
||||
if (modified) {
|
||||
return storage.saveSessions(sessions);
|
||||
} else {
|
||||
@@ -63,20 +77,40 @@ function loadSessions() {
|
||||
module.exports = {
|
||||
init: function(adminAuthSettings, _storage) {
|
||||
storage = _storage;
|
||||
|
||||
sessionExpiryListeners = [];
|
||||
|
||||
sessionExpiryTime = adminAuthSettings.sessionExpiryTime || 604800; // 1 week in seconds
|
||||
// At this point, storage will not have been initialised, so defer loading
|
||||
// the sessions until there's a request for them.
|
||||
loadedSessions = null;
|
||||
|
||||
apiAccessTokens = {};
|
||||
if ( Array.isArray(adminAuthSettings.tokens) ) {
|
||||
apiAccessTokens = adminAuthSettings.tokens.reduce(function(prev, current) {
|
||||
prev[current.token] = {
|
||||
user: current.user,
|
||||
scope: current.scope
|
||||
};
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
get: function(token) {
|
||||
return loadSessions().then(function() {
|
||||
if (sessions[token]) {
|
||||
if (sessions[token].expires < Date.now()) {
|
||||
return expireSessions().then(function() { return null });
|
||||
var info = apiAccessTokens[token] || null;
|
||||
|
||||
if (info) {
|
||||
return Promise.resolve(info);
|
||||
} else {
|
||||
if (sessions[token]) {
|
||||
if (sessions[token].expires < Date.now()) {
|
||||
return expireSessions().then(function() { return null });
|
||||
}
|
||||
}
|
||||
return Promise.resolve(sessions[token]);
|
||||
}
|
||||
return Promise.resolve(sessions[token]);
|
||||
});
|
||||
},
|
||||
create: function(user,client,scope) {
|
||||
@@ -93,6 +127,11 @@ module.exports = {
|
||||
expires: accessTokenExpiresAt
|
||||
};
|
||||
sessions[accessToken] = session;
|
||||
|
||||
if (!expiryTimeout) {
|
||||
expiryTimeout = setTimeout(expireSessions,(accessTokenExpiresAt - Date.now()) + 5000)
|
||||
}
|
||||
|
||||
return storage.saveSessions(sessions).then(function() {
|
||||
return {
|
||||
accessToken: accessToken,
|
||||
@@ -106,5 +145,8 @@ module.exports = {
|
||||
delete sessions[token];
|
||||
return storage.saveSessions(sessions);
|
||||
});
|
||||
},
|
||||
onSessionExpiry: function(callback) {
|
||||
sessionExpiryListeners.push(callback);
|
||||
}
|
||||
}
|
@@ -86,6 +86,10 @@ function init(config) {
|
||||
} else {
|
||||
api.authenticate = authenticate;
|
||||
}
|
||||
} else {
|
||||
api.get = get;
|
||||
api.authenticate = authenticate;
|
||||
api.default = api.default;
|
||||
}
|
||||
if (config.default) {
|
||||
if (typeof config.default === "function") {
|
253
packages/node_modules/@node-red/editor-api/lib/editor/comms.js
vendored
Normal file
253
packages/node_modules/@node-red/editor-api/lib/editor/comms.js
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var ws = require("ws");
|
||||
var url = require("url");
|
||||
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var Tokens;
|
||||
var Users;
|
||||
var Permissions;
|
||||
|
||||
var server;
|
||||
var settings;
|
||||
var runtimeAPI;
|
||||
|
||||
var wsServer;
|
||||
var activeConnections = [];
|
||||
|
||||
var anonymousUser;
|
||||
|
||||
var retained = {};
|
||||
|
||||
var heartbeatTimer;
|
||||
var lastSentTime;
|
||||
|
||||
function init(_server,_settings,_runtimeAPI) {
|
||||
server = _server;
|
||||
settings = _settings;
|
||||
runtimeAPI = _runtimeAPI;
|
||||
Tokens = require("../auth/tokens");
|
||||
Tokens.onSessionExpiry(handleSessionExpiry);
|
||||
Users = require("../auth/users");
|
||||
Permissions = require("../auth/permissions");
|
||||
|
||||
}
|
||||
function handleSessionExpiry(session) {
|
||||
activeConnections.forEach(connection => {
|
||||
if (connection.token === session.accessToken) {
|
||||
connection.ws.send(JSON.stringify({auth:"fail"}));
|
||||
connection.ws.close();
|
||||
}
|
||||
})
|
||||
}
|
||||
function generateSession(length) {
|
||||
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
var token = [];
|
||||
for (var i=0;i<length;i++) {
|
||||
token.push(c[Math.floor(Math.random()*c.length)]);
|
||||
}
|
||||
return token.join("");
|
||||
}
|
||||
|
||||
function CommsConnection(ws) {
|
||||
this.session = generateSession(32);
|
||||
this.ws = ws;
|
||||
this.stack = [];
|
||||
this.user = null;
|
||||
this.lastSentTime = 0;
|
||||
var self = this;
|
||||
|
||||
log.audit({event: "comms.open"});
|
||||
log.trace("comms.open "+self.session);
|
||||
var pendingAuth = (settings.adminAuth != null);
|
||||
|
||||
if (!pendingAuth) {
|
||||
addActiveConnection(self);
|
||||
}
|
||||
ws.on('close',function() {
|
||||
log.audit({event: "comms.close",user:self.user, session: self.session});
|
||||
log.trace("comms.close "+self.session);
|
||||
removeActiveConnection(self);
|
||||
});
|
||||
ws.on('message', function(data,flags) {
|
||||
var msg = null;
|
||||
try {
|
||||
msg = JSON.parse(data);
|
||||
} catch(err) {
|
||||
log.trace("comms received malformed message : "+err.toString());
|
||||
return;
|
||||
}
|
||||
if (!pendingAuth) {
|
||||
if (msg.subscribe) {
|
||||
self.subscribe(msg.subscribe);
|
||||
// handleRemoteSubscription(ws,msg.subscribe);
|
||||
}
|
||||
} else {
|
||||
var completeConnection = function(userScope,session,sendAck) {
|
||||
try {
|
||||
if (!userScope || !Permissions.hasPermission(userScope,"status.read")) {
|
||||
ws.send(JSON.stringify({auth:"fail"}));
|
||||
ws.close();
|
||||
} else {
|
||||
pendingAuth = false;
|
||||
addActiveConnection(self);
|
||||
self.token = msg.auth;
|
||||
if (sendAck) {
|
||||
ws.send(JSON.stringify({auth:"ok"}));
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err.stack);
|
||||
// Just in case the socket closes before we attempt
|
||||
// to send anything.
|
||||
}
|
||||
}
|
||||
if (msg.auth) {
|
||||
Tokens.get(msg.auth).then(function(client) {
|
||||
if (client) {
|
||||
Users.get(client.user).then(function(user) {
|
||||
if (user) {
|
||||
self.user = user;
|
||||
log.audit({event: "comms.auth",user:self.user});
|
||||
completeConnection(client.scope,msg.auth,true);
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (anonymousUser) {
|
||||
log.audit({event: "comms.auth",user:anonymousUser});
|
||||
self.user = anonymousUser;
|
||||
completeConnection(anonymousUser.permissions,null,false);
|
||||
//TODO: duplicated code - pull non-auth message handling out
|
||||
if (msg.subscribe) {
|
||||
self.subscribe(msg.subscribe);
|
||||
}
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ws.on('error', function(err) {
|
||||
log.warn(log._("comms.error",{message:err.toString()}));
|
||||
});
|
||||
}
|
||||
|
||||
CommsConnection.prototype.send = function(topic,data) {
|
||||
var self = this;
|
||||
if (topic && data) {
|
||||
this.stack.push({topic:topic,data:data});
|
||||
}
|
||||
if (!this._xmitTimer) {
|
||||
this._xmitTimer = setTimeout(function() {
|
||||
try {
|
||||
self.ws.send(JSON.stringify(self.stack));
|
||||
self.lastSentTime = Date.now();
|
||||
} catch(err) {
|
||||
removeActiveConnection(self);
|
||||
log.warn(log._("comms.error-send",{message:err.toString()}));
|
||||
}
|
||||
delete self._xmitTimer;
|
||||
self.stack = [];
|
||||
},50);
|
||||
}
|
||||
}
|
||||
|
||||
CommsConnection.prototype.subscribe = function(topic) {
|
||||
runtimeAPI.comms.subscribe({
|
||||
user: this.user,
|
||||
client: this,
|
||||
topic: topic
|
||||
})
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (!settings.disableEditor) {
|
||||
Users.default().then(function(_anonymousUser) {
|
||||
anonymousUser = _anonymousUser;
|
||||
var webSocketKeepAliveTime = settings.webSocketKeepAliveTime || 15000;
|
||||
var commsPath = settings.httpAdminRoot || "/";
|
||||
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
|
||||
wsServer = new ws.Server({ noServer: true });
|
||||
wsServer.on('connection',function(ws) {
|
||||
var commsConnection = new CommsConnection(ws);
|
||||
});
|
||||
wsServer.on('error', function(err) {
|
||||
log.warn(log._("comms.error-server",{message:err.toString()}));
|
||||
});
|
||||
|
||||
server.on('upgrade', function upgrade(request, socket, head) {
|
||||
const pathname = url.parse(request.url).pathname;
|
||||
if (pathname === commsPath) {
|
||||
wsServer.handleUpgrade(request, socket, head, function done(ws) {
|
||||
wsServer.emit('connection', ws, request);
|
||||
});
|
||||
}
|
||||
// Don't destroy the socket as other listeners may want to handle the
|
||||
// event.
|
||||
});
|
||||
|
||||
lastSentTime = Date.now();
|
||||
|
||||
heartbeatTimer = setInterval(function() {
|
||||
var now = Date.now();
|
||||
if (now-lastSentTime > webSocketKeepAliveTime) {
|
||||
activeConnections.forEach(connection => connection.send("hb",lastSentTime));
|
||||
}
|
||||
}, webSocketKeepAliveTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (heartbeatTimer) {
|
||||
clearInterval(heartbeatTimer);
|
||||
heartbeatTimer = null;
|
||||
}
|
||||
if (wsServer) {
|
||||
wsServer.close();
|
||||
wsServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function addActiveConnection(connection) {
|
||||
activeConnections.push(connection);
|
||||
runtimeAPI.comms.addConnection({client: connection});
|
||||
}
|
||||
function removeActiveConnection(connection) {
|
||||
for (var i=0;i<activeConnections.length;i++) {
|
||||
if (activeConnections[i] === connection) {
|
||||
activeConnections.splice(i,1);
|
||||
runtimeAPI.comms.removeConnection({client:connection})
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init:init,
|
||||
start:start,
|
||||
stop:stop
|
||||
}
|
36
packages/node_modules/@node-red/editor-api/lib/editor/credentials.js
vendored
Normal file
36
packages/node_modules/@node-red/editor-api/lib/editor/credentials.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI
|
||||
},
|
||||
get: function (req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params.type,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.getNodeCredentials(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
@@ -24,31 +24,35 @@ var info = require("./settings");
|
||||
var auth = require("../auth");
|
||||
var nodes = require("../admin/nodes"); // TODO: move /icons into here
|
||||
var needsPermission;
|
||||
var runtime;
|
||||
var log;
|
||||
var runtimeAPI;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
var apiUtil = require("../util");
|
||||
|
||||
var ensureRuntimeStarted = function(req,res,next) {
|
||||
if (!runtime.isStarted()) {
|
||||
log.error("Node-RED runtime not started");
|
||||
res.status(503).send("Not started");
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
runtimeAPI.isStarted().then( started => {
|
||||
if (!started) {
|
||||
log.error("Node-RED runtime not started");
|
||||
res.status(503).send("Not started");
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(server, _runtime) {
|
||||
runtime = _runtime;
|
||||
log = runtime.log;
|
||||
init: function(server, settings, _runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
needsPermission = auth.needsPermission;
|
||||
var settings = runtime.settings;
|
||||
if (!settings.disableEditor) {
|
||||
info.init(runtime);
|
||||
comms.init(server,runtime);
|
||||
info.init(runtimeAPI);
|
||||
comms.init(server,settings,runtimeAPI);
|
||||
|
||||
var ui = require("./ui");
|
||||
ui.init(runtime);
|
||||
|
||||
ui.init(runtimeAPI);
|
||||
|
||||
var editorApp = express();
|
||||
if (settings.requireHttps === true) {
|
||||
editorApp.enable('trust proxy');
|
||||
@@ -60,6 +64,11 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settings.httpServerOptions) {
|
||||
for (var eOption in settings.httpServerOptions) {
|
||||
editorApp.set(eOption, settings.httpServerOptions[eOption]);
|
||||
}
|
||||
}
|
||||
editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
|
||||
|
||||
editorApp.get("/icons",needsPermission("nodes.read"),nodes.getIcons,apiUtil.errorHandler);
|
||||
@@ -67,31 +76,31 @@ module.exports = {
|
||||
editorApp.get("/icons/:scope/:module/:icon",ui.icon);
|
||||
|
||||
var theme = require("./theme");
|
||||
theme.init(runtime);
|
||||
theme.init(settings);
|
||||
editorApp.use("/theme",theme.app());
|
||||
editorApp.use("/",ui.editorResources);
|
||||
|
||||
//Projects
|
||||
var projects = require("./projects");
|
||||
projects.init(runtime);
|
||||
projects.init(runtimeAPI);
|
||||
editorApp.use("/projects",projects.app());
|
||||
|
||||
// Locales
|
||||
var locales = require("./locales");
|
||||
locales.init(runtime);
|
||||
editorApp.get('/locales/nodes',locales.getAllNodes,apiUtil.errorHandler);
|
||||
locales.init(runtimeAPI);
|
||||
editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
|
||||
|
||||
// Library
|
||||
var library = require("./library");
|
||||
library.init(editorApp,runtime);
|
||||
editorApp.post(new RegExp("/library/flows\/(.*)"),needsPermission("library.write"),library.post,apiUtil.errorHandler);
|
||||
library.init(runtimeAPI);
|
||||
editorApp.get("/library/flows",needsPermission("library.read"),library.getAll,apiUtil.errorHandler);
|
||||
editorApp.get(new RegExp("/library/flows\/(.*)"),needsPermission("library.read"),library.get,apiUtil.errorHandler);
|
||||
editorApp.get(/library\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
|
||||
editorApp.post(/library\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
|
||||
|
||||
|
||||
// Credentials
|
||||
var credentials = require("./credentials");
|
||||
credentials.init(runtime);
|
||||
credentials.init(runtimeAPI);
|
||||
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
|
||||
|
||||
// Settings
|
||||
@@ -100,18 +109,15 @@ module.exports = {
|
||||
editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler);
|
||||
// User Settings
|
||||
editorApp.post("/settings/user",needsPermission("settings.write"),info.updateUserSettings,apiUtil.errorHandler);
|
||||
|
||||
// SSH keys
|
||||
var sshkeys = require("./sshkeys");
|
||||
sshkeys.init(runtime);
|
||||
editorApp.use("/settings/user/keys",sshkeys.app());
|
||||
editorApp.use("/settings/user/keys",needsPermission("settings.write"),info.sshkeys());
|
||||
|
||||
return editorApp;
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var catalogPath = path.resolve(path.join(__dirname,"locales"));
|
||||
return runtime.i18n.registerMessageCatalogs([
|
||||
var catalogPath = path.resolve(path.join(path.dirname(require.resolve("@node-red/editor-client")),"locales"));
|
||||
return i18n.registerMessageCatalogs([
|
||||
{namespace: "editor", dir: catalogPath, file:"editor.json"},
|
||||
{namespace: "jsonata", dir: catalogPath, file:"jsonata.json"},
|
||||
{namespace: "infotips", dir: catalogPath, file:"infotips.json"}
|
||||
@@ -119,7 +125,5 @@ module.exports = {
|
||||
comms.start();
|
||||
});
|
||||
},
|
||||
stop: comms.stop,
|
||||
publish: comms.publish,
|
||||
registerLibrary: library.register
|
||||
stop: comms.stop
|
||||
}
|
83
packages/node_modules/@node-red/editor-api/lib/editor/library.js
vendored
Normal file
83
packages/node_modules/@node-red/editor-api/lib/editor/library.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
var fs = require('fs');
|
||||
var fspath = require('path');
|
||||
var when = require('when');
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
|
||||
getAll: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: 'flows'
|
||||
}
|
||||
runtimeAPI.library.getEntries(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
getEntry: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params[0],
|
||||
path: req.params[1]||""
|
||||
}
|
||||
runtimeAPI.library.getEntry(opts).then(function(result) {
|
||||
if (typeof result === "string") {
|
||||
if (opts.type === 'flows') {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
}
|
||||
res.write(result);
|
||||
res.end();
|
||||
} else {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
saveEntry: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params[0],
|
||||
path: req.params[1]||""
|
||||
}
|
||||
// TODO: horrible inconsistencies between flows and all other types
|
||||
if (opts.type === "flows") {
|
||||
opts.meta = {};
|
||||
opts.body = JSON.stringify(req.body);
|
||||
} else {
|
||||
opts.meta = req.body;
|
||||
opts.body = opts.meta.text;
|
||||
delete opts.meta.text;
|
||||
}
|
||||
runtimeAPI.library.saveEntry(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
}
|
||||
}
|
@@ -16,37 +16,38 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
//var apiUtil = require('../util');
|
||||
var i18n;
|
||||
var redNodes;
|
||||
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
function loadResource(lang, namespace) {
|
||||
var catalog = i18n.i.getResourceBundle(lang, namespace);
|
||||
if (!catalog) {
|
||||
var parts = lang.split("-");
|
||||
if (parts.length == 2) {
|
||||
var new_lang = parts[0];
|
||||
return i18n.i.getResourceBundle(new_lang, namespace);
|
||||
}
|
||||
}
|
||||
return catalog;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
i18n = runtime.i18n;
|
||||
redNodes = runtime.nodes;
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var namespace = req.params[0];
|
||||
var lngs = req.query.lng;
|
||||
namespace = namespace.replace(/\.json$/,"");
|
||||
var lang = req.query.lng; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []);
|
||||
var prevLang = i18n.i.lng();
|
||||
var prevLang = i18n.i.language;
|
||||
// Trigger a load from disk of the language if it is not the default
|
||||
i18n.i.setLng(lang, function(){
|
||||
var catalog = i18n.catalog(namespace,lang);
|
||||
i18n.i.changeLanguage(lang, function(){
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
});
|
||||
i18n.i.setLng(prevLang);
|
||||
|
||||
},
|
||||
getAllNodes: function(req,res) {
|
||||
var lngs = req.query.lng;
|
||||
var nodeList = redNodes.getNodeList();
|
||||
var result = {};
|
||||
nodeList.forEach(function(n) {
|
||||
if (n.module !== "node-red") {
|
||||
result[n.id] = i18n.catalog(n.id,lngs)||{};
|
||||
}
|
||||
});
|
||||
res.json(result);
|
||||
i18n.i.changeLanguage(prevLang);
|
||||
}
|
||||
}
|
511
packages/node_modules/@node-red/editor-api/lib/editor/projects.js
vendored
Normal file
511
packages/node_modules/@node-red/editor-api/lib/editor/projects.js
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var express = require("express");
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
var needsPermission = require("../auth").needsPermission;
|
||||
|
||||
function listProjects(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.projects.listProjects(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
}
|
||||
function getProject(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getProject(opts).then(function(data) {
|
||||
if (data) {
|
||||
res.json(data);
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
function getProjectStatus(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.query.remote
|
||||
}
|
||||
runtimeAPI.projects.getStatus(opts).then(function(data){
|
||||
if (data) {
|
||||
res.json(data);
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
function getProjectRemotes(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getRemotes(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
app: function() {
|
||||
var app = express();
|
||||
|
||||
app.use(function(req,res,next) {
|
||||
runtimeAPI.projects.available().then(function(available) {
|
||||
if (!available) {
|
||||
res.status(404).end();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Projects
|
||||
|
||||
// List all projects
|
||||
app.get("/", needsPermission("projects.read"),listProjects);
|
||||
|
||||
// Create project
|
||||
app.post("/", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
project: req.body
|
||||
}
|
||||
runtimeAPI.projects.createProject(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Update a project
|
||||
app.put("/:id", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
project: req.body
|
||||
}
|
||||
|
||||
if (req.body.active) {
|
||||
runtimeAPI.projects.setActiveProject(opts).then(function() {
|
||||
listProjects(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else if (req.body.initialise) {
|
||||
runtimeAPI.projects.initialiseProject(opts).then(function() {
|
||||
getProject(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else if (req.body.hasOwnProperty('credentialSecret') ||
|
||||
req.body.hasOwnProperty('description') ||
|
||||
req.body.hasOwnProperty('dependencies')||
|
||||
req.body.hasOwnProperty('summary') ||
|
||||
req.body.hasOwnProperty('files') ||
|
||||
req.body.hasOwnProperty('git')) {
|
||||
runtimeAPI.projects.updateProject(opts).then(function() {
|
||||
getProject(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else {
|
||||
res.status(400).json({error:"unexpected_error", message:"invalid_request"});
|
||||
}
|
||||
});
|
||||
|
||||
// Get project metadata
|
||||
app.get("/:id", needsPermission("projects.read"), getProject);
|
||||
|
||||
// Delete project
|
||||
app.delete("/:id", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.deleteProject(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// Get project status - files, commit counts, branch info
|
||||
app.get("/:id/status", needsPermission("projects.read"), getProjectStatus);
|
||||
|
||||
|
||||
// Project file listing
|
||||
app.get("/:id/files", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getFiles(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Get file content in a given tree (index/stage)
|
||||
app.get("/:id/files/:treeish/*", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
tree: req.params.treeish
|
||||
}
|
||||
runtimeAPI.projects.getFile(opts).then(function(data) {
|
||||
res.json({content:data});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Revert a file
|
||||
app.delete("/:id/files/_/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
|
||||
runtimeAPI.projects.revertFile(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Stage a file
|
||||
app.post("/:id/stage/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.stageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Stage multiple files
|
||||
app.post("/:id/stage", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.body.files
|
||||
}
|
||||
runtimeAPI.projects.stageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Commit changes
|
||||
app.post("/:id/commit", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
message: req.body.message
|
||||
}
|
||||
runtimeAPI.projects.commit(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Unstage a file
|
||||
app.delete("/:id/stage/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.unstageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Unstage multiple files
|
||||
app.delete("/:id/stage", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.unstageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a file diff
|
||||
app.get("/:id/diff/:type/*", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
type: req.params.type
|
||||
}
|
||||
runtimeAPI.projects.getFileDiff(opts).then(function(data) {
|
||||
res.json({
|
||||
diff: data
|
||||
})
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of commits
|
||||
app.get("/:id/commits", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
limit: req.query.limit || 20,
|
||||
before: req.query.before
|
||||
}
|
||||
runtimeAPI.projects.getCommits(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get an individual commit details
|
||||
app.get("/:id/commits/:sha", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
sha: req.params.sha
|
||||
}
|
||||
runtimeAPI.projects.getCommit(opts).then(function(data) {
|
||||
res.json({commit:data});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Push local commits to remote
|
||||
app.post("/:id/push/?*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params[0],
|
||||
track: req.query.u
|
||||
}
|
||||
runtimeAPI.projects.push(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Pull remote commits
|
||||
app.post("/:id/pull/?*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params[0],
|
||||
track: req.query.setUpstream,
|
||||
allowUnrelatedHistories: req.query.allowUnrelatedHistories
|
||||
}
|
||||
runtimeAPI.projects.pull(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Abort an ongoing merge
|
||||
app.delete("/:id/merge", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.abortMerge(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Resolve a merge
|
||||
app.post("/:id/resolve/*", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
resolution: req.body.resolutions
|
||||
}
|
||||
runtimeAPI.projects.resolveMerge(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of local branches
|
||||
app.get("/:id/branches", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: false
|
||||
}
|
||||
runtimeAPI.projects.getBranches(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Delete a local branch - ?force=true
|
||||
app.delete("/:id/branches/:branchName", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.params.branchName,
|
||||
force: !!req.query.force
|
||||
}
|
||||
runtimeAPI.projects.deleteBranch(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of remote branches
|
||||
app.get("/:id/branches/remote", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: true
|
||||
}
|
||||
runtimeAPI.projects.getBranches(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get branch status - commit counts/ahead/behind
|
||||
app.get("/:id/branches/remote/*/status", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.getBranchStatus(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Set the active local branch
|
||||
app.post("/:id/branches", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.body.name,
|
||||
create: req.body.create
|
||||
}
|
||||
runtimeAPI.projects.setBranch(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of remotes
|
||||
app.get("/:id/remotes", needsPermission("projects.read"), getProjectRemotes);
|
||||
|
||||
// Add a remote
|
||||
app.post("/:id/remotes", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.body
|
||||
}
|
||||
if (/^https?:\/\/[^/]+@/i.test(req.body.url)) {
|
||||
res.status(400).json({error:"unexpected_error", message:"Git http url must not include username/password"});
|
||||
return;
|
||||
}
|
||||
runtimeAPI.projects.addRemote(opts).then(function(data) {
|
||||
getProjectRemotes(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Delete a remote
|
||||
app.delete("/:id/remotes/:remoteName", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params.remoteName
|
||||
}
|
||||
runtimeAPI.projects.removeRemote(opts).then(function(data) {
|
||||
getProjectRemotes(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Update a remote
|
||||
app.put("/:id/remotes/:remoteName", needsPermission("projects.write"), function(req,res) {
|
||||
var remote = req.body || {};
|
||||
remote.name = req.params.remoteName;
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: remote
|
||||
}
|
||||
runtimeAPI.projects.updateRemote(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
87
packages/node_modules/@node-red/editor-api/lib/editor/settings.js
vendored
Normal file
87
packages/node_modules/@node-red/editor-api/lib/editor/settings.js
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var apiUtils = require("../util");
|
||||
var runtimeAPI;
|
||||
var sshkeys = require("./sshkeys");
|
||||
var theme = require("./theme");
|
||||
var clone = require("clone");
|
||||
|
||||
function extend(target, source) {
|
||||
var keys = Object.keys(source);
|
||||
var i = keys.length;
|
||||
while(i--) {
|
||||
var value = source[keys[i]]
|
||||
var type = typeof value;
|
||||
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
|
||||
target[keys[i]] = value;
|
||||
} else if (value === null) {
|
||||
if (target.hasOwnProperty(keys[i])) {
|
||||
delete target[keys[i]];
|
||||
}
|
||||
} else {
|
||||
// Object
|
||||
if (target.hasOwnProperty(keys[i])) {
|
||||
target[keys[i]] = extend(target[keys[i]],value);
|
||||
} else {
|
||||
target[keys[i]] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
sshkeys.init(runtimeAPI);
|
||||
},
|
||||
runtimeSettings: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
|
||||
var themeSettings = theme.settings();
|
||||
if (themeSettings) {
|
||||
// result.editorTheme may already exist with the palette
|
||||
// disabled. Need to merge that into the receive settings
|
||||
result.editorTheme = extend(clone(themeSettings),result.editorTheme||{});
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
},
|
||||
userSettings: function(req, res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getUserSettings(opts).then(function(result) {
|
||||
res.json(result);
|
||||
});
|
||||
},
|
||||
updateUserSettings: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
settings: req.body
|
||||
}
|
||||
runtimeAPI.settings.updateUserSettings(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
sshkeys: function() {
|
||||
return sshkeys.app()
|
||||
}
|
||||
}
|
101
packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js
vendored
Normal file
101
packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
var express = require("express");
|
||||
var runtimeAPI;
|
||||
|
||||
function getUsername(userObj) {
|
||||
var username = '__default';
|
||||
if ( userObj && userObj.name ) {
|
||||
username = userObj.name;
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
app: function() {
|
||||
var app = express();
|
||||
|
||||
// List all SSH keys
|
||||
app.get("/", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getUserKeys(opts).then(function(list) {
|
||||
res.json({
|
||||
keys: list
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Get SSH key detail
|
||||
app.get("/:id", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.settings.getUserKey(opts).then(function(data) {
|
||||
res.json({
|
||||
publickey: data
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Generate a SSH key
|
||||
app.post("/", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
// TODO: validate params
|
||||
opts.name = req.body.name;
|
||||
opts.password = req.body.password;
|
||||
opts.comment = req.body.comment;
|
||||
opts.size = req.body.size;
|
||||
|
||||
runtimeAPI.settings.generateUserKey(opts).then(function(name) {
|
||||
res.json({
|
||||
name: name
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Delete a SSH key
|
||||
app.delete("/:id", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.settings.removeUserKey(opts).then(function(name) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
@@ -40,7 +40,6 @@ var defaultContext = {
|
||||
var theme = null;
|
||||
var themeContext = clone(defaultContext);
|
||||
var themeSettings = null;
|
||||
var runtime = null;
|
||||
|
||||
var themeApp;
|
||||
|
||||
@@ -78,12 +77,8 @@ function serveFilesFromTheme(themeValue, themeApp, directory) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
var settings = runtime.settings;
|
||||
init: function(settings) {
|
||||
themeContext = clone(defaultContext);
|
||||
if (runtime.version) {
|
||||
themeContext.version = runtime.version();
|
||||
}
|
||||
themeSettings = null;
|
||||
theme = settings.editorTheme || {};
|
||||
},
|
@@ -17,18 +17,22 @@ var express = require('express');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var Mustache = require("mustache");
|
||||
var mime = require("mime");
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var theme = require("./theme");
|
||||
|
||||
var redNodes;
|
||||
|
||||
var templateDir = path.resolve(__dirname+"/../../../editor/templates");
|
||||
var runtimeAPI;
|
||||
var editorClientDir = path.dirname(require.resolve("@node-red/editor-client"));
|
||||
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.png");
|
||||
var editorTemplatePath = path.join(editorClientDir,"templates","index.mst");
|
||||
var editorTemplate;
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
redNodes = runtime.nodes;
|
||||
editorTemplate = fs.readFileSync(path.join(templateDir,"index.mst"),"utf8");
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
editorTemplate = fs.readFileSync(editorTemplatePath,"utf8");
|
||||
Mustache.parse(editorTemplate);
|
||||
},
|
||||
|
||||
@@ -46,11 +50,26 @@ module.exports = {
|
||||
var icon = req.params.icon;
|
||||
var scope = req.params.scope;
|
||||
var module = scope ? scope + '/' + req.params.module : req.params.module;
|
||||
var iconPath = redNodes.getNodeIconPath(module,icon);
|
||||
res.sendFile(iconPath);
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: module,
|
||||
icon: icon
|
||||
}
|
||||
runtimeAPI.nodes.getIcon(opts).then(function(data) {
|
||||
if (data) {
|
||||
var contentType = mime.getType(icon);
|
||||
res.set("Content-Type", contentType);
|
||||
res.send(data);
|
||||
} else {
|
||||
res.sendFile(defaultNodeIcon);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
editor: function(req,res) {
|
||||
res.send(Mustache.render(editorTemplate,theme.context()));
|
||||
},
|
||||
editorResources: express.static(__dirname + '/../../../public')
|
||||
editorResources: express.static(path.join(editorClientDir,'public'))
|
||||
};
|
@@ -26,17 +26,21 @@ var apiUtil = require("./util");
|
||||
|
||||
var adminApp;
|
||||
var server;
|
||||
var runtime;
|
||||
var editor;
|
||||
|
||||
function init(_server,_runtime) {
|
||||
function init(settings,_server,storage,runtimeAPI) {
|
||||
server = _server;
|
||||
runtime = _runtime;
|
||||
var settings = runtime.settings;
|
||||
if (settings.httpAdminRoot !== false) {
|
||||
apiUtil.init(runtime);
|
||||
adminApp = express();
|
||||
auth.init(runtime);
|
||||
|
||||
var cors = require('cors');
|
||||
var corsHandler = cors({
|
||||
origin: "*",
|
||||
methods: "GET,PUT,POST,DELETE"
|
||||
});
|
||||
adminApp.use(corsHandler);
|
||||
|
||||
auth.init(settings,storage);
|
||||
|
||||
var maxApiRequestSize = settings.apiMaxLength || '5mb';
|
||||
adminApp.use(bodyParser.json({limit:maxApiRequestSize}));
|
||||
@@ -61,7 +65,7 @@ function init(_server,_runtime) {
|
||||
// Editor
|
||||
if (!settings.disableEditor) {
|
||||
editor = require("./editor");
|
||||
var editorApp = editor.init(server, runtime);
|
||||
var editorApp = editor.init(server, settings, runtimeAPI);
|
||||
adminApp.use(editorApp);
|
||||
}
|
||||
|
||||
@@ -70,7 +74,7 @@ function init(_server,_runtime) {
|
||||
adminApp.use(corsHandler);
|
||||
}
|
||||
|
||||
var adminApiApp = require("./admin").init(runtime);
|
||||
var adminApiApp = require("./admin").init(runtimeAPI);
|
||||
adminApp.use(adminApiApp);
|
||||
} else {
|
||||
adminApp = null;
|
||||
@@ -93,23 +97,8 @@ module.exports = {
|
||||
init: init,
|
||||
start: start,
|
||||
stop: stop,
|
||||
library: {
|
||||
register: function(type) {
|
||||
if (editor) {
|
||||
editor.registerLibrary(type);
|
||||
}
|
||||
}
|
||||
},
|
||||
auth: {
|
||||
needsPermission: auth.needsPermission
|
||||
},
|
||||
comms: {
|
||||
publish: function(topic,data,retain) {
|
||||
if (editor) {
|
||||
editor.publish(topic,data,retain);
|
||||
}
|
||||
}
|
||||
},
|
||||
get adminApp() { return adminApp; },
|
||||
get server() { return server; }
|
||||
get httpAdmin() { return adminApp; }
|
||||
};
|
@@ -15,16 +15,14 @@
|
||||
**/
|
||||
|
||||
|
||||
var i18n;
|
||||
var log;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtime) {
|
||||
log = _runtime.log;
|
||||
i18n = _runtime.i18n;
|
||||
},
|
||||
errorHandler: function(err,req,res,next) {
|
||||
console.error(err.stack);
|
||||
//TODO: why this when rejectHandler also?!
|
||||
|
||||
if (err.message === "request entity too large") {
|
||||
log.error(err);
|
||||
} else {
|
||||
@@ -41,5 +39,13 @@ module.exports = {
|
||||
lang = acceptedLanguages[0];
|
||||
}
|
||||
return lang;
|
||||
},
|
||||
rejectHandler: function(req,res,err) {
|
||||
//TODO: why this when errorHandler also?!
|
||||
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
|
||||
res.status(err.status||400).json({
|
||||
code: err.code||"unexpected_error",
|
||||
message: err.message||err.toString()
|
||||
});
|
||||
}
|
||||
}
|
37
packages/node_modules/@node-red/editor-api/package.json
vendored
Normal file
37
packages/node_modules/@node-red/editor-api/package.json
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "0.20.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "0.20.0-beta.3",
|
||||
"@node-red/editor-client": "0.20.0-beta.3",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.15.6",
|
||||
"express": "4.16.4",
|
||||
"memorystore": "1.6.0",
|
||||
"mime": "2.4.0",
|
||||
"mustache": "3.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.4.0",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.2"
|
||||
}
|
||||
}
|
2
packages/node_modules/@node-red/editor-client/.npmignore
vendored
Normal file
2
packages/node_modules/@node-red/editor-client/.npmignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
src
|
||||
docs
|
178
packages/node_modules/@node-red/editor-client/LICENSE
vendored
Normal file
178
packages/node_modules/@node-red/editor-client/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
10
packages/node_modules/@node-red/editor-client/README.md
vendored
Normal file
10
packages/node_modules/@node-red/editor-client/README.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
@node-red/editor-client
|
||||
====================
|
||||
|
||||
Node-RED editor resources module.
|
||||
|
||||
This provides all of the client-side resources of the Node-RED editor application.
|
||||
|
||||
### Source
|
||||
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
@@ -13,4 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var RED = {};
|
||||
|
||||
module.exports = false
|
906
packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
vendored
Executable file
906
packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
vendored
Executable file
@@ -0,0 +1,906 @@
|
||||
{
|
||||
"common": {
|
||||
"label": {
|
||||
"name": "Name",
|
||||
"ok": "Ok",
|
||||
"done":"Done",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"close": "Close",
|
||||
"load": "Load",
|
||||
"save": "Save",
|
||||
"import": "Import",
|
||||
"export": "Export",
|
||||
"back": "Back",
|
||||
"next": "Next",
|
||||
"clone": "Clone project",
|
||||
"cont": "Continue"
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "Flow __number__",
|
||||
"editFlow": "Edit flow: __name__",
|
||||
"confirmDelete": "Confirm delete",
|
||||
"delete": "Are you sure you want to delete '__label__'?",
|
||||
"dropFlowHere": "Drop the flow here",
|
||||
"addFlow": "Add Flow",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled":"Disabled",
|
||||
"info": "Description"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
"view": {
|
||||
"view": "View",
|
||||
"grid": "Grid",
|
||||
"showGrid": "Show grid",
|
||||
"snapGrid": "Snap to grid",
|
||||
"gridSize": "Grid size",
|
||||
"textDir": "Text Direction",
|
||||
"defaultDir": "Default",
|
||||
"ltr": "Left-to-right",
|
||||
"rtl": "Right-to-left",
|
||||
"auto": "Contextual"
|
||||
},
|
||||
"sidebar": {
|
||||
"show": "Show sidebar"
|
||||
},
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
"displayStatus": "Show node status",
|
||||
"displayConfig": "Configuration nodes",
|
||||
"import": "Import",
|
||||
"export": "Export",
|
||||
"search": "Search flows",
|
||||
"searchInput": "search your flows",
|
||||
"clipboard": "Clipboard",
|
||||
"library": "Library",
|
||||
"examples": "Examples",
|
||||
"subflows": "Subflows",
|
||||
"createSubflow": "Create Subflow",
|
||||
"selectionToSubflow": "Selection to Subflow",
|
||||
"flows": "Flows",
|
||||
"add": "Add",
|
||||
"rename": "Rename",
|
||||
"delete": "Delete",
|
||||
"keyboardShortcuts": "Keyboard shortcuts",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"editPalette":"Manage palette",
|
||||
"other": "Other",
|
||||
"showTips": "Show tips",
|
||||
"help": "Node-RED website",
|
||||
"projects": "Projects",
|
||||
"projects-new": "New",
|
||||
"projects-open": "Open",
|
||||
"projects-settings": "Project Settings",
|
||||
"showNodeLabelDefault": "Show label of newly added nodes"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "Toggle navigator",
|
||||
"zoom-out": "Zoom out",
|
||||
"zoom-reset": "Reset zoom",
|
||||
"zoom-in": "Zoom in"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Logged in as __name__",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"login": "Login",
|
||||
"loginFailed": "Login failed",
|
||||
"notAuthorized": "Not authorized",
|
||||
"errors": {
|
||||
"settings": "You must be logged in to access settings",
|
||||
"deploy": "You must be logged in to deploy changes",
|
||||
"notAuthorized": "You must be logged in to perform this action"
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"warning": "<strong>Warning</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "node has undeployed changes",
|
||||
"nodeActionDisabled": "node actions disabled",
|
||||
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||
"credentials_load_failed_reset":"<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
|
||||
"missing_package_file": "<p>Project package file not found.</p><p>The project is missing a package.json file.</p>",
|
||||
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
|
||||
"project_not_found": "<p>Project '__project__' not found.</p>",
|
||||
"git_merge_conflict": "<p>Automatic merging of changes failed.</p><p>Fix the unmerged conflicts then commit the results.</p>"
|
||||
},
|
||||
"error": "<strong>Error</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "Lost connection to server, reconnecting...",
|
||||
"lostConnectionReconnect": "Lost connection to server, reconnecting in __time__s.",
|
||||
"lostConnectionTry": "Try now",
|
||||
"cannotAddSubflowToItself": "Cannot add subflow to itself",
|
||||
"cannotAddCircularReference": "Cannot add subflow - circular reference detected",
|
||||
"unsupportedVersion": "<p>Using an unsupported version of Node.js</p><p>You should upgrade to the latest Node.js LTS release</p>",
|
||||
"failedToAppendNode": "<p>Failed to load '__module__'</p><p>__error__</p>"
|
||||
},
|
||||
"project": {
|
||||
"change-branch": "Change to local branch '__project__'",
|
||||
"merge-abort": "Git merge aborted",
|
||||
"loaded": "Project '__project__' loaded",
|
||||
"updated": "Project '__project__' updated",
|
||||
"pull": "Project '__project__' reloaded",
|
||||
"revert": "Project '__project__' reverted",
|
||||
"merge-complete": "Git merge completed"
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "Manage project dependencies",
|
||||
"setup-cred": "Setup credentials",
|
||||
"setup-project": "Setup project files",
|
||||
"create-default-package": "Create default package file",
|
||||
"no-thanks": "No thanks",
|
||||
"create-default-project": "Create default project files",
|
||||
"show-merge-conflicts": "Show merge conflicts"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"nodes": "Nodes",
|
||||
"node": "__count__ node",
|
||||
"node_plural": "__count__ nodes",
|
||||
"configNode": "__count__ configuration node",
|
||||
"configNode_plural": "__count__ configuration nodes",
|
||||
"flow": "__count__ flow",
|
||||
"flow_plural": "__count__ flows",
|
||||
"subflow": "__count__ subflow",
|
||||
"subflow_plural": "__count__ subflows",
|
||||
"selectNodes": "Select the text above and copy to the clipboard.",
|
||||
"pasteNodes": "Paste flow json or",
|
||||
"selectFile": "select a file to import",
|
||||
"importNodes": "Import nodes",
|
||||
"exportNodes": "Export nodes",
|
||||
"download": "Download",
|
||||
"importUnrecognised": "Imported unrecognised type:",
|
||||
"importUnrecognised_plural": "Imported unrecognised types:",
|
||||
"nodesExported": "Nodes exported to clipboard",
|
||||
"nodesImported": "Imported:",
|
||||
"nodeCopied": "__count__ node copied",
|
||||
"nodeCopied_plural": "__count__ nodes copied",
|
||||
"invalidFlow": "Invalid flow: __message__",
|
||||
"export": {
|
||||
"selected":"selected nodes",
|
||||
"current":"current flow",
|
||||
"all":"all flows",
|
||||
"compact":"compact",
|
||||
"formatted":"formatted",
|
||||
"copy": "Export to clipboard"
|
||||
},
|
||||
"import": {
|
||||
"import": "Import to",
|
||||
"newFlow": "new flow",
|
||||
"errors": {
|
||||
"notArray": "Input not a JSON Array",
|
||||
"itemNotObject": "Input not a valid flow - item __index__ not a node object",
|
||||
"missingId": "Input not a valid flow - item __index__ missing 'id' property",
|
||||
"missingType": "Input not a valid flow - item __index__ missing 'type' property"
|
||||
}
|
||||
},
|
||||
"copyMessagePath": "Path copied",
|
||||
"copyMessageValue": "Value copied",
|
||||
"copyMessageValue_truncated": "Truncated value copied"
|
||||
},
|
||||
"deploy": {
|
||||
"deploy": "Deploy",
|
||||
"full": "Full",
|
||||
"fullDesc": "Deploys everything in the workspace",
|
||||
"modifiedFlows": "Modified Flows",
|
||||
"modifiedFlowsDesc": "Only deploys flows that contain changed nodes",
|
||||
"modifiedNodes": "Modified Nodes",
|
||||
"modifiedNodesDesc": "Only deploys nodes that have changed",
|
||||
"restartFlows": "Restart Flows",
|
||||
"restartFlowsDesc": "Restarts the current deployed flows",
|
||||
"successfulDeploy": "Successfully deployed",
|
||||
"successfulRestart": "Successfully restarted flows",
|
||||
"deployFailed": "Deploy failed: __message__",
|
||||
"unusedConfigNodes":"You have some unused configuration nodes.",
|
||||
"unusedConfigNodesLink":"Click here to see them",
|
||||
"errors": {
|
||||
"noResponse": "no response from server"
|
||||
},
|
||||
"confirm": {
|
||||
"button": {
|
||||
"ignore": "Ignore",
|
||||
"confirm": "Confirm deploy",
|
||||
"review": "Review changes",
|
||||
"cancel": "Cancel",
|
||||
"merge": "Merge",
|
||||
"overwrite": "Ignore & deploy"
|
||||
},
|
||||
"undeployedChanges": "You have undeployed changes.\n\nLeaving this page will lose these changes.",
|
||||
"improperlyConfigured": "The workspace contains some nodes that are not properly configured:",
|
||||
"unknown": "The workspace contains some unknown node types:",
|
||||
"confirm": "Are you sure you want to deploy?",
|
||||
"doNotWarn": "do not warn about this again",
|
||||
"conflict": "The server is running a more recent set of flows.",
|
||||
"backgroundUpdate": "The flows on the server have been updated.",
|
||||
"conflictChecking": "Checking to see if the changes can be merged automatically",
|
||||
"conflictAutoMerge": "The changes include no conflicts and can be merged automatically.",
|
||||
"conflictManualMerge": "The changes include conflicts that must be resolved before they can be deployed.",
|
||||
"plusNMore": "+ __count__ more"
|
||||
}
|
||||
},
|
||||
"eventLog": {
|
||||
"title": "Event log",
|
||||
"view": "View log"
|
||||
},
|
||||
"diff": {
|
||||
"unresolvedCount": "__count__ unresolved conflict",
|
||||
"unresolvedCount_plural": "__count__ unresolved conflicts",
|
||||
"globalNodes": "Global nodes",
|
||||
"flowProperties": "Flow Properties",
|
||||
"type": {
|
||||
"added": "added",
|
||||
"changed": "changed",
|
||||
"unchanged": "unchanged",
|
||||
"deleted": "deleted",
|
||||
"flowDeleted": "flow deleted",
|
||||
"flowAdded": "flow added",
|
||||
"movedTo": "moved to __id__",
|
||||
"movedFrom": "moved from __id__"
|
||||
},
|
||||
"nodeCount": "__count__ node",
|
||||
"nodeCount_plural": "__count__ nodes",
|
||||
"local":"Local changes",
|
||||
"remote":"Remote changes",
|
||||
"reviewChanges": "Review Changes",
|
||||
"noBinaryFileShowed": "Cannot show binary file contents",
|
||||
"viewCommitDiff": "View Commit Changes",
|
||||
"compareChanges": "Compare Changes",
|
||||
"saveConflict": "Save conflict resolution",
|
||||
"conflictHeader": "<span>__resolved__</span> of <span>__unresolved__</span> conflicts resolved",
|
||||
"commonVersionError": "Common Version doesn't contain valid JSON:",
|
||||
"oldVersionError": "Old Version doesn't contain valid JSON:",
|
||||
"newVersionError": "New Version doesn't contain valid JSON:"
|
||||
},
|
||||
"subflow": {
|
||||
"editSubflow": "Edit flow template: __name__",
|
||||
"edit": "Edit flow template",
|
||||
"subflowInstances": "There is __count__ instance of this subflow template",
|
||||
"subflowInstances_plural": "There are __count__ instances of this subflow template",
|
||||
"editSubflowProperties": "edit properties",
|
||||
"input": "inputs:",
|
||||
"output": "outputs:",
|
||||
"deleteSubflow": "delete subflow",
|
||||
"info": "Description",
|
||||
"category": "Category",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
|
||||
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"configEdit": "Edit",
|
||||
"configAdd": "Add",
|
||||
"configUpdate": "Update",
|
||||
"configDelete": "Delete",
|
||||
"nodesUse": "__count__ node uses this config",
|
||||
"nodesUse_plural": "__count__ nodes use this config",
|
||||
"addNewConfig": "Add new __type__ config node",
|
||||
"editNode": "Edit __type__ node",
|
||||
"editConfig": "Edit __type__ config node",
|
||||
"addNewType": "Add new __type__...",
|
||||
"nodeProperties": "node properties",
|
||||
"label": "Label",
|
||||
"portLabels": "Port labels",
|
||||
"labelInputs": "Inputs",
|
||||
"labelOutputs": "Outputs",
|
||||
"settingIcon": "Icon",
|
||||
"noDefaultLabel": "none",
|
||||
"defaultLabel": "use default label",
|
||||
"searchIcons": "Search icons",
|
||||
"useDefault": "use default",
|
||||
"description": "Description",
|
||||
"show": "Show",
|
||||
"hide": "Hide",
|
||||
"errors": {
|
||||
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it"
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
"title": "Keyboard Shortcuts",
|
||||
"keyboard": "Keyboard",
|
||||
"filterActions": "filter actions",
|
||||
"shortcut": "shortcut",
|
||||
"scope": "scope",
|
||||
"unassigned": "Unassigned",
|
||||
"global": "global",
|
||||
"workspace": "workspace",
|
||||
"selectAll": "Select all nodes",
|
||||
"selectAllConnected": "Select all connected nodes",
|
||||
"addRemoveNode": "Add/remove node from selection",
|
||||
"editSelected": "Edit selected node",
|
||||
"deleteSelected": "Delete selected nodes or link",
|
||||
"importNode": "Import nodes",
|
||||
"exportNode": "Export nodes",
|
||||
"nudgeNode": "Move selected nodes (1px)",
|
||||
"moveNode": "Move selected nodes (20px)",
|
||||
"toggleSidebar": "Toggle sidebar",
|
||||
"togglePalette": "Toggle palette",
|
||||
"copyNode": "Copy selected nodes",
|
||||
"cutNode": "Cut selected nodes",
|
||||
"pasteNode": "Paste nodes",
|
||||
"undoChange": "Undo the last change performed",
|
||||
"searchBox": "Open search box",
|
||||
"managePalette": "Manage palette"
|
||||
},
|
||||
"library": {
|
||||
"openLibrary": "Open Library...",
|
||||
"saveToLibrary": "Save to Library...",
|
||||
"typeLibrary": "__type__ library",
|
||||
"unnamedType": "Unnamed __type__",
|
||||
"exportToLibrary": "Export nodes to library",
|
||||
"dialogSaveOverwrite": "A __libraryType__ called __libraryName__ already exists. Overwrite?",
|
||||
"invalidFilename": "Invalid filename",
|
||||
"savedNodes": "Saved nodes",
|
||||
"savedType": "Saved __type__",
|
||||
"saveFailed": "Save failed: __message__",
|
||||
"filename": "Filename",
|
||||
"folder": "Folder",
|
||||
"filenamePlaceholder": "file",
|
||||
"fullFilenamePlaceholder": "a/b/file",
|
||||
"folderPlaceholder": "a/b",
|
||||
"breadcrumb": "Library"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "no information available",
|
||||
"filter": "filter nodes",
|
||||
"search": "search modules",
|
||||
"addCategory": "Add new...",
|
||||
"label": {
|
||||
"subflows": "subflows",
|
||||
"input": "input",
|
||||
"output": "output",
|
||||
"function": "function",
|
||||
"social": "social",
|
||||
"storage": "storage",
|
||||
"analysis": "analysis",
|
||||
"advanced": "advanced"
|
||||
},
|
||||
"actions": {
|
||||
"collapse-all": "Collapse all categories",
|
||||
"expand-all": "Expand all categories"
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "Node added to palette:",
|
||||
"nodeAdded_plural": "Nodes added to palette",
|
||||
"nodeRemoved": "Node removed from palette:",
|
||||
"nodeRemoved_plural": "Nodes removed from palette:",
|
||||
"nodeEnabled": "Node enabled:",
|
||||
"nodeEnabled_plural": "Nodes enabled:",
|
||||
"nodeDisabled": "Node disabled:",
|
||||
"nodeDisabled_plural": "Nodes disabled:",
|
||||
"nodeUpgraded": "Node module __module__ upgraded to version __version__"
|
||||
},
|
||||
"editor": {
|
||||
"title": "Manage palette",
|
||||
"palette": "Palette",
|
||||
"times": {
|
||||
"seconds": "seconds ago",
|
||||
"minutes": "minutes ago",
|
||||
"minutesV": "__count__ minutes ago",
|
||||
"hoursV": "__count__ hour ago",
|
||||
"hoursV_plural": "__count__ hours ago",
|
||||
"daysV": "__count__ day ago",
|
||||
"daysV_plural": "__count__ days ago",
|
||||
"weeksV": "__count__ week ago",
|
||||
"weeksV_plural": "__count__ weeks ago",
|
||||
"monthsV": "__count__ month ago",
|
||||
"monthsV_plural": "__count__ months ago",
|
||||
"yearsV": "__count__ year ago",
|
||||
"yearsV_plural": "__count__ years ago",
|
||||
"yearMonthsV": "__y__ year, __count__ month ago",
|
||||
"yearMonthsV_plural": "__y__ year, __count__ months ago",
|
||||
"yearsMonthsV": "__y__ years, __count__ month ago",
|
||||
"yearsMonthsV_plural": "__y__ years, __count__ months ago"
|
||||
},
|
||||
"nodeCount": "__label__ node",
|
||||
"nodeCount_plural": "__label__ nodes",
|
||||
"moduleCount": "__count__ module available",
|
||||
"moduleCount_plural": "__count__ modules available",
|
||||
"inuse": "in use",
|
||||
"enableall": "enable all",
|
||||
"disableall": "disable all",
|
||||
"enable": "enable",
|
||||
"disable": "disable",
|
||||
"remove": "remove",
|
||||
"update": "update to __version__",
|
||||
"updated": "updated",
|
||||
"install": "install",
|
||||
"installed": "installed",
|
||||
"conflict": "conflict",
|
||||
"conflictTip": "<p>This module cannot be installed as it includes a<br/>node type that has already been installed</p><p>Conflicts with <code>__module__</code></p>",
|
||||
"loading": "Loading catalogues...",
|
||||
"tab-nodes": "Nodes",
|
||||
"tab-install": "Install",
|
||||
"sort": "sort:",
|
||||
"sortAZ": "a-z",
|
||||
"sortRecent": "recent",
|
||||
"more": "+ __count__ more",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
|
||||
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
|
||||
"removeFailed": "<p>Failed to remove: __module__</p><p>__message__</p><p>Check the log for more information</p>",
|
||||
"updateFailed": "<p>Failed to update: __module__</p><p>__message__</p><p>Check the log for more information</p>",
|
||||
"enableFailed": "<p>Failed to enable: __module__</p><p>__message__</p><p>Check the log for more information</p>",
|
||||
"disableFailed": "<p>Failed to disable: __module__</p><p>__message__</p><p>Check the log for more information</p>"
|
||||
},
|
||||
"confirm": {
|
||||
"install": {
|
||||
"body":"<p>Installing '__module__'</p><p>Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.</p>",
|
||||
"title": "Install nodes"
|
||||
},
|
||||
"remove": {
|
||||
"body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
|
||||
"title": "Remove nodes"
|
||||
},
|
||||
"update": {
|
||||
"body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
|
||||
"title": "Update nodes"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body":"An update for this node is available, but it is not installed in a location that the palette manager can update.<br/><br/>Please refer to the documentation for how to update this node."
|
||||
},
|
||||
"button": {
|
||||
"review": "Open node information",
|
||||
"install": "Install",
|
||||
"remove": "Remove",
|
||||
"update": "Update"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"info": {
|
||||
"name": "Node information",
|
||||
"tabName": "Name",
|
||||
"label": "info",
|
||||
"node": "Node",
|
||||
"type": "Type",
|
||||
"module": "Module",
|
||||
"id": "ID",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"subflow": "Subflow",
|
||||
"instances": "Instances",
|
||||
"properties": "Properties",
|
||||
"info": "Information",
|
||||
"desc": "Description",
|
||||
"blank": "blank",
|
||||
"null": "null",
|
||||
"showMore": "show more",
|
||||
"showLess": "show less",
|
||||
"flow": "Flow",
|
||||
"selection":"Selection",
|
||||
"nodes":"__count__ nodes",
|
||||
"flowDesc": "Flow Description",
|
||||
"subflowDesc": "Subflow Description",
|
||||
"nodeHelp": "Node Help",
|
||||
"none":"None",
|
||||
"arrayItems": "__count__ items",
|
||||
"showTips":"You can open the tips from the settings panel"
|
||||
},
|
||||
"config": {
|
||||
"name": "Configuration nodes",
|
||||
"label": "config",
|
||||
"global": "On all flows",
|
||||
"none": "none",
|
||||
"subflows": "subflows",
|
||||
"flows": "flows",
|
||||
"filterUnused":"unused",
|
||||
"filterAll":"all",
|
||||
"filtered": "__count__ hidden"
|
||||
},
|
||||
"context": {
|
||||
"name":"Context Data",
|
||||
"label":"context",
|
||||
"none": "none selected",
|
||||
"refresh": "refresh to load",
|
||||
"empty": "empty",
|
||||
"node": "Node",
|
||||
"flow": "Flow",
|
||||
"global": "Global",
|
||||
"deleteConfirm": "Are you sure you want to delete this item?"
|
||||
},
|
||||
"palette": {
|
||||
"name": "Palette management",
|
||||
"label": "palette"
|
||||
},
|
||||
"project": {
|
||||
"label": "project",
|
||||
"name": "Project",
|
||||
"description": "Description",
|
||||
"dependencies": "Dependencies",
|
||||
"settings": "Settings",
|
||||
"noSummaryAvailable": "No summary available",
|
||||
"editDescription": "Edit project description",
|
||||
"editDependencies": "Edit project dependencies",
|
||||
"editReadme": "Edit README.md",
|
||||
"showProjectSettings": "Show project settings",
|
||||
"projectSettings": {
|
||||
"title": "Project Settings",
|
||||
"edit": "edit",
|
||||
"none": "None",
|
||||
"install": "install",
|
||||
"removeFromProject": "remove from project",
|
||||
"addToProject": "add to project",
|
||||
"files": "Files",
|
||||
"flow": "Flow",
|
||||
"credentials": "Credentials",
|
||||
"invalidEncryptionKey": "Invalid encryption key",
|
||||
"encryptionEnabled": "Encryption enabled",
|
||||
"encryptionDisabled": "Encryption disabled",
|
||||
"setTheEncryptionKey": "Set the encryption key:",
|
||||
"resetTheEncryptionKey": "Reset the encryption key:",
|
||||
"changeTheEncryptionKey": "Change the encryption key:",
|
||||
"currentKey": "Current key",
|
||||
"newKey": "New key",
|
||||
"credentialsAlert": "This will delete all existing credentials",
|
||||
"versionControl": "Version Control",
|
||||
"branches": "Branches",
|
||||
"noBranches": "No branches",
|
||||
"deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.",
|
||||
"unmergedConfirm": "The local branch '__name__' has unmerged changes that will be lost. Are you sure you want to delete it?",
|
||||
"deleteUnmergedBranch": "Delete unmerged branch",
|
||||
"gitRemotes": "Git remotes",
|
||||
"addRemote": "add remote",
|
||||
"addRemote2": "Add remote",
|
||||
"remoteName": "Remote name",
|
||||
"nameRule": "Must contain only A-Z 0-9 _ -",
|
||||
"url": "URL",
|
||||
"urlRule": "https://, ssh:// or file://",
|
||||
"urlRule2": "Do not include the username/password in the URL",
|
||||
"noRemotes": "No remotes",
|
||||
"deleteRemoteConfrim": "Are you sure you want to delete the remote '__name__'?",
|
||||
"deleteRemote": "Delete remote"
|
||||
},
|
||||
"userSettings": {
|
||||
"committerDetail": "Committer Details",
|
||||
"committerTip": "Leave blank to use system default",
|
||||
"userName": "Username",
|
||||
"email": "Email",
|
||||
"sshKeys": "SSH Keys",
|
||||
"sshKeysTip": "Allows you to create secure connections to remote git repositories.",
|
||||
"add": "add key",
|
||||
"addSshKey": "Add SSH Key",
|
||||
"addSshKeyTip": "Generate a new public/private key pair",
|
||||
"name": "Name",
|
||||
"nameRule": "Must contain only A-Z 0-9 _ -",
|
||||
"passphrase": "Passphrase",
|
||||
"passphraseShort": "Passphrase too short",
|
||||
"optional": "Optional",
|
||||
"cancel": "Cancel",
|
||||
"generate": "Generate key",
|
||||
"noSshKeys": "No SSH keys",
|
||||
"copyPublicKey": "Copy public key to clipboard",
|
||||
"delete": "Delete key",
|
||||
"gitConfig": "Git config",
|
||||
"deleteConfirm": "Are you sure you want to delete the SSH key __name__? This cannot be undone."
|
||||
},
|
||||
"versionControl": {
|
||||
"unstagedChanges": "Unstaged changes",
|
||||
"stagedChanges": "Staged changes",
|
||||
"unstageChange": "Unstage change",
|
||||
"stageChange": "Stage change",
|
||||
"unstageAllChange": "Unstage all changes",
|
||||
"stageAllChange": "Stage all changes",
|
||||
"commitChanges": "Commit changes",
|
||||
"resolveConflicts": "Resolve conflicts",
|
||||
"head": "HEAD",
|
||||
"staged": "Staged",
|
||||
"unstaged": "Unstaged",
|
||||
"local": "Local",
|
||||
"remote": "Remote",
|
||||
"revert": "Are you sure you want to revert the changes to '__file__'? This cannot be undone.",
|
||||
"revertChanges": "Revert changes",
|
||||
"localChanges": "Local Changes",
|
||||
"none": "None",
|
||||
"conflictResolve": "All conflicts resolved. Commit the changes to complete the merge.",
|
||||
"localFiles": "Local files",
|
||||
"all": "all",
|
||||
"unmergedChanges": "Unmerged changes",
|
||||
"abortMerge": "abort merge",
|
||||
"commit": "commit",
|
||||
"changeToCommit": "Changes to commit",
|
||||
"commitPlaceholder": "Enter your commit message",
|
||||
"cancelCapital": "Cancel",
|
||||
"commitCapital": "Commit",
|
||||
"commitHistory": "Commit History",
|
||||
"branch": "Branch:",
|
||||
"moreCommits": " more commit(s)",
|
||||
"changeLocalBranch": "Change local branch",
|
||||
"createBranchPlaceholder": "Find or create a branch",
|
||||
"upstream": "upstream",
|
||||
"localOverwrite": "You have local changes that would be overwritten by changing the branch. You must either commit or undo those changes first.",
|
||||
"manageRemoteBranch": "Manage remote branch",
|
||||
"unableToAccess": "Unable to access remote repository",
|
||||
"retry": "Retry",
|
||||
"setUpstreamBranch": "Set as upstream branch",
|
||||
"createRemoteBranchPlaceholder": "Find or create a remote branch",
|
||||
"trackedUpstreamBranch": "The created branch will be set as the tracked upstream branch.",
|
||||
"selectUpstreamBranch": "The branch will be created. Select below to set it as the tracked upstream branch.",
|
||||
"pushFailed": "Push failed as the remote has more recent commits. Pull and merge first, then push again.",
|
||||
"push": "push",
|
||||
"pull": "pull",
|
||||
"unablePull": "<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>",
|
||||
"showUnstagedChanges": "Show unstaged changes",
|
||||
"connectionFailed": "Could not connect to remote repository: ",
|
||||
"pullUnrelatedHistory": "<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",
|
||||
"pullChanges": "Pull changes",
|
||||
"history": "history",
|
||||
"projectHistory": "Project History",
|
||||
"daysAgo": "__count__ day ago",
|
||||
"daysAgo_plural": "__count__ days ago",
|
||||
"hoursAgo": "__count__ hour ago",
|
||||
"hoursAgo_plural": "__count__ hours ago",
|
||||
"minsAgo": "__count__ min ago",
|
||||
"minsAgo_plural": "__count__ mins ago",
|
||||
"secondsAgo": "Seconds ago",
|
||||
"notTracking": "Your local branch is not currently tracking a remote branch.",
|
||||
"statusUnmergedChanged": "Your repository has unmerged changes. You need to fix the conflicts and commit the result.",
|
||||
"repositoryUpToDate": "Your repository is up to date.",
|
||||
"commitsAhead": "Your repository is __count__ commit ahead of the remote. You can push this commit now.",
|
||||
"commitsAhead_plural": "Your repository is __count__ commits ahead of the remote. You can push these commits now.",
|
||||
"commitsBehind": "Your repository is __count__ commit behind of the remote. You can pull this commit now.",
|
||||
"commitsBehind_plural": "Your repository is __count__ commits behind of the remote. You can pull these commits now.",
|
||||
"commitsAheadAndBehind1": "Your repository is __count__ commit behind and ",
|
||||
"commitsAheadAndBehind1_plural": "Your repository is __count__ commits behind and ",
|
||||
"commitsAheadAndBehind2": "__count__ commit ahead of the remote. ",
|
||||
"commitsAheadAndBehind2_plural": "__count__ commits ahead of the remote. ",
|
||||
"commitsAheadAndBehind3": "You must pull the remote commit down before pushing.",
|
||||
"commitsAheadAndBehind3_plural": "You must pull the remote commits down before pushing.",
|
||||
"refreshCommitHistory": "Refresh commit history",
|
||||
"refreshChanges": "Refresh changes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"typedInput": {
|
||||
"type": {
|
||||
"str": "string",
|
||||
"num": "number",
|
||||
"re": "regular expression",
|
||||
"bool": "boolean",
|
||||
"json": "JSON",
|
||||
"bin": "buffer",
|
||||
"date": "timestamp",
|
||||
"jsonata": "expression",
|
||||
"env": "env variable"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
"add": "add"
|
||||
},
|
||||
"search": {
|
||||
"empty": "No matches found",
|
||||
"addNode": "add a node..."
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Functions",
|
||||
"functionReference": "Function reference",
|
||||
"insert": "Insert",
|
||||
"title": "JSONata Expression editor",
|
||||
"test": "Test",
|
||||
"data": "Example message",
|
||||
"result": "Result",
|
||||
"format": "format expression",
|
||||
"compatMode": "Compatibility mode enabled",
|
||||
"compatModeDesc": "<h3>JSONata compatibility mode</h3><p> The current expression appears to still reference <code>msg</code> so will be evaluated in compatibility mode. Please update the expression to not use <code>msg</code> as this mode will be removed in the future.</p><p> When JSONata support was first added to Node-RED, it required the expression to reference the <code>msg</code> object. For example <code>msg.payload</code> would be used to access the payload.</p><p> That is no longer necessary as the expression will be evaluated against the message directly. To access the payload, the expression should be just <code>payload</code>.</p>",
|
||||
"noMatch": "No matching result",
|
||||
"errors": {
|
||||
"invalid-expr": "Invalid JSONata expression:\n __message__",
|
||||
"invalid-msg": "Invalid example JSON message:\n __message__",
|
||||
"context-unsupported": "Cannot test context functions\n $flowContext or $globalContext",
|
||||
"eval": "Error evaluating expression:\n __message__"
|
||||
}
|
||||
},
|
||||
"jsEditor": {
|
||||
"title": "JavaScript editor"
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "JSON editor",
|
||||
"format": "format JSON"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "Markdown editor",
|
||||
"format": "Formatted with markdown",
|
||||
"heading1": "Heading 1",
|
||||
"heading2": "Heading 2",
|
||||
"heading3": "Heading 3",
|
||||
"bold": "Bold",
|
||||
"italic": "Italic",
|
||||
"code": "Code",
|
||||
"ordered-list": "Ordered list",
|
||||
"unordered-list": "Unordered list",
|
||||
"quote": "Quote",
|
||||
"link": "Link",
|
||||
"horizontal-rule": "Horizontal rule",
|
||||
"toggle-preview": "Toggle preview"
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "Buffer editor",
|
||||
"modeString": "Handle as UTF-8 String",
|
||||
"modeArray": "Handle as JSON array",
|
||||
"modeDesc":"<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||
},
|
||||
"projects": {
|
||||
"config-git": "Configure Git client",
|
||||
"welcome": {
|
||||
"hello": "Hello! We have introduced 'projects' to Node-RED.",
|
||||
"desc0": "This is a new way for you to manage your flow files and includes version control of your flows.",
|
||||
"desc1": "To get started you can create your first project or clone an existing project from a git repository.",
|
||||
"desc2": "If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.",
|
||||
"create": "Create Project",
|
||||
"clone": "Clone Repository",
|
||||
"not-right-now": "Not right now"
|
||||
},
|
||||
"git-config": {
|
||||
"setup": "Setup your version control client",
|
||||
"desc0": "Node-RED uses the open source tool Git for version control. It tracks changes to your project files and lets you push them to remote repositories.",
|
||||
"desc1": "When you commit a set of changes, Git records who made the changes with a username and email address. The Username can be anything you want - it does not need to be your real name.",
|
||||
"desc2": "Your Git client is already configured with the details below.",
|
||||
"desc3": "You can change these settings later under the 'Git config' tab of the settings dialog.",
|
||||
"username": "Username",
|
||||
"email": "Email"
|
||||
},
|
||||
"project-details": {
|
||||
"create": "Create your project",
|
||||
"desc0": "A project is maintained as a Git repository. It makes it much easier to share your flows with others and to collaborate on them.",
|
||||
"desc1": "You can create multiple projects and quickly switch between them from the editor.",
|
||||
"desc2": "To begin, your project needs a name and an optional description.",
|
||||
"already-exists": "Project already exists",
|
||||
"must-contain": "Must contain only A-Z 0-9 _ -",
|
||||
"project-name": "Project name",
|
||||
"desc": "Description",
|
||||
"opt": "Optional"
|
||||
},
|
||||
"clone-project": {
|
||||
"clone": "Clone a project",
|
||||
"desc0": "If you already have a git repository containing a project, you can clone it to get started.",
|
||||
"already-exists": "Project already exists",
|
||||
"must-contain": "Must contain only A-Z 0-9 _ -",
|
||||
"project-name": "Project name",
|
||||
"no-info-in-url": "Do not include the username/password in the url",
|
||||
"git-url": "Git repository URL",
|
||||
"protocols": "https://, ssh:// or file://",
|
||||
"auth-failed": "Authentication failed",
|
||||
"username": "Username",
|
||||
"passwd": "Password",
|
||||
"ssh-key": "SSH Key",
|
||||
"passphrase": "Passphrase",
|
||||
"ssh-key-desc": "Before you can clone a repository over ssh you must add an SSH key to access it.",
|
||||
"ssh-key-add": "Add an ssh key",
|
||||
"credential-key": "Credentials encryption key",
|
||||
"cant-get-ssh-key": "Error! Can't get selected SSH key path.",
|
||||
"already-exists2": "already exists",
|
||||
"git-error": "git error",
|
||||
"connection-failed": "Connection failed",
|
||||
"not-git-repo": "Not a git repository",
|
||||
"repo-not-found": "Repository not found"
|
||||
},
|
||||
"default-files": {
|
||||
"create": "Create your project files",
|
||||
"desc0": "A project contains your flow files, a README file and a package.json file.",
|
||||
"desc1": "It can contain any other files you want to maintain in the Git repository.",
|
||||
"desc2": "Your existing flow and credential files will be copied into the project.",
|
||||
"flow-file": "Flow file",
|
||||
"credentials-file": "Credentials file"
|
||||
},
|
||||
"encryption-config": {
|
||||
"setup": "Setup encryption of your credentials file",
|
||||
"desc0": "Your flow credentials file can be encrypted to keep its contents secure.",
|
||||
"desc1": "If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.",
|
||||
"desc2": "Your flow credentials file is not currently encrypted.",
|
||||
"desc3": "That means its contents, such as passwords and access tokens, can be read by anyone with access to the file.",
|
||||
"desc4": "If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.",
|
||||
"desc5": "Your flow credentials file is currently encrypted using the credentialSecret property from your settings file as the key.",
|
||||
"desc6": "Your flow credentials file is currently encrypted using a system-generated key. You should provide a new secret key for this project.",
|
||||
"desc7": "The key will be stored separately from your project files. You will need to provide the key to use this project in another instance of Node-RED.",
|
||||
"credentials": "Credentials",
|
||||
"enable": "Enable encryption",
|
||||
"disable": "Disable encryption",
|
||||
"disabled": "disabled",
|
||||
"copy": "Copy over existing key",
|
||||
"use-custom": "Use custom key",
|
||||
"desc8": "The credentials file will not be encrypted and its contents easily read",
|
||||
"create-project-files": "Create project files",
|
||||
"create-project": "Create project",
|
||||
"already-exists": "already exists",
|
||||
"git-error": "git error",
|
||||
"git-auth-error": "git auth error"
|
||||
},
|
||||
"create-success": {
|
||||
"success": "You have successfully created your first project!",
|
||||
"desc0": "You can now continue to use Node-RED just as you always have.",
|
||||
"desc1": "The 'info' tab in the sidebar shows you what your current active project is. The button next to the name can be used to access the project settings view.",
|
||||
"desc2": "The 'history' tab in the sidebar can be used to view files that have changed in your project and to commit them. It shows you a complete history of your commits and allows you to push your changes to a remote repository."
|
||||
},
|
||||
"create": {
|
||||
"projects": "Projects",
|
||||
"already-exists": "Project already exists",
|
||||
"must-contain": "Must contain only A-Z 0-9 _ -",
|
||||
"no-info-in-url": "Do not include the username/password in the url",
|
||||
"open": "Open Project",
|
||||
"create": "Create Project",
|
||||
"clone": "Clone Repository",
|
||||
"project-name": "Project name",
|
||||
"desc": "Description",
|
||||
"opt": "Optional",
|
||||
"flow-file": "Flow file",
|
||||
"credentials": "Credentials",
|
||||
"enable-encryption": "Enable encryption",
|
||||
"disable-encryption": "Disable encryption",
|
||||
"encryption-key": "Encryption key",
|
||||
"desc0": "A phrase to secure your credentials with",
|
||||
"desc1": "The credentials file will not be encrypted and its contents easily read",
|
||||
"git-url": "Git repository URL",
|
||||
"protocols": "https://, ssh:// or file://",
|
||||
"auth-failed": "Authentication failed",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"ssh-key": "SSH Key",
|
||||
"passphrase": "Passphrase",
|
||||
"desc2": "Before you can clone a repository over ssh you must add an SSH key to access it.",
|
||||
"add-ssh-key": "Add an ssh key",
|
||||
"credentials-encryption-key": "Credentials encryption key",
|
||||
"already-exists-2": "already exists",
|
||||
"git-error": "git error",
|
||||
"con-failed": "Connection failed",
|
||||
"not-git": "Not a git repository",
|
||||
"no-resource": "Repository not found",
|
||||
"cant-get-ssh-key-path": "Error! Can't get selected SSH key path.",
|
||||
"unexpected_error": "unexpected_error"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "Are you sure you want to delete this project?"
|
||||
},
|
||||
"create-project-list": {
|
||||
"search": "search your projects",
|
||||
"current": "current"
|
||||
},
|
||||
"require-clean": {
|
||||
"confirm": "<p>You have undeployed changes that will be lost.</p><p>Do you want to continue?</p>"
|
||||
},
|
||||
"send-req": {
|
||||
"auth-req": "Authentication required for repository",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"passphrase": "Passphrase",
|
||||
"retry": "Retry",
|
||||
"update-failed": "Failed to update auth",
|
||||
"unhandled": "Unhandled error response"
|
||||
},
|
||||
"create-branch-list": {
|
||||
"invalid": "Invalid branch",
|
||||
"create": "Create branch",
|
||||
"current": "current"
|
||||
},
|
||||
"create-default-file-set": {
|
||||
"no-active": "Cannot create default file set without an active project",
|
||||
"no-empty": "Cannot create default file set on a non-empty project",
|
||||
"git-error": "git error"
|
||||
},
|
||||
"errors" : {
|
||||
"no-username-email": "Your Git client is not configured with a username/email.",
|
||||
"unexpected": "An unexpected error occurred",
|
||||
"code": "code"
|
||||
}
|
||||
},
|
||||
"editor-tab": {
|
||||
"properties": "Properties",
|
||||
"description": "Description",
|
||||
"appearance": "Appearance"
|
||||
}
|
||||
}
|
26
red/api/editor/locales/en-US/jsonata.json → packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json
vendored
Normal file → Executable file
26
red/api/editor/locales/en-US/jsonata.json → packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json
vendored
Normal file → Executable file
@@ -115,7 +115,6 @@
|
||||
"args": "array",
|
||||
"desc": "Returns the mean value of an `array` of numbers. It is an error if the input `array` contains an item which isn't a number."
|
||||
},
|
||||
|
||||
"$boolean": {
|
||||
"args": "arg",
|
||||
"desc": "Casts the argument to a Boolean using the following rules:\n\n - `Boolean` : unchanged\n - `string`: empty : `false`\n - `string`: non-empty : `true`\n - `number`: `0` : `false`\n - `number`: non-zero : `true`\n - `null` : `false`\n - `array`: empty : `false`\n - `array`: contains a member that casts to `true` : `true`\n - `array`: all members cast to `false` : `false`\n - `object`: empty : `false`\n - `object`: non-empty : `true`\n - `function` : `false`"
|
||||
@@ -189,12 +188,12 @@
|
||||
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`.\n\nThe optional `init` parameter is used as the initial value in the aggregation."
|
||||
},
|
||||
"$flowContext": {
|
||||
"args": "string",
|
||||
"desc": "Retrieves a flow context property."
|
||||
"args": "string[, string]",
|
||||
"desc": "Retrieves a flow context property.\n\nThis is a Node-RED defined function."
|
||||
},
|
||||
"$globalContext": {
|
||||
"args": "string",
|
||||
"desc": "Retrieves a global context property."
|
||||
"args": "string[, string]",
|
||||
"desc": "Retrieves a global context property.\n\nThis is a Node-RED defined function."
|
||||
},
|
||||
"$pad": {
|
||||
"args": "string, width [, char]",
|
||||
@@ -215,5 +214,22 @@
|
||||
"$toMillis": {
|
||||
"args": "timestamp",
|
||||
"desc": "Convert a `timestamp` string in the ISO 8601 format to the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. An error is thrown if the string is not in the correct format."
|
||||
},
|
||||
"$env": {
|
||||
"args": "arg",
|
||||
"desc": "Returns the value of an environment variable.\n\nThis is a Node-RED defined function."
|
||||
},
|
||||
"$eval": {
|
||||
"args": "expr [, context]",
|
||||
"desc": "Parses and evaluates the string `expr` which contains literal JSON or a JSONata expression using the current context as the context for evaluation."
|
||||
},
|
||||
"$formatInteger": {
|
||||
"args": "number, picture",
|
||||
"desc": "Casts the `number` to a string and formats it to an integer representation as specified by the `picture` string. The picture string parameter defines how the number is formatted and has the same syntax as `fn:format-integer` from the XPath F&O 3.1 specification."
|
||||
},
|
||||
"$parseInteger": {
|
||||
"args": "string, picture",
|
||||
"desc": "Parses the contents of the `string` parameter to an integer (as a JSON number) using the format specified by the `picture` string. The `picture` string parameter has the same format as `$formatInteger`."
|
||||
|
||||
}
|
||||
}
|
906
packages/node_modules/@node-red/editor-client/locales/ja/editor.json
vendored
Executable file
906
packages/node_modules/@node-red/editor-client/locales/ja/editor.json
vendored
Executable file
@@ -0,0 +1,906 @@
|
||||
{
|
||||
"common": {
|
||||
"label": {
|
||||
"name": "名前",
|
||||
"ok": "OK",
|
||||
"done": "完了",
|
||||
"cancel": "中止",
|
||||
"delete": "削除",
|
||||
"close": "閉じる",
|
||||
"load": "読み込み",
|
||||
"save": "保存",
|
||||
"import": "読み込み",
|
||||
"export": "書き出し",
|
||||
"back": "戻る",
|
||||
"next": "進む",
|
||||
"clone": "プロジェクトをクローン",
|
||||
"cont": "続ける"
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "フロー __number__",
|
||||
"editFlow": "フローを編集: __name__",
|
||||
"confirmDelete": "削除の確認",
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
"info": "詳細"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
"view": {
|
||||
"view": "表示",
|
||||
"grid": "グリッド",
|
||||
"showGrid": "グリッドを表示",
|
||||
"snapGrid": "ノードの配置を補助",
|
||||
"gridSize": "グリッドの大きさ",
|
||||
"textDir": "テキストの方向",
|
||||
"defaultDir": "標準",
|
||||
"ltr": "左から右",
|
||||
"rtl": "右から左",
|
||||
"auto": "文脈"
|
||||
},
|
||||
"sidebar": {
|
||||
"show": "サイドバーを表示"
|
||||
},
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
"displayStatus": "ノードの状態を表示",
|
||||
"displayConfig": "ノードの設定",
|
||||
"import": "読み込み",
|
||||
"export": "書き出し",
|
||||
"search": "ノードを検索",
|
||||
"searchInput": "ノードを検索",
|
||||
"clipboard": "クリップボード",
|
||||
"library": "ライブラリ",
|
||||
"examples": "サンプル",
|
||||
"subflows": "サブフロー",
|
||||
"createSubflow": "サブフローを作成",
|
||||
"selectionToSubflow": "選択部分をサブフロー化",
|
||||
"flows": "フロー",
|
||||
"add": "フローを新規追加",
|
||||
"rename": "フロー名を変更",
|
||||
"delete": "フローを削除",
|
||||
"keyboardShortcuts": "ショートカットキーの説明",
|
||||
"login": "ログイン",
|
||||
"logout": "ログアウト",
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
"projects-open": "開く",
|
||||
"projects-settings": "設定",
|
||||
"showNodeLabelDefault": "追加したノードのラベルを表示する"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "ナビゲータの表示/非表示を切替",
|
||||
"zoom-out": "縮小",
|
||||
"zoom-reset": "拡大/縮小を初期化",
|
||||
"zoom-in": "拡大"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "__name__ としてログインしました",
|
||||
"username": "ユーザ名",
|
||||
"password": "パスワード",
|
||||
"login": "ログイン",
|
||||
"loginFailed": "ログインに失敗しました",
|
||||
"notAuthorized": "権限がありません",
|
||||
"errors": {
|
||||
"settings": "設定を参照するには、ログインする必要があります",
|
||||
"deploy": "変更をデプロイするには、ログインする必要があります",
|
||||
"notAuthorized": "本アクションを行うには、ログインする必要があります"
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"warning": "<strong>警告</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "ノードの変更をデプロイしていません",
|
||||
"nodeActionDisabled": "ノードのアクションは無効になっています",
|
||||
"nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています",
|
||||
"missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください。",
|
||||
"safe-mode": "<p>セーフモードでフローを停止しました</p><p>フローを変更し、再起動するために変更をデプロイできます</p>",
|
||||
"restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります",
|
||||
"credentials_load_failed": "<p>認証情報を復号できないため、フローを停止しました</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です</p>",
|
||||
"credentials_load_failed_reset": "<p>認証情報を復号できません</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です。</p><p>次回のデプロイでフローの認証情報ファイルがリセットされます。既存フローの認証情報は削除されます。</p>",
|
||||
"missing_flow_file": "<p>プロジェクトのフローファイルが存在しません</p><p>本プロジェクトにフローファイルが登録されていません</p>",
|
||||
"missing_package_file": "<p>プロジェクトのパッケージファイルが存在しません</p><p>本プロジェクトにはpackage.jsonファイルがありません</p>",
|
||||
"project_empty": "<p>空のプロジェクトです</p><p>デフォルトのプロジェクトファイルを作成しますか?<br/>作成しない場合、エディタの外でファイルをプロジェクトへ手動で追加する必要があります</p>",
|
||||
"project_not_found": "<p>プロジェクト '__project__' が存在しません</p>",
|
||||
"git_merge_conflict": "<p>変更の自動マージが失敗しました</p><p>マージされていない競合を解決し、コミットしてください</p>"
|
||||
},
|
||||
"error": "<strong>エラー</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "サーバとの接続が切断されました: 再接続しています",
|
||||
"lostConnectionReconnect": "サーバとの接続が切断されました: __time__ 秒後に再接続します",
|
||||
"lostConnectionTry": "すぐに接続",
|
||||
"cannotAddSubflowToItself": "サブフロー自身を追加できません",
|
||||
"cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません",
|
||||
"unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p><br/>最新のNode.js LTSに更新してください。</p>",
|
||||
"failedToAppendNode": "<p>'__module__'がロードできませんでした。</p><p>__error__</p>"
|
||||
},
|
||||
"project": {
|
||||
"change-branch": "ローカルブランチ'__project__'に変更しました",
|
||||
"merge-abort": "Gitマージを中止しました",
|
||||
"loaded": "プロジェクト'__project__'をロードしました",
|
||||
"updated": "プロジェクト'__project__'を更新しました",
|
||||
"pull": "プロジェクト'__project__'を再ロードしました",
|
||||
"revert": "プロジェクト'__project__'を取り消しました",
|
||||
"merge-complete": "Gitマージが完了しました"
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "プロジェクトの依存関係の管理",
|
||||
"setup-cred": "認証情報の設定",
|
||||
"setup-project": "プロジェクトファイルの設定",
|
||||
"create-default-package": "デフォルトパッケージファイルの作成",
|
||||
"no-thanks": "不要",
|
||||
"create-default-project": "デフォルトプロジェクトファイルの作成",
|
||||
"show-merge-conflicts": "マージ競合を表示"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"nodes": "ノード",
|
||||
"node": "__count__ 個のノード",
|
||||
"node_plural": "__count__ 個のノード",
|
||||
"configNode": "__count__ 個の設定ノード",
|
||||
"configNode_plural": "__count__ 個の設定ノード",
|
||||
"flow": "__count__ 個のフロー",
|
||||
"flow_plural": "__count__ 個のフロー",
|
||||
"subflow": "__count__ 個のサブフロー",
|
||||
"subflow_plural": "__count__ 個のサブフロー",
|
||||
"selectNodes": "上のテキストを選択し、クリップボードへコピーしてください",
|
||||
"pasteNodes": "JSON形式のフローデータを貼り付けてください",
|
||||
"selectFile": "読み込むファイルを選択してください",
|
||||
"importNodes": "フローをクリップボートから読み込み",
|
||||
"exportNodes": "フローをクリップボードへ書き出し",
|
||||
"download": "ダウンロード",
|
||||
"importUnrecognised": "認識できない型が読み込まれました:",
|
||||
"importUnrecognised_plural": "認識できない型が読み込まれました:",
|
||||
"nodesExported": "クリップボードへフローを書き出しました",
|
||||
"nodesImported": "読み込みました:",
|
||||
"nodeCopied": "__count__ 個のノードをコピーしました",
|
||||
"nodeCopied_plural": "__count__ 個のノードをコピーしました",
|
||||
"invalidFlow": "不正なフロー: __message__",
|
||||
"export": {
|
||||
"selected": "選択したフロー",
|
||||
"current": "現在のタブ",
|
||||
"all": "全てのタブ",
|
||||
"compact": "インデントのないJSONフォーマット",
|
||||
"formatted": "インデント付きのJSONフォーマット",
|
||||
"copy": "書き出し"
|
||||
},
|
||||
"import": {
|
||||
"import": "読み込み先",
|
||||
"newFlow": "新規のタブ",
|
||||
"errors": {
|
||||
"notArray": "JSON形式の配列ではありません",
|
||||
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
|
||||
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
|
||||
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
|
||||
}
|
||||
},
|
||||
"copyMessagePath": "パスをコピーしました",
|
||||
"copyMessageValue": "値をコピーしました",
|
||||
"copyMessageValue_truncated": "切り捨てられた値をコピーしました"
|
||||
},
|
||||
"deploy": {
|
||||
"deploy": "デプロイ",
|
||||
"full": "全て",
|
||||
"fullDesc": "ワークスペースを全てデプロイ",
|
||||
"modifiedFlows": "変更したフロー",
|
||||
"modifiedFlowsDesc": "変更したノードを含むフローのみデプロイ",
|
||||
"modifiedNodes": "変更したノード",
|
||||
"modifiedNodesDesc": "変更したノードのみデプロイ",
|
||||
"restartFlows": "フローを再起動",
|
||||
"restartFlowsDesc": "デプロイされた現在のフローを再起動",
|
||||
"successfulDeploy": "デプロイが成功しました",
|
||||
"successfulRestart": "フローの再起動が成功しました",
|
||||
"deployFailed": "デプロイが失敗しました: __message__",
|
||||
"unusedConfigNodes": "使われていない「ノードの設定」があります。",
|
||||
"unusedConfigNodesLink": "設定を参照する",
|
||||
"errors": {
|
||||
"noResponse": "サーバの応答がありません"
|
||||
},
|
||||
"confirm": {
|
||||
"button": {
|
||||
"ignore": "無視",
|
||||
"confirm": "デプロイの確認",
|
||||
"review": "差分を確認",
|
||||
"cancel": "中止",
|
||||
"merge": "変更をマージ",
|
||||
"overwrite": "無視してデプロイ"
|
||||
},
|
||||
"undeployedChanges": "デプロイしていない変更があります。このページを抜けると変更が削除されます。",
|
||||
"improperlyConfigured": "以下のノードは、正しくプロパティが設定されていません:",
|
||||
"unknown": "ワークスペースに未知の型のノードがあります。",
|
||||
"confirm": "このままデプロイしても良いですか?",
|
||||
"doNotWarn": "この警告を再度表示しない",
|
||||
"conflict": "フローを編集している間に、他のブラウザがフローをデプロイしました。",
|
||||
"backgroundUpdate": "サーバ上のフローが更新されました",
|
||||
"conflictChecking": "変更を自動的にマージしてよいか確認してください。",
|
||||
"conflictAutoMerge": "変更の衝突がないため、自動的にマージできます。",
|
||||
"conflictManualMerge": "変更に衝突があるため、デプロイ前に解決する必要があります。",
|
||||
"plusNMore": "さらに __count__ 個"
|
||||
}
|
||||
},
|
||||
"eventLog": {
|
||||
"title": "イベントログ",
|
||||
"view": "ログを確認"
|
||||
},
|
||||
"diff": {
|
||||
"unresolvedCount": "未解決の衝突 __count__",
|
||||
"unresolvedCount_plural": "未解決の衝突 __count__",
|
||||
"globalNodes": "グローバルノード",
|
||||
"flowProperties": "フロープロパティ",
|
||||
"type": {
|
||||
"added": "追加",
|
||||
"changed": "変更",
|
||||
"unchanged": "変更なし",
|
||||
"deleted": "削除",
|
||||
"flowDeleted": "削除されたフロー",
|
||||
"flowAdded": "追加されたフロー",
|
||||
"movedTo": "__id__ へ移動",
|
||||
"movedFrom": "__id__ から移動"
|
||||
},
|
||||
"nodeCount": "__count__ 個のノード",
|
||||
"nodeCount_plural": "__count__ 個のノード",
|
||||
"local": "ローカルの変更",
|
||||
"remote": "リモートの変更",
|
||||
"reviewChanges": "変更を表示",
|
||||
"noBinaryFileShowed": "バイナリファイルの中身は表示することができません",
|
||||
"viewCommitDiff": "コミットの内容を表示",
|
||||
"compareChanges": "変更を比較",
|
||||
"saveConflict": "解決して保存",
|
||||
"conflictHeader": "<span>__unresolved__</span> 個中 <span>__resolved__</span> 個のコンフリクトを解決",
|
||||
"commonVersionError": "共通バージョンは正しいJSON形式ではありません:",
|
||||
"oldVersionError": "古いバージョンは正しいJSON形式ではありません:",
|
||||
"newVersionError": "新しいバージョンは正しいJSON形式ではありません:"
|
||||
},
|
||||
"subflow": {
|
||||
"editSubflow": "フローのテンプレートを編集: __name__",
|
||||
"edit": "フローのテンプレートを編集",
|
||||
"subflowInstances": "このサブフローのテンプレートのインスタンスが __count__ 個存在します",
|
||||
"subflowInstances_plural": "このサブフローのテンプレートのインスタンスが __count__ 個存在します",
|
||||
"editSubflowProperties": "プロパティを編集",
|
||||
"input": "入力:",
|
||||
"output": "出力:",
|
||||
"deleteSubflow": "サブフローを削除",
|
||||
"info": "詳細",
|
||||
"category": "カテゴリ",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません",
|
||||
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"configEdit": "編集",
|
||||
"configAdd": "追加",
|
||||
"configUpdate": "更新",
|
||||
"configDelete": "削除",
|
||||
"nodesUse": "__count__ 個のノードが、この設定を使用しています",
|
||||
"nodesUse_plural": "__count__ 個のノードが、この設定を使用しています",
|
||||
"addNewConfig": "新規に __type__ ノードの設定を追加",
|
||||
"editNode": "__type__ ノードを編集",
|
||||
"editConfig": "__type__ ノードの設定を編集",
|
||||
"addNewType": "新規に __type__ を追加...",
|
||||
"nodeProperties": "プロパティ",
|
||||
"label": "ラベル",
|
||||
"portLabels": "ポートラベル",
|
||||
"labelInputs": "入力",
|
||||
"labelOutputs": "出力",
|
||||
"settingIcon": "アイコン",
|
||||
"noDefaultLabel": "なし",
|
||||
"defaultLabel": "既定のラベルを使用",
|
||||
"searchIcons": "アイコンを検索",
|
||||
"useDefault": "デフォルトを使用",
|
||||
"description": "詳細",
|
||||
"show": "表示",
|
||||
"hide": "非表示",
|
||||
"errors": {
|
||||
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします"
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
"title": "キーボードショートカット",
|
||||
"keyboard": "キーボード",
|
||||
"filterActions": "動作を検索",
|
||||
"shortcut": "ショートカット",
|
||||
"scope": "範囲",
|
||||
"unassigned": "未割当",
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectAllConnected": "接続された全てのノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
"importNode": "フローの読み込み",
|
||||
"exportNode": "フローの書き出し",
|
||||
"nudgeNode": "選択したノードを移動(移動量小)",
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
"undoChange": "変更操作を戻す",
|
||||
"searchBox": "ノードを検索",
|
||||
"managePalette": "パレットの管理"
|
||||
},
|
||||
"library": {
|
||||
"openLibrary": "ライブラリを開く",
|
||||
"saveToLibrary": "ライブラリへ保存",
|
||||
"typeLibrary": "__type__ ライブラリ",
|
||||
"unnamedType": "名前なし __type__",
|
||||
"exportToLibrary": "ライブラリへフローを書き出す",
|
||||
"dialogSaveOverwrite": "__libraryName__ という __libraryType__ は既に存在しています 上書きしますか?",
|
||||
"invalidFilename": "不正なファイル名",
|
||||
"savedNodes": "フローを保存しました",
|
||||
"savedType": "__type__ を保存しました",
|
||||
"saveFailed": "保存に失敗しました: __message__",
|
||||
"filename": "ファイル名",
|
||||
"folder": "フォルダ",
|
||||
"filenamePlaceholder": "ファイル",
|
||||
"fullFilenamePlaceholder": "a/b/file",
|
||||
"folderPlaceholder": "a/b",
|
||||
"breadcrumb": "ライブラリ"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "情報がありません",
|
||||
"filter": "ノードを検索",
|
||||
"search": "ノードを検索",
|
||||
"addCategory": "新規追加...",
|
||||
"label": {
|
||||
"subflows": "サブフロー",
|
||||
"input": "入力",
|
||||
"output": "出力",
|
||||
"function": "機能",
|
||||
"social": "ソーシャル",
|
||||
"storage": "ストレージ",
|
||||
"analysis": "分析",
|
||||
"advanced": "その他"
|
||||
},
|
||||
"actions": {
|
||||
"collapse-all": "全カテゴリを折畳む",
|
||||
"expand-all": "全カテゴリを展開"
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "ノードをパレットへ追加しました:",
|
||||
"nodeAdded_plural": "ノードをパレットへ追加しました",
|
||||
"nodeRemoved": "ノードをパレットから削除しました:",
|
||||
"nodeRemoved_plural": "ノードをパレットから削除しました:",
|
||||
"nodeEnabled": "ノードを有効化しました:",
|
||||
"nodeEnabled_plural": "ノードを有効化しました:",
|
||||
"nodeDisabled": "ノードを無効化しました:",
|
||||
"nodeDisabled_plural": "ノードを無効化しました:",
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
|
||||
},
|
||||
"editor": {
|
||||
"title": "パレットの管理",
|
||||
"palette": "パレット",
|
||||
"times": {
|
||||
"seconds": "秒前",
|
||||
"minutes": "分前",
|
||||
"minutesV": "__count__ 分前",
|
||||
"hoursV": "__count__ 時間前",
|
||||
"hoursV_plural": "__count__ 時間前",
|
||||
"daysV": "__count__ 日前",
|
||||
"daysV_plural": "__count__ 日前",
|
||||
"weeksV": "__count__ 週間前",
|
||||
"weeksV_plural": "__count__ 週間前",
|
||||
"monthsV": "__count__ ヵ月前",
|
||||
"monthsV_plural": "__count__ ヵ月前",
|
||||
"yearsV": "__count__ 年前",
|
||||
"yearsV_plural": "__count__ 年前",
|
||||
"yearMonthsV": "__y__ 年 __count__ ヵ月前",
|
||||
"yearMonthsV_plural": "__y__ 年 __count__ ヵ月前",
|
||||
"yearsMonthsV": "__y__ 年 __count__ ヵ月前",
|
||||
"yearsMonthsV_plural": "__y__ 年 __count__ ヵ月前"
|
||||
},
|
||||
"nodeCount": "__label__ 個のノード",
|
||||
"nodeCount_plural": "__label__ 個のノード",
|
||||
"moduleCount": "__count__ 個のモジュール",
|
||||
"moduleCount_plural": "__count__ 個のモジュール",
|
||||
"inuse": "使用中",
|
||||
"enableall": "全て有効化",
|
||||
"disableall": "全て無効化",
|
||||
"enable": "有効化",
|
||||
"disable": "無効化",
|
||||
"remove": "削除",
|
||||
"update": "__version__ へ更新",
|
||||
"updated": "更新済",
|
||||
"install": "ノードを追加",
|
||||
"installed": "追加しました",
|
||||
"conflict": "競合",
|
||||
"conflictTip": "<p>インストール済みのノードの種別と競合しているため<br/>ノードをインストールできません</p><p>競合: <code>__module__</code></p>",
|
||||
"loading": "カタログを読み込み中",
|
||||
"tab-nodes": "現在のノード",
|
||||
"tab-install": "ノードを追加",
|
||||
"sort": "並べ替え:",
|
||||
"sortAZ": "辞書順",
|
||||
"sortRecent": "日付順",
|
||||
"more": "+ さらに __count__ 個",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
|
||||
"installFailed": "<p.追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"disableFailed": "<p>無効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>"
|
||||
},
|
||||
"confirm": {
|
||||
"install": {
|
||||
"body": "<p>__module__ をインストールします。</p><p>ノードを追加する前に、ドキュメントを確認してください。ノードによっては、モジュールの依存関係を自動的に解決できない場合や、Node-REDの再起動が必要となる場合があります。</p>",
|
||||
"title": "ノードを追加"
|
||||
},
|
||||
"remove": {
|
||||
"body": "<p>__module__ を削除します。</p><p>Node-REDからノードを削除します。ノードはNode-REDが再起動されるまで、リソースを使い続ける可能性があります。</p>",
|
||||
"title": "ノードを削除"
|
||||
},
|
||||
"update": {
|
||||
"body": "<p>__module__ を更新します。</p><p>更新を完了するには手動でNode-REDを再起動する必要があります。</p>",
|
||||
"title": "ノードの更新"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body": "ノードの更新があります。「パレットの管理」の画面では更新されません。<br/><br/>ドキュメントを参照し、ノードの更新手順を確認してください。"
|
||||
},
|
||||
"button": {
|
||||
"review": "ノードの情報を参照",
|
||||
"install": "追加",
|
||||
"remove": "削除",
|
||||
"update": "更新"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"info": {
|
||||
"name": "ノードの情報を表示",
|
||||
"tabName": "名前",
|
||||
"label": "情報",
|
||||
"node": "ノード",
|
||||
"type": "型",
|
||||
"module": "モジュール",
|
||||
"id": "ID",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
"subflow": "サブフロー",
|
||||
"instances": "インスタンス",
|
||||
"properties": "プロパティ",
|
||||
"info": "情報",
|
||||
"desc": "詳細",
|
||||
"blank": "ブランク",
|
||||
"null": "ヌル",
|
||||
"showMore": "さらに表示",
|
||||
"showLess": "表示を省略",
|
||||
"flow": "フロー",
|
||||
"selection": "選択",
|
||||
"nodes": "__count__ 個のノード",
|
||||
"flowDesc": "フローの詳細",
|
||||
"subflowDesc": "サブフローの詳細",
|
||||
"nodeHelp": "ノードのヘルプ",
|
||||
"none": "なし",
|
||||
"arrayItems": "__count__ 要素",
|
||||
"showTips": "設定からヒントを表示できます"
|
||||
},
|
||||
"config": {
|
||||
"name": "ノードの設定を表示",
|
||||
"label": "ノードの設定",
|
||||
"global": "全てのフロー上",
|
||||
"none": "なし",
|
||||
"subflows": "サブフロー",
|
||||
"flows": "フロー",
|
||||
"filterUnused": "未使用",
|
||||
"filterAll": "全て",
|
||||
"filtered": "__count__ 個が無効"
|
||||
},
|
||||
"context": {
|
||||
"name": "コンテキストデータ",
|
||||
"label": "コンテキストデータ",
|
||||
"none": "選択されていません",
|
||||
"refresh": "読み込みのため更新してください",
|
||||
"empty": "データが存在しません",
|
||||
"node": "Node",
|
||||
"flow": "Flow",
|
||||
"global": "Global",
|
||||
"deleteConfirm": "データを削除しても良いですか?"
|
||||
},
|
||||
"palette": {
|
||||
"name": "パレットの管理",
|
||||
"label": "パレット"
|
||||
},
|
||||
"project": {
|
||||
"label": "プロジェクト",
|
||||
"name": "プロジェクト",
|
||||
"description": "詳細",
|
||||
"dependencies": "依存関係",
|
||||
"settings": "設定",
|
||||
"noSummaryAvailable": "サマリが存在しません",
|
||||
"editDescription": "プロジェクトの詳細を編集",
|
||||
"editDependencies": "プロジェクトの依存関係を編集",
|
||||
"editReadme": "README.mdを編集",
|
||||
"showProjectSettings": "プロジェクト設定を表示",
|
||||
"projectSettings": {
|
||||
"title": "プロジェクト設定",
|
||||
"edit": "編集",
|
||||
"none": "なし",
|
||||
"install": "インストール",
|
||||
"removeFromProject": "プロジェクトから削除",
|
||||
"addToProject": "プロジェクトへ追加",
|
||||
"files": "ファイル",
|
||||
"flow": "フロー",
|
||||
"credentials": "認証情報",
|
||||
"invalidEncryptionKey": "不正な暗号化キー",
|
||||
"encryptionEnabled": "暗号化が有効になっています",
|
||||
"encryptionDisabled": "暗号化が無効になっています",
|
||||
"setTheEncryptionKey": "暗号化キーを設定:",
|
||||
"resetTheEncryptionKey": "暗号化キーを初期化:",
|
||||
"changeTheEncryptionKey": "暗号化キーを変更:",
|
||||
"currentKey": "現在のキー",
|
||||
"newKey": "新規のキー",
|
||||
"credentialsAlert": "既存の認証情報は全て削除されます",
|
||||
"versionControl": "バージョン管理",
|
||||
"branches": "ブランチ",
|
||||
"noBranches": "ブランチなし",
|
||||
"deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。",
|
||||
"unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?",
|
||||
"deleteUnmergedBranch": "マージされていないブランチを削除",
|
||||
"gitRemotes": "Gitリモート",
|
||||
"addRemote": "リモートを追加",
|
||||
"addRemote2": "リモートを追加",
|
||||
"remoteName": "リモート名",
|
||||
"nameRule": "A-Z 0-9 _ - のみを含む",
|
||||
"url": "URL",
|
||||
"urlRule": "https://、ssh:// または file://",
|
||||
"urlRule2": "URLにユーザ名、パスワードを含んではいけません",
|
||||
"noRemotes": "リモートなし",
|
||||
"deleteRemoteConfrim": "本当にリモート'__name__'を削除しますか?",
|
||||
"deleteRemote": "リモートを削除"
|
||||
},
|
||||
"userSettings": {
|
||||
"committerDetail": "コミッター詳細",
|
||||
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
|
||||
"userName": "ユーザ名",
|
||||
"email": "メールアドレス",
|
||||
"sshKeys": "SSH キー",
|
||||
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
|
||||
"add": "キーを追加",
|
||||
"addSshKey": "SSHキーを追加",
|
||||
"addSshKeyTip": "新しい公開鍵/秘密鍵ペアを生成します",
|
||||
"name": "名前",
|
||||
"nameRule": "A-Z 0-9 _ - のみを含む",
|
||||
"passphrase": "パスフレーズ",
|
||||
"passphraseShort": "パスフレーズが短すぎます",
|
||||
"optional": "任意",
|
||||
"cancel": "中止",
|
||||
"generate": "キーを生成",
|
||||
"noSshKeys": "SSHキーがありません",
|
||||
"copyPublicKey": "公開鍵をクリップボードにコピー",
|
||||
"delete": "キーを削除",
|
||||
"gitConfig": "Git設定",
|
||||
"deleteConfirm": "SSHキー __name__ を削除してもよいですか? 削除したSSHキーを元に戻すことはできません。"
|
||||
},
|
||||
"versionControl": {
|
||||
"unstagedChanges": "ステージングされていない変更",
|
||||
"stagedChanges": "ステージングされた変更",
|
||||
"unstageChange": "ステージングした変更の取り消し",
|
||||
"stageChange": "変更をステージング",
|
||||
"unstageAllChange": "ステージングした全ての変更の取り消し",
|
||||
"stageAllChange": "全ての変更をステージング",
|
||||
"commitChanges": "変更をコミット",
|
||||
"resolveConflicts": "コンフリクトの解決",
|
||||
"head": "最新",
|
||||
"staged": "ステージング",
|
||||
"unstaged": "未ステージング",
|
||||
"local": "ローカル",
|
||||
"remote": "リモート",
|
||||
"revert": "'__file__'への変更を本当に戻しますか?この操作は元に戻せません。",
|
||||
"revertChanges": "変更を戻す",
|
||||
"localChanges": "ローカルの変更",
|
||||
"none": "なし",
|
||||
"conflictResolve": "全てのコンフリクトが解消されました。マージを完了するため、変更をコミットしてください。",
|
||||
"localFiles": "ローカルファイル",
|
||||
"all": "全て",
|
||||
"unmergedChanges": "マージされていない変更",
|
||||
"abortMerge": "マージ中止",
|
||||
"commit": "コミット",
|
||||
"changeToCommit": "コミット対象とする変更",
|
||||
"commitPlaceholder": "コミットメッセージを入力してください。",
|
||||
"cancelCapital": "キャンセル",
|
||||
"commitCapital": "コミット",
|
||||
"commitHistory": "コミット履歴",
|
||||
"branch": "ブランチ:",
|
||||
"moreCommits": "個のコミット",
|
||||
"changeLocalBranch": "ローカルブランチの変更",
|
||||
"createBranchPlaceholder": "ブランチの検索または作成",
|
||||
"upstream": "アップストリーム",
|
||||
"localOverwrite": "ブランチの変更によって上書きされたローカルの変更があります。これらの変更を先にコミットするか、あるいは元に戻さなければなりません。",
|
||||
"manageRemoteBranch": "リモートブランチの管理",
|
||||
"unableToAccess": "リモートのリポジトリにアクセスできません。",
|
||||
"retry": "リトライ",
|
||||
"setUpstreamBranch": "アップストリームとして設定する",
|
||||
"createRemoteBranchPlaceholder": "リモートブランチの検索または作成",
|
||||
"trackedUpstreamBranch": "作成されたブランチは、トラッキングされたアップストリームブランチとなります。",
|
||||
"selectUpstreamBranch": "ブランチが作成されました。トラッキングするアップストリームブランチを選択してください。",
|
||||
"pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。",
|
||||
"push": "プッシュ",
|
||||
"pull": "プル",
|
||||
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更を上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
|
||||
"showUnstagedChanges": "ステージングされていない変更を表示",
|
||||
"connectionFailed": "リモートリポジトリに接続できません: ",
|
||||
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
|
||||
"pullChanges": "プル変更",
|
||||
"history": "履歴",
|
||||
"projectHistory": "プロジェクト履歴",
|
||||
"daysAgo": "__count__ 日前",
|
||||
"daysAgo_plural": "__count__ 日前",
|
||||
"hoursAgo": "__count__ 時間前",
|
||||
"hoursAgo_plural": "__count__ 時間前",
|
||||
"minsAgo": "__count__ 分前",
|
||||
"minsAgo_plural": "__count__ 分前",
|
||||
"secondsAgo": "数秒前",
|
||||
"notTracking": "ローカルブランチは現在リモートブランチをトラッキングしていません。",
|
||||
"statusUnmergedChanged": "リポジトリ内にマージされていない変更があります。コンフリクトを解決してコミットしてください。",
|
||||
"repositoryUpToDate": "リポジトリは最新です。",
|
||||
"commitsAhead": "あなたのリポジトリはリモートより__count__コミット進んでいます。現在のコミットをプッシュできます。",
|
||||
"commitsAhead_plural": "あなたのリポジトリはリモートより__count__コミット進んでいます。現在のコミットをプッシュできます。",
|
||||
"commitsBehind": "あなたのリポジトリはリモートより__count__コミット遅れています。現在のコミットをプルできます。",
|
||||
"commitsBehind_plural": "あなたのリポジトリはリモートより__count__コミット遅れています。現在のコミットをプルできます。",
|
||||
"commitsAheadAndBehind1": "あなたのリポジトリはリモートより__count__コミット遅れており、かつ",
|
||||
"commitsAheadAndBehind1_plural": "あなたのリポジトリはリモートより__count__コミット遅れており、かつ",
|
||||
"commitsAheadAndBehind2": "__count__コミット進んでいます。 ",
|
||||
"commitsAheadAndBehind2_plural": "__count__コミット進んでいます。 ",
|
||||
"commitsAheadAndBehind3": "プッシュする前にリモートのコミットをプルしてください。",
|
||||
"commitsAheadAndBehind3_plural": "プッシュする前にリモートのコミットをプルしてください。",
|
||||
"refreshCommitHistory": "コミット履歴を更新",
|
||||
"refreshChanges": "変更を更新"
|
||||
}
|
||||
}
|
||||
},
|
||||
"typedInput": {
|
||||
"type": {
|
||||
"str": "文字列",
|
||||
"num": "数値",
|
||||
"re": "正規表現",
|
||||
"bool": "真偽",
|
||||
"json": "JSON",
|
||||
"bin": "バッファ",
|
||||
"date": "日時",
|
||||
"jsonata": "JSONata式",
|
||||
"env": "環境変数"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
"add": "追加"
|
||||
},
|
||||
"search": {
|
||||
"empty": "一致したものが見つかりませんでした",
|
||||
"addNode": "ノードを追加..."
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "関数",
|
||||
"functionReference": "関数リファレンス",
|
||||
"insert": "挿入",
|
||||
"title": "JSONata式エディタ",
|
||||
"test": "テスト",
|
||||
"data": "メッセージ例",
|
||||
"result": "結果",
|
||||
"format": "整形",
|
||||
"compatMode": "互換モードが有効になっています",
|
||||
"compatModeDesc": "<h3>JSONata互換モード</h3><p> 入力された式では <code>msg</code> を参照しているため、互換モードで評価します。このモードは将来廃止予定のため、式で <code>msg</code> を使わないよう修正してください。</p><p> JSONataをNode-REDで最初にサポートした際には、 <code>msg</code> オブジェクトの参照が必要でした。例えば <code>msg.payload</code> がペイロードを参照するために使われていました。</p><p> 直接メッセージに対して式を評価するようになったため、この形式は使えなくなります。ペイロードを参照するには、単に <code>payload</code> にしてください。</p>",
|
||||
"noMatch": "一致した結果なし",
|
||||
"errors": {
|
||||
"invalid-expr": "不正なJSONata式:\n __message__",
|
||||
"invalid-msg": "不正なJSONメッセージ例:\n __message__",
|
||||
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト機能をテストできません",
|
||||
"eval": "表現評価エラー:\n __message__"
|
||||
}
|
||||
},
|
||||
"jsEditor": {
|
||||
"title": "JavaScriptエディタ"
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "JSONエディタ",
|
||||
"format": "JSONフォーマット"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "マークダウンエディタ",
|
||||
"format": "マークダウン形式で記述",
|
||||
"heading1": "見出しレベル1",
|
||||
"heading2": "見出しレベル2",
|
||||
"heading3": "見出しレベル3",
|
||||
"bold": "太字",
|
||||
"italic": "斜体",
|
||||
"code": "コード",
|
||||
"ordered-list": "箇条書き(番号付き)",
|
||||
"unordered-list": "箇条書き",
|
||||
"quote": "引用",
|
||||
"link": "リンク",
|
||||
"horizontal-rule": "区切り線",
|
||||
"toggle-preview": "プレビュー表示切替え"
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "バッファエディタ",
|
||||
"modeString": "UTF-8文字列として処理",
|
||||
"modeArray": "JSON配列として処理",
|
||||
"modeDesc": "<h3>バッファエディタ</h3><p>バッファ型は、バイト値から成るJSON配列として格納されます。このエディタは、入力値をJSON配列として構文解析します。もし不正なJSON配列の場合、UTF-8文字列として扱い、各文字コード番号から成る配列へ変換します。</p><p>例えば、 <code>Hello World</code> という値を、以下のJSON配列へ変換します。<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||
},
|
||||
"projects": {
|
||||
"config-git": "Gitクライアントの設定",
|
||||
"welcome": {
|
||||
"hello": "こんにちは! Node-REDで「プロジェクト」機能が利用できるようになりました。",
|
||||
"desc0": "フローファイルの管理方法が刷新され、バージョン管理も可能です。",
|
||||
"desc1": "まず最初にプロジェクトを作成するか、既存のGitリポジトリからプロジェクトをクローンしてください。",
|
||||
"desc2": "とりあえずこの処理をスキップしてもかまいません。「プロジェクト」メニューから、いつでもプロジェクトの作成を開始できます。",
|
||||
"create": "プロジェクトの作成",
|
||||
"clone": "プロジェクトのクローン",
|
||||
"not-right-now": "後にする"
|
||||
},
|
||||
"git-config": {
|
||||
"setup": "バージョン管理クライアントの設定",
|
||||
"desc0": "Node-REDはオープンソースツールのGitを使ってバージョン管理を行います。Gitによりプロジェクトファイルに対する変化を記録し、外部リポジトリに保存することができます。",
|
||||
"desc1": "変更をコミットする際、変更を行った人物の情報としてユーザ名とEmailアドレスをGitが記憶します。ユーザ名は本名でなくても構いません。好きな名前を使ってください。",
|
||||
"desc2": "Gitクライアントの現在の設定は以下の通りです。",
|
||||
"desc3": "設定ダイアログの「Git設定」タブから別途変更することもできます。",
|
||||
"username": "ユーザ名",
|
||||
"email": "Email"
|
||||
},
|
||||
"project-details": {
|
||||
"create": "プロジェクトの作成",
|
||||
"desc0": "プロジェクトはGitリポジトリとして管理します。Gitリポジトリを使ってフローの共有やコラボレーションが簡単にできます。",
|
||||
"desc1": "複数のプロジェクトを作成し、エディタから即座に変更できます。",
|
||||
"desc2": "まず、プロジェクト名と説明(任意)を指定してください。",
|
||||
"already-exists": "既に存在するプロジェクトです",
|
||||
"must-contain": "A-Z 0-9 _ - のみ指定可能",
|
||||
"project-name": "プロジェクト名",
|
||||
"desc": "説明",
|
||||
"opt": "任意"
|
||||
},
|
||||
"clone-project": {
|
||||
"clone": "プロジェクトをクローン",
|
||||
"desc0": "プロジェクトを含んだGitリポジトリを作成済みの場合、クローンを作成することができます。",
|
||||
"already-exists": "既に存在するプロジェクトです",
|
||||
"must-contain": "A-Z 0-9 _ - のみ指定可能",
|
||||
"project-name": "プロジェクト名",
|
||||
"no-info-in-url": "URLにユーザ名/パスワードを含めないようにしてください",
|
||||
"git-url": "GitリポジトリのURL",
|
||||
"protocols": "https://, ssh:// もしくは file://",
|
||||
"auth-failed": "認証に失敗しました",
|
||||
"username": "ユーザ名",
|
||||
"passwd": "パスワード",
|
||||
"ssh-key": "SSHキー",
|
||||
"passphrase": "パスフレーズ",
|
||||
"ssh-key-desc": "SSHでリポジトリをクローンする前にSSHキーを追加してください。",
|
||||
"ssh-key-add": "SSHキーの追加",
|
||||
"credential-key": "認証情報の暗号化キー",
|
||||
"cant-get-ssh-key": "エラー! 選択したSSHキーのパスを取得できません。",
|
||||
"already-exists2": "既に存在します",
|
||||
"git-error": "Gitエラー",
|
||||
"connection-failed": "接続に失敗しました",
|
||||
"not-git-repo": "Gitリポジトリではありません",
|
||||
"repo-not-found": "リポジトリが見つかりません"
|
||||
},
|
||||
"default-files": {
|
||||
"create": "プロジェクト関連ファイルの作成",
|
||||
"desc0": "プロジェクトはフローファイル、README、package.jsonを含みます。",
|
||||
"desc1": "その他、Gitリポジトリで管理したいファイルを含めても構いません。",
|
||||
"desc2": "既存のフローと認証情報ファイルをプロジェクトにコピーします。",
|
||||
"flow-file": "フローファイル",
|
||||
"credentials-file": "認証情報ファイル"
|
||||
},
|
||||
"encryption-config": {
|
||||
"setup": "認証情報ファイルの暗号化設定",
|
||||
"desc0": "フロー認証情報ファイルを暗号化して内容の安全性を担保できます。",
|
||||
"desc1": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。",
|
||||
"desc2": "認証情報ファイルは暗号化されていません。",
|
||||
"desc3": "パスワードやアクセストークンといった認証情報を他人が参照できます。",
|
||||
"desc4": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。",
|
||||
"desc5": "フロー認証情報ファイルはsettingsファイルのcredentialSecretプロパティで暗号化されています。",
|
||||
"desc6": "フロー認証情報ファイルはシステムが生成したキーによって暗号化されています。このプロジェクト用に新しい秘密キーを指定してください。",
|
||||
"desc7": "キーはプロジェクトファイルとは別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。",
|
||||
"credentials": "認証情報",
|
||||
"enable": "暗号化を有効にする",
|
||||
"disable": "暗号化を無効にする",
|
||||
"disabled": "無効",
|
||||
"copy": "既存のキーをコピー",
|
||||
"use-custom": "カスタムキーを使用",
|
||||
"desc8": "認証情報ファイルが暗号化されないため、簡単に読み出すことができます。",
|
||||
"create-project-files": "プロジェクト関連ファイル作成",
|
||||
"create-project": "プロジェクト作成",
|
||||
"already-exists": "既に存在",
|
||||
"git-error": "Gitエラー",
|
||||
"git-auth-error": "Git認証エラー"
|
||||
},
|
||||
"create-success": {
|
||||
"success": "最初のプロジェクトの作成が成功しました!",
|
||||
"desc0": "以降は、これまでと同様にNode-REDを利用できます。",
|
||||
"desc1": "サイドバーの「情報」タブに現在選択されたプロジェクトを表示します。プロジェクト名の隣のボタンでプロジェクト設定画面を呼び出すことができます。",
|
||||
"desc2": "サイドバーの「履歴」タブで変更が加えられたプロジェクト内のファイルを確認しコミットできます。このサイドバーでは、全てのコミット履歴を確認し、変更を外部リポジトリにプッシュすることが可能です。"
|
||||
},
|
||||
"create": {
|
||||
"projects": "プロジェクト",
|
||||
"already-exists": "プロジェクトは既に存在します",
|
||||
"must-contain": "A-Z 0-9 _ - のみ指定可能",
|
||||
"no-info-in-url": "URLにユーザ名/パスワードを含めないようにしてください",
|
||||
"open": "プロジェクトを開く",
|
||||
"create": "プロジェクトを作成",
|
||||
"clone": "プロジェクトをクローン",
|
||||
"project-name": "プロジェクト名",
|
||||
"desc": "説明",
|
||||
"opt": "任意",
|
||||
"flow-file": "フローファイル",
|
||||
"credentials": "認証情報",
|
||||
"enable-encryption": "暗号化を有効にする",
|
||||
"disable-encryption": "暗号化を無効にする",
|
||||
"encryption-key": "暗号化キー",
|
||||
"desc0": "認証情報をセキュアにするためのフレーズ",
|
||||
"desc1": "認証情報ファイルが暗号化されないため、簡単に読み出すことができます",
|
||||
"git-url": "GitリポジトリのURL",
|
||||
"protocols": "https://, ssh:// もしくは file://",
|
||||
"auth-failed": "認証に失敗しました",
|
||||
"username": "ユーザ名",
|
||||
"password": "パスワード",
|
||||
"ssh-key": "SSHキー",
|
||||
"passphrase": "パスフレーズ",
|
||||
"desc2": "SSHでリポジトリをクローンする前にSSHキーを追加してください。",
|
||||
"add-ssh-key": "SSHキーの追加",
|
||||
"credentials-encryption-key": "認証情報の暗号化キー",
|
||||
"already-exists-2": "既に存在します",
|
||||
"git-error": "Gitエラー",
|
||||
"con-failed": "接続に失敗しました",
|
||||
"not-git": "Gitリポジトリではありません",
|
||||
"no-resource": "リポジトリが見つかりません",
|
||||
"cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。",
|
||||
"unexpected_error": "予期しないエラー"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "プロジェクトを削除しても良いですか?"
|
||||
},
|
||||
"create-project-list": {
|
||||
"search": "プロジェクトを検索",
|
||||
"current": "有効"
|
||||
},
|
||||
"require-clean": {
|
||||
"confirm": "<p>デプロイされていない変更は失われます。</p><p>続けますか?</p>"
|
||||
},
|
||||
"send-req": {
|
||||
"auth-req": "リポジトリ対する認証が必要です",
|
||||
"username": "ユーザ名",
|
||||
"password": "パスワード",
|
||||
"passphrase": "パスフレーズ",
|
||||
"retry": "リトライ",
|
||||
"update-failed": "認証の更新に失敗しました",
|
||||
"unhandled": "エラー応答が処理されませんでした"
|
||||
},
|
||||
"create-branch-list": {
|
||||
"invalid": "不正なブランチ",
|
||||
"create": "ブランチの作成",
|
||||
"current": "有効"
|
||||
},
|
||||
"create-default-file-set": {
|
||||
"no-active": "有効なプロジェクトが無い場合、デフォルトのファイル群を作成できません。",
|
||||
"no-empty": "デフォルトのファイル群を空でないプロジェクトに作成することはできません。",
|
||||
"git-error": "Gitエラー"
|
||||
},
|
||||
"errors": {
|
||||
"no-username-email": "Gitクライアントのユーザ名/emailが設定されていません。",
|
||||
"unexpected": "予期しないエラーが発生しました",
|
||||
"code": "コード"
|
||||
}
|
||||
},
|
||||
"editor-tab": {
|
||||
"properties": "プロパティ",
|
||||
"description": "説明",
|
||||
"appearance": "外観"
|
||||
}
|
||||
}
|
@@ -214,5 +214,9 @@
|
||||
"$toMillis": {
|
||||
"args": "timestamp",
|
||||
"desc": "ISO 8601形式の文字列 `timestamp` を、Unixエポック(1 January, 1970 UTC)からの経過ミリ秒を表す数値へ変換します。 文字列が正しい形式でない場合、エラーとなります。"
|
||||
},
|
||||
"$env": {
|
||||
"args": "arg",
|
||||
"desc": "環境変数の値を返します。\n\n本関数はNode-REDの定義関数です。"
|
||||
}
|
||||
}
|
@@ -22,8 +22,7 @@
|
||||
"status": "状态",
|
||||
"enabled": "有效",
|
||||
"disabled": "无效",
|
||||
"info": "详细描述",
|
||||
"tip": "详细描述支持Markdown轻量级标记语言,并将出现在信息标签中。"
|
||||
"info": "详细描述"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -86,7 +85,7 @@
|
||||
"warning": "<strong>警告</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "节点中存在未部署的更改",
|
||||
"nodeActionDisabled": "节点动作在子流程中被禁用",
|
||||
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
|
||||
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
|
||||
"restartRequired": "Node-RED必须重新启动,以启用升级的模块"
|
||||
},
|
||||
@@ -191,7 +190,6 @@
|
||||
"output": "输出:",
|
||||
"deleteSubflow": "删除子流程",
|
||||
"info": "详细描述",
|
||||
"format": "标记格式",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
|
||||
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
|
18
packages/node_modules/@node-red/editor-client/package.json
vendored
Normal file
18
packages/node_modules/@node-red/editor-client/package.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "0.20.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js"
|
||||
}
|
50
packages/node_modules/@node-red/editor-client/src/ace/README.md
vendored
Normal file
50
packages/node_modules/@node-red/editor-client/src/ace/README.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
How to build the custom ACE modes for Node-RED
|
||||
----------------------------------------------
|
||||
|
||||
Node-RED includes custom JSONata and JavaScript modes.
|
||||
|
||||
|
||||
## JSONata
|
||||
|
||||
The `ace/mode/jsonata` mode is maintained under `editor-client/src/vendor/jsonata`.
|
||||
Those files are edited in place and copied into the build by Grunt.
|
||||
|
||||
## JavaScript
|
||||
|
||||
The `ace/mode/nrjavascript` mode is used exclusively by the Function node. It
|
||||
inherits almost entirely from the normal JavaScript mode. The one key difference
|
||||
is that it wraps the code with a Function before parsing. This is required to
|
||||
avoid some false-flagged errors.
|
||||
|
||||
The source of the mode is under `editor-client/src/ace/mode`. If those files are
|
||||
modified in anyway, they *must* be manually built to generate the files under
|
||||
`editor-client/src/ace/bin` and checked in. Those files are the ones the Grunt
|
||||
built copies out in the Node-RED build.
|
||||
|
||||
### Building the mode files
|
||||
|
||||
|
||||
#### Setup build environment
|
||||
|
||||
cd /tmp/
|
||||
git clone https://github.com/ajaxorg/ace.git
|
||||
cd ace
|
||||
npm install
|
||||
|
||||
#### Copy mode src files into build environment
|
||||
|
||||
cd <node-red-source-directory
|
||||
cp packages/node_modules/@node-red/editor-client/src/ace/mode/* \
|
||||
/tmp/ace/lib/ace/mode/
|
||||
|
||||
#### Run the build
|
||||
|
||||
cd /tmp/ace
|
||||
node ./Makefile.dryice.js -m -nc
|
||||
|
||||
#### Copy the built versions back
|
||||
|
||||
cp build/src-min-noconflict/*-nrjavascript.js \
|
||||
<node-red-source-directory>/packages/node_modules/@node-red/editor-client/src/ace/bin/
|
||||
cp build/src-min-noconflict/snippets/nrjavascript.js \
|
||||
<node-red-source-directory>/packages/node_modules/@node-red/editor-client/src/ace/bin/snippets/
|
9
packages/node_modules/@node-red/editor-client/src/ace/bin/mode-nrjavascript.js
vendored
Normal file
9
packages/node_modules/@node-red/editor-client/src/ace/bin/mode-nrjavascript.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9
packages/node_modules/@node-red/editor-client/src/ace/bin/snippets/nrjavascript.js
vendored
Normal file
9
packages/node_modules/@node-red/editor-client/src/ace/bin/snippets/nrjavascript.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="nrjavascript"});
|
||||
(function() {
|
||||
ace.require(["ace/snippets/nrjavascript"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
1
packages/node_modules/@node-red/editor-client/src/ace/bin/worker-nrjavascript.js
vendored
Normal file
1
packages/node_modules/@node-red/editor-client/src/ace/bin/worker-nrjavascript.js
vendored
Normal file
File diff suppressed because one or more lines are too long
49
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript.js
vendored
Normal file
49
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var JavaScriptMode = require("./javascript").Mode;
|
||||
var WorkerClient = require("../worker/worker_client").WorkerClient;
|
||||
|
||||
var Mode = function() {
|
||||
// Inherit everything from the standard JavaScript mode
|
||||
JavaScriptMode.call(this);
|
||||
};
|
||||
oop.inherits(Mode, JavaScriptMode);
|
||||
|
||||
(function() {
|
||||
// Insert our custom worker
|
||||
this.createWorker = function(session) {
|
||||
var worker = new WorkerClient(["ace"], "ace/mode/nrjavascript_worker", "NRJavaScriptWorker");
|
||||
worker.attachToDocument(session.getDocument());
|
||||
|
||||
worker.on("annotate", function(results) {
|
||||
session.setAnnotations(results.data);
|
||||
});
|
||||
|
||||
worker.on("terminate", function() {
|
||||
session.clearAnnotations();
|
||||
});
|
||||
|
||||
return worker;
|
||||
};
|
||||
|
||||
this.$id = "ace/mode/nrjavascript";
|
||||
}).call(Mode.prototype);
|
||||
exports.Mode = Mode;
|
||||
});
|
189
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript_worker.js
vendored
Normal file
189
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript_worker.js
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var Mirror = require("../worker/mirror").Mirror;
|
||||
var lint = require("./javascript/jshint").JSHINT;
|
||||
|
||||
function startRegex(arr) {
|
||||
return RegExp("^(" + arr.join("|") + ")");
|
||||
}
|
||||
|
||||
var disabledWarningsRe = startRegex([
|
||||
"Bad for in variable '(.+)'.",
|
||||
'Missing "use strict"'
|
||||
]);
|
||||
var errorsRe = startRegex([
|
||||
"Unexpected",
|
||||
"Expected ",
|
||||
"Confusing (plus|minus)",
|
||||
"\\{a\\} unterminated regular expression",
|
||||
"Unclosed ",
|
||||
"Unmatched ",
|
||||
"Unbegun comment",
|
||||
"Bad invocation",
|
||||
"Missing space after",
|
||||
"Missing operator at"
|
||||
]);
|
||||
var infoRe = startRegex([
|
||||
"Expected an assignment",
|
||||
"Bad escapement of EOL",
|
||||
"Unexpected comma",
|
||||
"Unexpected space",
|
||||
"Missing radix parameter.",
|
||||
"A leading decimal point can",
|
||||
"\\['{a}'\\] is better written in dot notation.",
|
||||
"'{a}' used out of scope"
|
||||
]);
|
||||
|
||||
var NRJavaScriptWorker = exports.NRJavaScriptWorker = function(sender) {
|
||||
Mirror.call(this, sender);
|
||||
this.setTimeout(500);
|
||||
this.setOptions();
|
||||
};
|
||||
|
||||
oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
this.setOptions = function(options) {
|
||||
this.options = options || {
|
||||
// undef: true,
|
||||
// unused: true,
|
||||
esnext: true,
|
||||
moz: true,
|
||||
devel: true,
|
||||
browser: true,
|
||||
node: true,
|
||||
laxcomma: true,
|
||||
laxbreak: true,
|
||||
lastsemic: true,
|
||||
onevar: false,
|
||||
passfail: false,
|
||||
maxerr: 100,
|
||||
expr: true,
|
||||
multistr: true,
|
||||
globalstrict: true
|
||||
};
|
||||
this.doc.getValue() && this.deferredUpdate.schedule(100);
|
||||
};
|
||||
|
||||
this.changeOptions = function(newOptions) {
|
||||
oop.mixin(this.options, newOptions);
|
||||
this.doc.getValue() && this.deferredUpdate.schedule(100);
|
||||
};
|
||||
|
||||
this.isValidJS = function(str) {
|
||||
try {
|
||||
// evaluated code can only create variables in this function
|
||||
eval("throw 0;" + str);
|
||||
} catch(e) {
|
||||
if (e === 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.onUpdate = function() {
|
||||
var value = this.doc.getValue();
|
||||
value = value.replace(/^#!.*\n/, "\n");
|
||||
if (!value)
|
||||
return this.sender.emit("annotate", []);
|
||||
|
||||
// [Node-RED] wrap the code in a function
|
||||
value = "async function __nodered__(msg) {\n"+value+"\n}";
|
||||
|
||||
var errors = [];
|
||||
// jshint reports many false errors
|
||||
// report them as error only if code is actually invalid
|
||||
var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
|
||||
|
||||
// var start = new Date();
|
||||
lint(value, this.options, this.options.globals);
|
||||
var results = lint.errors;
|
||||
|
||||
var errorAdded = false;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var error = results[i];
|
||||
if (!error)
|
||||
continue;
|
||||
var raw = error.raw;
|
||||
var type = "warning";
|
||||
|
||||
if (raw == "Missing semicolon.") {
|
||||
var str = error.evidence.substr(error.character);
|
||||
str = str.charAt(str.search(/\S/));
|
||||
if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
|
||||
error.reason = 'Missing ";" before statement';
|
||||
type = "error";
|
||||
} else {
|
||||
type = "info";
|
||||
}
|
||||
}
|
||||
else if (disabledWarningsRe.test(raw)) {
|
||||
continue;
|
||||
}
|
||||
else if (infoRe.test(raw)) {
|
||||
type = "info";
|
||||
}
|
||||
else if (errorsRe.test(raw)) {
|
||||
errorAdded = true;
|
||||
type = maxErrorLevel;
|
||||
}
|
||||
else if (raw == "'{a}' is not defined.") {
|
||||
type = "warning";
|
||||
}
|
||||
else if (raw == "'{a}' is defined but never used.") {
|
||||
type = "info";
|
||||
}
|
||||
|
||||
errors.push({
|
||||
// [Node-RED] offset the row for the added line
|
||||
row: error.line-2,
|
||||
column: error.character-1,
|
||||
text: error.reason,
|
||||
type: type,
|
||||
raw: raw
|
||||
});
|
||||
|
||||
if (errorAdded) {
|
||||
// break;
|
||||
}
|
||||
}
|
||||
// console.log("lint time: " + (new Date() - start));
|
||||
|
||||
this.sender.emit("annotate", errors);
|
||||
};
|
||||
|
||||
}).call(NRJavaScriptWorker.prototype);
|
||||
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user